From 57f879fa8b55284c1ea19f14cab0065953778b71 Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <coelckers@users.noreply.github.com>
Date: Thu, 31 Oct 2019 23:25:21 +0100
Subject: [PATCH] - moved the startup dialog out of the game front ends, now
 that there is a global cross-game list of playable configurations.

---
 source/CMakeLists.txt                         |   30 +-
 source/blood/CMakeLists.txt                   |    8 +-
 source/blood/src/blood.cpp                    |   27 -
 source/blood/src/common.cpp                   |   83 +-
 source/blood/src/common_game.h                |    4 -
 source/blood/src/startgtk.game.cpp            |  748 ---------
 source/blood/src/startosx.game.mm             |  859 ----------
 source/blood/src/startwin.game.h              |   48 -
 source/build/include/baselayer.h              |    6 -
 source/build/include/compat.h                 |    1 -
 source/build/src/compat.cpp                   |   49 -
 source/build/src/sdlayer.cpp                  |  188 +--
 source/common/filesystem/filesystem.cpp       |    1 +
 source/common/gamecontrol.cpp                 |   63 +-
 source/common/gamecontrol.h                   |    7 +-
 .../common/textures/formats/jpegtexture.cpp   |    1 +
 source/common/utility/m_argv.h                |   31 +
 source/common/utility/printf.h                |    2 -
 source/common/utility/sc_man.cpp              |    2 +-
 source/duke3d/CMakeLists.txt                  |    8 +-
 source/duke3d/src/GameListSource.game.h       |   26 -
 source/duke3d/src/GameListSource.game.mm      |   77 -
 source/duke3d/src/GrpFile.game.h              |   26 -
 source/duke3d/src/GrpFile.game.mm             |   44 -
 source/duke3d/src/common.cpp                  |  232 +--
 source/duke3d/src/common_game.h               |   17 -
 source/duke3d/src/duke3d.h                    |    1 -
 source/duke3d/src/game.cpp                    |   39 +-
 source/duke3d/src/game.h                      |    1 -
 source/duke3d/src/gamedef.cpp                 |   18 +-
 source/duke3d/src/gamedefs.h                  |    0
 source/duke3d/src/startwin.game.h             |   47 -
 .../src => platform/gtk}/startgtk.game.cpp    |    0
 .../macos}/GameListSource.game.h              |    0
 .../macos}/GameListSource.game.mm             |    0
 .../{rr/src => platform/macos}/GrpFile.game.h |    0
 .../src => platform/macos}/GrpFile.game.mm    |    1 -
 .../src => platform/macos}/startosx.game.mm   | 1436 ++++++++---------
 .../src => platform/win32}/startwin.game.cpp  |   89 +-
 source/rr/CMakeLists.txt                      |    7 -
 source/rr/src/common.cpp                      |  181 +--
 source/rr/src/common_game.h                   |   17 -
 source/rr/src/game.cpp                        |   41 +-
 source/rr/src/gamedef.cpp                     |   10 +-
 source/rr/src/startgtk.game.cpp               |  888 ----------
 source/rr/src/startosx.game.mm                |  715 --------
 source/rr/src/startwin.game.cpp               |  676 --------
 source/rr/src/startwin.game.h                 |   47 -
 source/sw/CMakeLists.txt                      |    8 +-
 source/sw/src/GameListSource.game.h           |   37 -
 source/sw/src/GameListSource.game.mm          |   89 -
 source/sw/src/GrpFile.game.h                  |   40 -
 source/sw/src/GrpFile.game.mm                 |   54 -
 source/sw/src/StartupWinController.game.mm    |  468 ------
 source/sw/src/game.cpp                        |   24 -
 source/sw/src/startgtk.game.cpp               |  756 ---------
 source/sw/src/startwin.game.cpp               |  675 --------
 source/sw/src/startwin.game.h                 |   25 -
 58 files changed, 907 insertions(+), 8071 deletions(-)
 delete mode 100644 source/blood/src/startgtk.game.cpp
 delete mode 100644 source/blood/src/startosx.game.mm
 delete mode 100644 source/blood/src/startwin.game.h
 delete mode 100644 source/duke3d/src/GameListSource.game.h
 delete mode 100644 source/duke3d/src/GameListSource.game.mm
 delete mode 100644 source/duke3d/src/GrpFile.game.h
 delete mode 100644 source/duke3d/src/GrpFile.game.mm
 delete mode 100644 source/duke3d/src/gamedefs.h
 delete mode 100644 source/duke3d/src/startwin.game.h
 rename source/{duke3d/src => platform/gtk}/startgtk.game.cpp (100%)
 rename source/{rr/src => platform/macos}/GameListSource.game.h (100%)
 rename source/{rr/src => platform/macos}/GameListSource.game.mm (100%)
 rename source/{rr/src => platform/macos}/GrpFile.game.h (100%)
 rename source/{rr/src => platform/macos}/GrpFile.game.mm (99%)
 rename source/{duke3d/src => platform/macos}/startosx.game.mm (97%)
 rename source/{duke3d/src => platform/win32}/startwin.game.cpp (90%)
 delete mode 100644 source/rr/src/startgtk.game.cpp
 delete mode 100644 source/rr/src/startosx.game.mm
 delete mode 100644 source/rr/src/startwin.game.cpp
 delete mode 100644 source/rr/src/startwin.game.h
 delete mode 100644 source/sw/src/GameListSource.game.h
 delete mode 100644 source/sw/src/GameListSource.game.mm
 delete mode 100644 source/sw/src/GrpFile.game.h
 delete mode 100644 source/sw/src/GrpFile.game.mm
 delete mode 100644 source/sw/src/StartupWinController.game.mm
 delete mode 100644 source/sw/src/startgtk.game.cpp
 delete mode 100644 source/sw/src/startwin.game.cpp
 delete mode 100644 source/sw/src/startwin.game.h

diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
index 2a83750ba..bd625e074 100644
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -352,30 +352,6 @@ if( DEM_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
 		set( CMAKE_CXX_FLAGS "-DNO_SSE ${CMAKE_CXX_FLAGS}" )
 	endif()
 
-	# Use the highest C++ standard available since VS2015 compiles with C++14
-	# but we only require C++11.  The recommended way to do this in CMake is to
-	# probably to use target_compile_features, but I don't feel like maintaining
-	# a list of features we use.
-	CHECK_CXX_COMPILER_FLAG( "-std=gnu++14" CAN_DO_CPP14 )
-	if ( CAN_DO_CPP14 )
-		set ( CMAKE_CXX_FLAGS "-std=gnu++14 ${CMAKE_CXX_FLAGS}" )
-	else ()
-		CHECK_CXX_COMPILER_FLAG( "-std=gnu++1y" CAN_DO_CPP1Y )
-		if ( CAN_DO_CPP1Y )
-			set ( CMAKE_CXX_FLAGS "-std=gnu++1y ${CMAKE_CXX_FLAGS}" )
-		else ()
-			CHECK_CXX_COMPILER_FLAG( "-std=gnu++11" CAN_DO_CPP11 )
-			if ( CAN_DO_CPP11 )
-				set ( CMAKE_CXX_FLAGS "-std=gnu++11 ${CMAKE_CXX_FLAGS}" )
-			else ()
-				CHECK_CXX_COMPILER_FLAG( "-std=gnu++0x" CAN_DO_CPP0X )
-				if ( CAN_DO_CPP0X )
-					set ( CMAKE_CXX_FLAGS "-std=gnu++0x ${CMAKE_CXX_FLAGS}" )
-				endif ()
-			endif ()
-		endif ()
-	endif ()
-
 	# Remove extra warnings when using the official DirectX headers.
 	# Also, TDM-GCC 4.4.0 no longer accepts glibc-style printf formats as valid,
 	# which is a royal pain. The previous version I had been using was fine with them.
@@ -501,9 +477,9 @@ set( PLAT_WIN32_SOURCES
 	glad/src/glad_wgl.c
 	platform/win32/winbits.cpp
 	platform/win32/i_specialpaths.cpp
+	platform/win32/startwin.game.cpp
 	
 	# This needs a rework anyway in order to consolidate the startup dialogs so don't bother to sort in properly.
-	#startgtk.game.cpp
 	#startosx.game.mm
 	#sw/src/startgtk.game.cpp
 	
@@ -512,6 +488,7 @@ set( PLAT_WIN32_SOURCES
 set( PLAT_POSIX_SOURCES
 	#audiolib/src/driver_sdl.cpp
 	#audiolib/src/sdlmusic.cpp
+	#platform/gtk/startgtk.game.cpp
 	)
 	
 set( PLAT_SDL_SOURCES
@@ -530,6 +507,9 @@ set( PLAT_OSX_SOURCES
 	)
 	
 set( PLAT_COCOA_SOURCES
+	#platform/macos/startosx.game.mm
+	#platform/macos/GrpFile.game.mm
+	#platform/macos/GameListSource.game.mm
 	)
 	
 
diff --git a/source/blood/CMakeLists.txt b/source/blood/CMakeLists.txt
index 250ff20a2..2df18ed54 100644
--- a/source/blood/CMakeLists.txt
+++ b/source/blood/CMakeLists.txt
@@ -26,12 +26,7 @@ include_directories(
 )
 
 
-if (WIN32)
-set( PLAT_SOURCES
-	src/startwin.game.cpp
-	)
-endif()
-	
+
 set( PCH_SOURCES
 	src/actor.cpp
 	src/ai.cpp
@@ -123,7 +118,6 @@ file( GLOB HEADER_FILES
 add_library( blood STATIC
 	${HEADER_FILES}
 	${PCH_SOURCES}
-	${PLAT_SOURCES}
 	)
 
 
diff --git a/source/blood/src/blood.cpp b/source/blood/src/blood.cpp
index 42ca2fada..a63f5e415 100644
--- a/source/blood/src/blood.cpp
+++ b/source/blood/src/blood.cpp
@@ -1259,10 +1259,6 @@ int app_main(int argc, char const * const * argv)
 	gGameOptions.nMonsterSettings = userConfig.nomonsters;
 	bQuickStart = userConfig.nologo;
     ParseOptions();
-    G_ExtInit();
-
-    //G_AddSearchPaths();
-
     
 #ifdef STARTUP_SETUP_WINDOW
     int const readSetup =
@@ -1279,17 +1275,6 @@ int app_main(int argc, char const * const * argv)
 
     ScanINIFiles();
 
-#ifdef STARTUP_SETUP_WINDOW
-    if (readSetup < 0 || (!gNoSetup && (displaysetup)) || gCommandSetup)
-    {
-        if (quitevent || !gi->startwin_run())
-        {
-            engineUnInit();
-            Bexit(0);
-        }
-    }
-#endif
-
 	G_LoadGroups();
 
     initprintf("Initializing OSD...\n");
@@ -2294,12 +2279,6 @@ void sndPlaySpecialMusicOrNothing(int nMusic)
 extern void faketimerhandler();
 extern int app_main(int argc, char const* const* argv);
 extern void app_crashhandler(void);
-extern int32_t startwin_open(void);
-extern int32_t startwin_close(void);
-extern int32_t startwin_puts(const char*);
-extern int32_t startwin_settitle(const char*);
-extern int32_t startwin_idle(void*);
-extern int32_t startwin_run(void);
 bool validate_hud(int layout);
 void set_hud_layout(int layout);
 void set_hud_scale(int scale);
@@ -2313,12 +2292,6 @@ GameInterface Interface = {
 	set_hud_layout,
 	set_hud_scale,
 	app_crashhandler,
-	startwin_open,
-	startwin_close,
-	startwin_puts,
-	startwin_settitle,
-	startwin_idle,
-	startwin_run,
 	G_DefaultDefFile,
 	G_DefFile,
 };
diff --git a/source/blood/src/common.cpp b/source/blood/src/common.cpp
index d8d675c94..145dada7c 100644
--- a/source/blood/src/common.cpp
+++ b/source/blood/src/common.cpp
@@ -64,7 +64,7 @@ void clearGrpNamePtr(void)
 
 const char *G_DefaultGrpFile(void)
 {
-    return "nblood.pk3";
+    return "blood.rff";
 }
 
 const char *G_DefaultDefFile(void)
@@ -104,41 +104,8 @@ void G_SetupGlobalPsky(void)
 
 
 int32_t g_groupFileHandle;
-struct strllist* CommandPaths, * CommandGrps;
+struct strllist* CommandGrps;
 
-void G_ExtInit(void)
-{
-    char cwd[BMAX_PATH];
-
-#ifdef EDUKE32_OSX
-    char *appdir = Bgetappdir();
-    addsearchpath(appdir);
-    Bfree(appdir);
-#endif
-
-    if (getcwd(cwd,BMAX_PATH) && Bstrcmp(cwd,"/") != 0)
-        addsearchpath(cwd);
-
-    if (CommandPaths)
-    {
-        int32_t i;
-        struct strllist *s;
-        while (CommandPaths)
-        {
-            s = CommandPaths->next;
-            i = addsearchpath(CommandPaths->str);
-            if (i < 0)
-            {
-                initprintf("Failed adding %s for game data: %s\n", CommandPaths->str,
-                           i==-1 ? "not a directory" : "no such directory");
-            }
-
-            Bfree(CommandPaths->str);
-            Bfree(CommandPaths);
-            CommandPaths = s;
-        }
-    }
-}
 
 static int32_t G_TryLoadingGrp(char const * const grpfile)
 {
@@ -232,52 +199,6 @@ void G_LoadGroups()
     pathsearchmode = bakpathsearchmode;
 }
 
-void G_CleanupSearchPaths(void)
-{
-    removesearchpaths_withuser(SEARCHPATH_REMOVE);
-}
-
-//////////
-
-
-void G_AddGroup(const char *buffer)
-{
-    char buf[BMAX_PATH];
-
-    struct strllist *s = (struct strllist *)Xcalloc(1,sizeof(struct strllist));
-
-    Bstrcpy(buf, buffer);
-
-    if (Bstrchr(buf,'.') == 0)
-        Bstrcat(buf,".grp");
-
-    s->str = Xstrdup(buf);
-
-    if (CommandGrps)
-    {
-        struct strllist *t;
-        for (t = CommandGrps; t->next; t=t->next) ;
-        t->next = s;
-        return;
-    }
-    CommandGrps = s;
-}
-
-void G_AddPath(const char *buffer)
-{
-    struct strllist *s = (struct strllist *)Xcalloc(1,sizeof(struct strllist));
-    s->str = Xstrdup(buffer);
-
-    if (CommandPaths)
-    {
-        struct strllist *t;
-        for (t = CommandPaths; t->next; t=t->next) ;
-        t->next = s;
-        return;
-    }
-    CommandPaths = s;
-}
-
 //////////
 
 // loads all group (grp, zip, pk3/4) files in the given directory
diff --git a/source/blood/src/common_game.h b/source/blood/src/common_game.h
index 0632f4146..dd2f14e15 100644
--- a/source/blood/src/common_game.h
+++ b/source/blood/src/common_game.h
@@ -514,7 +514,6 @@ extern char *g_grpNamePtr;
 extern int loaddefinitions_game(const char *fn, int32_t preload);
 
 extern void G_AddSearchPaths(void);
-extern void G_CleanupSearchPaths(void);
 
 extern void G_ExtInit(void);
 
@@ -961,7 +960,4 @@ public:
     }
 };
 
-void G_AddGroup(const char* buffer);
-void G_AddPath(const char* buffer);
-
 END_BLD_NS
diff --git a/source/blood/src/startgtk.game.cpp b/source/blood/src/startgtk.game.cpp
deleted file mode 100644
index 692f17c71..000000000
--- a/source/blood/src/startgtk.game.cpp
+++ /dev/null
@@ -1,748 +0,0 @@
-//-------------------------------------------------------------------------
-/*
-Copyright (C) 2010 EDuke32 developers and contributors
-
-This file is part of EDuke32.
-
-EDuke32 is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License version 2
-as published by the Free Software Foundation.
-
-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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-//-------------------------------------------------------------------------
-#include "ns.h"	// Must come before everything else!
-
-#include "build.h"
-#include "common.h"
-#include "common_game.h"
-#include "compat.h"
-#include "dynamicgtk.h"
-#include "blood.h"
-#include "gtkpixdata.h"
-#include "globals.h"
-
-enum
-{
-    NONE,
-    ALL,
-    POPULATE_VIDEO,
-    POPULATE_CONFIG,
-    POPULATE_GAME,
-};
-
-enum
-{
-    TAB_CONFIG,
-    TAB_GAME,
-    TAB_MESSAGES,
-};
-
-enum
-{
-    INPUT_KB,
-    INPUT_MOUSE,
-    INPUT_JOYSTICK,
-    INPUT_ALL,
-};
-
-static struct
-{
-    GtkWidget *startwin;
-    GtkWidget *hlayout;
-    GtkWidget *banner;
-    GtkWidget *vlayout;
-    GtkWidget *tabs;
-    GtkWidget *configtlayout;
-    GtkWidget *displayvlayout;
-    GtkWidget *vmode3dlabel;
-    GtkWidget *vmode3dcombo;
-    GtkWidget *fullscreencheck;
-    GtkWidget *inputdevlabel;
-    GtkWidget *inputdevcombo;
-    GtkWidget *custommodlabel;
-    GtkWidget *custommodcombo;
-    GtkWidget *emptyhlayout;
-    GtkWidget *autoloadcheck;
-    GtkWidget *alwaysshowcheck;
-    GtkWidget *configtab;
-    GtkWidget *messagesscroll;
-    GtkWidget *messagestext;
-    GtkWidget *messagestab;
-    GtkWidget *buttons;
-    GtkWidget *cancelbutton;
-    GtkWidget *cancelbuttonalign;
-    GtkWidget *cancelbuttonlayout;
-    GtkWidget *cancelbuttonicon;
-    GtkWidget *cancelbuttonlabel;
-    GtkWidget *startbutton;
-    GtkWidget *startbuttonalign;
-    GtkWidget *startbuttonlayout;
-    GtkWidget *startbuttonicon;
-    GtkWidget *startbuttonlabel;
-} stwidgets;
-
-static struct
-{
-    char *gamedir;
-    ud_setup_t shared;
-#ifdef POLYMER
-    int polymer;
-#endif
-} settings;
-
-static int32_t retval = -1, mode = TAB_MESSAGES;
-extern int32_t gtkenabled;
-static void PopulateForm(unsigned char pgs);
-
-
-// -- EVENT CALLBACKS AND CREATION STUFF --------------------------------------
-
-static void on_vmode3dcombo_changed(GtkComboBox *combobox, gpointer user_data)
-{
-    GtkTreeModel *data;
-    GtkTreeIter iter;
-    int32_t val;
-    UNREFERENCED_PARAMETER(user_data);
-
-    if (!gtk_combo_box_get_active_iter(combobox, &iter)) return;
-    if (!(data = gtk_combo_box_get_model(combobox))) return;
-    gtk_tree_model_get(data, &iter, 1, &val, -1);
-    settings.shared.xdim = validmode[val].xdim;
-    settings.shared.ydim = validmode[val].ydim;
-    settings.shared.bpp = validmode[val].bpp;
-}
-
-static void on_fullscreencheck_toggled(GtkToggleButton *togglebutton, gpointer user_data)
-{
-    UNREFERENCED_PARAMETER(user_data);
-    settings.shared.fullscreen = gtk_toggle_button_get_active(togglebutton);
-    PopulateForm(POPULATE_VIDEO);
-}
-
-static void on_inputdevcombo_changed(GtkComboBox *combobox, gpointer user_data)
-{
-    UNREFERENCED_PARAMETER(user_data);
-    switch (gtk_combo_box_get_active(combobox))
-    {
-    case 0: settings.shared.usemouse = 0; settings.shared.usejoystick = 0; break;
-    case 1:	settings.shared.usemouse = 1; settings.shared.usejoystick = 0; break;
-    case 2:	settings.shared.usemouse = 0; settings.shared.usejoystick = 1; break;
-    case 3:	settings.shared.usemouse = 1; settings.shared.usejoystick = 1; break;
-    }
-}
-
-static void on_custommodcombo_changed(GtkComboBox *combobox, gpointer user_data)
-{
-    GtkTreeIter iter;
-    GtkTreeModel *model;
-    GtkTreePath *path;
-    char *value;
-    UNREFERENCED_PARAMETER(user_data);
-
-    if (gtk_combo_box_get_active_iter(combobox, &iter))
-    {
-        model = gtk_combo_box_get_model(combobox);
-        gtk_tree_model_get(model, &iter, 0,&value, -1);
-        path = gtk_tree_model_get_path(model, &iter);
-
-        if (*gtk_tree_path_get_indices(path) == NONE)
-            settings.gamedir = NULL;
-        else settings.gamedir = value;
-    }
-}
-
-static void on_autoloadcheck_toggled(GtkToggleButton *togglebutton, gpointer user_data)
-{
-    UNREFERENCED_PARAMETER(user_data);
-    settings.shared.noautoload = !gtk_toggle_button_get_active(togglebutton);
-}
-
-static void on_alwaysshowcheck_toggled(GtkToggleButton *togglebutton, gpointer user_data)
-{
-    UNREFERENCED_PARAMETER(user_data);
-    settings.shared.forcesetup = gtk_toggle_button_get_active(togglebutton);
-}
-
-static void on_cancelbutton_clicked(GtkButton *button, gpointer user_data)
-{
-    UNREFERENCED_PARAMETER(button);
-    UNREFERENCED_PARAMETER(user_data);
-    if (mode == TAB_CONFIG) { retval = 0; gtk_main_quit(); }
-    else quitevent++;
-}
-
-static void on_startbutton_clicked(GtkButton *button, gpointer user_data)
-{
-    UNREFERENCED_PARAMETER(button);
-    UNREFERENCED_PARAMETER(user_data);
-    retval = 1;
-    gtk_main_quit();
-}
-
-static gboolean on_startwin_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
-{
-    UNREFERENCED_PARAMETER(widget);
-    UNREFERENCED_PARAMETER(event);
-    UNREFERENCED_PARAMETER(user_data);
-    if (mode == TAB_CONFIG) { retval = 0; gtk_main_quit(); }
-    else quitevent++;
-    return TRUE;	// FALSE would let the event go through. we want the game to decide when to close
-}
-
-
-// -- SUPPORT FUNCTIONS -------------------------------------------------------
-
-static GdkPixbuf *load_banner(void)
-{
-    return gdk_pixbuf_from_pixdata((GdkPixdata const *)&startbanner_pixdata, FALSE, NULL);
-}
-
-static void SetPage(int32_t n)
-{
-    if (!gtkenabled || !stwidgets.startwin) return;
-    mode = n;
-    gtk_notebook_set_current_page(GTK_NOTEBOOK(stwidgets.tabs), n);
-
-    // each control in the config page vertical layout plus the start button should be made (in)sensitive
-    if (n == TAB_CONFIG) n = TRUE; else n = FALSE;
-    gtk_widget_set_sensitive(stwidgets.startbutton, n);
-    gtk_container_foreach(GTK_CONTAINER(stwidgets.configtlayout),
-                          (GtkCallback)gtk_widget_set_sensitive,
-                          (gpointer)&n);
-}
-
-static unsigned char GetModsDirNames(GtkListStore *list)
-{
-    char *homedir;
-    char pdir[BMAX_PATH];
-    unsigned char iternumb = 0;
-    CACHE1D_FIND_REC *dirs = NULL;
-    GtkTreeIter iter;
-
-    pathsearchmode = 1;
-
-    if ((homedir = Bgethomedir()))
-    {
-        Bsnprintf(pdir, sizeof(pdir), "%s/" ".blood", homedir);
-        dirs = klistpath(pdir, "*", CACHE1D_FIND_DIR);
-        for (; dirs != NULL; dirs=dirs->next)
-        {
-            if ((Bstrcmp(dirs->name, "autoload") == 0) ||
-                    (Bstrcmp(dirs->name, "..") == 0) ||
-                    (Bstrcmp(dirs->name, ".") == 0))
-                continue;
-            else
-            {
-                gtk_list_store_append(list, &iter);
-                gtk_list_store_set(list, &iter, 0,dirs->name, -1);
-                iternumb++;
-            }
-        }
-    }
-
-    klistfree(dirs);
-    dirs = NULL;
-
-    return iternumb;
-}
-
-static void PopulateForm(unsigned char pgs)
-{
-    if ((pgs == ALL) || (pgs == POPULATE_VIDEO))
-    {
-        int32_t mode3d, i;
-        GtkListStore *modes3d;
-        GtkTreeIter iter;
-        char buf[64];
-
-        mode3d = videoCheckMode(&settings.shared.xdim, &settings.shared.ydim, settings.shared.bpp, settings.shared.fullscreen, 1);
-        if (mode3d < 0)
-        {
-            int32_t i, cd[] = { 32, 24, 16, 15, 8, 0 };
-
-            for (i=0; cd[i];) { if (cd[i] >= settings.shared.bpp) i++; else break; }
-            for (; cd[i]; i++)
-            {
-                mode3d = videoCheckMode(&settings.shared.xdim, &settings.shared.ydim, cd[i], settings.shared.fullscreen, 1);
-                if (mode3d < 0) continue;
-                settings.shared.bpp = cd[i];
-                break;
-            }
-        }
-
-        modes3d = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(stwidgets.vmode3dcombo)));
-        gtk_list_store_clear(modes3d);
-
-        for (i=0; i<validmodecnt; i++)
-        {
-            if (validmode[i].fs != settings.shared.fullscreen) continue;
-
-            // all modes get added to the 3D mode list
-            Bsprintf(buf, "%dx%d %s", validmode[i].xdim, validmode[i].ydim, validmode[i].bpp == 8 ? "software" : "OpenGL");
-            gtk_list_store_append(modes3d, &iter);
-            gtk_list_store_set(modes3d, &iter, 0,buf, 1,i, -1);
-            if (i == mode3d)
-            {
-                g_signal_handlers_block_by_func(stwidgets.vmode3dcombo, (gpointer)on_vmode3dcombo_changed, NULL);
-                gtk_combo_box_set_active_iter(GTK_COMBO_BOX(stwidgets.vmode3dcombo), &iter);
-                g_signal_handlers_unblock_by_func(stwidgets.vmode3dcombo, (gpointer)on_vmode3dcombo_changed, NULL);
-            }
-        }
-    }
-
-    if ((pgs == ALL) || (pgs == POPULATE_CONFIG))
-    {
-        GtkListStore *devlist, *modsdir;
-        GtkTreeIter iter;
-        GtkTreePath *path;
-        char *value;
-        unsigned char i, r = 0;
-        const char *availabledev[] =
-        {
-            "Keyboard only",
-            "Keyboard and mouse",
-            "Keyboard and joystick",
-            "All supported devices"
-        };
-
-        // populate input devices combo
-        devlist = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(stwidgets.inputdevcombo)));
-        gtk_list_store_clear(devlist);
-
-        for (i=0; i<(int32_t)G_N_ELEMENTS(availabledev); i++)
-        {
-            gtk_list_store_append(devlist, &iter);
-            gtk_list_store_set(devlist, &iter, 0,availabledev[i], -1);
-        }
-        switch (settings.shared.usemouse)
-        {
-        case 0: if (settings.shared.usejoystick)
-                gtk_combo_box_set_active(GTK_COMBO_BOX(stwidgets.inputdevcombo), INPUT_JOYSTICK);
-            else
-                gtk_combo_box_set_active(GTK_COMBO_BOX(stwidgets.inputdevcombo), INPUT_KB);
-            break;
-        case 1:	if (settings.shared.usejoystick)
-                gtk_combo_box_set_active(GTK_COMBO_BOX(stwidgets.inputdevcombo), INPUT_ALL);
-            else
-                gtk_combo_box_set_active(GTK_COMBO_BOX(stwidgets.inputdevcombo), INPUT_MOUSE);
-            break;
-        }
-
-        // populate custom mod combo
-        modsdir = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(stwidgets.custommodcombo)));
-        gtk_list_store_clear(modsdir);
-
-        gtk_list_store_append(modsdir, &iter);
-        gtk_list_store_set(modsdir, &iter, 0,"None", -1);
-        r = GetModsDirNames(modsdir);
-
-        for (i=0; i<=r; i++)
-        {
-            path = gtk_tree_path_new_from_indices(i, -1);
-            gtk_tree_model_get_iter(GTK_TREE_MODEL(modsdir), &iter, path);
-            gtk_tree_model_get(GTK_TREE_MODEL(modsdir), &iter, 0,&value, -1);
-
-            if (Bstrcmp(settings.gamedir, "/") == 0)
-            {
-                gtk_combo_box_set_active(GTK_COMBO_BOX(stwidgets.custommodcombo), NONE);
-                settings.gamedir = NULL;
-
-                break;
-            }
-            if (Bstrcmp(settings.gamedir, value) == 0)
-            {
-                gtk_combo_box_set_active_iter(GTK_COMBO_BOX(stwidgets.custommodcombo),
-                                              &iter);
-
-                break;
-            }
-        }
-
-        // populate check buttons
-        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(stwidgets.fullscreencheck), settings.shared.fullscreen);
-        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(stwidgets.autoloadcheck), !settings.shared.noautoload);
-        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(stwidgets.alwaysshowcheck), settings.shared.forcesetup);
-    }
-
-#if 0
-    if ((pgs == ALL) || (pgs == POPULATE_GAME))
-    {
-        GtkListStore *list;
-        GtkTreeIter iter;
-        GtkTreeView *gamelist;
-
-        gamelist = GTK_TREE_VIEW(stwidgets.gamelist);
-        list = GTK_LIST_STORE(gtk_tree_view_get_model(gamelist));
-        gtk_list_store_clear(list);
-
-        for (grpfile_t const * fg = foundgrps; fg; fg=fg->next)
-        {
-            gtk_list_store_append(list, &iter);
-            gtk_list_store_set(list, &iter, 0, fg->type->name, 1, fg->filename, 2, (void const *)fg, -1);
-            if (settings.grp == fg)
-            {
-                GtkTreeSelection *sel = gtk_tree_view_get_selection(gamelist);
-                g_signal_handlers_block_by_func(sel, (gpointer)on_gamelist_selection_changed, NULL);
-                gtk_tree_selection_select_iter(sel, &iter);
-                g_signal_handlers_unblock_by_func(sel, (gpointer)on_gamelist_selection_changed, NULL);
-            }
-        }
-    }
-#endif
-}
-
-static GtkWidget *create_window(void)
-{
-    // Basic window
-    stwidgets.startwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-    gtk_window_set_title(GTK_WINDOW(stwidgets.startwin), apptitle);	// NOTE: use global app title
-    gtk_window_set_position(GTK_WINDOW(stwidgets.startwin), GTK_WIN_POS_CENTER);
-    gtk_window_set_resizable(GTK_WINDOW(stwidgets.startwin), FALSE);
-    gtk_window_set_type_hint(GTK_WINDOW(stwidgets.startwin), GDK_WINDOW_TYPE_HINT_DIALOG);
-
-    // Horizontal layout of banner and controls
-    stwidgets.hlayout = gtk_hbox_new(FALSE, 0);
-    gtk_container_add(GTK_CONTAINER(stwidgets.startwin), stwidgets.hlayout);
-
-    // banner
-    {
-        GdkPixbuf *pixbuf = load_banner();
-        stwidgets.banner = gtk_image_new_from_pixbuf(pixbuf);
-        g_object_unref((gpointer)pixbuf);
-    }
-    gtk_box_pack_start(GTK_BOX(stwidgets.hlayout), stwidgets.banner, FALSE, FALSE, 0);
-    gtk_misc_set_alignment(GTK_MISC(stwidgets.banner), 0.5, 0);
-
-    // Vertical layout of tab control and start+cancel buttons
-    stwidgets.vlayout = gtk_vbox_new(FALSE, 0);
-    gtk_box_pack_start(GTK_BOX(stwidgets.hlayout), stwidgets.vlayout, TRUE, TRUE, 0);
-
-    // Tab control
-    stwidgets.tabs = gtk_notebook_new();
-    gtk_box_pack_start(GTK_BOX(stwidgets.vlayout), stwidgets.tabs, TRUE, TRUE, 0);
-    gtk_container_set_border_width(GTK_CONTAINER(stwidgets.tabs), 4);
-
-    // layout table of config page
-    stwidgets.configtlayout = gtk_table_new(6, 3, FALSE);
-    gtk_container_add(GTK_CONTAINER(stwidgets.tabs), stwidgets.configtlayout);
-
-    // 3D video mode LabelText
-    stwidgets.vmode3dlabel = gtk_label_new_with_mnemonic("_Video mode:");
-    gtk_misc_set_alignment(GTK_MISC(stwidgets.vmode3dlabel), 0.3, 0);
-    gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.vmode3dlabel, 0,1, 0,1, GTK_FILL, (GtkAttachOptions)0, 4, 7);
-
-    // 3D video mode combo
-    {
-        GtkListStore *list = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
-        GtkCellRenderer *cell;
-
-        stwidgets.vmode3dcombo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(list));
-        g_object_unref(G_OBJECT(list));
-
-        cell = gtk_cell_renderer_text_new();
-        gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(stwidgets.vmode3dcombo), cell, FALSE);
-        gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(stwidgets.vmode3dcombo), cell, "text", 0, NULL);
-    }
-
-   gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.vmode3dcombo, 1,2, 0,1,
-       (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)0, 4, 0);
-
-    // Fullscreen checkbox
-    stwidgets.displayvlayout = gtk_vbox_new(TRUE, 0);
-    gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.displayvlayout, 2,3, 0,1, GTK_FILL, (GtkAttachOptions)0, 4, 0);
-
-    stwidgets.fullscreencheck = gtk_check_button_new_with_mnemonic("_Fullscreen");
-    gtk_box_pack_start(GTK_BOX(stwidgets.displayvlayout), stwidgets.fullscreencheck, FALSE, FALSE, 0);
-
-    // Input devices LabelText
-    stwidgets.inputdevlabel = gtk_label_new_with_mnemonic("_Input devices:");
-    gtk_misc_set_alignment(GTK_MISC(stwidgets.inputdevlabel), 0.3, 0);
-    gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.inputdevlabel, 0,1, 1,2, GTK_FILL, (GtkAttachOptions)0, 4, 0);
-
-    // Input devices combo
-    {
-        GtkListStore *list = gtk_list_store_new(1, G_TYPE_STRING);
-        GtkCellRenderer *cell;
-
-        stwidgets.inputdevcombo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(list));
-        g_object_unref(G_OBJECT(list));
-
-        cell = gtk_cell_renderer_text_new();
-        gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(stwidgets.inputdevcombo), cell, FALSE);
-        gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(stwidgets.inputdevcombo), cell, "text", 0, NULL);
-    }
-    gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.inputdevcombo, 1,2, 1,2,
-        (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)0, 4, 0);
-
-    // Custom mod LabelText
-    stwidgets.custommodlabel = gtk_label_new_with_mnemonic("Custom _game:");
-    gtk_misc_set_alignment(GTK_MISC(stwidgets.custommodlabel), 0.3, 0);
-    gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.custommodlabel, 0,1, 2,3, GTK_FILL, (GtkAttachOptions)0, 4, 7);
-
-    // Custom mod combo
-    {
-        GtkListStore *list = gtk_list_store_new(1, G_TYPE_STRING);
-        GtkCellRenderer *cell;
-
-        stwidgets.custommodcombo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(list));
-        g_object_unref(G_OBJECT(list));
-
-        cell = gtk_cell_renderer_text_new();
-        gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(stwidgets.custommodcombo), cell, FALSE);
-        gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(stwidgets.custommodcombo), cell, "text", 0, NULL);
-    }
-    gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.custommodcombo, 1,2, 2,3,
-        (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)0, 4, 7);
-
-    // Empty horizontal layout
-    stwidgets.emptyhlayout = gtk_hbox_new(TRUE, 0);
-    gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.emptyhlayout, 0,3, 3,4, (GtkAttachOptions)0,
-        (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 4, 0);
-
-    // Autoload checkbox
-    stwidgets.autoloadcheck = gtk_check_button_new_with_mnemonic("_Enable \"autoload\" folder");
-    gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.autoloadcheck, 0,3, 4,5, GTK_FILL, (GtkAttachOptions)0, 2, 2);
-
-    // Always show config checkbox
-    stwidgets.alwaysshowcheck = gtk_check_button_new_with_mnemonic("_Always show this window at startup");
-    gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.alwaysshowcheck, 0,3, 5,6, GTK_FILL, (GtkAttachOptions)0, 2, 2);
-
-    // Configuration tab
-    stwidgets.configtab = gtk_label_new("Configuration");
-    gtk_notebook_set_tab_label(GTK_NOTEBOOK(stwidgets.tabs), gtk_notebook_get_nth_page(GTK_NOTEBOOK(stwidgets.tabs), 0), stwidgets.configtab);
-
-    // Messages scrollable area
-    stwidgets.messagesscroll = gtk_scrolled_window_new(NULL, NULL);
-    gtk_container_add(GTK_CONTAINER(stwidgets.tabs), stwidgets.messagesscroll);
-    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(stwidgets.messagesscroll), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
-
-    // Messages text area
-    stwidgets.messagestext = gtk_text_view_new();
-    gtk_container_add(GTK_CONTAINER(stwidgets.messagesscroll), stwidgets.messagestext);
-    gtk_text_view_set_editable(GTK_TEXT_VIEW(stwidgets.messagestext), FALSE);
-    gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(stwidgets.messagestext), GTK_WRAP_WORD);
-    gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(stwidgets.messagestext), FALSE);
-    gtk_text_view_set_left_margin(GTK_TEXT_VIEW(stwidgets.messagestext), 2);
-    gtk_text_view_set_right_margin(GTK_TEXT_VIEW(stwidgets.messagestext), 2);
-
-    // Messages tab
-    stwidgets.messagestab = gtk_label_new("Messages");
-    gtk_notebook_set_tab_label(GTK_NOTEBOOK(stwidgets.tabs), gtk_notebook_get_nth_page(GTK_NOTEBOOK(stwidgets.tabs), 1), stwidgets.messagestab);
-
-    // Dialogue box buttons layout
-    stwidgets.buttons = gtk_hbutton_box_new();
-    gtk_box_pack_start(GTK_BOX(stwidgets.vlayout), stwidgets.buttons, FALSE, TRUE, 0);
-    gtk_container_set_border_width(GTK_CONTAINER(stwidgets.buttons), 3);
-    gtk_button_box_set_layout(GTK_BUTTON_BOX(stwidgets.buttons), GTK_BUTTONBOX_END);
-
-    // Cancel button
-    stwidgets.cancelbutton = gtk_button_new();
-    gtk_container_add(GTK_CONTAINER(stwidgets.buttons), stwidgets.cancelbutton);
-    GTK_WIDGET_SET_FLAGS(stwidgets.cancelbutton, GTK_CAN_DEFAULT);
-
-    stwidgets.cancelbuttonalign = gtk_alignment_new(0.5, 0.5, 0, 0);
-    gtk_container_add(GTK_CONTAINER(stwidgets.cancelbutton), stwidgets.cancelbuttonalign);
-
-    stwidgets.cancelbuttonlayout = gtk_hbox_new(FALSE, 2);
-    gtk_container_add(GTK_CONTAINER(stwidgets.cancelbuttonalign), stwidgets.cancelbuttonlayout);
-
-    stwidgets.cancelbuttonicon = gtk_image_new_from_stock("gtk-cancel", GTK_ICON_SIZE_BUTTON);
-    gtk_box_pack_start(GTK_BOX(stwidgets.cancelbuttonlayout), stwidgets.cancelbuttonicon, FALSE, FALSE, 0);
-
-    stwidgets.cancelbuttonlabel = gtk_label_new_with_mnemonic("_Cancel");
-    gtk_box_pack_start(GTK_BOX(stwidgets.cancelbuttonlayout), stwidgets.cancelbuttonlabel, FALSE, FALSE, 0);
-
-    // Start button
-    stwidgets.startbutton = gtk_button_new();
-    gtk_container_add(GTK_CONTAINER(stwidgets.buttons), stwidgets.startbutton);
-    GTK_WIDGET_SET_FLAGS(stwidgets.startbutton, GTK_CAN_DEFAULT);
-
-    gtk_window_set_default(GTK_WINDOW(stwidgets.startwin), stwidgets.startbutton);
-
-    stwidgets.startbuttonalign = gtk_alignment_new(0.5, 0.5, 0, 0);
-    gtk_container_add(GTK_CONTAINER(stwidgets.startbutton), stwidgets.startbuttonalign);
-
-    stwidgets.startbuttonlayout = gtk_hbox_new(FALSE, 2);
-    gtk_container_add(GTK_CONTAINER(stwidgets.startbuttonalign), stwidgets.startbuttonlayout);
-
-    stwidgets.startbuttonicon = gtk_image_new_from_stock("gtk-execute", GTK_ICON_SIZE_BUTTON);
-    gtk_box_pack_start(GTK_BOX(stwidgets.startbuttonlayout), stwidgets.startbuttonicon, FALSE, FALSE, 0);
-
-    stwidgets.startbuttonlabel = gtk_label_new_with_mnemonic("_Start");
-    gtk_box_pack_start(GTK_BOX(stwidgets.startbuttonlayout), stwidgets.startbuttonlabel, FALSE, FALSE, 0);
-
-    // Wire up the signals
-    g_signal_connect((gpointer) stwidgets.startwin, "delete_event",
-                     G_CALLBACK(on_startwin_delete_event),
-                     NULL);
-    g_signal_connect((gpointer) stwidgets.vmode3dcombo, "changed",
-                     G_CALLBACK(on_vmode3dcombo_changed),
-                     NULL);
-    g_signal_connect((gpointer) stwidgets.fullscreencheck, "toggled",
-                     G_CALLBACK(on_fullscreencheck_toggled),
-                     NULL);
-    g_signal_connect((gpointer) stwidgets.inputdevcombo, "changed",
-                     G_CALLBACK(on_inputdevcombo_changed),
-                     NULL);
-    g_signal_connect((gpointer) stwidgets.custommodcombo, "changed",
-                     G_CALLBACK(on_custommodcombo_changed),
-                     NULL);
-    g_signal_connect((gpointer) stwidgets.autoloadcheck, "toggled",
-                     G_CALLBACK(on_autoloadcheck_toggled),
-                     NULL);
-    g_signal_connect((gpointer) stwidgets.alwaysshowcheck, "toggled",
-                     G_CALLBACK(on_alwaysshowcheck_toggled),
-                     NULL);
-    g_signal_connect((gpointer) stwidgets.cancelbutton, "clicked",
-                     G_CALLBACK(on_cancelbutton_clicked),
-                     NULL);
-    g_signal_connect((gpointer) stwidgets.startbutton, "clicked",
-                     G_CALLBACK(on_startbutton_clicked),
-                     NULL);
-
-    // Associate labels with their controls
-    gtk_label_set_mnemonic_widget(GTK_LABEL(stwidgets.vmode3dlabel), stwidgets.vmode3dcombo);
-    gtk_label_set_mnemonic_widget(GTK_LABEL(stwidgets.inputdevlabel), stwidgets.inputdevcombo);
-    gtk_label_set_mnemonic_widget(GTK_LABEL(stwidgets.custommodlabel), stwidgets.custommodcombo);
-
-    return stwidgets.startwin;
-}
-
-
-// -- BUILD ENTRY POINTS ------------------------------------------------------
-
-int32_t startwin_open(void)
-{
-    if (!gtkenabled) return 0;
-    if (stwidgets.startwin) return 1;
-
-    stwidgets.startwin = create_window();
-    if (stwidgets.startwin)
-    {
-        SetPage(TAB_MESSAGES);
-        gtk_widget_show_all(stwidgets.startwin);
-        gtk_main_iteration_do(FALSE);
-        return 0;
-    }
-    return -1;
-}
-
-int32_t startwin_close(void)
-{
-    if (!gtkenabled) return 0;
-    if (!stwidgets.startwin) return 1;
-    gtk_widget_destroy(stwidgets.startwin);
-    stwidgets.startwin = NULL;
-    return 0;
-}
-
-int32_t startwin_puts(const char *str)
-{
-    GtkWidget *textview;
-    GtkTextBuffer *textbuffer;
-    GtkTextIter enditer;
-    GtkTextMark *mark;
-    const char *aptr, *bptr;
-
-    if (!gtkenabled || !str) return 0;
-    if (!stwidgets.startwin) return 1;
-    if (!(textview = stwidgets.messagestext)) return -1;
-    textbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
-
-    gtk_text_buffer_get_end_iter(textbuffer, &enditer);
-    for (aptr = bptr = str; *aptr != 0;)
-    {
-        switch (*bptr)
-        {
-        case '\b':
-            if (bptr > aptr)
-                gtk_text_buffer_insert(textbuffer, &enditer, (const gchar *)aptr, (gint)(bptr-aptr)-1);
-#if GTK_CHECK_VERSION(2,6,0)
-            gtk_text_buffer_backspace(textbuffer, &enditer, FALSE, TRUE);
-#else
-            {
-                GtkTextIter iter2 = enditer;
-                gtk_text_iter_backward_cursor_position(&iter2);
-                //FIXME: this seems be deleting one too many chars somewhere!
-                if (!gtk_text_iter_equal(&iter2, &enditer))
-                    gtk_text_buffer_delete_interactive(textbuffer, &iter2, &enditer, TRUE);
-            }
-#endif
-            aptr = ++bptr;
-            break;
-        case 0:
-            if (bptr > aptr)
-                gtk_text_buffer_insert(textbuffer, &enditer, (const gchar *)aptr, (gint)(bptr-aptr));
-            aptr = bptr;
-            break;
-        case '\r':	// FIXME
-        default:
-            bptr++;
-            break;
-        }
-    }
-
-    mark = gtk_text_buffer_create_mark(textbuffer, NULL, &enditer, 1);
-    gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(textview), mark, 0.0, FALSE, 0.0, 1.0);
-    gtk_text_buffer_delete_mark(textbuffer, mark);
-
-    return 0;
-}
-
-int32_t startwin_settitle(const char *title)
-{
-    if (!gtkenabled) return 0;
-    if (!stwidgets.startwin) return 1;
-    gtk_window_set_title(GTK_WINDOW(stwidgets.startwin), title);
-    return 0;
-}
-
-int32_t startwin_idle(void *s)
-{
-    UNREFERENCED_PARAMETER(s);
-    if (!gtkenabled) return 0;
-    //if (!stwidgets.startwin) return 1;
-    gtk_main_iteration_do(FALSE);
-    return 0;
-}
-
-int32_t startwin_run(void)
-{
-    if (!gtkenabled) return 1;
-    if (!stwidgets.startwin) return 1;
-
-    SetPage(TAB_CONFIG);
-
-    settings.shared = gSetup;
-    settings.gamedir = g_modDir;
-    //settings.grp = g_selectedGrp;
-#ifdef POLYMER
-    settings.polymer = 0;
-#endif
-    PopulateForm(ALL);
-
-    gtk_main();
-
-    SetPage(TAB_MESSAGES);
-    if (retval) // launch the game with these parameters
-    {
-        gSetup = settings.shared;
-#ifdef POLYMER
-        glrendmode = (settings.polymer) ? REND_POLYMER : REND_POLYMOST;
-#endif
-        //g_selectedGrp = settings.grp;
-
-        Bstrcpy(g_modDir, (gNoSetup == 0 && settings.gamedir != NULL) ? settings.gamedir : "/");
-    }
-
-    return retval;
-}
diff --git a/source/blood/src/startosx.game.mm b/source/blood/src/startosx.game.mm
deleted file mode 100644
index c7545729b..000000000
--- a/source/blood/src/startosx.game.mm
+++ /dev/null
@@ -1,859 +0,0 @@
-
-#define Rect CocoaRect
-
-#import <Cocoa/Cocoa.h>
-
-#undef Rect
-
-#include "ns.h"	// Must come before everything else!
-
-#include "blood.h"
-#include "common.h"
-#include "common_game.h"
-#include "build.h"
-#include "compat.h"
-#include "baselayer.h"
-#include "globals.h"
-
-#ifndef MAC_OS_X_VERSION_10_5
-# define NSImageScaleNone NSScaleNone
-#endif
-
-#ifndef MAC_OS_X_VERSION_10_12
-# define NSEventModifierFlagOption NSAlternateKeyMask
-# define NSEventModifierFlagCommand NSCommandKeyMask
-# define NSEventMaskAny NSAnyEventMask
-# define NSWindowStyleMaskTitled NSTitledWindowMask
-# define NSWindowStyleMaskClosable NSClosableWindowMask
-# define NSWindowStyleMaskMiniaturizable NSMiniaturizableWindowMask
-# define NSWindowStyleMaskResizable NSResizableWindowMask
-# define NSAlertStyleInformational NSInformationalAlertStyle
-# define NSControlSizeSmall NSSmallControlSize
-#endif
-
-@interface GameEntry : NSObject
-{
-    NSString *namestring;
-    NSString *inifilestring;
-    INICHAIN const *fg;
-}
-
-- (id)initWithINICHAIN:(INICHAIN const *)inichain;
-- (void)dealloc;
-
-- (NSString *)name;
-- (NSString *)inifile;
-- (INICHAIN const *)entryptr;
-
-@end
-
-@implementation GameEntry
-
-- (id)initWithINICHAIN:(INICHAIN const *)inichain
-{
-    self = [super init];
-
-    if (self)
-    {
-        fg = inichain;
-
-        char const *const name = nullptr == fg->pDescription ? fg->zName : fg->pDescription->pzName;
-
-        namestring = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
-        [namestring retain];
-
-        inifilestring = [NSString stringWithCString:fg->zName encoding:NSUTF8StringEncoding];
-        [inifilestring retain];
-    }
-
-    return self;
-}
-
-- (void)dealloc
-{
-    [namestring release];
-    [inifilestring release];
-    [super dealloc];
-}
-
-- (NSString *)name
-{
-    return namestring;
-}
-
-- (NSString *)inifile
-{
-    return inifilestring;
-}
-
-- (INICHAIN const *)entryptr
-{
-    return fg;
-}
-
-@end
-
-@interface GameListSource : NSObject <NSComboBoxDataSource>
-{
-    NSMutableArray *list;
-}
-
-- (id)init;
-- (void)dealloc;
-
-- (GameEntry *)entryAtIndex:(int)index;
-- (int)findIndexForINI:(NSString*)inifile;
-
-- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex;
-- (int)numberOfRowsInTableView:(NSTableView *)aTableView;
-
-@end
-
-@implementation GameListSource
-
-- (id)init
-{
-    self = [super init];
-
-    if (self)
-    {
-        list = [[NSMutableArray alloc] init];
-
-        for (auto fg = pINIChain; nullptr != fg; fg = fg->pNext)
-        {
-            [list addObject:[[GameEntry alloc] initWithINICHAIN:fg]];
-        }
-    }
-
-    return self;
-}
-
-- (void)dealloc
-{
-    [list release];
-    [super dealloc];
-}
-
-- (GameEntry *)entryAtIndex:(int)index
-{
-    return [list objectAtIndex:index];
-}
-
-- (int)findIndexForINI:(NSString*)inifile
-{
-    for (NSUInteger i = 0, count = [list count]; i < count; ++i)
-    {
-        if ([[[list objectAtIndex:i] inifile] isEqual:inifile])
-        {
-            return i;
-        }
-    }
-
-    return -1;
-}
-
-- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
-{
-    UNREFERENCED_PARAMETER(aTableView);
-    NSParameterAssert((NSUInteger)rowIndex < [list count]);
-
-    switch ([[aTableColumn identifier] intValue])
-    {
-        case 0:    // name column
-            return [[list objectAtIndex:rowIndex] name];
-        case 1:    // ini file column
-            return [[list objectAtIndex:rowIndex] inifile];
-        default:
-            return nil;
-    }
-}
-
-- (int)numberOfRowsInTableView:(NSTableView *)aTableView
-{
-    UNREFERENCED_PARAMETER(aTableView);
-
-    return [list count];
-}
-
-@end
-
-static NSRect NSRectChangeXY(NSRect const rect, CGFloat const x, CGFloat const y)
-{
-    return NSMakeRect(x, y, rect.size.width, rect.size.height);
-}
-static NSRect NSSizeAddXY(NSSize const size, CGFloat const x, CGFloat const y)
-{
-    return NSMakeRect(x, y, size.width, size.height);
-}
-#if 0
-static CGFloat NSRightEdge(NSRect rect)
-{
-    return rect.origin.x + rect.size.width;
-}
-#endif
-static CGFloat NSTopEdge(NSRect rect)
-{
-    return rect.origin.y + rect.size.height;
-}
-
-static void setFontToSmall(id control)
-{
-    [control setFont:[NSFont fontWithDescriptor:[[control font] fontDescriptor] size:[NSFont smallSystemFontSize]]];
-}
-
-static void setControlToSmall(id control)
-{
-#ifdef MAC_OS_X_VERSION_10_12
-    [control setControlSize:NSControlSizeSmall];
-#else
-    [control setControlSize:NSControlSizeSmall];
-#endif
-}
-
-static NSTextField * makeLabel(NSString * labelText)
-{
-    NSTextField *textField = [[NSTextField alloc] init];
-    setFontToSmall(textField);
-    setControlToSmall([textField cell]);
-    [textField setStringValue:labelText];
-    [textField setBezeled:NO];
-    [textField setDrawsBackground:NO];
-    [textField setEditable:NO];
-    [textField setSelectable:NO];
-    [textField sizeToFit];
-    return textField;
-}
-
-static NSButton * makeCheckbox(NSString * labelText)
-{
-    NSButton *checkbox = [[NSButton alloc] init];
-    setFontToSmall(checkbox);
-    setControlToSmall([checkbox cell]);
-    [checkbox setTitle:labelText];
-    [checkbox setButtonType:NSSwitchButton];
-    [checkbox sizeToFit];
-    return checkbox;
-}
-
-static NSPopUpButton * makeComboBox(void)
-{
-    NSPopUpButton *comboBox = [[NSPopUpButton alloc] init];
-    [comboBox setPullsDown:NO];
-    setFontToSmall(comboBox);
-    setControlToSmall([comboBox cell]);
-    [comboBox setBezelStyle:NSRoundedBezelStyle];
-    [comboBox setPreferredEdge:NSMaxYEdge];
-    [[comboBox cell] setArrowPosition:NSPopUpArrowAtCenter];
-    [comboBox sizeToFit];
-    return comboBox;
-}
-
-static id nsapp;
-
-/* setAppleMenu disappeared from the headers in 10.4 */
-@interface NSApplication(NSAppleMenu)
-- (void)setAppleMenu:(NSMenu *)menu;
-@end
-
-static NSString * GetApplicationName(void)
-{
-    NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
-    if (!appName)
-        appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
-    if (![appName length])
-        appName = [[NSProcessInfo processInfo] processName];
-
-    return appName;
-}
-
-static void CreateApplicationMenus(void)
-{
-    NSString *appName;
-    NSString *title;
-    NSMenu *rootMenu;
-    NSMenu *serviceMenu;
-    NSMenuItem *menuItem;
-
-    NSMenu *mainMenu = [[NSMenu alloc] init];
-
-    /* Create the application menu */
-    appName = GetApplicationName();
-    rootMenu = [[NSMenu alloc] init];
-
-    /* Put menu into the menubar */
-    menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
-    [menuItem setSubmenu:rootMenu];
-    [mainMenu addItem:menuItem];
-    [menuItem release];
-
-    /* Add menu items */
-    title = [@"About " stringByAppendingString:appName];
-    [rootMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
-
-    [rootMenu addItem:[NSMenuItem separatorItem]];
-
-    serviceMenu = [[NSMenu alloc] init];
-    menuItem = (NSMenuItem *)[rootMenu addItemWithTitle:@"Services" action:nil keyEquivalent:@""];
-    [menuItem setSubmenu:serviceMenu];
-
-    [nsapp setServicesMenu:serviceMenu];
-    [serviceMenu release];
-
-    [rootMenu addItem:[NSMenuItem separatorItem]];
-
-    title = [@"Hide " stringByAppendingString:appName];
-    [rootMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
-
-    menuItem = (NSMenuItem *)[rootMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
-    [menuItem setKeyEquivalentModifierMask:(NSEventModifierFlagOption|NSEventModifierFlagCommand)];
-
-    [rootMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
-
-    [rootMenu addItem:[NSMenuItem separatorItem]];
-
-    title = [@"Quit " stringByAppendingString:appName];
-    [rootMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
-
-    /* Create the main menu bar */
-    [nsapp setMainMenu:mainMenu];
-    [mainMenu release];  /* we're done with it, let NSApp own it. */
-
-    /* Tell the application object that this is now the application menu */
-    [nsapp setAppleMenu:rootMenu];
-    [rootMenu release];
-}
-
-static int retval = -1;
-
-static struct
-{
-    INICHAIN const * ini;
-    char *gamedir;
-    ud_setup_t shared;
-    int polymer;
-}
-settings;
-
-@interface StartupWindow : NSWindow <NSWindowDelegate>
-{
-    NSMutableArray *modeslist3d;
-    GameListSource *gamelistsrc;
-
-    NSButton *alwaysShowButton;
-    NSButton *fullscreenButton;
-    NSTextView *messagesView;
-    NSTabView *tabView;
-    NSTabViewItem *tabViewItemSetup;
-    NSTabViewItem *tabViewItemMessageLog;
-    NSPopUpButton *videoMode3DPUButton;
-    NSScrollView *gameList;
-
-    NSButton *cancelButton;
-    NSButton *startButton;
-}
-
-- (StartupWindow *)init;
-
-- (void)dealloc;
-- (void)populateVideoModes:(BOOL)firstTime;
-
-- (void)fullscreenClicked:(id)sender;
-
-- (void)cancel:(id)sender;
-- (void)start:(id)sender;
-
-- (void)setupRunMode;
-- (void)setupMessagesMode;
-
-- (void)putsMessage:(NSString *)str;
-
-@end
-
-@implementation StartupWindow : NSWindow
-
-- (StartupWindow *)init
-{
-    NSUInteger const style = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable;
-    NSRect const windowFrame = NSMakeRect(0, 0, 480, 280);
-    self = [super initWithContentRect:windowFrame styleMask:style backing:NSBackingStoreBuffered defer:NO];
-
-    if (self)
-    {
-        // window properties
-        [self setDelegate:self];
-        [self setReleasedWhenClosed:NO];
-#if defined MAC_OS_X_VERSION_10_3 && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3
-        [self setContentMinSize:[[self contentView] frame].size];
-#else
-        [self setMinSize:[NSWindow frameRectForContentRect:[[self contentView] frame] styleMask:[self styleMask]].size];
-#endif
-
-
-        // image on the left
-        NSRect const imageFrame = NSMakeRect(0, 0, 100, 280);
-        NSImageView * imageView = [[NSImageView alloc] initWithFrame:imageFrame];
-        [imageView setImageScaling:NSImageScaleNone];
-        [imageView setImage:[NSImage imageNamed:@"game"]];
-        [[self contentView] addSubview:imageView];
-        [imageView setAutoresizingMask:NSViewMaxXMargin | NSViewHeightSizable];
-
-
-        // buttons
-        CGFloat const buttonWidth = 80;
-        CGFloat const buttonHeight = 32;
-
-        NSRect const startButtonFrame = NSMakeRect(windowFrame.size.width - buttonWidth, 0, buttonWidth, buttonHeight);
-        startButton = [[NSButton alloc] initWithFrame:startButtonFrame];
-        [[self contentView] addSubview:startButton];
-        [startButton setTitle:@"Start"];
-        [startButton setTarget:self];
-        [startButton setAction:@selector(start:)];
-        [startButton setBezelStyle:NSRoundedBezelStyle];
-        [startButton setKeyEquivalent:@"\r"];
-        [startButton setAutoresizingMask:NSViewMinXMargin | NSViewMaxYMargin];
-
-        NSRect const cancelButtonFrame = NSMakeRect(startButtonFrame.origin.x - buttonWidth, 0, buttonWidth, buttonHeight);
-        cancelButton = [[NSButton alloc] initWithFrame:cancelButtonFrame];
-        [[self contentView] addSubview:cancelButton];
-        [cancelButton setTitle:@"Cancel"];
-        [cancelButton setTarget:self];
-        [cancelButton setAction:@selector(cancel:)];
-        [cancelButton setBezelStyle:NSRoundedBezelStyle];
-        [cancelButton setAutoresizingMask:NSViewMinXMargin | NSViewMaxYMargin];
-
-
-        // tab frame
-        NSRect const tabViewFrame = NSMakeRect(imageFrame.size.width, buttonHeight, windowFrame.size.width - imageFrame.size.width, windowFrame.size.height - buttonHeight - 5);
-        tabView = [[NSTabView alloc] initWithFrame:tabViewFrame];
-        [[self contentView] addSubview:tabView];
-        setFontToSmall(tabView);
-        setControlToSmall(tabView);
-        [tabView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
-
-
-        // setup tab
-
-        tabViewItemSetup = [[NSTabViewItem alloc] init];
-        [tabView addTabViewItem:tabViewItemSetup];
-        [tabViewItemSetup setLabel:@"Setup"];
-        NSRect const tabViewItemSetupFrame = [[tabViewItemSetup view] frame];
-
-
-        // always show checkbox
-        alwaysShowButton = makeCheckbox(@"Always show this window at startup");
-        [[tabViewItemSetup view] addSubview:alwaysShowButton];
-        NSSize const alwaysShowButtonSize = [alwaysShowButton frame].size;
-        NSRect const alwaysShowButtonFrame = NSSizeAddXY(alwaysShowButtonSize, tabViewItemSetupFrame.size.width - alwaysShowButtonSize.width, 0);
-        [alwaysShowButton setFrame:alwaysShowButtonFrame];
-        [alwaysShowButton setAutoresizingMask:NSViewMinXMargin | NSViewMaxYMargin];
-
-
-        // video mode selectors and labels
-        NSTextField * labelVideoMode = makeLabel(@"Video mode:");
-        [[tabViewItemSetup view] addSubview:labelVideoMode];
-        NSSize const labelVideoModeSize = [labelVideoMode frame].size;
-        [labelVideoMode setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
-
-        fullscreenButton = makeCheckbox(@"Fullscreen");
-        [[tabViewItemSetup view] addSubview:fullscreenButton];
-        NSSize const fullscreenButtonSize = [fullscreenButton frame].size;
-        [fullscreenButton setAction:@selector(fullscreenClicked:)];
-        [fullscreenButton setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
-
-        videoMode3DPUButton = makeComboBox();
-        [[tabViewItemSetup view] addSubview:videoMode3DPUButton];
-        NSSize const videoMode3DPUButtonSize = [videoMode3DPUButton frame].size;
-        CGFloat const videoMode3DButtonX = labelVideoModeSize.width; // NSRightEdge(labelVideoModeFrame);
-        NSRect const videoMode3DPUButtonFrame = NSMakeRect(videoMode3DButtonX, tabViewItemSetupFrame.size.height - videoMode3DPUButtonSize.height, tabViewItemSetupFrame.size.width - videoMode3DButtonX - fullscreenButtonSize.width, videoMode3DPUButtonSize.height);
-        [videoMode3DPUButton setFrame:videoMode3DPUButtonFrame];
-        [videoMode3DPUButton setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin];
-
-        NSRect const labelVideoModeFrame = NSSizeAddXY(labelVideoModeSize, 0, videoMode3DPUButtonFrame.origin.y + rintf((videoMode3DPUButtonSize.height - labelVideoModeSize.height) * 0.5f) + 1);
-        [labelVideoMode setFrame:labelVideoModeFrame];
-
-        NSRect const fullscreenButtonFrame = NSSizeAddXY(fullscreenButtonSize, tabViewItemSetupFrame.size.width - fullscreenButtonSize.width, videoMode3DPUButtonFrame.origin.y + rintf((videoMode3DPUButtonSize.height - fullscreenButtonSize.height) * 0.5f) + 1);
-        [fullscreenButton setFrame:fullscreenButtonFrame];
-
-
-        // game selector and label
-        NSTextField * labelGame = makeLabel(@"Game:");
-        [[tabViewItemSetup view] addSubview:labelGame];
-        NSSize const labelGameSize = [labelGame frame].size;
-        NSRect const labelGameFrame = NSSizeAddXY(labelGameSize, 0, videoMode3DPUButtonFrame.origin.y - labelGameSize.height);
-        [labelGame setFrame:labelGameFrame];
-        [labelGame setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
-
-        CGFloat const gameListVerticalPadding = 3;
-        CGFloat const gameListY = NSTopEdge(alwaysShowButtonFrame) + gameListVerticalPadding;
-        NSRect const gameListFrame = NSMakeRect(0, gameListY, tabViewItemSetupFrame.size.width, labelGameFrame.origin.y - gameListY - gameListVerticalPadding);
-        gameList = [[NSScrollView alloc] initWithFrame:gameListFrame];
-        [[tabViewItemSetup view] addSubview:gameList];
-        [gameList setBorderType:NSBezelBorder];
-        [gameList setHasVerticalScroller:YES];
-        [gameList setHasHorizontalScroller:NO];
-        setControlToSmall([[gameList verticalScroller] cell]);
-        NSSize const gameListContentSize = [gameList contentSize];
-        [gameList setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
-
-        NSTableView * gameListTable = [[NSTableView alloc] initWithFrame:NSMakeRect(0, 0, gameListContentSize.width, gameListContentSize.height)];
-        [gameList setDocumentView:gameListTable];
-
-        NSTableColumn * nameColumn = [[NSTableColumn alloc] initWithIdentifier:@"0"];
-        [gameListTable addTableColumn:nameColumn];
-        NSTableColumn * fileColumn = [[NSTableColumn alloc] initWithIdentifier:@"1"];
-        [gameListTable addTableColumn:fileColumn];
-        [nameColumn setEditable:NO];
-        [[nameColumn headerCell] setStringValue:@"Name"];
-        [nameColumn setWidth:gameListContentSize.width * (2.f/3.f)];
-        [fileColumn setEditable:NO];
-        [[fileColumn headerCell] setStringValue:@"File"];
-        [gameListTable sizeLastColumnToFit];
-        [gameListTable setAutoresizingMask:NSViewWidthSizable];
-
-
-        // message log tab
-
-        tabViewItemMessageLog = [[NSTabViewItem alloc] init];
-        [tabView addTabViewItem:tabViewItemMessageLog];
-        [tabViewItemMessageLog setLabel:@"Message Log"];
-        NSRect const tabViewItemMessageLogFrame = [[tabViewItemMessageLog view] frame];
-
-
-        // message log
-        NSScrollView * messagesScrollView = [[NSScrollView alloc] initWithFrame:NSRectChangeXY(tabViewItemMessageLogFrame, 0, 0)];
-        [[tabViewItemMessageLog view] addSubview:messagesScrollView];
-        [messagesScrollView setBorderType:NSBezelBorder];
-        [messagesScrollView setHasVerticalScroller:YES];
-        [messagesScrollView setHasHorizontalScroller:NO];
-        setControlToSmall([[messagesScrollView verticalScroller] cell]);
-        NSSize const messagesScrollViewContentSize = [messagesScrollView contentSize];
-        [messagesScrollView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
-
-        messagesView = [[NSTextView alloc] initWithFrame:NSMakeRect(0, 0, messagesScrollViewContentSize.width, messagesScrollViewContentSize.height)];
-        [messagesScrollView setDocumentView:messagesView];
-        [messagesView setEditable:NO];
-        [messagesView setRichText:NO];
-        setFontToSmall(messagesView);
-        [messagesView setMinSize:NSMakeSize(0.0, messagesScrollViewContentSize.height)];
-        [messagesView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
-        [messagesView setVerticallyResizable:YES];
-        [messagesView setHorizontallyResizable:NO];
-        [messagesView setAutoresizingMask:NSViewWidthSizable];
-
-        [[messagesView textContainer] setContainerSize:NSMakeSize(messagesScrollViewContentSize.width, FLT_MAX)];
-        [[messagesView textContainer] setWidthTracksTextView:YES];
-    }
-
-    return self;
-}
-
-- (BOOL)canBecomeKeyWindow
-{
-    return YES;
-}
-
-- (BOOL)canBecomeMainWindow
-{
-    return YES;
-}
-
-- (BOOL) windowShouldClose:(id)sender
-{
-    UNREFERENCED_PARAMETER(sender);
-
-    retval = 0;
-
-    return YES;
-}
-
-- (void)dealloc
-{
-    [gamelistsrc release];
-    [modeslist3d release];
-    [super dealloc];
-}
-
-- (void)populateVideoModes:(BOOL)firstTime
-{
-    int i, mode3d, fullscreen = ([fullscreenButton state] == NSOnState);
-    int idx3d = -1;
-    int xdim = 0, ydim = 0, bpp = 0;
-
-    if (firstTime) {
-        xdim = settings.shared.xdim;
-        ydim = settings.shared.ydim;
-        bpp  = settings.shared.bpp;
-    } else {
-        mode3d = [[modeslist3d objectAtIndex:[videoMode3DPUButton indexOfSelectedItem]] intValue];
-        if (mode3d >= 0) {
-            xdim = validmode[mode3d].xdim;
-            ydim = validmode[mode3d].ydim;
-            bpp = validmode[mode3d].bpp;
-        }
-
-    }
-    mode3d = videoCheckMode(&xdim, &ydim, bpp, fullscreen, 1);
-    if (mode3d < 0) {
-        int i, cd[] = { 32, 24, 16, 15, 8, 0 };
-        for (i=0; cd[i]; ) { if (cd[i] >= bpp) i++; else break; }
-        for ( ; cd[i]; i++) {
-            mode3d = videoCheckMode(&xdim, &ydim, cd[i], fullscreen, 1);
-            if (mode3d < 0) continue;
-            break;
-        }
-    }
-
-    [modeslist3d release];
-    [videoMode3DPUButton removeAllItems];
-
-    modeslist3d = [[NSMutableArray alloc] init];
-
-    for (i = 0; i < validmodecnt; i++) {
-        if (fullscreen == validmode[i].fs) {
-            if (i == mode3d) idx3d = [modeslist3d count];
-            [modeslist3d addObject:[NSNumber numberWithInt:i]];
-            [videoMode3DPUButton addItemWithTitle:[NSString stringWithFormat:@"%d %C %d %d-bpp",
-                                                   validmode[i].xdim, 0xd7, validmode[i].ydim, validmode[i].bpp]];
-        }
-    }
-
-    if (idx3d >= 0) [videoMode3DPUButton selectItemAtIndex:idx3d];
-}
-
-- (void)fullscreenClicked:(id)sender
-{
-    UNREFERENCED_PARAMETER(sender);
-
-    [self populateVideoModes:NO];
-}
-
-- (void)cancel:(id)sender
-{
-    UNREFERENCED_PARAMETER(sender);
-
-    retval = 0;
-}
-
-- (void)start:(id)sender
-{
-    UNREFERENCED_PARAMETER(sender);
-
-    int mode = [[modeslist3d objectAtIndex:[videoMode3DPUButton indexOfSelectedItem]] intValue];
-    if (mode >= 0) {
-        settings.shared.xdim = validmode[mode].xdim;
-        settings.shared.ydim = validmode[mode].ydim;
-        settings.shared.bpp = validmode[mode].bpp;
-        settings.shared.fullscreen = validmode[mode].fs;
-    }
-
-    int row = [[gameList documentView] selectedRow];
-    if (row >= 0)
-    {
-        settings.ini = [[gamelistsrc entryAtIndex:row] entryptr];
-    }
-
-    settings.shared.forcesetup = [alwaysShowButton state] == NSOnState;
-
-    retval = 1;
-}
-
-- (void)setupRunMode
-{
-    videoGetModes();
-
-    [fullscreenButton setState: (settings.shared.fullscreen ? NSOnState : NSOffState)];
-    [alwaysShowButton setState: (settings.shared.forcesetup ? NSOnState : NSOffState)];
-    [self populateVideoModes:YES];
-
-    // enable all the controls on the Configuration page
-    NSEnumerator *enumerator = [[[tabViewItemSetup view] subviews] objectEnumerator];
-    NSControl *control;
-    while ((control = [enumerator nextObject]))
-    {
-        if ([control respondsToSelector:@selector(setEnabled:)])
-            [control setEnabled:true];
-    }
-
-    gamelistsrc = [[GameListSource alloc] init];
-    [[gameList documentView] setDataSource:gamelistsrc];
-    [[gameList documentView] deselectAll:nil];
-
-    if (settings.ini)
-    {
-        int row = [gamelistsrc findIndexForINI:[NSString stringWithUTF8String:settings.ini->zName]];
-        if (row >= 0)
-        {
-            [[gameList documentView] scrollRowToVisible:row];
-#if defined MAC_OS_X_VERSION_10_3 && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3
-            [[gameList documentView] selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
-#else
-            [[gameList documentView] selectRow:row byExtendingSelection:NO];
-#endif
-        }
-    }
-
-    [cancelButton setEnabled:true];
-    [startButton setEnabled:true];
-
-    [tabView selectTabViewItem:tabViewItemSetup];
-    [NSCursor unhide]; // Why should I need to do this?
-}
-
-- (void)setupMessagesMode
-{
-    [tabView selectTabViewItem:tabViewItemMessageLog];
-
-    // disable all the controls on the Configuration page except "always show", so the
-    // user can enable it if they want to while waiting for something else to happen
-    NSEnumerator *enumerator = [[[tabViewItemSetup view] subviews] objectEnumerator];
-    NSControl *control;
-    while ((control = [enumerator nextObject]))
-    {
-        if (control != alwaysShowButton && [control respondsToSelector:@selector(setEnabled:)])
-            [control setEnabled:false];
-    }
-
-    [cancelButton setEnabled:false];
-    [startButton setEnabled:false];
-}
-
-- (void)putsMessage:(NSString *)str
-{
-    NSRange end;
-    NSTextStorage *text = [messagesView textStorage];
-    BOOL shouldAutoScroll;
-
-    shouldAutoScroll = ((int)NSMaxY([messagesView bounds]) == (int)NSMaxY([messagesView visibleRect]));
-
-    end.location = [text length];
-    end.length = 0;
-
-    [text beginEditing];
-    [messagesView replaceCharactersInRange:end withString:str];
-    [text endEditing];
-
-    if (shouldAutoScroll) {
-        end.location = [text length];
-        end.length = 0;
-        [messagesView scrollRangeToVisible:end];
-    }
-}
-
-@end
-
-static StartupWindow *startwin = nil;
-
-int startwin_open(void)
-{
-    // fix for "ld: absolute address to symbol _NSApp in a different linkage unit not supported"
-    // (OS X 10.6) when building for PPC
-    nsapp = [NSApplication sharedApplication];
-
-    if (startwin != nil) return 1;
-
-    startwin = [[StartupWindow alloc] init];
-    if (startwin == nil) return -1;
-
-    [startwin setupMessagesMode];
-
-    [nsapp finishLaunching];
-
-    [startwin center];
-    [startwin makeKeyAndOrderFront:nil];
-
-    CreateApplicationMenus();
-
-    return 0;
-}
-
-int startwin_close(void)
-{
-    if (startwin == nil) return 1;
-
-    [startwin close];
-    [startwin release];
-    startwin = nil;
-
-    return 0;
-}
-
-int startwin_puts(const char *s)
-{
-    NSString *ns;
-
-    if (!s) return -1;
-    if (startwin == nil) return 1;
-
-    ns = [NSString stringWithUTF8String:s];
-    [startwin putsMessage:ns];
-    [ns release];
-
-    return 0;
-}
-
-int startwin_settitle(const char *s)
-{
-    NSString *ns;
-
-    if (!s) return -1;
-    if (startwin == nil) return 1;
-
-    ns = [NSString stringWithUTF8String:s];
-    [startwin setTitle:ns];
-    [ns release];
-
-    return 0;
-}
-
-int startwin_idle(void *v)
-{
-    UNREFERENCED_PARAMETER(v);
-
-    if (startwin)
-    {
-        NSEvent *event;
-        do
-        {
-            event = [nsapp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate date] inMode:NSDefaultRunLoopMode dequeue:YES];
-            [nsapp sendEvent:event];
-        }
-        while (event != nil);
-
-        [startwin displayIfNeeded];
-        [nsapp updateWindows];
-    }
-
-    return 0;
-}
-
-
-int startwin_run(void)
-{
-    if (startwin == nil) return 0;
-
-    settings.shared = gSetup;
-    settings.ini = pINISelected;
-    settings.gamedir = g_modDir;
-
-    [startwin setupRunMode];
-
-    do
-    {
-        NSEvent *event = [nsapp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantFuture] inMode:NSDefaultRunLoopMode dequeue:YES];
-        [nsapp sendEvent:event];
-        [nsapp updateWindows];
-    }
-    while (retval == -1);
-
-    [startwin setupMessagesMode];
-    [nsapp updateWindows];
-
-    if (retval) {
-        gSetup = settings.shared;
-        glrendmode = settings.polymer ? REND_POLYMER : REND_POLYMOST;
-        pINISelected = settings.ini;
-        Bstrcpy(g_modDir, (gNoSetup == 0 && settings.gamedir != NULL) ? settings.gamedir : "/");
-    }
-
-    return retval;
-}
diff --git a/source/blood/src/startwin.game.h b/source/blood/src/startwin.game.h
deleted file mode 100644
index d97dc31cb..000000000
--- a/source/blood/src/startwin.game.h
+++ /dev/null
@@ -1,48 +0,0 @@
-//-------------------------------------------------------------------------
-/*
-Copyright (C) 2010-2019 EDuke32 developers and contributors
-Copyright (C) 2019 Nuke.YKT
-
-This file is part of NBlood.
-
-NBlood is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License version 2
-as published by the Free Software Foundation.
-
-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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-//-------------------------------------------------------------------------
-
-// resource ids
-#define WIN_STARTWIN		1000
-#define WIN_STARTWINPAGE_CONFIG 2000
-#define WIN_STARTWIN_BITMAP	100	// banner bitmap
-#define WIN_STARTWIN_TABCTL	101
-#define WIN_STARTWIN_CANCEL	IDCANCEL
-#define WIN_STARTWIN_START	IDOK
-
-#define WIN_STARTWIN_MESSAGES	104	// output list box
-
-#define RSRC_ICON		100
-#define RSRC_BMP		200
-
-// config page
-#define IDCFULLSCREEN	100
-#define IDCVMODE	    101
-#define IDCSOUNDDRV	    102
-#define IDCMIDIDEV	    103
-#define IDCCDADEV	    104
-#define IDCALWAYSSHOW	105
-#define IDCDATA         106
-#define IDCGAMEDIR      107
-#define IDCPOLYMER      108
-#define IDCAUTOLOAD     109
-#define IDCINPUT	    110
diff --git a/source/build/include/baselayer.h b/source/build/include/baselayer.h
index 16cf841b4..d1a9f0902 100644
--- a/source/build/include/baselayer.h
+++ b/source/build/include/baselayer.h
@@ -237,12 +237,6 @@ struct GameInterface
 
 	// These will later be removed.
 	void (*app_crashhandler)();
-	int32_t(*startwin_open)();
-	int32_t(*startwin_close)();
-	int32_t(*startwin_puts)(const char*);
-	int32_t(*startwin_settitle)(const char*);
-	int32_t (*startwin_idle)(void*);
-	int32_t (*startwin_run)(void);
 	const char* (*DefaultDefFile)();
 	const char* (*DefFile)();
 
diff --git a/source/build/include/compat.h b/source/build/include/compat.h
index 28fc9427d..615fe4186 100644
--- a/source/build/include/compat.h
+++ b/source/build/include/compat.h
@@ -1217,7 +1217,6 @@ int32_t Bclosedir(BDIR *dir);
 ////////// Paths //////////
 
 char *Bgethomedir(void);
-char *Bgetappdir(void);
 
 int32_t Bcorrectfilename(char *filename, int32_t removefn);
 int32_t Bcanonicalisefilename(char *filename, int32_t removefn);
diff --git a/source/build/src/compat.cpp b/source/build/src/compat.cpp
index 9c1b62cc6..54cbeeb82 100644
--- a/source/build/src/compat.cpp
+++ b/source/build/src/compat.cpp
@@ -98,55 +98,6 @@ char *Bgethomedir(void)
 #endif
 }
 
-char *Bgetappdir(void)
-{
-    char *dir = NULL;
-
-#ifdef _WIN32
-    char appdir[MAX_PATH];
-
-    if (GetModuleFileNameA(NULL, appdir, MAX_PATH) > 0) {
-        // trim off the filename
-        char *slash = Bstrrchr(appdir, '\\');
-        if (slash) slash[0] = 0;
-        dir = Xstrdup(appdir);
-    }
-
-#elif defined EDUKE32_OSX
-    dir = osx_getappdir();
-#elif defined __FreeBSD__
-    // the sysctl should also work when /proc/ is not mounted (which seems to
-    // be common on FreeBSD), so use it..
-    char   buf[PATH_MAX] = {0};
-    int    name[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
-    size_t len     = sizeof(buf) - 1;
-    int    ret     = sysctl(name, ARRAY_SIZE(name), buf, &len, NULL, 0);
-
-    if (ret == 0 && buf[0] != '\0')
-    {
-        // again, remove executable name with dirname()
-        // on FreeBSD dirname() seems to use some internal buffer
-        dir = Xstrdup(dirname(buf));
-    }
-#elif defined __linux || defined EDUKE32_BSD
-    char buf[PATH_MAX] = {0};
-    char buf2[PATH_MAX] = {0};
-#  ifdef __linux
-    Bsnprintf(buf, sizeof(buf), "/proc/%d/exe", getpid());
-#  else // the BSDs.. except for FreeBSD which has a sysctl
-    Bsnprintf(buf, sizeof(buf), "/proc/%d/file", getpid());
-#  endif
-    int len = readlink(buf, buf2, sizeof(buf2));
-    if (len != -1) {
-        // remove executable name with dirname(3)
-        // on Linux, dirname() will modify buf2 (cutting off executable name) and return it
-        // on FreeBSD it seems to use some internal buffer instead.. anyway, just strdup()
-        dir = Xstrdup(dirname(buf2));
-    }
-#endif
-
-    return dir;
-}
 
 int32_t Bcorrectfilename(char *filename, int32_t removefn)
 {
diff --git a/source/build/src/sdlayer.cpp b/source/build/src/sdlayer.cpp
index 4b4afb686..aee2ade06 100644
--- a/source/build/src/sdlayer.cpp
+++ b/source/build/src/sdlayer.cpp
@@ -72,13 +72,6 @@ int32_t startwin_puts(const char *s) { UNREFERENCED_PARAMETER(s); return 0; }
 int32_t startwin_idle(void *s) { UNREFERENCED_PARAMETER(s); return 0; }
 int32_t startwin_settitle(const char *s) { UNREFERENCED_PARAMETER(s); return 0; }
 int32_t startwin_run(void) { return 0; }
-#else
-int32_t startwin_open(void) { return gi->startwin_open(); }
-int32_t startwin_close(void) { return gi->startwin_close(); }
-int32_t startwin_puts(const char* s) { return gi->startwin_puts(s); }
-int32_t startwin_idle(void* s) { return gi->startwin_idle(s); }
-int32_t startwin_settitle(const char* s) { return gi->startwin_settitle(s); }
-int32_t startwin_run(void) { return gi->startwin_run(); }
 #endif
 
 int myconnectindex, numplayers;
@@ -338,7 +331,6 @@ void wm_setapptitle(const char *name)
     }
 #endif
 
-    startwin_settitle(apptitle);
 #else
     UNREFERENCED_PARAMETER(name);
 #endif
@@ -395,167 +387,6 @@ static void sighandler(int signum)
 
 FString currentGame;	// Currently there is no global state for the current game. This is a temporary workaround because the video init code needs to do a few things based on the active game.
 
-namespace Duke
-{
-	extern GameInterface Interface;
-}
-namespace Redneck
-{
-	extern GameInterface Interface;
-}
-namespace Blood
-{
-	extern GameInterface Interface;
-}
-namespace ShadowWarrior
-{
-	extern GameInterface Interface;
-}
-
-GameInterface *CheckFrontend()
-{
-	FILE* f = fopen("blood.rff", "rb");
-	if (f)
-	{
-		currentGame = "Blood";
-		fclose(f);
-		return &Blood::Interface;
-	}
-	else
-	{
-		f = fopen("redneck.grp", "rb");
-		if (f)
-		{
-			currentGame = "Redneck";
-			fseek(f, 0, SEEK_END);
-			auto pos = ftell(f);
-			// Quick hack to distinguish these two. This won't survive until production but for testing it's sufficient.
-			if (pos > 190'000'000) currentGame = "RedneckRides";
-			fclose(f);
-			return &Redneck::Interface;
-		}
-		else
-		{
-			f = fopen("sw.grp", "rb");
-			if (f)
-			{
-				currentGame = "ShadowWarrior";
-				fclose(f);
-				return &ShadowWarrior::Interface;
-			}
-			f = fopen("fury.grp", "rb");
-			if (f)
-			{
-				currentGame = "IonFury";
-				fclose(f);
-				return &Duke::Interface;
-			}
-			f = fopen("nam.grp", "rb");
-			if (f)
-			{
-				currentGame = "Nam";
-				fclose(f);
-				return &Duke::Interface;
-			}
-			f = fopen("ww2gi.grp", "rb");
-			if (f)
-			{
-				currentGame = "WW2GI";
-				fclose(f);
-				return &Duke::Interface;
-			}
-			else
-			{
-				currentGame = "Duke";
-			}
-			return &Duke::Interface;
-		}
-	}
-}
-
-void ChooseGame()
-{
-#if 0
-	gi = CheckFrontend();
-	return;
-#else
-	auto dir = Args->CheckValue("-game");
-	if (dir && !chdir(dir))
-	{
-		gi = CheckFrontend();
-		return;
-	}
-
-	TArray<FString> paths;
-	std::vector<std::wstring> wgames;
-	TArray<TASKDIALOG_BUTTON> buttons;
-	char* token;
-	
-	FileReader fr;
-	if (fr.OpenFile("./games.list"))
-	{
-		auto filedata = fr.ReadPadded(1);
-
-		auto script = scriptfile_fromstring((char*)filedata.Data());
-		int id = 1000;
-		while (!scriptfile_eof(script))
-		{
-			scriptfile_getstring(script, &token);
-			if (scriptfile_eof(script))
-			{
-				break;
-			}
-			FString game = token;
-			scriptfile_getstring(script, &token);
-			paths.Push(token);
-			FStringf display("%s\n%s", game.GetChars(), token);
-			wgames.push_back(display.WideString());
-			buttons.Push({ id++, wgames.back().c_str() });
-		}
-	}
-	if (paths.Size() == 0)
-	{
-		exit(1);
-	}
-
-	int nResult = 0;
-
-	TASKDIALOGCONFIG stTaskConfig;
-	ZeroMemory(&stTaskConfig, sizeof(stTaskConfig));
-
-	stTaskConfig.cbSize = sizeof(TASKDIALOGCONFIG);
-	stTaskConfig.hwndParent = NULL;
-	stTaskConfig.hInstance = NULL;
-
-	stTaskConfig.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION| TDF_USE_COMMAND_LINKS;
-
-	if (!gi)
-	{
-		// Open a popup to select the game.
-		// The entire startup code just doesn't work right if this isn't checked as the very first thing.
-		stTaskConfig.pszWindowTitle = L"Demolition";
-		stTaskConfig.pszMainInstruction = L"Choose your game";
-		stTaskConfig.pszContent = L"";
-		stTaskConfig.cButtons = buttons.Size();
-
-		stTaskConfig.pButtons = buttons.Data();
-		stTaskConfig.nDefaultButton = 1000;
-
-		if (SUCCEEDED(TaskDialogIndirect(&stTaskConfig, &nResult, NULL, NULL)))
-		{
-			if (nResult >= 1000 && nResult < 1000 +(int)buttons.Size())
-			{
-				nResult -= 1000;
-				chdir(paths[nResult]);
-				gi = CheckFrontend();
-			}
-		}
-		if (gi == nullptr) exit(1);
-	}
-#endif
-}
-
-
 
 int WINAPI WinMain(HINSTANCE , HINSTANCE , LPSTR , int )
 #else
@@ -581,8 +412,6 @@ int main(int argc, char *argv[])
 
 	Args = new FArgs(buildargc, buildargv);
 
-	ChooseGame();
-
 #if defined _WIN32 && defined SDL_HINT_WINDOWS_DISABLE_THREAD_NAMING
     // Thread naming interferes with debugging using MinGW-w64's GDB.
     SDL_SetHint(SDL_HINT_WINDOWS_DISABLE_THREAD_NAMING, "1");
@@ -616,7 +445,6 @@ int main(int argc, char *argv[])
     gtkbuild_init(&argc, &argv);
 #endif
 
-    startwin_open();
 
 	try
 	{
@@ -638,8 +466,6 @@ int main(int argc, char *argv[])
 		r = exit.Reason();
 	}
 
-    startwin_close();
-
 #if defined(HAVE_GTK2)
     gtkbuild_exit(r);
 #endif
@@ -884,6 +710,7 @@ void initputs(const char *buf)
     OSD_Puts(buf);
 //    Bprintf("%s", buf);
 
+#if 0
     mutex_lock(&m_initprintf);
     if (Bstrlen(dabuf) + Bstrlen(buf) > 1022)
     {
@@ -904,6 +731,7 @@ void initputs(const char *buf)
         Bmemset(dabuf, 0, sizeof(dabuf));
     }
     mutex_unlock(&m_initprintf);
+#endif
 }
 
 //
@@ -1465,6 +1293,7 @@ static void destroy_window_resources()
 #endif
 }
 
+extern int globalShadeDiv;
 void sdlayer_setvideomode_opengl(void)
 {
     glsurface_destroy();
@@ -1474,9 +1303,7 @@ void sdlayer_setvideomode_opengl(void)
 	GLInterface.Init();
 	GLInterface.InitGLState(4, glmultisample);
 	// I have no idea how to get this info from the lookup tables. Fortunately it is consistent per game.
-	if (!currentGame.Compare("Blood")) GLInterface.SetShadeDiv(62);
-	else if (!currentGame.Compare("IonFury")) GLInterface.SetShadeDiv(30);
-	else GLInterface.SetShadeDiv(26);
+	GLInterface.SetShadeDiv(globalShadeDiv);
 
 	GLInterface.mSamplers->SetTextureFilterMode(hw_texfilter, hw_anisotropy);
 
@@ -1494,8 +1321,6 @@ int32_t setvideomode_sdlcommon(int32_t *x, int32_t *y, int32_t c, int32_t fs, in
     if (videoCheckMode(x, y, c, fs, 0) < 0)
         return -1;
 
-    startwin_close();
-
     if (g_mouseGrabbed)
     {
         *regrab = 1;
@@ -2341,11 +2166,6 @@ int32_t handleevents(void)
 
     inputchecked = 0;
     timerUpdateClock();
-
-#ifndef _WIN32
-    startwin_idle(NULL);
-#endif
-
     return rv;
 }
 
diff --git a/source/common/filesystem/filesystem.cpp b/source/common/filesystem/filesystem.cpp
index 123008126..a372d2b79 100644
--- a/source/common/filesystem/filesystem.cpp
+++ b/source/common/filesystem/filesystem.cpp
@@ -48,6 +48,7 @@
 #include "filesystem.h"
 #include "superfasthash.h"
 #include "resourcefile.h"
+#include "v_text.h"
 //#include "md5.h"
 //#include "doomstat.h"
 
diff --git a/source/common/gamecontrol.cpp b/source/common/gamecontrol.cpp
index 19572a989..4d2abb42a 100644
--- a/source/common/gamecontrol.cpp
+++ b/source/common/gamecontrol.cpp
@@ -17,6 +17,8 @@
 
 InputState inputState;
 void SetClipshapes();
+int ShowStartupWindow(TArray<GrpEntry> &);
+int globalShadeDiv;
 
 struct GameFuncNameDesc
 {
@@ -287,6 +289,60 @@ void UserConfig::ProcessOptions()
 
 }
 
+
+//==========================================================================
+//
+//
+//
+//==========================================================================
+
+namespace Duke
+{
+	extern GameInterface Interface;
+}
+namespace Redneck
+{
+	extern GameInterface Interface;
+}
+namespace Blood
+{
+	extern GameInterface Interface;
+}
+namespace ShadowWarrior
+{
+	extern GameInterface Interface;
+}
+
+void CheckFrontend(int flags)
+{
+	if (flags & GAMEFLAG_BLOOD)
+	{
+		gi = &Blood::Interface;
+		globalShadeDiv = 62;
+	}
+	else if (flags & GAMEFLAG_RR)
+	{
+		gi = &Redneck::Interface;
+		globalShadeDiv = 30;
+	}
+	else if (flags & GAMEFLAG_FURY)
+	{
+		gi = &Duke::Interface;
+		globalShadeDiv = 26;	// This is different from all other games which need a value two less than the amount of shades.
+	}
+	else if (flags & GAMEFLAG_SW)
+	{
+		gi = &ShadowWarrior::Interface;
+		globalShadeDiv = 30;
+	}
+	else
+	{
+		gi = &Duke::Interface;
+		globalShadeDiv = 30;
+	}
+}
+
+
 //==========================================================================
 //
 //
@@ -305,14 +361,11 @@ void CONFIG_Init()
 	userConfig.ProcessOptions();
 
 	G_LoadConfig();
+
 	// Startup dialog must be presented here so that everything can be set up before reading the keybinds.
 
 	auto groups = GrpScan();
-	for (auto& grp : groups)
-	{
-		FStringf grpinfo("%s: %s, %s, %s, %s\r\n", grp.FileInfo.name.GetChars(), grp.FileName.GetChars(), grp.FileInfo.scriptname.GetChars(), grp.FileInfo.rtsname.GetChars(), grp.FileInfo.defname.GetChars());
-		OutputDebugStringA(grpinfo);
-	}
+	int groupno = ShowStartupWindow(groups);
 	LumpFilter = currentGame;
 	if (LumpFilter.Compare("Redneck") == 0) LumpFilter = "Redneck.Redneck";
 	else if (LumpFilter.Compare("RedneckRides") == 0) LumpFilter = "Redneck.RidesAgain";
diff --git a/source/common/gamecontrol.h b/source/common/gamecontrol.h
index 9ee1368df..2514f0d13 100644
--- a/source/common/gamecontrol.h
+++ b/source/common/gamecontrol.h
@@ -127,10 +127,11 @@ enum
 	GAMEFLAG_DUKEBETA   = 0x00000060, // includes 0x20 since it's a shareware beta
 	GAMEFLAG_FURY       = 0x00000080,
 	GAMEFLAG_RR         = 0x00000100,
-	GAMEFLAG_RRRA       = 0x00000200,
+	GAMEFLAG_RRRA       = 0x00000300,
 	GAMEFLAG_BLOOD      = 0x00000400,
-	GAMEFLAG_STANDALONE = 0x00000800,
-	GAMEFLAGMASK        = 0x000007FF, // flags allowed from grpinfo
+	GAMEFLAG_SW			= 0x00000800,
+	GAMEFLAG_STANDALONE = 0x00001000,
+	GAMEFLAGMASK        = 0x00000FFF, // flags allowed from grpinfo
 
 };
 
diff --git a/source/common/textures/formats/jpegtexture.cpp b/source/common/textures/formats/jpegtexture.cpp
index a8a60c0c5..19404fd79 100644
--- a/source/common/textures/formats/jpegtexture.cpp
+++ b/source/common/textures/formats/jpegtexture.cpp
@@ -42,6 +42,7 @@
 #include "image.h"
 #include "cache1d.h"
 #include "imagehelpers.h"
+#include "v_text.h"
 
 extern "C"
 {
diff --git a/source/common/utility/m_argv.h b/source/common/utility/m_argv.h
index ecb9b605e..26df5b587 100644
--- a/source/common/utility/m_argv.h
+++ b/source/common/utility/m_argv.h
@@ -43,6 +43,37 @@
 class FArgs
 {
 public:
+
+	typedef TIterator<FString>                  iterator;
+	typedef TIterator<const FString>            const_iterator;
+	typedef FString								value_type;
+
+	iterator begin()
+	{
+		return &Argv[0];
+	}
+	const_iterator begin() const
+	{
+		return &Argv[0];
+	}
+	const_iterator cbegin() const
+	{
+		return &Argv[0];
+	}
+
+	iterator end()
+	{
+		return &Argv[Argv.Size()];
+	}
+	const_iterator end() const
+	{
+		return &Argv[Argv.Size()];
+	}
+	const_iterator cend() const
+	{
+		return &Argv[Argv.Size()];
+	}
+
 	FArgs();
 	FArgs(const FArgs &args);
 	FArgs(int argc, char **argv);
diff --git a/source/common/utility/printf.h b/source/common/utility/printf.h
index 0ef9fee53..c9f389084 100644
--- a/source/common/utility/printf.h
+++ b/source/common/utility/printf.h
@@ -13,5 +13,3 @@ void OSD_Printf(const char *fmt, ...) ATTRIBUTE((format(printf,1,2)));
 
 void I_Error(const char *fmt, ...) ATTRIBUTE((format(printf,1,2)));
 
-
-#include "v_text.h"
diff --git a/source/common/utility/sc_man.cpp b/source/common/utility/sc_man.cpp
index 160220c75..d7c388d44 100644
--- a/source/common/utility/sc_man.cpp
+++ b/source/common/utility/sc_man.cpp
@@ -19,7 +19,7 @@
 #include "templates.h"
 #include "printf.h"
 #include "name.h"
-//#include "v_text.h"
+#include "v_text.h"
 #include "cache1d.h"
 
 // MACROS ------------------------------------------------------------------
diff --git a/source/duke3d/CMakeLists.txt b/source/duke3d/CMakeLists.txt
index cc2f42243..66c64d607 100644
--- a/source/duke3d/CMakeLists.txt
+++ b/source/duke3d/CMakeLists.txt
@@ -26,12 +26,7 @@ include_directories(
 )
 
 
-if (WIN32)
-set( PLAT_SOURCES
-	src/startwin.game.cpp
-	)
-endif()
-	
+
 set( NOT_COMPILED_SOURCE_FILES
 	src/gamestructures.cpp
 )
@@ -84,7 +79,6 @@ file( GLOB HEADER_FILES
 add_library( duke3d STATIC
 	${HEADER_FILES}
 	${PCH_SOURCES}
-	${PLAT_SOURCES}
 	${NOT_COMPILED_SOURCE_FILES}
 	)
 
diff --git a/source/duke3d/src/GameListSource.game.h b/source/duke3d/src/GameListSource.game.h
deleted file mode 100644
index a0054c92f..000000000
--- a/source/duke3d/src/GameListSource.game.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- *  GameListSource.game.h
- *  duke3d
- *
- *  Created by Jonathon Fowler on 24/07/09.
- *  Copyright 2009 __MyCompanyName__. All rights reserved.
- *
- */
-
-#import <Foundation/Foundation.h>
-#import <AppKit/AppKit.h>
-
-@interface GameListSource : NSObject <NSComboBoxDataSource>
-{
-    NSMutableArray *list;
-}
-- (id)init;
-- (void)dealloc;
-- (GrpFile*)grpAtIndex:(int)index;
-- (int)findIndexForGrpname:(NSString*)grpname;
-- (id)tableView:(NSTableView *)aTableView
-objectValueForTableColumn:(NSTableColumn *)aTableColumn
-	    row:(NSInteger)rowIndex;
-- (int)numberOfRowsInTableView:(NSTableView *)aTableView;
-@end
-
diff --git a/source/duke3d/src/GameListSource.game.mm b/source/duke3d/src/GameListSource.game.mm
deleted file mode 100644
index 257385dec..000000000
--- a/source/duke3d/src/GameListSource.game.mm
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- *  GameListSource.game.m
- *  duke3d
- *
- *  Created by Jonathon Fowler on 24/07/09.
- *  Copyright 2009 __MyCompanyName__. All rights reserved.
- *
- */
-
-#import <Foundation/Foundation.h>
-
-#include "ns.h"	// Must come before everything else!
-
-#include "compat.h"
-
-#import "GrpFile.game.h"
-#import "GameListSource.game.h"
-
-@implementation GameListSource
-- (id)init
-{
-    self = [super init];
-    if (self) {
-        list = [[NSMutableArray alloc] init];
-
-        for (grpfile_t const *p = foundgrps; p; p=p->next) {
-            [list addObject:[[GrpFile alloc] initWithGrpfile:p]];
-        }
-    }
-
-    return self;
-}
-
-- (void)dealloc
-{
-    [list release];
-    [super dealloc];
-}
-
-- (GrpFile*)grpAtIndex:(int)index
-{
-    return [list objectAtIndex:index];
-}
-
-- (int)findIndexForGrpname:(NSString*)grpname
-{
-    NSUInteger i, listcount = [list count];
-    for (i=0; i<listcount; i++) {
-        if ([[[list objectAtIndex:i] grpname] isEqual:grpname]) return i;
-    }
-    return -1;
-}
-
-- (id)tableView:(NSTableView *)aTableView
-        objectValueForTableColumn:(NSTableColumn *)aTableColumn
-            row:(NSInteger)rowIndex
-{
-    UNREFERENCED_PARAMETER(aTableView);
-
-    NSParameterAssert((NSUInteger)rowIndex < [list count]);
-    switch ([[aTableColumn identifier] intValue]) {
-        case 0:	// name column
-            return [[list objectAtIndex:rowIndex] name];
-        case 1:	// grp column
-            return [[list objectAtIndex:rowIndex] grpname];
-        default: return nil;
-    }
-}
-
-- (int)numberOfRowsInTableView:(NSTableView *)aTableView
-{
-    UNREFERENCED_PARAMETER(aTableView);
-
-    return [list count];
-}
-@end
-
diff --git a/source/duke3d/src/GrpFile.game.h b/source/duke3d/src/GrpFile.game.h
deleted file mode 100644
index 9fc761816..000000000
--- a/source/duke3d/src/GrpFile.game.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- *  GrpFile.game.h
- *  duke3d
- *
- *  Created by Jonathon Fowler on 24/07/09.
- *  Copyright 2009 __MyCompanyName__. All rights reserved.
- *
- */
-
-#import <Foundation/Foundation.h>
-
-#include "grpscan.h"
-
-@interface GrpFile : NSObject
-{
-    NSString *namestring;
-    NSString *grpnamestring;
-    grpfile_t const *fg;
-}
-- (id)initWithGrpfile:(grpfile_t const *)grpfile;
-- (void)dealloc;
-- (NSString *)name;
-- (NSString *)grpname;
-- (grpfile_t const *)entryptr;
-@end
-
diff --git a/source/duke3d/src/GrpFile.game.mm b/source/duke3d/src/GrpFile.game.mm
deleted file mode 100644
index 07248aa02..000000000
--- a/source/duke3d/src/GrpFile.game.mm
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- *  GrpFile.game.m
- *  duke3d
- *
- *  Created by Jonathon Fowler on 24/07/09.
- *  Copyright 2009 __MyCompanyName__. All rights reserved.
- *
- */
-#include "ns.h"	// Must come before everything else!
-
-#include "GrpFile.game.h"
-
-@implementation GrpFile
-- (id)initWithGrpfile:(grpfile_t const *)grpfile
-{
-    self = [super init];
-    if (self) {
-        fg = grpfile;
-        namestring = [NSString stringWithCString:fg->type->name encoding:NSUTF8StringEncoding];
-        [namestring retain];
-        grpnamestring = [NSString stringWithCString:fg->filename encoding:NSUTF8StringEncoding];
-        [grpnamestring retain];
-    }
-    return self;
-}
-- (void)dealloc
-{
-    [namestring release];
-    [grpnamestring release];
-    [super dealloc];
-}
-- (NSString *)name
-{
-    return namestring;
-}
-- (NSString *)grpname
-{
-    return grpnamestring;
-}
-- (grpfile_t const *)entryptr
-{
-    return fg;
-}
-@end
diff --git a/source/duke3d/src/common.cpp b/source/duke3d/src/common.cpp
index 39077ebcd..f181ee8d1 100644
--- a/source/duke3d/src/common.cpp
+++ b/source/duke3d/src/common.cpp
@@ -12,15 +12,10 @@
 #include "cmdlib.h"
 #include "grpscan.h"
 #include "rts.h"
+#include "gamecontrol.h"
 
 #include "vfs.h"
 
-#ifdef _WIN32
-# include "windows_inc.h"
-# include "win32/winbits.h"
-#elif defined __APPLE__
-# include "osxbits.h"
-#endif
 
 #include "common.h"
 #include "common_game.h"
@@ -46,69 +41,19 @@ static const char *defaultdeffilename[GAMECOUNT]     = { "duke3d.def", "nam.def"
 static const char *defaultgameconfilename[GAMECOUNT] = { "EDUKE.CON", "NAM.CON", "NAPALM.CON", "WW2GI.CON" };
 #endif
 
-// g_grpNamePtr can ONLY point to a malloc'd block (length BMAX_PATH)
-char *g_grpNamePtr = NULL;
-// g_scriptNamePtr can ONLY point to a malloc'd block (length BMAX_PATH)
-char *g_scriptNamePtr = NULL;
-
-void clearGrpNamePtr(void)
-{
-    Xfree(g_grpNamePtr);
-    // g_grpNamePtr assumed to be assigned to right after
-}
-
-void clearScriptNamePtr(void)
-{
-    Xfree(g_scriptNamePtr);
-    // g_scriptNamePtr assumed to be assigned to right after
-}
-
 const char *G_DefaultGrpFile(void)
 {
-#ifndef EDUKE32_STANDALONE
-    if (DUKE)
-        return defaultgamegrp[GAME_DUKE];
-    else if (NAPALM)
-        return defaultgamegrp[GAME_NAPALM];
-    else if (WW2GI)
-        return defaultgamegrp[GAME_WW2GI];
-    else if (NAM)
-        return defaultgamegrp[GAME_NAM];
-
-    return defaultgamegrp[0];
-#else
-    return "(none)";
-#endif
+	return "(none)";	// must be define in GRPINFO.
 }
+
 const char *G_DefaultDefFile(void)
 {
-#ifndef EDUKE32_STANDALONE
-    if (DUKE)
-        return defaultdeffilename[GAME_DUKE];
-    else if (WW2GI)
-        return defaultdeffilename[GAME_WW2GI];
-    else if (NAPALM)
-    {
-        if (!testkopen(defaultdeffilename[GAME_NAPALM],0) && testkopen(defaultdeffilename[GAME_NAM],0))
-            return defaultdeffilename[GAME_NAM]; // NAM/NAPALM Sharing
-        else
-            return defaultdeffilename[GAME_NAPALM];
-    }
-    else if (NAM)
-    {
-        if (!testkopen(defaultdeffilename[GAME_NAM],0) && testkopen(defaultdeffilename[GAME_NAPALM],0))
-            return defaultdeffilename[GAME_NAPALM]; // NAM/NAPALM Sharing
-        else
-            return defaultdeffilename[GAME_NAM];
-    }
-
-    return defaultdeffilename[0];
-#else
-    return "(none)";
-#endif
+	// Todo: Get from the selected game record.
+	return "DUKE3D.DEF";
 }
 const char *G_DefaultConFile(void)
 {
+	// Todo: Get from the selected game record.
 #ifndef EDUKE32_STANDALONE
     if (DUKE && testkopen(defaultgameconfilename[GAME_DUKE],0))
         return defaultgameconfilename[GAME_DUKE];
@@ -138,19 +83,19 @@ const char *G_DefaultConFile(void)
     return defaultconfilename;
 }
 
-const char *G_GrpFile(void)
+const char* G_GrpFile(void)
 {
-    return (g_grpNamePtr == NULL) ? G_DefaultGrpFile() : g_grpNamePtr;
+	return userConfig.gamegrp.IsNotEmpty() ? userConfig.gamegrp.GetChars() : G_DefaultGrpFile();
 }
 
-const char *G_DefFile(void)
+const char* G_DefFile(void)
 {
-    return (g_defNamePtr == NULL) ? G_DefaultDefFile() : g_defNamePtr;
+	return userConfig.DefaultDef.IsNotEmpty() ? userConfig.DefaultDef.GetChars() : G_DefaultDefFile();
 }
 
-const char *G_ConFile(void)
+const char* G_ConFile(void)
 {
-    return (g_scriptNamePtr == NULL) ? G_DefaultConFile() : g_scriptNamePtr;
+	return userConfig.DefaultCon.IsNotEmpty() ? userConfig.DefaultCon.GetChars() : G_DefaultConFile();
 }
 
 //////////
@@ -241,66 +186,7 @@ void G_SetupGlobalPsky(void)
 
 static void G_LoadAddon(void);
 int32_t g_groupFileHandle;
-struct strllist* CommandPaths, * CommandGrps;
-
-void G_ExtInit(void)
-{
-#ifdef EDUKE32_OSX
-    char *appdir = Bgetappdir();
-    addsearchpath(appdir);
-    Xfree(appdir);
-#endif
-
-    char cwd[BMAX_PATH];
-#ifdef USE_PHYSFS
-    strncpy(cwd, PHYSFS_getBaseDir(), ARRAY_SIZE(cwd));
-    cwd[ARRAY_SIZE(cwd)-1] = '\0';
-#else
-    if (buildvfs_getcwd(cwd, ARRAY_SIZE(cwd)) && Bstrcmp(cwd, "/") != 0)
-#endif
-        addsearchpath(cwd);
-
-    if (CommandPaths)
-    {
-        int32_t i;
-        struct strllist *s;
-        while (CommandPaths)
-        {
-            s = CommandPaths->next;
-            i = addsearchpath(CommandPaths->str);
-            if (i < 0)
-            {
-                initprintf("Failed adding %s for game data: %s\n", CommandPaths->str,
-                           i==-1 ? "not a directory" : "no such directory");
-            }
-
-            Xfree(CommandPaths->str);
-            Xfree(CommandPaths);
-            CommandPaths = s;
-        }
-    }
-}
-
-void G_ScanGroups(void)
-{
-    ScanGroups();
-
-    g_selectedGrp = NULL;
-
-    char const * const currentGrp = G_GrpFile();
-
-    for (grpfile_t const *fg = foundgrps; fg; fg=fg->next)
-    {
-        if (!Bstrcasecmp(fg->filename, currentGrp))
-        {
-            g_selectedGrp = fg;
-            break;
-        }
-    }
-
-    if (g_selectedGrp == NULL)
-        g_selectedGrp = foundgrps;
-}
+struct strllist* CommandGrps;
 
 static int32_t G_TryLoadingGrp(char const * const grpfile)
 {
@@ -363,16 +249,16 @@ void G_LoadGroups()
     {
         grpfile = g_selectedGrp->filename;
 
-        clearGrpNamePtr();
-        g_grpNamePtr = dup_filename(grpfile);
+        //clearGrpNamePtr();
+        //g_grpNamePtr = dup_filename(grpfile);
 
         grpinfo_t const * const type = g_selectedGrp->type;
 
         g_gameType = type->game;
         g_gameNamePtr = type->name;
 
-        if (type->scriptname && g_scriptNamePtr == NULL)
-            g_scriptNamePtr = dup_filename(type->scriptname);
+        //if (type->scriptname && g_scriptNamePtr == NULL)
+           // g_scriptNamePtr = dup_filename(type->scriptname);
 
         if (type->defname && g_defNamePtr == NULL)
             g_defNamePtr = dup_filename(type->defname);
@@ -397,18 +283,6 @@ void G_LoadGroups()
     if (g_modDir[0] != '/')
         G_LoadGroupsInDir(g_modDir);
 
-#ifndef EDUKE32_STANDALONE
-    if (g_defNamePtr == NULL)
-    {
-        const char *tmpptr = getenv("DUKE3DDEF");
-        if (tmpptr)
-        {
-            clearDefNamePtr();
-            g_defNamePtr = dup_filename(tmpptr);
-            initprintf("Using \"%s\" as definitions file\n", g_defNamePtr);
-        }
-    }
-#endif
 
     loaddefinitions_game(G_DefFile(), TRUE);
 
@@ -470,72 +344,6 @@ static void G_LoadAddon(void)
 }
 
 
-void G_CleanupSearchPaths(void)
-{
-    removesearchpaths_withuser(SEARCHPATH_REMOVE);
-
-    if (!NAM)
-        removesearchpaths_withuser(SEARCHPATH_NAM);
-
-    if (!WW2GI)
-        removesearchpaths_withuser(SEARCHPATH_WW2GI);
-}
-
-//////////
-
-
-GrowArray<char *> g_scriptModules;
-
-void G_AddGroup(const char *buffer)
-{
-    char buf[BMAX_PATH];
-
-    struct strllist *s = (struct strllist *)Xcalloc(1,sizeof(struct strllist));
-
-    Bstrcpy(buf, buffer);
-
-    if (Bstrchr(buf,'.') == 0)
-        Bstrcat(buf,".grp");
-
-    s->str = Xstrdup(buf);
-
-    if (CommandGrps)
-    {
-        struct strllist *t;
-        for (t = CommandGrps; t->next; t=t->next) ;
-        t->next = s;
-        return;
-    }
-    CommandGrps = s;
-}
-
-void G_AddPath(const char *buffer)
-{
-    struct strllist *s = (struct strllist *)Xcalloc(1,sizeof(struct strllist));
-    s->str = Xstrdup(buffer);
-
-    if (CommandPaths)
-    {
-        struct strllist *t;
-        for (t = CommandPaths; t->next; t=t->next) ;
-        t->next = s;
-        return;
-    }
-    CommandPaths = s;
-}
-
-void G_AddCon(const char *buffer)
-{
-    clearScriptNamePtr();
-    g_scriptNamePtr = dup_filename(buffer);
-    initprintf("Using CON file \"%s\".\n",g_scriptNamePtr);
-}
-
-void G_AddConModule(const char *buffer)
-{
-    g_scriptModules.append(Xstrdup(buffer));
-}
-
 //////////
 
 // loads all group (grp, zip, pk3/4) files in the given directory
@@ -717,12 +525,6 @@ FileReader S_OpenAudio(const char *fn, char searchfirst, uint8_t const ismusic)
 	return origfp;
 }
 
-void Duke_CommonCleanup(void)
-{
-    DO_FREE_AND_NULL(g_grpNamePtr);
-    DO_FREE_AND_NULL(g_scriptNamePtr);
-}
-
 #endif
 
 END_DUKE_NS
diff --git a/source/duke3d/src/common_game.h b/source/duke3d/src/common_game.h
index 7a21e0151..27d1a505f 100644
--- a/source/duke3d/src/common_game.h
+++ b/source/duke3d/src/common_game.h
@@ -67,23 +67,12 @@ typedef enum basepal_ {
 
 extern const char *g_gameNamePtr;
 
-extern char *g_grpNamePtr;
-extern char *g_scriptNamePtr;
-
 extern const char *G_DefaultGrpFile(void);
 extern const char *G_GrpFile(void);
 
 extern const char *G_DefaultConFile(void);
 extern const char *G_ConFile(void);
 
-extern GrowArray<char *> g_scriptModules;
-
-extern void G_AddCon(const char *buffer);
-extern void G_AddConModule(const char *buffer);
-
-extern void clearGrpNamePtr(void);
-extern void clearScriptNamePtr(void);
-
 extern int loaddefinitions_game(const char *fn, int32_t preload);
 extern int32_t g_groupFileHandle;
 
@@ -95,10 +84,7 @@ extern void G_SetupGlobalPsky(void);
 //////////
 
 extern void G_AddSearchPaths(void);
-extern void G_CleanupSearchPaths(void);
 
-extern void G_ExtInit(void);
-extern void G_ScanGroups(void);
 extern void G_LoadGroups();
 
 extern const char * G_GetInstallPath(int32_t insttype);
@@ -117,8 +103,5 @@ extern void G_LoadLookups(void);
 # define FORMAT_UPGRADE_ELIGIBLE
 extern FileReader S_OpenAudio(const char *fn, char searchfirst, uint8_t ismusic);
 
-void G_AddGroup(const char* buffer);
-void G_AddPath(const char* buffer);
-
 END_DUKE_NS
 #endif
diff --git a/source/duke3d/src/duke3d.h b/source/duke3d/src/duke3d.h
index 8bb72b8ba..cacada738 100644
--- a/source/duke3d/src/duke3d.h
+++ b/source/duke3d/src/duke3d.h
@@ -116,7 +116,6 @@ EDUKE32_STATIC_ASSERT(7 <= MAXTILES-MAXUSERTILES);
 #include "gamecontrol.h"
 #include "game.h"
 #include "gamedef.h"
-#include "gamedefs.h"
 #include "gameexec.h"
 #include "gamevars.h"
 #include "global.h"
diff --git a/source/duke3d/src/game.cpp b/source/duke3d/src/game.cpp
index 672f3efec..0d1243469 100644
--- a/source/duke3d/src/game.cpp
+++ b/source/duke3d/src/game.cpp
@@ -71,7 +71,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 BEGIN_DUKE_NS
 
-void Duke_CommonCleanup(void);
 extern const char* G_DefaultDefFile(void);
 extern const char* G_DefFile(void);
 
@@ -5776,8 +5775,6 @@ static void G_Cleanup(void)
 
     hash_loop(&h_dukeanim, G_FreeHashAnim);
     hash_free(&h_dukeanim);
-
-    Duke_CommonCleanup();
 }
 
 /*
@@ -5821,9 +5818,6 @@ static void G_CompileScripts(void)
     labeltype = (int32_t *)&wall[0];   // V8: 16384*32/4 = 131072  V7: 8192*32/4 = 65536
 #endif
 
-    if (g_scriptNamePtr != NULL)
-        Bcorrectfilename(g_scriptNamePtr,0);
-
 #if defined LUNATIC
     Gv_Init();
     C_InitProjectiles();
@@ -6307,11 +6301,6 @@ int app_main(int argc, const char * const*argv)
 
     // This needs to happen afterwards, as G_CheckCommandLine() is where we set
     // up the command-line-provided search paths (duh).
-    G_ExtInit();
-
-#if defined(RENDERTYPEWIN) && defined(USE_OPENGL)
-    if (forcegl) initprintf("GL driver blacklist disabled.\n");
-#endif
 
 #ifdef STARTUP_SETUP_WINDOW
     int const readSetup =
@@ -6326,25 +6315,11 @@ int app_main(int argc, const char * const*argv)
         Bexit(2);
     }
 
-    G_ScanGroups();
-
-#ifdef STARTUP_SETUP_WINDOW
-    if (readSetup < 0 || (!g_noSetup && (displaysetup)) || g_commandSetup)
-    {
-        if (quitevent || !gi->startwin_run())
-        {
-            engineUnInit();
-            Bexit(EXIT_SUCCESS);
-        }
-    }
-#endif
-
+    
     g_logFlushWindow = 0;
     G_LoadGroups();
 //    flushlogwindow = 1;
 
-    G_CleanupSearchPaths();
-
 #ifndef EDUKE32_STANDALONE
     G_SetupCheats();
 
@@ -7112,12 +7087,6 @@ void A_SpawnRandomGlass(int spriteNum, int wallNum, int glassCnt)
 extern void faketimerhandler();
 extern int app_main(int argc, char const* const* argv);
 extern void app_crashhandler(void);
-extern int32_t startwin_open(void);
-extern int32_t startwin_close(void);
-extern int32_t startwin_puts(const char*);
-extern int32_t startwin_settitle(const char*);
-extern int32_t startwin_idle(void*);
-extern int32_t startwin_run(void);
 
 GameInterface Interface = {
 	TICRATE,
@@ -7127,12 +7096,6 @@ GameInterface Interface = {
 	set_hud_layout,
 	set_hud_scale,
 	app_crashhandler,
-	startwin_open,
-	startwin_close,
-	startwin_puts,
-	startwin_settitle,
-	startwin_idle,
-	startwin_run,
 	G_DefaultDefFile,
 	G_DefFile,
 };
diff --git a/source/duke3d/src/game.h b/source/duke3d/src/game.h
index a4f9e6125..48779a7b0 100644
--- a/source/duke3d/src/game.h
+++ b/source/duke3d/src/game.h
@@ -30,7 +30,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 #endif
 
 #include "fix16.h"
-#include "gamedefs.h"
 #include "gamevars.h"
 #include "mmulti.h"
 #include "network.h"
diff --git a/source/duke3d/src/gamedef.cpp b/source/duke3d/src/gamedef.cpp
index 32757ea27..ad0242484 100644
--- a/source/duke3d/src/gamedef.cpp
+++ b/source/duke3d/src/gamedef.cpp
@@ -33,6 +33,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 #include "namesdyn.h"
 #include "osd.h"
 #include "savegame.h"
+#include "printf.h"
+#include "m_argv.h"
 
 #include "vfs.h"
 
@@ -6104,9 +6106,7 @@ void C_Compile(const char *fileName)
         if (g_loadFromGroupOnly == 1 || numgroupfiles == 0)
         {
 #ifndef EDUKE32_STANDALONE
-            char const *gf = G_GrpFile();
-            Bsprintf(tempbuf,"Required game data was not found.  A valid copy of \"%s\" or other compatible data is needed to run EDuke32.\n\n"
-                     "You must copy \"%s\" to your game directory before continuing!", gf, gf);
+            I_Error("Required game data was not found.");
             G_GameExit(tempbuf);
 #else
             G_GameExit(" ");
@@ -6157,13 +6157,11 @@ void C_Compile(const char *fileName)
     C_AddDefaultDefinitions();
     C_ParseCommand(true);
 
-    for (char * m : g_scriptModules)
-    {
-        C_Include(m);
-        free(m);
-    }
-    g_scriptModules.clear();
-
+	for (FString& m : *userConfig.AddCons.get())
+	{
+		C_Include(m);
+	}
+	
     g_logFlushWindow = 1;
 
     if (g_errorCnt > 63)
diff --git a/source/duke3d/src/gamedefs.h b/source/duke3d/src/gamedefs.h
deleted file mode 100644
index e69de29bb..000000000
diff --git a/source/duke3d/src/startwin.game.h b/source/duke3d/src/startwin.game.h
deleted file mode 100644
index a2b52f9fc..000000000
--- a/source/duke3d/src/startwin.game.h
+++ /dev/null
@@ -1,47 +0,0 @@
-//-------------------------------------------------------------------------
-/*
-Copyright (C) 2010 EDuke32 developers and contributors
-
-This file is part of EDuke32.
-
-EDuke32 is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License version 2
-as published by the Free Software Foundation.
-
-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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-//-------------------------------------------------------------------------
-
-// resource ids
-#define WIN_STARTWIN		1000
-#define WIN_STARTWINPAGE_CONFIG 2000
-#define WIN_STARTWIN_BITMAP	100	// banner bitmap
-#define WIN_STARTWIN_TABCTL	101
-#define WIN_STARTWIN_CANCEL	IDCANCEL
-#define WIN_STARTWIN_START	IDOK
-
-#define WIN_STARTWIN_MESSAGES	104	// output list box
-
-#define RSRC_ICON		100
-#define RSRC_BMP		200
-
-// config page
-#define IDCFULLSCREEN	100
-#define IDCVMODE	    101
-#define IDCSOUNDDRV	    102
-#define IDCMIDIDEV	    103
-#define IDCCDADEV	    104
-#define IDCALWAYSSHOW	105
-#define IDCDATA         106
-#define IDCGAMEDIR      107
-#define IDCPOLYMER      108
-#define IDCAUTOLOAD     109
-#define IDCINPUT	    110
diff --git a/source/duke3d/src/startgtk.game.cpp b/source/platform/gtk/startgtk.game.cpp
similarity index 100%
rename from source/duke3d/src/startgtk.game.cpp
rename to source/platform/gtk/startgtk.game.cpp
diff --git a/source/rr/src/GameListSource.game.h b/source/platform/macos/GameListSource.game.h
similarity index 100%
rename from source/rr/src/GameListSource.game.h
rename to source/platform/macos/GameListSource.game.h
diff --git a/source/rr/src/GameListSource.game.mm b/source/platform/macos/GameListSource.game.mm
similarity index 100%
rename from source/rr/src/GameListSource.game.mm
rename to source/platform/macos/GameListSource.game.mm
diff --git a/source/rr/src/GrpFile.game.h b/source/platform/macos/GrpFile.game.h
similarity index 100%
rename from source/rr/src/GrpFile.game.h
rename to source/platform/macos/GrpFile.game.h
diff --git a/source/rr/src/GrpFile.game.mm b/source/platform/macos/GrpFile.game.mm
similarity index 99%
rename from source/rr/src/GrpFile.game.mm
rename to source/platform/macos/GrpFile.game.mm
index fd460e6c6..ac28b5f49 100644
--- a/source/rr/src/GrpFile.game.mm
+++ b/source/platform/macos/GrpFile.game.mm
@@ -6,7 +6,6 @@
  *  Copyright 2009 __MyCompanyName__. All rights reserved.
  *
  */
-
 #include "ns.h"	// Must come before everything else!
 
 #include "GrpFile.game.h"
diff --git a/source/duke3d/src/startosx.game.mm b/source/platform/macos/startosx.game.mm
similarity index 97%
rename from source/duke3d/src/startosx.game.mm
rename to source/platform/macos/startosx.game.mm
index d2db5e86a..731a4634f 100644
--- a/source/duke3d/src/startosx.game.mm
+++ b/source/platform/macos/startosx.game.mm
@@ -1,718 +1,718 @@
-
-#import <Cocoa/Cocoa.h>
-
-#include "ns.h"	// Must come before everything else!
-
-#include "duke3d.h"
-#include "game.h"
-#include "common.h"
-#include "common_game.h"
-#include "build.h"
-#include "compat.h"
-#include "baselayer.h"
-#include "grpscan.h"
-
-#import "GrpFile.game.h"
-#import "GameListSource.game.h"
-
-#ifndef MAC_OS_X_VERSION_10_5
-# define NSImageScaleNone NSScaleNone
-#endif
-
-#ifndef MAC_OS_X_VERSION_10_12
-# define NSEventModifierFlagOption NSAlternateKeyMask
-# define NSEventModifierFlagCommand NSCommandKeyMask
-# define NSEventMaskAny NSAnyEventMask
-# define NSWindowStyleMaskTitled NSTitledWindowMask
-# define NSWindowStyleMaskClosable NSClosableWindowMask
-# define NSWindowStyleMaskMiniaturizable NSMiniaturizableWindowMask
-# define NSWindowStyleMaskResizable NSResizableWindowMask
-# define NSAlertStyleInformational NSInformationalAlertStyle
-# define NSControlSizeSmall NSSmallControlSize
-#endif
-
-#ifndef MAC_OS_X_VERSION_10_14
-# define NSButtonTypeSwitch NSSwitchButton
-# define NSBezelStyleRounded NSRoundedBezelStyle
-# define NSControlStateValueOn NSOnState
-# define NSControlStateValueOff NSOffState
-#endif
-
-static NSRect NSRectChangeXY(NSRect const rect, CGFloat const x, CGFloat const y)
-{
-    return NSMakeRect(x, y, rect.size.width, rect.size.height);
-}
-static NSRect NSSizeAddXY(NSSize const size, CGFloat const x, CGFloat const y)
-{
-    return NSMakeRect(x, y, size.width, size.height);
-}
-#if 0
-static CGFloat NSRightEdge(NSRect rect)
-{
-    return rect.origin.x + rect.size.width;
-}
-#endif
-static CGFloat NSTopEdge(NSRect rect)
-{
-    return rect.origin.y + rect.size.height;
-}
-
-static void setFontToSmall(id control)
-{
-    [control setFont:[NSFont fontWithDescriptor:[[control font] fontDescriptor] size:[NSFont smallSystemFontSize]]];
-}
-
-static void setControlToSmall(id control)
-{
-    [control setControlSize:NSControlSizeSmall];
-}
-
-static NSTextField * makeLabel(NSString * labelText)
-{
-    NSTextField *textField = [[NSTextField alloc] init];
-    setFontToSmall(textField);
-    setControlToSmall([textField cell]);
-    [textField setStringValue:labelText];
-    [textField setBezeled:NO];
-    [textField setDrawsBackground:NO];
-    [textField setEditable:NO];
-    [textField setSelectable:NO];
-    [textField sizeToFit];
-    return textField;
-}
-
-static NSButton * makeCheckbox(NSString * labelText)
-{
-    NSButton *checkbox = [[NSButton alloc] init];
-    setFontToSmall(checkbox);
-    setControlToSmall([checkbox cell]);
-    [checkbox setTitle:labelText];
-    [checkbox setButtonType:NSButtonTypeSwitch];
-    [checkbox sizeToFit];
-    return checkbox;
-}
-
-static NSPopUpButton * makeComboBox(void)
-{
-    NSPopUpButton *comboBox = [[NSPopUpButton alloc] init];
-    [comboBox setPullsDown:NO];
-    setFontToSmall(comboBox);
-    setControlToSmall([comboBox cell]);
-    [comboBox setBezelStyle:NSBezelStyleRounded];
-    [comboBox setPreferredEdge:NSMaxYEdge];
-    [[comboBox cell] setArrowPosition:NSPopUpArrowAtCenter];
-    [comboBox sizeToFit];
-    return comboBox;
-}
-
-static id nsapp;
-
-/* setAppleMenu disappeared from the headers in 10.4 */
-@interface NSApplication(NSAppleMenu)
-- (void)setAppleMenu:(NSMenu *)menu;
-@end
-
-static NSString * GetApplicationName(void)
-{
-    NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
-    if (!appName)
-        appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
-    if (![appName length])
-        appName = [[NSProcessInfo processInfo] processName];
-
-    return appName;
-}
-
-static void CreateApplicationMenus(void)
-{
-    NSString *appName;
-    NSString *title;
-    NSMenu *rootMenu;
-    NSMenu *serviceMenu;
-    NSMenuItem *menuItem;
-
-    NSMenu *mainMenu = [[NSMenu alloc] init];
-
-    /* Create the application menu */
-    appName = GetApplicationName();
-    rootMenu = [[NSMenu alloc] init];
-
-    /* Put menu into the menubar */
-    menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
-    [menuItem setSubmenu:rootMenu];
-    [mainMenu addItem:menuItem];
-    [menuItem release];
-
-    /* Add menu items */
-    title = [@"About " stringByAppendingString:appName];
-    [rootMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
-
-    [rootMenu addItem:[NSMenuItem separatorItem]];
-
-    serviceMenu = [[NSMenu alloc] init];
-    menuItem = (NSMenuItem *)[rootMenu addItemWithTitle:@"Services" action:nil keyEquivalent:@""];
-    [menuItem setSubmenu:serviceMenu];
-
-    [nsapp setServicesMenu:serviceMenu];
-    [serviceMenu release];
-
-    [rootMenu addItem:[NSMenuItem separatorItem]];
-
-    title = [@"Hide " stringByAppendingString:appName];
-    [rootMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
-
-    menuItem = (NSMenuItem *)[rootMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
-    [menuItem setKeyEquivalentModifierMask:(NSEventModifierFlagOption|NSEventModifierFlagCommand)];
-
-    [rootMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
-
-    [rootMenu addItem:[NSMenuItem separatorItem]];
-
-    title = [@"Quit " stringByAppendingString:appName];
-    [rootMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
-
-    /* Create the main menu bar */
-    [nsapp setMainMenu:mainMenu];
-    [mainMenu release];  /* we're done with it, let NSApp own it. */
-
-    /* Tell the application object that this is now the application menu */
-    [nsapp setAppleMenu:rootMenu];
-    [rootMenu release];
-}
-
-static int retval = -1;
-
-static struct {
-    grpfile_t const * grp;
-    int fullscreen;
-    int xdim3d, ydim3d, bpp3d;
-    int forcesetup;
-} settings;
-
-@interface StartupWindow : NSWindow <NSWindowDelegate>
-{
-    NSMutableArray *modeslist3d;
-    GameListSource *gamelistsrc;
-
-    NSButton *alwaysShowButton;
-    NSButton *fullscreenButton;
-    NSTextView *messagesView;
-    NSTabView *tabView;
-    NSTabViewItem *tabViewItemSetup;
-    NSTabViewItem *tabViewItemMessageLog;
-    NSPopUpButton *videoMode3DPUButton;
-    NSScrollView *gameList;
-
-    NSButton *cancelButton;
-    NSButton *startButton;
-}
-
-- (StartupWindow *)init;
-
-- (void)dealloc;
-- (void)populateVideoModes:(BOOL)firstTime;
-
-- (void)fullscreenClicked:(id)sender;
-
-- (void)cancel:(id)sender;
-- (void)start:(id)sender;
-
-- (void)setupRunMode;
-- (void)setupMessagesMode;
-
-- (void)putsMessage:(NSString *)str;
-
-@end
-
-@implementation StartupWindow : NSWindow
-
-- (StartupWindow *)init
-{
-    NSUInteger const style = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable;
-    NSRect const windowFrame = NSMakeRect(0, 0, 480, 280);
-    self = [super initWithContentRect:windowFrame styleMask:style backing:NSBackingStoreBuffered defer:NO];
-
-    if (self)
-    {
-        // window properties
-        [self setDelegate:self];
-        [self setReleasedWhenClosed:NO];
-#if defined MAC_OS_X_VERSION_10_3 && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3
-        [self setContentMinSize:[[self contentView] frame].size];
-#else
-        [self setMinSize:[NSWindow frameRectForContentRect:[[self contentView] frame] styleMask:[self styleMask]].size];
-#endif
-
-
-        // image on the left
-        NSRect const imageFrame = NSMakeRect(0, 0, 100, 280);
-        NSImageView * imageView = [[NSImageView alloc] initWithFrame:imageFrame];
-        [imageView setImageScaling:NSImageScaleNone];
-        [imageView setImage:[NSImage imageNamed:@"game"]];
-        [[self contentView] addSubview:imageView];
-        [imageView setAutoresizingMask:NSViewMaxXMargin | NSViewHeightSizable];
-
-
-        // buttons
-        CGFloat const buttonWidth = 80;
-        CGFloat const buttonHeight = 32;
-
-        NSRect const startButtonFrame = NSMakeRect(windowFrame.size.width - buttonWidth, 0, buttonWidth, buttonHeight);
-        startButton = [[NSButton alloc] initWithFrame:startButtonFrame];
-        [[self contentView] addSubview:startButton];
-        [startButton setTitle:@"Start"];
-        [startButton setTarget:self];
-        [startButton setAction:@selector(start:)];
-        [startButton setBezelStyle:NSBezelStyleRounded];
-        [startButton setKeyEquivalent:@"\r"];
-        [startButton setAutoresizingMask:NSViewMinXMargin | NSViewMaxYMargin];
-
-        NSRect const cancelButtonFrame = NSMakeRect(startButtonFrame.origin.x - buttonWidth, 0, buttonWidth, buttonHeight);
-        cancelButton = [[NSButton alloc] initWithFrame:cancelButtonFrame];
-        [[self contentView] addSubview:cancelButton];
-        [cancelButton setTitle:@"Cancel"];
-        [cancelButton setTarget:self];
-        [cancelButton setAction:@selector(cancel:)];
-        [cancelButton setBezelStyle:NSBezelStyleRounded];
-        [cancelButton setAutoresizingMask:NSViewMinXMargin | NSViewMaxYMargin];
-
-
-        // tab frame
-        NSRect const tabViewFrame = NSMakeRect(imageFrame.size.width, buttonHeight, windowFrame.size.width - imageFrame.size.width, windowFrame.size.height - buttonHeight - 5);
-        tabView = [[NSTabView alloc] initWithFrame:tabViewFrame];
-        [[self contentView] addSubview:tabView];
-        setFontToSmall(tabView);
-        setControlToSmall(tabView);
-        [tabView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
-
-
-        // setup tab
-
-        tabViewItemSetup = [[NSTabViewItem alloc] init];
-        [tabView addTabViewItem:tabViewItemSetup];
-        [tabViewItemSetup setLabel:@"Setup"];
-        NSRect const tabViewItemSetupFrame = [[tabViewItemSetup view] frame];
-
-
-        // always show checkbox
-        alwaysShowButton = makeCheckbox(@"Always show this window at startup");
-        [[tabViewItemSetup view] addSubview:alwaysShowButton];
-        NSSize const alwaysShowButtonSize = [alwaysShowButton frame].size;
-        NSRect const alwaysShowButtonFrame = NSSizeAddXY(alwaysShowButtonSize, tabViewItemSetupFrame.size.width - alwaysShowButtonSize.width, 0);
-        [alwaysShowButton setFrame:alwaysShowButtonFrame];
-        [alwaysShowButton setAutoresizingMask:NSViewMinXMargin | NSViewMaxYMargin];
-
-
-        // video mode selectors and labels
-        NSTextField * labelVideoMode = makeLabel(@"Video mode:");
-        [[tabViewItemSetup view] addSubview:labelVideoMode];
-        NSSize const labelVideoModeSize = [labelVideoMode frame].size;
-        [labelVideoMode setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
-
-        fullscreenButton = makeCheckbox(@"Fullscreen");
-        [[tabViewItemSetup view] addSubview:fullscreenButton];
-        NSSize const fullscreenButtonSize = [fullscreenButton frame].size;
-        [fullscreenButton setAction:@selector(fullscreenClicked:)];
-        [fullscreenButton setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
-
-        videoMode3DPUButton = makeComboBox();
-        [[tabViewItemSetup view] addSubview:videoMode3DPUButton];
-        NSSize const videoMode3DPUButtonSize = [videoMode3DPUButton frame].size;
-        CGFloat const videoMode3DButtonX = labelVideoModeSize.width; // NSRightEdge(labelVideoModeFrame);
-        NSRect const videoMode3DPUButtonFrame = NSMakeRect(videoMode3DButtonX, tabViewItemSetupFrame.size.height - videoMode3DPUButtonSize.height, tabViewItemSetupFrame.size.width - videoMode3DButtonX - fullscreenButtonSize.width, videoMode3DPUButtonSize.height);
-        [videoMode3DPUButton setFrame:videoMode3DPUButtonFrame];
-        [videoMode3DPUButton setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin];
-
-        NSRect const labelVideoModeFrame = NSSizeAddXY(labelVideoModeSize, 0, videoMode3DPUButtonFrame.origin.y + rintf((videoMode3DPUButtonSize.height - labelVideoModeSize.height) * 0.5f) + 1);
-        [labelVideoMode setFrame:labelVideoModeFrame];
-
-        NSRect const fullscreenButtonFrame = NSSizeAddXY(fullscreenButtonSize, tabViewItemSetupFrame.size.width - fullscreenButtonSize.width, videoMode3DPUButtonFrame.origin.y + rintf((videoMode3DPUButtonSize.height - fullscreenButtonSize.height) * 0.5f) + 1);
-        [fullscreenButton setFrame:fullscreenButtonFrame];
-
-
-        // game selector and label
-        NSTextField * labelGame = makeLabel(@"Game:");
-        [[tabViewItemSetup view] addSubview:labelGame];
-        NSSize const labelGameSize = [labelGame frame].size;
-        NSRect const labelGameFrame = NSSizeAddXY(labelGameSize, 0, videoMode3DPUButtonFrame.origin.y - labelGameSize.height);
-        [labelGame setFrame:labelGameFrame];
-        [labelGame setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
-
-        CGFloat const gameListVerticalPadding = 3;
-        CGFloat const gameListY = NSTopEdge(alwaysShowButtonFrame) + gameListVerticalPadding;
-        NSRect const gameListFrame = NSMakeRect(0, gameListY, tabViewItemSetupFrame.size.width, labelGameFrame.origin.y - gameListY - gameListVerticalPadding);
-        gameList = [[NSScrollView alloc] initWithFrame:gameListFrame];
-        [[tabViewItemSetup view] addSubview:gameList];
-        [gameList setBorderType:NSBezelBorder];
-        [gameList setHasVerticalScroller:YES];
-        [gameList setHasHorizontalScroller:NO];
-        setControlToSmall([[gameList verticalScroller] cell]);
-        NSSize const gameListContentSize = [gameList contentSize];
-        [gameList setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
-
-        NSTableView * gameListTable = [[NSTableView alloc] initWithFrame:NSMakeRect(0, 0, gameListContentSize.width, gameListContentSize.height)];
-        [gameList setDocumentView:gameListTable];
-
-        NSTableColumn * nameColumn = [[NSTableColumn alloc] initWithIdentifier:@"0"];
-        [gameListTable addTableColumn:nameColumn];
-        NSTableColumn * fileColumn = [[NSTableColumn alloc] initWithIdentifier:@"1"];
-        [gameListTable addTableColumn:fileColumn];
-        [nameColumn setEditable:NO];
-        [[nameColumn headerCell] setStringValue:@"Name"];
-        [nameColumn setWidth:gameListContentSize.width * (2.f/3.f)];
-        [fileColumn setEditable:NO];
-        [[fileColumn headerCell] setStringValue:@"File"];
-        [gameListTable sizeLastColumnToFit];
-        [gameListTable setAutoresizingMask:NSViewWidthSizable];
-
-
-        // message log tab
-
-        tabViewItemMessageLog = [[NSTabViewItem alloc] init];
-        [tabView addTabViewItem:tabViewItemMessageLog];
-        [tabViewItemMessageLog setLabel:@"Message Log"];
-        NSRect const tabViewItemMessageLogFrame = [[tabViewItemMessageLog view] frame];
-
-
-        // message log
-        NSScrollView * messagesScrollView = [[NSScrollView alloc] initWithFrame:NSRectChangeXY(tabViewItemMessageLogFrame, 0, 0)];
-        [[tabViewItemMessageLog view] addSubview:messagesScrollView];
-        [messagesScrollView setBorderType:NSBezelBorder];
-        [messagesScrollView setHasVerticalScroller:YES];
-        [messagesScrollView setHasHorizontalScroller:NO];
-        setControlToSmall([[messagesScrollView verticalScroller] cell]);
-        NSSize const messagesScrollViewContentSize = [messagesScrollView contentSize];
-        [messagesScrollView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
-
-        messagesView = [[NSTextView alloc] initWithFrame:NSMakeRect(0, 0, messagesScrollViewContentSize.width, messagesScrollViewContentSize.height)];
-        [messagesScrollView setDocumentView:messagesView];
-        [messagesView setEditable:NO];
-        [messagesView setRichText:NO];
-        setFontToSmall(messagesView);
-        [messagesView setMinSize:NSMakeSize(0.0, messagesScrollViewContentSize.height)];
-        [messagesView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
-        [messagesView setVerticallyResizable:YES];
-        [messagesView setHorizontallyResizable:NO];
-        [messagesView setAutoresizingMask:NSViewWidthSizable];
-
-        [[messagesView textContainer] setContainerSize:NSMakeSize(messagesScrollViewContentSize.width, FLT_MAX)];
-        [[messagesView textContainer] setWidthTracksTextView:YES];
-    }
-
-    return self;
-}
-
-- (BOOL)canBecomeKeyWindow
-{
-    return YES;
-}
-
-- (BOOL)canBecomeMainWindow
-{
-    return YES;
-}
-
-- (BOOL) windowShouldClose:(id)sender
-{
-    UNREFERENCED_PARAMETER(sender);
-
-    retval = 0;
-
-    return YES;
-}
-
-- (void)dealloc
-{
-    [gamelistsrc release];
-    [modeslist3d release];
-    [super dealloc];
-}
-
-- (void)populateVideoModes:(BOOL)firstTime
-{
-    int i, mode3d, fullscreen = ([fullscreenButton state] == NSControlStateValueOn);
-    int idx3d = -1;
-    int xdim = 0, ydim = 0, bpp = 0;
-
-    if (firstTime) {
-        xdim = settings.xdim3d;
-        ydim = settings.ydim3d;
-        bpp  = settings.bpp3d;
-    } else {
-        mode3d = [[modeslist3d objectAtIndex:[videoMode3DPUButton indexOfSelectedItem]] intValue];
-        if (mode3d >= 0) {
-            xdim = validmode[mode3d].xdim;
-            ydim = validmode[mode3d].ydim;
-            bpp = validmode[mode3d].bpp;
-        }
-
-    }
-    mode3d = videoCheckMode(&xdim, &ydim, bpp, fullscreen, 1);
-    if (mode3d < 0) {
-        int i, cd[] = { 32, 24, 16, 15, 8, 0 };
-        for (i=0; cd[i]; ) { if (cd[i] >= bpp) i++; else break; }
-        for ( ; cd[i]; i++) {
-            mode3d = videoCheckMode(&xdim, &ydim, cd[i], fullscreen, 1);
-            if (mode3d < 0) continue;
-            break;
-        }
-    }
-
-    [modeslist3d release];
-    [videoMode3DPUButton removeAllItems];
-
-    modeslist3d = [[NSMutableArray alloc] init];
-
-    for (i = 0; i < validmodecnt; i++) {
-        if (fullscreen == validmode[i].fs) {
-            if (i == mode3d) idx3d = [modeslist3d count];
-            [modeslist3d addObject:[NSNumber numberWithInt:i]];
-            [videoMode3DPUButton addItemWithTitle:[NSString stringWithFormat:@"%d %C %d %d-bpp",
-                                                   validmode[i].xdim, 0xd7, validmode[i].ydim, validmode[i].bpp]];
-        }
-    }
-
-    if (idx3d >= 0) [videoMode3DPUButton selectItemAtIndex:idx3d];
-}
-
-- (void)fullscreenClicked:(id)sender
-{
-    UNREFERENCED_PARAMETER(sender);
-
-    [self populateVideoModes:NO];
-}
-
-- (void)cancel:(id)sender
-{
-    UNREFERENCED_PARAMETER(sender);
-
-    retval = 0;
-}
-
-- (void)start:(id)sender
-{
-    UNREFERENCED_PARAMETER(sender);
-
-    int mode = [[modeslist3d objectAtIndex:[videoMode3DPUButton indexOfSelectedItem]] intValue];
-    if (mode >= 0) {
-        settings.xdim3d = validmode[mode].xdim;
-        settings.ydim3d = validmode[mode].ydim;
-        settings.bpp3d = validmode[mode].bpp;
-        settings.fullscreen = validmode[mode].fs;
-    }
-
-    int row = [[gameList documentView] selectedRow];
-    if (row >= 0) {
-        settings.grp = [[gamelistsrc grpAtIndex:row] entryptr];
-    }
-
-    settings.forcesetup = [alwaysShowButton state] == NSControlStateValueOn;
-
-    retval = 1;
-}
-
-- (void)setupRunMode
-{
-    videoGetModes();
-
-    [fullscreenButton setState: (settings.fullscreen ? NSControlStateValueOn : NSControlStateValueOff)];
-    [alwaysShowButton setState: (settings.forcesetup ? NSControlStateValueOn : NSControlStateValueOff)];
-    [self populateVideoModes:YES];
-
-    // enable all the controls on the Configuration page
-    NSEnumerator *enumerator = [[[tabViewItemSetup view] subviews] objectEnumerator];
-    NSControl *control;
-    while ((control = [enumerator nextObject]))
-    {
-        if ([control respondsToSelector:@selector(setEnabled:)])
-            [control setEnabled:true];
-    }
-
-    gamelistsrc = [[GameListSource alloc] init];
-    [[gameList documentView] setDataSource:gamelistsrc];
-    [[gameList documentView] deselectAll:nil];
-
-    if (settings.grp)
-    {
-        int row = [gamelistsrc findIndexForGrpname:[NSString stringWithUTF8String:settings.grp->filename]];
-        if (row >= 0)
-        {
-            [[gameList documentView] scrollRowToVisible:row];
-#if defined MAC_OS_X_VERSION_10_3 && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3
-            [[gameList documentView] selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
-#else
-            [[gameList documentView] selectRow:row byExtendingSelection:NO];
-#endif
-        }
-    }
-
-    [cancelButton setEnabled:true];
-    [startButton setEnabled:true];
-
-    [tabView selectTabViewItem:tabViewItemSetup];
-    [NSCursor unhide]; // Why should I need to do this?
-}
-
-- (void)setupMessagesMode
-{
-    [tabView selectTabViewItem:tabViewItemMessageLog];
-
-    // disable all the controls on the Configuration page except "always show", so the
-    // user can enable it if they want to while waiting for something else to happen
-    NSEnumerator *enumerator = [[[tabViewItemSetup view] subviews] objectEnumerator];
-    NSControl *control;
-    while ((control = [enumerator nextObject]))
-    {
-        if (control != alwaysShowButton && [control respondsToSelector:@selector(setEnabled:)])
-            [control setEnabled:false];
-    }
-
-    [cancelButton setEnabled:false];
-    [startButton setEnabled:false];
-}
-
-- (void)putsMessage:(NSString *)str
-{
-    NSRange end;
-    NSTextStorage *text = [messagesView textStorage];
-    BOOL shouldAutoScroll;
-
-    shouldAutoScroll = ((int)NSMaxY([messagesView bounds]) == (int)NSMaxY([messagesView visibleRect]));
-
-    end.location = [text length];
-    end.length = 0;
-
-    [text beginEditing];
-    [messagesView replaceCharactersInRange:end withString:str];
-    [text endEditing];
-
-    if (shouldAutoScroll) {
-        end.location = [text length];
-        end.length = 0;
-        [messagesView scrollRangeToVisible:end];
-    }
-}
-
-@end
-
-static StartupWindow *startwin = nil;
-
-int startwin_open(void)
-{
-    // fix for "ld: absolute address to symbol _NSApp in a different linkage unit not supported"
-    // (OS X 10.6) when building for PPC
-    nsapp = [NSApplication sharedApplication];
-
-    if (startwin != nil) return 1;
-
-    startwin = [[StartupWindow alloc] init];
-    if (startwin == nil) return -1;
-
-    [startwin setupMessagesMode];
-
-    [nsapp finishLaunching];
-
-    [startwin center];
-    [startwin makeKeyAndOrderFront:nil];
-
-    CreateApplicationMenus();
-
-    return 0;
-}
-
-int startwin_close(void)
-{
-    if (startwin == nil) return 1;
-
-    [startwin close];
-    [startwin release];
-    startwin = nil;
-
-    return 0;
-}
-
-int startwin_puts(const char *s)
-{
-    NSString *ns;
-
-    if (!s) return -1;
-    if (startwin == nil) return 1;
-
-    ns = [NSString stringWithUTF8String:s];
-    [startwin putsMessage:ns];
-    [ns release];
-
-    return 0;
-}
-
-int startwin_settitle(const char *s)
-{
-    NSString *ns;
-
-    if (!s) return -1;
-    if (startwin == nil) return 1;
-
-    ns = [NSString stringWithUTF8String:s];
-    [startwin setTitle:ns];
-    [ns release];
-
-    return 0;
-}
-
-int startwin_idle(void *v)
-{
-    UNREFERENCED_PARAMETER(v);
-
-    if (startwin)
-    {
-        NSEvent *event;
-        do
-        {
-            event = [nsapp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate date] inMode:NSDefaultRunLoopMode dequeue:YES];
-            [nsapp sendEvent:event];
-        }
-        while (event != nil);
-
-        [startwin displayIfNeeded];
-        [nsapp updateWindows];
-    }
-
-    return 0;
-}
-
-
-int startwin_run(void)
-{
-    if (startwin == nil) return 0;
-
-    settings.fullscreen = ud.setup.fullscreen;
-    settings.xdim3d = ud.setup.xdim;
-    settings.ydim3d = ud.setup.ydim;
-    settings.bpp3d = ud.setup.bpp;
-    settings.forcesetup = ud.setup.forcesetup;
-    settings.grp = g_selectedGrp;
-
-    [startwin setupRunMode];
-
-    do
-    {
-        NSEvent *event = [nsapp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantFuture] inMode:NSDefaultRunLoopMode dequeue:YES];
-        [nsapp sendEvent:event];
-        [nsapp updateWindows];
-    }
-    while (retval == -1);
-
-    [startwin setupMessagesMode];
-    [nsapp updateWindows];
-
-    if (retval) {
-        ud.setup.fullscreen = settings.fullscreen;
-        ud.setup.xdim = settings.xdim3d;
-        ud.setup.ydim = settings.ydim3d;
-        ud.setup.bpp = settings.bpp3d;
-        ud.setup.forcesetup = settings.forcesetup;
-        g_selectedGrp = settings.grp;
-    }
-
-    return retval;
-}
+
+#import <Cocoa/Cocoa.h>
+
+#include "ns.h"	// Must come before everything else!
+
+#include "duke3d.h"
+#include "game.h"
+#include "common.h"
+#include "common_game.h"
+#include "build.h"
+#include "compat.h"
+#include "baselayer.h"
+#include "grpscan.h"
+
+#import "GrpFile.game.h"
+#import "GameListSource.game.h"
+
+#ifndef MAC_OS_X_VERSION_10_5
+# define NSImageScaleNone NSScaleNone
+#endif
+
+#ifndef MAC_OS_X_VERSION_10_12
+# define NSEventModifierFlagOption NSAlternateKeyMask
+# define NSEventModifierFlagCommand NSCommandKeyMask
+# define NSEventMaskAny NSAnyEventMask
+# define NSWindowStyleMaskTitled NSTitledWindowMask
+# define NSWindowStyleMaskClosable NSClosableWindowMask
+# define NSWindowStyleMaskMiniaturizable NSMiniaturizableWindowMask
+# define NSWindowStyleMaskResizable NSResizableWindowMask
+# define NSAlertStyleInformational NSInformationalAlertStyle
+# define NSControlSizeSmall NSSmallControlSize
+#endif
+
+#ifndef MAC_OS_X_VERSION_10_14
+# define NSButtonTypeSwitch NSSwitchButton
+# define NSBezelStyleRounded NSRoundedBezelStyle
+# define NSControlStateValueOn NSOnState
+# define NSControlStateValueOff NSOffState
+#endif
+
+static NSRect NSRectChangeXY(NSRect const rect, CGFloat const x, CGFloat const y)
+{
+    return NSMakeRect(x, y, rect.size.width, rect.size.height);
+}
+static NSRect NSSizeAddXY(NSSize const size, CGFloat const x, CGFloat const y)
+{
+    return NSMakeRect(x, y, size.width, size.height);
+}
+#if 0
+static CGFloat NSRightEdge(NSRect rect)
+{
+    return rect.origin.x + rect.size.width;
+}
+#endif
+static CGFloat NSTopEdge(NSRect rect)
+{
+    return rect.origin.y + rect.size.height;
+}
+
+static void setFontToSmall(id control)
+{
+    [control setFont:[NSFont fontWithDescriptor:[[control font] fontDescriptor] size:[NSFont smallSystemFontSize]]];
+}
+
+static void setControlToSmall(id control)
+{
+    [control setControlSize:NSControlSizeSmall];
+}
+
+static NSTextField * makeLabel(NSString * labelText)
+{
+    NSTextField *textField = [[NSTextField alloc] init];
+    setFontToSmall(textField);
+    setControlToSmall([textField cell]);
+    [textField setStringValue:labelText];
+    [textField setBezeled:NO];
+    [textField setDrawsBackground:NO];
+    [textField setEditable:NO];
+    [textField setSelectable:NO];
+    [textField sizeToFit];
+    return textField;
+}
+
+static NSButton * makeCheckbox(NSString * labelText)
+{
+    NSButton *checkbox = [[NSButton alloc] init];
+    setFontToSmall(checkbox);
+    setControlToSmall([checkbox cell]);
+    [checkbox setTitle:labelText];
+    [checkbox setButtonType:NSButtonTypeSwitch];
+    [checkbox sizeToFit];
+    return checkbox;
+}
+
+static NSPopUpButton * makeComboBox(void)
+{
+    NSPopUpButton *comboBox = [[NSPopUpButton alloc] init];
+    [comboBox setPullsDown:NO];
+    setFontToSmall(comboBox);
+    setControlToSmall([comboBox cell]);
+    [comboBox setBezelStyle:NSBezelStyleRounded];
+    [comboBox setPreferredEdge:NSMaxYEdge];
+    [[comboBox cell] setArrowPosition:NSPopUpArrowAtCenter];
+    [comboBox sizeToFit];
+    return comboBox;
+}
+
+static id nsapp;
+
+/* setAppleMenu disappeared from the headers in 10.4 */
+@interface NSApplication(NSAppleMenu)
+- (void)setAppleMenu:(NSMenu *)menu;
+@end
+
+static NSString * GetApplicationName(void)
+{
+    NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
+    if (!appName)
+        appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
+    if (![appName length])
+        appName = [[NSProcessInfo processInfo] processName];
+
+    return appName;
+}
+
+static void CreateApplicationMenus(void)
+{
+    NSString *appName;
+    NSString *title;
+    NSMenu *rootMenu;
+    NSMenu *serviceMenu;
+    NSMenuItem *menuItem;
+
+    NSMenu *mainMenu = [[NSMenu alloc] init];
+
+    /* Create the application menu */
+    appName = GetApplicationName();
+    rootMenu = [[NSMenu alloc] init];
+
+    /* Put menu into the menubar */
+    menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
+    [menuItem setSubmenu:rootMenu];
+    [mainMenu addItem:menuItem];
+    [menuItem release];
+
+    /* Add menu items */
+    title = [@"About " stringByAppendingString:appName];
+    [rootMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
+
+    [rootMenu addItem:[NSMenuItem separatorItem]];
+
+    serviceMenu = [[NSMenu alloc] init];
+    menuItem = (NSMenuItem *)[rootMenu addItemWithTitle:@"Services" action:nil keyEquivalent:@""];
+    [menuItem setSubmenu:serviceMenu];
+
+    [nsapp setServicesMenu:serviceMenu];
+    [serviceMenu release];
+
+    [rootMenu addItem:[NSMenuItem separatorItem]];
+
+    title = [@"Hide " stringByAppendingString:appName];
+    [rootMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
+
+    menuItem = (NSMenuItem *)[rootMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
+    [menuItem setKeyEquivalentModifierMask:(NSEventModifierFlagOption|NSEventModifierFlagCommand)];
+
+    [rootMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
+
+    [rootMenu addItem:[NSMenuItem separatorItem]];
+
+    title = [@"Quit " stringByAppendingString:appName];
+    [rootMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
+
+    /* Create the main menu bar */
+    [nsapp setMainMenu:mainMenu];
+    [mainMenu release];  /* we're done with it, let NSApp own it. */
+
+    /* Tell the application object that this is now the application menu */
+    [nsapp setAppleMenu:rootMenu];
+    [rootMenu release];
+}
+
+static int retval = -1;
+
+static struct {
+    grpfile_t const * grp;
+    int fullscreen;
+    int xdim3d, ydim3d, bpp3d;
+    int forcesetup;
+} settings;
+
+@interface StartupWindow : NSWindow <NSWindowDelegate>
+{
+    NSMutableArray *modeslist3d;
+    GameListSource *gamelistsrc;
+
+    NSButton *alwaysShowButton;
+    NSButton *fullscreenButton;
+    NSTextView *messagesView;
+    NSTabView *tabView;
+    NSTabViewItem *tabViewItemSetup;
+    NSTabViewItem *tabViewItemMessageLog;
+    NSPopUpButton *videoMode3DPUButton;
+    NSScrollView *gameList;
+
+    NSButton *cancelButton;
+    NSButton *startButton;
+}
+
+- (StartupWindow *)init;
+
+- (void)dealloc;
+- (void)populateVideoModes:(BOOL)firstTime;
+
+- (void)fullscreenClicked:(id)sender;
+
+- (void)cancel:(id)sender;
+- (void)start:(id)sender;
+
+- (void)setupRunMode;
+- (void)setupMessagesMode;
+
+- (void)putsMessage:(NSString *)str;
+
+@end
+
+@implementation StartupWindow : NSWindow
+
+- (StartupWindow *)init
+{
+    NSUInteger const style = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable;
+    NSRect const windowFrame = NSMakeRect(0, 0, 480, 280);
+    self = [super initWithContentRect:windowFrame styleMask:style backing:NSBackingStoreBuffered defer:NO];
+
+    if (self)
+    {
+        // window properties
+        [self setDelegate:self];
+        [self setReleasedWhenClosed:NO];
+#if defined MAC_OS_X_VERSION_10_3 && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3
+        [self setContentMinSize:[[self contentView] frame].size];
+#else
+        [self setMinSize:[NSWindow frameRectForContentRect:[[self contentView] frame] styleMask:[self styleMask]].size];
+#endif
+
+
+        // image on the left
+        NSRect const imageFrame = NSMakeRect(0, 0, 100, 280);
+        NSImageView * imageView = [[NSImageView alloc] initWithFrame:imageFrame];
+        [imageView setImageScaling:NSImageScaleNone];
+        [imageView setImage:[NSImage imageNamed:@"game"]];
+        [[self contentView] addSubview:imageView];
+        [imageView setAutoresizingMask:NSViewMaxXMargin | NSViewHeightSizable];
+
+
+        // buttons
+        CGFloat const buttonWidth = 80;
+        CGFloat const buttonHeight = 32;
+
+        NSRect const startButtonFrame = NSMakeRect(windowFrame.size.width - buttonWidth, 0, buttonWidth, buttonHeight);
+        startButton = [[NSButton alloc] initWithFrame:startButtonFrame];
+        [[self contentView] addSubview:startButton];
+        [startButton setTitle:@"Start"];
+        [startButton setTarget:self];
+        [startButton setAction:@selector(start:)];
+        [startButton setBezelStyle:NSBezelStyleRounded];
+        [startButton setKeyEquivalent:@"\r"];
+        [startButton setAutoresizingMask:NSViewMinXMargin | NSViewMaxYMargin];
+
+        NSRect const cancelButtonFrame = NSMakeRect(startButtonFrame.origin.x - buttonWidth, 0, buttonWidth, buttonHeight);
+        cancelButton = [[NSButton alloc] initWithFrame:cancelButtonFrame];
+        [[self contentView] addSubview:cancelButton];
+        [cancelButton setTitle:@"Cancel"];
+        [cancelButton setTarget:self];
+        [cancelButton setAction:@selector(cancel:)];
+        [cancelButton setBezelStyle:NSBezelStyleRounded];
+        [cancelButton setAutoresizingMask:NSViewMinXMargin | NSViewMaxYMargin];
+
+
+        // tab frame
+        NSRect const tabViewFrame = NSMakeRect(imageFrame.size.width, buttonHeight, windowFrame.size.width - imageFrame.size.width, windowFrame.size.height - buttonHeight - 5);
+        tabView = [[NSTabView alloc] initWithFrame:tabViewFrame];
+        [[self contentView] addSubview:tabView];
+        setFontToSmall(tabView);
+        setControlToSmall(tabView);
+        [tabView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+
+
+        // setup tab
+
+        tabViewItemSetup = [[NSTabViewItem alloc] init];
+        [tabView addTabViewItem:tabViewItemSetup];
+        [tabViewItemSetup setLabel:@"Setup"];
+        NSRect const tabViewItemSetupFrame = [[tabViewItemSetup view] frame];
+
+
+        // always show checkbox
+        alwaysShowButton = makeCheckbox(@"Always show this window at startup");
+        [[tabViewItemSetup view] addSubview:alwaysShowButton];
+        NSSize const alwaysShowButtonSize = [alwaysShowButton frame].size;
+        NSRect const alwaysShowButtonFrame = NSSizeAddXY(alwaysShowButtonSize, tabViewItemSetupFrame.size.width - alwaysShowButtonSize.width, 0);
+        [alwaysShowButton setFrame:alwaysShowButtonFrame];
+        [alwaysShowButton setAutoresizingMask:NSViewMinXMargin | NSViewMaxYMargin];
+
+
+        // video mode selectors and labels
+        NSTextField * labelVideoMode = makeLabel(@"Video mode:");
+        [[tabViewItemSetup view] addSubview:labelVideoMode];
+        NSSize const labelVideoModeSize = [labelVideoMode frame].size;
+        [labelVideoMode setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
+
+        fullscreenButton = makeCheckbox(@"Fullscreen");
+        [[tabViewItemSetup view] addSubview:fullscreenButton];
+        NSSize const fullscreenButtonSize = [fullscreenButton frame].size;
+        [fullscreenButton setAction:@selector(fullscreenClicked:)];
+        [fullscreenButton setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
+
+        videoMode3DPUButton = makeComboBox();
+        [[tabViewItemSetup view] addSubview:videoMode3DPUButton];
+        NSSize const videoMode3DPUButtonSize = [videoMode3DPUButton frame].size;
+        CGFloat const videoMode3DButtonX = labelVideoModeSize.width; // NSRightEdge(labelVideoModeFrame);
+        NSRect const videoMode3DPUButtonFrame = NSMakeRect(videoMode3DButtonX, tabViewItemSetupFrame.size.height - videoMode3DPUButtonSize.height, tabViewItemSetupFrame.size.width - videoMode3DButtonX - fullscreenButtonSize.width, videoMode3DPUButtonSize.height);
+        [videoMode3DPUButton setFrame:videoMode3DPUButtonFrame];
+        [videoMode3DPUButton setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin];
+
+        NSRect const labelVideoModeFrame = NSSizeAddXY(labelVideoModeSize, 0, videoMode3DPUButtonFrame.origin.y + rintf((videoMode3DPUButtonSize.height - labelVideoModeSize.height) * 0.5f) + 1);
+        [labelVideoMode setFrame:labelVideoModeFrame];
+
+        NSRect const fullscreenButtonFrame = NSSizeAddXY(fullscreenButtonSize, tabViewItemSetupFrame.size.width - fullscreenButtonSize.width, videoMode3DPUButtonFrame.origin.y + rintf((videoMode3DPUButtonSize.height - fullscreenButtonSize.height) * 0.5f) + 1);
+        [fullscreenButton setFrame:fullscreenButtonFrame];
+
+
+        // game selector and label
+        NSTextField * labelGame = makeLabel(@"Game:");
+        [[tabViewItemSetup view] addSubview:labelGame];
+        NSSize const labelGameSize = [labelGame frame].size;
+        NSRect const labelGameFrame = NSSizeAddXY(labelGameSize, 0, videoMode3DPUButtonFrame.origin.y - labelGameSize.height);
+        [labelGame setFrame:labelGameFrame];
+        [labelGame setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
+
+        CGFloat const gameListVerticalPadding = 3;
+        CGFloat const gameListY = NSTopEdge(alwaysShowButtonFrame) + gameListVerticalPadding;
+        NSRect const gameListFrame = NSMakeRect(0, gameListY, tabViewItemSetupFrame.size.width, labelGameFrame.origin.y - gameListY - gameListVerticalPadding);
+        gameList = [[NSScrollView alloc] initWithFrame:gameListFrame];
+        [[tabViewItemSetup view] addSubview:gameList];
+        [gameList setBorderType:NSBezelBorder];
+        [gameList setHasVerticalScroller:YES];
+        [gameList setHasHorizontalScroller:NO];
+        setControlToSmall([[gameList verticalScroller] cell]);
+        NSSize const gameListContentSize = [gameList contentSize];
+        [gameList setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+
+        NSTableView * gameListTable = [[NSTableView alloc] initWithFrame:NSMakeRect(0, 0, gameListContentSize.width, gameListContentSize.height)];
+        [gameList setDocumentView:gameListTable];
+
+        NSTableColumn * nameColumn = [[NSTableColumn alloc] initWithIdentifier:@"0"];
+        [gameListTable addTableColumn:nameColumn];
+        NSTableColumn * fileColumn = [[NSTableColumn alloc] initWithIdentifier:@"1"];
+        [gameListTable addTableColumn:fileColumn];
+        [nameColumn setEditable:NO];
+        [[nameColumn headerCell] setStringValue:@"Name"];
+        [nameColumn setWidth:gameListContentSize.width * (2.f/3.f)];
+        [fileColumn setEditable:NO];
+        [[fileColumn headerCell] setStringValue:@"File"];
+        [gameListTable sizeLastColumnToFit];
+        [gameListTable setAutoresizingMask:NSViewWidthSizable];
+
+
+        // message log tab
+
+        tabViewItemMessageLog = [[NSTabViewItem alloc] init];
+        [tabView addTabViewItem:tabViewItemMessageLog];
+        [tabViewItemMessageLog setLabel:@"Message Log"];
+        NSRect const tabViewItemMessageLogFrame = [[tabViewItemMessageLog view] frame];
+
+
+        // message log
+        NSScrollView * messagesScrollView = [[NSScrollView alloc] initWithFrame:NSRectChangeXY(tabViewItemMessageLogFrame, 0, 0)];
+        [[tabViewItemMessageLog view] addSubview:messagesScrollView];
+        [messagesScrollView setBorderType:NSBezelBorder];
+        [messagesScrollView setHasVerticalScroller:YES];
+        [messagesScrollView setHasHorizontalScroller:NO];
+        setControlToSmall([[messagesScrollView verticalScroller] cell]);
+        NSSize const messagesScrollViewContentSize = [messagesScrollView contentSize];
+        [messagesScrollView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+
+        messagesView = [[NSTextView alloc] initWithFrame:NSMakeRect(0, 0, messagesScrollViewContentSize.width, messagesScrollViewContentSize.height)];
+        [messagesScrollView setDocumentView:messagesView];
+        [messagesView setEditable:NO];
+        [messagesView setRichText:NO];
+        setFontToSmall(messagesView);
+        [messagesView setMinSize:NSMakeSize(0.0, messagesScrollViewContentSize.height)];
+        [messagesView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
+        [messagesView setVerticallyResizable:YES];
+        [messagesView setHorizontallyResizable:NO];
+        [messagesView setAutoresizingMask:NSViewWidthSizable];
+
+        [[messagesView textContainer] setContainerSize:NSMakeSize(messagesScrollViewContentSize.width, FLT_MAX)];
+        [[messagesView textContainer] setWidthTracksTextView:YES];
+    }
+
+    return self;
+}
+
+- (BOOL)canBecomeKeyWindow
+{
+    return YES;
+}
+
+- (BOOL)canBecomeMainWindow
+{
+    return YES;
+}
+
+- (BOOL) windowShouldClose:(id)sender
+{
+    UNREFERENCED_PARAMETER(sender);
+
+    retval = 0;
+
+    return YES;
+}
+
+- (void)dealloc
+{
+    [gamelistsrc release];
+    [modeslist3d release];
+    [super dealloc];
+}
+
+- (void)populateVideoModes:(BOOL)firstTime
+{
+    int i, mode3d, fullscreen = ([fullscreenButton state] == NSControlStateValueOn);
+    int idx3d = -1;
+    int xdim = 0, ydim = 0, bpp = 0;
+
+    if (firstTime) {
+        xdim = settings.xdim3d;
+        ydim = settings.ydim3d;
+        bpp  = settings.bpp3d;
+    } else {
+        mode3d = [[modeslist3d objectAtIndex:[videoMode3DPUButton indexOfSelectedItem]] intValue];
+        if (mode3d >= 0) {
+            xdim = validmode[mode3d].xdim;
+            ydim = validmode[mode3d].ydim;
+            bpp = validmode[mode3d].bpp;
+        }
+
+    }
+    mode3d = videoCheckMode(&xdim, &ydim, bpp, fullscreen, 1);
+    if (mode3d < 0) {
+        int i, cd[] = { 32, 24, 16, 15, 8, 0 };
+        for (i=0; cd[i]; ) { if (cd[i] >= bpp) i++; else break; }
+        for ( ; cd[i]; i++) {
+            mode3d = videoCheckMode(&xdim, &ydim, cd[i], fullscreen, 1);
+            if (mode3d < 0) continue;
+            break;
+        }
+    }
+
+    [modeslist3d release];
+    [videoMode3DPUButton removeAllItems];
+
+    modeslist3d = [[NSMutableArray alloc] init];
+
+    for (i = 0; i < validmodecnt; i++) {
+        if (fullscreen == validmode[i].fs) {
+            if (i == mode3d) idx3d = [modeslist3d count];
+            [modeslist3d addObject:[NSNumber numberWithInt:i]];
+            [videoMode3DPUButton addItemWithTitle:[NSString stringWithFormat:@"%d %C %d %d-bpp",
+                                                   validmode[i].xdim, 0xd7, validmode[i].ydim, validmode[i].bpp]];
+        }
+    }
+
+    if (idx3d >= 0) [videoMode3DPUButton selectItemAtIndex:idx3d];
+}
+
+- (void)fullscreenClicked:(id)sender
+{
+    UNREFERENCED_PARAMETER(sender);
+
+    [self populateVideoModes:NO];
+}
+
+- (void)cancel:(id)sender
+{
+    UNREFERENCED_PARAMETER(sender);
+
+    retval = 0;
+}
+
+- (void)start:(id)sender
+{
+    UNREFERENCED_PARAMETER(sender);
+
+    int mode = [[modeslist3d objectAtIndex:[videoMode3DPUButton indexOfSelectedItem]] intValue];
+    if (mode >= 0) {
+        settings.xdim3d = validmode[mode].xdim;
+        settings.ydim3d = validmode[mode].ydim;
+        settings.bpp3d = validmode[mode].bpp;
+        settings.fullscreen = validmode[mode].fs;
+    }
+
+    int row = [[gameList documentView] selectedRow];
+    if (row >= 0) {
+        settings.grp = [[gamelistsrc grpAtIndex:row] entryptr];
+    }
+
+    settings.forcesetup = [alwaysShowButton state] == NSControlStateValueOn;
+
+    retval = 1;
+}
+
+- (void)setupRunMode
+{
+    videoGetModes();
+
+    [fullscreenButton setState: (settings.fullscreen ? NSControlStateValueOn : NSControlStateValueOff)];
+    [alwaysShowButton setState: (settings.forcesetup ? NSControlStateValueOn : NSControlStateValueOff)];
+    [self populateVideoModes:YES];
+
+    // enable all the controls on the Configuration page
+    NSEnumerator *enumerator = [[[tabViewItemSetup view] subviews] objectEnumerator];
+    NSControl *control;
+    while ((control = [enumerator nextObject]))
+    {
+        if ([control respondsToSelector:@selector(setEnabled:)])
+            [control setEnabled:true];
+    }
+
+    gamelistsrc = [[GameListSource alloc] init];
+    [[gameList documentView] setDataSource:gamelistsrc];
+    [[gameList documentView] deselectAll:nil];
+
+    if (settings.grp)
+    {
+        int row = [gamelistsrc findIndexForGrpname:[NSString stringWithUTF8String:settings.grp->filename]];
+        if (row >= 0)
+        {
+            [[gameList documentView] scrollRowToVisible:row];
+#if defined MAC_OS_X_VERSION_10_3 && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3
+            [[gameList documentView] selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
+#else
+            [[gameList documentView] selectRow:row byExtendingSelection:NO];
+#endif
+        }
+    }
+
+    [cancelButton setEnabled:true];
+    [startButton setEnabled:true];
+
+    [tabView selectTabViewItem:tabViewItemSetup];
+    [NSCursor unhide]; // Why should I need to do this?
+}
+
+- (void)setupMessagesMode
+{
+    [tabView selectTabViewItem:tabViewItemMessageLog];
+
+    // disable all the controls on the Configuration page except "always show", so the
+    // user can enable it if they want to while waiting for something else to happen
+    NSEnumerator *enumerator = [[[tabViewItemSetup view] subviews] objectEnumerator];
+    NSControl *control;
+    while ((control = [enumerator nextObject]))
+    {
+        if (control != alwaysShowButton && [control respondsToSelector:@selector(setEnabled:)])
+            [control setEnabled:false];
+    }
+
+    [cancelButton setEnabled:false];
+    [startButton setEnabled:false];
+}
+
+- (void)putsMessage:(NSString *)str
+{
+    NSRange end;
+    NSTextStorage *text = [messagesView textStorage];
+    BOOL shouldAutoScroll;
+
+    shouldAutoScroll = ((int)NSMaxY([messagesView bounds]) == (int)NSMaxY([messagesView visibleRect]));
+
+    end.location = [text length];
+    end.length = 0;
+
+    [text beginEditing];
+    [messagesView replaceCharactersInRange:end withString:str];
+    [text endEditing];
+
+    if (shouldAutoScroll) {
+        end.location = [text length];
+        end.length = 0;
+        [messagesView scrollRangeToVisible:end];
+    }
+}
+
+@end
+
+static StartupWindow *startwin = nil;
+
+int startwin_open(void)
+{
+    // fix for "ld: absolute address to symbol _NSApp in a different linkage unit not supported"
+    // (OS X 10.6) when building for PPC
+    nsapp = [NSApplication sharedApplication];
+
+    if (startwin != nil) return 1;
+
+    startwin = [[StartupWindow alloc] init];
+    if (startwin == nil) return -1;
+
+    [startwin setupMessagesMode];
+
+    [nsapp finishLaunching];
+
+    [startwin center];
+    [startwin makeKeyAndOrderFront:nil];
+
+    CreateApplicationMenus();
+
+    return 0;
+}
+
+int startwin_close(void)
+{
+    if (startwin == nil) return 1;
+
+    [startwin close];
+    [startwin release];
+    startwin = nil;
+
+    return 0;
+}
+
+int startwin_puts(const char *s)
+{
+    NSString *ns;
+
+    if (!s) return -1;
+    if (startwin == nil) return 1;
+
+    ns = [NSString stringWithUTF8String:s];
+    [startwin putsMessage:ns];
+    [ns release];
+
+    return 0;
+}
+
+int startwin_settitle(const char *s)
+{
+    NSString *ns;
+
+    if (!s) return -1;
+    if (startwin == nil) return 1;
+
+    ns = [NSString stringWithUTF8String:s];
+    [startwin setTitle:ns];
+    [ns release];
+
+    return 0;
+}
+
+int startwin_idle(void *v)
+{
+    UNREFERENCED_PARAMETER(v);
+
+    if (startwin)
+    {
+        NSEvent *event;
+        do
+        {
+            event = [nsapp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate date] inMode:NSDefaultRunLoopMode dequeue:YES];
+            [nsapp sendEvent:event];
+        }
+        while (event != nil);
+
+        [startwin displayIfNeeded];
+        [nsapp updateWindows];
+    }
+
+    return 0;
+}
+
+
+int startwin_run(void)
+{
+    if (startwin == nil) return 0;
+
+    settings.fullscreen = ud.setup.fullscreen;
+    settings.xdim3d = ud.setup.xdim;
+    settings.ydim3d = ud.setup.ydim;
+    settings.bpp3d = ud.setup.bpp;
+    settings.forcesetup = ud.setup.forcesetup;
+    settings.grp = g_selectedGrp;
+
+    [startwin setupRunMode];
+
+    do
+    {
+        NSEvent *event = [nsapp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantFuture] inMode:NSDefaultRunLoopMode dequeue:YES];
+        [nsapp sendEvent:event];
+        [nsapp updateWindows];
+    }
+    while (retval == -1);
+
+    [startwin setupMessagesMode];
+    [nsapp updateWindows];
+
+    if (retval) {
+        ud.setup.fullscreen = settings.fullscreen;
+        ud.setup.xdim = settings.xdim3d;
+        ud.setup.ydim = settings.ydim3d;
+        ud.setup.bpp = settings.bpp3d;
+        ud.setup.forcesetup = settings.forcesetup;
+        g_selectedGrp = settings.grp;
+    }
+
+    return retval;
+}
diff --git a/source/duke3d/src/startwin.game.cpp b/source/platform/win32/startwin.game.cpp
similarity index 90%
rename from source/duke3d/src/startwin.game.cpp
rename to source/platform/win32/startwin.game.cpp
index 9feae5aee..09ca3e33b 100644
--- a/source/duke3d/src/startwin.game.cpp
+++ b/source/platform/win32/startwin.game.cpp
@@ -37,22 +37,15 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 #include "_control.h"
 #include "build.h"
 #include "cache1d.h"
-#include "cmdline.h"
-#include "common_game.h"
 #include "compat.h"
 #include "control.h"
-#include "gamecontrol.h"
-#include "game.h"
-#include "grpscan.h"
-#include "inv.h"
 #include "keyboard.h"
 #include "startwin.game.h"
 #include "windows_inc.h"
-#include "gamecvars.h"
+#include "gamecontrol.h"
 
 #pragma warning(disable:4244) // There's just a bit too much of these in here...
 
-BEGIN_DUKE_NS
 
 
 #define TAB_CONFIG 0
@@ -67,8 +60,7 @@ typedef struct {
 
 static struct
 {
-    struct grpfile_t const * grp;
-    char *gamedir;
+    int grp;
     ud_setup_t shared;
     int polymer;
 }
@@ -79,6 +71,8 @@ static HWND pages[3];
 static int done = -1;
 static int mode = TAB_CONFIG;
 
+static TArray<GrpEntry> *gamedata;
+
 static CACHE1D_FIND_REC *finddirs;
 
 static inline void clearfilenames(void)
@@ -121,6 +115,7 @@ static void PopulateForm(int32_t pgs)
     {
         HWND hwnd = GetDlgItem(pages[TAB_CONFIG], IDCGAMEDIR);
 
+#if 0 // This doesn't currently work and in its current form is useless anyway. It should offer a real directory picker.
         getfilenames("/");
         (void)ComboBox_ResetContent(hwnd);
         int const r = ComboBox_AddString(hwnd, "None");
@@ -137,12 +132,11 @@ static void PopulateForm(int32_t pgs)
 
             (void)ComboBox_AddString(hwnd, dirs->name);
             (void)ComboBox_SetItemData(hwnd, i, j);
-            if (Bstrcasecmp(dirs->name, settings.gamedir) == 0)
-                (void)ComboBox_SetCurSel(hwnd, i);
 
             i++;
             j++;
         }
+#endif
     }
 
     if (pgs & POPULATE_VIDEO)
@@ -150,7 +144,7 @@ static void PopulateForm(int32_t pgs)
         HWND hwnd = GetDlgItem(pages[TAB_CONFIG], IDCVMODE);
         int mode = videoCheckMode(&settings.shared.xdim, &settings.shared.ydim, settings.shared.bpp, settings.shared.fullscreen, 1);
 
-        if (mode < 0 || (settings.shared.bpp < 15 && (settings.polymer)))
+        if (mode < 0 || (settings.shared.bpp < 15))
         {
             int CONSTEXPR cd[] = { 32, 24, 16, 15, 8, 0 };
             int i;
@@ -177,7 +171,7 @@ static void PopulateForm(int32_t pgs)
         for (int i=0; i<validmodecnt; i++)
         {
             if (validmode[i].fs != (settings.shared.fullscreen)) continue;
-            if ((validmode[i].bpp < 15) && (settings.polymer)) continue;
+            if ((validmode[i].bpp < 15)) continue;
 
             // all modes get added to the 3D mode list
             Bsprintf(buf, "%dx%d %s", validmode[i].xdim, validmode[i].ydim, validmode[i].bpp == 8 ? "software" : "OpenGL");
@@ -192,13 +186,13 @@ static void PopulateForm(int32_t pgs)
     {
         HWND hwnd = GetDlgItem(pages[TAB_CONFIG], IDCDATA);
 
-        for (auto fg = foundgrps; fg; fg=fg->next)
-        {
-            Bsprintf(buf, "%s\t%s", fg->type->name, fg->filename);
-            int const j = ListBox_AddString(hwnd, buf);
-            (void)ListBox_SetItemData(hwnd, j, (LPARAM)fg);
-            if (settings.grp == fg)
-                (void)ListBox_SetCurSel(hwnd, j);
+		int i=0;
+		for (auto& grp : *gamedata)
+		{
+			FStringf grpinfo("%s %s", grp.FileInfo.name.GetChars(), grp.FileName.GetChars());
+            int const j = ListBox_AddString(hwnd, grpinfo.GetChars());
+            (void)ListBox_SetItemData(hwnd, j, i);
+			i++;
         }
     }
 }
@@ -239,28 +233,6 @@ static INT_PTR CALLBACK ConfigPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, L
             noautoload = (IsDlgButtonChecked(hwndDlg, IDCAUTOLOAD) != BST_CHECKED);
             return TRUE;
         case IDCGAMEDIR:
-            if (HIWORD(wParam) == CBN_SELCHANGE)
-            {
-                int i = ComboBox_GetCurSel((HWND)lParam);
-                if (i != CB_ERR) i = ComboBox_GetItemData((HWND)lParam, i);
-                if (i != CB_ERR)
-                {
-                    if (i==0)
-                        settings.gamedir = NULL;
-                    else
-                    {
-                        CACHE1D_FIND_REC *dir = finddirs;
-                        for (int j = 1; dir != NULL; dir = dir->next, j++)
-                        {
-                            if (j == i)
-                            {
-                                settings.gamedir = dir->name;
-                                break;
-                            }
-                        }
-                    }
-                }
-            }
             return TRUE;
         case IDCDATA:
         {
@@ -269,7 +241,7 @@ static INT_PTR CALLBACK ConfigPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, L
             if (i != CB_ERR) i = ListBox_GetItemData((HWND)lParam, i);
             if (i != CB_ERR)
             {
-                settings.grp = (grpfile_t const *)i;
+                settings.grp = i;
             }
             return TRUE;
         }
@@ -619,15 +591,8 @@ int32_t startwin_run(void)
     SetPage(TAB_CONFIG);
     EnableConfig(1);
 
-#ifdef POLYMER
-    settings.polymer = (glrendmode == REND_POLYMER);
-#else
-    settings.polymer = 0;
-#endif
-
 	settings.shared = { ScreenMode, ScreenWidth, ScreenHeight, ScreenBPP };
-	settings.grp = g_selectedGrp;
-    settings.gamedir = g_modDir;
+	settings.grp = 0;
 
     PopulateForm(-1);
 
@@ -661,14 +626,28 @@ int32_t startwin_run(void)
 		ScreenHeight = settings.shared.ydim;
 		ScreenMode = settings.shared.fullscreen;
 		ScreenBPP = settings.shared.bpp;
-		g_selectedGrp = settings.grp;
-        Bstrcpy(g_modDir, (g_noSetup == 0 && settings.gamedir != NULL) ? settings.gamedir : "/");
     }
 
     return done;
 }
 
-END_DUKE_NS
+int ShowStartupWindow(TArray<GrpEntry> &groups)
+{
+	gamedata = &groups;
+	startwin_open();
+	startwin_settitle("Demolition");
+
+	if (1)//readSetup < 0 || (!g_noSetup && (displaysetup)) || g_commandSetup)
+	{
+		auto choice = startwin_run();
+		if (choice == 0)
+		{
+			Bexit(EXIT_SUCCESS);
+		}
+	}
+	startwin_close();
+	return settings.grp;
+}
 
 #endif // STARTUP_SETUP_WINDOW
 
diff --git a/source/rr/CMakeLists.txt b/source/rr/CMakeLists.txt
index 609bfc634..5bd82ab22 100644
--- a/source/rr/CMakeLists.txt
+++ b/source/rr/CMakeLists.txt
@@ -26,12 +26,6 @@ include_directories(
 )
 
 
-if (WIN32)
-set( PLAT_SOURCES
-	src/startwin.game.cpp
-	)
-endif()
-	
 set( NOT_COMPILED_SOURCE_FILES
 )
 	
@@ -82,7 +76,6 @@ file( GLOB HEADER_FILES
 add_library( rr STATIC
 	${HEADER_FILES}
 	${PCH_SOURCES}
-	${PLAT_SOURCES}
 	${NOT_COMPILED_SOURCE_FILES}
 	)
 
diff --git a/source/rr/src/common.cpp b/source/rr/src/common.cpp
index d52d88dee..92392a515 100644
--- a/source/rr/src/common.cpp
+++ b/source/rr/src/common.cpp
@@ -11,20 +11,8 @@
 #include "grpscan.h"
 #include "gamecvars.h"
 #include "rts.h"
+#include "gamecontrol.h"
 
-#ifdef _WIN32
-# define NEED_SHLWAPI_H
-# include "windows_inc.h"
-# include "win32/winbits.h"
-# ifndef KEY_WOW64_64KEY
-#  define KEY_WOW64_64KEY 0x0100
-# endif
-# ifndef KEY_WOW64_32KEY
-#  define KEY_WOW64_32KEY 0x0200
-# endif
-#elif defined __APPLE__
-# include "osxbits.h"
-#endif
 
 #include "common.h"
 #include "common_game.h"
@@ -47,24 +35,7 @@ static const char *defaultgamegrp[GAMECOUNT]         = { "DUKE3D.GRP", "REDNECK.
 static const char *defaultdeffilename[GAMECOUNT]     = { "duke3d.def", "rr.def", "rrra.def", "nam.def", "napalm.grp" };
 static const char *defaultgameconfilename[GAMECOUNT] = { "GAME.CON", "GAME.CON", "GAME.CON", "NAM.CON", "NAPALM.CON" };
 
-// g_grpNamePtr can ONLY point to a malloc'd block (length BMAX_PATH)
-char *g_grpNamePtr = NULL;
-// g_scriptNamePtr can ONLY point to a malloc'd block (length BMAX_PATH)
-char *g_scriptNamePtr = NULL;
-
-void clearGrpNamePtr(void)
-{
-    Bfree(g_grpNamePtr);
-    // g_grpNamePtr assumed to be assigned to right after
-}
-
-void clearScriptNamePtr(void)
-{
-    Bfree(g_scriptNamePtr);
-    // g_scriptNamePtr assumed to be assigned to right after
-}
-
-const char *G_DefaultGrpFile(void)
+const char* G_DefaultGrpFile(void)
 {
     if (DUKE)
         return defaultgamegrp[GAME_DUKE];
@@ -73,7 +44,8 @@ const char *G_DefaultGrpFile(void)
 
     return defaultgamegrp[0];
 }
-const char *G_DefaultDefFile(void)
+
+const char* G_DefaultDefFile(void)
 {
     if (DUKE)
         return defaultdeffilename[GAME_DUKE];
@@ -115,17 +87,17 @@ const char *G_DefaultConFile(void)
 
 const char *G_GrpFile(void)
 {
-    return (g_grpNamePtr == NULL) ? G_DefaultGrpFile() : g_grpNamePtr;
+    return userConfig.gamegrp.IsNotEmpty()? userConfig.gamegrp.GetChars() : G_DefaultGrpFile();
 }
 
 const char *G_DefFile(void)
 {
-    return (g_defNamePtr == NULL) ? G_DefaultDefFile() : g_defNamePtr;
+	return userConfig.DefaultDef.IsNotEmpty() ? userConfig.DefaultDef.GetChars() : G_DefaultDefFile();
 }
 
 const char *G_ConFile(void)
 {
-    return (g_scriptNamePtr == NULL) ? G_DefaultConFile() : g_scriptNamePtr;
+	return userConfig.DefaultCon.IsNotEmpty() ? userConfig.DefaultCon.GetChars() : G_DefaultConFile();
 }
 
 //////////
@@ -213,62 +185,7 @@ void G_SetupGlobalPsky(void)
 
 static void G_LoadAddon(void);
 int32_t g_groupFileHandle;
-struct strllist* CommandPaths, * CommandGrps;
-
-void G_ExtInit(void)
-{
-    char cwd[BMAX_PATH];
-
-#ifdef EDUKE32_OSX
-    char *appdir = Bgetappdir();
-    addsearchpath(appdir);
-    Bfree(appdir);
-#endif
-
-    if (getcwd(cwd,BMAX_PATH) && Bstrcmp(cwd,"/") != 0)
-        addsearchpath(cwd);
-
-    if (CommandPaths)
-    {
-        int32_t i;
-        struct strllist *s;
-        while (CommandPaths)
-        {
-            s = CommandPaths->next;
-            i = addsearchpath(CommandPaths->str);
-            if (i < 0)
-            {
-                initprintf("Failed adding %s for game data: %s\n", CommandPaths->str,
-                           i==-1 ? "not a directory" : "no such directory");
-            }
-
-            Bfree(CommandPaths->str);
-            Bfree(CommandPaths);
-            CommandPaths = s;
-        }
-    }
-}
-
-void G_ScanGroups(void)
-{
-    ScanGroups();
-
-    g_selectedGrp = NULL;
-
-    char const * const currentGrp = G_GrpFile();
-
-    for (grpfile_t const *fg = foundgrps; fg; fg=fg->next)
-    {
-        if (!Bstrcasecmp(fg->filename, currentGrp))
-        {
-            g_selectedGrp = fg;
-            break;
-        }
-    }
-
-    if (g_selectedGrp == NULL)
-        g_selectedGrp = foundgrps;
-}
+struct strllist* CommandGrps;
 
 static int32_t G_TryLoadingGrp(char const * const grpfile)
 {
@@ -333,16 +250,16 @@ void G_LoadGroups()
     {
         grpfile = g_selectedGrp->filename;
 
-        clearGrpNamePtr();
-        g_grpNamePtr = dup_filename(grpfile);
+        //clearGrpNamePtr();
+        //g_grpNamePtr = dup_filename(grpfile);
 
         grpinfo_t const * const type = g_selectedGrp->type;
 
         g_gameType = type->game;
         g_gameNamePtr = type->name;
 
-        if (type->scriptname && g_scriptNamePtr == NULL)
-            g_scriptNamePtr = dup_filename(type->scriptname);
+        //if (type->scriptname && g_scriptNamePtr == NULL)
+          //  g_scriptNamePtr = dup_filename(type->scriptname);
 
         if (type->defname && g_defNamePtr == NULL)
             g_defNamePtr = dup_filename(type->defname);
@@ -437,77 +354,9 @@ static void G_LoadAddon(void)
 
 
 
-void G_CleanupSearchPaths(void)
-{
-    removesearchpaths_withuser(SEARCHPATH_REMOVE);
-
-    if (!NAM)
-        removesearchpaths_withuser(SEARCHPATH_NAM);
-
-    if (!RRRA)
-        removesearchpaths_withuser(SEARCHPATH_RRRA);
-
-    if (!RR || RRRA)
-        removesearchpaths_withuser(SEARCHPATH_RR);
-}
-
 //////////
 
 
-GrowArray<char *> g_scriptModules;
-
-void G_AddGroup(const char *buffer)
-{
-    char buf[BMAX_PATH];
-
-    struct strllist *s = (struct strllist *)Xcalloc(1,sizeof(struct strllist));
-
-    Bstrcpy(buf, buffer);
-
-    if (Bstrchr(buf,'.') == 0)
-        Bstrcat(buf,".grp");
-
-    s->str = Xstrdup(buf);
-
-    if (CommandGrps)
-    {
-        struct strllist *t;
-        for (t = CommandGrps; t->next; t=t->next) ;
-        t->next = s;
-        return;
-    }
-    CommandGrps = s;
-}
-
-void G_AddPath(const char *buffer)
-{
-    struct strllist *s = (struct strllist *)Xcalloc(1,sizeof(struct strllist));
-    s->str = Xstrdup(buffer);
-
-    if (CommandPaths)
-    {
-        struct strllist *t;
-        for (t = CommandPaths; t->next; t=t->next) ;
-        t->next = s;
-        return;
-    }
-    CommandPaths = s;
-}
-
-void G_AddCon(const char *buffer)
-{
-    clearScriptNamePtr();
-    g_scriptNamePtr = dup_filename(buffer);
-    initprintf("Using CON file \"%s\".\n",g_scriptNamePtr);
-}
-
-void G_AddConModule(const char *buffer)
-{
-    g_scriptModules.append(Xstrdup(buffer));
-}
-
-//////////
-
 // loads all group (grp, zip, pk3/4) files in the given directory
 void G_LoadGroupsInDir(const char *dirname)
 {
@@ -733,12 +582,6 @@ FileReader S_OpenAudio(const char *fn, char searchfirst, uint8_t const ismusic)
     return origfp;
 }
 
-void Duke_CommonCleanup(void)
-{
-    DO_FREE_AND_NULL(g_grpNamePtr);
-    DO_FREE_AND_NULL(g_scriptNamePtr);
-}
-
 #endif
 
 END_RR_NS
diff --git a/source/rr/src/common_game.h b/source/rr/src/common_game.h
index e943d8c16..feba48ea8 100644
--- a/source/rr/src/common_game.h
+++ b/source/rr/src/common_game.h
@@ -84,23 +84,12 @@ typedef enum basepal_ {
 
 extern const char *g_gameNamePtr;
 
-extern char *g_grpNamePtr;
-extern char *g_scriptNamePtr;
-
 extern const char *G_DefaultGrpFile(void);
 extern const char *G_GrpFile(void);
 
 extern const char *G_DefaultConFile(void);
 extern const char *G_ConFile(void);
 
-extern GrowArray<char *> g_scriptModules;
-
-extern void G_AddCon(const char *buffer);
-extern void G_AddConModule(const char *buffer);
-
-extern void clearGrpNamePtr(void);
-extern void clearScriptNamePtr(void);
-
 extern int loaddefinitions_game(const char *fn, int32_t preload);
 extern int32_t g_groupFileHandle;
 
@@ -112,10 +101,7 @@ extern void G_SetupGlobalPsky(void);
 //////////
 
 extern void G_AddSearchPaths(void);
-extern void G_CleanupSearchPaths(void);
 
-extern void G_ExtInit(void);
-extern void G_ScanGroups(void);
 extern void G_LoadGroups();
 
 extern const char * G_GetInstallPath(int32_t insttype);
@@ -134,9 +120,6 @@ extern void G_LoadLookups(void);
 # define FORMAT_UPGRADE_ELIGIBLE
 extern FileReader S_OpenAudio(const char *fn, char searchfirst, uint8_t ismusic);
 
-void G_AddGroup(const char* buffer);
-void G_AddPath(const char* buffer);
-
 END_RR_NS
 
 #endif
diff --git a/source/rr/src/game.cpp b/source/rr/src/game.cpp
index eb1b892b3..6c231a783 100644
--- a/source/rr/src/game.cpp
+++ b/source/rr/src/game.cpp
@@ -71,7 +71,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 BEGIN_RR_NS
 
 
-void Duke_CommonCleanup(void);
 extern const char* G_DefaultDefFile(void);
 extern const char* G_DefFile(void);
 
@@ -7134,8 +7133,6 @@ static void G_Cleanup(void)
 
     hash_loop(&h_dukeanim, G_FreeHashAnim);
     hash_free(&h_dukeanim);
-
-    Duke_CommonCleanup();
 }
 
 /*
@@ -7178,9 +7175,6 @@ static void G_CompileScripts(void)
     labelcode = (int32_t *)&sector[0]; // V8: 4096*40/4 = 40960    V7: 1024*40/4 = 10240
     labeltype = (int32_t *)&wall[0];   // V8: 16384*32/4 = 131072  V7: 8192*32/4 = 65536
 
-    if (g_scriptNamePtr != NULL)
-        Bcorrectfilename(g_scriptNamePtr,0);
-
     // if we compile for a V7 engine wall[] should be used for label names since it's bigger
     pathsearchmode = 1;
 
@@ -7682,12 +7676,7 @@ int app_main(int argc, char const * const * argv)
 
     // This needs to happen afterwards, as G_CheckCommandLine() is where we set
     // up the command-line-provided search paths (duh).
-    G_ExtInit();
-
-#if defined(RENDERTYPEWIN) && defined(USE_OPENGL)
-    if (forcegl) initprintf("GL driver blacklist disabled.\n");
-#endif
-
+    
 #ifdef STARTUP_SETUP_WINDOW
     int const readSetup =
 #endif
@@ -7702,25 +7691,11 @@ int app_main(int argc, char const * const * argv)
         Bexit(2);
     }
 
-    G_ScanGroups();
-
-#ifdef STARTUP_SETUP_WINDOW
-    if (readSetup < 0 || (!g_noSetup && (displaysetup)) || g_commandSetup)
-    {
-        if (quitevent || !gi->startwin_run())
-        {
-            engineUnInit();
-            Bexit(0);
-        }
-    }
-#endif
-
+    
     g_logFlushWindow = 0;
     G_LoadGroups();
 //    flushlogwindow = 1;
 
-    G_CleanupSearchPaths();
-
     if (RR)
     {
         osdscale2 *= 0.5f;
@@ -8561,12 +8536,6 @@ void A_SpawnRandomGlass(int spriteNum, int wallNum, int glassCnt)
 extern void faketimerhandler();
 extern int app_main(int argc, char const* const* argv);
 extern void app_crashhandler(void);
-extern int32_t startwin_open(void);
-extern int32_t startwin_close(void);
-extern int32_t startwin_puts(const char*);
-extern int32_t startwin_settitle(const char*);
-extern int32_t startwin_idle(void*);
-extern int32_t startwin_run(void);
 
 GameInterface Interface = {
 	TICRATE,
@@ -8576,12 +8545,6 @@ GameInterface Interface = {
 	set_hud_layout,
 	set_hud_scale,
 	app_crashhandler,
-	startwin_open,
-	startwin_close,
-	startwin_puts,
-	startwin_settitle,
-	startwin_idle,
-	startwin_run,
 	G_DefaultDefFile,
 	G_DefFile,
 
diff --git a/source/rr/src/gamedef.cpp b/source/rr/src/gamedef.cpp
index 98c98c440..2d1ba85ce 100644
--- a/source/rr/src/gamedef.cpp
+++ b/source/rr/src/gamedef.cpp
@@ -30,6 +30,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 #include "common.h"
 #include "common_game.h"
 #include "cheats.h"
+#include "m_argv.h"
 
 #include "osd.h"
 #include "crc32_.h"
@@ -2430,13 +2431,12 @@ void C_Compile(const char *fileName)
 
     C_ParseCommand(1);
 
-    for (char * m : g_scriptModules)
+	for (FString & m : *userConfig.AddCons.get())
     {
-        C_Include(m);
-        free(m);
+		C_Include(m);
     }
-    g_scriptModules.clear();
-
+	userConfig.AddCons.reset();
+    
     g_logFlushWindow = 1;
 
     if (g_errorCnt > 63)
diff --git a/source/rr/src/startgtk.game.cpp b/source/rr/src/startgtk.game.cpp
deleted file mode 100644
index 3322e7a71..000000000
--- a/source/rr/src/startgtk.game.cpp
+++ /dev/null
@@ -1,888 +0,0 @@
-//-------------------------------------------------------------------------
-/*
-Copyright (C) 2010 EDuke32 developers and contributors
-
-This file is part of EDuke32.
-
-EDuke32 is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License version 2
-as published by the Free Software Foundation.
-
-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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-//-------------------------------------------------------------------------
-#include "ns.h"	// Must come before everything else!
-
-#include "build.h"
-#include "cmdline.h"
-#include "common.h"
-#include "common_game.h"
-#include "compat.h"
-#include "duke3d.h"
-#include "dynamicgtk.h"
-#include "game.h"
-#include "grpscan.h"
-#include "gtkpixdata.h"
-
-BEGIN_RR_NS
-
-enum
-{
-    NONE,
-    ALL,
-    POPULATE_VIDEO,
-    POPULATE_CONFIG,
-    POPULATE_GAME,
-};
-
-enum
-{
-    TAB_CONFIG,
-    TAB_GAME,
-    TAB_MESSAGES,
-};
-
-enum
-{
-    INPUT_KB,
-    INPUT_MOUSE,
-    INPUT_JOYSTICK,
-    INPUT_ALL,
-};
-
-static struct
-{
-    GtkWidget *startwin;
-    GtkWidget *hlayout;
-    GtkWidget *banner;
-    GtkWidget *vlayout;
-    GtkWidget *tabs;
-    GtkWidget *configtlayout;
-    GtkWidget *displayvlayout;
-    GtkWidget *vmode3dlabel;
-    GtkWidget *vmode3dcombo;
-    GtkWidget *fullscreencheck;
-#ifdef POLYMER
-    GtkWidget *polymercheck;
-#endif
-    GtkWidget *inputdevlabel;
-    GtkWidget *inputdevcombo;
-    GtkWidget *custommodlabel;
-    GtkWidget *custommodcombo;
-    GtkWidget *emptyhlayout;
-    GtkWidget *autoloadcheck;
-    GtkWidget *alwaysshowcheck;
-    GtkWidget *configtab;
-    GtkWidget *gamevlayout;
-    GtkWidget *gamelabel;
-    GtkWidget *gamescroll;
-    GtkWidget *gamelist;
-    GtkWidget *gametab;
-    GtkWidget *messagesscroll;
-    GtkWidget *messagestext;
-    GtkWidget *messagestab;
-    GtkWidget *buttons;
-    GtkWidget *cancelbutton;
-    GtkWidget *cancelbuttonalign;
-    GtkWidget *cancelbuttonlayout;
-    GtkWidget *cancelbuttonicon;
-    GtkWidget *cancelbuttonlabel;
-    GtkWidget *startbutton;
-    GtkWidget *startbuttonalign;
-    GtkWidget *startbuttonlayout;
-    GtkWidget *startbuttonicon;
-    GtkWidget *startbuttonlabel;
-} stwidgets;
-
-static struct
-{
-    grpfile_t const * grp;
-    char *gamedir;
-    ud_setup_t shared;
-    int polymer;
-} settings;
-
-static int32_t retval = -1, mode = TAB_MESSAGES;
-extern int32_t gtkenabled;
-static void PopulateForm(unsigned char pgs);
-
-
-// -- EVENT CALLBACKS AND CREATION STUFF --------------------------------------
-
-static void on_vmode3dcombo_changed(GtkComboBox *combobox, gpointer user_data)
-{
-    GtkTreeModel *data;
-    GtkTreeIter iter;
-    int32_t val;
-    UNREFERENCED_PARAMETER(user_data);
-
-    if (!gtk_combo_box_get_active_iter(combobox, &iter)) return;
-    if (!(data = gtk_combo_box_get_model(combobox))) return;
-    gtk_tree_model_get(data, &iter, 1, &val, -1);
-    settings.shared.xdim = validmode[val].xdim;
-    settings.shared.ydim = validmode[val].ydim;
-}
-
-static void on_fullscreencheck_toggled(GtkToggleButton *togglebutton, gpointer user_data)
-{
-    UNREFERENCED_PARAMETER(user_data);
-    settings.shared.fullscreen = gtk_toggle_button_get_active(togglebutton);
-    PopulateForm(POPULATE_VIDEO);
-}
-
-#ifdef POLYMER
-static void on_polymercheck_toggled(GtkToggleButton *togglebutton, gpointer user_data)
-{
-    UNREFERENCED_PARAMETER(user_data);
-    if (gtk_toggle_button_get_active(togglebutton))
-    {
-        glrendmode = REND_POLYMER;
-        settings.polymer = TRUE;
-        if (settings.shared.bpp == 8)
-        {
-            settings.shared.bpp = 32;
-            PopulateForm(POPULATE_VIDEO);
-        }
-    }
-    else
-    {
-        glrendmode = REND_POLYMOST;
-        settings.polymer = FALSE;
-    }
-}
-#endif
-
-static void on_inputdevcombo_changed(GtkComboBox *combobox, gpointer user_data)
-{
-    UNREFERENCED_PARAMETER(user_data);
-    switch (gtk_combo_box_get_active(combobox))
-    {
-    case 0: settings.shared.usemouse = 0; settings.shared.usejoystick = 0; break;
-    case 1:	settings.shared.usemouse = 1; settings.shared.usejoystick = 0; break;
-    case 2:	settings.shared.usemouse = 0; settings.shared.usejoystick = 1; break;
-    case 3:	settings.shared.usemouse = 1; settings.shared.usejoystick = 1; break;
-    }
-}
-
-static void on_custommodcombo_changed(GtkComboBox *combobox, gpointer user_data)
-{
-    GtkTreeIter iter;
-    GtkTreeModel *model;
-    GtkTreePath *path;
-    char *value;
-    UNREFERENCED_PARAMETER(user_data);
-
-    if (gtk_combo_box_get_active_iter(combobox, &iter))
-    {
-        model = gtk_combo_box_get_model(combobox);
-        gtk_tree_model_get(model, &iter, 0,&value, -1);
-        path = gtk_tree_model_get_path(model, &iter);
-
-        if (*gtk_tree_path_get_indices(path) == NONE)
-            settings.gamedir = NULL;
-        else settings.gamedir = value;
-    }
-}
-
-static void on_autoloadcheck_toggled(GtkToggleButton *togglebutton, gpointer user_data)
-{
-    UNREFERENCED_PARAMETER(user_data);
-    settings.shared.noautoload = !gtk_toggle_button_get_active(togglebutton);
-}
-
-static void on_alwaysshowcheck_toggled(GtkToggleButton *togglebutton, gpointer user_data)
-{
-    UNREFERENCED_PARAMETER(user_data);
-    settings.shared.forcesetup = gtk_toggle_button_get_active(togglebutton);
-}
-
-static void on_cancelbutton_clicked(GtkButton *button, gpointer user_data)
-{
-    UNREFERENCED_PARAMETER(button);
-    UNREFERENCED_PARAMETER(user_data);
-    if (mode == TAB_CONFIG) { retval = 0; gtk_main_quit(); }
-    else quitevent++;
-}
-
-static void on_startbutton_clicked(GtkButton *button, gpointer user_data)
-{
-    UNREFERENCED_PARAMETER(button);
-    UNREFERENCED_PARAMETER(user_data);
-    retval = 1;
-    gtk_main_quit();
-}
-
-static void on_gamelist_selection_changed(GtkTreeSelection *selection, gpointer user_data)
-{
-    GtkTreeIter iter;
-    GtkTreeModel *model;
-    UNREFERENCED_PARAMETER(user_data);
-
-    if (gtk_tree_selection_get_selected(selection, &model, &iter))
-    {
-        grpfile_t const *fg;
-        gtk_tree_model_get(model, &iter, 2, (gpointer)&fg, -1);
-        settings.grp = fg;
-    }
-}
-
-static gboolean on_startwin_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
-{
-    UNREFERENCED_PARAMETER(widget);
-    UNREFERENCED_PARAMETER(event);
-    UNREFERENCED_PARAMETER(user_data);
-    if (mode == TAB_CONFIG) { retval = 0; gtk_main_quit(); }
-    else quitevent++;
-    return TRUE;	// FALSE would let the event go through. we want the game to decide when to close
-}
-
-
-// -- SUPPORT FUNCTIONS -------------------------------------------------------
-
-static GdkPixbuf *load_banner(void)
-{
-    return gdk_pixbuf_from_pixdata((GdkPixdata const *)&startbanner_pixdata, FALSE, NULL);
-}
-
-static void SetPage(int32_t n)
-{
-    if (!gtkenabled || !stwidgets.startwin) return;
-    mode = n;
-    gtk_notebook_set_current_page(GTK_NOTEBOOK(stwidgets.tabs), n);
-
-    // each control in the config page vertical layout plus the start button should be made (in)sensitive
-    if (n == TAB_CONFIG) n = TRUE; else n = FALSE;
-    gtk_widget_set_sensitive(stwidgets.startbutton, n);
-    gtk_container_foreach(GTK_CONTAINER(stwidgets.configtlayout),
-                          (GtkCallback)gtk_widget_set_sensitive,
-                          (gpointer)&n);
-}
-
-static unsigned char GetModsDirNames(GtkListStore *list)
-{
-    char *homedir;
-    char pdir[BMAX_PATH];
-    unsigned char iternumb = 0;
-    CACHE1D_FIND_REC *dirs = NULL;
-    GtkTreeIter iter;
-
-    pathsearchmode = 1;
-
-    if ((homedir = Bgethomedir()))
-    {
-        Bsnprintf(pdir, sizeof(pdir), "%s/" ".eduke32", homedir);
-        dirs = klistpath(pdir, "*", CACHE1D_FIND_DIR);
-        for (; dirs != NULL; dirs=dirs->next)
-        {
-            if ((Bstrcmp(dirs->name, "autoload") == 0) ||
-                    (Bstrcmp(dirs->name, "..") == 0) ||
-                    (Bstrcmp(dirs->name, ".") == 0))
-                continue;
-            else
-            {
-                gtk_list_store_append(list, &iter);
-                gtk_list_store_set(list, &iter, 0,dirs->name, -1);
-                iternumb++;
-            }
-        }
-    }
-
-    klistfree(dirs);
-    dirs = NULL;
-
-    return iternumb;
-}
-
-static void PopulateForm(unsigned char pgs)
-{
-    if ((pgs == ALL) || (pgs == POPULATE_VIDEO))
-    {
-        int32_t mode3d, i;
-        GtkListStore *modes3d;
-        GtkTreeIter iter;
-        char buf[64];
-
-        mode3d = videoCheckMode(&settings.shared.xdim, &settings.shared.ydim, settings.shared.bpp, settings.shared.fullscreen, 1);
-        if (mode3d < 0)
-        {
-            int32_t i, cd[] = { 32, 24, 16, 15, 8, 0 };
-
-            for (i=0; cd[i];) { if (cd[i] >= settings.shared.bpp) i++; else break; }
-            for (; cd[i]; i++)
-            {
-                mode3d = videoCheckMode(&settings.shared.xdim, &settings.shared.ydim, cd[i], settings.shared.fullscreen, 1);
-                if (mode3d < 0) continue;
-                settings.shared.bpp = cd[i];
-                break;
-            }
-        }
-
-        modes3d = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(stwidgets.vmode3dcombo)));
-        gtk_list_store_clear(modes3d);
-
-        for (i=0; i<validmodecnt; i++)
-        {
-            if (validmode[i].fs != settings.shared.fullscreen) continue;
-
-            // all modes get added to the 3D mode list
-            Bsprintf(buf, "%dx%d %s", validmode[i].xdim, validmode[i].ydim, validmode[i].bpp == 8 ? "software" : "OpenGL");
-            gtk_list_store_append(modes3d, &iter);
-            gtk_list_store_set(modes3d, &iter, 0,buf, 1,i, -1);
-            if (i == mode3d)
-            {
-                g_signal_handlers_block_by_func(stwidgets.vmode3dcombo, (gpointer)on_vmode3dcombo_changed, NULL);
-                gtk_combo_box_set_active_iter(GTK_COMBO_BOX(stwidgets.vmode3dcombo), &iter);
-                g_signal_handlers_unblock_by_func(stwidgets.vmode3dcombo, (gpointer)on_vmode3dcombo_changed, NULL);
-            }
-        }
-    }
-
-    if ((pgs == ALL) || (pgs == POPULATE_CONFIG))
-    {
-        GtkListStore *devlist, *modsdir;
-        GtkTreeIter iter;
-        GtkTreePath *path;
-        char *value;
-        unsigned char i, r = 0;
-        const char *availabledev[] =
-        {
-            "Keyboard only",
-            "Keyboard and mouse",
-            "Keyboard and joystick",
-            "All supported devices"
-        };
-
-        // populate input devices combo
-        devlist = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(stwidgets.inputdevcombo)));
-        gtk_list_store_clear(devlist);
-
-        for (i=0; i<(int32_t)G_N_ELEMENTS(availabledev); i++)
-        {
-            gtk_list_store_append(devlist, &iter);
-            gtk_list_store_set(devlist, &iter, 0,availabledev[i], -1);
-        }
-        switch (settings.shared.usemouse)
-        {
-        case 0: if (settings.shared.usejoystick)
-                gtk_combo_box_set_active(GTK_COMBO_BOX(stwidgets.inputdevcombo), INPUT_JOYSTICK);
-            else
-                gtk_combo_box_set_active(GTK_COMBO_BOX(stwidgets.inputdevcombo), INPUT_KB);
-            break;
-        case 1:	if (settings.shared.usejoystick)
-                gtk_combo_box_set_active(GTK_COMBO_BOX(stwidgets.inputdevcombo), INPUT_ALL);
-            else
-                gtk_combo_box_set_active(GTK_COMBO_BOX(stwidgets.inputdevcombo), INPUT_MOUSE);
-            break;
-        }
-
-        // populate custom mod combo
-        modsdir = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(stwidgets.custommodcombo)));
-        gtk_list_store_clear(modsdir);
-
-        gtk_list_store_append(modsdir, &iter);
-        gtk_list_store_set(modsdir, &iter, 0,"None", -1);
-        r = GetModsDirNames(modsdir);
-
-        for (i=0; i<=r; i++)
-        {
-            path = gtk_tree_path_new_from_indices(i, -1);
-            gtk_tree_model_get_iter(GTK_TREE_MODEL(modsdir), &iter, path);
-            gtk_tree_model_get(GTK_TREE_MODEL(modsdir), &iter, 0,&value, -1);
-
-            if (Bstrcmp(settings.gamedir, "/") == 0)
-            {
-                gtk_combo_box_set_active(GTK_COMBO_BOX(stwidgets.custommodcombo), NONE);
-                settings.gamedir = NULL;
-
-                break;
-            }
-            if (Bstrcmp(settings.gamedir, value) == 0)
-            {
-                gtk_combo_box_set_active_iter(GTK_COMBO_BOX(stwidgets.custommodcombo),
-                                              &iter);
-
-                break;
-            }
-        }
-
-        // populate check buttons
-        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(stwidgets.fullscreencheck), settings.shared.fullscreen);
-#ifdef POLYMER
-        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(stwidgets.polymercheck), settings.polymer);
-#endif
-        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(stwidgets.autoloadcheck), !settings.shared.noautoload);
-        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(stwidgets.alwaysshowcheck), settings.shared.forcesetup);
-    }
-
-    if ((pgs == ALL) || (pgs == POPULATE_GAME))
-    {
-        GtkListStore *list;
-        GtkTreeIter iter;
-        GtkTreeView *gamelist;
-
-        gamelist = GTK_TREE_VIEW(stwidgets.gamelist);
-        list = GTK_LIST_STORE(gtk_tree_view_get_model(gamelist));
-        gtk_list_store_clear(list);
-
-        for (grpfile_t const * fg = foundgrps; fg; fg=fg->next)
-        {
-            gtk_list_store_append(list, &iter);
-            gtk_list_store_set(list, &iter, 0, fg->type->name, 1, fg->filename, 2, (void const *)fg, -1);
-            if (settings.grp == fg)
-            {
-                GtkTreeSelection *sel = gtk_tree_view_get_selection(gamelist);
-                g_signal_handlers_block_by_func(sel, (gpointer)on_gamelist_selection_changed, NULL);
-                gtk_tree_selection_select_iter(sel, &iter);
-                g_signal_handlers_unblock_by_func(sel, (gpointer)on_gamelist_selection_changed, NULL);
-            }
-        }
-    }
-}
-
-static gint name_sorter(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data)
-{
-    gchar *as, *bs;
-    gint r;
-    UNREFERENCED_PARAMETER(user_data);
-    gtk_tree_model_get(model, a, 0, &as, -1);
-    gtk_tree_model_get(model, b, 0, &bs, -1);
-
-    r = g_utf8_collate(as,bs);
-
-    g_free(as);
-    g_free(bs);
-
-    return r;
-}
-
-static GtkWidget *create_window(void)
-{
-    // Basic window
-    stwidgets.startwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-    gtk_window_set_title(GTK_WINDOW(stwidgets.startwin), apptitle);	// NOTE: use global app title
-    gtk_window_set_position(GTK_WINDOW(stwidgets.startwin), GTK_WIN_POS_CENTER);
-    gtk_window_set_resizable(GTK_WINDOW(stwidgets.startwin), FALSE);
-    gtk_window_set_type_hint(GTK_WINDOW(stwidgets.startwin), GDK_WINDOW_TYPE_HINT_DIALOG);
-
-    // Horizontal layout of banner and controls
-    stwidgets.hlayout = gtk_hbox_new(FALSE, 0);
-    gtk_container_add(GTK_CONTAINER(stwidgets.startwin), stwidgets.hlayout);
-
-    // banner
-    {
-        GdkPixbuf *pixbuf = load_banner();
-        stwidgets.banner = gtk_image_new_from_pixbuf(pixbuf);
-        g_object_unref((gpointer)pixbuf);
-    }
-    gtk_box_pack_start(GTK_BOX(stwidgets.hlayout), stwidgets.banner, FALSE, FALSE, 0);
-    gtk_misc_set_alignment(GTK_MISC(stwidgets.banner), 0.5, 0);
-
-    // Vertical layout of tab control and start+cancel buttons
-    stwidgets.vlayout = gtk_vbox_new(FALSE, 0);
-    gtk_box_pack_start(GTK_BOX(stwidgets.hlayout), stwidgets.vlayout, TRUE, TRUE, 0);
-
-    // Tab control
-    stwidgets.tabs = gtk_notebook_new();
-    gtk_box_pack_start(GTK_BOX(stwidgets.vlayout), stwidgets.tabs, TRUE, TRUE, 0);
-    gtk_container_set_border_width(GTK_CONTAINER(stwidgets.tabs), 4);
-
-    // layout table of config page
-    stwidgets.configtlayout = gtk_table_new(6, 3, FALSE);
-    gtk_container_add(GTK_CONTAINER(stwidgets.tabs), stwidgets.configtlayout);
-
-    // 3D video mode LabelText
-    stwidgets.vmode3dlabel = gtk_label_new_with_mnemonic("_Video mode:");
-    gtk_misc_set_alignment(GTK_MISC(stwidgets.vmode3dlabel), 0.3, 0);
-#ifdef POLYMER
-    gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.vmode3dlabel, 0,1, 0,1, GTK_FILL, (GtkAttachOptions)0, 4, 0);
-#else
-    gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.vmode3dlabel, 0,1, 0,1, GTK_FILL, (GtkAttachOptions)0, 4, 7);
-#endif
-
-    // 3D video mode combo
-    {
-        GtkListStore *list = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
-        GtkCellRenderer *cell;
-
-        stwidgets.vmode3dcombo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(list));
-        g_object_unref(G_OBJECT(list));
-
-        cell = gtk_cell_renderer_text_new();
-        gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(stwidgets.vmode3dcombo), cell, FALSE);
-        gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(stwidgets.vmode3dcombo), cell, "text", 0, NULL);
-    }
-
-#ifdef POLYMER
-   gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.vmode3dcombo, 1,2, 0,1,
-       (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)0, 4, 0);
-#else
-   gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.vmode3dcombo, 1,2, 0,1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)0, 4, 7);
-#endif
-
-    // Fullscreen checkbox
-    stwidgets.displayvlayout = gtk_vbox_new(TRUE, 0);
-#ifdef POLYMER
-    gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.displayvlayout, 2,3, 0,1, GTK_FILL, (GtkAttachOptions)0, 4, 0);
-#else
-    gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.displayvlayout, 2,3, 0,1, GTK_FILL, (GtkAttachOptions)0, 4, 7);
-#endif
-
-    stwidgets.fullscreencheck = gtk_check_button_new_with_mnemonic("_Fullscreen");
-    gtk_box_pack_start(GTK_BOX(stwidgets.displayvlayout), stwidgets.fullscreencheck, FALSE, FALSE, 0);
-
-#ifdef POLYMER
-    // Polymer checkbox
-    stwidgets.polymercheck = gtk_check_button_new_with_mnemonic("_Polymer");
-    gtk_box_pack_start(GTK_BOX(stwidgets.displayvlayout), stwidgets.polymercheck, FALSE, FALSE, 0);
-#endif
-
-    // Input devices LabelText
-    stwidgets.inputdevlabel = gtk_label_new_with_mnemonic("_Input devices:");
-    gtk_misc_set_alignment(GTK_MISC(stwidgets.inputdevlabel), 0.3, 0);
-    gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.inputdevlabel, 0,1, 1,2, GTK_FILL, (GtkAttachOptions)0, 4, 0);
-
-    // Input devices combo
-    {
-        GtkListStore *list = gtk_list_store_new(1, G_TYPE_STRING);
-        GtkCellRenderer *cell;
-
-        stwidgets.inputdevcombo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(list));
-        g_object_unref(G_OBJECT(list));
-
-        cell = gtk_cell_renderer_text_new();
-        gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(stwidgets.inputdevcombo), cell, FALSE);
-        gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(stwidgets.inputdevcombo), cell, "text", 0, NULL);
-    }
-    gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.inputdevcombo, 1,2, 1,2,
-        (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)0, 4, 0);
-
-    // Custom mod LabelText
-    stwidgets.custommodlabel = gtk_label_new_with_mnemonic("Custom _game:");
-    gtk_misc_set_alignment(GTK_MISC(stwidgets.custommodlabel), 0.3, 0);
-    gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.custommodlabel, 0,1, 2,3, GTK_FILL, (GtkAttachOptions)0, 4, 7);
-
-    // Custom mod combo
-    {
-        GtkListStore *list = gtk_list_store_new(1, G_TYPE_STRING);
-        GtkCellRenderer *cell;
-
-        stwidgets.custommodcombo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(list));
-        g_object_unref(G_OBJECT(list));
-
-        cell = gtk_cell_renderer_text_new();
-        gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(stwidgets.custommodcombo), cell, FALSE);
-        gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(stwidgets.custommodcombo), cell, "text", 0, NULL);
-    }
-    gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.custommodcombo, 1,2, 2,3,
-        (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)0, 4, 7);
-
-    // Empty horizontal layout
-    stwidgets.emptyhlayout = gtk_hbox_new(TRUE, 0);
-    gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.emptyhlayout, 0,3, 3,4, (GtkAttachOptions)0,
-        (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 4, 0);
-
-    // Autoload checkbox
-    stwidgets.autoloadcheck = gtk_check_button_new_with_mnemonic("_Enable \"autoload\" folder");
-    gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.autoloadcheck, 0,3, 4,5, GTK_FILL, (GtkAttachOptions)0, 2, 2);
-
-    // Always show config checkbox
-    stwidgets.alwaysshowcheck = gtk_check_button_new_with_mnemonic("_Always show this window at startup");
-    gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.alwaysshowcheck, 0,3, 5,6, GTK_FILL, (GtkAttachOptions)0, 2, 2);
-
-    // Configuration tab
-    stwidgets.configtab = gtk_label_new("Configuration");
-    gtk_notebook_set_tab_label(GTK_NOTEBOOK(stwidgets.tabs), gtk_notebook_get_nth_page(GTK_NOTEBOOK(stwidgets.tabs), 0), stwidgets.configtab);
-
-    // Game data layout
-    stwidgets.gamevlayout = gtk_vbox_new(FALSE, 0);
-    gtk_container_add(GTK_CONTAINER(stwidgets.tabs), stwidgets.gamevlayout);
-    gtk_container_set_border_width(GTK_CONTAINER(stwidgets.gamevlayout), 4);
-
-    // Game data field LabelText
-    stwidgets.gamelabel = gtk_label_new_with_mnemonic("_Game:");
-    gtk_box_pack_start(GTK_BOX(stwidgets.gamevlayout), stwidgets.gamelabel, FALSE, FALSE, 0);
-    gtk_misc_set_alignment(GTK_MISC(stwidgets.gamelabel), 0, 0.5);
-
-    // Game data scrollable area
-    stwidgets.gamescroll = gtk_scrolled_window_new(NULL, NULL);
-    gtk_box_pack_start(GTK_BOX(stwidgets.gamevlayout), stwidgets.gamescroll, TRUE, TRUE, 0);
-    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(stwidgets.gamescroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-    gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(stwidgets.gamescroll), GTK_SHADOW_IN);
-
-    // Game data list
-    {
-        GtkListStore *list = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
-        GtkCellRenderer *cell;
-        GtkTreeViewColumn *col;
-
-        gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(list), 0, name_sorter, NULL, NULL);
-        gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(list), 0, GTK_SORT_ASCENDING);
-
-        stwidgets.gamelist = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list));
-        g_object_unref(G_OBJECT(list));
-
-        cell = gtk_cell_renderer_text_new();
-        col = gtk_tree_view_column_new_with_attributes("Game", cell, "text", 0, NULL);
-        gtk_tree_view_column_set_expand(col, TRUE);
-        gtk_tree_view_append_column(GTK_TREE_VIEW(stwidgets.gamelist), col);
-        col = gtk_tree_view_column_new_with_attributes("GRP file", cell, "text", 1, NULL);
-        gtk_tree_view_column_set_min_width(col, 64);
-        gtk_tree_view_append_column(GTK_TREE_VIEW(stwidgets.gamelist), col);
-    }
-    gtk_container_add(GTK_CONTAINER(stwidgets.gamescroll), stwidgets.gamelist);
-
-    gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(stwidgets.gamelist), FALSE);
-    gtk_tree_view_set_enable_search(GTK_TREE_VIEW(stwidgets.gamelist), FALSE);
-
-    // Game tab
-    stwidgets.gametab = gtk_label_new("Game");
-    gtk_notebook_set_tab_label(GTK_NOTEBOOK(stwidgets.tabs), gtk_notebook_get_nth_page(GTK_NOTEBOOK(stwidgets.tabs), 1), stwidgets.gametab);
-
-    // Messages scrollable area
-    stwidgets.messagesscroll = gtk_scrolled_window_new(NULL, NULL);
-    gtk_container_add(GTK_CONTAINER(stwidgets.tabs), stwidgets.messagesscroll);
-    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(stwidgets.messagesscroll), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
-
-    // Messages text area
-    stwidgets.messagestext = gtk_text_view_new();
-    gtk_container_add(GTK_CONTAINER(stwidgets.messagesscroll), stwidgets.messagestext);
-    gtk_text_view_set_editable(GTK_TEXT_VIEW(stwidgets.messagestext), FALSE);
-    gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(stwidgets.messagestext), GTK_WRAP_WORD);
-    gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(stwidgets.messagestext), FALSE);
-    gtk_text_view_set_left_margin(GTK_TEXT_VIEW(stwidgets.messagestext), 2);
-    gtk_text_view_set_right_margin(GTK_TEXT_VIEW(stwidgets.messagestext), 2);
-
-    // Messages tab
-    stwidgets.messagestab = gtk_label_new("Messages");
-    gtk_notebook_set_tab_label(GTK_NOTEBOOK(stwidgets.tabs), gtk_notebook_get_nth_page(GTK_NOTEBOOK(stwidgets.tabs), 2), stwidgets.messagestab);
-
-    // Dialogue box buttons layout
-    stwidgets.buttons = gtk_hbutton_box_new();
-    gtk_box_pack_start(GTK_BOX(stwidgets.vlayout), stwidgets.buttons, FALSE, TRUE, 0);
-    gtk_container_set_border_width(GTK_CONTAINER(stwidgets.buttons), 3);
-    gtk_button_box_set_layout(GTK_BUTTON_BOX(stwidgets.buttons), GTK_BUTTONBOX_END);
-
-    // Cancel button
-    stwidgets.cancelbutton = gtk_button_new();
-    gtk_container_add(GTK_CONTAINER(stwidgets.buttons), stwidgets.cancelbutton);
-    GTK_WIDGET_SET_FLAGS(stwidgets.cancelbutton, GTK_CAN_DEFAULT);
-
-    stwidgets.cancelbuttonalign = gtk_alignment_new(0.5, 0.5, 0, 0);
-    gtk_container_add(GTK_CONTAINER(stwidgets.cancelbutton), stwidgets.cancelbuttonalign);
-
-    stwidgets.cancelbuttonlayout = gtk_hbox_new(FALSE, 2);
-    gtk_container_add(GTK_CONTAINER(stwidgets.cancelbuttonalign), stwidgets.cancelbuttonlayout);
-
-    stwidgets.cancelbuttonicon = gtk_image_new_from_stock("gtk-cancel", GTK_ICON_SIZE_BUTTON);
-    gtk_box_pack_start(GTK_BOX(stwidgets.cancelbuttonlayout), stwidgets.cancelbuttonicon, FALSE, FALSE, 0);
-
-    stwidgets.cancelbuttonlabel = gtk_label_new_with_mnemonic("_Cancel");
-    gtk_box_pack_start(GTK_BOX(stwidgets.cancelbuttonlayout), stwidgets.cancelbuttonlabel, FALSE, FALSE, 0);
-
-    // Start button
-    stwidgets.startbutton = gtk_button_new();
-    gtk_container_add(GTK_CONTAINER(stwidgets.buttons), stwidgets.startbutton);
-    GTK_WIDGET_SET_FLAGS(stwidgets.startbutton, GTK_CAN_DEFAULT);
-
-    gtk_window_set_default(GTK_WINDOW(stwidgets.startwin), stwidgets.startbutton);
-
-    stwidgets.startbuttonalign = gtk_alignment_new(0.5, 0.5, 0, 0);
-    gtk_container_add(GTK_CONTAINER(stwidgets.startbutton), stwidgets.startbuttonalign);
-
-    stwidgets.startbuttonlayout = gtk_hbox_new(FALSE, 2);
-    gtk_container_add(GTK_CONTAINER(stwidgets.startbuttonalign), stwidgets.startbuttonlayout);
-
-    stwidgets.startbuttonicon = gtk_image_new_from_stock("gtk-execute", GTK_ICON_SIZE_BUTTON);
-    gtk_box_pack_start(GTK_BOX(stwidgets.startbuttonlayout), stwidgets.startbuttonicon, FALSE, FALSE, 0);
-
-    stwidgets.startbuttonlabel = gtk_label_new_with_mnemonic("_Start");
-    gtk_box_pack_start(GTK_BOX(stwidgets.startbuttonlayout), stwidgets.startbuttonlabel, FALSE, FALSE, 0);
-
-    // Wire up the signals
-    g_signal_connect((gpointer) stwidgets.startwin, "delete_event",
-                     G_CALLBACK(on_startwin_delete_event),
-                     NULL);
-    g_signal_connect((gpointer) stwidgets.vmode3dcombo, "changed",
-                     G_CALLBACK(on_vmode3dcombo_changed),
-                     NULL);
-    g_signal_connect((gpointer) stwidgets.fullscreencheck, "toggled",
-                     G_CALLBACK(on_fullscreencheck_toggled),
-                     NULL);
-#ifdef POLYMER
-    g_signal_connect((gpointer) stwidgets.polymercheck, "toggled",
-                     G_CALLBACK(on_polymercheck_toggled),
-                     NULL);
-#endif
-    g_signal_connect((gpointer) stwidgets.inputdevcombo, "changed",
-                     G_CALLBACK(on_inputdevcombo_changed),
-                     NULL);
-    g_signal_connect((gpointer) stwidgets.custommodcombo, "changed",
-                     G_CALLBACK(on_custommodcombo_changed),
-                     NULL);
-    g_signal_connect((gpointer) stwidgets.autoloadcheck, "toggled",
-                     G_CALLBACK(on_autoloadcheck_toggled),
-                     NULL);
-    g_signal_connect((gpointer) stwidgets.alwaysshowcheck, "toggled",
-                     G_CALLBACK(on_alwaysshowcheck_toggled),
-                     NULL);
-    g_signal_connect((gpointer) stwidgets.cancelbutton, "clicked",
-                     G_CALLBACK(on_cancelbutton_clicked),
-                     NULL);
-    g_signal_connect((gpointer) stwidgets.startbutton, "clicked",
-                     G_CALLBACK(on_startbutton_clicked),
-                     NULL);
-    {
-        GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(stwidgets.gamelist));
-        gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
-        g_signal_connect((gpointer) sel, "changed",
-                         G_CALLBACK(on_gamelist_selection_changed),
-                         NULL);
-    }
-
-    // Associate labels with their controls
-    gtk_label_set_mnemonic_widget(GTK_LABEL(stwidgets.vmode3dlabel), stwidgets.vmode3dcombo);
-    gtk_label_set_mnemonic_widget(GTK_LABEL(stwidgets.inputdevlabel), stwidgets.inputdevcombo);
-    gtk_label_set_mnemonic_widget(GTK_LABEL(stwidgets.custommodlabel), stwidgets.custommodcombo);
-    gtk_label_set_mnemonic_widget(GTK_LABEL(stwidgets.gamelabel), stwidgets.gamelist);
-
-    return stwidgets.startwin;
-}
-
-
-// -- BUILD ENTRY POINTS ------------------------------------------------------
-
-int32_t startwin_open(void)
-{
-    if (!gtkenabled) return 0;
-    if (stwidgets.startwin) return 1;
-
-    stwidgets.startwin = create_window();
-    if (stwidgets.startwin)
-    {
-        SetPage(TAB_MESSAGES);
-        gtk_widget_show_all(stwidgets.startwin);
-        gtk_main_iteration_do(FALSE);
-        return 0;
-    }
-    return -1;
-}
-
-int32_t startwin_close(void)
-{
-    if (!gtkenabled) return 0;
-    if (!stwidgets.startwin) return 1;
-    gtk_widget_destroy(stwidgets.startwin);
-    stwidgets.startwin = NULL;
-    return 0;
-}
-
-int32_t startwin_puts(const char *str)
-{
-    GtkWidget *textview;
-    GtkTextBuffer *textbuffer;
-    GtkTextIter enditer;
-    GtkTextMark *mark;
-    const char *aptr, *bptr;
-
-    if (!gtkenabled || !str) return 0;
-    if (!stwidgets.startwin) return 1;
-    if (!(textview = stwidgets.messagestext)) return -1;
-    textbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
-
-    gtk_text_buffer_get_end_iter(textbuffer, &enditer);
-    for (aptr = bptr = str; *aptr != 0;)
-    {
-        switch (*bptr)
-        {
-        case '\b':
-            if (bptr > aptr)
-                gtk_text_buffer_insert(textbuffer, &enditer, (const gchar *)aptr, (gint)(bptr-aptr)-1);
-#if GTK_CHECK_VERSION(2,6,0)
-            gtk_text_buffer_backspace(textbuffer, &enditer, FALSE, TRUE);
-#else
-            {
-                GtkTextIter iter2 = enditer;
-                gtk_text_iter_backward_cursor_position(&iter2);
-                //FIXME: this seems be deleting one too many chars somewhere!
-                if (!gtk_text_iter_equal(&iter2, &enditer))
-                    gtk_text_buffer_delete_interactive(textbuffer, &iter2, &enditer, TRUE);
-            }
-#endif
-            aptr = ++bptr;
-            break;
-        case 0:
-            if (bptr > aptr)
-                gtk_text_buffer_insert(textbuffer, &enditer, (const gchar *)aptr, (gint)(bptr-aptr));
-            aptr = bptr;
-            break;
-        case '\r':	// FIXME
-        default:
-            bptr++;
-            break;
-        }
-    }
-
-    mark = gtk_text_buffer_create_mark(textbuffer, NULL, &enditer, 1);
-    gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(textview), mark, 0.0, FALSE, 0.0, 1.0);
-    gtk_text_buffer_delete_mark(textbuffer, mark);
-
-    return 0;
-}
-
-int32_t startwin_settitle(const char *title)
-{
-    if (!gtkenabled) return 0;
-    if (!stwidgets.startwin) return 1;
-    gtk_window_set_title(GTK_WINDOW(stwidgets.startwin), title);
-    return 0;
-}
-
-int32_t startwin_idle(void *s)
-{
-    UNREFERENCED_PARAMETER(s);
-    if (!gtkenabled) return 0;
-    //if (!stwidgets.startwin) return 1;
-    gtk_main_iteration_do(FALSE);
-    return 0;
-}
-
-int32_t startwin_run(void)
-{
-    if (!gtkenabled) return 1;
-    if (!stwidgets.startwin) return 1;
-
-    SetPage(TAB_CONFIG);
-
-    settings.shared = ud.setup;
-    settings.gamedir = g_modDir;
-    settings.grp = g_selectedGrp;
-#ifdef POLYMER
-    settings.polymer = (glrendmode == REND_POLYMER);
-#else
-    settings.polymer = 0;
-#endif
-    PopulateForm(ALL);
-
-    gtk_main();
-
-    SetPage(TAB_MESSAGES);
-    if (retval) // launch the game with these parameters
-    {
-        ud.setup = settings.shared;
-        glrendmode = (settings.polymer) ? REND_POLYMER : REND_POLYMOST;
-        g_selectedGrp = settings.grp;
-
-        Bstrcpy(g_modDir, (g_noSetup == 0 && settings.gamedir != NULL) ? settings.gamedir : "/");
-    }
-
-    return retval;
-}
-END_RR_NS
diff --git a/source/rr/src/startosx.game.mm b/source/rr/src/startosx.game.mm
deleted file mode 100644
index 97c0db66e..000000000
--- a/source/rr/src/startosx.game.mm
+++ /dev/null
@@ -1,715 +0,0 @@
-
-#import <Cocoa/Cocoa.h>
-
-#include "ns.h"	// Must come before everything else!
-
-#include "duke3d.h"
-#include "game.h"
-#include "common.h"
-#include "common_game.h"
-#include "build.h"
-#include "compat.h"
-#include "baselayer.h"
-#include "grpscan.h"
-
-#import "GrpFile.game.h"
-#import "GameListSource.game.h"
-
-#ifndef MAC_OS_X_VERSION_10_5
-# define NSImageScaleNone NSScaleNone
-#endif
-
-#ifndef MAC_OS_X_VERSION_10_12
-# define NSEventModifierFlagOption NSAlternateKeyMask
-# define NSEventModifierFlagCommand NSCommandKeyMask
-# define NSEventMaskAny NSAnyEventMask
-# define NSWindowStyleMaskTitled NSTitledWindowMask
-# define NSWindowStyleMaskClosable NSClosableWindowMask
-# define NSWindowStyleMaskMiniaturizable NSMiniaturizableWindowMask
-# define NSWindowStyleMaskResizable NSResizableWindowMask
-# define NSAlertStyleInformational NSInformationalAlertStyle
-# define NSControlSizeSmall NSSmallControlSize
-#endif
-
-static NSRect NSRectChangeXY(NSRect const rect, CGFloat const x, CGFloat const y)
-{
-    return NSMakeRect(x, y, rect.size.width, rect.size.height);
-}
-static NSRect NSSizeAddXY(NSSize const size, CGFloat const x, CGFloat const y)
-{
-    return NSMakeRect(x, y, size.width, size.height);
-}
-#if 0
-static CGFloat NSRightEdge(NSRect rect)
-{
-    return rect.origin.x + rect.size.width;
-}
-#endif
-static CGFloat NSTopEdge(NSRect rect)
-{
-    return rect.origin.y + rect.size.height;
-}
-
-static void setFontToSmall(id control)
-{
-    [control setFont:[NSFont fontWithDescriptor:[[control font] fontDescriptor] size:[NSFont smallSystemFontSize]]];
-}
-
-static void setControlToSmall(id control)
-{
-#ifdef MAC_OS_X_VERSION_10_12
-    [control setControlSize:NSControlSizeSmall];
-#else
-    [control setControlSize:NSControlSizeSmall];
-#endif
-}
-
-static NSTextField * makeLabel(NSString * labelText)
-{
-    NSTextField *textField = [[NSTextField alloc] init];
-    setFontToSmall(textField);
-    setControlToSmall([textField cell]);
-    [textField setStringValue:labelText];
-    [textField setBezeled:NO];
-    [textField setDrawsBackground:NO];
-    [textField setEditable:NO];
-    [textField setSelectable:NO];
-    [textField sizeToFit];
-    return textField;
-}
-
-static NSButton * makeCheckbox(NSString * labelText)
-{
-    NSButton *checkbox = [[NSButton alloc] init];
-    setFontToSmall(checkbox);
-    setControlToSmall([checkbox cell]);
-    [checkbox setTitle:labelText];
-    [checkbox setButtonType:NSSwitchButton];
-    [checkbox sizeToFit];
-    return checkbox;
-}
-
-static NSPopUpButton * makeComboBox(void)
-{
-    NSPopUpButton *comboBox = [[NSPopUpButton alloc] init];
-    [comboBox setPullsDown:NO];
-    setFontToSmall(comboBox);
-    setControlToSmall([comboBox cell]);
-    [comboBox setBezelStyle:NSRoundedBezelStyle];
-    [comboBox setPreferredEdge:NSMaxYEdge];
-    [[comboBox cell] setArrowPosition:NSPopUpArrowAtCenter];
-    [comboBox sizeToFit];
-    return comboBox;
-}
-
-static id nsapp;
-
-/* setAppleMenu disappeared from the headers in 10.4 */
-@interface NSApplication(NSAppleMenu)
-- (void)setAppleMenu:(NSMenu *)menu;
-@end
-
-static NSString * GetApplicationName(void)
-{
-    NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
-    if (!appName)
-        appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
-    if (![appName length])
-        appName = [[NSProcessInfo processInfo] processName];
-
-    return appName;
-}
-
-static void CreateApplicationMenus(void)
-{
-    NSString *appName;
-    NSString *title;
-    NSMenu *rootMenu;
-    NSMenu *serviceMenu;
-    NSMenuItem *menuItem;
-
-    NSMenu *mainMenu = [[NSMenu alloc] init];
-
-    /* Create the application menu */
-    appName = GetApplicationName();
-    rootMenu = [[NSMenu alloc] init];
-
-    /* Put menu into the menubar */
-    menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
-    [menuItem setSubmenu:rootMenu];
-    [mainMenu addItem:menuItem];
-    [menuItem release];
-
-    /* Add menu items */
-    title = [@"About " stringByAppendingString:appName];
-    [rootMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
-
-    [rootMenu addItem:[NSMenuItem separatorItem]];
-
-    serviceMenu = [[NSMenu alloc] init];
-    menuItem = (NSMenuItem *)[rootMenu addItemWithTitle:@"Services" action:nil keyEquivalent:@""];
-    [menuItem setSubmenu:serviceMenu];
-
-    [nsapp setServicesMenu:serviceMenu];
-    [serviceMenu release];
-
-    [rootMenu addItem:[NSMenuItem separatorItem]];
-
-    title = [@"Hide " stringByAppendingString:appName];
-    [rootMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
-
-    menuItem = (NSMenuItem *)[rootMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
-    [menuItem setKeyEquivalentModifierMask:(NSEventModifierFlagOption|NSEventModifierFlagCommand)];
-
-    [rootMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
-
-    [rootMenu addItem:[NSMenuItem separatorItem]];
-
-    title = [@"Quit " stringByAppendingString:appName];
-    [rootMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
-
-    /* Create the main menu bar */
-    [nsapp setMainMenu:mainMenu];
-    [mainMenu release];  /* we're done with it, let NSApp own it. */
-
-    /* Tell the application object that this is now the application menu */
-    [nsapp setAppleMenu:rootMenu];
-    [rootMenu release];
-}
-
-static int retval = -1;
-
-static struct {
-    grpfile_t const * grp;
-    int fullscreen;
-    int xdim3d, ydim3d, bpp3d;
-    int forcesetup;
-} settings;
-
-@interface StartupWindow : NSWindow <NSWindowDelegate>
-{
-    NSMutableArray *modeslist3d;
-    GameListSource *gamelistsrc;
-
-    NSButton *alwaysShowButton;
-    NSButton *fullscreenButton;
-    NSTextView *messagesView;
-    NSTabView *tabView;
-    NSTabViewItem *tabViewItemSetup;
-    NSTabViewItem *tabViewItemMessageLog;
-    NSPopUpButton *videoMode3DPUButton;
-    NSScrollView *gameList;
-
-    NSButton *cancelButton;
-    NSButton *startButton;
-}
-
-- (StartupWindow *)init;
-
-- (void)dealloc;
-- (void)populateVideoModes:(BOOL)firstTime;
-
-- (void)fullscreenClicked:(id)sender;
-
-- (void)cancel:(id)sender;
-- (void)start:(id)sender;
-
-- (void)setupRunMode;
-- (void)setupMessagesMode;
-
-- (void)putsMessage:(NSString *)str;
-
-@end
-
-@implementation StartupWindow : NSWindow
-
-- (StartupWindow *)init
-{
-    NSUInteger const style = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable;
-    NSRect const windowFrame = NSMakeRect(0, 0, 480, 280);
-    self = [super initWithContentRect:windowFrame styleMask:style backing:NSBackingStoreBuffered defer:NO];
-
-    if (self)
-    {
-        // window properties
-        [self setDelegate:self];
-        [self setReleasedWhenClosed:NO];
-#if defined MAC_OS_X_VERSION_10_3 && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3
-        [self setContentMinSize:[[self contentView] frame].size];
-#else
-        [self setMinSize:[NSWindow frameRectForContentRect:[[self contentView] frame] styleMask:[self styleMask]].size];
-#endif
-
-
-        // image on the left
-        NSRect const imageFrame = NSMakeRect(0, 0, 100, 280);
-        NSImageView * imageView = [[NSImageView alloc] initWithFrame:imageFrame];
-        [imageView setImageScaling:NSImageScaleNone];
-        [imageView setImage:[NSImage imageNamed:@"game"]];
-        [[self contentView] addSubview:imageView];
-        [imageView setAutoresizingMask:NSViewMaxXMargin | NSViewHeightSizable];
-
-
-        // buttons
-        CGFloat const buttonWidth = 80;
-        CGFloat const buttonHeight = 32;
-
-        NSRect const startButtonFrame = NSMakeRect(windowFrame.size.width - buttonWidth, 0, buttonWidth, buttonHeight);
-        startButton = [[NSButton alloc] initWithFrame:startButtonFrame];
-        [[self contentView] addSubview:startButton];
-        [startButton setTitle:@"Start"];
-        [startButton setTarget:self];
-        [startButton setAction:@selector(start:)];
-        [startButton setBezelStyle:NSRoundedBezelStyle];
-        [startButton setKeyEquivalent:@"\r"];
-        [startButton setAutoresizingMask:NSViewMinXMargin | NSViewMaxYMargin];
-
-        NSRect const cancelButtonFrame = NSMakeRect(startButtonFrame.origin.x - buttonWidth, 0, buttonWidth, buttonHeight);
-        cancelButton = [[NSButton alloc] initWithFrame:cancelButtonFrame];
-        [[self contentView] addSubview:cancelButton];
-        [cancelButton setTitle:@"Cancel"];
-        [cancelButton setTarget:self];
-        [cancelButton setAction:@selector(cancel:)];
-        [cancelButton setBezelStyle:NSRoundedBezelStyle];
-        [cancelButton setAutoresizingMask:NSViewMinXMargin | NSViewMaxYMargin];
-
-
-        // tab frame
-        NSRect const tabViewFrame = NSMakeRect(imageFrame.size.width, buttonHeight, windowFrame.size.width - imageFrame.size.width, windowFrame.size.height - buttonHeight - 5);
-        tabView = [[NSTabView alloc] initWithFrame:tabViewFrame];
-        [[self contentView] addSubview:tabView];
-        setFontToSmall(tabView);
-        setControlToSmall(tabView);
-        [tabView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
-
-
-        // setup tab
-
-        tabViewItemSetup = [[NSTabViewItem alloc] init];
-        [tabView addTabViewItem:tabViewItemSetup];
-        [tabViewItemSetup setLabel:@"Setup"];
-        NSRect const tabViewItemSetupFrame = [[tabViewItemSetup view] frame];
-
-
-        // always show checkbox
-        alwaysShowButton = makeCheckbox(@"Always show this window at startup");
-        [[tabViewItemSetup view] addSubview:alwaysShowButton];
-        NSSize const alwaysShowButtonSize = [alwaysShowButton frame].size;
-        NSRect const alwaysShowButtonFrame = NSSizeAddXY(alwaysShowButtonSize, tabViewItemSetupFrame.size.width - alwaysShowButtonSize.width, 0);
-        [alwaysShowButton setFrame:alwaysShowButtonFrame];
-        [alwaysShowButton setAutoresizingMask:NSViewMinXMargin | NSViewMaxYMargin];
-
-
-        // video mode selectors and labels
-        NSTextField * labelVideoMode = makeLabel(@"Video mode:");
-        [[tabViewItemSetup view] addSubview:labelVideoMode];
-        NSSize const labelVideoModeSize = [labelVideoMode frame].size;
-        [labelVideoMode setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
-
-        fullscreenButton = makeCheckbox(@"Fullscreen");
-        [[tabViewItemSetup view] addSubview:fullscreenButton];
-        NSSize const fullscreenButtonSize = [fullscreenButton frame].size;
-        [fullscreenButton setAction:@selector(fullscreenClicked:)];
-        [fullscreenButton setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
-
-        videoMode3DPUButton = makeComboBox();
-        [[tabViewItemSetup view] addSubview:videoMode3DPUButton];
-        NSSize const videoMode3DPUButtonSize = [videoMode3DPUButton frame].size;
-        CGFloat const videoMode3DButtonX = labelVideoModeSize.width; // NSRightEdge(labelVideoModeFrame);
-        NSRect const videoMode3DPUButtonFrame = NSMakeRect(videoMode3DButtonX, tabViewItemSetupFrame.size.height - videoMode3DPUButtonSize.height, tabViewItemSetupFrame.size.width - videoMode3DButtonX - fullscreenButtonSize.width, videoMode3DPUButtonSize.height);
-        [videoMode3DPUButton setFrame:videoMode3DPUButtonFrame];
-        [videoMode3DPUButton setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin];
-
-        NSRect const labelVideoModeFrame = NSSizeAddXY(labelVideoModeSize, 0, videoMode3DPUButtonFrame.origin.y + rintf((videoMode3DPUButtonSize.height - labelVideoModeSize.height) * 0.5f) + 1);
-        [labelVideoMode setFrame:labelVideoModeFrame];
-
-        NSRect const fullscreenButtonFrame = NSSizeAddXY(fullscreenButtonSize, tabViewItemSetupFrame.size.width - fullscreenButtonSize.width, videoMode3DPUButtonFrame.origin.y + rintf((videoMode3DPUButtonSize.height - fullscreenButtonSize.height) * 0.5f) + 1);
-        [fullscreenButton setFrame:fullscreenButtonFrame];
-
-
-        // game selector and label
-        NSTextField * labelGame = makeLabel(@"Game:");
-        [[tabViewItemSetup view] addSubview:labelGame];
-        NSSize const labelGameSize = [labelGame frame].size;
-        NSRect const labelGameFrame = NSSizeAddXY(labelGameSize, 0, videoMode3DPUButtonFrame.origin.y - labelGameSize.height);
-        [labelGame setFrame:labelGameFrame];
-        [labelGame setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
-
-        CGFloat const gameListVerticalPadding = 3;
-        CGFloat const gameListY = NSTopEdge(alwaysShowButtonFrame) + gameListVerticalPadding;
-        NSRect const gameListFrame = NSMakeRect(0, gameListY, tabViewItemSetupFrame.size.width, labelGameFrame.origin.y - gameListY - gameListVerticalPadding);
-        gameList = [[NSScrollView alloc] initWithFrame:gameListFrame];
-        [[tabViewItemSetup view] addSubview:gameList];
-        [gameList setBorderType:NSBezelBorder];
-        [gameList setHasVerticalScroller:YES];
-        [gameList setHasHorizontalScroller:NO];
-        setControlToSmall([[gameList verticalScroller] cell]);
-        NSSize const gameListContentSize = [gameList contentSize];
-        [gameList setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
-
-        NSTableView * gameListTable = [[NSTableView alloc] initWithFrame:NSMakeRect(0, 0, gameListContentSize.width, gameListContentSize.height)];
-        [gameList setDocumentView:gameListTable];
-
-        NSTableColumn * nameColumn = [[NSTableColumn alloc] initWithIdentifier:@"0"];
-        [gameListTable addTableColumn:nameColumn];
-        NSTableColumn * fileColumn = [[NSTableColumn alloc] initWithIdentifier:@"1"];
-        [gameListTable addTableColumn:fileColumn];
-        [nameColumn setEditable:NO];
-        [[nameColumn headerCell] setStringValue:@"Name"];
-        [nameColumn setWidth:gameListContentSize.width * (2.f/3.f)];
-        [fileColumn setEditable:NO];
-        [[fileColumn headerCell] setStringValue:@"File"];
-        [gameListTable sizeLastColumnToFit];
-        [gameListTable setAutoresizingMask:NSViewWidthSizable];
-
-
-        // message log tab
-
-        tabViewItemMessageLog = [[NSTabViewItem alloc] init];
-        [tabView addTabViewItem:tabViewItemMessageLog];
-        [tabViewItemMessageLog setLabel:@"Message Log"];
-        NSRect const tabViewItemMessageLogFrame = [[tabViewItemMessageLog view] frame];
-
-
-        // message log
-        NSScrollView * messagesScrollView = [[NSScrollView alloc] initWithFrame:NSRectChangeXY(tabViewItemMessageLogFrame, 0, 0)];
-        [[tabViewItemMessageLog view] addSubview:messagesScrollView];
-        [messagesScrollView setBorderType:NSBezelBorder];
-        [messagesScrollView setHasVerticalScroller:YES];
-        [messagesScrollView setHasHorizontalScroller:NO];
-        setControlToSmall([[messagesScrollView verticalScroller] cell]);
-        NSSize const messagesScrollViewContentSize = [messagesScrollView contentSize];
-        [messagesScrollView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
-
-        messagesView = [[NSTextView alloc] initWithFrame:NSMakeRect(0, 0, messagesScrollViewContentSize.width, messagesScrollViewContentSize.height)];
-        [messagesScrollView setDocumentView:messagesView];
-        [messagesView setEditable:NO];
-        [messagesView setRichText:NO];
-        setFontToSmall(messagesView);
-        [messagesView setMinSize:NSMakeSize(0.0, messagesScrollViewContentSize.height)];
-        [messagesView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
-        [messagesView setVerticallyResizable:YES];
-        [messagesView setHorizontallyResizable:NO];
-        [messagesView setAutoresizingMask:NSViewWidthSizable];
-
-        [[messagesView textContainer] setContainerSize:NSMakeSize(messagesScrollViewContentSize.width, FLT_MAX)];
-        [[messagesView textContainer] setWidthTracksTextView:YES];
-    }
-
-    return self;
-}
-
-- (BOOL)canBecomeKeyWindow
-{
-    return YES;
-}
-
-- (BOOL)canBecomeMainWindow
-{
-    return YES;
-}
-
-- (BOOL) windowShouldClose:(id)sender
-{
-    UNREFERENCED_PARAMETER(sender);
-
-    retval = 0;
-
-    return YES;
-}
-
-- (void)dealloc
-{
-    [gamelistsrc release];
-    [modeslist3d release];
-    [super dealloc];
-}
-
-- (void)populateVideoModes:(BOOL)firstTime
-{
-    int i, mode3d, fullscreen = ([fullscreenButton state] == NSOnState);
-    int idx3d = -1;
-    int xdim = 0, ydim = 0, bpp = 0;
-
-    if (firstTime) {
-        xdim = settings.xdim3d;
-        ydim = settings.ydim3d;
-        bpp  = settings.bpp3d;
-    } else {
-        mode3d = [[modeslist3d objectAtIndex:[videoMode3DPUButton indexOfSelectedItem]] intValue];
-        if (mode3d >= 0) {
-            xdim = validmode[mode3d].xdim;
-            ydim = validmode[mode3d].ydim;
-            bpp = validmode[mode3d].bpp;
-        }
-
-    }
-    mode3d = videoCheckMode(&xdim, &ydim, bpp, fullscreen, 1);
-    if (mode3d < 0) {
-        int i, cd[] = { 32, 24, 16, 15, 8, 0 };
-        for (i=0; cd[i]; ) { if (cd[i] >= bpp) i++; else break; }
-        for ( ; cd[i]; i++) {
-            mode3d = videoCheckMode(&xdim, &ydim, cd[i], fullscreen, 1);
-            if (mode3d < 0) continue;
-            break;
-        }
-    }
-
-    [modeslist3d release];
-    [videoMode3DPUButton removeAllItems];
-
-    modeslist3d = [[NSMutableArray alloc] init];
-
-    for (i = 0; i < validmodecnt; i++) {
-        if (fullscreen == validmode[i].fs) {
-            if (i == mode3d) idx3d = [modeslist3d count];
-            [modeslist3d addObject:[NSNumber numberWithInt:i]];
-            [videoMode3DPUButton addItemWithTitle:[NSString stringWithFormat:@"%d %C %d %d-bpp",
-                                                   validmode[i].xdim, 0xd7, validmode[i].ydim, validmode[i].bpp]];
-        }
-    }
-
-    if (idx3d >= 0) [videoMode3DPUButton selectItemAtIndex:idx3d];
-}
-
-- (void)fullscreenClicked:(id)sender
-{
-    UNREFERENCED_PARAMETER(sender);
-
-    [self populateVideoModes:NO];
-}
-
-- (void)cancel:(id)sender
-{
-    UNREFERENCED_PARAMETER(sender);
-
-    retval = 0;
-}
-
-- (void)start:(id)sender
-{
-    UNREFERENCED_PARAMETER(sender);
-
-    int mode = [[modeslist3d objectAtIndex:[videoMode3DPUButton indexOfSelectedItem]] intValue];
-    if (mode >= 0) {
-        settings.xdim3d = validmode[mode].xdim;
-        settings.ydim3d = validmode[mode].ydim;
-        settings.bpp3d = validmode[mode].bpp;
-        settings.fullscreen = validmode[mode].fs;
-    }
-
-    int row = [[gameList documentView] selectedRow];
-    if (row >= 0) {
-        settings.grp = [[gamelistsrc grpAtIndex:row] entryptr];
-    }
-
-    settings.forcesetup = [alwaysShowButton state] == NSOnState;
-
-    retval = 1;
-}
-
-- (void)setupRunMode
-{
-    videoGetModes();
-
-    [fullscreenButton setState: (settings.fullscreen ? NSOnState : NSOffState)];
-    [alwaysShowButton setState: (settings.forcesetup ? NSOnState : NSOffState)];
-    [self populateVideoModes:YES];
-
-    // enable all the controls on the Configuration page
-    NSEnumerator *enumerator = [[[tabViewItemSetup view] subviews] objectEnumerator];
-    NSControl *control;
-    while ((control = [enumerator nextObject]))
-    {
-        if ([control respondsToSelector:@selector(setEnabled:)])
-            [control setEnabled:true];
-    }
-
-    gamelistsrc = [[GameListSource alloc] init];
-    [[gameList documentView] setDataSource:gamelistsrc];
-    [[gameList documentView] deselectAll:nil];
-
-    if (settings.grp)
-    {
-        int row = [gamelistsrc findIndexForGrpname:[NSString stringWithUTF8String:settings.grp->filename]];
-        if (row >= 0)
-        {
-            [[gameList documentView] scrollRowToVisible:row];
-#if defined MAC_OS_X_VERSION_10_3 && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3
-            [[gameList documentView] selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
-#else
-            [[gameList documentView] selectRow:row byExtendingSelection:NO];
-#endif
-        }
-    }
-
-    [cancelButton setEnabled:true];
-    [startButton setEnabled:true];
-
-    [tabView selectTabViewItem:tabViewItemSetup];
-    [NSCursor unhide]; // Why should I need to do this?
-}
-
-- (void)setupMessagesMode
-{
-    [tabView selectTabViewItem:tabViewItemMessageLog];
-
-    // disable all the controls on the Configuration page except "always show", so the
-    // user can enable it if they want to while waiting for something else to happen
-    NSEnumerator *enumerator = [[[tabViewItemSetup view] subviews] objectEnumerator];
-    NSControl *control;
-    while ((control = [enumerator nextObject]))
-    {
-        if (control != alwaysShowButton && [control respondsToSelector:@selector(setEnabled:)])
-            [control setEnabled:false];
-    }
-
-    [cancelButton setEnabled:false];
-    [startButton setEnabled:false];
-}
-
-- (void)putsMessage:(NSString *)str
-{
-    NSRange end;
-    NSTextStorage *text = [messagesView textStorage];
-    BOOL shouldAutoScroll;
-
-    shouldAutoScroll = ((int)NSMaxY([messagesView bounds]) == (int)NSMaxY([messagesView visibleRect]));
-
-    end.location = [text length];
-    end.length = 0;
-
-    [text beginEditing];
-    [messagesView replaceCharactersInRange:end withString:str];
-    [text endEditing];
-
-    if (shouldAutoScroll) {
-        end.location = [text length];
-        end.length = 0;
-        [messagesView scrollRangeToVisible:end];
-    }
-}
-
-@end
-
-static StartupWindow *startwin = nil;
-
-int startwin_open(void)
-{
-    // fix for "ld: absolute address to symbol _NSApp in a different linkage unit not supported"
-    // (OS X 10.6) when building for PPC
-    nsapp = [NSApplication sharedApplication];
-
-    if (startwin != nil) return 1;
-
-    startwin = [[StartupWindow alloc] init];
-    if (startwin == nil) return -1;
-
-    [startwin setupMessagesMode];
-
-    [nsapp finishLaunching];
-
-    [startwin center];
-    [startwin makeKeyAndOrderFront:nil];
-
-    CreateApplicationMenus();
-
-    return 0;
-}
-
-int startwin_close(void)
-{
-    if (startwin == nil) return 1;
-
-    [startwin close];
-    [startwin release];
-    startwin = nil;
-
-    return 0;
-}
-
-int startwin_puts(const char *s)
-{
-    NSString *ns;
-
-    if (!s) return -1;
-    if (startwin == nil) return 1;
-
-    ns = [NSString stringWithUTF8String:s];
-    [startwin putsMessage:ns];
-    [ns release];
-
-    return 0;
-}
-
-int startwin_settitle(const char *s)
-{
-    NSString *ns;
-
-    if (!s) return -1;
-    if (startwin == nil) return 1;
-
-    ns = [NSString stringWithUTF8String:s];
-    [startwin setTitle:ns];
-    [ns release];
-
-    return 0;
-}
-
-int startwin_idle(void *v)
-{
-    UNREFERENCED_PARAMETER(v);
-
-    if (startwin)
-    {
-        NSEvent *event;
-        do
-        {
-            event = [nsapp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate date] inMode:NSDefaultRunLoopMode dequeue:YES];
-            [nsapp sendEvent:event];
-        }
-        while (event != nil);
-
-        [startwin displayIfNeeded];
-        [nsapp updateWindows];
-    }
-
-    return 0;
-}
-
-
-int startwin_run(void)
-{
-    if (startwin == nil) return 0;
-
-    settings.fullscreen = ud.config.ScreenMode;
-    settings.xdim3d = ud.config.ScreenWidth;
-    settings.ydim3d = ud.config.ScreenHeight;
-    settings.bpp3d = ud.config.ScreenBPP;
-    settings.forcesetup = ud.config.ForceSetup;
-    settings.grp = g_selectedGrp;
-
-    [startwin setupRunMode];
-
-    do
-    {
-        NSEvent *event = [nsapp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantFuture] inMode:NSDefaultRunLoopMode dequeue:YES];
-        [nsapp sendEvent:event];
-        [nsapp updateWindows];
-    }
-    while (retval == -1);
-
-    [startwin setupMessagesMode];
-    [nsapp updateWindows];
-
-    if (retval) {
-        ud.config.ScreenMode = settings.fullscreen;
-        ud.config.ScreenWidth = settings.xdim3d;
-        ud.config.ScreenHeight = settings.ydim3d;
-        ud.config.ScreenBPP = settings.bpp3d;
-        ud.config.ForceSetup = settings.forcesetup;
-        g_selectedGrp = settings.grp;
-    }
-
-    return retval;
-}
diff --git a/source/rr/src/startwin.game.cpp b/source/rr/src/startwin.game.cpp
deleted file mode 100644
index 1168ce385..000000000
--- a/source/rr/src/startwin.game.cpp
+++ /dev/null
@@ -1,676 +0,0 @@
-//-------------------------------------------------------------------------
-/*
-Copyright (C) 2010 EDuke32 developers and contributors
-
-This file is part of EDuke32.
-
-EDuke32 is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License version 2
-as published by the Free Software Foundation.
-
-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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-//-------------------------------------------------------------------------
-#include "ns.h"	// Must come before everything else!
-
-#ifndef _WIN32
-#error Only for Windows
-#endif
-
-#include "renderlayer.h"
-
-#ifdef STARTUP_SETUP_WINDOW
-
-#define NEED_WINDOWSX_H
-#define NEED_COMMCTRL_H
-#define ONLY_USERDEFS
-
-#include "_control.h"
-#include "build.h"
-#include "cache1d.h"
-#include "cmdline.h"
-#include "common_game.h"
-#include "compat.h"
-#include "control.h"
-#include "gamecontrol.h"
-#include "game.h"
-#include "grpscan.h"
-#include "inv.h"
-#include "keyboard.h"
-#include "gamecvars.h"
-#include "startwin.game.h"
-#include "windows_inc.h"
-
-#pragma warning(disable:4244) // There's just a bit too much of these in here...
-
-BEGIN_RR_NS
-
-#define TAB_CONFIG 0
-#define TAB_MESSAGES 1
-
-typedef struct {
-	int32_t fullscreen;
-	int32_t xdim;
-	int32_t ydim;
-	int32_t bpp;
-} ud_setup_t;
-
-
-static struct
-{
-    struct grpfile_t const * grp;
-    char *gamedir;
-    ud_setup_t shared;
-    int polymer;
-}
-settings;
-
-static HWND startupdlg;
-static HWND pages[3];
-static int done = -1;
-static int mode = TAB_CONFIG;
-
-static CACHE1D_FIND_REC *finddirs;
-
-static inline void clearfilenames(void)
-{
-    klistfree(finddirs);
-    finddirs = NULL;
-}
-
-static inline void getfilenames(char const *path)
-{
-    clearfilenames();
-    finddirs = klistpath(path,"*",CACHE1D_FIND_DIR);
-}
-
-#define POPULATE_VIDEO 1
-#define POPULATE_CONFIG 2
-#define POPULATE_GAME 4
-#define POPULATE_GAMEDIRS 8
-
-#ifdef INPUT_MOUSE
-#undef INPUT_MOUSE
-#endif
-
-#define INPUT_KB 0
-#define INPUT_MOUSE 1
-#define INPUT_JOYSTICK 2
-#define INPUT_ALL 3
-
-// Thanks, Microsoft for not providing alternatives for the dialog control macros. :(
-#undef SNDMSG
-#define SNDMSG ::SendMessageA
-
-const char *controlstrings[] = { "Keyboard only", "Keyboard and mouse", "Keyboard and joystick", "All supported devices" };
-
-static void PopulateForm(int32_t pgs)
-{
-    char buf[512];
-
-    if (pgs & POPULATE_GAMEDIRS)
-    {
-        HWND hwnd = GetDlgItem(pages[TAB_CONFIG], IDCGAMEDIR);
-
-        getfilenames("/");
-        (void)ComboBox_ResetContent(hwnd);
-        int const r = ComboBox_AddString(hwnd, "None");
-        (void)ComboBox_SetItemData(hwnd, r, 0);
-        (void)ComboBox_SetCurSel(hwnd, r);
-        auto dirs = finddirs;
-        for (int i=1, j=1; dirs != NULL; dirs=dirs->next)
-        {
-            if (Bstrcasecmp(dirs->name, "autoload") == 0)
-            {
-                j++;
-                continue;
-            }
-
-            (void)ComboBox_AddString(hwnd, dirs->name);
-            (void)ComboBox_SetItemData(hwnd, i, j);
-            if (Bstrcasecmp(dirs->name, settings.gamedir) == 0)
-                (void)ComboBox_SetCurSel(hwnd, i);
-
-            i++;
-            j++;
-        }
-    }
-
-    if (pgs & POPULATE_VIDEO)
-    {
-        HWND hwnd = GetDlgItem(pages[TAB_CONFIG], IDCVMODE);
-        int mode = videoCheckMode(&settings.shared.xdim, &settings.shared.ydim, settings.shared.bpp, settings.shared.fullscreen, 1);
-
-        if (mode < 0 || (settings.shared.bpp < 15 && (settings.polymer)))
-        {
-            int CONSTEXPR cd[] = { 32, 24, 16, 15, 8, 0 };
-            int i;
-
-            for (i=0; cd[i];)
-            {
-                if (cd[i] >= settings.shared.bpp) i++;
-                else break;
-            }
-            for (; cd[i]; i++)
-            {
-                mode = videoCheckMode(&settings.shared.xdim, &settings.shared.ydim, cd[i], settings.shared.fullscreen, 1);
-                if (mode < 0) continue;
-                settings.shared.bpp = cd[i];
-                break;
-            }
-        }
-
-        Button_SetCheck(GetDlgItem(pages[TAB_CONFIG], IDCFULLSCREEN), ((settings.shared.fullscreen) ? BST_CHECKED : BST_UNCHECKED));
-        //Button_SetCheck(GetDlgItem(pages[TAB_CONFIG], IDCPOLYMER), ((settings.polymer) ? BST_CHECKED : BST_UNCHECKED));
-
-        (void)ComboBox_ResetContent(hwnd);
-
-        for (int i=0; i<validmodecnt; i++)
-        {
-            if (validmode[i].fs != (settings.shared.fullscreen)) continue;
-            if ((validmode[i].bpp < 15) && (settings.polymer)) continue;
-
-            // all modes get added to the 3D mode list
-            Bsprintf(buf, "%dx%d %s", validmode[i].xdim, validmode[i].ydim, validmode[i].bpp == 8 ? "software" : "OpenGL");
-            int const j = ComboBox_AddString(hwnd, buf);
-            (void)ComboBox_SetItemData(hwnd, j, i);
-            if (i == mode)(void)ComboBox_SetCurSel(hwnd, j);
-        }
-    }
-
-    if (pgs & POPULATE_GAME)
-    {
-        HWND hwnd = GetDlgItem(pages[TAB_CONFIG], IDCDATA);
-
-        for (auto fg = foundgrps; fg; fg=fg->next)
-        {
-            Bsprintf(buf, "%s\t%s", fg->type->name, fg->filename);
-            int const j = ListBox_AddString(hwnd, buf);
-            (void)ListBox_SetItemData(hwnd, j, (LPARAM)fg);
-            if (settings.grp == fg)
-                (void)ListBox_SetCurSel(hwnd, j);
-        }
-    }
-}
-
-static INT_PTR CALLBACK ConfigPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
-    switch (uMsg)
-    {
-    case WM_COMMAND:
-        switch (LOWORD(wParam))
-        {
-        case IDCFULLSCREEN:
-            settings.shared.fullscreen = !settings.shared.fullscreen;
-            PopulateForm(POPULATE_VIDEO);
-            return TRUE;
-        //case IDCPOLYMER:
-        //    settings.polymer = !settings.polymer;
-        //    if (settings.shared.bpp == 8) settings.shared.bpp = 32;
-        //    PopulateForm(POPULATE_VIDEO);
-        //    return TRUE;
-        case IDCVMODE:
-            if (HIWORD(wParam) == CBN_SELCHANGE)
-            {
-                int i = ComboBox_GetCurSel((HWND)lParam);
-                if (i != CB_ERR) i = ComboBox_GetItemData((HWND)lParam, i);
-                if (i != CB_ERR)
-                {
-                    settings.shared.xdim = validmode[i].xdim;
-                    settings.shared.ydim = validmode[i].ydim;
-                    settings.shared.bpp  = validmode[i].bpp;
-                }
-            }
-            return TRUE;
-        case IDCALWAYSSHOW:
-            displaysetup = IsDlgButtonChecked(hwndDlg, IDCALWAYSSHOW) == BST_CHECKED;
-            return TRUE;
-        case IDCAUTOLOAD:
-            noautoload = (IsDlgButtonChecked(hwndDlg, IDCAUTOLOAD) != BST_CHECKED);
-            return TRUE;
-        case IDCINPUT:
-            return TRUE;
-
-        case IDCGAMEDIR:
-            if (HIWORD(wParam) == CBN_SELCHANGE)
-            {
-                int i = ComboBox_GetCurSel((HWND)lParam);
-                if (i != CB_ERR) i = ComboBox_GetItemData((HWND)lParam, i);
-                if (i != CB_ERR)
-                {
-                    if (i==0)
-                        settings.gamedir = NULL;
-                    else
-                    {
-                        CACHE1D_FIND_REC *dir = finddirs;
-                        for (int j = 1; dir != NULL; dir = dir->next, j++)
-                        {
-                            if (j == i)
-                            {
-                                settings.gamedir = dir->name;
-                                break;
-                            }
-                        }
-                    }
-                }
-            }
-            return TRUE;
-        case IDCDATA:
-        {
-            if (HIWORD(wParam) != LBN_SELCHANGE) break;
-            intptr_t i = ListBox_GetCurSel((HWND)lParam);
-            if (i != CB_ERR) i = ListBox_GetItemData((HWND)lParam, i);
-            if (i != CB_ERR)
-            {
-                settings.grp = (grpfile_t const *)i;
-            }
-            return TRUE;
-        }
-        default:
-            break;
-        }
-        break;
-    default:
-        break;
-    }
-    return FALSE;
-}
-
-
-static void SetPage(int pageNum)
-{
-    HWND tab = GetDlgItem(startupdlg, WIN_STARTWIN_TABCTL);
-    auto const cur = SendMessageA(tab, TCM_GETCURSEL, 0, 0);
-    ShowWindow(pages[cur], SW_HIDE);
-    SendMessageA(tab, TCM_SETCURSEL, pageNum, 0);
-    ShowWindow(pages[pageNum], SW_SHOW);
-    mode = pageNum;
-
-    SetFocus(GetDlgItem(startupdlg, WIN_STARTWIN_TABCTL));
-}
-
-static void EnableConfig(bool n)
-{
-    //EnableWindow(GetDlgItem(startupdlg, WIN_STARTWIN_CANCEL), n);
-    EnableWindow(GetDlgItem(startupdlg, WIN_STARTWIN_START), n);
-    EnableWindow(GetDlgItem(pages[TAB_CONFIG], IDCDATA), n);
-    EnableWindow(GetDlgItem(pages[TAB_CONFIG], IDCFULLSCREEN), n);
-    EnableWindow(GetDlgItem(pages[TAB_CONFIG], IDCGAMEDIR), n);
-    EnableWindow(GetDlgItem(pages[TAB_CONFIG], IDCINPUT), n);
-    //EnableWindow(GetDlgItem(pages[TAB_CONFIG], IDCPOLYMER), n);
-    EnableWindow(GetDlgItem(pages[TAB_CONFIG], IDCVMODE), n);
-}
-
-static INT_PTR CALLBACK startup_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
-    static HBITMAP hbmp = NULL;
-
-    switch (uMsg)
-    {
-    case WM_INITDIALOG:
-    {
-        // Fetch the positions (in screen coordinates) of all the windows we need to tweak
-        RECT chrome = {};
-        AdjustWindowRect(&chrome, GetWindowLong(hwndDlg, GWL_STYLE), FALSE);
-        RECT rdlg;
-        GetWindowRect(hwndDlg, &rdlg);
-
-        // Knock off the non-client area of the main dialogue to give just the client area
-        rdlg.left -= chrome.left;
-        rdlg.top -= chrome.top;
-        rdlg.right -= chrome.right;
-        rdlg.bottom -= chrome.bottom;
-
-        RECT rtab;
-        GetWindowRect(GetDlgItem(hwndDlg, WIN_STARTWIN_TABCTL), &rtab);
-
-        // Translate them to client-relative coordinates wrt the main dialogue window
-        rtab.right -= rtab.left - 1;
-        rtab.bottom -= rtab.top - 1;
-        rtab.left  -= rdlg.left;
-        rtab.top -= rdlg.top;
-
-        RECT rcancel;
-        GetWindowRect(GetDlgItem(hwndDlg, WIN_STARTWIN_CANCEL), &rcancel);
-
-        rcancel.right -= rcancel.left - 1;
-        rcancel.bottom -= rcancel.top - 1;
-        rcancel.left -= rdlg.left;
-        rcancel.top -= rdlg.top;
-
-        RECT rstart;
-        GetWindowRect(GetDlgItem(hwndDlg, WIN_STARTWIN_START), &rstart);
-
-        rstart.right -= rstart.left - 1;
-        rstart.bottom -= rstart.top - 1;
-        rstart.left -= rdlg.left;
-        rstart.top -= rdlg.top;
-
-        // And then convert the main dialogue coordinates to just width/length
-        rdlg.right -= rdlg.left - 1;
-        rdlg.bottom -= rdlg.top - 1;
-        rdlg.left = 0;
-        rdlg.top = 0;
-
-        // Load the bitmap into the bitmap control and fetch its dimensions
-        hbmp = LoadBitmap((HINSTANCE)win_gethinstance(), MAKEINTRESOURCE(RSRC_BMP));
-
-        HWND hwnd = GetDlgItem(hwndDlg, WIN_STARTWIN_BITMAP);
-        SendMessageA(hwnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbmp);
-
-        RECT r;
-        GetClientRect(hwnd, &r);
-
-        int const xoffset = r.right;
-        int const yoffset = r.bottom - rdlg.bottom;
-
-        // Shift and resize the controls that require it
-        rtab.left += xoffset;
-        rtab.bottom += yoffset;
-        rcancel.left += xoffset;
-        rcancel.top += yoffset;
-        rstart.left += xoffset;
-        rstart.top += yoffset;
-        rdlg.right += xoffset;
-        rdlg.bottom += yoffset;
-
-        // Move the controls to their new positions
-        MoveWindow(GetDlgItem(hwndDlg, WIN_STARTWIN_TABCTL), rtab.left, rtab.top, rtab.right, rtab.bottom, FALSE);
-        MoveWindow(GetDlgItem(hwndDlg, WIN_STARTWIN_CANCEL), rcancel.left, rcancel.top, rcancel.right, rcancel.bottom, FALSE);
-        MoveWindow(GetDlgItem(hwndDlg, WIN_STARTWIN_START), rstart.left, rstart.top, rstart.right, rstart.bottom, FALSE);
-
-        // Move the main dialogue to the centre of the screen
-        HDC hdc = GetDC(NULL);
-        rdlg.left = (GetDeviceCaps(hdc, HORZRES) - rdlg.right) / 2;
-        rdlg.top = (GetDeviceCaps(hdc, VERTRES) - rdlg.bottom) / 2;
-        ReleaseDC(NULL, hdc);
-        MoveWindow(hwndDlg, rdlg.left + chrome.left, rdlg.top + chrome.left,
-                   rdlg.right + (-chrome.left+chrome.right), rdlg.bottom + (-chrome.top+chrome.bottom), TRUE);
-
-        // Add tabs to the tab control
-        {
-            static char textSetup[] = "Setup";
-            static char textMessageLog[] = "Message Log";
-
-            hwnd = GetDlgItem(hwndDlg, WIN_STARTWIN_TABCTL);
-
-            TCITEMA tab = {};
-            tab.mask = TCIF_TEXT;
-            tab.pszText = textSetup;
-            SendMessageA(hwnd, TCM_INSERTITEMA, (WPARAM)TAB_CONFIG, (LPARAM)&tab);
-            tab.mask = TCIF_TEXT;
-            tab.pszText = textMessageLog;
-            SendMessageA(hwnd, TCM_INSERTITEMA, (WPARAM)TAB_MESSAGES, (LPARAM)&tab);
-
-            // Work out the position and size of the area inside the tab control for the pages
-            ZeroMemory(&r, sizeof(r));
-            GetClientRect(hwnd, &r);
-            SendMessageA(hwnd, TCM_ADJUSTRECT, FALSE, (LPARAM)&r);
-            r.right -= r.left-1;
-            r.bottom -= r.top-1;
-            r.top += rtab.top;
-            r.left += rtab.left;
-
-            // Create the pages and position them in the tab control, but hide them
-            pages[TAB_CONFIG] = CreateDialog((HINSTANCE)win_gethinstance(), MAKEINTRESOURCE(WIN_STARTWINPAGE_CONFIG), hwndDlg, ConfigPageProc);
-            SetWindowPos(pages[TAB_CONFIG], hwnd, r.left, r.top, r.right, r.bottom, SWP_HIDEWINDOW);
-
-            pages[TAB_MESSAGES] = GetDlgItem(hwndDlg, WIN_STARTWIN_MESSAGES);
-            SetWindowPos(pages[TAB_MESSAGES], hwnd, r.left, r.top, r.right, r.bottom, SWP_HIDEWINDOW);
-
-            // Tell the editfield acting as the console to exclude the width of the scrollbar
-            GetClientRect(pages[TAB_MESSAGES], &r);
-            r.right -= GetSystemMetrics(SM_CXVSCROLL)+4;
-            r.left = r.top = 0;
-            SendMessageA(pages[TAB_MESSAGES], EM_SETRECTNP,0,(LPARAM)&r);
-
-            // Set a tab stop in the game data listbox
-            {
-                DWORD tabs[1] = { 150 };
-                (void)ListBox_SetTabStops(GetDlgItem(pages[TAB_CONFIG], IDCDATA), 1, tabs);
-            }
-
-            SetFocus(GetDlgItem(hwndDlg, WIN_STARTWIN_START));
-            SetWindowTextA(hwndDlg, apptitle);
-        }
-        return FALSE;
-    }
-
-    case WM_NOTIFY:
-    {
-        auto nmhdr = (LPNMHDR)lParam;
-        if (nmhdr->idFrom != WIN_STARTWIN_TABCTL) break;
-        int const cur = SendMessageA(nmhdr->hwndFrom, TCM_GETCURSEL,0,0);
-        switch (nmhdr->code)
-        {
-            case TCN_SELCHANGING:
-            case TCN_SELCHANGE:
-                if (cur < 0 || !pages[cur])
-                    break;
-                ShowWindow(pages[cur], nmhdr->code == TCN_SELCHANGING ? SW_HIDE : SW_SHOW);
-                return TRUE;
-        }
-        break;
-    }
-
-    case WM_CLOSE:
-        if (mode == TAB_CONFIG) done = 0;
-        else quitevent++;
-        return TRUE;
-
-    case WM_DESTROY:
-        if (hbmp)
-        {
-            DeleteObject(hbmp);
-            hbmp = NULL;
-        }
-
-        if (pages[TAB_CONFIG])
-        {
-            DestroyWindow(pages[TAB_CONFIG]);
-            pages[TAB_CONFIG] = NULL;
-        }
-
-        startupdlg = NULL;
-        return TRUE;
-
-    case WM_COMMAND:
-        switch (LOWORD(wParam))
-        {
-        case WIN_STARTWIN_CANCEL:
-            if (mode == TAB_CONFIG) done = 0;
-            else quitevent++;
-            return TRUE;
-        case WIN_STARTWIN_START:
-            done = 1;
-            return TRUE;
-        }
-        return FALSE;
-
-    case WM_CTLCOLORSTATIC:
-        if ((HWND)lParam == pages[TAB_MESSAGES])
-            return (BOOL)(intptr_t)GetSysColorBrush(COLOR_WINDOW);
-        break;
-
-    default:
-        break;
-    }
-
-    return FALSE;
-}
-
-
-int32_t startwin_open(void)
-{
-    if (startupdlg) return 1;
-    INITCOMMONCONTROLSEX icc = { sizeof(icc), ICC_TAB_CLASSES };
-    InitCommonControlsEx(&icc);
-    startupdlg = CreateDialog((HINSTANCE)win_gethinstance(), MAKEINTRESOURCE(WIN_STARTWIN), NULL, startup_dlgproc);
-    if (startupdlg)
-    {
-        SetPage(TAB_MESSAGES);
-        EnableConfig(0);
-        return 0;
-    }
-    return -1;
-}
-
-int32_t startwin_close(void)
-{
-    if (!startupdlg) return 1;
-    DestroyWindow(startupdlg);
-    startupdlg = NULL;
-    return 0;
-}
-
-int32_t startwin_puts(const char *buf)
-{
-    if (!startupdlg) return 1;
-
-    const HWND edctl = pages[TAB_MESSAGES];
-
-    if (!edctl) return -1;
-
-    static HWND dactrl = NULL;
-    if (!dactrl) dactrl = GetDlgItem(startupdlg, WIN_STARTWIN_TABCTL);
-
-    int const vis = ((int)SendMessageA(dactrl, TCM_GETCURSEL,0,0) == TAB_MESSAGES);
-
-    if (vis)
-        SendMessageA(edctl, WM_SETREDRAW, FALSE, 0);
-
-    int const curlen = SendMessageA(edctl, WM_GETTEXTLENGTH, 0,0);
-    SendMessageA(edctl, EM_SETSEL, (WPARAM)curlen, (LPARAM)curlen);
-
-    int const   numlines = SendMessageA(edctl, EM_GETLINECOUNT, 0, 0);
-    static bool newline  = false;
-    const char *p        = buf;
-
-    while (*p)
-    {
-        if (newline)
-        {
-            SendMessageA(edctl, EM_REPLACESEL, 0, (LPARAM)"\r\n");
-            newline = false;
-        }
-        const char *q = p;
-        while (*q && *q != '\n') q++;
-        static char workbuf[1024];
-        Bmemcpy(workbuf, p, q-p);
-        if (*q == '\n')
-        {
-            if (!q[1])
-            {
-                newline = true;
-                workbuf[q-p] = 0;
-            }
-            else
-            {
-                workbuf[q-p] = '\r';
-                workbuf[q-p+1] = '\n';
-                workbuf[q-p+2] = 0;
-            }
-            p = q+1;
-        }
-        else
-        {
-            workbuf[q-p] = 0;
-            p = q;
-        }
-        SendMessageA(edctl, EM_REPLACESEL, 0, (LPARAM)workbuf);
-    }
-
-    int const newnumlines = SendMessageA(edctl, EM_GETLINECOUNT, 0, 0);
-    SendMessageA(edctl, EM_LINESCROLL, 0, newnumlines - numlines);
-
-    if (vis)
-        SendMessageA(edctl, WM_SETREDRAW, TRUE, 0);
-
-    return 0;
-}
-
-int32_t startwin_settitle(const char *str)
-{
-    if (!startupdlg) return 1;
-    SetWindowTextA(startupdlg, str);
-    return 0;
-}
-
-int32_t startwin_idle(void *v)
-{
-    if (!startupdlg || !IsWindow(startupdlg)) return 0;
-    if (IsDialogMessage(startupdlg, (MSG *)v)) return 1;
-    return 0;
-}
-
-int32_t startwin_run(void)
-{
-    if (!startupdlg) return 1;
-
-    done = -1;
-
-    SetPage(TAB_CONFIG);
-    EnableConfig(1);
-
-#ifdef POLYMER
-    settings.polymer = (glrendmode == REND_POLYMER);
-#else
-    settings.polymer = 0;
-#endif
-
-	settings.shared = { ScreenMode, ScreenWidth, ScreenHeight, ScreenBPP };
-	settings.grp = g_selectedGrp;
-    settings.gamedir = g_modDir;
-
-    PopulateForm(-1);
-
-    do
-    {
-        MSG msg;
-
-        switch (GetMessage(&msg, NULL, 0,0))
-        {
-        case 0:
-            done = 1;
-            break;
-        case -1:
-            return -1;
-        default:
-            if (IsWindow(startupdlg) && IsDialogMessage(startupdlg, &msg))
-                break;
-            TranslateMessage(&msg);
-            DispatchMessage(&msg);
-            break;
-        }
-    }
-    while (done < 0);
-
-    SetPage(TAB_MESSAGES);
-    EnableConfig(0);
-
-    if (done)
-    {
-		ScreenWidth = settings.shared.xdim;
-		ScreenHeight = settings.shared.ydim;
-		ScreenMode = settings.shared.fullscreen;
-		ScreenBPP = settings.shared.bpp;
-		glrendmode = REND_POLYMOST;
-        g_selectedGrp = settings.grp;
-        Bstrcpy(g_modDir, (g_noSetup == 0 && settings.gamedir != NULL) ? settings.gamedir : "/");
-    }
-
-    return done;
-}
-
-END_RR_NS
-
-#endif // STARTUP_SETUP_WINDOW
-
diff --git a/source/rr/src/startwin.game.h b/source/rr/src/startwin.game.h
deleted file mode 100644
index a2b52f9fc..000000000
--- a/source/rr/src/startwin.game.h
+++ /dev/null
@@ -1,47 +0,0 @@
-//-------------------------------------------------------------------------
-/*
-Copyright (C) 2010 EDuke32 developers and contributors
-
-This file is part of EDuke32.
-
-EDuke32 is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License version 2
-as published by the Free Software Foundation.
-
-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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-//-------------------------------------------------------------------------
-
-// resource ids
-#define WIN_STARTWIN		1000
-#define WIN_STARTWINPAGE_CONFIG 2000
-#define WIN_STARTWIN_BITMAP	100	// banner bitmap
-#define WIN_STARTWIN_TABCTL	101
-#define WIN_STARTWIN_CANCEL	IDCANCEL
-#define WIN_STARTWIN_START	IDOK
-
-#define WIN_STARTWIN_MESSAGES	104	// output list box
-
-#define RSRC_ICON		100
-#define RSRC_BMP		200
-
-// config page
-#define IDCFULLSCREEN	100
-#define IDCVMODE	    101
-#define IDCSOUNDDRV	    102
-#define IDCMIDIDEV	    103
-#define IDCCDADEV	    104
-#define IDCALWAYSSHOW	105
-#define IDCDATA         106
-#define IDCGAMEDIR      107
-#define IDCPOLYMER      108
-#define IDCAUTOLOAD     109
-#define IDCINPUT	    110
diff --git a/source/sw/CMakeLists.txt b/source/sw/CMakeLists.txt
index 529a6cbfd..08c5a66c6 100644
--- a/source/sw/CMakeLists.txt
+++ b/source/sw/CMakeLists.txt
@@ -26,12 +26,7 @@ include_directories(
 )
 
 
-if (WIN32)
-set( PLAT_SOURCES
-	src/startwin.game.cpp
-	)
-endif()
-	
+
 set( PCH_SOURCES
 	src/actor.cpp
 	src/ai.cpp
@@ -125,7 +120,6 @@ file( GLOB HEADER_FILES
 add_library( sw STATIC
 	${HEADER_FILES}
 	${PCH_SOURCES}
-	${PLAT_SOURCES}
 	)
 
 
diff --git a/source/sw/src/GameListSource.game.h b/source/sw/src/GameListSource.game.h
deleted file mode 100644
index 1588dd5c0..000000000
--- a/source/sw/src/GameListSource.game.h
+++ /dev/null
@@ -1,37 +0,0 @@
-//-------------------------------------------------------------------------
-/*
- Copyright (C) 2013 Jonathon Fowler <jf@jonof.id.au>
-
- This file is part of JFShadowWarrior
-
- Shadow Warrior 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-//-------------------------------------------------------------------------
-
-@interface GameListSource : NSObject <NSComboBoxDataSource>
-{
-    NSMutableArray *list;
-}
-- (id)init;
-- (void)dealloc;
-- (GrpFile *)grpAtIndex:(int)index;
-- (int)findIndexForGrpname:(NSString *)grpname;
-- (id)tableView:(NSTableView *)aTableView
-    objectValueForTableColumn:(NSTableColumn *)aTableColumn
-    row:(NSInteger)rowIndex;
-- (int)numberOfRowsInTableView:(NSTableView *)aTableView;
-@end
-
diff --git a/source/sw/src/GameListSource.game.mm b/source/sw/src/GameListSource.game.mm
deleted file mode 100644
index ee7230be1..000000000
--- a/source/sw/src/GameListSource.game.mm
+++ /dev/null
@@ -1,89 +0,0 @@
-//-------------------------------------------------------------------------
-/*
- Copyright (C) 2013 Jonathon Fowler <jf@jonof.id.au>
-
- This file is part of JFShadowWarrior
-
- Shadow Warrior 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-//-------------------------------------------------------------------------
-
-
-#import <Cocoa/Cocoa.h>
-
-#import "GrpFile.game.h"
-#import "GameListSource.game.h"
-
-@implementation GameListSource
-- (id)init
-{
-    self = [super init];
-    if (self) {
-        struct grpfile *p;
-        int i;
-
-        list = [[NSMutableArray alloc] init];
-
-        for (p = foundgrps; p; p=p->next) {
-            for (i=0; i<numgrpfiles; i++) if (p->crcval == grpfiles[i].crcval) break;
-            if (i == numgrpfiles) continue;
-            [list addObject:[[GrpFile alloc] initWithGrpfile:p andName:[NSString stringWithUTF8String:grpfiles[i].name]]];
-        }
-    }
-
-    return self;
-}
-
-- (void)dealloc
-{
-    [list release];
-    [super dealloc];
-}
-
-- (GrpFile*)grpAtIndex:(int)index
-{
-    return [list objectAtIndex:index];
-}
-
-- (int)findIndexForGrpname:(NSString*)grpname
-{
-    unsigned i;
-    for (i=0; i<[list count]; i++) {
-        if ([[[list objectAtIndex:i] grpname] isEqual:grpname]) return i;
-    }
-    return -1;
-}
-
-- (id)tableView:(NSTableView *)aTableView
-        objectValueForTableColumn:(NSTableColumn *)aTableColumn
-            row:(NSInteger)rowIndex
-{
-    NSParameterAssert(rowIndex >= 0 && rowIndex < [list count]);
-    switch ([[aTableColumn identifier] intValue]) {
-        case 0:	// name column
-            return [[list objectAtIndex:rowIndex] name];
-        case 1:	// grp column
-            return [[list objectAtIndex:rowIndex] grpname];
-        default: return nil;
-    }
-}
-
-- (int)numberOfRowsInTableView:(NSTableView *)aTableView
-{
-    return [list count];
-}
-@end
-
diff --git a/source/sw/src/GrpFile.game.h b/source/sw/src/GrpFile.game.h
deleted file mode 100644
index b81d28799..000000000
--- a/source/sw/src/GrpFile.game.h
+++ /dev/null
@@ -1,40 +0,0 @@
-//-------------------------------------------------------------------------
-/*
- Copyright (C) 2013 Jonathon Fowler <jf@jonof.id.au>
-
- This file is part of JFShadowWarrior
-
- Shadow Warrior 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-//-------------------------------------------------------------------------
-
-
-#import <Cocoa/Cocoa.h>
-
-#include "grpscan.h"
-
-@interface GrpFile : NSObject
-{
-    NSString *name;
-    struct grpfile *fg;
-}
-- (id)initWithGrpfile:(struct grpfile *)grpfile andName:(NSString *)aName;
-- (void)dealloc;
-- (NSString *)name;
-- (NSString *)grpname;
-- (struct grpfile *)entryptr;
-@end
-
diff --git a/source/sw/src/GrpFile.game.mm b/source/sw/src/GrpFile.game.mm
deleted file mode 100644
index 40178bb5d..000000000
--- a/source/sw/src/GrpFile.game.mm
+++ /dev/null
@@ -1,54 +0,0 @@
-//-------------------------------------------------------------------------
-/*
- Copyright (C) 2013 Jonathon Fowler <jf@jonof.id.au>
-
- This file is part of JFShadowWarrior
-
- Shadow Warrior 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-//-------------------------------------------------------------------------
-
-#include "GrpFile.game.h"
-
-@implementation GrpFile
-- (id)initWithGrpfile:(struct grpfile *)grpfile andName:(NSString*)aName
-{
-    self = [super init];
-    if (self) {
-        fg = grpfile;
-        name = aName;
-        [aName retain];
-    }
-    return self;
-}
-- (void)dealloc
-{
-    [name release];
-    [super dealloc];
-}
-- (NSString *)name
-{
-    return name;
-}
-- (NSString *)grpname
-{
-    return [NSString stringWithUTF8String:(fg->name)];
-}
-- (struct grpfile *)entryptr
-{
-    return fg;
-}
-@end
diff --git a/source/sw/src/StartupWinController.game.mm b/source/sw/src/StartupWinController.game.mm
deleted file mode 100644
index 528a75dc7..000000000
--- a/source/sw/src/StartupWinController.game.mm
+++ /dev/null
@@ -1,468 +0,0 @@
-//-------------------------------------------------------------------------
-/*
- Copyright (C) 2007 Jonathon Fowler <jf@jonof.id.au>
-
- This file is part of JFShadowWarrior
-
- Shadow Warrior 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-//-------------------------------------------------------------------------
-
-#import <Cocoa/Cocoa.h>
-
-#include "compat.h"
-#include "types.h"
-#include "build.h"
-#include "baselayer.h"
-#include "grpscan.h"
-#include "gamedefs.h"
-#include "config.h"
-
-#import "GrpFile.game.h"
-#import "GameListSource.game.h"
-
-static struct {
-	int fullscreen;
-	int xdim3d, ydim3d, bpp3d;
-	int forcesetup;
-	char selectedgrp[BMAX_PATH+1];
-    int samplerate, bitspersample, channels;
-    int usemouse, usejoystick;
-} settings;
-
-static struct soundQuality_t {
-    int frequency;
-    int samplesize;
-    int channels;
-} * soundQualities = 0;
-
-
-@interface StartupWinController : NSWindowController
-{
-	NSMutableArray *modeslist3d;
-	GameListSource *gamelistsrc;
-
-	IBOutlet NSButton *alwaysShowButton;
-	IBOutlet NSButton *fullscreenButton;
-    IBOutlet NSButton *useMouseButton;
-    IBOutlet NSButton *useJoystickButton;
-	IBOutlet NSTextView *messagesView;
-	IBOutlet NSTabView *tabView;
-	IBOutlet NSPopUpButton *videoMode3DPUButton;
-    IBOutlet NSPopUpButton *soundQualityPUButton;
-	IBOutlet NSScrollView *gameList;
-
-	IBOutlet NSButton *cancelButton;
-	IBOutlet NSButton *startButton;
-}
-
-- (void)dealloc;
-- (void)populateVideoModes:(BOOL)firstTime;
-- (void)populateSoundQuality:(BOOL)firstTime;
-
-- (IBAction)alwaysShowClicked:(id)sender;
-- (IBAction)fullscreenClicked:(id)sender;
-
-- (IBAction)cancel:(id)sender;
-- (IBAction)start:(id)sender;
-
-- (void)setupRunMode;
-- (void)setupMessagesMode;
-- (void)putsMessage:(NSString *)str;
-- (void)setTitle:(NSString *)str;
-@end
-
-@implementation StartupWinController
-
-- (void)dealloc
-{
-	[gamelistsrc release];
-	[modeslist3d release];
-	[super dealloc];
-}
-
-- (void)populateVideoModes:(BOOL)firstTime
-{
-	int i, mode3d, fullscreen = ([fullscreenButton state] == NSOnState);
-	int idx3d = -1;
-	int xdim, ydim, bpp;
-
-	if (firstTime) {
-		xdim = settings.xdim3d;
-		ydim = settings.ydim3d;
-		bpp  = settings.bpp3d;
-	} else {
-		mode3d = [[modeslist3d objectAtIndex:[videoMode3DPUButton indexOfSelectedItem]] intValue];
-		if (mode3d >= 0) {
-			xdim = validmode[mode3d].xdim;
-			ydim = validmode[mode3d].ydim;
-			bpp = validmode[mode3d].bpp;
-		}
-
-	}
-	mode3d = checkvideomode(&xdim, &ydim, bpp, fullscreen, 1);
-	if (mode3d < 0) {
-		int i, cd[] = { 32, 24, 16, 15, 8, 0 };
-		for (i=0; cd[i]; ) { if (cd[i] >= bpp) i++; else break; }
-		for ( ; cd[i]; i++) {
-			mode3d = checkvideomode(&xdim, &ydim, cd[i], fullscreen, 1);
-			if (mode3d < 0) continue;
-			break;
-		}
-	}
-
-	[modeslist3d release];
-	[videoMode3DPUButton removeAllItems];
-
-	modeslist3d = [[NSMutableArray alloc] init];
-
-	for (i = 0; i < validmodecnt; i++) {
-		if (fullscreen == validmode[i].fs) {
-			if (i == mode3d) idx3d = [modeslist3d count];
-			[modeslist3d addObject:[NSNumber numberWithInt:i]];
-			[videoMode3DPUButton addItemWithTitle:[NSString stringWithFormat:@"%d %C %d %d-bpp",
-				validmode[i].xdim, 0xd7, validmode[i].ydim, validmode[i].bpp]];
-		}
-	}
-
-	if (idx3d >= 0) [videoMode3DPUButton selectItemAtIndex:idx3d];
-}
-
-- (void)populateSoundQuality:(BOOL)firstTime
-{
-    int i, curidx = -1;
-
-    [soundQualityPUButton removeAllItems];
-
-    for (i = 0; soundQualities[i].frequency > 0; i++) {
-        const char *ch;
-        switch (soundQualities[i].channels) {
-            case 1: ch = "Mono"; break;
-            case 2: ch = "Stereo"; break;
-            default: ch = "?"; break;
-        }
-
-        NSString *s = [NSString stringWithFormat:@"%dkHz, %d-bit, %s",
-                       soundQualities[i].frequency / 1000,
-                       soundQualities[i].samplesize,
-                       ch
-                       ];
-        [soundQualityPUButton addItemWithTitle:s];
-
-        if (firstTime &&
-            soundQualities[i].frequency == settings.samplerate &&
-            soundQualities[i].samplesize == settings.bitspersample &&
-            soundQualities[i].channels == settings.channels) {
-            curidx = i;
-        }
-    }
-
-    if (firstTime && curidx < 0) {
-        soundQualities[i].frequency = settings.samplerate;
-        soundQualities[i].samplesize = settings.bitspersample;
-        soundQualities[i].channels = settings.channels;
-
-        const char *ch;
-        switch (soundQualities[i].channels) {
-            case 1: ch = "Mono"; break;
-            case 2: ch = "Stereo"; break;
-            default: ch = "?"; break;
-        }
-        NSString *s = [NSString stringWithFormat:@"%dkHz, %d-bit, %s",
-                       soundQualities[i].frequency / 1000,
-                       soundQualities[i].samplesize,
-                       ch
-                       ];
-        [soundQualityPUButton addItemWithTitle:s];
-
-        curidx = i++;
-        soundQualities[i].frequency = -1;
-    }
-
-    if (curidx >= 0) {
-        [soundQualityPUButton selectItemAtIndex:curidx];
-    }
-}
-
-- (IBAction)alwaysShowClicked:(id)sender
-{
-}
-
-- (IBAction)fullscreenClicked:(id)sender
-{
-	[self populateVideoModes:NO];
-}
-
-- (IBAction)cancel:(id)sender
-{
-	[NSApp abortModal];
-}
-
-- (IBAction)start:(id)sender
-{
-	int mode = [[modeslist3d objectAtIndex:[videoMode3DPUButton indexOfSelectedItem]] intValue];
-	if (mode >= 0) {
-		settings.xdim3d = validmode[mode].xdim;
-		settings.ydim3d = validmode[mode].ydim;
-		settings.bpp3d = validmode[mode].bpp;
-		settings.fullscreen = validmode[mode].fs;
-	}
-
-    int quality = [soundQualityPUButton indexOfSelectedItem];
-    if (quality >= 0) {
-        settings.samplerate = soundQualities[quality].frequency;
-        settings.bitspersample = soundQualities[quality].samplesize;
-        settings.channels = soundQualities[quality].channels;
-    }
-
-	int row = [[gameList documentView] selectedRow];
-	if (row >= 0) {
-		struct grpfile *p = [[gamelistsrc grpAtIndex:row] entryptr];
-		if (p) {
-			strcpy(settings.selectedgrp, p->name);
-		}
-	}
-
-    settings.usemouse = [useMouseButton state] == NSOnState;
-    settings.usejoystick = [useJoystickButton state] == NSOnState;
-	settings.forcesetup = [alwaysShowButton state] == NSOnState;
-
-	[NSApp stopModal];
-}
-
-- (void)setupRunMode
-{
-	getvalidmodes();
-
-	[fullscreenButton setState: (settings.fullscreen ? NSOnState : NSOffState)];
-	[alwaysShowButton setState: (settings.forcesetup ? NSOnState : NSOffState)];
-    [useMouseButton setState: (settings.usemouse ? NSOnState : NSOffState)];
-    [useJoystickButton setState: (settings.usejoystick ? NSOnState : NSOffState)];
-	[self populateVideoModes:YES];
-    [self populateSoundQuality:YES];
-
-	// enable all the controls on the Configuration page
-	NSEnumerator *enumerator = [[[[tabView tabViewItemAtIndex:0] view] subviews] objectEnumerator];
-	NSControl *control;
-	while ((control = [enumerator nextObject])) {
-        [control setEnabled:true];
-    }
-
-	gamelistsrc = [[GameListSource alloc] init];
-	[[gameList documentView] setDataSource:gamelistsrc];
-	[[gameList documentView] deselectAll:nil];
-
-	int row = [gamelistsrc findIndexForGrpname:[NSString stringWithUTF8String:settings.selectedgrp]];
-	if (row >= 0) {
-		[[gameList documentView] scrollRowToVisible:row];
-		[[gameList documentView] selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
-	}
-
-	[cancelButton setEnabled:true];
-	[startButton setEnabled:true];
-
-	[tabView selectTabViewItemAtIndex:0];
-	[NSCursor unhide];	// Why should I need to do this?
-}
-
-- (void)setupMessagesMode
-{
-	[tabView selectTabViewItemAtIndex:2];
-
-	// disable all the controls on the Configuration page except "always show", so the
-	// user can enable it if they want to while waiting for something else to happen
-	NSEnumerator *enumerator = [[[[tabView tabViewItemAtIndex:0] view] subviews] objectEnumerator];
-	NSControl *control;
-	while ((control = [enumerator nextObject])) {
-		if (control == alwaysShowButton) continue;
-		[control setEnabled:false];
-	}
-
-	[cancelButton setEnabled:false];
-	[startButton setEnabled:false];
-}
-
-- (void)putsMessage:(NSString *)str
-{
-	NSRange end;
-	NSTextStorage *text = [messagesView textStorage];
-	BOOL shouldAutoScroll;
-
-	shouldAutoScroll = ((int)NSMaxY([messagesView bounds]) == (int)NSMaxY([messagesView visibleRect]));
-
-	end.location = [text length];
-	end.length = 0;
-
-	[text beginEditing];
-	[messagesView replaceCharactersInRange:end withString:str];
-	[text endEditing];
-
-	if (shouldAutoScroll) {
-		end.location = [text length];
-		end.length = 0;
-		[messagesView scrollRangeToVisible:end];
-	}
-}
-
-- (void)setTitle:(NSString *)str
-{
-	[[self window] setTitle:str];
-}
-
-@end
-
-static StartupWinController *startwin = nil;
-
-int startwin_open(void)
-{
-	if (startwin != nil) return 1;
-
-	startwin = [[StartupWinController alloc] initWithWindowNibName:@"startwin.game"];
-	if (startwin == nil) return -1;
-
-    {
-        static unsigned soundQualityFrequencies[] = { 44100, 22050, 11025 };
-        static unsigned soundQualitySampleSizes[] = { 16, 8 };
-        static unsigned soundQualityChannels[]    = { 2, 1 };
-        unsigned f, b, c, i;
-
-        i = sizeof(soundQualityFrequencies) *
-            sizeof(soundQualitySampleSizes) *
-            sizeof(soundQualityChannels) /
-            sizeof(int) + 2;    // one for the terminator, one for a custom setting
-        soundQualities = (struct soundQuality_t *) malloc(i * sizeof(struct soundQuality_t));
-
-        i = 0;
-        for (c = 0; c < sizeof(soundQualityChannels) / sizeof(int); c++) {
-            for (b = 0; b < sizeof(soundQualitySampleSizes) / sizeof(int); b++) {
-                for (f = 0; f < sizeof(soundQualityFrequencies) / sizeof(int); f++) {
-                    soundQualities[i].frequency = soundQualityFrequencies[f];
-                    soundQualities[i].samplesize = soundQualitySampleSizes[b];
-                    soundQualities[i].channels = soundQualityChannels[c];
-
-                    i++;
-                }
-            }
-        }
-
-        soundQualities[i].frequency = -1;
-    }
-
-	[startwin setupMessagesMode];
-	[startwin showWindow:nil];
-
-	return 0;
-}
-
-int startwin_close(void)
-{
-	if (startwin == nil) return 1;
-
-	[startwin close];
-	[startwin release];
-	startwin = nil;
-
-	return 0;
-}
-
-int startwin_puts(const char *s)
-{
-	NSString *ns;
-
-	if (!s) return -1;
-	if (startwin == nil) return 1;
-
-	ns = [[NSString alloc] initWithCString:s];
-	[startwin putsMessage:ns];
-	[ns release];
-
-	return 0;
-}
-
-int startwin_settitle(const char *s)
-{
-	NSString *ns;
-
-	if (!s) return -1;
-	if (startwin == nil) return 1;
-
-	ns = [[NSString alloc] initWithCString:s];
-	[startwin setTitle:ns];
-	[ns release];
-
-	return 0;
-}
-
-int startwin_idle(void *v)
-{
-	if (startwin) [[startwin window] displayIfNeeded];
-	return 0;
-}
-
-extern char* grpfile;
-extern int32 ScreenMode, ScreenWidth, ScreenHeight, ScreenBPP, ForceSetup, UseMouse, UseJoystick;
-
-int startwin_run(void)
-{
-	int retval;
-
-	if (startwin == nil) return 0;
-
-	ScanGroups();
-
-	settings.fullscreen = ScreenMode;
-	settings.xdim3d = ScreenWidth;
-	settings.ydim3d = ScreenHeight;
-	settings.bpp3d = ScreenBPP;
-    settings.samplerate = MixRate;
-    settings.bitspersample = NumBits;
-    settings.channels = NumChannels;
-    settings.usemouse = UseMouse;
-    settings.usejoystick = UseJoystick;
-	settings.forcesetup = ForceSetup;
-	strncpy(settings.selectedgrp, grpfile, BMAX_PATH);
-
-	[startwin setupRunMode];
-
-	switch ([NSApp runModalForWindow:[startwin window]]) {
-#ifdef MAC_OS_X_VERSION_10_9
-		case NSModalResponseStop: retval = 1; break;
-		case NSModalResponseAbort: retval = 0; break;
-#else
-		case NSRunStoppedResponse: retval = 1; break;
-		case NSRunAbortedResponse: retval = 0; break;
-#endif
-		default: retval = -1;
-	}
-
-	[startwin setupMessagesMode];
-
-	if (retval) {
-		ScreenMode = settings.fullscreen;
-		ScreenWidth = settings.xdim3d;
-		ScreenHeight = settings.ydim3d;
-		ScreenBPP = settings.bpp3d;
-        MixRate = settings.samplerate;
-        NumBits = settings.bitspersample;
-        NumChannels = settings.channels;
-        UseMouse = settings.usemouse;
-        UseJoystick = settings.usejoystick;
-		ForceSetup = settings.forcesetup;
-		grpfile = settings.selectedgrp;
-	}
-
-	return retval;
-}
diff --git a/source/sw/src/game.cpp b/source/sw/src/game.cpp
index 68c53cb1a..1af4fd79f 100644
--- a/source/sw/src/game.cpp
+++ b/source/sw/src/game.cpp
@@ -842,7 +842,6 @@ void COVERsetbrightness(int bright, unsigned char *pal)
 static int firstnet = 0;    // JBF
 int nextvoxid = 0;  // JBF
 
-extern int startwin_run(void);
 
 static void SW_FatalEngineError(void)
 {
@@ -3357,17 +3356,6 @@ int32_t app_main(int32_t argc, char const * const * argv)
         exit(1);
     }
 
-#ifdef STARTUP_SETUP_WINDOW
-    if (i < 0 || displaysetup || CommandSetup)
-    {
-        if (quitevent || !startwin_run())
-        {
-            engineUnInit();
-            exit(0);
-        }
-    }
-#endif
-
     initgroupfile(G_GrpFile());
     if (!DetectShareware())
     {
@@ -5562,12 +5550,6 @@ saveable_module saveable_build =
 extern void faketimerhandler();
 extern int app_main(int argc, char const* const* argv);
 extern void app_crashhandler(void);
-extern int32_t startwin_open(void);
-extern int32_t startwin_close(void);
-extern int32_t startwin_puts(const char*);
-extern int32_t startwin_settitle(const char*);
-extern int32_t startwin_idle(void*);
-extern int32_t startwin_run(void);
 /*extern*/ bool validate_hud(int requested_size) { return requested_size; }
 /*extern*/ void set_hud(int requested_size) { /* the relevant setting is gs.BorderNum */}
 
@@ -5579,12 +5561,6 @@ GameInterface Interface = {
 	set_hud,
 	set_hud,
 	app_crashhandler,
-	startwin_open,
-	startwin_close,
-	startwin_puts,
-	startwin_settitle,
-	startwin_idle,
-	startwin_run,
 	G_DefFile,
 	G_DefFile,
 };
diff --git a/source/sw/src/startgtk.game.cpp b/source/sw/src/startgtk.game.cpp
deleted file mode 100644
index 7d82653c6..000000000
--- a/source/sw/src/startgtk.game.cpp
+++ /dev/null
@@ -1,756 +0,0 @@
-/* NOTE: Glade will generate code for a dialogue box which you should
- * then patch into this file whenever you make a change to the Glade
- * template.
- */
-#include "ns.h"
-
-#include "compat.h"
-
-#include <gdk-pixbuf/gdk-pixdata.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#include <gdk/gdkkeysyms.h>
-#include <gtk/gtk.h>
-
-#include "dynamicgtk.h"
-
-#include "types.h"
-#include "build.h"
-
-#include "baselayer.h"
-#include "grpscan.h"
-
-#include "common.h"
-#include "common_game.h"
-
-#define TAB_CONFIG 0
-#define TAB_GAME 1
-#define TAB_MESSAGES 2
-
-BEGIN_SW_NS
-
-static struct
-{
-    int fullscreen;
-    int xdim3d, ydim3d, bpp3d;
-    int forcesetup;
-    int usemouse, usejoy;
-    char selectedgrp[BMAX_PATH+1];
-} settings;
-
-extern int gtkenabled;
-
-static GtkWidget *startwin = NULL;
-static int retval = -1, mode = TAB_MESSAGES;
-
-// -- SUPPORT FUNCTIONS -------------------------------------------------------
-
-#define GLADE_HOOKUP_OBJECT(component,widget,name) \
-    g_object_set_data_full (G_OBJECT (component), name, \
-                            gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref)
-
-#define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \
-    g_object_set_data (G_OBJECT (component), name, widget)
-
-#define lookup_widget(x,w) \
-    (GtkWidget*) g_object_get_data(G_OBJECT(x), w)
-
-static GdkPixbuf *load_banner(void)
-{
-    extern const GdkPixdata startbanner_pixdata;
-    return gdk_pixbuf_from_pixdata((GdkPixdata const *)&startbanner_pixdata, FALSE, NULL);
-}
-
-static void SetPage(int n)
-{
-    gboolean gb;
-
-    if (!gtkenabled || !startwin) return;
-    mode = n;
-    gtk_notebook_set_current_page(GTK_NOTEBOOK(lookup_widget(startwin,"tabs")), n);
-
-    // each control in the config page vertical layout plus the start button should be made (in)sensitive
-    if (n == TAB_CONFIG)
-    {
-        gb = TRUE;
-    }
-    else
-    {
-        gb = FALSE;
-    }
-    gtk_widget_set_sensitive(lookup_widget(startwin,"startbutton"), gb);
-    gtk_container_foreach(GTK_CONTAINER(lookup_widget(startwin,"configvlayout")),
-                          (GtkCallback)gtk_widget_set_sensitive, (gpointer)(gintptr)gb);
-}
-
-static void on_vmode3dcombo_changed(GtkComboBox *, gpointer);
-static void on_gamelist_selection_changed(GtkTreeSelection *, gpointer);
-static void PopulateForm(int pgs)
-{
-    if (pgs & (1<<TAB_CONFIG))
-    {
-        int mode3d, i;
-        GtkListStore *modes3d;
-        GtkTreeIter iter;
-        GtkComboBox *box3d;
-        char buf[64];
-
-        mode3d = checkvideomode(&settings.xdim3d, &settings.ydim3d, settings.bpp3d, settings.fullscreen, 1);
-        if (mode3d < 0)
-        {
-            int i, cd[] = { 32, 24, 16, 15, 8, 0 };
-            for (i=0; cd[i]; ) { if (cd[i] >= settings.bpp3d) i++; else break; }
-            for (; cd[i]; i++)
-            {
-                mode3d = checkvideomode(&settings.xdim3d, &settings.ydim3d, cd[i], settings.fullscreen, 1);
-                if (mode3d < 0) continue;
-                settings.bpp3d = cd[i];
-                break;
-            }
-        }
-
-        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(startwin,"fullscreencheck")), settings.fullscreen);
-        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(startwin,"alwaysshowcheck")), settings.forcesetup);
-
-        box3d = GTK_COMBO_BOX(lookup_widget(startwin,"vmode3dcombo"));
-        modes3d = GTK_LIST_STORE(gtk_combo_box_get_model(box3d));
-        gtk_list_store_clear(modes3d);
-
-        for (i=0; i<validmodecnt; i++)
-        {
-            if (validmode[i].fs != settings.fullscreen) continue;
-
-            // all modes get added to the 3D mode list
-            Bsprintf(buf, "%d x %d %dbpp", validmode[i].xdim, validmode[i].ydim, validmode[i].bpp);
-            gtk_list_store_append(modes3d, &iter);
-            gtk_list_store_set(modes3d, &iter, 0,buf, 1,i, -1);
-            if (i == mode3d)
-            {
-                g_signal_handlers_block_by_func(box3d, on_vmode3dcombo_changed, NULL);
-                gtk_combo_box_set_active_iter(box3d, &iter);
-                g_signal_handlers_unblock_by_func(box3d, on_vmode3dcombo_changed, NULL);
-            }
-        }
-
-        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(startwin,"inputmousecheck")), settings.usemouse);
-        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(startwin,"inputjoycheck")), settings.usejoy);
-    }
-
-    if (pgs & (1<<TAB_GAME))
-    {
-        struct grpfile *fg;
-        int i;
-        GtkListStore *list;
-        GtkTreeIter iter;
-        GtkTreeView *gamelist;
-
-        gamelist = GTK_TREE_VIEW(lookup_widget(startwin,"gamelist"));
-        list = GTK_LIST_STORE(gtk_tree_view_get_model(gamelist));
-        gtk_list_store_clear(list);
-
-        for (fg = foundgrps; fg; fg=fg->next)
-        {
-            for (i = 0; i<numgrpfiles; i++)
-                if (fg->crcval == grpfiles[i].crcval) break;
-            if (i == numgrpfiles) continue; // unrecognised grp file
-
-            gtk_list_store_append(list, &iter);
-            gtk_list_store_set(list, &iter, 0, grpfiles[i].name, 1, fg->name, 2, (gpointer)fg, -1);
-            if (!Bstrcasecmp(fg->name, settings.selectedgrp))
-            {
-                GtkTreeSelection *sel = gtk_tree_view_get_selection(gamelist);
-                g_signal_handlers_block_by_func(sel, on_gamelist_selection_changed, NULL);
-                gtk_tree_selection_select_iter(sel, &iter);
-                g_signal_handlers_unblock_by_func(sel, on_gamelist_selection_changed, NULL);
-            }
-        }
-    }
-}
-
-// -- EVENT CALLBACKS AND CREATION STUFF --------------------------------------
-
-static void on_vmode3dcombo_changed(GtkComboBox *combobox, gpointer user_data)
-{
-    GtkTreeModel *data;
-    GtkTreeIter iter;
-    int val;
-    if (!gtk_combo_box_get_active_iter(combobox, &iter)) return;
-    if (!(data = gtk_combo_box_get_model(combobox))) return;
-    gtk_tree_model_get(data, &iter, 1, &val, -1);
-    settings.xdim3d = validmode[val].xdim;
-    settings.ydim3d = validmode[val].ydim;
-}
-
-static void on_fullscreencheck_toggled(GtkToggleButton *togglebutton, gpointer user_data)
-{
-    settings.fullscreen = (gtk_toggle_button_get_active(togglebutton) == TRUE);
-    PopulateForm(1<<TAB_CONFIG);
-}
-
-static void on_alwaysshowcheck_toggled(GtkToggleButton *togglebutton, gpointer user_data)
-{
-    settings.forcesetup = (gtk_toggle_button_get_active(togglebutton) == TRUE);
-}
-
-static void on_cancelbutton_clicked(GtkButton *button, gpointer user_data)
-{
-    if (mode == TAB_CONFIG) { retval = 0; gtk_main_quit(); }
-    else quitevent++;
-}
-
-static void on_startbutton_clicked(GtkButton *button, gpointer user_data)
-{
-    retval = 1;
-    gtk_main_quit();
-}
-
-static void on_inputmousecheck_toggled(GtkToggleButton *togglebutton, gpointer user_data)
-{
-    settings.usemouse = (gtk_toggle_button_get_active(togglebutton) == TRUE);
-}
-
-static void on_inputjoycheck_toggled(GtkToggleButton *togglebutton, gpointer user_data)
-{
-    settings.usejoy = (gtk_toggle_button_get_active(togglebutton) == TRUE);
-}
-
-static void on_gamelist_selection_changed(GtkTreeSelection *selection, gpointer user_data)
-{
-    GtkTreeIter iter;
-    GtkTreeModel *model;
-    struct grpfile *fg;
-
-    if (gtk_tree_selection_get_selected(selection, &model, &iter))
-    {
-        gtk_tree_model_get(model, &iter, 2, (gpointer)&fg, -1);
-        strcpy(settings.selectedgrp, fg->name);
-    }
-}
-
-static gboolean on_startwin_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
-{
-    if (mode == TAB_CONFIG) { retval = 0; gtk_main_quit(); }
-    else quitevent++;
-    return TRUE;    // FALSE would let the event go through. we want the game to decide when to close
-}
-
-
-static gint name_sorter(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data)
-{
-    gchar *as, *bs;
-    gint r;
-
-    gtk_tree_model_get(model, a, 0, &as, -1);
-    gtk_tree_model_get(model, b, 0, &bs, -1);
-
-    r = g_utf8_collate(as,bs);
-
-    g_free(as);
-    g_free(bs);
-
-    return r;
-}
-
-static GtkWidget *create_window(void)
-{
-    GtkWidget *startwin;
-    GtkWidget *hlayout;
-    GtkWidget *banner;
-    GtkWidget *vlayout;
-    GtkWidget *tabs;
-    GtkWidget *configvlayout;
-    GtkWidget *configlayout;
-    GtkWidget *fullscreencheck;
-    GtkWidget *vmode3dlabel;
-    GtkWidget *inputdevlabel;
-    GtkWidget *inputmousecheck;
-    GtkWidget *inputjoycheck;
-    GtkWidget *vmode3dcombo;
-    GtkWidget *alwaysshowcheck;
-    GtkWidget *configtab;
-    GtkWidget *gamevlayout;
-    GtkWidget *gamelabel;
-    GtkWidget *gamescroll;
-    GtkWidget *gamelist;
-    GtkWidget *gametab;
-    GtkWidget *messagesscroll;
-    GtkWidget *messagestext;
-    GtkWidget *messagestab;
-    GtkWidget *buttons;
-    GtkWidget *cancelbutton;
-    GtkWidget *cancelbuttonalign;
-    GtkWidget *cancelbuttonlayout;
-    GtkWidget *cancelbuttonicon;
-    GtkWidget *cancelbuttonlabel;
-    GtkWidget *startbutton;
-    GtkWidget *startbuttonalign;
-    GtkWidget *startbuttonlayout;
-    GtkWidget *startbuttonicon;
-    GtkWidget *startbuttonlabel;
-    GtkAccelGroup *accel_group;
-
-    accel_group = gtk_accel_group_new();
-
-    // Basic window
-    startwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-    gtk_window_set_title(GTK_WINDOW(startwin), apptitle);     // NOTE: use global app title
-    gtk_window_set_position(GTK_WINDOW(startwin), GTK_WIN_POS_CENTER);
-    gtk_window_set_resizable(GTK_WINDOW(startwin), FALSE);
-    gtk_window_set_type_hint(GTK_WINDOW(startwin), GDK_WINDOW_TYPE_HINT_DIALOG);
-
-    // Horizontal layout of banner and controls
-    hlayout = gtk_hbox_new(FALSE, 0);
-    gtk_widget_show(hlayout);
-    gtk_container_add(GTK_CONTAINER(startwin), hlayout);
-
-    // Banner
-    {
-        GdkPixbuf *pixbuf = load_banner();
-        banner = gtk_image_new_from_pixbuf(pixbuf);
-        g_object_unref((gpointer)pixbuf);
-    }
-    gtk_widget_show(banner);
-    gtk_box_pack_start(GTK_BOX(hlayout), banner, FALSE, FALSE, 0);
-    gtk_misc_set_alignment(GTK_MISC(banner), 0.5, 0);
-
-    // Vertical layout of tab control and start+cancel buttons
-    vlayout = gtk_vbox_new(FALSE, 0);
-    gtk_widget_show(vlayout);
-    gtk_box_pack_start(GTK_BOX(hlayout), vlayout, TRUE, TRUE, 0);
-
-    // Tab control
-    tabs = gtk_notebook_new();
-    gtk_widget_show(tabs);
-    gtk_box_pack_start(GTK_BOX(vlayout), tabs, TRUE, TRUE, 0);
-    gtk_container_set_border_width(GTK_CONTAINER(tabs), 4);
-
-    // Vertical layout of config page main body
-    configvlayout = gtk_vbox_new(FALSE, 0);
-    gtk_widget_show(configvlayout);
-    gtk_container_add(GTK_CONTAINER(tabs), configvlayout);
-
-    // Fixed-position layout of config page controls
-    configlayout = gtk_fixed_new();
-    gtk_widget_show(configlayout);
-    gtk_box_pack_start(GTK_BOX(configvlayout), configlayout, TRUE, TRUE, 0);
-    gtk_container_set_border_width(GTK_CONTAINER(configlayout), 6);
-
-    // Fullscreen checkbox
-    fullscreencheck = gtk_check_button_new_with_mnemonic("_Fullscreen");
-    gtk_widget_show(fullscreencheck);
-    gtk_fixed_put(GTK_FIXED(configlayout), fullscreencheck, 248, 0);
-    gtk_widget_set_size_request(fullscreencheck, 85, 29);
-    gtk_widget_add_accelerator(fullscreencheck, "grab_focus", accel_group,
-                               GDK_F, GDK_MOD1_MASK,
-                               GTK_ACCEL_VISIBLE);
-
-    // 3D video mode label
-    vmode3dlabel = gtk_label_new_with_mnemonic("_Video mode:");
-    gtk_widget_show(vmode3dlabel);
-    gtk_fixed_put(GTK_FIXED(configlayout), vmode3dlabel, 0, 0);
-    gtk_widget_set_size_request(vmode3dlabel, 88, 29);
-    gtk_misc_set_alignment(GTK_MISC(vmode3dlabel), 0, 0.5);
-
-    inputdevlabel = gtk_label_new("Input devices:");
-    gtk_widget_show(inputdevlabel);
-    gtk_fixed_put(GTK_FIXED(configlayout), inputdevlabel, 0, 120);
-    gtk_widget_set_size_request(inputdevlabel, 88, 20);
-    gtk_misc_set_alignment(GTK_MISC(inputdevlabel), 0, 0.5);
-
-    inputmousecheck = gtk_check_button_new_with_mnemonic("Mo_use");
-    gtk_widget_show(inputmousecheck);
-    gtk_fixed_put(GTK_FIXED(configlayout), inputmousecheck, 88, 120);
-    gtk_widget_set_size_request(inputmousecheck, 80, 20);
-    gtk_widget_add_accelerator(inputmousecheck, "grab_focus", accel_group,
-                               GDK_U, GDK_MOD1_MASK,
-                               GTK_ACCEL_VISIBLE);
-
-    inputjoycheck = gtk_check_button_new_with_mnemonic("_Joystick");
-    gtk_widget_show(inputjoycheck);
-    gtk_fixed_put(GTK_FIXED(configlayout), inputjoycheck, 168, 120);
-    gtk_widget_set_size_request(inputjoycheck, 80, 20);
-    gtk_widget_add_accelerator(inputjoycheck, "grab_focus", accel_group,
-                               GDK_J, GDK_MOD1_MASK,
-                               GTK_ACCEL_VISIBLE);
-
-    // 3D video mode combo
-    {
-        GtkListStore *list = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
-        GtkCellRenderer *cell;
-
-        vmode3dcombo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(list));
-        g_object_unref(G_OBJECT(list));
-
-        cell = gtk_cell_renderer_text_new();
-        gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(vmode3dcombo), cell, FALSE);
-        gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(vmode3dcombo), cell, "text", 0, NULL);
-    }
-    gtk_widget_show(vmode3dcombo);
-    gtk_fixed_put(GTK_FIXED(configlayout), vmode3dcombo, 88, 0);
-    gtk_widget_set_size_request(vmode3dcombo, 150, 29);
-    gtk_widget_add_accelerator(vmode3dcombo, "grab_focus", accel_group,
-                               GDK_V, GDK_MOD1_MASK,
-                               GTK_ACCEL_VISIBLE);
-
-    // Always show config checkbox
-    alwaysshowcheck = gtk_check_button_new_with_mnemonic("_Always show configuration on start");
-    gtk_widget_show(alwaysshowcheck);
-    gtk_box_pack_start(GTK_BOX(configvlayout), alwaysshowcheck, FALSE, FALSE, 0);
-    gtk_widget_add_accelerator(alwaysshowcheck, "grab_focus", accel_group,
-                               GDK_A, GDK_MOD1_MASK,
-                               GTK_ACCEL_VISIBLE);
-
-    // Configuration tab
-    configtab = gtk_label_new("Configuration");
-    gtk_widget_show(configtab);
-    gtk_notebook_set_tab_label(GTK_NOTEBOOK(tabs), gtk_notebook_get_nth_page(GTK_NOTEBOOK(tabs), 0), configtab);
-
-    // Game data layout
-    gamevlayout = gtk_vbox_new(FALSE, 0);
-    gtk_widget_show(gamevlayout);
-    gtk_container_add(GTK_CONTAINER(tabs), gamevlayout);
-    gtk_container_set_border_width(GTK_CONTAINER(gamevlayout), 4);
-
-    // Game data field label
-    gamelabel = gtk_label_new_with_mnemonic("_Game or addon:");
-    gtk_widget_show(gamelabel);
-    gtk_box_pack_start(GTK_BOX(gamevlayout), gamelabel, FALSE, FALSE, 0);
-    gtk_misc_set_alignment(GTK_MISC(gamelabel), 0, 0.5);
-
-    // Game data scrollable area
-    gamescroll = gtk_scrolled_window_new(NULL, NULL);
-    gtk_widget_show(gamescroll);
-    gtk_box_pack_start(GTK_BOX(gamevlayout), gamescroll, TRUE, TRUE, 0);
-    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gamescroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-    gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(gamescroll), GTK_SHADOW_IN);
-
-    // Game data list
-    {
-        GtkListStore *list = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
-        GtkCellRenderer *cell;
-        GtkTreeViewColumn *col;
-
-        gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(list), 0, name_sorter, NULL, NULL);
-        gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(list), 0, GTK_SORT_ASCENDING);
-
-        gamelist = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list));
-        g_object_unref(G_OBJECT(list));
-
-        cell = gtk_cell_renderer_text_new();
-        col = gtk_tree_view_column_new_with_attributes("Game", cell, "text", 0, NULL);
-        gtk_tree_view_column_set_expand(col, TRUE);
-        gtk_tree_view_append_column(GTK_TREE_VIEW(gamelist), col);
-        col = gtk_tree_view_column_new_with_attributes("GRP file", cell, "text", 1, NULL);
-        gtk_tree_view_column_set_min_width(col, 64);
-        gtk_tree_view_append_column(GTK_TREE_VIEW(gamelist), col);
-    }
-    gtk_widget_show(gamelist);
-    gtk_container_add(GTK_CONTAINER(gamescroll), gamelist);
-    gtk_widget_add_accelerator(gamelist, "grab_focus", accel_group,
-                               GDK_G, GDK_MOD1_MASK,
-                               GTK_ACCEL_VISIBLE);
-    gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(gamelist), FALSE);
-    gtk_tree_view_set_enable_search(GTK_TREE_VIEW(gamelist), FALSE);
-
-    // Game tab
-    gametab = gtk_label_new("Game");
-    gtk_widget_show(gametab);
-    gtk_notebook_set_tab_label(GTK_NOTEBOOK(tabs), gtk_notebook_get_nth_page(GTK_NOTEBOOK(tabs), 1), gametab);
-
-    // Messages scrollable area
-    messagesscroll = gtk_scrolled_window_new(NULL, NULL);
-    gtk_widget_show(messagesscroll);
-    gtk_container_add(GTK_CONTAINER(tabs), messagesscroll);
-    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(messagesscroll), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
-
-    // Messages text area
-    messagestext = gtk_text_view_new();
-    gtk_widget_show(messagestext);
-    gtk_container_add(GTK_CONTAINER(messagesscroll), messagestext);
-    gtk_text_view_set_editable(GTK_TEXT_VIEW(messagestext), FALSE);
-    gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(messagestext), GTK_WRAP_WORD);
-    gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(messagestext), FALSE);
-    gtk_text_view_set_left_margin(GTK_TEXT_VIEW(messagestext), 2);
-    gtk_text_view_set_right_margin(GTK_TEXT_VIEW(messagestext), 2);
-
-    // Messages tab
-    messagestab = gtk_label_new("Messages");
-    gtk_widget_show(messagestab);
-    gtk_notebook_set_tab_label(GTK_NOTEBOOK(tabs), gtk_notebook_get_nth_page(GTK_NOTEBOOK(tabs), 2), messagestab);
-
-    // Dialogue box buttons layout
-    buttons = gtk_hbutton_box_new();
-    gtk_widget_show(buttons);
-    gtk_box_pack_start(GTK_BOX(vlayout), buttons, FALSE, TRUE, 0);
-    gtk_container_set_border_width(GTK_CONTAINER(buttons), 3);
-    gtk_button_box_set_layout(GTK_BUTTON_BOX(buttons), GTK_BUTTONBOX_END);
-
-    // Cancel button
-    cancelbutton = gtk_button_new();
-    gtk_widget_show(cancelbutton);
-    gtk_container_add(GTK_CONTAINER(buttons), cancelbutton);
-    GTK_WIDGET_SET_FLAGS(cancelbutton, GTK_CAN_DEFAULT);
-    gtk_widget_add_accelerator(cancelbutton, "grab_focus", accel_group,
-                               GDK_C, GDK_MOD1_MASK,
-                               GTK_ACCEL_VISIBLE);
-    gtk_widget_add_accelerator(cancelbutton, "clicked", accel_group,
-                               GDK_Escape, 0,
-                               GTK_ACCEL_VISIBLE);
-
-    cancelbuttonalign = gtk_alignment_new(0.5, 0.5, 0, 0);
-    gtk_widget_show(cancelbuttonalign);
-    gtk_container_add(GTK_CONTAINER(cancelbutton), cancelbuttonalign);
-
-    cancelbuttonlayout = gtk_hbox_new(FALSE, 2);
-    gtk_widget_show(cancelbuttonlayout);
-    gtk_container_add(GTK_CONTAINER(cancelbuttonalign), cancelbuttonlayout);
-
-    cancelbuttonicon = gtk_image_new_from_stock("gtk-cancel", GTK_ICON_SIZE_BUTTON);
-    gtk_widget_show(cancelbuttonicon);
-    gtk_box_pack_start(GTK_BOX(cancelbuttonlayout), cancelbuttonicon, FALSE, FALSE, 0);
-
-    cancelbuttonlabel = gtk_label_new_with_mnemonic("_Cancel");
-    gtk_widget_show(cancelbuttonlabel);
-    gtk_box_pack_start(GTK_BOX(cancelbuttonlayout), cancelbuttonlabel, FALSE, FALSE, 0);
-
-    // Start button
-    startbutton = gtk_button_new();
-    gtk_widget_show(startbutton);
-    gtk_container_add(GTK_CONTAINER(buttons), startbutton);
-    GTK_WIDGET_SET_FLAGS(startbutton, GTK_CAN_DEFAULT);
-    gtk_widget_add_accelerator(startbutton, "grab_focus", accel_group,
-                               GDK_S, GDK_MOD1_MASK,
-                               GTK_ACCEL_VISIBLE);
-    gtk_widget_add_accelerator(startbutton, "clicked", accel_group,
-                               GDK_Return, 0,
-                               GTK_ACCEL_VISIBLE);
-
-    startbuttonalign = gtk_alignment_new(0.5, 0.5, 0, 0);
-    gtk_widget_show(startbuttonalign);
-    gtk_container_add(GTK_CONTAINER(startbutton), startbuttonalign);
-
-    startbuttonlayout = gtk_hbox_new(FALSE, 2);
-    gtk_widget_show(startbuttonlayout);
-    gtk_container_add(GTK_CONTAINER(startbuttonalign), startbuttonlayout);
-
-    startbuttonicon = gtk_image_new_from_stock("gtk-execute", GTK_ICON_SIZE_BUTTON);
-    gtk_widget_show(startbuttonicon);
-    gtk_box_pack_start(GTK_BOX(startbuttonlayout), startbuttonicon, FALSE, FALSE, 0);
-
-    startbuttonlabel = gtk_label_new_with_mnemonic("_Start");
-    gtk_widget_show(startbuttonlabel);
-    gtk_box_pack_start(GTK_BOX(startbuttonlayout), startbuttonlabel, FALSE, FALSE, 0);
-
-    // Wire up the signals
-    g_signal_connect((gpointer) startwin, "delete_event",
-                     G_CALLBACK(on_startwin_delete_event),
-                     NULL);
-    g_signal_connect((gpointer) fullscreencheck, "toggled",
-                     G_CALLBACK(on_fullscreencheck_toggled),
-                     NULL);
-    g_signal_connect((gpointer) inputmousecheck, "toggled",
-                     G_CALLBACK(on_inputmousecheck_toggled),
-                     NULL);
-    g_signal_connect((gpointer) inputjoycheck, "toggled",
-                     G_CALLBACK(on_inputjoycheck_toggled),
-                     NULL);
-    g_signal_connect((gpointer) vmode3dcombo, "changed",
-                     G_CALLBACK(on_vmode3dcombo_changed),
-                     NULL);
-    g_signal_connect((gpointer) alwaysshowcheck, "toggled",
-                     G_CALLBACK(on_alwaysshowcheck_toggled),
-                     NULL);
-    g_signal_connect((gpointer) cancelbutton, "clicked",
-                     G_CALLBACK(on_cancelbutton_clicked),
-                     NULL);
-    g_signal_connect((gpointer) startbutton, "clicked",
-                     G_CALLBACK(on_startbutton_clicked),
-                     NULL);
-    {
-        GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(gamelist));
-        gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
-        g_signal_connect((gpointer) sel, "changed",
-                         G_CALLBACK(on_gamelist_selection_changed),
-                         NULL);
-    }
-
-    // Associate labels with their controls
-    gtk_label_set_mnemonic_widget(GTK_LABEL(vmode3dlabel), vmode3dcombo);
-    gtk_label_set_mnemonic_widget(GTK_LABEL(gamelabel), gamelist);
-
-    /* Store pointers to all widgets, for use by lookup_widget(). */
-    GLADE_HOOKUP_OBJECT_NO_REF(startwin, startwin, "startwin");
-    GLADE_HOOKUP_OBJECT(startwin, hlayout, "hlayout");
-    GLADE_HOOKUP_OBJECT(startwin, banner, "banner");
-    GLADE_HOOKUP_OBJECT(startwin, vlayout, "vlayout");
-    GLADE_HOOKUP_OBJECT(startwin, tabs, "tabs");
-    GLADE_HOOKUP_OBJECT(startwin, configvlayout, "configvlayout");
-    GLADE_HOOKUP_OBJECT(startwin, configlayout, "configlayout");
-    GLADE_HOOKUP_OBJECT(startwin, fullscreencheck, "fullscreencheck");
-    GLADE_HOOKUP_OBJECT(startwin, vmode3dlabel, "vmode3dlabel");
-    GLADE_HOOKUP_OBJECT(startwin, inputdevlabel, "inputdevlabel");
-    GLADE_HOOKUP_OBJECT(startwin, inputmousecheck, "inputmousecheck");
-    GLADE_HOOKUP_OBJECT(startwin, inputjoycheck, "inputjoycheck");
-    GLADE_HOOKUP_OBJECT(startwin, vmode3dcombo, "vmode3dcombo");
-    GLADE_HOOKUP_OBJECT(startwin, alwaysshowcheck, "alwaysshowcheck");
-    GLADE_HOOKUP_OBJECT(startwin, configtab, "configtab");
-    GLADE_HOOKUP_OBJECT(startwin, gamevlayout, "gamevlayout");
-    GLADE_HOOKUP_OBJECT(startwin, gamelabel, "gamelabel");
-    GLADE_HOOKUP_OBJECT(startwin, gamescroll, "gamescroll");
-    GLADE_HOOKUP_OBJECT(startwin, gamelist, "gamelist");
-    GLADE_HOOKUP_OBJECT(startwin, gametab, "gametab");
-    GLADE_HOOKUP_OBJECT(startwin, messagesscroll, "messagesscroll");
-    GLADE_HOOKUP_OBJECT(startwin, messagestext, "messagestext");
-    GLADE_HOOKUP_OBJECT(startwin, messagestab, "messagestab");
-    GLADE_HOOKUP_OBJECT(startwin, buttons, "buttons");
-    GLADE_HOOKUP_OBJECT(startwin, cancelbutton, "cancelbutton");
-    GLADE_HOOKUP_OBJECT(startwin, cancelbuttonalign, "cancelbuttonalign");
-    GLADE_HOOKUP_OBJECT(startwin, cancelbuttonlayout, "cancelbuttonlayout");
-    GLADE_HOOKUP_OBJECT(startwin, cancelbuttonicon, "cancelbuttonicon");
-    GLADE_HOOKUP_OBJECT(startwin, cancelbuttonlabel, "cancelbuttonlabel");
-    GLADE_HOOKUP_OBJECT(startwin, startbutton, "startbutton");
-    GLADE_HOOKUP_OBJECT(startwin, startbuttonalign, "startbuttonalign");
-    GLADE_HOOKUP_OBJECT(startwin, startbuttonlayout, "startbuttonlayout");
-    GLADE_HOOKUP_OBJECT(startwin, startbuttonicon, "startbuttonicon");
-    GLADE_HOOKUP_OBJECT(startwin, startbuttonlabel, "startbuttonlabel");
-
-    gtk_window_add_accel_group(GTK_WINDOW(startwin), accel_group);
-
-    return startwin;
-}
-
-// -- BUILD ENTRY POINTS ------------------------------------------------------
-
-int startwin_open(void)
-{
-    if (!gtkenabled) return 0;
-    if (startwin) return 1;
-
-    startwin = create_window();
-    if (startwin)
-    {
-        SetPage(TAB_MESSAGES);
-        gtk_widget_show(startwin);
-        gtk_main_iteration_do(FALSE);
-        return 0;
-    }
-    return -1;
-}
-
-int startwin_close(void)
-{
-    if (!gtkenabled) return 0;
-    if (!startwin) return 1;
-    gtk_widget_destroy(startwin);
-    startwin = NULL;
-    return 0;
-}
-
-int startwin_puts(const char *str)
-{
-    GtkWidget *textview;
-    GtkTextBuffer *textbuffer;
-    GtkTextIter enditer;
-    GtkTextMark *mark;
-    const char *aptr, *bptr;
-
-    if (!gtkenabled || !str) return 0;
-    if (!startwin) return 1;
-    if (!(textview = lookup_widget(startwin, "messagestext"))) return -1;
-    textbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
-
-    gtk_text_buffer_get_end_iter(textbuffer, &enditer);
-    for (aptr = bptr = str; *aptr != 0; )
-    {
-        switch (*bptr)
-        {
-        case '\b':
-            if (bptr > aptr)
-                gtk_text_buffer_insert(textbuffer, &enditer, (const gchar *)aptr, (gint)(bptr-aptr)-1);
-#if GTK_CHECK_VERSION(2,6,0)
-            gtk_text_buffer_backspace(textbuffer, &enditer, FALSE, TRUE);
-#else
-            {
-                GtkTextIter iter2 = enditer;
-                gtk_text_iter_backward_cursor_position(&iter2);
-                //FIXME: this seems be deleting one too many chars somewhere!
-                if (!gtk_text_iter_equal(&iter2, &enditer))
-                    gtk_text_buffer_delete_interactive(textbuffer, &iter2, &enditer, TRUE);
-            }
-#endif
-            aptr = ++bptr;
-            break;
-        case 0:
-            if (bptr > aptr)
-                gtk_text_buffer_insert(textbuffer, &enditer, (const gchar *)aptr, (gint)(bptr-aptr));
-            aptr = bptr;
-            break;
-        case '\r':  // FIXME
-        default:
-            bptr++;
-            break;
-        }
-    }
-
-    mark = gtk_text_buffer_create_mark(textbuffer, NULL, &enditer, 1);
-    gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(textview), mark, 0.0, FALSE, 0.0, 1.0);
-    gtk_text_buffer_delete_mark(textbuffer, mark);
-
-    return 0;
-}
-
-int startwin_settitle(const char *title)
-{
-    if (!gtkenabled) return 0;
-    if (!startwin) return 1;
-    gtk_window_set_title(GTK_WINDOW(startwin), title);
-    return 0;
-}
-
-int startwin_idle(void *s)
-{
-    if (!gtkenabled) return 0;
-    //if (!startwin) return 1;
-    gtk_main_iteration_do(FALSE);
-    return 0;
-}
-
-extern int32_t ScreenMode, ScreenWidth, ScreenHeight, ScreenBPP, ForceSetup, UseMouse, UseJoystick;
-
-int startwin_run(void)
-{
-    if (!gtkenabled) return 0;
-    if (!startwin) return 1;
-
-    ScanGroups();
-
-    SetPage(TAB_CONFIG);
-
-    settings.fullscreen = ScreenMode;
-    settings.xdim3d = ScreenWidth;
-    settings.ydim3d = ScreenHeight;
-    settings.bpp3d = ScreenBPP;
-    settings.forcesetup = ForceSetup;
-    settings.usemouse = UseMouse;
-    settings.usejoy = UseJoystick;
-    Bstrncpyz(settings.selectedgrp, G_GrpFile(), BMAX_PATH);
-    PopulateForm(-1);
-
-    gtk_main();
-
-    SetPage(TAB_MESSAGES);
-    if (retval)
-    {
-        ScreenMode = settings.fullscreen;
-        ScreenWidth = settings.xdim3d;
-        ScreenHeight = settings.ydim3d;
-        ScreenBPP = settings.bpp3d;
-        ForceSetup = settings.forcesetup;
-        UseMouse = settings.usemouse;
-        UseJoystick = settings.usejoy;
-        g_grpNamePtr = dup_filename(settings.selectedgrp);
-    }
-
-    return retval;
-}
-
-END_SW_NS
diff --git a/source/sw/src/startwin.game.cpp b/source/sw/src/startwin.game.cpp
deleted file mode 100644
index e3e161a7a..000000000
--- a/source/sw/src/startwin.game.cpp
+++ /dev/null
@@ -1,675 +0,0 @@
-#ifndef _WIN32
-#error Only for Windows
-#endif
-#include "ns.h"
-
-#include "build.h"
-
-#define NEED_WINDOWSX_H
-#define NEED_COMMCTRL_H
-#include "windows_inc.h"
-
-#include "renderlayer.h"
-
-#include "common.h"
-#include "common_game.h"
-
-#include "gamedefs.h"
-#include "config.h"
-
-#include "grpscan.h"
-#include "gamecvars.h"
-
-#include "startwin.game.h"
-
-BEGIN_SW_NS
-
-#define TAB_CONFIG 0
-#define TAB_GAME 1
-#define TAB_MESSAGES 2
-
-static struct
-{
-    int fullscreen;
-    int xdim, ydim, bpp;
-    int usemouse, usejoy;
-    char selectedgrp[BMAX_PATH+1];
-    int samplerate, bitspersample, channels;
-} settings;
-
-static struct soundQuality_t
-{
-    int frequency;
-    int samplesize;
-    int channels;
-} *soundQualities = 0;
-
-static HWND startupdlg = NULL;
-static HWND pages[3] = { NULL, NULL, NULL };
-static int done = -1, mode = TAB_CONFIG;
-
-#define POPULATE_VIDEO 1
-#define POPULATE_CONFIG 2
-#define POPULATE_GAME 4
-// Thanks, Microsoft for not providing alternatives for the dialog control macros. :(
-#undef SNDMSG
-#define SNDMSG ::SendMessageA
-
-static int addSoundQualityItem(struct soundQuality_t *q, HWND hwnd)
-{
-    char buf[128];
-    const char *ch;
-
-    switch (q->channels)
-    {
-    case 1: ch = "Mono"; break;
-    case 2: ch = "Stereo"; break;
-    default: ch = "?"; break;
-    }
-
-    sprintf(buf, "%dkHz, %d-bit, %s",
-            q->frequency / 1000,
-            q->samplesize,
-            ch);
-    return ComboBox_AddString(hwnd, buf);
-}
-
-static void PopulateForm(int pgs)
-{
-    HWND hwnd;
-    char buf[256];
-    int i,j;
-
-    if (pgs & POPULATE_VIDEO)
-    {
-        int mode;
-
-        hwnd = GetDlgItem(pages[TAB_CONFIG], IDCVMODE);
-
-        mode = videoCheckMode(&settings.xdim, &settings.ydim, settings.bpp, settings.fullscreen, 1);
-        if (mode < 0)
-        {
-            int cd[] = { 32, 24, 16, 15, 8, 0 };
-            for (i=0; cd[i]; ) { if (cd[i] >= settings.bpp) i++; else break; }
-            for (; cd[i]; i++)
-            {
-                mode = videoCheckMode(&settings.xdim, &settings.ydim, cd[i], settings.fullscreen, 1);
-                if (mode < 0) continue;
-                settings.bpp = cd[i];
-                break;
-            }
-        }
-
-        Button_SetCheck(GetDlgItem(pages[TAB_CONFIG], IDCFULLSCREEN), (settings.fullscreen ? BST_CHECKED : BST_UNCHECKED));
-        ComboBox_ResetContent(hwnd);
-        for (i=0; i<validmodecnt; i++)
-        {
-            if (validmode[i].fs != settings.fullscreen) continue;
-
-            // all modes get added to the 3D mode list
-            Bsprintf(buf, "%d x %d %dbpp", validmode[i].xdim, validmode[i].ydim, validmode[i].bpp);
-            j = ComboBox_AddString(hwnd, buf);
-            ComboBox_SetItemData(hwnd, j, i);
-            if (i == mode) ComboBox_SetCurSel(hwnd, j);
-        }
-    }
-
-    if (pgs & POPULATE_CONFIG)
-    {
-        int curidx = -1;
-
-        Button_SetCheck(GetDlgItem(pages[TAB_CONFIG], IDCALWAYSSHOW), (displaysetup ? BST_CHECKED : BST_UNCHECKED));
-
-        Button_SetCheck(GetDlgItem(pages[TAB_CONFIG], IDCINPUTMOUSE), (settings.usemouse ? BST_CHECKED : BST_UNCHECKED));
-        Button_SetCheck(GetDlgItem(pages[TAB_CONFIG], IDCINPUTJOY), (settings.usejoy ? BST_CHECKED : BST_UNCHECKED));
-
-        hwnd = GetDlgItem(pages[TAB_CONFIG], IDCSOUNDQUAL);
-
-        ComboBox_ResetContent(hwnd);
-        for (i = 0; soundQualities[i].frequency > 0; i++)
-        {
-            j = addSoundQualityItem(&soundQualities[i], hwnd);
-            ComboBox_SetItemData(hwnd, j, i);
-
-            if (soundQualities[i].frequency == settings.samplerate &&
-                soundQualities[i].samplesize == settings.bitspersample &&
-                soundQualities[i].channels == settings.channels)
-            {
-                ComboBox_SetCurSel(hwnd, j);
-            }
-        }
-
-        if (curidx < 0)
-        {
-            soundQualities[i].frequency = settings.samplerate;
-            soundQualities[i].samplesize = settings.bitspersample;
-            soundQualities[i].channels = settings.channels;
-
-            j = addSoundQualityItem(&soundQualities[i], hwnd);
-            ComboBox_SetItemData(hwnd, j, i);
-
-            i++;
-            soundQualities[i].frequency = -1;
-        }
-    }
-
-    if (pgs & POPULATE_GAME)
-    {
-        struct grpfile *fg;
-        int i, j;
-        char buf[128+BMAX_PATH];
-
-        hwnd = GetDlgItem(pages[TAB_GAME], IDGDATA);
-
-        for (fg = foundgrps; fg; fg=fg->next)
-        {
-            for (i = 0; i<numgrpfiles; i++)
-                if (fg->crcval == grpfiles[i].crcval) break;
-            if (i == numgrpfiles) continue; // unrecognised grp file
-
-            Bsprintf(buf, "%s\t%s", grpfiles[i].name, fg->name);
-            j = ListBox_AddString(hwnd, buf);
-            ListBox_SetItemData(hwnd, j, (LPARAM)fg);
-            if (!Bstrcasecmp(fg->name, settings.selectedgrp)) ListBox_SetCurSel(hwnd, j);
-        }
-    }
-}
-
-static INT_PTR CALLBACK ConfigPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
-    switch (uMsg)
-    {
-    case WM_COMMAND:
-        switch (LOWORD(wParam))
-        {
-        case IDCFULLSCREEN:
-            settings.fullscreen = !settings.fullscreen;
-            PopulateForm(1<<TAB_CONFIG);
-            return TRUE;
-        case IDCVMODE:
-            if (HIWORD(wParam) == CBN_SELCHANGE)
-            {
-                int i;
-                i = ComboBox_GetCurSel((HWND)lParam);
-                if (i != CB_ERR) i = ComboBox_GetItemData((HWND)lParam, i);
-                if (i != CB_ERR)
-                {
-                    settings.xdim = validmode[i].xdim;
-                    settings.ydim = validmode[i].ydim;
-                    settings.bpp  = validmode[i].bpp;
-                }
-            }
-            return TRUE;
-        case IDCSOUNDQUAL:
-            if (HIWORD(wParam) == CBN_SELCHANGE)
-            {
-                int i;
-                i = ComboBox_GetCurSel((HWND)lParam);
-                if (i != CB_ERR) i = ComboBox_GetItemData((HWND)lParam, i);
-                if (i != CB_ERR)
-                {
-                    settings.samplerate = soundQualities[i].frequency;
-                    settings.bitspersample = soundQualities[i].samplesize;
-                    settings.channels = soundQualities[i].channels;
-                }
-            }
-            return TRUE;
-        case IDCALWAYSSHOW:
-            displaysetup = IsDlgButtonChecked(hwndDlg, IDCALWAYSSHOW) == BST_CHECKED;
-            return TRUE;
-        case IDCINPUTMOUSE:
-            settings.usemouse = IsDlgButtonChecked(hwndDlg, IDCINPUTMOUSE) == BST_CHECKED;
-            return TRUE;
-        case IDCINPUTJOY:
-            settings.usejoy = IsDlgButtonChecked(hwndDlg, IDCINPUTJOY) == BST_CHECKED;
-            return TRUE;
-        default: break;
-        }
-        break;
-    default: break;
-    }
-    return FALSE;
-}
-
-static INT_PTR CALLBACK GamePageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
-    switch (uMsg)
-    {
-    case WM_COMMAND:
-        switch (LOWORD(wParam))
-        {
-        case IDGDATA:
-        {
-            int i;
-            i = ListBox_GetCurSel((HWND)lParam);
-            if (i != CB_ERR)
-            {
-                LRESULT j = ListBox_GetItemData((HWND)lParam, i);
-                if (j != CB_ERR)
-                    strcpy(settings.selectedgrp, ((struct grpfile const *)j)->name);
-            }
-            return TRUE;
-        }
-        default: break;
-        }
-        break;
-    default: break;
-    }
-    return FALSE;
-}
-
-
-static void SetPage(int n)
-{
-    HWND tab;
-    int cur;
-    tab = GetDlgItem(startupdlg, WIN_STARTWIN_TABCTL);
-    cur = (int)SendMessageA(tab, TCM_GETCURSEL,0,0);
-    ShowWindow(pages[cur],SW_HIDE);
-    SendMessageA(tab, TCM_SETCURSEL, n, 0);
-    ShowWindow(pages[n],SW_SHOW);
-    mode = n;
-
-    SetFocus(GetDlgItem(startupdlg, WIN_STARTWIN_TABCTL));
-}
-
-static void EnableConfig(int n)
-{
-    //EnableWindow(GetDlgItem(startupdlg, WIN_STARTWIN_CANCEL), n);
-    EnableWindow(GetDlgItem(startupdlg, WIN_STARTWIN_START), n);
-    EnableWindow(GetDlgItem(pages[TAB_CONFIG], IDCFULLSCREEN), n);
-    EnableWindow(GetDlgItem(pages[TAB_CONFIG], IDCVMODE), n);
-    EnableWindow(GetDlgItem(pages[TAB_CONFIG], IDCSOUNDQUAL), n);
-    EnableWindow(GetDlgItem(pages[TAB_CONFIG], IDCINPUTMOUSE), n);
-    EnableWindow(GetDlgItem(pages[TAB_CONFIG], IDCINPUTJOY), n);
-
-    EnableWindow(GetDlgItem(pages[TAB_GAME], IDGDATA), n);
-}
-
-static INT_PTR CALLBACK startup_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
-    static HBITMAP hbmp = NULL;
-    HDC hdc;
-
-    switch (uMsg)
-    {
-    case WM_INITDIALOG:
-    {
-        HWND hwnd;
-        RECT r, rdlg, chrome, rtab, rcancel, rstart;
-        int xoffset = 0, yoffset = 0;
-
-        // Fetch the positions (in screen coordinates) of all the windows we need to tweak
-        ZeroMemory(&chrome, sizeof(chrome));
-        AdjustWindowRect(&chrome, GetWindowLong(hwndDlg, GWL_STYLE), FALSE);
-        GetWindowRect(hwndDlg, &rdlg);
-        GetWindowRect(GetDlgItem(hwndDlg, WIN_STARTWIN_TABCTL), &rtab);
-        GetWindowRect(GetDlgItem(hwndDlg, WIN_STARTWIN_CANCEL), &rcancel);
-        GetWindowRect(GetDlgItem(hwndDlg, WIN_STARTWIN_START), &rstart);
-
-        // Knock off the non-client area of the main dialogue to give just the client area
-        rdlg.left -= chrome.left; rdlg.top -= chrome.top;
-        rdlg.right -= chrome.right; rdlg.bottom -= chrome.bottom;
-
-        // Translate them to client-relative coordinates wrt the main dialogue window
-        rtab.right -= rtab.left - 1; rtab.bottom -= rtab.top - 1;
-        rtab.left  -= rdlg.left; rtab.top -= rdlg.top;
-
-        rcancel.right -= rcancel.left - 1; rcancel.bottom -= rcancel.top - 1;
-        rcancel.left -= rdlg.left; rcancel.top -= rdlg.top;
-
-        rstart.right -= rstart.left - 1; rstart.bottom -= rstart.top - 1;
-        rstart.left -= rdlg.left; rstart.top -= rdlg.top;
-
-        // And then convert the main dialogue coordinates to just width/length
-        rdlg.right -= rdlg.left - 1; rdlg.bottom -= rdlg.top - 1;
-        rdlg.left = 0; rdlg.top = 0;
-
-        // Load the bitmap into the bitmap control and fetch its dimensions
-        hbmp = LoadBitmap((HINSTANCE)win_gethinstance(), MAKEINTRESOURCE(RSRC_BMP));
-        hwnd = GetDlgItem(hwndDlg,WIN_STARTWIN_BITMAP);
-        SendMessageA(hwnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbmp);
-        GetClientRect(hwnd, &r);
-        xoffset = r.right;
-        yoffset = r.bottom - rdlg.bottom;
-
-        // Shift and resize the controls that require it
-        rtab.left += xoffset; rtab.bottom += yoffset;
-        rcancel.left += xoffset; rcancel.top += yoffset;
-        rstart.left += xoffset; rstart.top += yoffset;
-        rdlg.right += xoffset;
-        rdlg.bottom += yoffset;
-
-        // Move the controls to their new positions
-        MoveWindow(GetDlgItem(hwndDlg, WIN_STARTWIN_TABCTL), rtab.left, rtab.top, rtab.right, rtab.bottom, FALSE);
-        MoveWindow(GetDlgItem(hwndDlg, WIN_STARTWIN_CANCEL), rcancel.left, rcancel.top, rcancel.right, rcancel.bottom, FALSE);
-        MoveWindow(GetDlgItem(hwndDlg, WIN_STARTWIN_START), rstart.left, rstart.top, rstart.right, rstart.bottom, FALSE);
-
-        // Move the main dialogue to the centre of the screen
-        hdc = GetDC(NULL);
-        rdlg.left = (GetDeviceCaps(hdc, HORZRES) - rdlg.right) / 2;
-        rdlg.top = (GetDeviceCaps(hdc, VERTRES) - rdlg.bottom) / 2;
-        ReleaseDC(NULL, hdc);
-        MoveWindow(hwndDlg, rdlg.left + chrome.left, rdlg.top + chrome.left,
-                   rdlg.right + (-chrome.left+chrome.right), rdlg.bottom + (-chrome.top+chrome.bottom), TRUE);
-
-        // Add tabs to the tab control
-        {
-            TCITEMA tab;
-
-            hwnd = GetDlgItem(hwndDlg, WIN_STARTWIN_TABCTL);
-
-            ZeroMemory(&tab, sizeof(tab));
-            tab.mask = TCIF_TEXT;
-            static char textConfiguration[] = ("Configuration");
-            tab.pszText = textConfiguration;
-            SendMessageA(hwnd, TCM_INSERTITEM, (WPARAM)TAB_CONFIG, (LPARAM)&tab);
-            tab.mask = TCIF_TEXT;
-            static char textGame[] = ("Game");
-            tab.pszText = textGame;
-            SendMessageA(hwnd, TCM_INSERTITEM, (WPARAM)TAB_GAME, (LPARAM)&tab);
-            tab.mask = TCIF_TEXT;
-            static char textMessages[] = ("Messages");
-            tab.pszText = textMessages;
-            SendMessageA(hwnd, TCM_INSERTITEM, (WPARAM)TAB_MESSAGES, (LPARAM)&tab);
-
-            // Work out the position and size of the area inside the tab control for the pages
-            ZeroMemory(&r, sizeof(r));
-            GetClientRect(hwnd, &r);
-            SendMessageA(hwnd, TCM_ADJUSTRECT, FALSE, (LPARAM)&r);
-            r.right -= r.left-1;
-            r.bottom -= r.top-1;
-            r.top += rtab.top;
-            r.left += rtab.left;
-
-            // Create the pages and position them in the tab control, but hide them
-            pages[TAB_CONFIG] = CreateDialog((HINSTANCE)win_gethinstance(),
-                                             MAKEINTRESOURCE(WIN_STARTWINPAGE_CONFIG), hwndDlg, ConfigPageProc);
-            pages[TAB_GAME] = CreateDialog((HINSTANCE)win_gethinstance(),
-                                           MAKEINTRESOURCE(WIN_STARTWINPAGE_GAME), hwndDlg, GamePageProc);
-            pages[TAB_MESSAGES] = GetDlgItem(hwndDlg, WIN_STARTWIN_MESSAGES);
-            SetWindowPos(pages[TAB_CONFIG], hwnd,r.left,r.top,r.right,r.bottom,SWP_HIDEWINDOW);
-            SetWindowPos(pages[TAB_GAME], hwnd,r.left,r.top,r.right,r.bottom,SWP_HIDEWINDOW);
-            SetWindowPos(pages[TAB_MESSAGES], hwnd,r.left,r.top,r.right,r.bottom,SWP_HIDEWINDOW);
-
-            // Tell the editfield acting as the console to exclude the width of the scrollbar
-            GetClientRect(pages[TAB_MESSAGES],&r);
-            r.right -= GetSystemMetrics(SM_CXVSCROLL)+4;
-            r.left = r.top = 0;
-            SendMessageA(pages[TAB_MESSAGES], EM_SETRECTNP,0,(LPARAM)&r);
-
-            // Set a tab stop in the game data listbox
-            {
-                DWORD tabs[1] = { 150 };
-                ListBox_SetTabStops(GetDlgItem(pages[TAB_GAME], IDGDATA), 1, tabs);
-            }
-
-            SetFocus(GetDlgItem(hwndDlg, WIN_STARTWIN_START));
-            SetWindowTextA(hwndDlg, apptitle);
-        }
-        return FALSE;
-    }
-
-    case WM_NOTIFY:
-    {
-        LPNMHDR nmhdr = (LPNMHDR)lParam;
-        int cur;
-        if (nmhdr->idFrom != WIN_STARTWIN_TABCTL) break;
-        cur = (int)SendMessageA(nmhdr->hwndFrom, TCM_GETCURSEL,0,0);
-        switch (nmhdr->code)
-        {
-        case TCN_SELCHANGING:
-        {
-            if (cur < 0 || !pages[cur]) break;
-            ShowWindow(pages[cur],SW_HIDE);
-            return TRUE;
-        }
-        case TCN_SELCHANGE:
-        {
-            if (cur < 0 || !pages[cur]) break;
-            ShowWindow(pages[cur],SW_SHOW);
-            return TRUE;
-        }
-        }
-        break;
-    }
-
-    case WM_CLOSE:
-        if (mode == TAB_CONFIG) done = 0;
-        else quitevent++;
-        return TRUE;
-
-    case WM_DESTROY:
-        if (hbmp)
-        {
-            DeleteObject(hbmp);
-            hbmp = NULL;
-        }
-
-        if (pages[TAB_GAME])
-        {
-            DestroyWindow(pages[TAB_GAME]);
-            pages[TAB_GAME] = NULL;
-        }
-
-        if (pages[TAB_CONFIG])
-        {
-            DestroyWindow(pages[TAB_CONFIG]);
-            pages[TAB_CONFIG] = NULL;
-        }
-
-        startupdlg = NULL;
-        return TRUE;
-
-    case WM_COMMAND:
-        switch (LOWORD(wParam))
-        {
-        case WIN_STARTWIN_CANCEL:
-            if (mode == TAB_CONFIG) done = 0;
-            else quitevent++;
-            return TRUE;
-        case WIN_STARTWIN_START: done = 1; return TRUE;
-        }
-        return FALSE;
-
-    case WM_CTLCOLORSTATIC:
-        if ((HWND)lParam == pages[TAB_MESSAGES])
-            return (BOOL)(intptr_t)GetSysColorBrush(COLOR_WINDOW);
-        break;
-
-    default: break;
-    }
-
-    return FALSE;
-}
-
-
-int startwin_open(void)
-{
-    INITCOMMONCONTROLSEX icc;
-    if (startupdlg) return 1;
-    icc.dwSize = sizeof(icc);
-    icc.dwICC = ICC_TAB_CLASSES;
-    InitCommonControlsEx(&icc);
-    startupdlg = CreateDialog((HINSTANCE)win_gethinstance(), MAKEINTRESOURCE(WIN_STARTWIN), NULL, startup_dlgproc);
-    if (startupdlg)
-    {
-        {
-            static int soundQualityFrequencies[] = { 44100, 22050, 11025 };
-            static int soundQualitySampleSizes[] = { 16, 8 };
-            static int soundQualityChannels[]    = { 2, 1 };
-            unsigned int f, b, c, i;
-
-            i = sizeof(soundQualityFrequencies) *
-                sizeof(soundQualitySampleSizes) *
-                sizeof(soundQualityChannels) /
-                sizeof(int) + 2;    // one for the terminator, one for a custom setting
-            soundQualities = (struct soundQuality_t *) malloc(i * sizeof(struct soundQuality_t));
-
-            i = 0;
-            for (c = 0; c < sizeof(soundQualityChannels) / sizeof(int); c++)
-            {
-                for (b = 0; b < sizeof(soundQualitySampleSizes) / sizeof(int); b++)
-                {
-                    for (f = 0; f < sizeof(soundQualityFrequencies) / sizeof(int); f++)
-                    {
-                        soundQualities[i].frequency = soundQualityFrequencies[f];
-                        soundQualities[i].samplesize = soundQualitySampleSizes[b];
-                        soundQualities[i].channels = soundQualityChannels[c];
-
-                        i++;
-                    }
-                }
-            }
-
-            soundQualities[i].frequency = -1;
-        }
-
-        SetPage(TAB_MESSAGES);
-        EnableConfig(0);
-        return 0;
-    }
-    return -1;
-}
-
-int startwin_close(void)
-{
-    if (!startupdlg) return 1;
-    DestroyWindow(startupdlg);
-    startupdlg = NULL;
-    free(soundQualities);
-    return 0;
-}
-
-int startwin_puts(const char *buf)
-{
-    const char *p = NULL, *q = NULL;
-    char workbuf[1024];
-    static int newline = 0;
-    int curlen, linesbefore, linesafter;
-    HWND edctl;
-    int vis;
-
-    if (!startupdlg) return 1;
-
-    edctl = pages[TAB_MESSAGES];
-    if (!edctl) return -1;
-
-    vis = ((int)SendMessageA(GetDlgItem(startupdlg, WIN_STARTWIN_TABCTL), TCM_GETCURSEL,0,0) == TAB_MESSAGES);
-
-    if (vis) SendMessageA(edctl, WM_SETREDRAW, FALSE,0);
-    curlen = SendMessageA(edctl, WM_GETTEXTLENGTH, 0,0);
-    SendMessageA(edctl, EM_SETSEL, (WPARAM)curlen, (LPARAM)curlen);
-    linesbefore = SendMessageA(edctl, EM_GETLINECOUNT, 0,0);
-    p = buf;
-    while (*p)
-    {
-        if (newline)
-        {
-            SendMessageA(edctl, EM_REPLACESEL, 0, (LPARAM)"\r\n");
-            newline = 0;
-        }
-        q = p;
-        while (*q && *q != '\n') q++;
-        memcpy(workbuf, p, q-p);
-        if (*q == '\n')
-        {
-            if (!q[1])
-            {
-                newline = 1;
-                workbuf[q-p] = 0;
-            }
-            else
-            {
-                workbuf[q-p] = '\r';
-                workbuf[q-p+1] = '\n';
-                workbuf[q-p+2] = 0;
-            }
-            p = q+1;
-        }
-        else
-        {
-            workbuf[q-p] = 0;
-            p = q;
-        }
-        SendMessageA(edctl, EM_REPLACESEL, 0, (LPARAM)workbuf);
-    }
-    linesafter = SendMessageA(edctl, EM_GETLINECOUNT, 0,0);
-    SendMessageA(edctl, EM_LINESCROLL, 0, linesafter-linesbefore);
-    if (vis) SendMessageA(edctl, WM_SETREDRAW, TRUE,0);
-    return 0;
-}
-
-int startwin_settitle(const char *str)
-{
-    if (!startupdlg) return 1;
-    SetWindowTextA(startupdlg, str);
-    return 0;
-}
-
-int startwin_idle(void *v)
-{
-    if (!startupdlg || !IsWindow(startupdlg)) return 0;
-    if (IsDialogMessage(startupdlg, (MSG *)v)) return 1;
-    return 0;
-}
-
-int startwin_run(void)
-{
-    MSG msg;
-    if (!startupdlg) return 1;
-
-    done = -1;
-
-    ScanGroups();
-
-    SetPage(TAB_CONFIG);
-    EnableConfig(1);
-
-    settings.fullscreen = ScreenMode;
-    settings.xdim = ScreenWidth;
-    settings.ydim = ScreenHeight;
-    settings.bpp = ScreenBPP;
-    settings.samplerate = snd_mixrate;
-    settings.bitspersample = 16;
-    settings.channels = snd_numchannels;
-    settings.usemouse = UseMouse;
-    settings.usejoy = UseJoystick;
-    Bstrncpyz(settings.selectedgrp, G_GrpFile(), BMAX_PATH);
-    PopulateForm(-1);
-
-    while (done < 0)
-    {
-        switch (GetMessage(&msg, NULL, 0,0))
-        {
-        case 0: done = 1; break;
-        case -1: return -1;
-        default:
-            if (IsWindow(startupdlg) && IsDialogMessage(startupdlg, &msg)) break;
-            TranslateMessage(&msg);
-            DispatchMessage(&msg);
-            break;
-        }
-    }
-
-    SetPage(TAB_MESSAGES);
-    EnableConfig(0);
-    if (done)
-    {
-        ScreenMode = settings.fullscreen;
-        ScreenWidth = settings.xdim;
-        ScreenHeight = settings.ydim;
-        ScreenBPP = settings.bpp;
-        UseMouse = settings.usemouse;
-        UseJoystick = settings.usejoy;
-        clearGrpNamePtr();
-        g_grpNamePtr = dup_filename(settings.selectedgrp);
-    }
-
-    FreeGroups();
-
-    return done;
-}
-
-
-END_SW_NS
diff --git a/source/sw/src/startwin.game.h b/source/sw/src/startwin.game.h
deleted file mode 100644
index a008300d2..000000000
--- a/source/sw/src/startwin.game.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// resource ids
-#define WIN_STARTWIN        1000
-#define WIN_STARTWINPAGE_CONFIG 2000
-#define WIN_STARTWINPAGE_GAME   3000
-#define WIN_STARTWIN_BITMAP 100 // banner bitmap
-#define WIN_STARTWIN_TABCTL 101
-#define WIN_STARTWIN_CANCEL IDCANCEL
-#define WIN_STARTWIN_START  IDOK
-
-#define WIN_STARTWIN_MESSAGES   104 // output list box
-
-#define RSRC_ICON       100
-#define RSRC_BMP        200
-
-// config page
-#define IDCFULLSCREEN   100
-#define IDCVMODE    101
-#define IDCSOUNDQUAL    102
-#define IDCINPUTMOUSE   105
-#define IDCINPUTJOY 106
-#define IDCALWAYSSHOW   107
-
-// game page
-#define IDGDATA     100
-