Index: CoreLibrary/cseries/windows_cseries.h
===================================================================
--- CoreLibrary/cseries/windows_cseries.h	(revision 5098)
+++ CoreLibrary/cseries/windows_cseries.h	(working copy)
@@ -101,6 +101,24 @@
 
 const char * get_current_exe_name(void);
 
+/* Build 403 - DRB - threads */
+
+typedef struct tagTHREAD
+{
+	byte running, exited, quit_signal, padding;
+	HANDLE thread_handle;
+	DWORD thread_id;
+	int exit_code;
+	void *user_data;
+	const char *name;
+	boolean (*init_proc)(struct tagTHREAD*, void*);
+	int (*thread_proc)(struct tagTHREAD*, void*);
+} THREAD, *PTHREAD;
+
+void set_thread_name(DWORD thread_id, const char* thread_name);
+void create_thread(THREAD *thread, const char *name, int (*thread_proc)(THREAD*, void*), boolean (*init_proc)(THREAD*, void*), void *user_data);
+int wait_thread(THREAD *thread);
+
 const char * get_windows_exception_string(DWORD exception_code);
 
 /* ---- cursors */
@@ -149,4 +167,4 @@
 }
 #endif
 
-#endif
\ No newline at end of file
+#endif
Index: CoreLibrary/cseries/windows_utilities.c
===================================================================
--- CoreLibrary/cseries/windows_utilities.c	(revision 5098)
+++ CoreLibrary/cseries/windows_utilities.c	(working copy)
@@ -47,9 +47,6 @@
 static boolean debugger_installed= FALSE;
 static boolean force_next_dprintf_state= FALSE;
 
-static void (*setup_for_messagebox)(void)= NULL;
-static void (*setdown_for_messagebox)(void)= NULL;
-
 // --------- local prototypes
 
 static void restore_screen_saver(void);
@@ -251,8 +248,6 @@
 		vsprintf(buffer, format, arglist);
 		va_end(arglist);
 
-//		if (setup_for_messagebox) setup_for_messagebox();
-//		MessageBox(screen_window, buffer, NULL, MB_OK | MB_ICONEXCLAMATION);
 		strcat(buffer, "\n");
 
 		// Send the dprintf to the debug file
@@ -260,12 +255,8 @@
 		write_to_error_file(buffer, FALSE);
 #endif
 
-//#ifndef EXTERNAL_DEBUG_BUILD
 		OutputDebugString(buffer);
-//#endif
-//		enter_debugger();
-//		if (setdown_for_messagebox) setdown_for_messagebox();
-		
+
 		force_next_dprintf_state= FALSE;
 	}
 #endif
@@ -304,16 +295,9 @@
 	return_value= vsprintf(buffer, format, arglist);
 	va_end(arglist);
 
-	if (setup_for_messagebox)
-	{
-		setup_for_messagebox();
-	}
-	MessageBox(NULL, buffer, NULL, MB_OK);
-	if (setdown_for_messagebox)
-	{
-		setdown_for_messagebox();
-	}
-	
+	//MessageBox(NULL, buffer, NULL, MB_OK);
+	log_message(NULL, NONE, buffer);
+
 	return;
 }
 
@@ -527,16 +511,6 @@
 	boost_timer_resolution(FALSE);
 }
 
-void set_pre_and_post_messagebox_functions(
-	void (*pre)(void),
-	void (*post)(void))
-{	
-	setup_for_messagebox= pre;
-	setdown_for_messagebox= post;
-
-	return;
-}
-
 void initialize_working_directory(
 	void)
 {
@@ -825,6 +799,77 @@
 	}
 }
 
+void set_thread_name(DWORD thread_id, const char* thread_name)
+{
+	enum { MS_VC_EXCEPTION = 0x406D1388 };
+
+	struct THREADNAME_INFO
+	{
+		DWORD dwType; // Must be 0x1000.
+		LPCSTR szName; // Pointer to name (in user addr space).
+		DWORD dwThreadID; // Thread ID (-1=caller thread).
+		DWORD dwFlags; // Reserved for future use, must be zero.
+	} info;
+
+	info.dwType = 0x1000;
+	info.szName = thread_name;
+	info.dwThreadID = thread_id;
+	info.dwFlags = 0;
+
+	__try
+	{
+		RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info);
+	}
+	__except(EXCEPTION_EXECUTE_HANDLER)
+	{
+	}
+}
+
+static DWORD WINAPI thread_startup(LPVOID lpParameter)
+{
+	THREAD *thread = (THREAD*)lpParameter;
+	if(!thread->init_proc ||
+		thread->init_proc(thread, thread->user_data))
+	{
+		thread->running = TRUE;
+		thread->exit_code = thread->thread_proc(thread, thread->user_data);
+	}
+	else
+	{
+		thread->exit_code = NONE;
+	}
+	thread->running = FALSE;
+	thread->exited = TRUE;
+	return thread->exit_code;
+}
+
+void create_thread(THREAD *thread, const char *name, int (*thread_proc)(THREAD*, void*), boolean (*init_proc)(THREAD*, void*), void *user_data)
+{
+	memset(thread, 0, sizeof(*thread));
+	thread->name = name;
+	thread->thread_proc = thread_proc;
+	thread->init_proc = init_proc;
+	thread->user_data = user_data;
+	thread->thread_handle = CreateThread(NULL, 0, thread_startup, thread, 0, &thread->thread_id);
+	set_thread_name(thread->thread_id, thread->name);
+	while(!thread->running)
+	{
+		Sleep(1);
+	}
+}
+
+int wait_thread(THREAD *thread)
+{
+	if(thread->thread_handle)
+	{
+		WaitForSingleObject(thread->thread_handle, INFINITE);
+		assert(thread->exited && !thread->running);
+		CloseHandle(thread->thread_handle);
+		thread->thread_handle = NULL;
+	}
+	return thread->exit_code;
+}
+
 const char * get_windows_exception_string(DWORD exception_code)
 {
 	switch(exception_code)
Index: CoreLibrary/sound/sound_manager.h
===================================================================
--- CoreLibrary/sound/sound_manager.h	(revision 5098)
+++ CoreLibrary/sound/sound_manager.h	(working copy)
@@ -45,6 +45,7 @@
 void initialize_sound_manager_for_new_map(void);
 void initialize_sound_mesh_parameters_for_new_map(void);
 void dispose_sound_manager_from_old_map(void);
+void reboot_sound_manager(void);
 
 boolean machine_can_play_sound(void);
 #ifdef MYTH2
@@ -97,6 +98,15 @@
 
 void set_global_ambient_sound_index(short ambient_sound_index);
 
+#ifdef windows
+#include "sound_provider_choice.h"
+#ifdef ENABLE_DSOUND
+#include "DirectX/dsound.h"
+void reset_dsound_hwnd(void);
+LPDIRECTSOUND get_direct_sound_object_for_cutscenes(void);
+#endif
+#endif
+
 #ifdef __cplusplus
 }
 #endif
Index: CoreLibrary/sound/sound_provider_choice.h
===================================================================
--- CoreLibrary/sound/sound_provider_choice.h	(revision 5098)
+++ CoreLibrary/sound/sound_provider_choice.h	(working copy)
@@ -1,4 +1,5 @@
-// Include this only where necessary, so that we can switch providers without big recompiles.
+#ifndef __SOUND_PROVIDER_CHOICE_H__
+#define __SOUND_PROVIDER_CHOICE_H__
 
 #include "platform_cseries.h"
 
@@ -27,3 +28,5 @@
 	_sound_provider_first = _sound_provider_native,
 	_sound_provider_last = _sound_provider_openal
 };
+
+#endif // __SOUND_PROVIDER_CHOICE_H__
Index: CoreLibrary/sound/sound_windows.c
===================================================================
--- CoreLibrary/sound/sound_windows.c	(revision 5098)
+++ CoreLibrary/sound/sound_windows.c	(working copy)
@@ -103,7 +103,7 @@
 	struct buffered_sound_data buffers[MAXIMUM_SOUNDS_BUFFERED_PER_CHANNEL];
 
 	// 3D sound channel data
-	boolean	bIs3D;
+	boolean bIs3D;
 	LPDIRECTSOUND3DBUFFER channel3D;
 	LPKSPROPERTYSET bufferPropertySet;
 
@@ -122,9 +122,7 @@
 	LPDIRECTSOUNDBUFFER primary_sound_buffer;
 	int sound_bit_depth;
 
-	DWORD thread_id;
-	boolean thread_active;
-	boolean continue_thread;
+	THREAD thread;
 
 	// For non-3D sound
 	short volume_remapping_table[MAXIMUM_VOLUME+1];
@@ -177,7 +175,7 @@
 
 static void install_sound_tickler_thread(void);
 static void remove_sound_tickler_thread(void);
-static DWORD WINAPI sound_tickler_thread_proc(LPVOID lpThreadParameter);
+static int sound_tickler_thread_proc(THREAD *thread, void *user_data);
 
 static boolean initialize_dsound_manager(void);
 static boolean initialize_dsound_channels(unsigned long flags);
@@ -261,13 +259,7 @@
 		goto _exit_with_error;
 	}
 
-	assert(screen_window);
-	err= IDirectSound_SetCooperativeLevel(dsound_globals->direct_sound, screen_window, DSSCL_EXCLUSIVE);
-	if (FAILED(err))
-	{
-		dprintf_ds_err("Setting cooperative level failed", err);
-		goto _exit_with_error;
-	}
+	reset_dsound_hwnd();
 
 	{
 		/* Create the volume remapping table, because windows uses a completely stupid logarithmic table */
@@ -1153,6 +1145,8 @@
 
 		// give the thread time to free all its globals.
 		Sleep(2);
+		// Build 403 - DRB - TODO/FIXME: Above comment and Sleep() call look quite suspicious.
+		// They should either be removed, or replaced with a proper wait based solution.
 
 		CoUninitialize();
 	}
@@ -1507,21 +1501,6 @@
 	return;
 }
 
-LPDIRECTSOUND get_direct_sound_object_for_cutscenes(
-	void)
-{
-	// dsound_globals will not be initialized if you don't have a valid
-	// DS driver, so don't assume it is.
-	if (dsound_globals)
-	{
-		return dsound_globals->direct_sound;
-	}
-	else
-	{
-		return NULL;
-	}
-}
-
 // A3D-code: Modified call to take boolean-flag requesting A3D or not.
 // Basically a global on/off for 3D-audio. (TRUE = ON.)
 static HRESULT create_direct_sound_object(
@@ -1593,30 +1572,14 @@
 static void install_sound_tickler_thread(
 	void)
 {
-	HANDLE thread;
-
 	assert(dsound_globals && dsound_globals->initialized);
-	assert(!dsound_globals->thread_active);
 
+	assert(!dsound_globals->update_event)
 	dsound_globals->update_event = CreateEvent(NULL, FALSE, FALSE, NULL);
 
-	dsound_globals->continue_thread= TRUE;
-	thread= CreateThread(NULL, 0, sound_tickler_thread_proc, dsound_globals, 0, &dsound_globals->thread_id);
-	if (thread)
-	{
-		SetThreadPriority(thread, THREAD_PRIORITY_HIGHEST);
+	assert(!dsound_globals->thread.thread_handle);
+	create_thread(&dsound_globals->thread, "Myth DSound Thread", sound_tickler_thread_proc, NULL, dsound_globals);
 
-		while (!dsound_globals->thread_active)
-		{	
-			Sleep(1);
-		}
-		CloseHandle(thread); // this is okay to do now.
-	}
-	else
-	{
-		dsound_globals->thread_id= (DWORD) NONE;
-	}
-	
 	return;
 }
 
@@ -1624,26 +1587,27 @@
 	void)
 {
 	assert(dsound_globals && dsound_globals->initialized);
-	dsound_globals->continue_thread= FALSE;
+	assert(dsound_globals->thread.thread_handle);
+
+	dsound_globals->thread.quit_signal = TRUE;
 	SetEvent(dsound_globals->update_event);
-	while (dsound_globals->thread_active)
-	{
-		Sleep(1);
-	}
+	wait_thread(&dsound_globals->thread);
 	CloseHandle(dsound_globals->update_event);
-	
+	dsound_globals->update_event = NULL;
+
 	return;
 }
 
-static DWORD WINAPI sound_tickler_thread_proc(
-	LPVOID lpThreadParameter)
+static int sound_tickler_thread_proc(
+	THREAD *thread, void *user_data)
 {
-	struct dsound_globals_data *globals= (struct dsound_globals_data *) lpThreadParameter;
+	struct dsound_globals_data *globals= (struct dsound_globals_data *) user_data;
 	
 	assert(globals && globals->initialized);
 
-	globals->thread_active= TRUE;
-	while (globals->continue_thread)
+	SetThreadPriority(thread->thread_handle, THREAD_PRIORITY_HIGHEST);
+
+	while(!thread->quit_signal)
 	{
 		unsigned long sleep_time, nearest_deadline = NONE;
 
@@ -1658,9 +1622,41 @@
 		// if nearest_deadline == NONE, then this is some huge unsigned number, which works out perfectly.
 		sleep_time = nearest_deadline - machine_tick_count();
 		sleep_time = MIN(sleep_time, MAXIMUM_TIME_BETWEEN_UPDATES_IN_MILISECONDS);
-		WaitForSingleObject(dsound_globals->update_event, sleep_time);
+		WaitForSingleObject(globals->update_event, sleep_time);
 	}
-	globals->thread_active= FALSE;
 	
-	return 0L;
+	return 0;
 }
+
+// ------------------ exports
+
+LPDIRECTSOUND get_direct_sound_object_for_cutscenes(
+	void)
+{
+	// dsound_globals will not be initialized if you don't have a valid
+	// DS driver, so don't assume it is.
+	if (dsound_globals)
+	{
+		return dsound_globals->direct_sound;
+	}
+	else
+	{
+		return NULL;
+	}
+}
+
+void reset_dsound_hwnd(
+	void)
+{
+	assert(screen_window);
+
+	if(dsound_globals)
+	{
+		HRESULT err;
+		err= IDirectSound_SetCooperativeLevel(dsound_globals->direct_sound, screen_window, DSSCL_EXCLUSIVE);
+		if (FAILED(err))
+		{
+			dprintf_ds_err("Setting cooperative level failed", err);
+		}
+	}
+}
Index: Myth2.vcproj
===================================================================
--- Myth2.vcproj	(revision 5098)
+++ Myth2.vcproj	(working copy)
@@ -1633,6 +1633,9 @@
 			RelativePath=".\Myth2Code\detail_textures.h">
 		</File>
 		<File
+			RelativePath=".\Myth2Code\display_device_windows.c">
+		</File>
+		<File
 			RelativePath=".\Myth2Code\effect_definitions.h">
 		</File>
 		<File
Index: Myth2_vc10.vcxproj
===================================================================
--- Myth2_vc10.vcxproj	(revision 5098)
+++ Myth2_vc10.vcxproj	(working copy)
@@ -130,6 +130,7 @@
     <ClCompile Include="Myth2Code\bitmap_dialogs\tag_list_control.c" />
     <ClCompile Include="Myth2Code\connectors.c" />
     <ClCompile Include="Myth2Code\connector_definitions.c" />
+    <ClCompile Include="Myth2Code\display_device_windows.c" />
     <ClCompile Include="Myth2Code\formation_definitions.c" />
     <ClCompile Include="Myth2Code\hardware\DirectX11\dx11_context.cpp" />
     <ClCompile Include="Myth2Code\hardware\DirectX11\dx11_shaders.cpp" />
Index: Myth2_vc10.vcxproj.filters
===================================================================
--- Myth2_vc10.vcxproj.filters	(revision 5098)
+++ Myth2_vc10.vcxproj.filters	(working copy)
@@ -857,6 +857,9 @@
     <ClCompile Include="Myth2Code\input\windows_touch_api.c">
       <Filter>input</Filter>
     </ClCompile>
+    <ClCompile Include="Myth2Code\display_device_windows.c">
+      <Filter>window manager\windows</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="CoreLibrary\myth\active_squads.h" />
Index: Myth2Code/cutscenes/cutscenes.c
===================================================================
--- Myth2Code/cutscenes/cutscenes.c	(revision 5098)
+++ Myth2Code/cutscenes/cutscenes.c	(working copy)
@@ -19,9 +19,7 @@
 #include "screen.h"
 #include "x_files.h"
 #include "error_manager.h"
-#include "keyboard.h"			// Build 112 - PAB - Get keypresses
-#include "input_controller.h"	// Build 112 - PAB - Get keypresses
-#include "shell.h"				// Build 112 - PAB - Get keypresses
+#include "keyboard.h"
 #include "sound_manager_private.h"
 #include "bitmap_drawing.h"
 #include "modal_loops.h"
Index: Myth2Code/display_device_windows.c
===================================================================
--- Myth2Code/display_device_windows.c	(revision 0)
+++ Myth2Code/display_device_windows.c	(working copy)
@@ -0,0 +1,290 @@
+// Build 403 - DRB - Moved this code from screen_windows.c into its own file.
+
+#include "platform_cseries.h"
+#include "screen_setup.h"
+#include "system_info.h"
+#include "screen.h"
+
+extern HWND screen_window;
+
+struct device_info generic_device;
+static WORD *startup_gamma_ramp = NULL;
+static boolean display_device_initialized = FALSE;
+
+static void dispose_display_device(void)
+{
+	if(startup_gamma_ramp)
+	{
+		free(startup_gamma_ramp);
+		startup_gamma_ramp = NULL;
+	}
+}
+
+void initialize_display_device(void)
+{
+	if(!display_device_initialized)
+	{
+		memset(&generic_device, 0, sizeof(generic_device));
+		display_device_get_modes(&generic_device);
+
+		atexit(dispose_display_device);
+
+		display_device_initialized = TRUE;
+	}
+}
+
+boolean enum_display_settings(DEVMODE *dm, int mode_index)
+{
+	boolean success;
+
+	ZeroMemory(dm, sizeof(DEVMODE));
+	dm->dmSize = sizeof(DEVMODE);
+
+	success = EnumDisplaySettings(NULL, mode_index, dm);
+
+	if(success && !(dm->dmPelsWidth && dm->dmPelsHeight))
+	{
+		success = FALSE;
+	}
+
+	if(!success && mode_index == ENUM_REGISTRY_SETTINGS)
+	{
+		// Fallback to GetSystemMetrics for getting the desktop size.
+		dm->dmPelsWidth = GetSystemMetrics(SM_CXSCREEN);
+		dm->dmPelsHeight = GetSystemMetrics(SM_CYSCREEN);
+		success = dm->dmPelsWidth && dm->dmPelsHeight;
+	}
+
+	if(!success)
+	{
+		ZeroMemory(dm, sizeof(DEVMODE));
+		dm->dmSize= sizeof(DEVMODE);
+	}
+
+	return success;
+}
+
+boolean display_device_set_mode(
+	boolean fullscreen,
+	int width,
+	int height,
+	int bit_depth)
+{
+	static int last_fullscreen= FALSE, last_width, last_height, last_bitdepth;
+
+	boolean success= TRUE;
+
+	boolean mode_changed=
+		fullscreen != last_fullscreen ||
+		last_width != width ||
+		last_height != height ||
+		last_bitdepth != bit_depth;
+
+	if(mode_changed)
+	{
+		LONG result;
+
+		if(fullscreen)
+		{
+			DEVMODE dm;
+			ZeroMemory(&dm, sizeof(dm));
+			dm.dmSize= sizeof(dm);
+			dm.dmBitsPerPel= bit_depth;
+			dm.dmPelsWidth= width;
+			dm.dmPelsHeight= height;
+			dm.dmFields= DM_PELSHEIGHT|DM_PELSWIDTH|DM_BITSPERPEL;
+			result= ChangeDisplaySettings(&dm, CDS_FULLSCREEN|CDS_RESET);
+		}
+		else
+		{
+			// Reset to the desktop mode.
+
+			// We used to just call ChangeDisplaySettings(NULL, 0) here, but the latest NVidia drivers apparently no longer ignores
+			// this call when it's redundant. (i.e. it does a hard mode reset on every call - screen goes black for a second.)
+			// To avoid this, explicitly check that we aren't already on the desktop mode.
+
+			boolean mode_change= TRUE;
+
+			DEVMODE dm_current, dm_registry;
+			if(enum_display_settings(&dm_current, ENUM_CURRENT_SETTINGS) &&
+				enum_display_settings(&dm_registry, ENUM_REGISTRY_SETTINGS))
+			{
+				// Just check the fields we care about - don't use memcmp() because
+				// there seems to be some other junk in the struct that doesn't match
+				// even though the modes are the same.
+				if(dm_current.dmBitsPerPel == dm_registry.dmBitsPerPel &&
+					dm_current.dmPelsWidth == dm_registry.dmPelsWidth &&
+					dm_current.dmPelsHeight == dm_registry.dmPelsHeight)
+				{
+					mode_change= FALSE;
+				}
+			}
+
+			if(mode_change)
+			{
+				result= ChangeDisplaySettings(NULL, 0);
+			}
+			else
+			{
+				result= DISP_CHANGE_SUCCESSFUL;
+			}
+		}
+
+		success= (result == DISP_CHANGE_SUCCESSFUL);
+
+		if(!success)
+		{
+			log_message(NULL, NONE, "Warning: ChangeDisplaySettings() failed! Result code = %d. Details = (mode=%dx%d, fullscreen=%d)",
+				result, width, height, fullscreen);
+		}
+	}
+
+	last_fullscreen= fullscreen;
+	last_width= width;
+	last_height= height;
+	last_bitdepth= bit_depth;
+
+	return success;
+}
+
+boolean display_device_supports_gamma(
+	void)
+{
+	static boolean support_tested= FALSE;
+	static boolean support_found= FALSE;
+
+	if(!support_tested)
+	{
+		HDC hdc= GetDC(screen_window);
+
+		if(hdc)
+		{
+			startup_gamma_ramp= malloc(768*sizeof(WORD));
+			support_found= GetDeviceGammaRamp(hdc, startup_gamma_ramp);
+			ReleaseDC(screen_window, hdc);
+		}
+
+		support_tested= TRUE;
+	}
+
+	return support_found;
+}
+
+void display_device_set_gamma(
+	boolean enable,
+	short_fixed gamma)
+{
+	HDC hdc;
+
+	if(!display_device_supports_gamma())
+	{
+		return;
+	}
+
+	hdc= GetDC(screen_window);
+
+	if(hdc)
+	{
+		WORD new_gamma_ramp[3][256];
+		WORD *ramp = startup_gamma_ramp;
+
+		if(enable)
+		{
+			int i;
+
+			for(i = 0; i < 256; ++i)
+			{
+				int level= MIN(i*gamma, UNSIGNED_SHORT_MAX);
+
+				new_gamma_ramp[0][i]= level;
+				new_gamma_ramp[1][i]= level;
+				new_gamma_ramp[2][i]= level;
+			}
+
+			ramp = (WORD*)new_gamma_ramp;
+		}
+
+		SetDeviceGammaRamp(hdc, ramp);
+		ReleaseDC(screen_window, hdc);
+	}
+}
+
+struct device_mode_info *display_device_supports_resolution(
+	struct device_info *device,
+	int width,
+	int height)
+{
+	int i;
+
+	if(!device)
+	{
+		device = &generic_device;
+	}
+
+	for(i = 0; i < device->mode_count; ++i)
+	{
+		if(device->modes[i].width == width &&
+			device->modes[i].height == height)
+		{
+			return device->modes+i;
+		}
+	}
+
+	return FALSE;
+}
+
+void display_device_get_modes(
+	struct device_info * device)
+{
+	int mode_index= 0;
+	DEVMODE devmode;
+
+	while(device->mode_count < MAXIMUM_DISPLAY_MODE_COUNT &&
+		enum_display_settings(&devmode, mode_index))
+	{
+		//if(ChangeDisplaySettings(&devmode, CDS_TEST) == DISP_CHANGE_SUCCESSFUL)
+		{
+			// Only use surfaces that match what we want.
+			if(devmode.dmBitsPerPel >= 16 && is_valid_resolution(devmode.dmPelsWidth, devmode.dmPelsHeight))
+			{
+				// Only add modes that we don't already have
+				if(!display_device_supports_resolution(device, devmode.dmPelsWidth, devmode.dmPelsHeight))
+				{
+					struct device_mode_info *mode= &device->modes[device->mode_count];
+
+					mode->width= devmode.dmPelsWidth;
+					mode->height= devmode.dmPelsHeight;
+#ifdef __RENDER_32_BIT__
+					mode->bit_depth= 32;
+#else
+					mode->bit_depth= 16;
+#endif
+					//don't set the refresh rate,
+					//this will be inherited from the user's desktop settings
+					mode->refresh_rate= 0;//devmode.dmDisplayFrequency;
+					mode->flags= 0;
+
+					// increment the number of display modes
+					++device->mode_count;
+				}
+			}
+		}
+		++mode_index;
+	}
+}
+
+void display_device_query_and_report_modes(
+	int rasterizer_code,
+	const char * rasterizer_string,
+	void * device_extra)
+{
+	if(generic_device.mode_count > 0)
+	{
+		struct device_info device;
+		memcpy(&device, &generic_device, sizeof(device));
+		strncpy(device.name, rasterizer_string, sizeof(device.name));
+		device.rasterizer_code= rasterizer_code;
+		device.extra_data= device_extra;
+		report_device(&device);
+	}
+}
Index: Myth2Code/hardware/Direct3D/utilities_d3d.c
===================================================================
--- Myth2Code/hardware/Direct3D/utilities_d3d.c	(revision 5098)
+++ Myth2Code/hardware/Direct3D/utilities_d3d.c	(working copy)
@@ -1344,12 +1344,16 @@
 	{
 		struct dialog_rasterization_data data;
 
-		// Build 402 - DRB - Inserted if statements so we don't crash if the bars don't exist yet. This is just a band-aid solution,
+		// Build 402/403 - DRB - Inserted if statements so we don't crash if the bars don't exist yet. This is just a band-aid solution,
 		// ideally the whole restore mechanism should be rewritten (probably abstracted through the texture cache).
-		get_rasterization_data_for_dialog(get_status_bar_dialog(), &data);
-		if(data.bitmap) draw_status_bar_hardware(&data);
-		get_rasterization_data_for_dialog(get_control_bar_dialog(), &data);
-		if(data.bitmap) draw_control_bar_hardware(&data);
+		if(get_status_bar_dialog()) {
+			get_rasterization_data_for_dialog(get_status_bar_dialog(), &data);
+			if(data.bitmap) draw_status_bar_hardware(&data);
+		}
+		if(get_control_bar_dialog()) {
+			get_rasterization_data_for_dialog(get_control_bar_dialog(), &data);
+			if(data.bitmap) draw_control_bar_hardware(&data);
+		}
 	}
 
 	// Restore cached surfaces
Index: Myth2Code/hardware/DirectX11/render_dx11.cpp
===================================================================
--- Myth2Code/hardware/DirectX11/render_dx11.cpp	(revision 5098)
+++ Myth2Code/hardware/DirectX11/render_dx11.cpp	(working copy)
@@ -187,9 +187,8 @@
 	// NOTE: Surrounding code (screen_windows.*) is handling mode switches so we just instruct DXGI to
 	// do "windowed" mode (i.e. don't change modes at all!). This works around some issues with multiple mode
 	// switches in full screen mode.
-	//bool windowed = !is_true_fullscreen_now();
 	bool windowed = true;
-		
+
 	// ATL TODO: Figure out how windowed mode and mode switches are supposed to interact with the rasterizer backends...
 	bool success = context.initialize(
 		screen_window,
Index: Myth2Code/hardware/OpenGL/setup_opengl_windows.c
===================================================================
--- Myth2Code/hardware/OpenGL/setup_opengl_windows.c	(revision 5102)
+++ Myth2Code/hardware/OpenGL/setup_opengl_windows.c	(working copy)
@@ -108,7 +108,7 @@
 	// Working around the Vista bug.
 	if(get_game_state() != _game_state_running) // Build 361 - DRB - no need to do this if we are just restarting the level or loading a saved game.
 	{
-		if(windows_vista_or_higher())
+		if(gOpenGLWindow && windows_vista_or_higher())
 		{
 			// While we still have a context, remove the WS_POPUP style and make the window not topmost.
 			// This works around the bug on nVidia cards.
Index: Myth2Code/input/action_queue.c
===================================================================
--- Myth2Code/input/action_queue.c	(revision 5098)
+++ Myth2Code/input/action_queue.c	(working copy)
@@ -62,6 +62,11 @@
 static void set_action_flags_for_axis_values(struct action_data *action,
 	float yaw_axis, float parallel_axis, float orthogonal_axis,
 	float orbit_axis, float zoom_axis);
+
+static void initialize_queue_mutex(void);
+static void lock_queue(void);
+static void unlock_queue(void);
+
 	
 /* ---------- globals */
 
@@ -69,6 +74,10 @@
 
 static boolean pointer_can_generate_actions= FALSE;
 
+#ifdef windows
+CRITICAL_SECTION queue_mutex;
+#endif
+
 /* ---------- code */
 
 void initialize_actions(
@@ -86,6 +95,8 @@
 	}
 	
 	actions->queue.read_index= actions->queue.write_index= 0;
+
+	initialize_queue_mutex();
 	initialize_selection();
 	initialize_keyboard();
 	
@@ -110,11 +121,15 @@
 }
 
 // interrupt-safe
+// Build 403 - DRB - the above comment is true for the single-writer case;
+// now that we have multiple writers on some platforms, locking is needed.
 void queue_action(
 	struct action_data *action)
 {
 	static int last_queued_action_time = 0;
 
+	lock_queue();
+
 	if (QUEUE_SIZE(actions->queue.read_index, actions->queue.write_index)<MAXIMUM_QUEUE_SIZE)
 	{
 		int now= get_local_time();
@@ -127,6 +142,8 @@
 		INCREMENT_QUEUE_INDEX(actions->queue.write_index);
 	}
 
+	unlock_queue();
+
 	return;
 }
 
@@ -361,6 +378,30 @@
 	return;
 }
 
+static void initialize_queue_mutex(
+	void)
+{
+#ifdef windows
+	InitializeCriticalSection(&queue_mutex);
+#endif
+}
+
+static void lock_queue(
+	void)
+{
+#ifdef windows
+	EnterCriticalSection(&queue_mutex);
+#endif
+}
+
+static void unlock_queue(
+	void)
+{
+#ifdef windows
+	LeaveCriticalSection(&queue_mutex);
+#endif
+}
+
 static void adjust_axis_values_for_mouse_movement(
 	rectangle2d *mouse_bounds,
 	point2d *p,
Index: Myth2Code/input/input_controller.h
===================================================================
--- Myth2Code/input/input_controller.h	(revision 5098)
+++ Myth2Code/input/input_controller.h	(working copy)
@@ -60,7 +60,6 @@
 #endif
 
 #ifdef windows
-	void pause_system_input_device(boolean paused);
 	void set_windows_keyboard_layout(void);
 #endif
 
Index: Myth2Code/input/input_controller_windows.c
===================================================================
--- Myth2Code/input/input_controller_windows.c	(revision 5098)
+++ Myth2Code/input/input_controller_windows.c	(working copy)
@@ -239,12 +239,6 @@
 	return TRUE;
 }
 
-void pause_system_input_device(
-	boolean paused)
-{
-	return;
-}
-
 void release_input_devices(
 	void)
 {
@@ -381,7 +375,7 @@
 
 	if(!myth_is_active())
 	{
-		return;	
+		return;
 	}
 
 	if(axis == _mouse_wheel_axis_y)
Index: Myth2Code/myth.c
===================================================================
--- Myth2Code/myth.c	(revision 5098)
+++ Myth2Code/myth.c	(working copy)
@@ -273,8 +273,11 @@
 	initialize_model_animations();
 	initialize_keybindings();
 
+	// must before above initialize_screen for _game_pref_multicore
+	initialize_game_preferences();
+
 	initialize_screen();
-	initialize_game_preferences();
+
 	atexit(save_preferences);
 
 	/* Must be after initialize_screen, for input_controller.c (directInput) */
Index: Myth2Code/preferences_ui.c
===================================================================
--- Myth2Code/preferences_ui.c	(revision 5098)
+++ Myth2Code/preferences_ui.c	(working copy)
@@ -227,9 +227,15 @@
 
 				{
 					boolean use_multicore = get_checkbox_state(dialog, iUSE_MULTICORE);
+					boolean old_use_multicore = (params->flags & _game_pref_multicore_flag) != 0;
 					SET_FLAG(params->flags, _game_pref_multicore_bit, use_multicore);
 #ifdef windows
 					set_cpu_affinity(use_multicore ? NONE : 1);
+					if(use_multicore != old_use_multicore)
+					{
+						// this will recreate the window in the appropriate thread
+						set_screen_parameters(NONE, NONE);
+					}
 #endif
 				}
 				write_game_preferences();
@@ -407,14 +413,11 @@
 					if(provider_id != prefs->provider_id)
 					{
 						prefs->provider_id = provider_id;
-						dispose_sound_manager_from_old_map(); // fade out sound, etc
-						initialize_sound_manager();
-						initialize_sound_manager_for_new_map();
+						reboot_sound_manager();
 						// since we reinitialized the sound manager, we have to restart the music
 						prefs= get_sound_preferences(); // initialize_sound_manager invalidates the old prefs pointer
 						if (!(prefs->flags&_sound_preferences_disable_menu_music_flag))
 							start_main_menu_music();
-						break;
 					}
 				}
 				break;
Index: Myth2Code/screen.c
===================================================================
--- Myth2Code/screen.c	(revision 5098)
+++ Myth2Code/screen.c	(working copy)
@@ -322,6 +322,17 @@
 	if(active_screen.device)
 	{
 		active_screen.bit_depth = get_ideal_mode_bitdepth(active_screen.device, active_screen.mode_index);
+
+		if(active_screen.rasterizer_code == _rasterizer_direct3d ||
+			active_screen.rasterizer_code == _rasterizer_3dfx)
+		{
+			// Old rasterizers don't work properly unless the HWND is in the same thread as the rendering.
+			set_window_multithread_mode(FALSE);
+		}
+		else
+		{
+			set_window_multithread_mode(TRUE);
+		}
 	}
 #endif
 
Index: Myth2Code/screen.h
===================================================================
--- Myth2Code/screen.h	(revision 5098)
+++ Myth2Code/screen.h	(working copy)
@@ -213,11 +213,6 @@
 
 boolean is_windowed_now(void);
 
-#ifdef windows
-	boolean is_fullscreen_windowed_now(void);
-	boolean is_true_fullscreen_now(void);
-#endif
-
 // should be in hardware.h? screen_xx.h? 
 struct bitmap_data *initialize_offscreen_bitmap(rectangle2d *bounds);
 void release_offscreen_bitmap(struct bitmap_data *bitmap);
Index: Myth2Code/screen_preferences.c
===================================================================
--- Myth2Code/screen_preferences.c	(revision 5098)
+++ Myth2Code/screen_preferences.c	(working copy)
@@ -423,7 +423,7 @@
 						break;
 #ifdef windows
 					case iGAMMA:
-						display_device_set_gamma(slider_value_to_gamma_value(get_slider_value(dialog, iGAMMA)));
+						display_device_set_gamma(TRUE, slider_value_to_gamma_value(get_slider_value(dialog, iGAMMA)));
 						break;
 #endif
 				}
@@ -448,14 +448,9 @@
 				load_screen_parameters(params);
 			}
 #ifdef windows
-			if(is_windowed_now())
-			{
-				display_device_restore_gamma();
-			}
-			else
-			{
-				display_device_set_gamma(active_screen.prefs->gamma);
-			}
+			display_device_set_gamma(
+				!is_windowed_now(), //enabled
+				active_screen.prefs->gamma);
 #endif
 			break;
 			
Index: Myth2Code/screen_setup.h
===================================================================
--- Myth2Code/screen_setup.h	(revision 5098)
+++ Myth2Code/screen_setup.h	(working copy)
@@ -73,8 +73,6 @@
 boolean find_device_and_mode(long rasterizer_id, const char *name, int width, int height, short *out_device_index, short *out_mode_index);
 
 #if defined(windows)
-void window_moved(int x, int y);
-boolean is_always_on_top_now(void);
 void toggle_always_on_top(boolean update_prefs);
 #endif
 
@@ -83,10 +81,16 @@
 #endif
 
 boolean display_device_supports_gamma(void);
-void display_device_set_gamma(short_fixed gamma);
-void display_device_restore_gamma(void);
-void display_device_query_and_report_modes(int rasterizer_code, const char * rasterizer_string, void * device_extra);
+void display_device_set_gamma(boolean enable, short_fixed gamma);
+void display_device_query_and_report_modes(int rasterizer_code, const char *rasterizer_string, void *device_extra);
 
+#ifdef windows
+void initialize_display_device(void);
+boolean display_device_set_mode(boolean fullscreen, int width, int height, int bit_depth);
+struct device_mode_info *display_device_supports_resolution(struct device_info *device, int width, int height);
+void display_device_get_modes(struct device_info * device);
+#endif
+
 #ifdef macintosh
 GDHandle get_game_device(void);
 void get_game_device_bounds(Rect *bounds);
Index: Myth2Code/screen_windows.c
===================================================================
--- Myth2Code/screen_windows.c	(revision 5098)
+++ Myth2Code/screen_windows.c	(working copy)
@@ -38,34 +38,51 @@
 
 // Build 362 - DRB - Fullscreen windowed mode.
 
+// Build 403 - DRB - Refactoring for multithreaded windowing. Most of this code lives in another thread now so be careful!
+
 #include "platform_cseries.h"
-#include "hack_versions.h"
-#define platform
 
 #include "shell.h"
 #include "screen.h"
-#include "shapes.h"
-#include "render.h"
 #include "screen_private.h"
+#include "screen_setup.h"
+#include "system_info.h"
 #include "bitmap_drawing.h"
-#include "bitmap_dialogs.h"
+#include "input_controller.h"
+#include "touch_controller.h"
+#include "windows_touch_api.h"
+#include "render.h"
+#include "utilities_d3d.h"
 #include "utilities_3dfx.h"
-#include "utilities_D3D.h"
-#include "utilities_opengl.h"
-#include "missing_strings.h"
-#include "screen_setup.h"
-#include "system_info.h"
-#include "binaries\resource.h"
-#include "error_manager.h"
-#include "screen_preferences.h"
 
-// -------- constants
+// -------- externs
 
+extern HINSTANCE application_instance;
+extern boolean windows_key_down;
+
+extern void input_keydown(int virtual_key, boolean repeat);
+extern void input_wheel_delta(int axis, int delta);
+extern boolean enum_display_settings(DEVMODE *dm, int mode_index);
+
 // -------- local globals
 
-static rectangle2d device_bounds;
 HWND screen_window = NULL; // can't be static, because this is our application window.....
+static HMENU system_menu = NULL;
 
+struct windows_screen_parameters
+{
+	boolean windowed;
+	boolean windowed_fullscreen;
+	boolean windowed_mode_capable_rasterizer;
+	int width;
+	int height;
+	int bit_depth;
+	short_fixed gamma;
+	short padding;
+};
+
+static struct windows_screen_parameters screen_params;
+
 // window position memorization
 static boolean lock_position_updates = FALSE;
 static boolean valid_last_windowed_pos_640x480 = FALSE;
@@ -76,70 +93,16 @@
 // always on top status
 static boolean always_on_top = FALSE;
 
-// gamma
-static WORD * startup_gamma = NULL;
-
 // windowed status
-boolean wants_windowed_now = FALSE;
+// TODO/FIXME: junk this variable, it shouldn't be needed.
+static boolean wants_windowed_now = FALSE;
 
-extern HINSTANCE application_instance;
-
 // -------- local prototypes
 
-static boolean display_device_set_fullscreen(boolean fullscreen, boolean pause_mode, boolean change_mode);
-static boolean display_device_set_mode(boolean fullscreen);
-void display_device_query_and_report_modes(int rasterizer_code, const char * rasterizer_string, void * device_extra);
+static void apply_screen_params(boolean fullscreen);
 
-static void create_screen_window(void);
-static void restore_world_device(void);
-static void destroy_and_unregister_window(void);
+// -------- local code
 
-static void clip_and_center_cursor(boolean clip, boolean center);
-
-static void pause_screen(void);
-static void unpause_screen(void);
-
-static void setup_screen_window(boolean fullscreen);
-
-boolean is_windowed_mode_capable_rasterizer(
-	int rasterizer_code)
-{
-	return rasterizer_code == _rasterizer_software ||
-	       rasterizer_code == _rasterizer_opengl ||
-	       rasterizer_code == _rasterizer_dx11;
-}
-
-static boolean enum_display_settings(DEVMODE *dm, int mode_index)
-{
-	boolean success;
-
-	ZeroMemory(dm, sizeof(DEVMODE));
-	dm->dmSize = sizeof(DEVMODE);
-
-	success = EnumDisplaySettings(NULL, mode_index, dm);
-
-	if(success && !(dm->dmPelsWidth && dm->dmPelsHeight))
-	{
-		success = FALSE;
-	}
-
-	if(!success && mode_index == ENUM_REGISTRY_SETTINGS)
-	{
-		// Fallback to GetSystemMetrics for getting the desktop size.
-		dm->dmPelsWidth = GetSystemMetrics(SM_CXSCREEN);
-		dm->dmPelsHeight = GetSystemMetrics(SM_CYSCREEN);
-		success = dm->dmPelsWidth && dm->dmPelsHeight;
-	}
-
-	if(!success)
-	{
-		ZeroMemory(dm, sizeof(DEVMODE));
-		dm->dmSize= sizeof(DEVMODE);
-	}
-
-	return success;
-}
-
 static void test_desktop_mode_vs_game_resolution(
 	boolean *match, boolean *game_higher)
 {
@@ -147,8 +110,8 @@
 
 	if(enum_display_settings(&dm, ENUM_REGISTRY_SETTINGS))
 	{
-		if(match)       *match       = active_screen.width == dm.dmPelsWidth && active_screen.height == dm.dmPelsHeight;
-		if(game_higher) *game_higher = active_screen.width >= dm.dmPelsWidth || active_screen.height >= dm.dmPelsHeight;
+		if(match)       *match       = screen_params.width == dm.dmPelsWidth && screen_params.height == dm.dmPelsHeight;
+		if(game_higher) *game_higher = screen_params.width >= dm.dmPelsWidth || screen_params.height >= dm.dmPelsHeight;
 	}
 	else
 	{
@@ -161,7 +124,7 @@
 	void)
 {
 	boolean forced = FALSE;
-	if(!is_windowed_mode_capable_rasterizer(active_screen.rasterizer_code))
+	if(!screen_params.windowed_mode_capable_rasterizer)
 	{
 		forced = TRUE;
 	}
@@ -177,28 +140,20 @@
 	return screen_window && ((GetWindowLongPtr(screen_window, GWL_STYLE) & WS_CAPTION) != 0);
 }
 
-boolean is_fullscreen_windowed_now(void)
+static boolean is_fullscreen_windowed_now(void)
 {
 	return screen_window && ((GetWindowLongPtr(screen_window, GWL_STYLE) & (WS_POPUP | WS_CAPTION)) == 0);
 }
 
-boolean is_true_fullscreen_now(void)
+static boolean is_true_fullscreen_now(void)
 {
 	return screen_window && ((GetWindowLongPtr(screen_window, GWL_STYLE) & (WS_POPUP | WS_CAPTION)) == WS_POPUP);
 }
 
-static boolean is_windowed_mode_desired(
-	void)
-{
-	return is_windowed_mode_capable_rasterizer(active_screen.rasterizer_code) &&
-		active_screen.prefs->flags & _screen_pref_windowed_flag;
-}
-
 static boolean is_fullscreen_windowed_mode_desired(
 	void)
 {
-	if(is_windowed_mode_capable_rasterizer(active_screen.rasterizer_code) &&
-		(active_screen.prefs->flags & _screen_pref_fullscreen_windowed_flag))
+	if(screen_params.windowed_fullscreen)
 	{
 		boolean match;
 		test_desktop_mode_vs_game_resolution(&match, NULL);
@@ -208,17 +163,10 @@
 	return FALSE;
 }
 
-static boolean is_true_fullscreen_mode_desired(
-	void)
-{
-	return !is_windowed_mode_capable_rasterizer(active_screen.rasterizer_code) ||
-		!(active_screen.prefs->flags & (_screen_pref_windowed_flag | _screen_pref_fullscreen_windowed_flag));
-}
-
 static boolean get_last_window_pos(
 	PPOINT *ppos, boolean **valid)
 {
-	if(active_screen.resolution_width == 640 && active_screen.resolution_height == 480)
+	if(screen_params.width == 640 && screen_params.height == 480)
 	{
 		if(ppos) *ppos = &last_windowed_pos_640x480;
 		if(valid) *valid = &valid_last_windowed_pos_640x480;
@@ -230,8 +178,8 @@
 		{
 			// construct a position for the larger resolution from our 640x480 position
 			// such that their centers are as close as possible
-			int expand_x = (active_screen.width - 640)/2;
-			int expand_y = (active_screen.height - 480)/2;
+			int expand_x = (screen_params.width - 640)/2;
+			int expand_y = (screen_params.height - 480)/2;
 			last_windowed_pos_other.x = last_windowed_pos_640x480.x - expand_x;
 			last_windowed_pos_other.y = last_windowed_pos_640x480.y - expand_y;
 			valid_last_windowed_pos_other = TRUE;
@@ -243,7 +191,7 @@
 	}
 }
 
-void window_moved(
+static void window_moved(
 	int x, int y)
 {
 	if(!lock_position_updates && is_windowed_now())
@@ -262,7 +210,7 @@
 	}
 }
 
-void set_always_on_top(
+static void set_always_on_top(
 	boolean on_top)
 {
 	boolean already_on_top = GetWindowLongPtr(screen_window, GWL_EXSTYLE) & WS_EX_TOPMOST;
@@ -272,15 +220,9 @@
 	}
 }
 
-boolean is_always_on_top_now(
+static void toggle_always_on_top_GUI(
 	void)
 {
-	return always_on_top;
-}
-
-void toggle_always_on_top(
-	boolean update_prefs)
-{
 	if(is_windowed_now())
 	{
 		always_on_top = !always_on_top;
@@ -288,8 +230,8 @@
 	}
 }
 
-void toggle_windowed_mode(
-	boolean update_prefs) // Build 280 - ALS
+static void toggle_windowed_mode_GUI(
+	void)
 {
 	boolean force_fullscreen = fullscreen_is_forced();
 	boolean windowed_now = is_windowed_now();
@@ -297,40 +239,53 @@
 	if(!force_fullscreen || windowed_now && force_fullscreen)
 	{
 		boolean go_fullscreen = windowed_now;
-		setup_screen_window(go_fullscreen);
+		apply_screen_params(go_fullscreen);
 	}
 }
 
-//----------------------------------------------------------------------------
-//
-//	DISPLAY DEVICE CODE
-//
-//----------------------------------------------------------------------------
+static void clip_and_center_cursor(boolean clip, boolean center)
+{
+	RECT rect;
 
-struct device_info generic_device;
+	GetWindowRect(screen_window, &rect);
 
-static void display_device_restore_registry_settings(
-	void)
-{
-	display_device_set_fullscreen(FALSE, TRUE, TRUE);
+	if(center)
+	{
+		SetCursorPos((rect.left+rect.right)/2, (rect.top+rect.bottom)/2);
+	}
+
+	ClipCursor(clip ? &rect : NULL);
 }
 
-static void display_device_setup_gamma(boolean fullscreen)
+static boolean setup_lowlevel_screen_mode(
+	boolean fullscreen)
 {
-	if(fullscreen)
+	if(screen_params.windowed_mode_capable_rasterizer)
 	{
-		display_device_set_gamma(active_screen.prefs->gamma);
+		// Check for Pseudo-fullscreen AKA fullscreen windowed mode.
+		if(fullscreen && is_fullscreen_windowed_mode_desired())
+		{
+			boolean pseudo_fullscreen = FALSE;
+			test_desktop_mode_vs_game_resolution(&pseudo_fullscreen, NULL);
+			if(pseudo_fullscreen)
+			{
+				fullscreen = FALSE;
+			}
+		}
+
+		return display_device_set_mode(fullscreen, screen_params.width, screen_params.height, screen_params.bit_depth);
 	}
 	else
 	{
-		display_device_restore_gamma();
+		// Non windowed mode capable rasterizers handle their own mode switching, so nothing to do here.
+		return TRUE;
 	}
 }
 
-static boolean display_device_set_fullscreen(
+static boolean setup_highlevel_screen_mode(
 	boolean fullscreen, boolean pause_mode, boolean change_mode)
 {
-	if(!change_mode || display_device_set_mode(fullscreen))
+	if(!change_mode || setup_lowlevel_screen_mode(fullscreen))
 	{
 		boolean clip_cursor, center_cursor, enable_gamma, on_top;
 		boolean windowed_now = is_windowed_now();
@@ -352,7 +307,7 @@
 		}
 
 		clip_and_center_cursor(clip_cursor, center_cursor);
-		display_device_setup_gamma(enable_gamma);
+		display_device_set_gamma(enable_gamma, screen_params.gamma);
 		set_always_on_top(on_top);
 
 		return TRUE;
@@ -361,449 +316,13 @@
 	return FALSE;
 }
 
-static boolean display_device_set_mode(
+static void apply_screen_params(
 	boolean fullscreen)
 {
-	static int last_fullscreen= FALSE, last_width, last_height, last_bitdepth, last_rasterizer;
+	//static int depth = 0;
+	//log_message(NULL, NONE, "enter apply_screen_params(depth=%d)",depth++);
+	//if(depth>1)__asm int 3;
 
-	boolean success= TRUE;
-
-	boolean mode_changed=
-		fullscreen != last_fullscreen ||
-		last_width != active_screen.width ||
-		last_height != active_screen.height ||
-		last_bitdepth != active_screen.bit_depth ||
-		last_rasterizer != active_screen.rasterizer_code ||
-		!is_windowed_mode_capable_rasterizer(last_rasterizer);
-
-	if(mode_changed)
-	{
-		boolean pseudo_fullscreen = FALSE;
-		LONG result;
-
-		// If the desktop settings match the settings we need, enable Pseudo-fullscreen.
-		if(is_windowed_mode_capable_rasterizer(active_screen.rasterizer_code) && fullscreen
-			// don't use pseudo fullscreen on vista or higher unless fullscreen windowed mode is enabled.
-			&& (!windows_vista_or_higher() || is_fullscreen_windowed_mode_desired()))
-		{
-			test_desktop_mode_vs_game_resolution(&pseudo_fullscreen, NULL);
-		}
-
-		if(fullscreen && !pseudo_fullscreen)
-		{
-			if(active_screen.rasterizer_code == _rasterizer_direct3d ||
-				active_screen.rasterizer_code == _rasterizer_3dfx)
-			{
-				// These rasterizers do their own mode change, so nothing to do here.
-				result= DISP_CHANGE_SUCCESSFUL;
-			}
-			else
-			{
-				DEVMODE dm;
-				ZeroMemory(&dm, sizeof(dm));
-				dm.dmSize= sizeof(dm);
-				dm.dmBitsPerPel= active_screen.bit_depth;
-				dm.dmPelsWidth= active_screen.width;
-				dm.dmPelsHeight= active_screen.height;
-				dm.dmFields= DM_PELSHEIGHT|DM_PELSWIDTH|DM_BITSPERPEL;
-				result= ChangeDisplaySettings(&dm, CDS_FULLSCREEN|CDS_RESET);
-			}
-		}
-		else
-		{
-			// Reset to the desktop mode.
-
-			// We used to just call ChangeDisplaySettings(NULL, 0) here, but the latest NVidia drivers apparently no longer ignores
-			// this call when it's redundant. (i.e. it does a hard mode reset on every call - screen goes black for a second.)
-			// To avoid this, explicitly check that we aren't already on the desktop mode.
-
-			boolean mode_change= TRUE;
-
-			DEVMODE dm_current, dm_registry;
-			if(enum_display_settings(&dm_current, ENUM_CURRENT_SETTINGS) &&
-				enum_display_settings(&dm_registry, ENUM_REGISTRY_SETTINGS))
-			{
-				// Just check the fields we care about - don't use memcmp() because
-				// there seems to be some other junk in the struct that doesn't match
-				// even though the modes are the same.
-				if(dm_current.dmBitsPerPel == dm_registry.dmBitsPerPel &&
-					dm_current.dmPelsWidth == dm_registry.dmPelsWidth &&
-					dm_current.dmPelsHeight == dm_registry.dmPelsHeight)
-				{
-					mode_change= FALSE;
-				}
-			}
-
-			if(mode_change)
-			{
-				result= ChangeDisplaySettings(NULL, 0);
-			}
-			else
-			{
-				result= DISP_CHANGE_SUCCESSFUL;
-			}
-		}
-
-		success= (result == DISP_CHANGE_SUCCESSFUL);
-
-		if(!success)
-		{
-			log_message(NULL, NONE, "Warning: ChangeDisplaySettings() failed! Result code = %d. Details = (mode=%dx%d, fullscreen=%d)",
-				result, active_screen.width, active_screen.height, fullscreen);
-		}
-	}
-
-	last_fullscreen= fullscreen;
-	last_width= active_screen.width;
-	last_height= active_screen.height;
-	last_bitdepth= active_screen.bit_depth;
-	last_rasterizer= active_screen.rasterizer_code;
-
-	return success;
-}
-
-void display_device_restore_gamma(
-	void)
-{
-	if(startup_gamma)
-	{
-		HDC hdc= GetDC(screen_window);
-
-		if(hdc)
-		{
-			SetDeviceGammaRamp(hdc, startup_gamma);
-			ReleaseDC(screen_window, hdc);
-		}
-	}
-}
-
-boolean display_device_supports_gamma(
-	void)
-{
-	static boolean support_tested= FALSE;
-	static boolean support_found= FALSE;
-
-	if(!support_tested)
-	{
-		HDC hdc= GetDC(screen_window);
-
-		if(hdc)
-		{
-			startup_gamma= malloc(768*sizeof(WORD));
-			support_found= GetDeviceGammaRamp(hdc, startup_gamma);
-			ReleaseDC(screen_window, hdc);
-		}
-
-		support_tested= TRUE;
-	}
-
-	return support_found;
-}
-
-void display_device_set_gamma(
-	short_fixed gamma)
-{
-	HDC hdc;
-
-	if(!display_device_supports_gamma())
-	{
-		return;
-	}
-
-	hdc= GetDC(screen_window);
-
-	if(hdc)
-	{
-		int i;
-		WORD new_gamma_ramp[3][256];
-
-		for(i= 0; i < 256; ++i)
-		{
-			int level= MIN(i*gamma, UNSIGNED_SHORT_MAX);
-
-			new_gamma_ramp[0][i]= level;
-			new_gamma_ramp[1][i]= level;
-			new_gamma_ramp[2][i]= level;
-		}
-
-		SetDeviceGammaRamp(hdc, new_gamma_ramp);
-		ReleaseDC(screen_window, hdc);
-	}
-}
-
-struct device_mode_info * display_device_supports_resolution(
-	struct device_info * device,
-	int width,
-	int height)
-{
-	int i;
-
-	for(i = 0; i < device->mode_count; ++i)
-	{
-		if(device->modes[i].width == width &&
-			device->modes[i].height == height)
-		{
-			return device->modes+i;
-		}
-	}
-
-	return FALSE;
-}
-
-void display_device_get_modes(
-	struct device_info * device)
-{
-	int mode_index= 0;
-	DEVMODE devmode;
-
-	while(device->mode_count < MAXIMUM_DISPLAY_MODE_COUNT &&
-		enum_display_settings(&devmode, mode_index))
-	{
-		//if(ChangeDisplaySettings(&devmode, CDS_TEST) == DISP_CHANGE_SUCCESSFUL)
-		{
-			// Only use surfaces that match what we want.
-			if(devmode.dmBitsPerPel >= 16 && is_valid_resolution(devmode.dmPelsWidth, devmode.dmPelsHeight))
-			{
-				// Only add modes that we don't already have
-				if(!display_device_supports_resolution(device, devmode.dmPelsWidth, devmode.dmPelsHeight))
-				{
-					struct device_mode_info *mode= &device->modes[device->mode_count];
-
-					mode->width= devmode.dmPelsWidth;
-					mode->height= devmode.dmPelsHeight;
-#ifdef __RENDER_32_BIT__
-					mode->bit_depth= 32;
-#else
-					mode->bit_depth= 16;
-#endif
-					//don't set the refresh rate,
-					//this will be inherited from the user's desktop settings
-					mode->refresh_rate= 0;//devmode.dmDisplayFrequency;
-					mode->flags= 0;
-
-					// increment the number of display modes
-					++device->mode_count;
-				}
-			}
-		}
-		++mode_index;
-	}
-}
-
-void display_device_query_and_report_modes(
-	int rasterizer_code,
-	const char * rasterizer_string,
-	void * device_extra)
-{
-	if(generic_device.mode_count > 0)
-	{
-		struct device_info device;
-		memcpy(&device, &generic_device, sizeof(device));
-		strncpy(device.name, rasterizer_string, sizeof(device.name));
-		device.rasterizer_code= rasterizer_code;
-		device.extra_data= device_extra;
-		report_device(&device);
-	}
-}
-
-// ----------- code
-
-void initialize_drawing_manager(
-	void)
-{
-	create_screen_window();
-
-	memset(&generic_device, 0, sizeof(generic_device));
-	display_device_get_modes(&generic_device);
-
-	query_for_screen_devices();
-
-	if (screen_window)
-	{
-		// show messageboxes on 3dfx, etc.
-		set_pre_and_post_messagebox_functions(pause_screen, unpause_screen);
-
-		atexit(restore_world_device);
-	}
-	
-	return;
-}
-
-//----------------------------------------------------------------------------
-//
-//	SOFTWARE BLITTING(GDI) CODE
-//
-//----------------------------------------------------------------------------
-
-void * screen_pixels= NULL;
-HBITMAP memory_bitmap= NULL;
-HDC window_dc= NULL;
-HDC memory_dc= NULL;
-
-short allocate_drawing_buffers(
-	short device_index,
-	short mode_index)
-{
-	// not strictly necessary afaik but let's be defensive here and make sure we don't leak
-	dispose_drawing_buffers();
-
-	set_active_screen(device_index, mode_index);
-
-	setup_screen_window(is_true_fullscreen_mode_desired());
-
-	if(active_screen.rasterizer_code == _rasterizer_software)
-	{
-		byte buffer[sizeof(BITMAPINFOHEADER)+3*sizeof(DWORD)];
-		BITMAPINFOHEADER* bmih = (BITMAPINFOHEADER*)buffer;
-
-		memset(buffer, 0, sizeof(buffer));
-		bmih->biSize= sizeof(BITMAPINFOHEADER);
-		bmih->biWidth= active_screen.width;
-		bmih->biHeight= -active_screen.height;
-		bmih->biBitCount= active_screen.bit_depth;
-		bmih->biPlanes= 1;
-
-		if(active_screen.bit_depth == 16)
-		{
-			DWORD* mask = (DWORD*)(bmih+1);
-			bmih->biCompression = BI_BITFIELDS;
-
-			if(active_screen.encoding == _16bit_565_encoding)
-			{
-				mask[0] = 0xf800;
-				mask[1] = 0x07e0;
-				mask[2] = 0x001f;
-			}
-			else // _16bit_555_encoding
-			{
-				mask[0] = 0x7c00;
-				mask[1] = 0x03e0;
-				mask[2] = 0x001f;
-			}
-		}
-
-		window_dc= GetDC(screen_window);
-		memory_dc= CreateCompatibleDC(window_dc);
-		memory_bitmap= CreateDIBSection(memory_dc,
-			(BITMAPINFO*)bmih, DIB_RGB_COLORS,
-			(void**)&screen_pixels, 0, 0);
-		SelectObject(memory_dc, memory_bitmap);
-	}
-
-	return 0; // 0 means success
-}
-
-void dispose_drawing_buffers(
-	void)
-{
-	if(window_dc)
-	{
-		ReleaseDC(screen_window, window_dc);
-		window_dc= NULL;
-	}
-
-	if(memory_dc)
-	{
-		DeleteDC(memory_dc);
-		memory_dc= NULL;
-	}
-
-	if(memory_bitmap)
-	{
-		DeleteObject(memory_bitmap);
-		memory_bitmap= NULL;
-	}
-}
-
-struct bitmap_data *initialize_offscreen_bitmap(
-	rectangle2d *bounds)
-{
-	return initialize_offscreen_bitmap_with_data(bounds, screen_pixels, NONE);
-}
-
-// this is called when all drawing for the current frame is complete
-// thus this is the time when we flip pages
-void release_offscreen_bitmap(
-	struct bitmap_data *bitmap)
-{
-	UNUSED_PARAMETER(bitmap);
-}
-
-void copy_offscreen_world_to_screen(
-	rectangle2d *source_bounds,
-	rectangle2d *destination_bounds)
-{
-	// blit the bitmap from memory to the window
-	if(memory_bitmap)
-	{
-		BitBlt(window_dc, source_bounds->left, source_bounds->top,
-			source_bounds->right-source_bounds->left,
-			source_bounds->bottom-source_bounds->top,
-			memory_dc, destination_bounds->left, destination_bounds->top,
-			SRCCOPY);
-	}
-}
-
-/* -------- miscellaneous */
-
-void calculate_mouse_movement_frame(
-	rectangle2d *mouse_bounds)
-{
-	switch (active_screen.rasterizer_code)
-	{
-		case _rasterizer_software:
-			get_active_screen_bounds(mouse_bounds);
-			break;
-		
-		default:
-			get_game_screen_bounds(mouse_bounds);
-			break;
-	}
-	
-	return;
-}
-
-void get_true_screen_dimensions(
-	short *width,
-	short *height)
-{
-	RECT rect;
-	GetClientRect(screen_window, &rect);
-
-	*width= rect.right;
-	*height= rect.bottom;
-
-	return;
-}
-
-// ----------- local code
- 
-static void restore_world_device(
-	void)
-{
-	display_device_restore_registry_settings();
-	dispose_drawing_buffers();
-	destroy_and_unregister_window();
-
-	if(startup_gamma)
-	{
-		free(startup_gamma);
-		startup_gamma= NULL;
-	}
-}
-
-static void destroy_and_unregister_window(
-	void)
-{
-	DestroyWindow(screen_window);
-	screen_window= NULL;
-
-	UnregisterClass(MAIN_WINDOW_CLASS, application_instance);
-}
-
-static void setup_screen_window(
-	boolean fullscreen)
-{
 	// save what was last requested, even if we can't honour it.
 	wants_windowed_now = !fullscreen;
 
@@ -814,10 +333,10 @@
 	}
 
 	// Setup the new mode.
-	if(fullscreen && !display_device_supports_resolution(&generic_device, active_screen.width, active_screen.height) ||
-		!display_device_set_fullscreen(fullscreen, FALSE, TRUE))
+	if(fullscreen && !display_device_supports_resolution(NULL, screen_params.width, screen_params.height) ||
+		!setup_highlevel_screen_mode(fullscreen, FALSE, TRUE))
 	{
-		log_message(NULL, NONE, "Warning: Could not setup fullscreen %dx%d, falling back to windowed mode.", active_screen.width, active_screen.height);
+		log_message(NULL, NONE, "Warning: Could not setup fullscreen %dx%d, falling back to windowed mode.", screen_params.width, screen_params.height);
 		fullscreen= FALSE;
 		wants_windowed_now= TRUE;
 	}
@@ -827,7 +346,7 @@
 		const DWORD fullscreen_style = WS_POPUP;
 		const DWORD windowed_style = WS_POPUPWINDOW | WS_CAPTION | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
 		DWORD style = basic_style | (fullscreen ? fullscreen_style : windowed_style);
-		RECT rect = {0, 0, active_screen.width, active_screen.height};
+		RECT rect = {0, 0, screen_params.width, screen_params.height};
 		int x = 0, y = 0;
 		int width, height;
 
@@ -911,27 +430,78 @@
 
 		clip_and_center_cursor(fullscreen, TRUE);
 	}
+
+	//log_message(NULL, NONE, "leave apply_screen_params(depth=%d)",--depth);
 }
 
-static void create_screen_window(
-	void)
+static LRESULT decode_touch(
+	HWND hWnd,
+	UINT uMsg,
+	WPARAM wParam,
+	LPARAM lParam)
 {
-	assert(!screen_window);
+	TOUCHINPUT all_touch_events[16];
+	const unsigned int max_events = sizeof(all_touch_events) / sizeof(TOUCHINPUT);
 
-	screen_window= CreateWindowEx(WS_EX_APPWINDOW, MAIN_WINDOW_CLASS, MAIN_WINDOW_TITLE,
-		WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE | WS_POPUPWINDOW,
-		0, 0, 0, 0, NULL, NULL, application_instance, NULL);
+	unsigned int num_touch_events = MIN(LOWORD(wParam), max_events);
+	
+	if (GetTouchInputInfo((HTOUCHINPUT)lParam, num_touch_events, all_touch_events, sizeof(TOUCHINPUT)))
+	{
+		unsigned int e;
+		for (e = 0; e < num_touch_events; ++e)
+		{
+			DWORD ID = all_touch_events[e].dwID;
+			DWORD flags = all_touch_events[e].dwFlags;
+
+			// Convert to pixel coordinates (maintain fractional portion for accuracy)
+			// TODO: Scaling this in terms of pixels seems a bit odd (especially with resolution changes)...
+			// Should we try to recover device metrics so that we can roughly convert to to real-world units?
+			// Hard to say how this should ideally work.
+			// TODO: If the absolute positions are used at all, we need to use ScreenToClient to normalize
+			// it to where our window is. But doing this we seem to lose the fractional precision, so that
+			// may not be ideal either.
+			float pixelX = (float)all_touch_events[e].x / 100.0f;
+			float pixelY = (float)all_touch_events[e].y / 100.0f;
+			//ScreenToClient(hWnd, &ptInput);
+
+			if (flags & TOUCHEVENTF_DOWN)
+				input_touch_point_down(ID, pixelX, pixelY);
+			if (flags & TOUCHEVENTF_MOVE)
+				input_touch_point_move(ID, pixelX, pixelY);
+			if (flags & TOUCHEVENTF_UP)
+				input_touch_point_up(ID, pixelX, pixelY);
+		}
+
+		// Message handled
+		CloseTouchInputHandle((HTOUCHINPUT)lParam);
+		return 0;
+	}
+
+	// Default handler
+	return DefWindowProc(hWnd, uMsg, wParam, lParam);
 }
 
-void pause_screen_data(
-	boolean paused)
+static void pause_old_rasterizers(
+	boolean pause)
 {
-	// Because we can get the unpause message before screen_window is set...
-	if (!screen_window)
+	if (active_screen.screen_initialized &&
+		active_screen.rasterizer_initialized)
 	{
-		return;
+		switch(active_screen.rasterizer_code)
+		{
+			case _rasterizer_direct3d:
+				pause_D3D_window(pause);
+				break;
+			case _rasterizer_3dfx:
+				pause_glide_window(pause);
+				break;
+		}
 	}
+}
 
+static void pause_screen_data(
+	boolean paused)
+{
 	if(is_true_fullscreen_now())
 	{
 		ShowWindow(screen_window, paused ? SW_MINIMIZE : SW_RESTORE);
@@ -950,74 +520,354 @@
 		}
 	}
 
-	if (active_screen.screen_initialized)
 	{
-		boolean change_mode = is_windowed_mode_capable_rasterizer(active_screen.rasterizer_code);
+		boolean change_mode = screen_params.windowed_mode_capable_rasterizer;
 
 		if (paused)
 		{
-			pause_screen();
-			display_device_set_fullscreen(FALSE, TRUE, change_mode);
+			pause_old_rasterizers(TRUE);
+			setup_highlevel_screen_mode(FALSE, TRUE, change_mode);
 		}
 		else
 		{
 			boolean fullscreen = !wants_windowed_now || fullscreen_is_forced();
-			display_device_set_fullscreen(fullscreen, FALSE, change_mode);
-			unpause_screen();
+			setup_highlevel_screen_mode(fullscreen, FALSE, change_mode);
+			pause_old_rasterizers(FALSE);
 		}
 	}
 
 	return;
 }
 
-static void clip_and_center_cursor(boolean clip, boolean center)
+static void set_gui_pause_state(
+	boolean paused, const char *reason)
 {
-	RECT rect;
+	int pause_flags = 0;
 
-	GetWindowRect(screen_window, &rect);
+	if(!paused && !IsIconic(screen_window))
+	{
+		pause_flags |= _myth_is_active_flag;
+	}
 
-	if(center)
+	if((!paused || !is_true_fullscreen_now()) && !IsIconic(screen_window))
 	{
-		SetCursorPos((rect.left+rect.right)/2, (rect.top+rect.bottom)/2);
+		pause_flags |= _myth_is_visible_flag;
 	}
 
-	ClipCursor(clip ? &rect : NULL);
+	// update for new activation state
+
+	if(paused)
+	{
+		restore_windows_lock_function();
+	}
+	else
+	{
+		disable_windows_lock_function();
+	}
+
+	boost_timer_resolution(!paused);
+
+	pause_screen_data(paused);
+
+	PostMythMessage(MYTHMSG_PAUSE, &pause_flags, sizeof(pause_flags));
+
+	//log_message(NULL, NONE, "set_gui_pause_state(%s, %s)", paused ? "TRUE" : "FALSE", reason);
+
+	return;
 }
 
-static void pause_screen(
-	void)
+static LRESULT CALLBACK MainWndProc(
+	HWND hWnd,        // handle to window
+	UINT uMsg,        // message identifier
+	WPARAM wParam,    // first message parameter
+	LPARAM lParam)    // second message parameter
 {
-	if (active_screen.screen_initialized &&
-		active_screen.rasterizer_initialized)
+	enum {
+		CMD_ON_TOP = 1337,
+		CMD_TOGGLE_FS,
+	};
+
+	switch(uMsg)
 	{
-		switch(active_screen.rasterizer_code)
+	case WM_CREATE:
 		{
-			case _rasterizer_direct3d:
-				pause_D3D_window(TRUE);
-				break;
-			case _rasterizer_3dfx:
-				pause_glide_window(TRUE);
-				break;
+			system_menu = GetSystemMenu(hWnd, FALSE);
+			InsertMenu(system_menu, 0, 0, CMD_TOGGLE_FS, "Fullscreen\tAlt+F11");
+			InsertMenu(system_menu, 0, 0, CMD_ON_TOP, "On Top\tAlt+F10");
+
+			// Build 402 - ATL - Register the window for touch instead of gestures
+			// ATL TODO: Experiment with WANTPALM and FINETOUCH flags
+
+			if(initialize_windows_touch_api())
+			{
+				RegisterTouchWindow(hWnd, TWF_WANTPALM);
+			}
 		}
+		return 0;
+	case WM_INITMENUPOPUP:
+		{
+			HMENU menu = (HMENU)wParam;
+			if(menu == system_menu)
+			{
+				CheckMenuItem(menu, CMD_ON_TOP, MF_BYCOMMAND | (always_on_top ? MF_CHECKED : 0)); 
+				CheckMenuItem(menu, CMD_TOGGLE_FS, MF_BYCOMMAND | (!is_windowed_now() ? MF_CHECKED : 0));
+				return 0;
+			}
+		}
+		break;
+	case WM_SYSCOMMAND:
+		{
+			switch(wParam)
+			{
+			case CMD_ON_TOP:
+				toggle_always_on_top_GUI();
+				return 0;
+			case SC_MAXIMIZE:
+			case CMD_TOGGLE_FS:
+				toggle_windowed_mode_GUI();
+				return 0;
+			}
+		}
+		break;
+	case WM_SYSCHAR:
+		return 0;
+	case WM_MOUSEACTIVATE:
+		return LOWORD(lParam) == HTCLIENT ? MA_ACTIVATEANDEAT : MA_ACTIVATE;
+	case WM_MOUSEWHEEL:
+		input_wheel_delta(_mouse_wheel_axis_y, GET_WHEEL_DELTA_WPARAM(wParam));
+		return 0;
+	case WM_SYSKEYDOWN:
+	case WM_KEYDOWN:
+		{
+			boolean repeat = (lParam & (1<<30)) != 0;
+			input_keydown(wParam, repeat);
+		}
+		if(wParam == VK_LWIN || wParam == VK_RWIN)
+		{
+			windows_key_down = TRUE;
+		}
+		return 0;
+	case WM_SYSKEYUP:
+	case WM_KEYUP:
+		if(wParam == VK_LWIN || wParam == VK_RWIN)
+		{
+			windows_key_down = FALSE;
+		}
+		return 0;
+	case WM_TOUCH:
+		return decode_touch(hWnd, uMsg, wParam, lParam);
+	case WM_TABLET_QUERYSYSTEMGESTURESTATUS:
+		// Disable "press and hold" right click gesture and some of the sillier UI
+		return TABLET_DISABLE_PRESSANDHOLD |
+			TABLET_DISABLE_PENTAPFEEDBACK |
+			TABLET_DISABLE_PENBARRELFEEDBACK |
+			TABLET_DISABLE_FLICKS;
+	case WM_CLOSE:
+		if(IsIconic(screen_window))
+		{
+			// the window is minimized, so close immediately
+			exit(0);
+		}
+		else
+		{
+			// treat this as if the user pressed escape
+			input_keydown(VK_ESCAPE, FALSE);
+		}
+		return 0;
+	case WM_PAINT:
+		{
+			RECT rect;
+			if(GetUpdateRect(hWnd, &rect, FALSE))
+			{
+				rectangle2d bounds;
+				set_rectangle2d(&bounds, rect.left, rect.top, rect.right, rect.bottom);
+				PostMythMessage(MYTHMSG_PAINT, &bounds, sizeof(bounds));
+			}
+			// no return value; fallthrough to the default behavior (which validates the region)
+		}
+		break;
+	case WM_SIZE:
+		switch(wParam)
+		{
+		case SIZE_MAXIMIZED:
+			// We shouldn't be getting this message now that we handle SC_MAXIMIZE
+			assert(FALSE);
+			break;
+		case SIZE_MINIMIZED:
+			set_gui_pause_state(TRUE, "SIZE_MINIMIZED");
+			break;
+		case SIZE_RESTORED:
+			set_gui_pause_state(FALSE, "SIZE_RESTORED");
+			break;
+		}
+		return 0;
+	case WM_MOVE:
+		window_moved(LOWORD(lParam), HIWORD(lParam));
+		return 0;
+	case WM_ACTIVATEAPP:
+		set_gui_pause_state(wParam == FALSE || IsIconic(screen_window), "WM_ACTIVATEAPP");
+		return 0;
+	case WM_ERASEBKGND:
+		return TRUE;
+	case WM_INPUTLANGCHANGE:
+		set_windows_keyboard_layout();
+		break;
+	case WM_ALTTAB:
+		set_gui_pause_state(TRUE, "alt-tab handler");
+		return 0;
+	case WM_TOGGLEFULLSCREEN:
+		toggle_windowed_mode_GUI();
+		break;
+	case WM_TOGGLEONTOP:
+		toggle_always_on_top_GUI();
+		break;
+	case WM_SETUP_SCREEN:
+		if(lParam)
+		{
+			screen_params = *(struct windows_screen_parameters*)lParam;
+		}
+		apply_screen_params(!screen_params.windowed);
+		return 0;
+	case WM_DESTROYSELF:
+		DestroyWindow(hWnd);
+		return 0;
 	}
+
+	return DefWindowProc(hWnd, uMsg, wParam, lParam);
 }
 
-static void unpause_screen(
+static void register_window_class(
 	void)
 {
-	if (active_screen.screen_initialized &&
-		active_screen.rasterizer_initialized)
+	WNDCLASS wndclass;
+	memset(&wndclass, 0, sizeof(wndclass));
+	wndclass.lpszClassName= MAIN_WINDOW_CLASS;
+	wndclass.hInstance= application_instance;
+	wndclass.lpfnWndProc= MainWndProc;
+	wndclass.hCursor= LoadCursor(NULL, IDC_ARROW);
+	wndclass.hIcon= LoadIcon(application_instance, MAKEINTRESOURCE(128));
+	wndclass.lpszMenuName= NULL;
+	wndclass.hbrBackground= (HBRUSH)GetStockObject(BLACK_BRUSH);
+	wndclass.style= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
+	wndclass.cbClsExtra= 0;
+	wndclass.cbWndExtra= 0;
+
+	RegisterClass(&wndclass);
+}
+
+void create_window(
+	void)
+{
+	if(!screen_window)
 	{
-		switch(active_screen.rasterizer_code)
-		{
-			case _rasterizer_direct3d:
-				pause_D3D_window(FALSE);
-				break;
-			case _rasterizer_3dfx:
-				pause_glide_window(FALSE);
-				break;
-		}
+		register_window_class();
+		screen_window= CreateWindowEx(WS_EX_APPWINDOW, MAIN_WINDOW_CLASS, MAIN_WINDOW_TITLE,
+			WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE | WS_POPUPWINDOW,
+			0, 0, 0, 0, NULL, NULL, application_instance, NULL);
 	}
-	
+}
+
+void destroy_window(
+	void)
+{
+	if(screen_window)
+	{
+		SendMessage(screen_window, WM_DESTROYSELF, 0, 0);
+		screen_window= NULL;
+	}
+}
+
+static void restore_world_device(
+	void)
+{
+	setup_highlevel_screen_mode(FALSE, TRUE, TRUE);
+
+	dispose_drawing_buffers();
+
+	destroy_window();
+
+	UnregisterClass(MAIN_WINDOW_CLASS, application_instance);
+
+	restore_windows_lock_function();
+}
+
+// ----------- exports
+
+void initialize_drawing_manager(
+	void)
+{
+	register_window_class();
+	initialize_display_device();
+	query_for_screen_devices();
+	atexit(restore_world_device);
+
 	return;
 }
+
+void calculate_mouse_movement_frame(
+	rectangle2d *mouse_bounds)
+{
+	get_game_screen_bounds(mouse_bounds);
+
+	return;
+}
+
+void get_true_screen_dimensions(
+	short *width,
+	short *height)
+{
+	RECT rect;
+	GetClientRect(screen_window, &rect);
+
+	*width= rect.right;
+	*height= rect.bottom;
+
+	return;
+}
+
+void toggle_always_on_top(
+	boolean update_prefs)
+{
+	PostMessage(screen_window, WM_TOGGLEONTOP, 0, 0);
+}
+
+void toggle_windowed_mode(
+	boolean update_prefs)
+{
+	PostMessage(screen_window, WM_TOGGLEFULLSCREEN, 0, 0);
+}
+ 
+void setup_screen(
+	boolean windowed,
+	boolean windowed_fullscreen,
+	boolean windowed_mode_capable_rasterizer,
+	int width,
+	int height,
+	int bit_depth,
+	int gamma)
+{
+	struct windows_screen_parameters params;
+
+	// sanitize params
+	if(!windowed_mode_capable_rasterizer)
+	{
+		windowed = windowed_fullscreen = FALSE;
+	}
+	else if(!windowed)
+	{
+		windowed_fullscreen = FALSE;
+	}
+
+	// build the struct
+	params.windowed = windowed;
+	params.windowed_fullscreen = windowed_fullscreen;
+	params.windowed_mode_capable_rasterizer = windowed_mode_capable_rasterizer;
+	params.width = width;
+	params.height = height;
+	params.bit_depth = bit_depth;
+	params.gamma = gamma;
+
+	// Pass it to the GUI thread. (NOTE: this is a blocking call)
+	SendMessage(screen_window, WM_SETUP_SCREEN, 0, (LPARAM)&params);
+}
+
Index: Myth2Code/setup_software_windows.c
===================================================================
--- Myth2Code/setup_software_windows.c	(revision 5098)
+++ Myth2Code/setup_software_windows.c	(working copy)
@@ -4,10 +4,14 @@
 Build 263 - Melekor:
 -removed ddraw
 -converted to use the new device enumeration stuff
+
+Build 403 - DRB - moved software blitting code here from screen_windows.c
+
 */
 
 #include "platform_cseries.h"
 #include "render.h"
+#include "screen.h"
 #include "screen_setup.h"
 
 //------------- code
@@ -17,3 +21,139 @@
 {
 	display_device_query_and_report_modes(_rasterizer_software, "Software", NULL);
 }
+
+boolean is_windowed_mode_capable_rasterizer(
+	int rasterizer_code)
+{
+	return rasterizer_code == _rasterizer_software ||
+	       rasterizer_code == _rasterizer_opengl ||
+	       rasterizer_code == _rasterizer_dx11;
+}
+
+//----------------------------------------------------------------------------
+//
+//	SOFTWARE BLITTING(GDI) CODE
+//
+//----------------------------------------------------------------------------
+
+void dispose_drawing_buffers(void);
+
+extern HWND screen_window;
+
+void * screen_pixels= NULL;
+HBITMAP memory_bitmap= NULL;
+HDC window_dc= NULL;
+HDC memory_dc= NULL;
+
+void setup_screen(
+	boolean windowed, boolean windowed_fullscreen,
+	boolean windowed_mode_capable_rasterizer,
+	int width, int height, int bit_depth, int gamma);
+
+short allocate_drawing_buffers(
+	short device_index,
+	short mode_index)
+{
+	dispose_drawing_buffers();
+
+	setup_screen(
+		active_screen.prefs->flags & _screen_pref_windowed_flag,
+		active_screen.prefs->flags & _screen_pref_fullscreen_windowed_flag,
+		is_windowed_mode_capable_rasterizer(active_screen.rasterizer_code),
+		active_screen.width,
+		active_screen.height,
+		active_screen.bit_depth,
+		active_screen.prefs->gamma);
+
+	if(active_screen.rasterizer_code == _rasterizer_software)
+	{
+		byte buffer[sizeof(BITMAPINFOHEADER)+3*sizeof(DWORD)];
+		BITMAPINFOHEADER* bmih = (BITMAPINFOHEADER*)buffer;
+
+		memset(buffer, 0, sizeof(buffer));
+		bmih->biSize= sizeof(BITMAPINFOHEADER);
+		bmih->biWidth= active_screen.width;
+		bmih->biHeight= -active_screen.height;
+		bmih->biBitCount= active_screen.bit_depth;
+		bmih->biPlanes= 1;
+
+		if(active_screen.bit_depth == 16)
+		{
+			DWORD* mask = (DWORD*)(bmih+1);
+			bmih->biCompression = BI_BITFIELDS;
+
+			if(active_screen.encoding == _16bit_565_encoding)
+			{
+				mask[0] = 0xf800;
+				mask[1] = 0x07e0;
+				mask[2] = 0x001f;
+			}
+			else // _16bit_555_encoding
+			{
+				mask[0] = 0x7c00;
+				mask[1] = 0x03e0;
+				mask[2] = 0x001f;
+			}
+		}
+
+		window_dc= GetDC(screen_window);
+		memory_dc= CreateCompatibleDC(window_dc);
+		memory_bitmap= CreateDIBSection(memory_dc,
+			(BITMAPINFO*)bmih, DIB_RGB_COLORS,
+			(void**)&screen_pixels, 0, 0);
+		SelectObject(memory_dc, memory_bitmap);
+	}
+
+	return 0; // 0 means success
+}
+
+void dispose_drawing_buffers(
+	void)
+{
+	if(window_dc)
+	{
+		ReleaseDC(screen_window, window_dc);
+		window_dc= NULL;
+	}
+
+	if(memory_dc)
+	{
+		DeleteDC(memory_dc);
+		memory_dc= NULL;
+	}
+
+	if(memory_bitmap)
+	{
+		DeleteObject(memory_bitmap);
+		memory_bitmap= NULL;
+	}
+}
+
+struct bitmap_data *initialize_offscreen_bitmap(
+	rectangle2d *bounds)
+{
+	return initialize_offscreen_bitmap_with_data(bounds, screen_pixels, NONE);
+}
+
+// this is called when all drawing for the current frame is complete
+// thus this is the time when we flip pages
+void release_offscreen_bitmap(
+	struct bitmap_data *bitmap)
+{
+	UNUSED_PARAMETER(bitmap);
+}
+
+void copy_offscreen_world_to_screen(
+	rectangle2d *source_bounds,
+	rectangle2d *destination_bounds)
+{
+	// blit the bitmap from memory to the window
+	if(memory_bitmap)
+	{
+		BitBlt(window_dc, source_bounds->left, source_bounds->top,
+			source_bounds->right-source_bounds->left,
+			source_bounds->bottom-source_bounds->top,
+			memory_dc, destination_bounds->left, destination_bounds->top,
+			SRCCOPY);
+	}
+}
Index: Myth2Code/shell.h
===================================================================
--- Myth2Code/shell.h	(revision 5098)
+++ Myth2Code/shell.h	(working copy)
@@ -45,15 +45,63 @@
 void platform_wait_quantum(void);
 void release_environment(void);
 
+#ifdef windows
+
+enum
+{
+	_myth_is_active_bit,
+	_myth_is_visible_bit,
+	_myth_is_paused_bit,
+
+	_myth_is_active_flag = FLAG(_myth_is_active_bit),
+	_myth_is_visible_flag = FLAG(_myth_is_visible_bit),
+	_myth_is_paused_flag = FLAG(_myth_is_paused_bit),
+};
+
+extern int myth_pause_flags;
+#define myth_is_active() (myth_pause_flags & _myth_is_active_flag)
+#define myth_is_visible() (myth_pause_flags & _myth_is_visible_flag)
+#define myth_is_paused() (myth_pause_flags & _myth_is_paused_flag)
+
+#else
 boolean myth_is_paused(void); // game loop paused?
 boolean myth_is_active(void); // game window in focus?
 boolean myth_is_visible(void); // game window visible?
+#endif
 
+#ifdef windows
+#define prevent_cutscenes_from_playing() FALSE
+#else
 boolean prevent_cutscenes_from_playing(void);
+#endif
 
 #ifdef windows
+
+#ifdef __PLATFORM_CSERIES_H__
+
+enum
+{
+	// Myth -> GUI window
+	WM_ALTTAB = WM_USER+1,
+	WM_SETUP_SCREEN,
+	WM_TOGGLEONTOP,
+	WM_TOGGLEFULLSCREEN,
+	WM_DESTROYSELF,
+
+	// GUI -> Myth
+	MYTHMSG_PAUSE,
+	MYTHMSG_PAINT,
+	MYTHMSG_RESHAPE
+};
+
+void PostMythMessage(long message_id, void *data, int count);
+
+#endif
+
+void set_window_multithread_mode(boolean enable);
 boolean unqueue_paint_message(void);
 void timer_task_hook(TIMER_TASK_PARAMS);
+
 #endif
 
 #ifdef __cplusplus
Index: Myth2Code/shell_windows.c
===================================================================
--- Myth2Code/shell_windows.c	(revision 5098)
+++ Myth2Code/shell_windows.c	(working copy)
@@ -62,70 +62,53 @@
    Install the low level keyboard hook in the timer thread instead of the main thread,
    to achieve lower latency. This fixes the hook getting timed out and removed on win7.
 
+-- Build 403 - DRB -
+   Refactoring for multithreaded gui.
+
 */
 
 #include "platform_cseries.h"
-#define platform
 
 #include "shell.h"
 #include "screen.h"
-#include "shapes.h"
-#include "render.h"
-#include "myth.h"
-#include "error_manager.h"
 #include "keyboard.h"
-#include "byte_swapping.h"
-#include "input_controller.h"
-#include "missing_strings.h"
-#include "bitmap_drawing.h"
-#include "bitmap_dialogs.h"
 #include "system_info.h"
-#include "binaries\resource.h"
 #include "stack_walk_windows.h"
-#include "myth_networking.h"
 #include "main.h"
 #include "recording.h"
 #include "selection.h"
-#include "input_controller.h"
-#include "touch_controller.h"
-#include "windows_touch_api.h"
+#include "game_preferences.h"
+#include "sound_manager.h"
+#include "hardware_rasterizers.h"
+#include "setup_opengl.h"
 
 #if defined(_MSC_VER) && (_MSC_VER < 1400)
 #define USE_SECURITY_ERROR_HANDLER
 #endif
 
-/* ---------- defines */
-
-#define WM_ALTTAB (WM_USER+1)
-
 /* ---------- globals */
 
+int myth_pause_flags = 0;
 HINSTANCE application_instance;
+static THREAD gui_thread;
+static DWORD myth_thread_id;
 static boolean redraw_queued = FALSE;
-static boolean game_paused= FALSE;
-static boolean myth_is_active_app = FALSE;
 static LPSTR command_line;
-static HMENU system_menu;
 static HHOOK hKeyboardHook = NULL;
 
 /* ---------- externs */
 
-extern boolean windows_key_down;
 extern HWND screen_window;
+extern void reset_dsound_hwnd(void);
 
-extern void input_keydown(int virtual_key, boolean repeat);
-extern void input_wheel_delta(int axis, int delta);
+/* ---------- local prototypes */
 
-/* ---------- private code */
+static void handle_prerun_commands(char *command_line);
 
-static void set_windows_game_pause_state(BOOL paused, const char *reason);
-static void remove_keyboard_hook(void);
-static void add_keyboard_hook(void);
+static void install_gui_thread(void);
+static void remove_gui_thread(void);
 
-static void handle_prerun_commands(char *command_line);
-
 /* ---------- code */
-long CALLBACK MainWndProc(HWND window, UINT msg, WPARAM wParam, LPARAM lParam);
 
 static void myth_crash_handler(CONTEXT *context, DWORD exception_code)
 {
@@ -189,20 +172,19 @@
 }
 #endif
 
-static LONG MythExceptionHandler(
+static LONG WINAPI MythExceptionHandler(
 	LPEXCEPTION_POINTERS lpexpExceptionInfo)
 {
 	myth_crash_handler(lpexpExceptionInfo->ContextRecord, lpexpExceptionInfo->ExceptionRecord->ExceptionCode); // doesn't return.
 	return EXCEPTION_CONTINUE_SEARCH;
 }
 
-int PASCAL WinMain(
+int WINAPI WinMain(
 	HINSTANCE hInstance,
 	HINSTANCE hPrevInstance,
 	LPSTR lpszCmdLine,
 	int cmdShow)
 {
-	//HANDLE h_proc;
 /*
 #ifdef _DEBUG
 	atexit(debug_dump_memory_by_file);
@@ -214,75 +196,21 @@
 
 	SetLastError(NO_ERROR);
 
+	command_line= lpszCmdLine;
+	application_instance= hInstance;
+	myth_thread_id= GetCurrentThreadId();
+	set_thread_name(myth_thread_id, "Myth Main Thread");
+
 	stack_walk_initialize();
-	SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)MythExceptionHandler);
+	SetUnhandledExceptionFilter(MythExceptionHandler);
 
 #ifdef USE_SECURITY_ERROR_HANDLER
 	_set_security_error_handler(security_failure_handler);
 #endif
-/*
-	h_proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
-	if (h_proc)
-	{
-		// If we don't set this, we can get preempted by another process
-		// that fucks with our VM.
-		if (!SetPriorityClass(h_proc, ABOVE_NORMAL_PRIORITY_CLASS))
-		{
-			log_message(NULL, NONE, "Could not set priority of process. Running under Windows NT?");
-		}
-		CloseHandle(h_proc);
-	}*/
 
-	command_line= lpszCmdLine;
 	handle_prerun_commands(command_line);
 
-	application_instance= hInstance;
-	
-	// Build 341 - DRB - Allow multiple instances for fun and profit!
-	/* Only run one instance.  Win32 doesn't set hPrevInstance like it used to */	
-	//if (!FindWindow(MAIN_WINDOW_CLASS, NULL))
-	if(TRUE)
-	{
-		WNDCLASS wndclass;
-
-		SetLastError(NO_ERROR); // We didn't find a copy running, but this isn't an error condition, so clear the error.
-
-		// Register the window class
-		memset(&wndclass, 0, sizeof(wndclass));
-		wndclass.lpszClassName= MAIN_WINDOW_CLASS;
-		wndclass.hInstance= hInstance;
-		wndclass.lpfnWndProc= MainWndProc;
-		wndclass.hCursor= LoadCursor(NULL, IDC_ARROW);
-
-		wndclass.hIcon= LoadIcon(hInstance, MAKEINTRESOURCE(128));
-		if (!wndclass.hIcon)
-		{
-			// Icon failed to load, but we can't do anything about it.
-			SetLastError(NO_ERROR);
-//			dprintf("LoadIcon() failed with error %d", GetLastError());
-		}
-
-		wndclass.lpszMenuName= NULL;
-		wndclass.hbrBackground= (HBRUSH)GetStockObject(BLACK_BRUSH);
-		wndclass.style= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;	// Build 243 - PAB - Added CS_OWNDC in an attempt to help OGL along
-		wndclass.cbClsExtra= 0;
-		wndclass.cbWndExtra= 0;
-
-		// Don't try running if registering the class failed.
-		// We'll unregister the class after closing the screen window (we can't put an atexit
-		// function here because it will get called first and that will fail because we won't
-		// have closed all the windows belonging to that class)
-		if (RegisterClass(&wndclass))
-		{
-			main(0, NULL);
-		}
-	}
-	else
-	{
-		MessageBox(NULL, getcstr(temporary, strMISSING_COLLECTION, _only_one_copy), NULL, MB_OK | MB_ICONERROR);
-	}
-
-	return 0;
+	return main(0, NULL);
 }
 
 void initialize_environment(int argc, char *argv[])
@@ -290,7 +218,6 @@
 	initialize_working_directory();
 	initialize_system_info();
 	set_cpu_affinity(1);
-	atexit(restore_windows_lock_function);
 
 	return;
 }
@@ -298,23 +225,97 @@
 void release_environment(
 	void)
 {
+	// kill the gui thread (if any)
+	remove_gui_thread();
+
 	return;
 }
 
+static void set_myth_pause_state(int pause_flags)
+{
+	boolean pausing;
+
+	// this needs to be first since all the myth_is_* functions work based on this variable.
+	myth_pause_flags = pause_flags;
+
+	pausing = !myth_is_active();
+
+	if(pausing)
+	{
+		reset_selection_mode();
+		reset_observer_velocity_to_zero();
+	}
+
+	// pause or unpause the main loop and timer task
+	{
+		// It's ok to stop updating time if:
+		boolean ok_to_pause = 
+			// we're in solo game, or
+			(get_game_type() == _game_type_local && get_game_state() == _game_state_running) ||
+			// we're not in a netgame, and the myth window is invisible (minimized, etc)
+			(get_game_type() != _game_type_networked && !myth_is_visible());
+
+		if(!pausing || ok_to_pause)
+		{
+			SET_FLAG(myth_pause_flags, _myth_is_paused_bit, pausing);
+			set_keyboard_queue_task_state(!pausing);
+		}
+	}
+}
+
+static void PostThreadMessageData(DWORD thread_id, long message_id, void *data, int count)
+{
+	long buffer[2] = {0, 0};
+	assert(count <= sizeof(buffer));
+	if(data) memcpy(buffer, data, count);
+	PostThreadMessage(thread_id, message_id, buffer[0], buffer[1]);
+}
+
+static void UnpackMythMessage(MSG *msg, void *data, int count)
+{
+	long buffer[2] = {msg->wParam, msg->lParam};
+	memcpy(data, buffer, count);
+}
+
+void PostMythMessage(long message_id, void *data, int count)
+{
+	PostThreadMessageData(myth_thread_id, message_id, data, count);
+}
+
 void platform_specific_update(boolean fps_limiting)
 {
 	MSG msg;
 
-	while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+	while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
 	{
-		if(msg.message == WM_QUIT)
+		switch(msg.message)
 		{
-			exit(0);
-		}
-		else
-		{
-			TranslateMessage(&msg); // This fixes the lights for the capslock/numlock keys
+		case MYTHMSG_PAUSE:
+			{
+				int pause_flags;
+				UnpackMythMessage(&msg, &pause_flags, sizeof(pause_flags));
+				set_myth_pause_state(pause_flags);
+			}
+			break;
+		case MYTHMSG_PAINT:
+			{
+				rectangle2d bounds;
+				UnpackMythMessage(&msg, &bounds, sizeof(bounds));
+				invalidate_dialog_rectangle(&bounds);
+				redraw_queued = TRUE;
+			}
+			break;
+		case MYTHMSG_RESHAPE:
+			{
+				rectangle2d bounds;
+				UnpackMythMessage(&msg, &bounds, sizeof(bounds));
+				// TODO: resize myth!
+			}
+			break;
+		default:
+			TranslateMessage(&msg);
 			DispatchMessage(&msg);
+			break;
 		}
 	}
 
@@ -324,35 +325,96 @@
 	}
 }
 
-void platform_wait_quantum(
-	void)
+static boolean multithread = NONE;
+
+void create_window(void);
+void destroy_window(void);
+
+static boolean gui_thread_init_proc(THREAD *thread, void *user_data)
 {
-	Sleep(1);
+	create_window();
+
+	return screen_window != NULL;
 }
 
-boolean myth_is_paused(
-	void)
+static int gui_thread_proc(THREAD *thread, void *user_data)
 {
-	return game_paused;
+	MSG msg;
+
+	while(GetMessage(&msg, NULL, 0, 0) > 0)
+	{
+		TranslateMessage(&msg);
+		DispatchMessage(&msg);
+	}
+
+	return 0;
 }
 
-boolean myth_is_active(
+static void install_gui_thread(
 	void)
 {
-	return myth_is_active_app && !IsIconic(screen_window);
+	if(!gui_thread.thread_handle)
+	{
+		create_thread(&gui_thread, "Myth GUI Thread", gui_thread_proc, gui_thread_init_proc, NULL);
+	}
 }
 
-boolean myth_is_visible(
+static void remove_gui_thread(
 	void)
 {
-	return (myth_is_active_app || !is_true_fullscreen_now()) && !IsIconic(screen_window);
+	if(gui_thread.thread_handle)
+	{
+		destroy_window();
+		// Technically you're not supposed to directly post a WM_QUIT message,
+		// but it's ok here -- since we've just destroyed the window,
+		// everything is cleaned up and ready to quit immediately.
+		PostThreadMessage(gui_thread.thread_id, WM_QUIT, 0, 0);
+		wait_thread(&gui_thread);
+	}
 }
 
-boolean prevent_cutscenes_from_playing(void)
+void set_window_multithread_mode(boolean enable)
 {
-	return FALSE;
+	enable = enable && (get_game_preferences()->flags & _game_pref_multicore_flag);
+
+	assert(GetCurrentThreadId() == myth_thread_id);
+
+	if(multithread != enable)
+	{
+		multithread = enable;
+
+		// Destroy the window and recreate it in the other thread.
+
+#ifdef ENABLE_OPENGL
+		// Dispose any saved context associated with the window
+		dispose_opengl_context(TRUE);
+#endif
+
+		if(multithread) {
+			// single thread => multi thread
+			destroy_window();
+			install_gui_thread();
+		} else {
+			// multi thread => single thread
+			remove_gui_thread();
+			create_window();
+		}
+
+		assert(screen_window);
+
+#ifdef ENABLE_DSOUND
+		// Reset the cooperative level on the new window
+		reset_dsound_hwnd();
+#endif
+	}
 }
 
+void platform_wait_quantum(
+	void)
+{
+	Sleep(1);
+}
+
 /* ---------- private code */
 
 struct AppCounter
@@ -421,7 +483,7 @@
 
 // NB: This hook is installed in the TIMER THREAD; as such, do not call any functions that interact
 // with the myth state from here. Communication with the main thread can be done safely via PostMessage.
-LRESULT CALLBACK KeyboardProc(
+static LRESULT CALLBACK KeyboardProc(
 	int nCode, WPARAM wParam, LPARAM lParam)
 {
 	// If nCode == HC_ACTION, then we have a keyboard event
@@ -601,271 +663,13 @@
 	}
 }
 
-void handle_close_message(
-	void)
-{
-	if(!myth_is_active())
-	{
-		// the window is minimized, so close immediately
-		PostQuitMessage(0);
-	}
-	else
-	{
-		// treat this as if the user pressed escape
-		input_keydown(VK_ESCAPE, FALSE);
-	}
-}
-
 boolean unqueue_paint_message(void)
 {
-	boolean paint = redraw_queued && myth_is_visible();
+	boolean paint = redraw_queued;
 	redraw_queued = FALSE;
 	return paint;
 }
 
-void handle_size_message(WPARAM wParam)
-{
-	switch(wParam)
-	{
-	case SIZE_MAXIMIZED:
-		if(is_windowed_now())
-		{
-			toggle_windowed_mode(TRUE);
-		}
-		break;
-	case SIZE_MINIMIZED:
-		set_windows_game_pause_state(TRUE, "SIZE_MINIMIZED");
-		break;
-	case SIZE_RESTORED:
-		set_windows_game_pause_state(FALSE, "SIZE_RESTORED");
-		break;
-	}
-}
-
-LRESULT decode_touch(
-	HWND hWnd,
-	UINT message,
-	WPARAM wParam,
-	LPARAM lParam)
-{
-	TOUCHINPUT all_touch_events[16];
-	const unsigned int max_events = sizeof(all_touch_events) / sizeof(TOUCHINPUT);
-
-	unsigned int num_touch_events = MIN(LOWORD(wParam), max_events);
-	
-	if (GetTouchInputInfo((HTOUCHINPUT)lParam, num_touch_events, all_touch_events, sizeof(TOUCHINPUT)))
-	{
-		unsigned int e;
-		for (e = 0; e < num_touch_events; ++e)
-		{
-			DWORD ID = all_touch_events[e].dwID;
-			DWORD flags = all_touch_events[e].dwFlags;
-
-			// Convert to pixel coordinates (maintain fractional portion for accuracy)
-			// TODO: Scaling this in terms of pixels seems a bit odd (especially with resolution changes)...
-			// Should we try to recover device metrics so that we can roughly convert to to real-world units?
-			// Hard to say how this should ideally work.
-			// TODO: If the absolute positions are used at all, we need to use ScreenToClient to normalize
-			// it to where our window is. But doing this we seem to lose the fractional precision, so that
-			// may not be ideal either.
-			float pixelX = (float)all_touch_events[e].x / 100.0f;
-			float pixelY = (float)all_touch_events[e].y / 100.0f;
-			//ScreenToClient(hWnd, &ptInput);
-
-			if (flags & TOUCHEVENTF_DOWN)
-				input_touch_point_down(ID, pixelX, pixelY);
-			if (flags & TOUCHEVENTF_MOVE)
-				input_touch_point_move(ID, pixelX, pixelY);
-			if (flags & TOUCHEVENTF_UP)
-				input_touch_point_up(ID, pixelX, pixelY);
-		}
-
-		// Message handled
-		CloseTouchInputHandle((HTOUCHINPUT)lParam);
-		return 0;
-	}
-
-	// Default handler
-	return DefWindowProc(hWnd, message, wParam, lParam);
-}
-
-long CALLBACK MainWndProc(
-	HWND window,
-	UINT Msg,
-	WPARAM wParam,
-	LPARAM lParam)
-{
-	enum {
-		CMD_ON_TOP = 1337,
-		CMD_TOGGLE_FS,
-	};
-
-	switch(Msg)
-	{
-		case WM_CREATE:
-			{
-				system_menu = GetSystemMenu(window, FALSE);
-				InsertMenu(system_menu, 0, 0, CMD_TOGGLE_FS, "Fullscreen\tAlt+F11");
-				InsertMenu(system_menu, 0, 0, CMD_ON_TOP, "On Top\tAlt+F10");
-
-				// Build 402 - ATL - Register the window for touch instead of gestures
-				// ATL TODO: Experiment with WANTPALM and FINETOUCH flags
-
-				if(initialize_windows_touch_api())
-				{
-					RegisterTouchWindow(window, TWF_WANTPALM);
-				}
-			}
-			return 0;
-		case WM_INITMENUPOPUP:
-			{
-				HMENU menu = (HMENU)wParam;
-				if(menu == system_menu)
-				{
-					CheckMenuItem(menu, CMD_ON_TOP, MF_BYCOMMAND | (is_always_on_top_now() ? MF_CHECKED : 0)); 
-					CheckMenuItem(menu, CMD_TOGGLE_FS, MF_BYCOMMAND | (!is_windowed_now() ? MF_CHECKED : 0));
-					return 0;
-				}
-			}
-			break;
-		case WM_SYSCOMMAND:
-			{
-				switch(wParam)
-				{
-				case CMD_ON_TOP:
-					toggle_always_on_top(FALSE);
-					return 0;
-				case CMD_TOGGLE_FS:
-					toggle_windowed_mode(FALSE);
-					return 0;
-				}
-			}
-			break;
-		case WM_SYSCHAR:
-			return 0;
-		case WM_MOUSEACTIVATE:
-			return LOWORD(lParam) == HTCLIENT ? MA_ACTIVATEANDEAT : MA_ACTIVATE;
-		case WM_MOUSEWHEEL:
-			input_wheel_delta(_mouse_wheel_axis_y, GET_WHEEL_DELTA_WPARAM(wParam));
-			return 0;
-		case WM_SYSKEYDOWN:
-		case WM_KEYDOWN:
-			{
-				boolean repeat = (lParam & (1<<30)) != 0;
-				input_keydown(wParam, repeat);
-			}
-			if(wParam == VK_LWIN || wParam == VK_RWIN)
-			{
-				windows_key_down = TRUE;
-			}
-			return 0;
-		case WM_SYSKEYUP:
-		case WM_KEYUP:
-			if(wParam == VK_LWIN || wParam == VK_RWIN)
-			{
-				windows_key_down = FALSE;
-			}
-			return 0;
-		case WM_CLOSE:
-			handle_close_message();
-			return 0;
-		case WM_PAINT:
-			{
-				RECT rect;
-				if(GetUpdateRect(window, &rect, FALSE))
-				{
-					rectangle2d bounds;
-					set_rectangle2d(&bounds, rect.left, rect.top, rect.right, rect.bottom);
-					invalidate_dialog_rectangle(&bounds);
-					redraw_queued = TRUE;
-				}
- 				// no return value; fallthrough to the default behavior (which validates the region)
-			}
-			break;
-		case WM_SIZE:
-			handle_size_message(wParam);
-			return 0;
-		case WM_MOVE:
-			window_moved(LOWORD(lParam), HIWORD(lParam));
-			return 0;
-		case WM_ACTIVATEAPP:
-			set_windows_game_pause_state(wParam == FALSE || IsIconic(screen_window), "WM_ACTIVATEAPP");
-			return 0;
-		case WM_ERASEBKGND:
-			return TRUE;
-		case WM_INPUTLANGCHANGE:
-			set_windows_keyboard_layout();
-			break;
-		case WM_ALTTAB:
-			set_windows_game_pause_state(TRUE, "alt-tab handler");
-			return 0;
-		case WM_TOUCH:
-			return decode_touch(screen_window, Msg, wParam, lParam);
-		case WM_TABLET_QUERYSYSTEMGESTURESTATUS:
-			// Disable "press and hold" right click gesture and some of the sillier UI
-			return TABLET_DISABLE_PRESSANDHOLD |
-				TABLET_DISABLE_PENTAPFEEDBACK |
-				TABLET_DISABLE_PENBARRELFEEDBACK |
-				TABLET_DISABLE_FLICKS;
-	}
-
-	return DefWindowProc(window, Msg, wParam, lParam);
-}
-
-/* ---------- pausing */
-static void set_windows_game_pause_state(
-	BOOL paused, const char *reason)
-{
-/*
-	// debugging
-	MessageBeep(-1);
-	sprintf(temporary, "%s (%s)", paused ? "P" : "U", reason);
-	log_message(NULL, NONE, temporary);
-	SetWindowText(screen_window, temporary);
-*/
-	// update for new activation state
-	{
-		myth_is_active_app = !paused;
-
-		if(paused)
-		{
-			reset_selection_mode();
-			reset_observer_velocity_to_zero();
-		}
-
-		if(paused)
-		{
-			restore_windows_lock_function();
-		}
-		else
-		{
-			disable_windows_lock_function();
-		}
-
-		boost_timer_resolution(!paused);
-		pause_screen_data(paused);
-		pause_system_input_device(paused);
-	}
-
-	// pause or unpause the main loop and timer task
-	{
-		// It's ok to stop updating time if:
-		boolean ok_to_pause = 
-			// we're in solo game, or
-			(get_game_type() == _game_type_local && get_game_state() == _game_state_running) ||
-			// we're not in a netgame, and the myth window is invisible (minimized, etc)
-			(get_game_type() != _game_type_networked && !myth_is_visible());
-
-		if(!paused || ok_to_pause)
-		{
-			game_paused = paused;
-			set_keyboard_queue_task_state(!game_paused);
-		}
-	}
-
-	return;
-}
-
 char *get_command_line(
 	void)
 {
Index: Myth2Code/smacker/smacker_dll.c
===================================================================
--- Myth2Code/smacker/smacker_dll.c	(revision 5098)
+++ Myth2Code/smacker/smacker_dll.c	(working copy)
@@ -8,13 +8,8 @@
 #include "platform_cseries.h"
 #include "smacker_dll.h"
 #include "error_manager.h"
+#include "sound_manager.h"
 
-#ifdef windows
-#include "sound_provider_choice.h"
-#include "DirectX/dsound.h"
-LPDIRECTSOUND get_direct_sound_object_for_cutscenes(void);
-#endif
-
 #ifdef macintosh
 #include <CoreFoundation/CoreFoundation.h>
 #endif
Index: Myth2Code/sound/sound_manager.c
===================================================================
--- Myth2Code/sound/sound_manager.c	(revision 5098)
+++ Myth2Code/sound/sound_manager.c	(working copy)
@@ -533,6 +533,14 @@
 	return;
 }
 
+void reboot_sound_manager(
+	void)
+{
+	dispose_sound_manager_from_old_map(); // fade out sound, etc
+	initialize_sound_manager();
+	initialize_sound_manager_for_new_map();
+}
+
 boolean machine_can_play_sound(
 	void)
 {
Index: Myth2Code/timer_windows.c
===================================================================
--- Myth2Code/timer_windows.c	(revision 5098)
+++ Myth2Code/timer_windows.c	(working copy)
@@ -1,16 +1,11 @@
 #include "platform_cseries.h"
 
-/* ------ timer related stuff. */
-static DWORD WINAPI thread_proc(LPVOID lpThreadParameter);
+int timer_thread_proc(THREAD *thread, void *user_data);
 
 struct thread_data {
-	boolean initialized;
-	boolean active;
-	HANDLE thread;
+	THREAD thread;
 	LONG sleep_time;
 	timer_task_proc proc;
-	DWORD thread_id;
-	boolean quit_thread;
 	int tasks_per_second;
 } private_thread_data = { FALSE, FALSE };
 
@@ -18,27 +13,14 @@
 	short tasks_per_second, 
 	timer_task_proc proc)
 {
-	assert(!private_thread_data.initialized);
-	private_thread_data.initialized= TRUE;
+	assert(!private_thread_data.thread.thread_handle);
+
 	private_thread_data.proc= proc;
-	private_thread_data.quit_thread= FALSE;
 	private_thread_data.sleep_time= MACHINE_TICKS_PER_SECOND/tasks_per_second;
 	private_thread_data.tasks_per_second= tasks_per_second;
-	private_thread_data.thread= CreateThread(NULL, 0, thread_proc, &private_thread_data, 0, &private_thread_data.thread_id);
-	if (private_thread_data.thread)
-	{
-		if (!CloseHandle(private_thread_data.thread))  // this is okay to do now.
-		{
-			vhalt(csprintf(temporary, "CloseHandle() for thread failed with error %d", GetLastError()));
-		}
-	}
-	else
-	{
-		vhalt(csprintf(temporary, "CreateThread() failed with error %d", GetLastError()));
-		private_thread_data.thread_id= (DWORD) NONE;
-	}
+	create_thread(&private_thread_data.thread, "Myth Timer Thread", timer_thread_proc, NULL, &private_thread_data);
 
-	return private_thread_data.thread_id;
+	return private_thread_data.thread.thread_id;
 }
 
 /*
@@ -49,30 +31,20 @@
 		added was a method to try and "guarantee" that over a second we got the right number
 		of packets.
 */
-static DWORD WINAPI thread_proc(
-	LPVOID lpThreadParameter)
+static int timer_thread_proc(THREAD *thread, void *user_data)
 {
-	struct thread_data *thread_data= (struct thread_data *) lpThreadParameter;
+	struct thread_data *thread_data= (struct thread_data *) user_data;
 	boolean continue_iterating= TRUE;
 	long task_startup_time= machine_tick_count();
 	unsigned long iterations= 0;
-	BOOL success;
 
-	success= SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
-#ifdef DEBUG
-	if (!success)
-	{
-		vhalt(csprintf(temporary, "SetThreadPriority() failed with error %d", GetLastError()));
-	}
-#endif
+	SetThreadPriority(thread->thread_handle, THREAD_PRIORITY_TIME_CRITICAL);
 
 	/* Call their function */
-	assert(thread_data);
-	thread_data->active= TRUE;
 	thread_data->proc(TIMER_TASK_INIT);
 	while (continue_iterating)
 	{
-		if (!thread_data->quit_thread)
+		if (!thread->quit_signal)
 		{
 			unsigned long target_iterations;
 
@@ -101,27 +73,17 @@
 		}
 	}
 	thread_data->proc(TIMER_TASK_DESTROY);
-	thread_data->active= FALSE;
-	
-	/* Note that if this ends prematurely, the memory is lost. (unless kill_thread is */
-	/*  called anyway) */
-	return 0l;	
+
+	return 0;
 }
 
-#define THREAD_TIMEOUT (3*MACHINE_TICKS_PER_SECOND)
 void remove_timer_task(
 	timer_task task)
 {
-	DWORD initial_tick_count= GetTickCount();
-
 	UNUSED_PARAMETER(task);
 
-	assert(private_thread_data.initialized);
-	private_thread_data.initialized= FALSE;
-	private_thread_data.quit_thread= TRUE;
-	
-	while (private_thread_data.active && (GetTickCount()-initial_tick_count)<THREAD_TIMEOUT) {};
-	vwarn(GetTickCount()-initial_tick_count<THREAD_TIMEOUT, "Unable to properly terminate the thread.");
-	
+	private_thread_data.thread.quit_signal = TRUE;
+	wait_thread(&private_thread_data.thread);
+
 	return;
 }
