(svn r8605) -Codechange: [OSX] changed all objective C to objective C++
authorbjarni
Mon, 05 Feb 2007 21:16:56 +0000
changeset 6192 c6adfc929c6b
parent 6191 12d69f54e920
child 6193 71f42ac93928
(svn r8605) -Codechange: [OSX] changed all objective C to objective C++
This will permanently solve the issue where compilation on OSX broke because C++ code was added to some header files

-Note: (important if you develop mac specific code)
taken from http://developer.apple.com/releasenotes/Cocoa/Objective-C++.html
gdb lacks an integrated C++ with Objective-C parser. This means that gdb won't be able to evaluate expressions that contain both C++ and Objective-C constructs.
gdb assumes that the language for ".mm" files is C++.
you can change it to objective C by typing: (gdb) set language objc
Mixing C++ and objective C has some limitation (see link for all of them)
Makefile.src.in
config.lib
configure
source.list
src/debug.h
src/gfx.h
src/hal.h
src/md5.h
src/os/macosx/macos.h
src/os/macosx/macos.m
src/os/macosx/macos.mm
src/unix.cpp
src/video/cocoa_v.h
src/video/cocoa_v.m
src/video/cocoa_v.mm
--- a/Makefile.src.in	Mon Feb 05 14:00:32 2007 +0000
+++ b/Makefile.src.in	Mon Feb 05 21:16:56 2007 +0000
@@ -35,9 +35,9 @@
 
 OBJS_C   := !!OBJS_C!!
 OBJS_CPP := !!OBJS_CPP!!
-OBJS_M   := !!OBJS_M!!
+OBJS_MM  := !!OBJS_MM!!
 OBJS_RC  := !!OBJS_RC!!
-OBJS     := $(OBJS_C) $(OBJS_CPP) $(OBJS_M) $(OBJS_RC)
+OBJS     := $(OBJS_C) $(OBJS_CPP) $(OBJS_MM) $(OBJS_RC)
 SRCS     := !!SRCS!!
 
 # All C-files depend on those 3 files
@@ -126,12 +126,12 @@
 	$(E) '$(STAGE) DEP $(<:$(SRC_DIR)/%.cpp=%.cpp)'
 	$(Q)$(CXX_HOST) $(CFLAGS) -MM $< | sed 's#^$(@F:%.d=%.o):#$@ $(@:%.d=%.o):#' > $@
 
-$(OBJS_M:%.o=%.d): %.d: $(SRC_DIR)/%.m $(FILE_DEP)
-	$(E) '$(STAGE) DEP $(<:$(SRC_DIR)/%.m=%.m)'
-	$(Q)$(CC_HOST) $(CC_CFLAGS) $(CFLAGS) -MM $< | sed 's#^$(@F:%.d=%.o):#$@ $(@:%.d=%.o):#' > $@
+$(OBJS_MM:%.o=%.d): %.d: $(SRC_DIR)/%.mm $(FILE_DEP)
+	$(E) '$(STAGE) DEP $(<:$(SRC_DIR)/%.mm=%.mm)'
+	$(Q)$(CC_HOST) $(CFLAGS) -MM $< | sed 's#^$(@F:%.d=%.o):#$@ $(@:%.d=%.o):#' > $@
 
 $(OBJS_RC:%.o=%.d): %.d: $(SRC_DIR)/%.rc $(FILE_DEP)
-	$(E) '$(STAGE) DEP $(<:$(SRC_DIR)/%.m=%.m)'
+	$(E) '$(STAGE) DEP $(<:$(SRC_DIR)/%.mm=%.mm)'
 	$(Q)touch $@
 
 else
@@ -211,9 +211,9 @@
 	$(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)'
 	$(Q)$(CXX_HOST) $(CFLAGS) -c -o $@ $<
 
-$(OBJS_M): %.o: $(SRC_DIR)/%.m $(DEP_MASK) $(FILE_DEP)
-	$(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.m=%.m)'
-	$(Q)$(CC_HOST) $(CC_CFLAGS) $(CFLAGS) -c -o $@ $<
+$(OBJS_MM): %.o: $(SRC_DIR)/%.mm $(DEP_MASK) $(FILE_DEP)
+	$(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.mm=%.mm)'
+	$(Q)$(CC_HOST) $(CFLAGS) -c -o $@ $<
 
 $(OBJS_RC): %.o: $(SRC_DIR)/%.rc $(FILE_DEP)
 	$(E) '$(STAGE) Compiling resource $(<:$(SRC_DIR)/%.rc=%.rc)'
--- a/config.lib	Mon Feb 05 14:00:32 2007 +0000
+++ b/config.lib	Mon Feb 05 21:16:56 2007 +0000
@@ -1639,7 +1639,7 @@
 		s#!!LANG_SUPPRESS!!#$lang_suppress#g;
 		s#!!OBJS_C!!#$OBJS_C#g;
 		s#!!OBJS_CPP!!#$OBJS_CPP#g;
-		s#!!OBJS_M!!#$OBJS_M#g;
+		s#!!OBJS_MM!!#$OBJS_MM#g;
 		s#!!OBJS_RC!!#$OBJS_RC#g;
 		s#!!SRCS!!#$SRCS#g;
 		s#!!OS!!#$os#g;
--- a/configure	Mon Feb 05 14:00:32 2007 +0000
+++ b/configure	Mon Feb 05 21:16:56 2007 +0000
@@ -100,7 +100,7 @@
 
 OBJS_C="`  echo \"$SRCS\" | awk ' { ORS = " " } /\.c$/   { gsub(".c$",   ".o", $0); print $0; }'`"
 OBJS_CPP="`echo \"$SRCS\" | awk ' { ORS = " " } /\.cpp$/ { gsub(".cpp$", ".o", $0); print $0; }'`"
-OBJS_M="`  echo \"$SRCS\" | awk ' { ORS = " " } /\.m$/   { gsub(".m$",   ".o", $0); print $0; }'`"
+OBJS_MM="` echo \"$SRCS\" | awk ' { ORS = " " } /\.mm$/  { gsub(".mm$",  ".o", $0); print $0; }'`"
 OBJS_RC="` echo \"$SRCS\" | awk ' { ORS = " " } /\.rc$/  { gsub(".rc$",  ".o", $0); print $0; }'`"
 SRCS="`    echo \"$SRCS\" | awk ' { ORS = " " } { print $0; }'`"
 
--- a/source.list	Mon Feb 05 14:00:32 2007 +0000
+++ b/source.list	Mon Feb 05 21:16:56 2007 +0000
@@ -384,7 +384,7 @@
 
 #if OSX
 # OSX Files
-	os/macosx/macos.m
+	os/macosx/macos.mm
 
 	#if DEDICATED
 	#else
@@ -392,7 +392,7 @@
 	#end
 
 	#if COCOA
-		video/cocoa_v.m
+		video/cocoa_v.mm
 		sound/cocoa_s.cpp
 		os/macosx/splash.cpp
 	#end
--- a/src/debug.h	Mon Feb 05 14:00:32 2007 +0000
+++ b/src/debug.h	Mon Feb 05 21:16:56 2007 +0000
@@ -3,10 +3,6 @@
 #ifndef DEBUG_H
 #define DEBUG_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif //__cplusplus
-
 /* Debugging messages policy:
  * These should be the severities used for direct DEBUG() calls
  * maximum debugging level should be 10 if really deep, deep
@@ -111,8 +107,4 @@
 	}\
 }
 
-#ifdef __cplusplus
-}
-#endif //__cplusplus
-
 #endif /* DEBUG_H */
--- a/src/gfx.h	Mon Feb 05 14:00:32 2007 +0000
+++ b/src/gfx.h	Mon Feb 05 21:16:56 2007 +0000
@@ -3,11 +3,6 @@
 #ifndef GFX_H
 #define GFX_H
 
-/* !!! Note that the first part of this file if enclosed in extern "C" due to cocoa/obj-C !!! */
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
 
 enum WindowKeyCodes {
 	WKC_SHIFT = 0x8000,
@@ -175,10 +170,6 @@
 void GameSizeChanged(void);
 void UndrawMouseCursor(void);
 
-#ifdef __cplusplus
-}; //extern "C"
-/* Following part is only for C++ */
-
 #include "helpers.hpp"
 
 typedef enum FontSizes {
@@ -245,7 +236,7 @@
 void UndrawMouseCursor(void);
 bool ChangeResInGame(int w, int h);
 void SortResolutions(int count);
-extern "C" void ToggleFullScreen(bool fs);
+void ToggleFullScreen(bool fs);
 
 /* gfx.c */
 #define ASCII_LETTERSTART 32
@@ -301,6 +292,4 @@
 extern bool _dbg_screen_rect;
 #endif
 
-#endif /* __cplusplus */
-
 #endif /* GFX_H */
--- a/src/hal.h	Mon Feb 05 14:00:32 2007 +0000
+++ b/src/hal.h	Mon Feb 05 21:16:56 2007 +0000
@@ -3,10 +3,6 @@
 #ifndef HAL_H
 #define HAL_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif //__cplusplus
-
 typedef struct {
 	const char *(*start)(const char * const *parm);
 	void (*stop)(void);
@@ -46,8 +42,4 @@
 	MUSIC_DRIVER = 2,
 };
 
-#ifdef __cplusplus
-} // extern "C"
-#endif //__cplusplus
-
 #endif /* HAL_H */
--- a/src/md5.h	Mon Feb 05 14:00:32 2007 +0000
+++ b/src/md5.h	Mon Feb 05 21:16:56 2007 +0000
@@ -72,11 +72,6 @@
     md5_byte_t buf[64];  /* accumulate block */
 } md5_state_t;
 
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
 /* Initialize the algorithm. */
 void md5_init(md5_state_t *pms);
 
@@ -86,8 +81,4 @@
 /* Finish the message and return the digest. */
 void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
 
-#ifdef __cplusplus
-}  /* end extern "C" */
-#endif
-
 #endif /* MD5_INCLUDED */
--- a/src/os/macosx/macos.h	Mon Feb 05 14:00:32 2007 +0000
+++ b/src/os/macosx/macos.h	Mon Feb 05 21:16:56 2007 +0000
@@ -11,15 +11,9 @@
  * the function then adds text that tells the user to update and then report the bug if it's present in the newest version
  * It also quits in a nice way since we call it when we know something happened that will crash OpenTTD (like a needed pointer turns out to be NULL or similar)
  */
-#ifdef __cplusplus
-extern "C" {
-#endif //__cplusplus
-	void ShowMacDialog ( const char *title, const char *message, const char *buttonLabel );
-	void ShowMacAssertDialog ( const char *function, const char *file, const int line, const char *expression );
-	void ShowMacErrorDialog(const char *error);
-#ifdef __cplusplus
-}
-#endif //__cplusplus
+void ShowMacDialog ( const char *title, const char *message, const char *buttonLabel );
+void ShowMacAssertDialog ( const char *function, const char *file, const int line, const char *expression );
+void ShowMacErrorDialog(const char *error);
 
 // Since MacOS X users will never see an assert unless they started the game from a terminal
 // we're using a custom assert(e) macro.
--- a/src/os/macosx/macos.m	Mon Feb 05 14:00:32 2007 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,160 +0,0 @@
-/* $Id$ */
-
-#include <AppKit/AppKit.h>
-
-#include <mach/mach.h>
-#include <mach/mach_host.h>
-#include <mach/host_info.h>
-#include <mach/machine.h>
-#include <stdio.h>
-#include "../../stdafx.h"
-#include "../../macros.h"
-
-#ifndef CPU_SUBTYPE_POWERPC_970
-#define CPU_SUBTYPE_POWERPC_970 ((cpu_subtype_t) 100)
-#endif
-
-/*
- * This file contains objective C
- * Apple uses objective C instead of plain C to interact with OS specific/native functions
- *
- * Note: TrueLight's crosscompiler can handle this, but it likely needs a manual modification for each change in this file.
- * To insure that the crosscompiler still works, let him try any changes before they are committed
- */
-
-void ToggleFullScreen(bool fs);
-
-static char *GetOSString(void)
-{
-	static char buffer[175];
-	const char* CPU;
-	char OS[20];
-	char newgrf[125];
-	long sysVersion;
-	extern const char _openttd_revision[];
-
-	// get the hardware info
-	host_basic_info_data_t hostInfo;
-	mach_msg_type_number_t infoCount;
-
-	infoCount = HOST_BASIC_INFO_COUNT;
-	host_info(
-		mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostInfo, &infoCount
-	);
-
-	// replace the hardware info with strings, that tells a bit more than just an int
-	switch (hostInfo.cpu_subtype) {
-#ifdef __POWERPC__
-		case CPU_SUBTYPE_POWERPC_750:  CPU = "G3"; break;
-		case CPU_SUBTYPE_POWERPC_7400:
-		case CPU_SUBTYPE_POWERPC_7450: CPU = "G4"; break;
-		case CPU_SUBTYPE_POWERPC_970:  CPU = "G5"; break;
-		default:                       CPU = "Unknown PPC"; break;
-#else
-		/* it looks odd to have a switch for two cases, but it leaves room for easy
-		 * expansion. Odds are that Apple will some day use newer CPUs than i686
-		 */
-		case CPU_SUBTYPE_PENTPRO: CPU = "i686"; break;
-		default:                  CPU = "Unknown Intel"; break;
-#endif
-	}
-
-	// get the version of OSX
-	if (Gestalt(gestaltSystemVersion, &sysVersion) != noErr) {
-		sprintf(OS, "Undetected");
-	} else {
-		int majorHiNib = GB(sysVersion, 12, 4);
-		int majorLoNib = GB(sysVersion,  8, 4);
-		int minorNib   = GB(sysVersion,  4, 4);
-		int bugNib     = GB(sysVersion,  0, 4);
-
-		sprintf(OS, "%d%d.%d.%d", majorHiNib, majorLoNib, minorNib, bugNib);
-	}
-
-	// make a list of used newgrf files
-/*	if (_first_grffile != NULL) {
-		char* n = newgrf;
-		const GRFFile* file;
-
-		for (file = _first_grffile; file != NULL; file = file->next) {
-			n = strecpy(n, " ", lastof(newgrf));
-			n = strecpy(n, file->filename, lastof(newgrf));
-		}
-	} else {*/
-		sprintf(newgrf, "none");
-//	}
-
-	snprintf(
-		buffer, lengthof(buffer),
-		"Please add this info: (tip: copy-paste works)\n"
-		"CPU: %s, OSX: %s, OpenTTD version: %s\n"
-		"NewGRF files:%s",
-		CPU, OS, _openttd_revision, newgrf
-	);
-	return buffer;
-}
-
-
-#ifdef WITH_SDL
-
-void ShowMacDialog(const char* title, const char* message, const char* buttonLabel)
-{
-	NSRunAlertPanel([NSString stringWithCString: title], [NSString stringWithCString: message], [NSString stringWithCString: buttonLabel], nil, nil);
-}
-
-#elif defined WITH_COCOA
-
-void CocoaDialog(const char* title, const char* message, const char* buttonLabel);
-
-void ShowMacDialog(const char* title, const char* message, const char* buttonLabel)
-{
-	CocoaDialog(title, message, buttonLabel);
-}
-
-
-#else
-
-void ShowMacDialog(const char* title, const char* message, const char* buttonLabel)
-{
-	fprintf(stderr, "%s: %s\n", title, message);
-}
-
-#endif
-
-void ShowMacAssertDialog(const char* function, const char* file, const int line, const char* expression)
-{
-	const char* buffer =
-		[[NSString stringWithFormat:@
-			"An assertion has failed and OpenTTD must quit.\n"
-			"%s in %s (line %d)\n"
-			"\"%s\"\n"
-			"\n"
-			"You should report this error the OpenTTD developers if you think you found a bug.\n"
-			"\n"
-			"%s",
-			function, file, line, expression, GetOSString()] cString
-		];
-	NSLog(@"%s", buffer);
-	ToggleFullScreen(0);
-	ShowMacDialog("Assertion Failed", buffer, "Quit");
-
-	// abort so that a debugger has a chance to notice
-	abort();
-}
-
-
-void ShowMacErrorDialog(const char *error)
-{
-	const char* buffer =
-		[[NSString stringWithFormat:@
-			"Please update to the newest version of OpenTTD\n"
-			"If the problem presists, please report this to\n"
-			"http://bugs.openttd.org\n"
-			"\n"
-			"%s",
-			GetOSString()] cString
-		];
-	ToggleFullScreen(0);
-	ShowMacDialog(error, buffer, "Quit");
-	abort();
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/os/macosx/macos.mm	Mon Feb 05 21:16:56 2007 +0000
@@ -0,0 +1,160 @@
+/* $Id$ */
+
+#include <AppKit/AppKit.h>
+
+#include <mach/mach.h>
+#include <mach/mach_host.h>
+#include <mach/host_info.h>
+#include <mach/machine.h>
+#include <stdio.h>
+#include "../../stdafx.h"
+#include "../../macros.h"
+
+#ifndef CPU_SUBTYPE_POWERPC_970
+#define CPU_SUBTYPE_POWERPC_970 ((cpu_subtype_t) 100)
+#endif
+
+/*
+ * This file contains objective C
+ * Apple uses objective C instead of plain C to interact with OS specific/native functions
+ *
+ * Note: TrueLight's crosscompiler can handle this, but it likely needs a manual modification for each change in this file.
+ * To insure that the crosscompiler still works, let him try any changes before they are committed
+ */
+
+void ToggleFullScreen(bool fs);
+
+static char *GetOSString(void)
+{
+	static char buffer[175];
+	const char* CPU;
+	char OS[20];
+	char newgrf[125];
+	long sysVersion;
+	extern const char _openttd_revision[];
+
+	// get the hardware info
+	host_basic_info_data_t hostInfo;
+	mach_msg_type_number_t infoCount;
+
+	infoCount = HOST_BASIC_INFO_COUNT;
+	host_info(
+		mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostInfo, &infoCount
+	);
+
+	// replace the hardware info with strings, that tells a bit more than just an int
+	switch (hostInfo.cpu_subtype) {
+#ifdef __POWERPC__
+		case CPU_SUBTYPE_POWERPC_750:  CPU = "G3"; break;
+		case CPU_SUBTYPE_POWERPC_7400:
+		case CPU_SUBTYPE_POWERPC_7450: CPU = "G4"; break;
+		case CPU_SUBTYPE_POWERPC_970:  CPU = "G5"; break;
+		default:                       CPU = "Unknown PPC"; break;
+#else
+		/* it looks odd to have a switch for two cases, but it leaves room for easy
+		 * expansion. Odds are that Apple will some day use newer CPUs than i686
+		 */
+		case CPU_SUBTYPE_PENTPRO: CPU = "i686"; break;
+		default:                  CPU = "Unknown Intel"; break;
+#endif
+	}
+
+	// get the version of OSX
+	if (Gestalt(gestaltSystemVersion, &sysVersion) != noErr) {
+		sprintf(OS, "Undetected");
+	} else {
+		int majorHiNib = GB(sysVersion, 12, 4);
+		int majorLoNib = GB(sysVersion,  8, 4);
+		int minorNib   = GB(sysVersion,  4, 4);
+		int bugNib     = GB(sysVersion,  0, 4);
+
+		sprintf(OS, "%d%d.%d.%d", majorHiNib, majorLoNib, minorNib, bugNib);
+	}
+
+	// make a list of used newgrf files
+/*	if (_first_grffile != NULL) {
+		char* n = newgrf;
+		const GRFFile* file;
+
+		for (file = _first_grffile; file != NULL; file = file->next) {
+			n = strecpy(n, " ", lastof(newgrf));
+			n = strecpy(n, file->filename, lastof(newgrf));
+		}
+	} else {*/
+		sprintf(newgrf, "none");
+//	}
+
+	snprintf(
+		buffer, lengthof(buffer),
+		"Please add this info: (tip: copy-paste works)\n"
+		"CPU: %s, OSX: %s, OpenTTD version: %s\n"
+		"NewGRF files:%s",
+		CPU, OS, _openttd_revision, newgrf
+	);
+	return buffer;
+}
+
+
+#ifdef WITH_SDL
+
+void ShowMacDialog(const char* title, const char* message, const char* buttonLabel)
+{
+	NSRunAlertPanel([NSString stringWithCString: title], [NSString stringWithCString: message], [NSString stringWithCString: buttonLabel], nil, nil);
+}
+
+#elif defined WITH_COCOA
+
+void CocoaDialog(const char* title, const char* message, const char* buttonLabel);
+
+void ShowMacDialog(const char* title, const char* message, const char* buttonLabel)
+{
+	CocoaDialog(title, message, buttonLabel);
+}
+
+
+#else
+
+void ShowMacDialog(const char* title, const char* message, const char* buttonLabel)
+{
+	fprintf(stderr, "%s: %s\n", title, message);
+}
+
+#endif
+
+void ShowMacAssertDialog(const char* function, const char* file, const int line, const char* expression)
+{
+	const char* buffer =
+		[[NSString stringWithFormat:@
+			"An assertion has failed and OpenTTD must quit.\n"
+			"%s in %s (line %d)\n"
+			"\"%s\"\n"
+			"\n"
+			"You should report this error the OpenTTD developers if you think you found a bug.\n"
+			"\n"
+			"%s",
+			function, file, line, expression, GetOSString()] cString
+		];
+	NSLog(@"%s", buffer);
+	ToggleFullScreen(0);
+	ShowMacDialog("Assertion Failed", buffer, "Quit");
+
+	// abort so that a debugger has a chance to notice
+	abort();
+}
+
+
+void ShowMacErrorDialog(const char *error)
+{
+	const char* buffer =
+		[[NSString stringWithFormat:@
+			"Please update to the newest version of OpenTTD\n"
+			"If the problem presists, please report this to\n"
+			"http://bugs.openttd.org\n"
+			"\n"
+			"%s",
+			GetOSString()] cString
+		];
+	ToggleFullScreen(0);
+	ShowMacDialog(error, buffer, "Quit");
+	abort();
+}
--- a/src/unix.cpp	Mon Feb 05 14:00:32 2007 +0000
+++ b/src/unix.cpp	Mon Feb 05 21:16:56 2007 +0000
@@ -127,9 +127,9 @@
 }
 
 #ifdef WITH_COCOA
-extern "C" void cocoaSetWorkingDirectory(void);
-extern "C" void cocoaSetupAutoreleasePool(void);
-extern "C" void cocoaReleaseAutoreleasePool(void);
+void cocoaSetWorkingDirectory(void);
+void cocoaSetupAutoreleasePool(void);
+void cocoaReleaseAutoreleasePool(void);
 #endif
 
 int CDECL main(int argc, char* argv[])
--- a/src/video/cocoa_v.h	Mon Feb 05 14:00:32 2007 +0000
+++ b/src/video/cocoa_v.h	Mon Feb 05 21:16:56 2007 +0000
@@ -5,22 +5,9 @@
 
 #include "../hal.h"
 
-#ifndef __cplusplus
-/* Really ugly workaround
- * It should be solved right as soon as possible */
-typedef uint32 SpriteID;
-#endif //__cplusplus
-
+#include "../openttd.h"
 #include "../gfx.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif //__cplusplus
-
 extern const HalVideoDriver _cocoa_video_driver;
 
-#ifdef __cplusplus
-} // extern "C"
-#endif //__cplusplus
-
 #endif
--- a/src/video/cocoa_v.m	Mon Feb 05 14:00:32 2007 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2055 +0,0 @@
-/* $Id$ */
-
-/******************************************************************************
- *                             Cocoa video driver                             *
- * Known things left to do:                                                   *
- *  Nothing at the moment.                                                    *
- ******************************************************************************/
-
-#ifdef WITH_COCOA
-
-#import <Cocoa/Cocoa.h>
-#import <sys/time.h> /* gettimeofday */
-#import <sys/param.h> /* for MAXPATHLEN */
-#import <unistd.h>
-
-/* Portions of CPS.h */
-typedef struct CPSProcessSerNum {
-	UInt32 lo;
-	UInt32 hi;
-} CPSProcessSerNum;
-
-extern OSErr CPSGetCurrentProcess(CPSProcessSerNum* psn);
-extern OSErr CPSEnableForegroundOperation(CPSProcessSerNum* psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
-extern OSErr CPSSetFrontProcess(CPSProcessSerNum* psn);
-
-/* From Menus.h (according to Xcode Developer Documentation) */
-extern void ShowMenuBar(void);
-extern void HideMenuBar(void);
-
-/* Disables a warning. This is needed since the method exists but has been dropped from the header, supposedly as of 10.4. */
-#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
-@interface NSApplication(NSAppleMenu)
-- (void)setAppleMenu:(NSMenu *)menu;
-@end
-#endif
-
-
-/* Defined in ppc/param.h or i386/param.h included from sys/param.h */
-#undef ALIGN
-/* Defined in stdbool.h */
-#ifndef __cplusplus
-# ifndef __BEOS__
-#  undef bool
-#  undef false
-#  undef true
-# endif
-#endif
-
-
-#include "../stdafx.h"
-#include "../debug.h"
-#include "../macros.h"
-#include "../os/macosx/splash.h"
-#include "cocoa_v.h"
-#include "cocoa_keys.h"
-
-#undef Point
-#undef Rect
-
-/* Taken from ../gfx.h */
-extern bool _dbg_screen_rect;
-
-
-/* Subclass of NSWindow to fix genie effect and support resize events  */
-@interface OTTD_QuartzWindow : NSWindow
-- (void)miniaturize:(id)sender;
-- (void)display;
-- (void)setFrame:(NSRect)frameRect display:(BOOL)flag;
-- (void)appDidHide:(NSNotification*)note;
-- (void)appWillUnhide:(NSNotification*)note;
-- (void)appDidUnhide:(NSNotification*)note;
-- (id)initWithContentRect:(NSRect)contentRect styleMask:(unsigned int)styleMask backing:(NSBackingStoreType)backingType defer:(BOOL)flag;
-@end
-
-/* Delegate for our NSWindow to send ask for quit on close */
-@interface OTTD_QuartzWindowDelegate : NSObject
-- (BOOL)windowShouldClose:(id)sender;
-@end
-
-@interface OTTDMain : NSObject
-@end
-
-
-/* Structure for rez switch gamma fades
- * We can hide the monitor flicker by setting the gamma tables to 0
- */
-#define QZ_GAMMA_TABLE_SIZE 256
-
-typedef struct {
-	CGGammaValue red[QZ_GAMMA_TABLE_SIZE];
-	CGGammaValue green[QZ_GAMMA_TABLE_SIZE];
-	CGGammaValue blue[QZ_GAMMA_TABLE_SIZE];
-} OTTD_QuartzGammaTable;
-
-/* Add methods to get at private members of NSScreen.
- * Since there is a bug in Apple's screen switching code that does not update
- * this variable when switching to fullscreen, we'll set it manually (but only
- * for the main screen).
- */
-@interface NSScreen (NSScreenAccess)
-	- (void) setFrame:(NSRect)frame;
-@end
-
-@implementation NSScreen (NSScreenAccess)
-- (void) setFrame:(NSRect)frame;
-{
-	_frame = frame;
-}
-@end
-
-
-static void QZ_Draw(void);
-static void QZ_UnsetVideoMode(void);
-static void QZ_UpdatePalette(uint start, uint count);
-static void QZ_WarpCursor(int x, int y);
-static void QZ_ShowMouse(void);
-static void QZ_HideMouse(void);
-static void CocoaVideoFullScreen(bool full_screen);
-
-
-static NSAutoreleasePool *_ottd_autorelease_pool;
-static OTTDMain *_ottd_main;
-
-
-static struct CocoaVideoData {
-	bool isset;
-	bool issetting;
-
-	CGDirectDisplayID  display_id;         /* 0 == main display (only support single display) */
-	CFDictionaryRef    mode;               /* current mode of the display */
-	CFDictionaryRef    save_mode;          /* original mode of the display */
-	CFArrayRef         mode_list;          /* list of available fullscreen modes */
-	CGDirectPaletteRef palette;            /* palette of an 8-bit display */
-
-	uint32 device_width;
-	uint32 device_height;
-	uint32 device_bpp;
-
-	void *realpixels;
-	uint8 *pixels;
-	uint32 width;
-	uint32 height;
-	uint32 pitch;
-	bool fullscreen;
-
-	unsigned int current_mods;
-	bool tab_is_down;
-	bool emulating_right_button;
-
-	bool cursor_visible;
-	bool active;
-
-#ifdef _DEBUG
-	uint32 tEvent;
-#endif
-
-	OTTD_QuartzWindow *window;
-	NSQuickDrawView *qdview;
-
-#define MAX_DIRTY_RECTS 100
-	Rect dirty_rects[MAX_DIRTY_RECTS];
-	int num_dirty_rects;
-
-	uint16 palette16[256];
-	uint32 palette32[256];
-} _cocoa_video_data;
-
-static bool _cocoa_video_started = false;
-static bool _cocoa_video_dialog = false;
-
-
-
-
-/******************************************************************************
- *                             Game loop and accessories                      *
- ******************************************************************************/
-
-static uint32 GetTick(void)
-{
-	struct timeval tim;
-
-	gettimeofday(&tim, NULL);
-	return tim.tv_usec / 1000 + tim.tv_sec * 1000;
-}
-
-static void QZ_CheckPaletteAnim(void)
-{
-	if (_pal_last_dirty != -1) {
-		QZ_UpdatePalette(_pal_first_dirty, _pal_last_dirty - _pal_first_dirty + 1);
-		_pal_last_dirty = -1;
-	}
-}
-
-
-
-typedef struct VkMapping {
-	unsigned short vk_from;
-	byte map_to;
-} VkMapping;
-
-#define AS(x, z) {x, z}
-
-static const VkMapping _vk_mapping[] = {
-	AS(QZ_BACKQUOTE,  WKC_BACKQUOTE), // key left of '1'
-	AS(QZ_BACKQUOTE2, WKC_BACKQUOTE), // some keyboards have it on another scancode
-
-	// Pageup stuff + up/down
-	//AM(SDLK_PAGEUP, SDLK_PAGEDOWN, WKC_PAGEUP, WKC_PAGEDOWN),  <==== Does this include HOME/END?
-	AS(QZ_PAGEUP,   WKC_PAGEUP),
-	AS(QZ_PAGEDOWN, WKC_PAGEDOWN),
-
-	AS(QZ_UP,    WKC_UP),
-	AS(QZ_DOWN,  WKC_DOWN),
-	AS(QZ_LEFT,  WKC_LEFT),
-	AS(QZ_RIGHT, WKC_RIGHT),
-
-	AS(QZ_HOME, WKC_HOME),
-	AS(QZ_END,  WKC_END),
-
-	AS(QZ_INSERT, WKC_INSERT),
-	AS(QZ_DELETE, WKC_DELETE),
-
-	// Letters. QZ_[a-z] is not in numerical order so we can't use AM(...)
-	AS(QZ_a, 'A'),
-	AS(QZ_b, 'B'),
-	AS(QZ_c, 'C'),
-	AS(QZ_d, 'D'),
-	AS(QZ_e, 'E'),
-	AS(QZ_f, 'F'),
-	AS(QZ_g, 'G'),
-	AS(QZ_h, 'H'),
-	AS(QZ_i, 'I'),
-	AS(QZ_j, 'J'),
-	AS(QZ_k, 'K'),
-	AS(QZ_l, 'L'),
-	AS(QZ_m, 'M'),
-	AS(QZ_n, 'N'),
-	AS(QZ_o, 'O'),
-	AS(QZ_p, 'P'),
-	AS(QZ_q, 'Q'),
-	AS(QZ_r, 'R'),
-	AS(QZ_s, 'S'),
-	AS(QZ_t, 'T'),
-	AS(QZ_u, 'U'),
-	AS(QZ_v, 'V'),
-	AS(QZ_w, 'W'),
-	AS(QZ_x, 'X'),
-	AS(QZ_y, 'Y'),
-	AS(QZ_z, 'Z'),
-	// Same thing for digits
-	AS(QZ_0, '0'),
-	AS(QZ_1, '1'),
-	AS(QZ_2, '2'),
-	AS(QZ_3, '3'),
-	AS(QZ_4, '4'),
-	AS(QZ_5, '5'),
-	AS(QZ_6, '6'),
-	AS(QZ_7, '7'),
-	AS(QZ_8, '8'),
-	AS(QZ_9, '9'),
-
-	AS(QZ_ESCAPE,    WKC_ESC),
-	AS(QZ_PAUSE,     WKC_PAUSE),
-	AS(QZ_BACKSPACE, WKC_BACKSPACE),
-
-	AS(QZ_SPACE,  WKC_SPACE),
-	AS(QZ_RETURN, WKC_RETURN),
-	AS(QZ_TAB,    WKC_TAB),
-
-	// Function keys
-	AS(QZ_F1,  WKC_F1),
-	AS(QZ_F2,  WKC_F2),
-	AS(QZ_F3,  WKC_F3),
-	AS(QZ_F4,  WKC_F4),
-	AS(QZ_F5,  WKC_F5),
-	AS(QZ_F6,  WKC_F6),
-	AS(QZ_F7,  WKC_F7),
-	AS(QZ_F8,  WKC_F8),
-	AS(QZ_F9,  WKC_F9),
-	AS(QZ_F10, WKC_F10),
-	AS(QZ_F11, WKC_F11),
-	AS(QZ_F12, WKC_F12),
-
-	// Numeric part.
-	AS(QZ_KP0,         WKC_NUM_0),
-	AS(QZ_KP1,         WKC_NUM_1),
-	AS(QZ_KP2,         WKC_NUM_2),
-	AS(QZ_KP3,         WKC_NUM_3),
-	AS(QZ_KP4,         WKC_NUM_4),
-	AS(QZ_KP5,         WKC_NUM_5),
-	AS(QZ_KP6,         WKC_NUM_6),
-	AS(QZ_KP7,         WKC_NUM_7),
-	AS(QZ_KP8,         WKC_NUM_8),
-	AS(QZ_KP9,         WKC_NUM_9),
-	AS(QZ_KP_DIVIDE,   WKC_NUM_DIV),
-	AS(QZ_KP_MULTIPLY, WKC_NUM_MUL),
-	AS(QZ_KP_MINUS,    WKC_NUM_MINUS),
-	AS(QZ_KP_PLUS,     WKC_NUM_PLUS),
-	AS(QZ_KP_ENTER,    WKC_NUM_ENTER),
-	AS(QZ_KP_PERIOD,   WKC_NUM_DECIMAL)
-};
-
-
-static uint32 QZ_MapKey(unsigned short sym)
-{
-	const VkMapping *map;
-	uint32 key = 0;
-
-	for (map = _vk_mapping; map != endof(_vk_mapping); ++map) {
-		if (sym == map->vk_from) {
-			key = map->map_to;
-			break;
-		}
-	}
-
-	if (_cocoa_video_data.current_mods & NSShiftKeyMask)     key |= WKC_SHIFT;
-	if (_cocoa_video_data.current_mods & NSControlKeyMask)   key |= WKC_CTRL;
-	if (_cocoa_video_data.current_mods & NSAlternateKeyMask) key |= WKC_ALT;
-	if (_cocoa_video_data.current_mods & NSCommandKeyMask)   key |= WKC_META;
-
-	return key << 16;
-}
-
-static void QZ_KeyEvent(unsigned short keycode, unsigned short unicode, BOOL down)
-{
-	switch (keycode) {
-		case QZ_UP:    SB(_dirkeys, 1, 1, down); break;
-		case QZ_DOWN:  SB(_dirkeys, 3, 1, down); break;
-		case QZ_LEFT:  SB(_dirkeys, 0, 1, down); break;
-		case QZ_RIGHT: SB(_dirkeys, 2, 1, down); break;
-
-		case QZ_TAB: _cocoa_video_data.tab_is_down = down; break;
-
-		case QZ_RETURN:
-		case QZ_f:
-			if (down && (_cocoa_video_data.current_mods & NSCommandKeyMask)) {
-				CocoaVideoFullScreen(!_fullscreen);
-			}
-			break;
-	}
-
-	if (down) {
-		uint32 pressed_key = QZ_MapKey(keycode) | unicode;
-		HandleKeypress(pressed_key);
-		DEBUG(driver, 2, "cocoa_v: QZ_KeyEvent: %x (%x), down, mapping: %x", keycode, unicode, pressed_key);
-	} else {
-		DEBUG(driver, 2, "cocoa_v: QZ_KeyEvent: %x (%x), up", keycode, unicode);
-	}
-}
-
-static void QZ_DoUnsidedModifiers(unsigned int newMods)
-{
-	const int mapping[] = { QZ_CAPSLOCK, QZ_LSHIFT, QZ_LCTRL, QZ_LALT, QZ_LMETA };
-
-	int i;
-	int bit;
-
-	if (_cocoa_video_data.current_mods == newMods) return;
-
-	/* Iterate through the bits, testing each against the current modifiers */
-	for (i = 0, bit = NSAlphaShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) {
-		unsigned int currentMask, newMask;
-
-		currentMask = _cocoa_video_data.current_mods & bit;
-		newMask     = newMods & bit;
-
-		if (currentMask && currentMask != newMask) { /* modifier up event */
-			/* If this was Caps Lock, we need some additional voodoo to make SDL happy (is this needed in ottd?) */
-			if (bit == NSAlphaShiftKeyMask) QZ_KeyEvent(mapping[i], 0, YES);
-			QZ_KeyEvent(mapping[i], 0, NO);
-		} else if (newMask && currentMask != newMask) { /* modifier down event */
-			QZ_KeyEvent(mapping[i], 0, YES);
-			/* If this was Caps Lock, we need some additional voodoo to make SDL happy (is this needed in ottd?) */
-			if (bit == NSAlphaShiftKeyMask) QZ_KeyEvent(mapping[i], 0, NO);
-		}
-	}
-
-	_cocoa_video_data.current_mods = newMods;
-}
-
-static void QZ_MouseMovedEvent(int x, int y)
-{
-	if (_cursor.fix_at) {
-		int dx = x - _cursor.pos.x;
-		int dy = y - _cursor.pos.y;
-
-		if (dx != 0 || dy != 0) {
-			_cursor.delta.x += dx;
-			_cursor.delta.y += dy;
-
-			QZ_WarpCursor(_cursor.pos.x, _cursor.pos.y);
-		}
-	} else {
-		_cursor.delta.x = x - _cursor.pos.x;
-		_cursor.delta.y = y - _cursor.pos.y;
-		_cursor.pos.x = x;
-		_cursor.pos.y = y;
-		_cursor.dirty = true;
-	}
-	HandleMouseEvents();
-}
-
-
-static void QZ_MouseButtonEvent(int button, BOOL down)
-{
-	switch (button) {
-		case 0:
-			if (down) {
-				_left_button_down = true;
-			} else {
-				_left_button_down = false;
-				_left_button_clicked = false;
-			}
-			HandleMouseEvents();
-			break;
-
-		case 1:
-			if (down) {
-				_right_button_down = true;
-				_right_button_clicked = true;
-			} else {
-				_right_button_down = false;
-			}
-			HandleMouseEvents();
-			break;
-	}
-}
-
-
-static inline NSPoint QZ_GetMouseLocation(NSEvent *event)
-{
-	NSPoint pt;
-
-	if (_cocoa_video_data.fullscreen) {
-		pt = [ NSEvent mouseLocation ];
-		pt.y = _cocoa_video_data.height - pt.y;
-	} else {
-		pt = [event locationInWindow];
-		pt = [_cocoa_video_data.qdview convertPoint:pt fromView:nil];
-	}
-
-	return pt;
-}
-
-static bool QZ_MouseIsInsideView(NSPoint *pt)
-{
-	if (_cocoa_video_data.fullscreen) {
-		return pt->x >= 0 && pt->y >= 0 && pt->x < _cocoa_video_data.width && pt->y < _cocoa_video_data.height;
-	} else {
-		return [ _cocoa_video_data.qdview mouse:*pt inRect:[ _cocoa_video_data.qdview bounds ] ];
-	}
-}
-
-
-static bool QZ_PollEvent(void)
-{
-	NSEvent *event;
-	NSPoint pt;
-	NSString *chars;
-#ifdef _DEBUG
-	uint32 et0, et;
-#endif
-
-#ifdef _DEBUG
-	et0 = GetTick();
-#endif
-	event = [ NSApp nextEventMatchingMask:NSAnyEventMask
-			untilDate: [ NSDate distantPast ]
-			inMode: NSDefaultRunLoopMode dequeue:YES ];
-#ifdef _DEBUG
-	et = GetTick();
-	_cocoa_video_data.tEvent+= et - et0;
-#endif
-
-	if (event == nil) return false;
-	if (!_cocoa_video_data.active) {
-		QZ_ShowMouse();
-		[NSApp sendEvent:event];
-		return true;
-	}
-
-	QZ_DoUnsidedModifiers( [ event modifierFlags ] );
-
-	switch ([event type]) {
-		case NSMouseMoved:
-		case NSOtherMouseDragged:
-		case NSRightMouseDragged:
-		case NSLeftMouseDragged:
-			pt = QZ_GetMouseLocation(event);
-			if (!QZ_MouseIsInsideView(&pt) &&
-					!_cocoa_video_data.emulating_right_button) {
-				QZ_ShowMouse();
-				[NSApp sendEvent:event];
-				break;
-			}
-
-			QZ_HideMouse();
-			QZ_MouseMovedEvent((int)pt.x, (int)pt.y);
-			break;
-
-		case NSLeftMouseDown:
-			if (!([ event modifierFlags ] & NSCommandKeyMask) ||
-					!QZ_MouseIsInsideView(&pt)) {
-				[NSApp sendEvent:event];
-			}
-
-			pt = QZ_GetMouseLocation(event);
-			if (!QZ_MouseIsInsideView(&pt)) {
-				QZ_ShowMouse();
-				break;
-			}
-
-			QZ_HideMouse();
-			QZ_MouseMovedEvent((int)pt.x, (int)pt.y);
-
-			/* Right mouse button emulation */
-			if ([ event modifierFlags ] & NSCommandKeyMask) {
-				_cocoa_video_data.emulating_right_button = true;
-				QZ_MouseButtonEvent(1, YES);
-			} else {
-				QZ_MouseButtonEvent(0, YES);
-			}
-			break;
-
-		case NSLeftMouseUp:
-			[NSApp sendEvent:event];
-
-			pt = QZ_GetMouseLocation(event);
-			if (!QZ_MouseIsInsideView(&pt)) {
-				QZ_ShowMouse();
-				break;
-			}
-
-			QZ_HideMouse();
-			QZ_MouseMovedEvent((int)pt.x, (int)pt.y);
-
-			/* Right mouse button emulation */
-			if (_cocoa_video_data.emulating_right_button) {
-				_cocoa_video_data.emulating_right_button = false;
-				QZ_MouseButtonEvent(1, NO);
-			} else {
-				QZ_MouseButtonEvent(0, NO);
-			}
-			break;
-
-		case NSRightMouseDown:
-			pt = QZ_GetMouseLocation(event);
-			if (!QZ_MouseIsInsideView(&pt)) {
-				QZ_ShowMouse();
-				[NSApp sendEvent:event];
-				break;
-			}
-
-			QZ_HideMouse();
-			QZ_MouseMovedEvent((int)pt.x, (int)pt.y);
-			QZ_MouseButtonEvent(1, YES);
-			break;
-
-		case NSRightMouseUp:
-			pt = QZ_GetMouseLocation(event);
-			if (!QZ_MouseIsInsideView(&pt)) {
-				QZ_ShowMouse();
-				[NSApp sendEvent:event];
-				break;
-			}
-
-			QZ_HideMouse();
-			QZ_MouseMovedEvent((int)pt.x, (int)pt.y);
-			QZ_MouseButtonEvent(1, NO);
-			break;
-
-#if 0
-		/* This is not needed since openttd currently only use two buttons */
-		case NSOtherMouseDown:
-			pt = QZ_GetMouseLocation(event);
-			if (!QZ_MouseIsInsideView(&pt)) {
-				QZ_ShowMouse();
-				[NSApp sendEvent:event];
-				break;
-			}
-
-			QZ_HideMouse();
-			QZ_MouseMovedEvent((int)pt.x, (int)pt.y);
-			QZ_MouseButtonEvent([ event buttonNumber ], YES);
-			break;
-
-		case NSOtherMouseUp:
-			pt = QZ_GetMouseLocation(event);
-			if (!QZ_MouseIsInsideView(&pt)) {
-				QZ_ShowMouse();
-				[NSApp sendEvent:event];
-				break;
-			}
-
-			QZ_HideMouse();
-			QZ_MouseMovedEvent((int)pt.x, (int)pt.y);
-			QZ_MouseButtonEvent([ event buttonNumber ], NO);
-			break;
-#endif
-
-		case NSKeyDown:
-			/* Quit, hide and minimize */
-			switch ([event keyCode]) {
-				case QZ_q:
-				case QZ_h:
-				case QZ_m:
-					if ([ event modifierFlags ] & NSCommandKeyMask) {
-						[NSApp sendEvent:event];
-					}
-					break;
-			}
-
-			chars = [ event characters ];
-			QZ_KeyEvent([event keyCode], [ chars length ] ? [ chars characterAtIndex:0 ] : 0, YES);
-			break;
-
-		case NSKeyUp:
-			/* Quit, hide and minimize */
-			switch ([event keyCode]) {
-				case QZ_q:
-				case QZ_h:
-				case QZ_m:
-					if ([ event modifierFlags ] & NSCommandKeyMask) {
-						[NSApp sendEvent:event];
-					}
-					break;
-			}
-
-			chars = [ event characters ];
-			QZ_KeyEvent([event keyCode], [ chars length ] ? [ chars characterAtIndex:0 ] : 0, NO);
-			break;
-
-		case NSScrollWheel:
-			if ([ event deltaY ] > 0.0) { /* Scroll up */
-				_cursor.wheel--;
-			} else if ([ event deltaY ] < 0.0) { /* Scroll down */
-				_cursor.wheel++;
-			} /* else: deltaY was 0.0 and we don't want to do anything */
-			break;
-
-		default:
-			[NSApp sendEvent:event];
-	}
-
-	return true;
-}
-
-
-static void QZ_GameLoop(void)
-{
-	uint32 cur_ticks = GetTick();
-	uint32 next_tick = cur_ticks + 30;
-	uint32 pal_tick = 0;
-#ifdef _DEBUG
-	uint32 et0, et, st0, st;
-#endif
-	int i;
-
-#ifdef _DEBUG
-	et0 = GetTick();
-	st = 0;
-#endif
-
-	_screen.dst_ptr = _cocoa_video_data.pixels;
-	DisplaySplashImage();
-	QZ_CheckPaletteAnim();
-	QZ_Draw();
-	CSleep(1);
-
-	for (i = 0; i < 2; i++) GameLoop();
-
-	_screen.dst_ptr = _cocoa_video_data.pixels;
-	UpdateWindows();
-	QZ_CheckPaletteAnim();
-	QZ_Draw();
-	CSleep(1);
-
-	for (;;) {
-		uint32 prev_cur_ticks = cur_ticks; // to check for wrapping
-		InteractiveRandom(); // randomness
-
-		while (QZ_PollEvent()) {}
-
-		if (_exit_game) break;
-
-#if defined(_DEBUG)
-		if (_cocoa_video_data.current_mods & NSShiftKeyMask)
-#else
-		if (_cocoa_video_data.tab_is_down)
-#endif
-		{
-			if (!_networking && _game_mode != GM_MENU) _fast_forward |= 2;
-		} else if (_fast_forward & 2) {
-			_fast_forward = 0;
-		}
-
-		cur_ticks = GetTick();
-		if (cur_ticks >= next_tick || (_fast_forward && !_pause) || cur_ticks < prev_cur_ticks) {
-			next_tick = cur_ticks + 30;
-
-			_ctrl_pressed = !!(_cocoa_video_data.current_mods & NSControlKeyMask);
-			_shift_pressed = !!(_cocoa_video_data.current_mods & NSShiftKeyMask);
-#ifdef _DEBUG
-			_dbg_screen_rect = !!(_cocoa_video_data.current_mods & NSAlphaShiftKeyMask);
-#endif
-
-			GameLoop();
-
-			_screen.dst_ptr = _cocoa_video_data.pixels;
-			UpdateWindows();
-			if (++pal_tick > 4) {
-				QZ_CheckPaletteAnim();
-				pal_tick = 1;
-			}
-			QZ_Draw();
-		} else {
-#ifdef _DEBUG
-			st0 = GetTick();
-#endif
-			CSleep(1);
-#ifdef _DEBUG
-			st += GetTick() - st0;
-#endif
-			_screen.dst_ptr = _cocoa_video_data.pixels;
-			DrawTextMessage();
-			DrawMouseCursor();
-			QZ_Draw();
-		}
-	}
-
-#ifdef _DEBUG
-	et = GetTick();
-
-	DEBUG(driver, 1, "cocoa_v: nextEventMatchingMask took %i ms total", _cocoa_video_data.tEvent);
-	DEBUG(driver, 1, "cocoa_v: game loop took %i ms total (%i ms without sleep)", et - et0, et - et0 - st);
-	DEBUG(driver, 1, "cocoa_v: (nextEventMatchingMask total)/(game loop total) is %f%%", (double)_cocoa_video_data.tEvent / (double)(et - et0) * 100);
-	DEBUG(driver, 1, "cocoa_v: (nextEventMatchingMask total)/(game loop without sleep total) is %f%%", (double)_cocoa_video_data.tEvent / (double)(et - et0 - st) * 100);
-#endif
-}
-
-
-/******************************************************************************
- *                             Windowed mode                                  *
- ******************************************************************************/
-
-/* This function makes the *game region* of the window 100% opaque.
- * The genie effect uses the alpha component. Otherwise,
- * it doesn't seem to matter what value it has.
- */
-static void QZ_SetPortAlphaOpaque(void)
-{
-	if (_cocoa_video_data.device_bpp == 32) {
-		uint32* pixels = (uint32*)_cocoa_video_data.realpixels;
-		uint32 rowPixels = _cocoa_video_data.pitch / 4;
-		uint32 i;
-		uint32 j;
-
-		for (i = 0; i < _cocoa_video_data.height; i++)
-			for (j = 0; j < _cocoa_video_data.width; j++) {
-			pixels[i * rowPixels + j] |= 0xFF000000;
-		}
-	}
-}
-
-
-@implementation OTTD_QuartzWindow
-
-/* we override these methods to fix the miniaturize animation/dock icon bug */
-- (void)miniaturize:(id)sender
-{
-	/* make the alpha channel opaque so anim won't have holes in it */
-	QZ_SetPortAlphaOpaque ();
-
-	/* window is hidden now */
-	_cocoa_video_data.active = false;
-
-	QZ_ShowMouse();
-
-	[ super miniaturize:sender ];
-}
-
-- (void)display
-{
-	/* This method fires just before the window deminaturizes from the Dock.
-	 * We'll save the current visible surface, let the window manager redraw any
-	 * UI elements, and restore the surface. This way, no expose event
-	 * is required, and the deminiaturize works perfectly.
-	 */
-
-	QZ_SetPortAlphaOpaque();
-
-	/* save current visible surface */
-	[ self cacheImageInRect:[ _cocoa_video_data.qdview frame ] ];
-
-	/* let the window manager redraw controls, border, etc */
-	[ super display ];
-
-	/* restore visible surface */
-	[ self restoreCachedImage ];
-
-	/* window is visible again */
-	_cocoa_video_data.active = true;
-}
-
-- (void)setFrame:(NSRect)frameRect display:(BOOL)flag
-{
-	NSRect newViewFrame;
-	CGrafPtr thePort;
-
-	[ super setFrame:frameRect display:flag ];
-
-	/* Don't do anything if the window is currently beign created */
-	if (_cocoa_video_data.issetting) return;
-
-	if (_cocoa_video_data.window == nil) return;
-
-	newViewFrame = [ _cocoa_video_data.qdview frame ];
-
-	/* Update the pixels and pitch */
-	thePort = [ _cocoa_video_data.qdview qdPort ];
-	LockPortBits(thePort);
-
-	_cocoa_video_data.realpixels = GetPixBaseAddr(GetPortPixMap(thePort));
-	_cocoa_video_data.pitch      = GetPixRowBytes(GetPortPixMap(thePort));
-
-	/* _cocoa_video_data.realpixels now points to the window's pixels
-	 * We want it to point to the *view's* pixels
-	 */
-	{
-		int vOffset = [ _cocoa_video_data.window frame ].size.height - newViewFrame.size.height - newViewFrame.origin.y;
-		int hOffset = newViewFrame.origin.x;
-
-		_cocoa_video_data.realpixels = (uint8*)_cocoa_video_data.realpixels + (vOffset * _cocoa_video_data.pitch) + hOffset * (_cocoa_video_data.device_bpp / 8);
-	}
-
-	UnlockPortBits(thePort);
-
-	/* Allocate new buffer */
-	free(_cocoa_video_data.pixels);
-	_cocoa_video_data.pixels = (uint8*)malloc(newViewFrame.size.width * newViewFrame.size.height);
-	assert(_cocoa_video_data.pixels != NULL);
-
-
-	/* Tell the game that the resolution changed */
-	_cocoa_video_data.width = newViewFrame.size.width;
-	_cocoa_video_data.height = newViewFrame.size.height;
-
-	_screen.width = _cocoa_video_data.width;
-	_screen.height = _cocoa_video_data.height;
-	_screen.pitch = _cocoa_video_data.width;
-
-	GameSizeChanged();
-
-	/* Redraw screen */
-	_cocoa_video_data.num_dirty_rects = MAX_DIRTY_RECTS;
-}
-
-- (void)appDidHide:(NSNotification*)note
-{
-	_cocoa_video_data.active = false;
-}
-
-
-- (void)appWillUnhide:(NSNotification*)note
-{
-	QZ_SetPortAlphaOpaque ();
-
-	/* save current visible surface */
-	[ self cacheImageInRect:[ _cocoa_video_data.qdview frame ] ];
-}
-
-- (void)appDidUnhide:(NSNotification*)note
-{
-	/* restore cached image, since it may not be current, post expose event too */
-	[ self restoreCachedImage ];
-
-	_cocoa_video_data.active = true;
-}
-
-
-- (id)initWithContentRect:(NSRect)contentRect styleMask:(unsigned int)styleMask backing:(NSBackingStoreType)backingType defer:(BOOL)flag
-{
-	/* Make our window subclass receive these application notifications */
-	[ [ NSNotificationCenter defaultCenter ] addObserver:self
-	selector:@selector(appDidHide:) name:NSApplicationDidHideNotification object:NSApp ];
-
-	[ [ NSNotificationCenter defaultCenter ] addObserver:self
-	selector:@selector(appDidUnhide:) name:NSApplicationDidUnhideNotification object:NSApp ];
-
-	[ [ NSNotificationCenter defaultCenter ] addObserver:self
-	selector:@selector(appWillUnhide:) name:NSApplicationWillUnhideNotification object:NSApp ];
-
-	return [ super initWithContentRect:contentRect styleMask:styleMask backing:backingType defer:flag ];
-}
-
-@end
-
-@implementation OTTD_QuartzWindowDelegate
-- (BOOL)windowShouldClose:(id)sender
-{
-	HandleExitGameRequest();
-
-	return NO;
-}
-
-- (void)windowDidBecomeKey:(NSNotification*)aNotification
-{
-	_cocoa_video_data.active = true;
-}
-
-- (void)windowDidResignKey:(NSNotification*)aNotification
-{
-	_cocoa_video_data.active = false;
-}
-
-- (void)windowDidBecomeMain:(NSNotification*)aNotification
-{
-	_cocoa_video_data.active = true;
-}
-
-- (void)windowDidResignMain:(NSNotification*)aNotification
-{
-	_cocoa_video_data.active = false;
-}
-
-@end
-
-
-static void QZ_UpdateWindowPalette(uint start, uint count)
-{
-	uint i;
-
-	switch (_cocoa_video_data.device_bpp) {
-		case 32:
-			for (i = start; i < start + count; i++) {
-				uint32 clr32 = 0xff000000;
-				clr32 |= (uint32)_cur_palette[i].r << 16;
-				clr32 |= (uint32)_cur_palette[i].g << 8;
-				clr32 |= (uint32)_cur_palette[i].b;
-				_cocoa_video_data.palette32[i] = clr32;
-			}
-			break;
-		case 16:
-			for (i = start; i < start + count; i++) {
-				uint16 clr16 = 0x0000;
-				clr16 |= (uint16)((_cur_palette[i].r >> 3) & 0x1f) << 10;
-				clr16 |= (uint16)((_cur_palette[i].g >> 3) & 0x1f) << 5;
-				clr16 |= (uint16)((_cur_palette[i].b >> 3) & 0x1f);
-				_cocoa_video_data.palette16[i] = clr16;
-			}
-			break;
-	}
-
-	_cocoa_video_data.num_dirty_rects = MAX_DIRTY_RECTS;
-}
-
-static inline void QZ_WindowBlitIndexedPixelsToView32(uint left, uint top, uint right, uint bottom)
-{
-	const uint32* pal = _cocoa_video_data.palette32;
-	const uint8* src = _cocoa_video_data.pixels;
-	uint32* dst = (uint32*)_cocoa_video_data.realpixels;
-	uint width = _cocoa_video_data.width;
-	uint pitch = _cocoa_video_data.pitch / 4;
-	uint x;
-	uint y;
-
-	for (y = top; y < bottom; y++) {
-		for (x = left; x < right; x++) {
-			dst[y * pitch + x] = pal[src[y * width + x]];
-		}
-	}
-}
-
-static inline void QZ_WindowBlitIndexedPixelsToView16(uint left, uint top, uint right, uint bottom)
-{
-	const uint16* pal = _cocoa_video_data.palette16;
-	const uint8* src = _cocoa_video_data.pixels;
-	uint16* dst = (uint16*)_cocoa_video_data.realpixels;
-	uint width = _cocoa_video_data.width;
-	uint pitch = _cocoa_video_data.pitch / 2;
-	uint x;
-	uint y;
-
-	for (y = top; y < bottom; y++) {
-		for (x = left; x < right; x++) {
-			dst[y * pitch + x] = pal[src[y * width + x]];
-		}
-	}
-}
-
-static inline void QZ_WindowBlitIndexedPixelsToView(int left, int top, int right, int bottom)
-{
-	switch (_cocoa_video_data.device_bpp) {
-		case 32: QZ_WindowBlitIndexedPixelsToView32(left, top, right, bottom); break;
-		case 16: QZ_WindowBlitIndexedPixelsToView16(left, top, right, bottom); break;
-	}
-}
-
-static bool _resize_icon[] = {
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1,
-	0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1,
-	0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0,
-	0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0,
-	0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1,
-	0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1,
-	0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0,
-	1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0
-};
-
-static void QZ_DrawResizeIcon(void)
-{
-	int xoff = _cocoa_video_data.width - 16;
-	int yoff = _cocoa_video_data.height - 16;
-	int x;
-	int y;
-
-	for (y = 0; y < 16; y++) {
-		uint16* trg16 = (uint16*)_cocoa_video_data.realpixels + (yoff + y) * _cocoa_video_data.pitch / 2 + xoff;
-		uint32* trg32 = (uint32*)_cocoa_video_data.realpixels + (yoff + y) * _cocoa_video_data.pitch / 4 + xoff;
-
-		for (x = 0; x < 16; x++, trg16++, trg32++) {
-			if (!_resize_icon[y * 16 + x]) continue;
-
-			switch (_cocoa_video_data.device_bpp) {
-				case 32: *trg32 = 0xff000000; break;
-				case 16: *trg16 = 0x0000;     break;
-			}
-		}
-	}
-}
-
-static void QZ_DrawWindow(void)
-{
-	int i;
-	RgnHandle dirty, temp;
-
-	/* Check if we need to do anything */
-	if (_cocoa_video_data.num_dirty_rects == 0 ||
-			[ _cocoa_video_data.window isMiniaturized ]) {
-		return;
-	}
-
-	if (_cocoa_video_data.num_dirty_rects >= MAX_DIRTY_RECTS) {
-		_cocoa_video_data.num_dirty_rects = 1;
-		_cocoa_video_data.dirty_rects[0].left = 0;
-		_cocoa_video_data.dirty_rects[0].top = 0;
-		_cocoa_video_data.dirty_rects[0].right = _cocoa_video_data.width;
-		_cocoa_video_data.dirty_rects[0].bottom = _cocoa_video_data.height;
-	}
-
-	dirty = NewRgn();
-	temp  = NewRgn();
-
-	SetEmptyRgn(dirty);
-
-	/* Build the region of dirty rectangles */
-	for (i = 0; i < _cocoa_video_data.num_dirty_rects; i++) {
-		QZ_WindowBlitIndexedPixelsToView(
-			_cocoa_video_data.dirty_rects[i].left,
-			_cocoa_video_data.dirty_rects[i].top,
-			_cocoa_video_data.dirty_rects[i].right,
-			_cocoa_video_data.dirty_rects[i].bottom
-		);
-
-		MacSetRectRgn(
-			temp,
-			_cocoa_video_data.dirty_rects[i].left,
-			_cocoa_video_data.dirty_rects[i].top,
-			_cocoa_video_data.dirty_rects[i].right,
-			_cocoa_video_data.dirty_rects[i].bottom
-		);
-		MacUnionRgn(dirty, temp, dirty);
-	}
-
-	QZ_DrawResizeIcon();
-
-	/* Flush the dirty region */
-	QDFlushPortBuffer([ _cocoa_video_data.qdview qdPort ], dirty);
-	DisposeRgn(dirty);
-	DisposeRgn(temp);
-
-	_cocoa_video_data.num_dirty_rects = 0;
-}
-
-
-extern const char _openttd_revision[];
-
-static const char* QZ_SetVideoWindowed(uint width, uint height)
-{
-	char caption[50];
-	NSString *nsscaption;
-	unsigned int style;
-	NSRect contentRect;
-	BOOL isCustom = NO;
-
-	if (width > _cocoa_video_data.device_width)
-		width = _cocoa_video_data.device_width;
-	if (height > _cocoa_video_data.device_height)
-		height = _cocoa_video_data.device_height;
-
-	_cocoa_video_data.width = width;
-	_cocoa_video_data.height = height;
-
-	contentRect = NSMakeRect(0, 0, width, height);
-
-	/* Check if we should completely destroy the previous mode
-	 * - If it is fullscreen
-	 */
-	if (_cocoa_video_data.isset && _cocoa_video_data.fullscreen)
-		QZ_UnsetVideoMode();
-
-	/* Check if we should recreate the window */
-	if (_cocoa_video_data.window == nil) {
-		/* Set the window style */
-		style = NSTitledWindowMask;
-		style |= (NSMiniaturizableWindowMask | NSClosableWindowMask);
-		style |= NSResizableWindowMask;
-
-		/* Manually create a window, avoids having a nib file resource */
-		_cocoa_video_data.window = [ [ OTTD_QuartzWindow alloc ]
-										initWithContentRect:contentRect
-										styleMask:style
-										backing:NSBackingStoreBuffered
-										defer:NO ];
-
-		if (_cocoa_video_data.window == nil)
-			return "Could not create the Cocoa window";
-
-		snprintf(caption, sizeof(caption), "OpenTTD %s", _openttd_revision);
-		nsscaption = [ [ NSString alloc ] initWithCString:caption ];
-		[ _cocoa_video_data.window setTitle:nsscaption ];
-		[ _cocoa_video_data.window setMiniwindowTitle:nsscaption ];
-		[ nsscaption release ];
-
-		[ _cocoa_video_data.window setAcceptsMouseMovedEvents:YES ];
-		[ _cocoa_video_data.window setViewsNeedDisplay:NO ];
-
-		[ _cocoa_video_data.window setDelegate: [ [ [ OTTD_QuartzWindowDelegate alloc ] init ] autorelease ] ];
-	} else {
-		/* We already have a window, just change its size */
-		if (!isCustom) {
-			[ _cocoa_video_data.window setContentSize:contentRect.size ];
-			[ _cocoa_video_data.qdview setFrameSize:contentRect.size ];
-		}
-	}
-
-	[ _cocoa_video_data.window center ];
-
-	/* Only recreate the view if it doesn't already exist */
-	if (_cocoa_video_data.qdview == nil) {
-		_cocoa_video_data.qdview = [ [ NSQuickDrawView alloc ] initWithFrame:contentRect ];
-		[ _cocoa_video_data.qdview setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ];
-		[ [ _cocoa_video_data.window contentView ] addSubview:_cocoa_video_data.qdview ];
-		[ _cocoa_video_data.qdview release ];
-		[ _cocoa_video_data.window makeKeyAndOrderFront:nil ];
-	}
-
-	LockPortBits([ _cocoa_video_data.qdview qdPort ]);
-	_cocoa_video_data.realpixels = GetPixBaseAddr(GetPortPixMap([ _cocoa_video_data.qdview qdPort ]));
-	_cocoa_video_data.pitch = GetPixRowBytes(GetPortPixMap([ _cocoa_video_data.qdview qdPort ]));
-	UnlockPortBits([ _cocoa_video_data.qdview qdPort ]);
-
-	/* _cocoa_video_data.realpixels now points to the window's pixels
-	 * We want it to point to the *view's* pixels
-	 */
-	{
-		int vOffset = [ _cocoa_video_data.window frame ].size.height - [ _cocoa_video_data.qdview frame ].size.height - [ _cocoa_video_data.qdview frame ].origin.y;
-		int hOffset = [ _cocoa_video_data.qdview frame ].origin.x;
-
-		_cocoa_video_data.realpixels = (uint8*)_cocoa_video_data.realpixels + (vOffset * _cocoa_video_data.pitch) + hOffset * (_cocoa_video_data.device_bpp / 8);
-	}
-
-	free(_cocoa_video_data.pixels);
-	_cocoa_video_data.pixels = (uint8*)malloc(width * height);
-	if (_cocoa_video_data.pixels == NULL) return "Failed to allocate 8-bit buffer";
-
-	_cocoa_video_data.fullscreen = false;
-
-	return NULL;
-}
-
-
-/******************************************************************************
- *                             Fullscreen mode                                *
- ******************************************************************************/
-
-/* Gamma functions to try to hide the flash from a rez switch
- * Fade the display from normal to black
- * Save gamma tables for fade back to normal
- */
-static uint32 QZ_FadeGammaOut(OTTD_QuartzGammaTable* table)
-{
-	CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE];
-	CGGammaValue greenTable[QZ_GAMMA_TABLE_SIZE];
-	CGGammaValue blueTable[QZ_GAMMA_TABLE_SIZE];
-	float percent;
-	int j;
-	unsigned int actual;
-
-	if (CGGetDisplayTransferByTable(
-				_cocoa_video_data.display_id, QZ_GAMMA_TABLE_SIZE,
-				table->red, table->green, table->blue, &actual
-			) != CGDisplayNoErr ||
-			actual != QZ_GAMMA_TABLE_SIZE) {
-		return 1;
-	}
-
-	memcpy(redTable,   table->red,   sizeof(redTable));
-	memcpy(greenTable, table->green, sizeof(greenTable));
-	memcpy(blueTable,  table->blue,  sizeof(greenTable));
-
-	for (percent = 1.0; percent >= 0.0; percent -= 0.01) {
-		for (j = 0; j < QZ_GAMMA_TABLE_SIZE; j++) {
-			redTable[j]   = redTable[j]   * percent;
-			greenTable[j] = greenTable[j] * percent;
-			blueTable[j]  = blueTable[j]  * percent;
-		}
-
-		if (CGSetDisplayTransferByTable(
-					_cocoa_video_data.display_id, QZ_GAMMA_TABLE_SIZE,
-					redTable, greenTable, blueTable
-				) != CGDisplayNoErr) {
-			CGDisplayRestoreColorSyncSettings();
-			return 1;
-		}
-
-		CSleep(10);
-	}
-
-	return 0;
-}
-
-/* Fade the display from black to normal
- * Restore previously saved gamma values
- */
-static uint32 QZ_FadeGammaIn(const OTTD_QuartzGammaTable* table)
-{
-	CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE];
-	CGGammaValue greenTable[QZ_GAMMA_TABLE_SIZE];
-	CGGammaValue blueTable[QZ_GAMMA_TABLE_SIZE];
-	float percent;
-	int j;
-
-	memset(redTable, 0, sizeof(redTable));
-	memset(greenTable, 0, sizeof(greenTable));
-	memset(blueTable, 0, sizeof(greenTable));
-
-	for (percent = 0.0; percent <= 1.0; percent += 0.01) {
-		for (j = 0; j < QZ_GAMMA_TABLE_SIZE; j++) {
-			redTable[j]   = table->red[j]   * percent;
-			greenTable[j] = table->green[j] * percent;
-			blueTable[j]  = table->blue[j]  * percent;
-		}
-
-		if (CGSetDisplayTransferByTable(
-					_cocoa_video_data.display_id, QZ_GAMMA_TABLE_SIZE,
-					redTable, greenTable, blueTable
-				) != CGDisplayNoErr) {
-			CGDisplayRestoreColorSyncSettings();
-			return 1;
-		}
-
-		CSleep(10);
-	}
-
-	return 0;
-}
-
-static const char* QZ_SetVideoFullScreen(int width, int height)
-{
-	const char* errstr = "QZ_SetVideoFullScreen error";
-	int exact_match;
-	CFNumberRef number;
-	int bpp;
-	int gamma_error;
-	OTTD_QuartzGammaTable gamma_table;
-	NSRect screen_rect;
-	CGError error;
-	NSPoint pt;
-
-	/* Destroy any previous mode */
-	if (_cocoa_video_data.isset) QZ_UnsetVideoMode();
-
-	/* See if requested mode exists */
-	_cocoa_video_data.mode = CGDisplayBestModeForParameters(_cocoa_video_data.display_id, 8, width, height, &exact_match);
-
-	/* If the mode wasn't an exact match, check if it has the right bpp, and update width and height */
-	if (!exact_match) {
-		number = CFDictionaryGetValue (_cocoa_video_data.mode, kCGDisplayBitsPerPixel);
-		CFNumberGetValue(number, kCFNumberSInt32Type, &bpp);
-		if (bpp != 8) {
-			errstr = "Failed to find display resolution";
-			goto ERR_NO_MATCH;
-		}
-
-		number = CFDictionaryGetValue(_cocoa_video_data.mode, kCGDisplayWidth);
-		CFNumberGetValue(number, kCFNumberSInt32Type, &width);
-
-		number = CFDictionaryGetValue(_cocoa_video_data.mode, kCGDisplayHeight);
-		CFNumberGetValue(number, kCFNumberSInt32Type, &height);
-	}
-
-	/* Fade display to zero gamma */
-	gamma_error = QZ_FadeGammaOut(&gamma_table);
-
-	/* Put up the blanking window (a window above all other windows) */
-	error = CGDisplayCapture(_cocoa_video_data.display_id);
-
-	if (CGDisplayNoErr != error) {
-		errstr = "Failed capturing display";
-		goto ERR_NO_CAPTURE;
-	}
-
-	/* Do the physical switch */
-	if (CGDisplaySwitchToMode(_cocoa_video_data.display_id, _cocoa_video_data.mode) != CGDisplayNoErr) {
-		errstr = "Failed switching display resolution";
-		goto ERR_NO_SWITCH;
-	}
-
-	_cocoa_video_data.realpixels = (uint8*)CGDisplayBaseAddress(_cocoa_video_data.display_id);
-	_cocoa_video_data.pitch  = CGDisplayBytesPerRow(_cocoa_video_data.display_id);
-
-	_cocoa_video_data.width = CGDisplayPixelsWide(_cocoa_video_data.display_id);
-	_cocoa_video_data.height = CGDisplayPixelsHigh(_cocoa_video_data.display_id);
-	_cocoa_video_data.fullscreen = true;
-
-	/* Setup double-buffer emulation */
-	_cocoa_video_data.pixels = (uint8*)malloc(width * height);
-	if (_cocoa_video_data.pixels == NULL) {
-		errstr = "Failed to allocate memory for double buffering";
-		goto ERR_DOUBLEBUF;
-	}
-
-	if (!CGDisplayCanSetPalette(_cocoa_video_data.display_id)) {
-		errstr = "Not an indexed display mode.";
-		goto ERR_NOT_INDEXED;
-	}
-
-	/* If we don't hide menu bar, it will get events and interrupt the program */
-	HideMenuBar();
-
-	/* Fade the display to original gamma */
-	if (!gamma_error) QZ_FadeGammaIn(&gamma_table);
-
-	/* There is a bug in Cocoa where NSScreen doesn't synchronize
-	 * with CGDirectDisplay, so the main screen's frame is wrong.
-	 * As a result, coordinate translation produces incorrect results.
-	 * We can hack around this bug by setting the screen rect ourselves.
-	 * This hack should be removed if/when the bug is fixed.
-	 */
-	screen_rect = NSMakeRect(0, 0, width, height);
-	[ [ NSScreen mainScreen ] setFrame:screen_rect ];
-
-	/* we're fullscreen, so flag all input states... */
-	_cocoa_video_data.active = true;
-
-
-	pt = [ NSEvent mouseLocation ];
-	pt.y = CGDisplayPixelsHigh(_cocoa_video_data.display_id) - pt.y;
-	if (QZ_MouseIsInsideView(&pt)) QZ_HideMouse();
-
-	return NULL;
-
-/* Since the blanking window covers *all* windows (even force quit) correct recovery is crucial */
-ERR_NOT_INDEXED:
-	free(_cocoa_video_data.pixels);
-	_cocoa_video_data.pixels = NULL;
-ERR_DOUBLEBUF:
-	CGDisplaySwitchToMode(_cocoa_video_data.display_id, _cocoa_video_data.save_mode);
-ERR_NO_SWITCH:
-	CGReleaseAllDisplays();
-ERR_NO_CAPTURE:
-	if (!gamma_error) QZ_FadeGammaIn(&gamma_table);
-ERR_NO_MATCH:
-	return errstr;
-}
-
-
-static void QZ_UpdateFullscreenPalette(uint first_color, uint num_colors)
-{
-	CGTableCount  index;
-	CGDeviceColor color;
-
-	for (index = first_color; index < first_color+num_colors; index++) {
-		/* Clamp colors between 0.0 and 1.0 */
-		color.red   = _cur_palette[index].r / 255.0;
-		color.blue  = _cur_palette[index].b / 255.0;
-		color.green = _cur_palette[index].g / 255.0;
-
-		CGPaletteSetColorAtIndex(_cocoa_video_data.palette, color, index);
-	}
-
-	CGDisplaySetPalette(_cocoa_video_data.display_id, _cocoa_video_data.palette);
-}
-
-/* Wait for the VBL to occur (estimated since we don't have a hardware interrupt) */
-static void QZ_WaitForVerticalBlank(void)
-{
-	/* The VBL delay is based on Ian Ollmann's RezLib <iano@cco.caltech.edu> */
-	double refreshRate;
-	double linesPerSecond;
-	double target;
-	double position;
-	double adjustment;
-	CFNumberRef refreshRateCFNumber;
-
-	refreshRateCFNumber = CFDictionaryGetValue(_cocoa_video_data.mode, kCGDisplayRefreshRate);
-	if (refreshRateCFNumber == NULL) return;
-
-	if (CFNumberGetValue(refreshRateCFNumber, kCFNumberDoubleType, &refreshRate) == 0)
-		return;
-
-	if (refreshRate == 0) return;
-
-	linesPerSecond = refreshRate * _cocoa_video_data.height;
-	target = _cocoa_video_data.height;
-
-	/* Figure out the first delay so we start off about right */
-	position = CGDisplayBeamPosition(_cocoa_video_data.display_id);
-	if (position > target) position = 0;
-
-	adjustment = (target - position) / linesPerSecond;
-
-	CSleep((uint32)(adjustment * 1000));
-}
-
-
-static void QZ_DrawScreen(void)
-{
-	const uint8* src = _cocoa_video_data.pixels;
-	uint8* dst       = (uint8*)_cocoa_video_data.realpixels;
-	uint pitch       = _cocoa_video_data.pitch;
-	uint width       = _cocoa_video_data.width;
-	uint num_dirty   = _cocoa_video_data.num_dirty_rects;
-	uint i;
-
-	/* Check if we need to do anything */
-	if (num_dirty == 0) return;
-
-	if (num_dirty >= MAX_DIRTY_RECTS) {
-		num_dirty = 1;
-		_cocoa_video_data.dirty_rects[0].left   = 0;
-		_cocoa_video_data.dirty_rects[0].top    = 0;
-		_cocoa_video_data.dirty_rects[0].right  = _cocoa_video_data.width;
-		_cocoa_video_data.dirty_rects[0].bottom = _cocoa_video_data.height;
-	}
-
-	QZ_WaitForVerticalBlank();
-	/* Build the region of dirty rectangles */
-	for (i = 0; i < num_dirty; i++) {
-		uint y      = _cocoa_video_data.dirty_rects[i].top;
-		uint left   = _cocoa_video_data.dirty_rects[i].left;
-		uint length = _cocoa_video_data.dirty_rects[i].right - left;
-		uint bottom = _cocoa_video_data.dirty_rects[i].bottom;
-
-		for (; y < bottom; y++) {
-			memcpy(dst + y * pitch + left, src + y * width + left, length);
-		}
-	}
-
-	_cocoa_video_data.num_dirty_rects = 0;
-}
-
-
-static int QZ_ListFullscreenModes(OTTDPoint* mode_list, int max_modes)
-{
-	CFIndex num_modes;
-	CFIndex i;
-	int list_size = 0;
-
-	num_modes = CFArrayGetCount(_cocoa_video_data.mode_list);
-
-	/* Build list of modes with the requested bpp */
-	for (i = 0; i < num_modes && list_size < max_modes; i++) {
-		CFDictionaryRef onemode;
-		CFNumberRef     number;
-		int bpp;
-		int intvalue;
-		bool hasMode;
-		uint16 width, height;
-
-		onemode = CFArrayGetValueAtIndex(_cocoa_video_data.mode_list, i);
-		number = CFDictionaryGetValue(onemode, kCGDisplayBitsPerPixel);
-		CFNumberGetValue (number, kCFNumberSInt32Type, &bpp);
-
-		if (bpp != 8) continue;
-
-		number = CFDictionaryGetValue(onemode, kCGDisplayWidth);
-		CFNumberGetValue(number, kCFNumberSInt32Type, &intvalue);
-		width = (uint16)intvalue;
-
-		number = CFDictionaryGetValue(onemode, kCGDisplayHeight);
-		CFNumberGetValue(number, kCFNumberSInt32Type, &intvalue);
-		height = (uint16)intvalue;
-
-		/* Check if mode is already in the list */
-		{
-			int i;
-			hasMode = false;
-			for (i = 0; i < list_size; i++) {
-				if (mode_list[i].x == width &&  mode_list[i].y == height) {
-					hasMode = true;
-					break;
-				}
-			}
-		}
-
-		if (hasMode) continue;
-
-		/* Add mode to the list */
-		mode_list[list_size].x = width;
-		mode_list[list_size].y = height;
-		list_size++;
-	}
-
-	/* Sort list smallest to largest */
-	{
-		int i, j;
-		for (i = 0; i < list_size; i++) {
-			for (j = 0; j < list_size-1; j++) {
-				if (mode_list[j].x > mode_list[j + 1].x || (
-							mode_list[j].x == mode_list[j + 1].x &&
-							mode_list[j].y >  mode_list[j + 1].y
-						)) {
-					uint tmpw = mode_list[j].x;
-					uint tmph = mode_list[j].y;
-
-					mode_list[j].x = mode_list[j + 1].x;
-					mode_list[j].y = mode_list[j + 1].y;
-
-					mode_list[j + 1].x = tmpw;
-					mode_list[j + 1].y = tmph;
-				}
-			}
-		}
-	}
-
-	return list_size;
-}
-
-
-/******************************************************************************
- *                             Windowed and fullscreen common code            *
- ******************************************************************************/
-
-static void QZ_UpdatePalette(uint start, uint count)
-{
-	if (_cocoa_video_data.fullscreen) {
-		QZ_UpdateFullscreenPalette(start, count);
-	} else {
-		QZ_UpdateWindowPalette(start, count);
-	}
-}
-
-static void QZ_InitPalette(void)
-{
-	QZ_UpdatePalette(0, 256);
-}
-
-static void QZ_Draw(void)
-{
-	if (_cocoa_video_data.fullscreen) {
-		QZ_DrawScreen();
-	} else {
-		QZ_DrawWindow();
-	}
-}
-
-
-static const OTTDPoint _default_resolutions[] = {
-	{ 640,  480},
-	{ 800,  600},
-	{1024,  768},
-	{1152,  864},
-	{1280,  800},
-	{1280,  960},
-	{1280, 1024},
-	{1400, 1050},
-	{1600, 1200},
-	{1680, 1050},
-	{1920, 1200}
-};
-
-static void QZ_UpdateVideoModes(void)
-{
-	uint i, j, count;
-	OTTDPoint modes[32];
-	const OTTDPoint *current_modes;
-
-	if (_cocoa_video_data.fullscreen) {
-		count = QZ_ListFullscreenModes(modes, 32);
-		current_modes = modes;
-	} else {
-		count = lengthof(_default_resolutions);
-		current_modes = _default_resolutions;
-	}
-
-	for (i = 0, j = 0; j < lengthof(_resolutions) && i < count; i++) {
-		if (_cocoa_video_data.fullscreen || (
-					(uint)current_modes[i].x < _cocoa_video_data.device_width &&
-					(uint)current_modes[i].y < _cocoa_video_data.device_height)
-				) {
-			_resolutions[j][0] = current_modes[i].x;
-			_resolutions[j][1] = current_modes[i].y;
-			j++;
-		}
-	}
-
-	_num_resolutions = j;
-}
-
-static void QZ_UnsetVideoMode(void)
-{
-	if (_cocoa_video_data.fullscreen) {
-		/* Release fullscreen resources */
-		OTTD_QuartzGammaTable gamma_table;
-		int gamma_error;
-		NSRect screen_rect;
-
-		gamma_error = QZ_FadeGammaOut(&gamma_table);
-
-		/* Restore original screen resolution/bpp */
-		CGDisplaySwitchToMode(_cocoa_video_data.display_id, _cocoa_video_data.save_mode);
-		CGReleaseAllDisplays();
-		ShowMenuBar();
-		/* Reset the main screen's rectangle
-		 * See comment in QZ_SetVideoFullscreen for why we do this
-		 */
-		screen_rect = NSMakeRect(0,0,_cocoa_video_data.device_width,_cocoa_video_data.device_height);
-		[ [ NSScreen mainScreen ] setFrame:screen_rect ];
-
-		if (!gamma_error) QZ_FadeGammaIn(&gamma_table);
-	} else {
-		/* Release window mode resources */
-		[ _cocoa_video_data.window close ];
-		_cocoa_video_data.window = nil;
-		_cocoa_video_data.qdview = nil;
-	}
-
-	free(_cocoa_video_data.pixels);
-	_cocoa_video_data.pixels = NULL;
-
-	/* Signal successful teardown */
-	_cocoa_video_data.isset = false;
-
-	QZ_ShowMouse();
-}
-
-
-static const char* QZ_SetVideoMode(uint width, uint height, bool fullscreen)
-{
-	const char *ret;
-
-	_cocoa_video_data.issetting = true;
-	if (fullscreen) {
-		/* Setup full screen video */
-		ret = QZ_SetVideoFullScreen(width, height);
-	} else {
-		/* Setup windowed video */
-		ret = QZ_SetVideoWindowed(width, height);
-	}
-	_cocoa_video_data.issetting = false;
-	if (ret != NULL) return ret;
-
-	/* Signal successful completion (used internally) */
-	_cocoa_video_data.isset = true;
-
-	/* Tell the game that the resolution has changed */
-	_screen.width = _cocoa_video_data.width;
-	_screen.height = _cocoa_video_data.height;
-	_screen.pitch = _cocoa_video_data.width;
-
-	QZ_UpdateVideoModes();
-	GameSizeChanged();
-
-	QZ_InitPalette();
-
-	return NULL;
-}
-
-static const char* QZ_SetVideoModeAndRestoreOnFailure(uint width, uint height, bool fullscreen)
-{
-	bool wasset = _cocoa_video_data.isset;
-	uint32 oldwidth = _cocoa_video_data.width;
-	uint32 oldheight = _cocoa_video_data.height;
-	bool oldfullscreen = _cocoa_video_data.fullscreen;
-	const char *ret;
-
-	ret = QZ_SetVideoMode(width, height, fullscreen);
-	if (ret != NULL && wasset) QZ_SetVideoMode(oldwidth, oldheight, oldfullscreen);
-
-	return ret;
-}
-
-static void QZ_VideoInit(void)
-{
-	memset(&_cocoa_video_data, 0, sizeof(_cocoa_video_data));
-
-	/* Initialize the video settings; this data persists between mode switches */
-	_cocoa_video_data.display_id = kCGDirectMainDisplay;
-	_cocoa_video_data.save_mode  = CGDisplayCurrentMode(_cocoa_video_data.display_id);
-	_cocoa_video_data.mode_list  = CGDisplayAvailableModes(_cocoa_video_data.display_id);
-	_cocoa_video_data.palette    = CGPaletteCreateDefaultColorPalette();
-
-	/* Gather some information that is useful to know about the display */
-	/* Maybe this should be moved to QZ_SetVideoMode, in case this is changed after startup */
-	CFNumberGetValue(
-		CFDictionaryGetValue(_cocoa_video_data.save_mode, kCGDisplayBitsPerPixel),
-		kCFNumberSInt32Type, &_cocoa_video_data.device_bpp
-	);
-
-	CFNumberGetValue(
-		CFDictionaryGetValue(_cocoa_video_data.save_mode, kCGDisplayWidth),
-		kCFNumberSInt32Type, &_cocoa_video_data.device_width
-	);
-
-	CFNumberGetValue(
-		CFDictionaryGetValue(_cocoa_video_data.save_mode, kCGDisplayHeight),
-		kCFNumberSInt32Type, &_cocoa_video_data.device_height
-	);
-
-	_cocoa_video_data.cursor_visible = true;
-
-	/* register for sleep notifications so wake from sleep generates SDL_VIDEOEXPOSE */
-//	QZ_RegisterForSleepNotifications();
-}
-
-
-/* Convert local coordinate to window server (CoreGraphics) coordinate */
-static CGPoint QZ_PrivateLocalToCG(NSPoint* p)
-{
-	CGPoint cgp;
-
-	if (!_cocoa_video_data.fullscreen) {
-		*p = [ _cocoa_video_data.qdview convertPoint:*p toView: nil ];
-		*p = [ _cocoa_video_data.window convertBaseToScreen:*p ];
-		p->y = _cocoa_video_data.device_height - p->y;
-	}
-
-	cgp.x = p->x;
-	cgp.y = p->y;
-
-	return cgp;
-}
-
-static void QZ_WarpCursor(int x, int y)
-{
-	NSPoint p;
-	CGPoint cgp;
-
-	/* Only allow warping when in foreground */
-	if (![ NSApp isActive ]) return;
-
-	p = NSMakePoint(x, y);
-	cgp = QZ_PrivateLocalToCG(&p);
-
-	/* this is the magic call that fixes cursor "freezing" after warp */
-	CGSetLocalEventsSuppressionInterval(0.0);
-	/* Do the actual warp */
-	CGWarpMouseCursorPosition(cgp);
-
-	/* Generate the mouse moved event */
-}
-
-static void QZ_ShowMouse(void)
-{
-	if (!_cocoa_video_data.cursor_visible) {
-		[ NSCursor unhide ];
-		_cocoa_video_data.cursor_visible = true;
-
-		// Hide the openttd cursor when leaving the window
-		if (_cocoa_video_data.isset)
-			UndrawMouseCursor();
-		_cursor.in_window = false;
-	}
-}
-
-static void QZ_HideMouse(void)
-{
-	if (_cocoa_video_data.cursor_visible) {
-#ifndef _DEBUG
-		[ NSCursor hide ];
-#endif
-		_cocoa_video_data.cursor_visible = false;
-
-		// Show the openttd cursor again
-		_cursor.in_window = true;
-	}
-}
-
-
-/******************************************************************************
- *                             OS X application creation                      *
- ******************************************************************************/
-
-/* The main class of the application, the application's delegate */
-@implementation OTTDMain
-/* Called when the internal event loop has just started running */
-- (void) applicationDidFinishLaunching: (NSNotification*) note
-{
-	/* Hand off to main application code */
-	QZ_GameLoop();
-
-	/* We're done, thank you for playing */
-	[ NSApp stop:_ottd_main ];
-}
-
-/* Display the in game quit confirmation dialog */
-- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*) sender
-{
-
-	HandleExitGameRequest();
-
-	return NSTerminateCancel; // NSTerminateLater ?
-}
-@end
-
-static void setApplicationMenu(void)
-{
-	/* warning: this code is very odd */
-	NSMenu *appleMenu;
-	NSMenuItem *menuItem;
-	NSString *title;
-	NSString *appName;
-
-	appName = @"OTTD";
-	appleMenu = [[NSMenu alloc] initWithTitle:appName];
-
-	/* Add menu items */
-	title = [@"About " stringByAppendingString:appName];
-	[appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
-
-	[appleMenu addItem:[NSMenuItem separatorItem]];
-
-	title = [@"Hide " stringByAppendingString:appName];
-	[appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
-
-	menuItem = (NSMenuItem*)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
-	[menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
-
-	[appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
-
-	[appleMenu addItem:[NSMenuItem separatorItem]];
-
-	title = [@"Quit " stringByAppendingString:appName];
-	[appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
-
-
-	/* Put menu into the menubar */
-	menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
-	[menuItem setSubmenu:appleMenu];
-	[[NSApp mainMenu] addItem:menuItem];
-
-	/* Tell the application object that this is now the application menu */
-	[NSApp setAppleMenu:appleMenu];
-
-	/* Finally give up our references to the objects */
-	[appleMenu release];
-	[menuItem release];
-}
-
-/* Create a window menu */
-static void setupWindowMenu(void)
-{
-	NSMenu* windowMenu;
-	NSMenuItem* windowMenuItem;
-	NSMenuItem* menuItem;
-
-	windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
-
-	/* "Minimize" item */
-	menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
-	[windowMenu addItem:menuItem];
-	[menuItem release];
-
-	/* Put menu into the menubar */
-	windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
-	[windowMenuItem setSubmenu:windowMenu];
-	[[NSApp mainMenu] addItem:windowMenuItem];
-
-	/* Tell the application object that this is now the window menu */
-	[NSApp setWindowsMenu:windowMenu];
-
-	/* Finally give up our references to the objects */
-	[windowMenu release];
-	[windowMenuItem release];
-}
-
-static void setupApplication(void)
-{
-	CPSProcessSerNum PSN;
-
-	/* Ensure the application object is initialised */
-	[NSApplication sharedApplication];
-
-	/* Tell the dock about us */
-	if (!CPSGetCurrentProcess(&PSN) &&
-			!CPSEnableForegroundOperation(&PSN, 0x03, 0x3C, 0x2C, 0x1103) &&
-			!CPSSetFrontProcess(&PSN)) {
-		[NSApplication sharedApplication];
-	}
-
-	/* Set up the menubar */
-	[NSApp setMainMenu:[[NSMenu alloc] init]];
-	setApplicationMenu();
-	setupWindowMenu();
-
-	/* Create OTTDMain and make it the app delegate */
-	_ottd_main = [[OTTDMain alloc] init];
-	[NSApp setDelegate:_ottd_main];
-}
-
-
-/******************************************************************************
- *                             Video driver interface                         *
- ******************************************************************************/
-
-static void CocoaVideoStop(void)
-{
-	if (!_cocoa_video_started) return;
-
-	if (_cocoa_video_data.isset) QZ_UnsetVideoMode();
-
-	[_ottd_main release];
-
-	_cocoa_video_started = false;
-}
-
-static const char *CocoaVideoStart(const char * const *parm)
-{
-	const char *ret;
-
-	if (_cocoa_video_started) return "Already started";
-	_cocoa_video_started = true;
-
-	memset(&_cocoa_video_data, 0, sizeof(_cocoa_video_data));
-
-	setupApplication();
-
-	/* Don't create a window or enter fullscreen if we're just going to show a dialog. */
-	if (_cocoa_video_dialog) return NULL;
-
-	QZ_VideoInit();
-
-	ret = QZ_SetVideoMode(_cur_resolution[0], _cur_resolution[1], _fullscreen);
-	if (ret != NULL) CocoaVideoStop();
-
-	return ret;
-}
-
-static void CocoaVideoMakeDirty(int left, int top, int width, int height)
-{
-	if (_cocoa_video_data.num_dirty_rects < MAX_DIRTY_RECTS) {
-		_cocoa_video_data.dirty_rects[_cocoa_video_data.num_dirty_rects].left = left;
-		_cocoa_video_data.dirty_rects[_cocoa_video_data.num_dirty_rects].top = top;
-		_cocoa_video_data.dirty_rects[_cocoa_video_data.num_dirty_rects].right = left + width;
-		_cocoa_video_data.dirty_rects[_cocoa_video_data.num_dirty_rects].bottom = top + height;
-	}
-	_cocoa_video_data.num_dirty_rects++;
-}
-
-static void CocoaVideoMainLoop(void)
-{
-	/* Start the main event loop */
-	[NSApp run];
-}
-
-static bool CocoaVideoChangeRes(int w, int h)
-{
-	const char *ret = QZ_SetVideoModeAndRestoreOnFailure((uint)w, (uint)h, _cocoa_video_data.fullscreen);
-	if (ret != NULL) {
-		DEBUG(driver, 0, "cocoa_v: CocoaVideoChangeRes failed with message: %s", ret);
-	}
-
-	return ret == NULL;
-}
-
-static void CocoaVideoFullScreen(bool full_screen)
-{
-	const char *ret = QZ_SetVideoModeAndRestoreOnFailure(_cocoa_video_data.width, _cocoa_video_data.height, full_screen);
-	if (ret != NULL) {
-		DEBUG(driver, 0, "cocoa_v: CocoaVideoFullScreen failed with message: %s", ret);
-	}
-
-	_fullscreen = _cocoa_video_data.fullscreen;
-}
-
-const HalVideoDriver _cocoa_video_driver = {
-	CocoaVideoStart,
-	CocoaVideoStop,
-	CocoaVideoMakeDirty,
-	CocoaVideoMainLoop,
-	CocoaVideoChangeRes,
-	CocoaVideoFullScreen,
-};
-
-
-/* This is needed since sometimes assert is called before the videodriver is initialized */
-void CocoaDialog(const char* title, const char* message, const char* buttonLabel)
-{
-	bool wasstarted;
-
-	_cocoa_video_dialog = true;
-
-	wasstarted = _cocoa_video_started;
-	if (!_cocoa_video_started && CocoaVideoStart(NULL) != NULL) {
-		fprintf(stderr, "%s: %s\n", title, message);
-		return;
-	}
-
-	NSRunAlertPanel([NSString stringWithCString: title], [NSString stringWithCString: message], [NSString stringWithCString: buttonLabel], nil, nil);
-
-	if (!wasstarted) CocoaVideoStop();
-
-	_cocoa_video_dialog = false;
-}
-
-
-/* This is needed since OS X applications are started with the working dir set to / when double-clicked */
-void cocoaSetWorkingDirectory(void)
-{
-	char parentdir[MAXPATHLEN];
-	int chdir_ret;
-	CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
-	CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url);
-	if (CFURLGetFileSystemRepresentation(url2, true, (unsigned char*)parentdir, MAXPATHLEN)) {
-		chdir_ret = chdir(parentdir); /* chdir to the binary app's parent */
-		assert(chdir_ret == 0);
-	}
-	CFRelease(url);
-	CFRelease(url2);
-}
-
-/* These are called from main() to prevent a _NSAutoreleaseNoPool error when
- * exiting before the cocoa video driver has been loaded
- */
-void cocoaSetupAutoreleasePool(void)
-{
-	_ottd_autorelease_pool = [[NSAutoreleasePool alloc] init];
-}
-
-void cocoaReleaseAutoreleasePool(void)
-{
-	[_ottd_autorelease_pool release];
-}
-
-#endif /* WITH_COCOA */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/cocoa_v.mm	Mon Feb 05 21:16:56 2007 +0000
@@ -0,0 +1,2066 @@
+/* $Id$ */
+
+/******************************************************************************
+ *                             Cocoa video driver                             *
+ * Known things left to do:                                                   *
+ *  Nothing at the moment.                                                    *
+ ******************************************************************************/
+
+#ifdef WITH_COCOA
+
+#import <Cocoa/Cocoa.h>
+#import <sys/time.h> /* gettimeofday */
+#import <sys/param.h> /* for MAXPATHLEN */
+#import <unistd.h>
+
+/**
+ * Important notice regarding all modifications!!!!!!!
+ * There are certain limitations because the file is objective C++.
+ * gdb has limitations.
+ * C++ and objective C code can't be joined in all cases (classes stuff).
+ * Read http://developer.apple.com/releasenotes/Cocoa/Objective-C++.html for more information.
+ */
+
+
+/* Portions of CPS.h */
+typedef struct CPSProcessSerNum {
+	UInt32 lo;
+	UInt32 hi;
+} CPSProcessSerNum;
+
+extern "C" OSErr CPSGetCurrentProcess(CPSProcessSerNum* psn);
+extern "C" OSErr CPSEnableForegroundOperation(CPSProcessSerNum* psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
+extern "C" OSErr CPSSetFrontProcess(CPSProcessSerNum* psn);
+
+/* From Menus.h (according to Xcode Developer Documentation) */
+extern "C" void ShowMenuBar(void);
+extern "C" void HideMenuBar(void);
+
+/* Disables a warning. This is needed since the method exists but has been dropped from the header, supposedly as of 10.4. */
+#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
+@interface NSApplication(NSAppleMenu)
+- (void)setAppleMenu:(NSMenu *)menu;
+@end
+#endif
+
+
+/* Defined in ppc/param.h or i386/param.h included from sys/param.h */
+#undef ALIGN
+/* Defined in stdbool.h */
+#ifndef __cplusplus
+# ifndef __BEOS__
+#  undef bool
+#  undef false
+#  undef true
+# endif
+#endif
+
+
+#include "../stdafx.h"
+#include "../debug.h"
+#include "../macros.h"
+#include "../os/macosx/splash.h"
+#include "cocoa_v.h"
+#include "cocoa_keys.h"
+
+#undef Point
+#undef Rect
+
+/* Taken from ../gfx.h */
+extern bool _dbg_screen_rect;
+
+
+/* Subclass of NSWindow to fix genie effect and support resize events  */
+@interface OTTD_QuartzWindow : NSWindow
+- (void)miniaturize:(id)sender;
+- (void)display;
+- (void)setFrame:(NSRect)frameRect display:(BOOL)flag;
+- (void)appDidHide:(NSNotification*)note;
+- (void)appWillUnhide:(NSNotification*)note;
+- (void)appDidUnhide:(NSNotification*)note;
+- (id)initWithContentRect:(NSRect)contentRect styleMask:(unsigned int)styleMask backing:(NSBackingStoreType)backingType defer:(BOOL)flag;
+@end
+
+/* Delegate for our NSWindow to send ask for quit on close */
+@interface OTTD_QuartzWindowDelegate : NSObject
+- (BOOL)windowShouldClose:(id)sender;
+@end
+
+@interface OTTDMain : NSObject
+@end
+
+
+/* Structure for rez switch gamma fades
+ * We can hide the monitor flicker by setting the gamma tables to 0
+ */
+#define QZ_GAMMA_TABLE_SIZE 256
+
+typedef struct {
+	CGGammaValue red[QZ_GAMMA_TABLE_SIZE];
+	CGGammaValue green[QZ_GAMMA_TABLE_SIZE];
+	CGGammaValue blue[QZ_GAMMA_TABLE_SIZE];
+} OTTD_QuartzGammaTable;
+
+/* Add methods to get at private members of NSScreen.
+ * Since there is a bug in Apple's screen switching code that does not update
+ * this variable when switching to fullscreen, we'll set it manually (but only
+ * for the main screen).
+ */
+@interface NSScreen (NSScreenAccess)
+	- (void) setFrame:(NSRect)frame;
+@end
+
+@implementation NSScreen (NSScreenAccess)
+- (void) setFrame:(NSRect)frame;
+{
+	_frame = frame;
+}
+@end
+
+
+static void QZ_Draw(void);
+static void QZ_UnsetVideoMode(void);
+static void QZ_UpdatePalette(uint start, uint count);
+static void QZ_WarpCursor(int x, int y);
+static void QZ_ShowMouse(void);
+static void QZ_HideMouse(void);
+static void CocoaVideoFullScreen(bool full_screen);
+
+
+static NSAutoreleasePool *_ottd_autorelease_pool;
+static OTTDMain *_ottd_main;
+
+
+static struct CocoaVideoData {
+	bool isset;
+	bool issetting;
+
+	CGDirectDisplayID  display_id;         /* 0 == main display (only support single display) */
+	CFDictionaryRef    mode;               /* current mode of the display */
+	CFDictionaryRef    save_mode;          /* original mode of the display */
+	CFArrayRef         mode_list;          /* list of available fullscreen modes */
+	CGDirectPaletteRef palette;            /* palette of an 8-bit display */
+
+	uint32 device_width;
+	uint32 device_height;
+	uint32 device_bpp;
+
+	void *realpixels;
+	uint8 *pixels;
+	uint32 width;
+	uint32 height;
+	uint32 pitch;
+	bool fullscreen;
+
+	unsigned int current_mods;
+	bool tab_is_down;
+	bool emulating_right_button;
+
+	bool cursor_visible;
+	bool active;
+
+#ifdef _DEBUG
+	uint32 tEvent;
+#endif
+
+	OTTD_QuartzWindow *window;
+	NSQuickDrawView *qdview;
+
+#define MAX_DIRTY_RECTS 100
+	Rect dirty_rects[MAX_DIRTY_RECTS];
+	int num_dirty_rects;
+
+	uint16 palette16[256];
+	uint32 palette32[256];
+} _cocoa_video_data;
+
+static bool _cocoa_video_started = false;
+static bool _cocoa_video_dialog = false;
+
+
+
+
+/******************************************************************************
+ *                             Game loop and accessories                      *
+ ******************************************************************************/
+
+static uint32 GetTick(void)
+{
+	struct timeval tim;
+
+	gettimeofday(&tim, NULL);
+	return tim.tv_usec / 1000 + tim.tv_sec * 1000;
+}
+
+static void QZ_CheckPaletteAnim(void)
+{
+	if (_pal_last_dirty != -1) {
+		QZ_UpdatePalette(_pal_first_dirty, _pal_last_dirty - _pal_first_dirty + 1);
+		_pal_last_dirty = -1;
+	}
+}
+
+
+
+typedef struct VkMapping {
+	unsigned short vk_from;
+	byte map_to;
+} VkMapping;
+
+#define AS(x, z) {x, z}
+
+static const VkMapping _vk_mapping[] = {
+	AS(QZ_BACKQUOTE,  WKC_BACKQUOTE), // key left of '1'
+	AS(QZ_BACKQUOTE2, WKC_BACKQUOTE), // some keyboards have it on another scancode
+
+	// Pageup stuff + up/down
+	//AM(SDLK_PAGEUP, SDLK_PAGEDOWN, WKC_PAGEUP, WKC_PAGEDOWN),  <==== Does this include HOME/END?
+	AS(QZ_PAGEUP,   WKC_PAGEUP),
+	AS(QZ_PAGEDOWN, WKC_PAGEDOWN),
+
+	AS(QZ_UP,    WKC_UP),
+	AS(QZ_DOWN,  WKC_DOWN),
+	AS(QZ_LEFT,  WKC_LEFT),
+	AS(QZ_RIGHT, WKC_RIGHT),
+
+	AS(QZ_HOME, WKC_HOME),
+	AS(QZ_END,  WKC_END),
+
+	AS(QZ_INSERT, WKC_INSERT),
+	AS(QZ_DELETE, WKC_DELETE),
+
+	// Letters. QZ_[a-z] is not in numerical order so we can't use AM(...)
+	AS(QZ_a, 'A'),
+	AS(QZ_b, 'B'),
+	AS(QZ_c, 'C'),
+	AS(QZ_d, 'D'),
+	AS(QZ_e, 'E'),
+	AS(QZ_f, 'F'),
+	AS(QZ_g, 'G'),
+	AS(QZ_h, 'H'),
+	AS(QZ_i, 'I'),
+	AS(QZ_j, 'J'),
+	AS(QZ_k, 'K'),
+	AS(QZ_l, 'L'),
+	AS(QZ_m, 'M'),
+	AS(QZ_n, 'N'),
+	AS(QZ_o, 'O'),
+	AS(QZ_p, 'P'),
+	AS(QZ_q, 'Q'),
+	AS(QZ_r, 'R'),
+	AS(QZ_s, 'S'),
+	AS(QZ_t, 'T'),
+	AS(QZ_u, 'U'),
+	AS(QZ_v, 'V'),
+	AS(QZ_w, 'W'),
+	AS(QZ_x, 'X'),
+	AS(QZ_y, 'Y'),
+	AS(QZ_z, 'Z'),
+	// Same thing for digits
+	AS(QZ_0, '0'),
+	AS(QZ_1, '1'),
+	AS(QZ_2, '2'),
+	AS(QZ_3, '3'),
+	AS(QZ_4, '4'),
+	AS(QZ_5, '5'),
+	AS(QZ_6, '6'),
+	AS(QZ_7, '7'),
+	AS(QZ_8, '8'),
+	AS(QZ_9, '9'),
+
+	AS(QZ_ESCAPE,    WKC_ESC),
+	AS(QZ_PAUSE,     WKC_PAUSE),
+	AS(QZ_BACKSPACE, WKC_BACKSPACE),
+
+	AS(QZ_SPACE,  WKC_SPACE),
+	AS(QZ_RETURN, WKC_RETURN),
+	AS(QZ_TAB,    WKC_TAB),
+
+	// Function keys
+	AS(QZ_F1,  WKC_F1),
+	AS(QZ_F2,  WKC_F2),
+	AS(QZ_F3,  WKC_F3),
+	AS(QZ_F4,  WKC_F4),
+	AS(QZ_F5,  WKC_F5),
+	AS(QZ_F6,  WKC_F6),
+	AS(QZ_F7,  WKC_F7),
+	AS(QZ_F8,  WKC_F8),
+	AS(QZ_F9,  WKC_F9),
+	AS(QZ_F10, WKC_F10),
+	AS(QZ_F11, WKC_F11),
+	AS(QZ_F12, WKC_F12),
+
+	// Numeric part.
+	AS(QZ_KP0,         WKC_NUM_0),
+	AS(QZ_KP1,         WKC_NUM_1),
+	AS(QZ_KP2,         WKC_NUM_2),
+	AS(QZ_KP3,         WKC_NUM_3),
+	AS(QZ_KP4,         WKC_NUM_4),
+	AS(QZ_KP5,         WKC_NUM_5),
+	AS(QZ_KP6,         WKC_NUM_6),
+	AS(QZ_KP7,         WKC_NUM_7),
+	AS(QZ_KP8,         WKC_NUM_8),
+	AS(QZ_KP9,         WKC_NUM_9),
+	AS(QZ_KP_DIVIDE,   WKC_NUM_DIV),
+	AS(QZ_KP_MULTIPLY, WKC_NUM_MUL),
+	AS(QZ_KP_MINUS,    WKC_NUM_MINUS),
+	AS(QZ_KP_PLUS,     WKC_NUM_PLUS),
+	AS(QZ_KP_ENTER,    WKC_NUM_ENTER),
+	AS(QZ_KP_PERIOD,   WKC_NUM_DECIMAL)
+};
+
+
+static uint32 QZ_MapKey(unsigned short sym)
+{
+	const VkMapping *map;
+	uint32 key = 0;
+
+	for (map = _vk_mapping; map != endof(_vk_mapping); ++map) {
+		if (sym == map->vk_from) {
+			key = map->map_to;
+			break;
+		}
+	}
+
+	if (_cocoa_video_data.current_mods & NSShiftKeyMask)     key |= WKC_SHIFT;
+	if (_cocoa_video_data.current_mods & NSControlKeyMask)   key |= WKC_CTRL;
+	if (_cocoa_video_data.current_mods & NSAlternateKeyMask) key |= WKC_ALT;
+	if (_cocoa_video_data.current_mods & NSCommandKeyMask)   key |= WKC_META;
+
+	return key << 16;
+}
+
+static void QZ_KeyEvent(unsigned short keycode, unsigned short unicode, BOOL down)
+{
+	switch (keycode) {
+		case QZ_UP:    SB(_dirkeys, 1, 1, down); break;
+		case QZ_DOWN:  SB(_dirkeys, 3, 1, down); break;
+		case QZ_LEFT:  SB(_dirkeys, 0, 1, down); break;
+		case QZ_RIGHT: SB(_dirkeys, 2, 1, down); break;
+
+		case QZ_TAB: _cocoa_video_data.tab_is_down = down; break;
+
+		case QZ_RETURN:
+		case QZ_f:
+			if (down && (_cocoa_video_data.current_mods & NSCommandKeyMask)) {
+				CocoaVideoFullScreen(!_fullscreen);
+			}
+			break;
+	}
+
+	if (down) {
+		uint32 pressed_key = QZ_MapKey(keycode) | unicode;
+		HandleKeypress(pressed_key);
+		DEBUG(driver, 2, "cocoa_v: QZ_KeyEvent: %x (%x), down, mapping: %x", keycode, unicode, pressed_key);
+	} else {
+		DEBUG(driver, 2, "cocoa_v: QZ_KeyEvent: %x (%x), up", keycode, unicode);
+	}
+}
+
+static void QZ_DoUnsidedModifiers(unsigned int newMods)
+{
+	const int mapping[] = { QZ_CAPSLOCK, QZ_LSHIFT, QZ_LCTRL, QZ_LALT, QZ_LMETA };
+
+	int i;
+	unsigned int bit;
+
+	if (_cocoa_video_data.current_mods == newMods) return;
+
+	/* Iterate through the bits, testing each against the current modifiers */
+	for (i = 0, bit = NSAlphaShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) {
+		unsigned int currentMask, newMask;
+
+		currentMask = _cocoa_video_data.current_mods & bit;
+		newMask     = newMods & bit;
+
+		if (currentMask && currentMask != newMask) { /* modifier up event */
+			/* If this was Caps Lock, we need some additional voodoo to make SDL happy (is this needed in ottd?) */
+			if (bit == NSAlphaShiftKeyMask) QZ_KeyEvent(mapping[i], 0, YES);
+			QZ_KeyEvent(mapping[i], 0, NO);
+		} else if (newMask && currentMask != newMask) { /* modifier down event */
+			QZ_KeyEvent(mapping[i], 0, YES);
+			/* If this was Caps Lock, we need some additional voodoo to make SDL happy (is this needed in ottd?) */
+			if (bit == NSAlphaShiftKeyMask) QZ_KeyEvent(mapping[i], 0, NO);
+		}
+	}
+
+	_cocoa_video_data.current_mods = newMods;
+}
+
+static void QZ_MouseMovedEvent(int x, int y)
+{
+	if (_cursor.fix_at) {
+		int dx = x - _cursor.pos.x;
+		int dy = y - _cursor.pos.y;
+
+		if (dx != 0 || dy != 0) {
+			_cursor.delta.x += dx;
+			_cursor.delta.y += dy;
+
+			QZ_WarpCursor(_cursor.pos.x, _cursor.pos.y);
+		}
+	} else {
+		_cursor.delta.x = x - _cursor.pos.x;
+		_cursor.delta.y = y - _cursor.pos.y;
+		_cursor.pos.x = x;
+		_cursor.pos.y = y;
+		_cursor.dirty = true;
+	}
+	HandleMouseEvents();
+}
+
+
+static void QZ_MouseButtonEvent(int button, BOOL down)
+{
+	switch (button) {
+		case 0:
+			if (down) {
+				_left_button_down = true;
+			} else {
+				_left_button_down = false;
+				_left_button_clicked = false;
+			}
+			HandleMouseEvents();
+			break;
+
+		case 1:
+			if (down) {
+				_right_button_down = true;
+				_right_button_clicked = true;
+			} else {
+				_right_button_down = false;
+			}
+			HandleMouseEvents();
+			break;
+	}
+}
+
+
+static inline NSPoint QZ_GetMouseLocation(NSEvent *event)
+{
+	NSPoint pt;
+
+	if (_cocoa_video_data.fullscreen) {
+		pt = [ NSEvent mouseLocation ];
+		pt.y = _cocoa_video_data.height - pt.y;
+	} else {
+		pt = [event locationInWindow];
+		pt = [_cocoa_video_data.qdview convertPoint:pt fromView:nil];
+	}
+
+	return pt;
+}
+
+static bool QZ_MouseIsInsideView(NSPoint *pt)
+{
+	if (_cocoa_video_data.fullscreen) {
+		return pt->x >= 0 && pt->y >= 0 && pt->x < _cocoa_video_data.width && pt->y < _cocoa_video_data.height;
+	} else {
+		return [ _cocoa_video_data.qdview mouse:*pt inRect:[ _cocoa_video_data.qdview bounds ] ];
+	}
+}
+
+
+static bool QZ_PollEvent(void)
+{
+	NSEvent *event;
+	NSPoint pt;
+	NSString *chars;
+#ifdef _DEBUG
+	uint32 et0, et;
+#endif
+
+#ifdef _DEBUG
+	et0 = GetTick();
+#endif
+	event = [ NSApp nextEventMatchingMask:NSAnyEventMask
+			untilDate: [ NSDate distantPast ]
+			inMode: NSDefaultRunLoopMode dequeue:YES ];
+#ifdef _DEBUG
+	et = GetTick();
+	_cocoa_video_data.tEvent+= et - et0;
+#endif
+
+	if (event == nil) return false;
+	if (!_cocoa_video_data.active) {
+		QZ_ShowMouse();
+		[NSApp sendEvent:event];
+		return true;
+	}
+
+	QZ_DoUnsidedModifiers( [ event modifierFlags ] );
+
+	switch ([event type]) {
+		case NSMouseMoved:
+		case NSOtherMouseDragged:
+		case NSRightMouseDragged:
+		case NSLeftMouseDragged:
+			pt = QZ_GetMouseLocation(event);
+			if (!QZ_MouseIsInsideView(&pt) &&
+					!_cocoa_video_data.emulating_right_button) {
+				QZ_ShowMouse();
+				[NSApp sendEvent:event];
+				break;
+			}
+
+			QZ_HideMouse();
+			QZ_MouseMovedEvent((int)pt.x, (int)pt.y);
+			break;
+
+		case NSLeftMouseDown:
+			if (!([ event modifierFlags ] & NSCommandKeyMask) ||
+					!QZ_MouseIsInsideView(&pt)) {
+				[NSApp sendEvent:event];
+			}
+
+			pt = QZ_GetMouseLocation(event);
+			if (!QZ_MouseIsInsideView(&pt)) {
+				QZ_ShowMouse();
+				break;
+			}
+
+			QZ_HideMouse();
+			QZ_MouseMovedEvent((int)pt.x, (int)pt.y);
+
+			/* Right mouse button emulation */
+			if ([ event modifierFlags ] & NSCommandKeyMask) {
+				_cocoa_video_data.emulating_right_button = true;
+				QZ_MouseButtonEvent(1, YES);
+			} else {
+				QZ_MouseButtonEvent(0, YES);
+			}
+			break;
+
+		case NSLeftMouseUp:
+			[NSApp sendEvent:event];
+
+			pt = QZ_GetMouseLocation(event);
+			if (!QZ_MouseIsInsideView(&pt)) {
+				QZ_ShowMouse();
+				break;
+			}
+
+			QZ_HideMouse();
+			QZ_MouseMovedEvent((int)pt.x, (int)pt.y);
+
+			/* Right mouse button emulation */
+			if (_cocoa_video_data.emulating_right_button) {
+				_cocoa_video_data.emulating_right_button = false;
+				QZ_MouseButtonEvent(1, NO);
+			} else {
+				QZ_MouseButtonEvent(0, NO);
+			}
+			break;
+
+		case NSRightMouseDown:
+			pt = QZ_GetMouseLocation(event);
+			if (!QZ_MouseIsInsideView(&pt)) {
+				QZ_ShowMouse();
+				[NSApp sendEvent:event];
+				break;
+			}
+
+			QZ_HideMouse();
+			QZ_MouseMovedEvent((int)pt.x, (int)pt.y);
+			QZ_MouseButtonEvent(1, YES);
+			break;
+
+		case NSRightMouseUp:
+			pt = QZ_GetMouseLocation(event);
+			if (!QZ_MouseIsInsideView(&pt)) {
+				QZ_ShowMouse();
+				[NSApp sendEvent:event];
+				break;
+			}
+
+			QZ_HideMouse();
+			QZ_MouseMovedEvent((int)pt.x, (int)pt.y);
+			QZ_MouseButtonEvent(1, NO);
+			break;
+
+#if 0
+		/* This is not needed since openttd currently only use two buttons */
+		case NSOtherMouseDown:
+			pt = QZ_GetMouseLocation(event);
+			if (!QZ_MouseIsInsideView(&pt)) {
+				QZ_ShowMouse();
+				[NSApp sendEvent:event];
+				break;
+			}
+
+			QZ_HideMouse();
+			QZ_MouseMovedEvent((int)pt.x, (int)pt.y);
+			QZ_MouseButtonEvent([ event buttonNumber ], YES);
+			break;
+
+		case NSOtherMouseUp:
+			pt = QZ_GetMouseLocation(event);
+			if (!QZ_MouseIsInsideView(&pt)) {
+				QZ_ShowMouse();
+				[NSApp sendEvent:event];
+				break;
+			}
+
+			QZ_HideMouse();
+			QZ_MouseMovedEvent((int)pt.x, (int)pt.y);
+			QZ_MouseButtonEvent([ event buttonNumber ], NO);
+			break;
+#endif
+
+		case NSKeyDown:
+			/* Quit, hide and minimize */
+			switch ([event keyCode]) {
+				case QZ_q:
+				case QZ_h:
+				case QZ_m:
+					if ([ event modifierFlags ] & NSCommandKeyMask) {
+						[NSApp sendEvent:event];
+					}
+					break;
+			}
+
+			chars = [ event characters ];
+			QZ_KeyEvent([event keyCode], [ chars length ] ? [ chars characterAtIndex:0 ] : 0, YES);
+			break;
+
+		case NSKeyUp:
+			/* Quit, hide and minimize */
+			switch ([event keyCode]) {
+				case QZ_q:
+				case QZ_h:
+				case QZ_m:
+					if ([ event modifierFlags ] & NSCommandKeyMask) {
+						[NSApp sendEvent:event];
+					}
+					break;
+			}
+
+			chars = [ event characters ];
+			QZ_KeyEvent([event keyCode], [ chars length ] ? [ chars characterAtIndex:0 ] : 0, NO);
+			break;
+
+		case NSScrollWheel:
+			if ([ event deltaY ] > 0.0) { /* Scroll up */
+				_cursor.wheel--;
+			} else if ([ event deltaY ] < 0.0) { /* Scroll down */
+				_cursor.wheel++;
+			} /* else: deltaY was 0.0 and we don't want to do anything */
+			break;
+
+		default:
+			[NSApp sendEvent:event];
+	}
+
+	return true;
+}
+
+
+static void QZ_GameLoop(void)
+{
+	uint32 cur_ticks = GetTick();
+	uint32 next_tick = cur_ticks + 30;
+	uint32 pal_tick = 0;
+#ifdef _DEBUG
+	uint32 et0, et, st0, st;
+#endif
+	int i;
+
+#ifdef _DEBUG
+	et0 = GetTick();
+	st = 0;
+#endif
+
+	_screen.dst_ptr = _cocoa_video_data.pixels;
+	DisplaySplashImage();
+	QZ_CheckPaletteAnim();
+	QZ_Draw();
+	CSleep(1);
+
+	for (i = 0; i < 2; i++) GameLoop();
+
+	_screen.dst_ptr = _cocoa_video_data.pixels;
+	UpdateWindows();
+	QZ_CheckPaletteAnim();
+	QZ_Draw();
+	CSleep(1);
+
+	for (;;) {
+		uint32 prev_cur_ticks = cur_ticks; // to check for wrapping
+		InteractiveRandom(); // randomness
+
+		while (QZ_PollEvent()) {}
+
+		if (_exit_game) break;
+
+#if defined(_DEBUG)
+		if (_cocoa_video_data.current_mods & NSShiftKeyMask)
+#else
+		if (_cocoa_video_data.tab_is_down)
+#endif
+		{
+			if (!_networking && _game_mode != GM_MENU) _fast_forward |= 2;
+		} else if (_fast_forward & 2) {
+			_fast_forward = 0;
+		}
+
+		cur_ticks = GetTick();
+		if (cur_ticks >= next_tick || (_fast_forward && !_pause) || cur_ticks < prev_cur_ticks) {
+			next_tick = cur_ticks + 30;
+
+			_ctrl_pressed = !!(_cocoa_video_data.current_mods & NSControlKeyMask);
+			_shift_pressed = !!(_cocoa_video_data.current_mods & NSShiftKeyMask);
+#ifdef _DEBUG
+			_dbg_screen_rect = !!(_cocoa_video_data.current_mods & NSAlphaShiftKeyMask);
+#endif
+
+			GameLoop();
+
+			_screen.dst_ptr = _cocoa_video_data.pixels;
+			UpdateWindows();
+			if (++pal_tick > 4) {
+				QZ_CheckPaletteAnim();
+				pal_tick = 1;
+			}
+			QZ_Draw();
+		} else {
+#ifdef _DEBUG
+			st0 = GetTick();
+#endif
+			CSleep(1);
+#ifdef _DEBUG
+			st += GetTick() - st0;
+#endif
+			_screen.dst_ptr = _cocoa_video_data.pixels;
+			DrawTextMessage();
+			DrawMouseCursor();
+			QZ_Draw();
+		}
+	}
+
+#ifdef _DEBUG
+	et = GetTick();
+
+	DEBUG(driver, 1, "cocoa_v: nextEventMatchingMask took %i ms total", _cocoa_video_data.tEvent);
+	DEBUG(driver, 1, "cocoa_v: game loop took %i ms total (%i ms without sleep)", et - et0, et - et0 - st);
+	DEBUG(driver, 1, "cocoa_v: (nextEventMatchingMask total)/(game loop total) is %f%%", (double)_cocoa_video_data.tEvent / (double)(et - et0) * 100);
+	DEBUG(driver, 1, "cocoa_v: (nextEventMatchingMask total)/(game loop without sleep total) is %f%%", (double)_cocoa_video_data.tEvent / (double)(et - et0 - st) * 100);
+#endif
+}
+
+
+/******************************************************************************
+ *                             Windowed mode                                  *
+ ******************************************************************************/
+
+/* This function makes the *game region* of the window 100% opaque.
+ * The genie effect uses the alpha component. Otherwise,
+ * it doesn't seem to matter what value it has.
+ */
+static void QZ_SetPortAlphaOpaque(void)
+{
+	if (_cocoa_video_data.device_bpp == 32) {
+		uint32* pixels = (uint32*)_cocoa_video_data.realpixels;
+		uint32 rowPixels = _cocoa_video_data.pitch / 4;
+		uint32 i;
+		uint32 j;
+
+		for (i = 0; i < _cocoa_video_data.height; i++)
+			for (j = 0; j < _cocoa_video_data.width; j++) {
+			pixels[i * rowPixels + j] |= 0xFF000000;
+		}
+	}
+}
+
+
+@implementation OTTD_QuartzWindow
+
+/* we override these methods to fix the miniaturize animation/dock icon bug */
+- (void)miniaturize:(id)sender
+{
+	/* make the alpha channel opaque so anim won't have holes in it */
+	QZ_SetPortAlphaOpaque ();
+
+	/* window is hidden now */
+	_cocoa_video_data.active = false;
+
+	QZ_ShowMouse();
+
+	[ super miniaturize:sender ];
+}
+
+- (void)display
+{
+	/* This method fires just before the window deminaturizes from the Dock.
+	 * We'll save the current visible surface, let the window manager redraw any
+	 * UI elements, and restore the surface. This way, no expose event
+	 * is required, and the deminiaturize works perfectly.
+	 */
+
+	QZ_SetPortAlphaOpaque();
+
+	/* save current visible surface */
+	[ self cacheImageInRect:[ _cocoa_video_data.qdview frame ] ];
+
+	/* let the window manager redraw controls, border, etc */
+	[ super display ];
+
+	/* restore visible surface */
+	[ self restoreCachedImage ];
+
+	/* window is visible again */
+	_cocoa_video_data.active = true;
+}
+
+- (void)setFrame:(NSRect)frameRect display:(BOOL)flag
+{
+	NSRect newViewFrame;
+	CGrafPtr thePort;
+
+	[ super setFrame:frameRect display:flag ];
+
+	/* Don't do anything if the window is currently beign created */
+	if (_cocoa_video_data.issetting) return;
+
+	if (_cocoa_video_data.window == nil) return;
+
+	newViewFrame = [ _cocoa_video_data.qdview frame ];
+
+	/* Update the pixels and pitch */
+	thePort = (OpaqueGrafPtr*) [ _cocoa_video_data.qdview qdPort ];
+	LockPortBits(thePort);
+
+	_cocoa_video_data.realpixels = GetPixBaseAddr(GetPortPixMap(thePort));
+	_cocoa_video_data.pitch      = GetPixRowBytes(GetPortPixMap(thePort));
+
+	/* _cocoa_video_data.realpixels now points to the window's pixels
+	 * We want it to point to the *view's* pixels
+	 */
+	{
+		int vOffset = [ _cocoa_video_data.window frame ].size.height - newViewFrame.size.height - newViewFrame.origin.y;
+		int hOffset = newViewFrame.origin.x;
+
+		_cocoa_video_data.realpixels = (uint8*)_cocoa_video_data.realpixels + (vOffset * _cocoa_video_data.pitch) + hOffset * (_cocoa_video_data.device_bpp / 8);
+	}
+
+	UnlockPortBits(thePort);
+
+	/* Allocate new buffer */
+	free(_cocoa_video_data.pixels);
+	_cocoa_video_data.pixels = (uint8*)malloc(newViewFrame.size.width * newViewFrame.size.height);
+	assert(_cocoa_video_data.pixels != NULL);
+
+
+	/* Tell the game that the resolution changed */
+	_cocoa_video_data.width = newViewFrame.size.width;
+	_cocoa_video_data.height = newViewFrame.size.height;
+
+	_screen.width = _cocoa_video_data.width;
+	_screen.height = _cocoa_video_data.height;
+	_screen.pitch = _cocoa_video_data.width;
+
+	GameSizeChanged();
+
+	/* Redraw screen */
+	_cocoa_video_data.num_dirty_rects = MAX_DIRTY_RECTS;
+}
+
+- (void)appDidHide:(NSNotification*)note
+{
+	_cocoa_video_data.active = false;
+}
+
+
+- (void)appWillUnhide:(NSNotification*)note
+{
+	QZ_SetPortAlphaOpaque ();
+
+	/* save current visible surface */
+	[ self cacheImageInRect:[ _cocoa_video_data.qdview frame ] ];
+}
+
+- (void)appDidUnhide:(NSNotification*)note
+{
+	/* restore cached image, since it may not be current, post expose event too */
+	[ self restoreCachedImage ];
+
+	_cocoa_video_data.active = true;
+}
+
+
+- (id)initWithContentRect:(NSRect)contentRect styleMask:(unsigned int)styleMask backing:(NSBackingStoreType)backingType defer:(BOOL)flag
+{
+	/* Make our window subclass receive these application notifications */
+	[ [ NSNotificationCenter defaultCenter ] addObserver:self
+	selector:@selector(appDidHide:) name:NSApplicationDidHideNotification object:NSApp ];
+
+	[ [ NSNotificationCenter defaultCenter ] addObserver:self
+	selector:@selector(appDidUnhide:) name:NSApplicationDidUnhideNotification object:NSApp ];
+
+	[ [ NSNotificationCenter defaultCenter ] addObserver:self
+	selector:@selector(appWillUnhide:) name:NSApplicationWillUnhideNotification object:NSApp ];
+
+	return [ super initWithContentRect:contentRect styleMask:styleMask backing:backingType defer:flag ];
+}
+
+@end
+
+@implementation OTTD_QuartzWindowDelegate
+- (BOOL)windowShouldClose:(id)sender
+{
+	HandleExitGameRequest();
+
+	return NO;
+}
+
+- (void)windowDidBecomeKey:(NSNotification*)aNotification
+{
+	_cocoa_video_data.active = true;
+}
+
+- (void)windowDidResignKey:(NSNotification*)aNotification
+{
+	_cocoa_video_data.active = false;
+}
+
+- (void)windowDidBecomeMain:(NSNotification*)aNotification
+{
+	_cocoa_video_data.active = true;
+}
+
+- (void)windowDidResignMain:(NSNotification*)aNotification
+{
+	_cocoa_video_data.active = false;
+}
+
+@end
+
+
+static void QZ_UpdateWindowPalette(uint start, uint count)
+{
+	uint i;
+
+	switch (_cocoa_video_data.device_bpp) {
+		case 32:
+			for (i = start; i < start + count; i++) {
+				uint32 clr32 = 0xff000000;
+				clr32 |= (uint32)_cur_palette[i].r << 16;
+				clr32 |= (uint32)_cur_palette[i].g << 8;
+				clr32 |= (uint32)_cur_palette[i].b;
+				_cocoa_video_data.palette32[i] = clr32;
+			}
+			break;
+		case 16:
+			for (i = start; i < start + count; i++) {
+				uint16 clr16 = 0x0000;
+				clr16 |= (uint16)((_cur_palette[i].r >> 3) & 0x1f) << 10;
+				clr16 |= (uint16)((_cur_palette[i].g >> 3) & 0x1f) << 5;
+				clr16 |= (uint16)((_cur_palette[i].b >> 3) & 0x1f);
+				_cocoa_video_data.palette16[i] = clr16;
+			}
+			break;
+	}
+
+	_cocoa_video_data.num_dirty_rects = MAX_DIRTY_RECTS;
+}
+
+static inline void QZ_WindowBlitIndexedPixelsToView32(uint left, uint top, uint right, uint bottom)
+{
+	const uint32* pal = _cocoa_video_data.palette32;
+	const uint8* src = _cocoa_video_data.pixels;
+	uint32* dst = (uint32*)_cocoa_video_data.realpixels;
+	uint width = _cocoa_video_data.width;
+	uint pitch = _cocoa_video_data.pitch / 4;
+	uint x;
+	uint y;
+
+	for (y = top; y < bottom; y++) {
+		for (x = left; x < right; x++) {
+			dst[y * pitch + x] = pal[src[y * width + x]];
+		}
+	}
+}
+
+static inline void QZ_WindowBlitIndexedPixelsToView16(uint left, uint top, uint right, uint bottom)
+{
+	const uint16* pal = _cocoa_video_data.palette16;
+	const uint8* src = _cocoa_video_data.pixels;
+	uint16* dst = (uint16*)_cocoa_video_data.realpixels;
+	uint width = _cocoa_video_data.width;
+	uint pitch = _cocoa_video_data.pitch / 2;
+	uint x;
+	uint y;
+
+	for (y = top; y < bottom; y++) {
+		for (x = left; x < right; x++) {
+			dst[y * pitch + x] = pal[src[y * width + x]];
+		}
+	}
+}
+
+static inline void QZ_WindowBlitIndexedPixelsToView(int left, int top, int right, int bottom)
+{
+	switch (_cocoa_video_data.device_bpp) {
+		case 32: QZ_WindowBlitIndexedPixelsToView32(left, top, right, bottom); break;
+		case 16: QZ_WindowBlitIndexedPixelsToView16(left, top, right, bottom); break;
+	}
+}
+
+static bool _resize_icon[] = {
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1,
+	0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1,
+	0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0,
+	0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0,
+	0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1,
+	0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1,
+	0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0,
+	1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0
+};
+
+static void QZ_DrawResizeIcon(void)
+{
+	int xoff = _cocoa_video_data.width - 16;
+	int yoff = _cocoa_video_data.height - 16;
+	int x;
+	int y;
+
+	for (y = 0; y < 16; y++) {
+		uint16* trg16 = (uint16*)_cocoa_video_data.realpixels + (yoff + y) * _cocoa_video_data.pitch / 2 + xoff;
+		uint32* trg32 = (uint32*)_cocoa_video_data.realpixels + (yoff + y) * _cocoa_video_data.pitch / 4 + xoff;
+
+		for (x = 0; x < 16; x++, trg16++, trg32++) {
+			if (!_resize_icon[y * 16 + x]) continue;
+
+			switch (_cocoa_video_data.device_bpp) {
+				case 32: *trg32 = 0xff000000; break;
+				case 16: *trg16 = 0x0000;     break;
+			}
+		}
+	}
+}
+
+static void QZ_DrawWindow(void)
+{
+	int i;
+	RgnHandle dirty, temp;
+
+	/* Check if we need to do anything */
+	if (_cocoa_video_data.num_dirty_rects == 0 ||
+			[ _cocoa_video_data.window isMiniaturized ]) {
+		return;
+	}
+
+	if (_cocoa_video_data.num_dirty_rects >= MAX_DIRTY_RECTS) {
+		_cocoa_video_data.num_dirty_rects = 1;
+		_cocoa_video_data.dirty_rects[0].left = 0;
+		_cocoa_video_data.dirty_rects[0].top = 0;
+		_cocoa_video_data.dirty_rects[0].right = _cocoa_video_data.width;
+		_cocoa_video_data.dirty_rects[0].bottom = _cocoa_video_data.height;
+	}
+
+	dirty = NewRgn();
+	temp  = NewRgn();
+
+	SetEmptyRgn(dirty);
+
+	/* Build the region of dirty rectangles */
+	for (i = 0; i < _cocoa_video_data.num_dirty_rects; i++) {
+		QZ_WindowBlitIndexedPixelsToView(
+			_cocoa_video_data.dirty_rects[i].left,
+			_cocoa_video_data.dirty_rects[i].top,
+			_cocoa_video_data.dirty_rects[i].right,
+			_cocoa_video_data.dirty_rects[i].bottom
+		);
+
+		MacSetRectRgn(
+			temp,
+			_cocoa_video_data.dirty_rects[i].left,
+			_cocoa_video_data.dirty_rects[i].top,
+			_cocoa_video_data.dirty_rects[i].right,
+			_cocoa_video_data.dirty_rects[i].bottom
+		);
+		MacUnionRgn(dirty, temp, dirty);
+	}
+
+	QZ_DrawResizeIcon();
+
+	/* Flush the dirty region */
+	QDFlushPortBuffer( (OpaqueGrafPtr*) [ _cocoa_video_data.qdview qdPort ], dirty);
+	DisposeRgn(dirty);
+	DisposeRgn(temp);
+
+	_cocoa_video_data.num_dirty_rects = 0;
+}
+
+
+extern const char _openttd_revision[];
+
+static const char* QZ_SetVideoWindowed(uint width, uint height)
+{
+	char caption[50];
+	NSString *nsscaption;
+	unsigned int style;
+	NSRect contentRect;
+	BOOL isCustom = NO;
+
+	if (width > _cocoa_video_data.device_width)
+		width = _cocoa_video_data.device_width;
+	if (height > _cocoa_video_data.device_height)
+		height = _cocoa_video_data.device_height;
+
+	_cocoa_video_data.width = width;
+	_cocoa_video_data.height = height;
+
+	contentRect = NSMakeRect(0, 0, width, height);
+
+	/* Check if we should completely destroy the previous mode
+	 * - If it is fullscreen
+	 */
+	if (_cocoa_video_data.isset && _cocoa_video_data.fullscreen)
+		QZ_UnsetVideoMode();
+
+	/* Check if we should recreate the window */
+	if (_cocoa_video_data.window == nil) {
+		/* Set the window style */
+		style = NSTitledWindowMask;
+		style |= (NSMiniaturizableWindowMask | NSClosableWindowMask);
+		style |= NSResizableWindowMask;
+
+		/* Manually create a window, avoids having a nib file resource */
+		_cocoa_video_data.window = [ [ OTTD_QuartzWindow alloc ]
+										initWithContentRect:contentRect
+										styleMask:style
+										backing:NSBackingStoreBuffered
+										defer:NO ];
+
+		if (_cocoa_video_data.window == nil)
+			return "Could not create the Cocoa window";
+
+		snprintf(caption, sizeof(caption), "OpenTTD %s", _openttd_revision);
+		nsscaption = [ [ NSString alloc ] initWithCString:caption ];
+		[ _cocoa_video_data.window setTitle:nsscaption ];
+		[ _cocoa_video_data.window setMiniwindowTitle:nsscaption ];
+		[ nsscaption release ];
+
+		[ _cocoa_video_data.window setAcceptsMouseMovedEvents:YES ];
+		[ _cocoa_video_data.window setViewsNeedDisplay:NO ];
+
+		[ _cocoa_video_data.window setDelegate: [ [ [ OTTD_QuartzWindowDelegate alloc ] init ] autorelease ] ];
+	} else {
+		/* We already have a window, just change its size */
+		if (!isCustom) {
+			[ _cocoa_video_data.window setContentSize:contentRect.size ];
+			[ _cocoa_video_data.qdview setFrameSize:contentRect.size ];
+		}
+	}
+
+	[ _cocoa_video_data.window center ];
+
+	/* Only recreate the view if it doesn't already exist */
+	if (_cocoa_video_data.qdview == nil) {
+		_cocoa_video_data.qdview = [ [ NSQuickDrawView alloc ] initWithFrame:contentRect ];
+		[ _cocoa_video_data.qdview setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ];
+		[ [ _cocoa_video_data.window contentView ] addSubview:_cocoa_video_data.qdview ];
+		[ _cocoa_video_data.qdview release ];
+		[ _cocoa_video_data.window makeKeyAndOrderFront:nil ];
+	}
+
+	CGrafPtr thePort = (OpaqueGrafPtr*) [ _cocoa_video_data.qdview qdPort ];
+
+	LockPortBits(thePort);
+	_cocoa_video_data.realpixels = GetPixBaseAddr(GetPortPixMap(thePort));
+	_cocoa_video_data.pitch = GetPixRowBytes(GetPortPixMap(thePort));
+	UnlockPortBits(thePort);
+
+	/* _cocoa_video_data.realpixels now points to the window's pixels
+	 * We want it to point to the *view's* pixels
+	 */
+	{
+		int vOffset = [ _cocoa_video_data.window frame ].size.height - [ _cocoa_video_data.qdview frame ].size.height - [ _cocoa_video_data.qdview frame ].origin.y;
+		int hOffset = [ _cocoa_video_data.qdview frame ].origin.x;
+
+		_cocoa_video_data.realpixels = (uint8*)_cocoa_video_data.realpixels + (vOffset * _cocoa_video_data.pitch) + hOffset * (_cocoa_video_data.device_bpp / 8);
+	}
+
+	free(_cocoa_video_data.pixels);
+	_cocoa_video_data.pixels = (uint8*)malloc(width * height);
+	if (_cocoa_video_data.pixels == NULL) return "Failed to allocate 8-bit buffer";
+
+	_cocoa_video_data.fullscreen = false;
+
+	return NULL;
+}
+
+
+/******************************************************************************
+ *                             Fullscreen mode                                *
+ ******************************************************************************/
+
+/* Gamma functions to try to hide the flash from a rez switch
+ * Fade the display from normal to black
+ * Save gamma tables for fade back to normal
+ */
+static uint32 QZ_FadeGammaOut(OTTD_QuartzGammaTable* table)
+{
+	CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE];
+	CGGammaValue greenTable[QZ_GAMMA_TABLE_SIZE];
+	CGGammaValue blueTable[QZ_GAMMA_TABLE_SIZE];
+	float percent;
+	int j;
+	unsigned int actual;
+
+	if (CGGetDisplayTransferByTable(
+				_cocoa_video_data.display_id, QZ_GAMMA_TABLE_SIZE,
+				table->red, table->green, table->blue, &actual
+			) != CGDisplayNoErr ||
+			actual != QZ_GAMMA_TABLE_SIZE) {
+		return 1;
+	}
+
+	memcpy(redTable,   table->red,   sizeof(redTable));
+	memcpy(greenTable, table->green, sizeof(greenTable));
+	memcpy(blueTable,  table->blue,  sizeof(greenTable));
+
+	for (percent = 1.0; percent >= 0.0; percent -= 0.01) {
+		for (j = 0; j < QZ_GAMMA_TABLE_SIZE; j++) {
+			redTable[j]   = redTable[j]   * percent;
+			greenTable[j] = greenTable[j] * percent;
+			blueTable[j]  = blueTable[j]  * percent;
+		}
+
+		if (CGSetDisplayTransferByTable(
+					_cocoa_video_data.display_id, QZ_GAMMA_TABLE_SIZE,
+					redTable, greenTable, blueTable
+				) != CGDisplayNoErr) {
+			CGDisplayRestoreColorSyncSettings();
+			return 1;
+		}
+
+		CSleep(10);
+	}
+
+	return 0;
+}
+
+/* Fade the display from black to normal
+ * Restore previously saved gamma values
+ */
+static uint32 QZ_FadeGammaIn(const OTTD_QuartzGammaTable* table)
+{
+	CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE];
+	CGGammaValue greenTable[QZ_GAMMA_TABLE_SIZE];
+	CGGammaValue blueTable[QZ_GAMMA_TABLE_SIZE];
+	float percent;
+	int j;
+
+	memset(redTable, 0, sizeof(redTable));
+	memset(greenTable, 0, sizeof(greenTable));
+	memset(blueTable, 0, sizeof(greenTable));
+
+	for (percent = 0.0; percent <= 1.0; percent += 0.01) {
+		for (j = 0; j < QZ_GAMMA_TABLE_SIZE; j++) {
+			redTable[j]   = table->red[j]   * percent;
+			greenTable[j] = table->green[j] * percent;
+			blueTable[j]  = table->blue[j]  * percent;
+		}
+
+		if (CGSetDisplayTransferByTable(
+					_cocoa_video_data.display_id, QZ_GAMMA_TABLE_SIZE,
+					redTable, greenTable, blueTable
+				) != CGDisplayNoErr) {
+			CGDisplayRestoreColorSyncSettings();
+			return 1;
+		}
+
+		CSleep(10);
+	}
+
+	return 0;
+}
+
+static const char* QZ_SetVideoFullScreen(int width, int height)
+{
+	const char* errstr = "QZ_SetVideoFullScreen error";
+	int exact_match;
+	CFNumberRef number;
+	int bpp;
+	int gamma_error;
+	OTTD_QuartzGammaTable gamma_table;
+	NSRect screen_rect;
+	CGError error;
+	NSPoint pt;
+
+	/* Destroy any previous mode */
+	if (_cocoa_video_data.isset) QZ_UnsetVideoMode();
+
+	/* See if requested mode exists */
+	_cocoa_video_data.mode = CGDisplayBestModeForParameters(_cocoa_video_data.display_id, 8, width, height, &exact_match);
+
+	/* If the mode wasn't an exact match, check if it has the right bpp, and update width and height */
+	if (!exact_match) {
+		number = (const __CFNumber*) CFDictionaryGetValue(_cocoa_video_data.mode, kCGDisplayBitsPerPixel);
+		CFNumberGetValue(number, kCFNumberSInt32Type, &bpp);
+		if (bpp != 8) {
+			errstr = "Failed to find display resolution";
+			goto ERR_NO_MATCH;
+		}
+
+		number = (const __CFNumber*)CFDictionaryGetValue(_cocoa_video_data.mode, kCGDisplayWidth);
+		CFNumberGetValue(number, kCFNumberSInt32Type, &width);
+
+		number = (const __CFNumber*)CFDictionaryGetValue(_cocoa_video_data.mode, kCGDisplayHeight);
+		CFNumberGetValue(number, kCFNumberSInt32Type, &height);
+	}
+
+	/* Fade display to zero gamma */
+	gamma_error = QZ_FadeGammaOut(&gamma_table);
+
+	/* Put up the blanking window (a window above all other windows) */
+	error = CGDisplayCapture(_cocoa_video_data.display_id);
+
+	if (CGDisplayNoErr != error) {
+		errstr = "Failed capturing display";
+		goto ERR_NO_CAPTURE;
+	}
+
+	/* Do the physical switch */
+	if (CGDisplaySwitchToMode(_cocoa_video_data.display_id, _cocoa_video_data.mode) != CGDisplayNoErr) {
+		errstr = "Failed switching display resolution";
+		goto ERR_NO_SWITCH;
+	}
+
+	_cocoa_video_data.realpixels = (uint8*)CGDisplayBaseAddress(_cocoa_video_data.display_id);
+	_cocoa_video_data.pitch  = CGDisplayBytesPerRow(_cocoa_video_data.display_id);
+
+	_cocoa_video_data.width = CGDisplayPixelsWide(_cocoa_video_data.display_id);
+	_cocoa_video_data.height = CGDisplayPixelsHigh(_cocoa_video_data.display_id);
+	_cocoa_video_data.fullscreen = true;
+
+	/* Setup double-buffer emulation */
+	_cocoa_video_data.pixels = (uint8*)malloc(width * height);
+	if (_cocoa_video_data.pixels == NULL) {
+		errstr = "Failed to allocate memory for double buffering";
+		goto ERR_DOUBLEBUF;
+	}
+
+	if (!CGDisplayCanSetPalette(_cocoa_video_data.display_id)) {
+		errstr = "Not an indexed display mode.";
+		goto ERR_NOT_INDEXED;
+	}
+
+	/* If we don't hide menu bar, it will get events and interrupt the program */
+	HideMenuBar();
+
+	/* Fade the display to original gamma */
+	if (!gamma_error) QZ_FadeGammaIn(&gamma_table);
+
+	/* There is a bug in Cocoa where NSScreen doesn't synchronize
+	 * with CGDirectDisplay, so the main screen's frame is wrong.
+	 * As a result, coordinate translation produces incorrect results.
+	 * We can hack around this bug by setting the screen rect ourselves.
+	 * This hack should be removed if/when the bug is fixed.
+	 */
+	screen_rect = NSMakeRect(0, 0, width, height);
+	[ [ NSScreen mainScreen ] setFrame:screen_rect ];
+
+	/* we're fullscreen, so flag all input states... */
+	_cocoa_video_data.active = true;
+
+
+	pt = [ NSEvent mouseLocation ];
+	pt.y = CGDisplayPixelsHigh(_cocoa_video_data.display_id) - pt.y;
+	if (QZ_MouseIsInsideView(&pt)) QZ_HideMouse();
+
+	return NULL;
+
+/* Since the blanking window covers *all* windows (even force quit) correct recovery is crucial */
+ERR_NOT_INDEXED:
+	free(_cocoa_video_data.pixels);
+	_cocoa_video_data.pixels = NULL;
+ERR_DOUBLEBUF:
+	CGDisplaySwitchToMode(_cocoa_video_data.display_id, _cocoa_video_data.save_mode);
+ERR_NO_SWITCH:
+	CGReleaseAllDisplays();
+ERR_NO_CAPTURE:
+	if (!gamma_error) QZ_FadeGammaIn(&gamma_table);
+ERR_NO_MATCH:
+	return errstr;
+}
+
+
+static void QZ_UpdateFullscreenPalette(uint first_color, uint num_colors)
+{
+	CGTableCount  index;
+	CGDeviceColor color;
+
+	for (index = first_color; index < first_color+num_colors; index++) {
+		/* Clamp colors between 0.0 and 1.0 */
+		color.red   = _cur_palette[index].r / 255.0;
+		color.blue  = _cur_palette[index].b / 255.0;
+		color.green = _cur_palette[index].g / 255.0;
+
+		CGPaletteSetColorAtIndex(_cocoa_video_data.palette, color, index);
+	}
+
+	CGDisplaySetPalette(_cocoa_video_data.display_id, _cocoa_video_data.palette);
+}
+
+/* Wait for the VBL to occur (estimated since we don't have a hardware interrupt) */
+static void QZ_WaitForVerticalBlank(void)
+{
+	/* The VBL delay is based on Ian Ollmann's RezLib <iano@cco.caltech.edu> */
+	double refreshRate;
+	double linesPerSecond;
+	double target;
+	double position;
+	double adjustment;
+	CFNumberRef refreshRateCFNumber;
+
+	refreshRateCFNumber = (const __CFNumber*)CFDictionaryGetValue(_cocoa_video_data.mode, kCGDisplayRefreshRate);
+	if (refreshRateCFNumber == NULL) return;
+
+	if (CFNumberGetValue(refreshRateCFNumber, kCFNumberDoubleType, &refreshRate) == 0)
+		return;
+
+	if (refreshRate == 0) return;
+
+	linesPerSecond = refreshRate * _cocoa_video_data.height;
+	target = _cocoa_video_data.height;
+
+	/* Figure out the first delay so we start off about right */
+	position = CGDisplayBeamPosition(_cocoa_video_data.display_id);
+	if (position > target) position = 0;
+
+	adjustment = (target - position) / linesPerSecond;
+
+	CSleep((uint32)(adjustment * 1000));
+}
+
+
+static void QZ_DrawScreen(void)
+{
+	const uint8* src = _cocoa_video_data.pixels;
+	uint8* dst       = (uint8*)_cocoa_video_data.realpixels;
+	uint pitch       = _cocoa_video_data.pitch;
+	uint width       = _cocoa_video_data.width;
+	uint num_dirty   = _cocoa_video_data.num_dirty_rects;
+	uint i;
+
+	/* Check if we need to do anything */
+	if (num_dirty == 0) return;
+
+	if (num_dirty >= MAX_DIRTY_RECTS) {
+		num_dirty = 1;
+		_cocoa_video_data.dirty_rects[0].left   = 0;
+		_cocoa_video_data.dirty_rects[0].top    = 0;
+		_cocoa_video_data.dirty_rects[0].right  = _cocoa_video_data.width;
+		_cocoa_video_data.dirty_rects[0].bottom = _cocoa_video_data.height;
+	}
+
+	QZ_WaitForVerticalBlank();
+	/* Build the region of dirty rectangles */
+	for (i = 0; i < num_dirty; i++) {
+		uint y      = _cocoa_video_data.dirty_rects[i].top;
+		uint left   = _cocoa_video_data.dirty_rects[i].left;
+		uint length = _cocoa_video_data.dirty_rects[i].right - left;
+		uint bottom = _cocoa_video_data.dirty_rects[i].bottom;
+
+		for (; y < bottom; y++) {
+			memcpy(dst + y * pitch + left, src + y * width + left, length);
+		}
+	}
+
+	_cocoa_video_data.num_dirty_rects = 0;
+}
+
+
+static int QZ_ListFullscreenModes(OTTDPoint* mode_list, int max_modes)
+{
+	CFIndex num_modes;
+	CFIndex i;
+	int list_size = 0;
+
+	num_modes = CFArrayGetCount(_cocoa_video_data.mode_list);
+
+	/* Build list of modes with the requested bpp */
+	for (i = 0; i < num_modes && list_size < max_modes; i++) {
+		CFDictionaryRef onemode;
+		CFNumberRef     number;
+		int bpp;
+		int intvalue;
+		bool hasMode;
+		uint16 width, height;
+
+		onemode = (const __CFDictionary*)CFArrayGetValueAtIndex(_cocoa_video_data.mode_list, i);
+		number = (const __CFNumber*)CFDictionaryGetValue(onemode, kCGDisplayBitsPerPixel);
+		CFNumberGetValue (number, kCFNumberSInt32Type, &bpp);
+
+		if (bpp != 8) continue;
+
+		number = (const __CFNumber*)CFDictionaryGetValue(onemode, kCGDisplayWidth);
+		CFNumberGetValue(number, kCFNumberSInt32Type, &intvalue);
+		width = (uint16)intvalue;
+
+		number = (const __CFNumber*)CFDictionaryGetValue(onemode, kCGDisplayHeight);
+		CFNumberGetValue(number, kCFNumberSInt32Type, &intvalue);
+		height = (uint16)intvalue;
+
+		/* Check if mode is already in the list */
+		{
+			int i;
+			hasMode = false;
+			for (i = 0; i < list_size; i++) {
+				if (mode_list[i].x == width &&  mode_list[i].y == height) {
+					hasMode = true;
+					break;
+				}
+			}
+		}
+
+		if (hasMode) continue;
+
+		/* Add mode to the list */
+		mode_list[list_size].x = width;
+		mode_list[list_size].y = height;
+		list_size++;
+	}
+
+	/* Sort list smallest to largest */
+	{
+		int i, j;
+		for (i = 0; i < list_size; i++) {
+			for (j = 0; j < list_size-1; j++) {
+				if (mode_list[j].x > mode_list[j + 1].x || (
+							mode_list[j].x == mode_list[j + 1].x &&
+							mode_list[j].y >  mode_list[j + 1].y
+						)) {
+					uint tmpw = mode_list[j].x;
+					uint tmph = mode_list[j].y;
+
+					mode_list[j].x = mode_list[j + 1].x;
+					mode_list[j].y = mode_list[j + 1].y;
+
+					mode_list[j + 1].x = tmpw;
+					mode_list[j + 1].y = tmph;
+				}
+			}
+		}
+	}
+
+	return list_size;
+}
+
+
+/******************************************************************************
+ *                             Windowed and fullscreen common code            *
+ ******************************************************************************/
+
+static void QZ_UpdatePalette(uint start, uint count)
+{
+	if (_cocoa_video_data.fullscreen) {
+		QZ_UpdateFullscreenPalette(start, count);
+	} else {
+		QZ_UpdateWindowPalette(start, count);
+	}
+}
+
+static void QZ_InitPalette(void)
+{
+	QZ_UpdatePalette(0, 256);
+}
+
+static void QZ_Draw(void)
+{
+	if (_cocoa_video_data.fullscreen) {
+		QZ_DrawScreen();
+	} else {
+		QZ_DrawWindow();
+	}
+}
+
+
+static const OTTDPoint _default_resolutions[] = {
+	{ 640,  480},
+	{ 800,  600},
+	{1024,  768},
+	{1152,  864},
+	{1280,  800},
+	{1280,  960},
+	{1280, 1024},
+	{1400, 1050},
+	{1600, 1200},
+	{1680, 1050},
+	{1920, 1200}
+};
+
+static void QZ_UpdateVideoModes(void)
+{
+	uint i, j, count;
+	OTTDPoint modes[32];
+	const OTTDPoint *current_modes;
+
+	if (_cocoa_video_data.fullscreen) {
+		count = QZ_ListFullscreenModes(modes, 32);
+		current_modes = modes;
+	} else {
+		count = lengthof(_default_resolutions);
+		current_modes = _default_resolutions;
+	}
+
+	for (i = 0, j = 0; j < lengthof(_resolutions) && i < count; i++) {
+		if (_cocoa_video_data.fullscreen || (
+					(uint)current_modes[i].x < _cocoa_video_data.device_width &&
+					(uint)current_modes[i].y < _cocoa_video_data.device_height)
+				) {
+			_resolutions[j][0] = current_modes[i].x;
+			_resolutions[j][1] = current_modes[i].y;
+			j++;
+		}
+	}
+
+	_num_resolutions = j;
+}
+
+static void QZ_UnsetVideoMode(void)
+{
+	if (_cocoa_video_data.fullscreen) {
+		/* Release fullscreen resources */
+		OTTD_QuartzGammaTable gamma_table;
+		int gamma_error;
+		NSRect screen_rect;
+
+		gamma_error = QZ_FadeGammaOut(&gamma_table);
+
+		/* Restore original screen resolution/bpp */
+		CGDisplaySwitchToMode(_cocoa_video_data.display_id, _cocoa_video_data.save_mode);
+		CGReleaseAllDisplays();
+		ShowMenuBar();
+		/* Reset the main screen's rectangle
+		 * See comment in QZ_SetVideoFullscreen for why we do this
+		 */
+		screen_rect = NSMakeRect(0,0,_cocoa_video_data.device_width,_cocoa_video_data.device_height);
+		[ [ NSScreen mainScreen ] setFrame:screen_rect ];
+
+		if (!gamma_error) QZ_FadeGammaIn(&gamma_table);
+	} else {
+		/* Release window mode resources */
+		[ _cocoa_video_data.window close ];
+		_cocoa_video_data.window = nil;
+		_cocoa_video_data.qdview = nil;
+	}
+
+	free(_cocoa_video_data.pixels);
+	_cocoa_video_data.pixels = NULL;
+
+	/* Signal successful teardown */
+	_cocoa_video_data.isset = false;
+
+	QZ_ShowMouse();
+}
+
+
+static const char* QZ_SetVideoMode(uint width, uint height, bool fullscreen)
+{
+	const char *ret;
+
+	_cocoa_video_data.issetting = true;
+	if (fullscreen) {
+		/* Setup full screen video */
+		ret = QZ_SetVideoFullScreen(width, height);
+	} else {
+		/* Setup windowed video */
+		ret = QZ_SetVideoWindowed(width, height);
+	}
+	_cocoa_video_data.issetting = false;
+	if (ret != NULL) return ret;
+
+	/* Signal successful completion (used internally) */
+	_cocoa_video_data.isset = true;
+
+	/* Tell the game that the resolution has changed */
+	_screen.width = _cocoa_video_data.width;
+	_screen.height = _cocoa_video_data.height;
+	_screen.pitch = _cocoa_video_data.width;
+
+	QZ_UpdateVideoModes();
+	GameSizeChanged();
+
+	QZ_InitPalette();
+
+	return NULL;
+}
+
+static const char* QZ_SetVideoModeAndRestoreOnFailure(uint width, uint height, bool fullscreen)
+{
+	bool wasset = _cocoa_video_data.isset;
+	uint32 oldwidth = _cocoa_video_data.width;
+	uint32 oldheight = _cocoa_video_data.height;
+	bool oldfullscreen = _cocoa_video_data.fullscreen;
+	const char *ret;
+
+	ret = QZ_SetVideoMode(width, height, fullscreen);
+	if (ret != NULL && wasset) QZ_SetVideoMode(oldwidth, oldheight, oldfullscreen);
+
+	return ret;
+}
+
+static void QZ_VideoInit(void)
+{
+	memset(&_cocoa_video_data, 0, sizeof(_cocoa_video_data));
+
+	/* Initialize the video settings; this data persists between mode switches */
+	_cocoa_video_data.display_id = kCGDirectMainDisplay;
+	_cocoa_video_data.save_mode  = CGDisplayCurrentMode(_cocoa_video_data.display_id);
+	_cocoa_video_data.mode_list  = CGDisplayAvailableModes(_cocoa_video_data.display_id);
+	_cocoa_video_data.palette    = CGPaletteCreateDefaultColorPalette();
+
+	/* Gather some information that is useful to know about the display */
+	/* Maybe this should be moved to QZ_SetVideoMode, in case this is changed after startup */
+	CFNumberGetValue(
+		(const __CFNumber*)CFDictionaryGetValue(_cocoa_video_data.save_mode, kCGDisplayBitsPerPixel),
+		kCFNumberSInt32Type, &_cocoa_video_data.device_bpp
+	);
+
+	CFNumberGetValue(
+		(const __CFNumber*)CFDictionaryGetValue(_cocoa_video_data.save_mode, kCGDisplayWidth),
+		kCFNumberSInt32Type, &_cocoa_video_data.device_width
+	);
+
+	CFNumberGetValue(
+		(const __CFNumber*)CFDictionaryGetValue(_cocoa_video_data.save_mode, kCGDisplayHeight),
+		kCFNumberSInt32Type, &_cocoa_video_data.device_height
+	);
+
+	_cocoa_video_data.cursor_visible = true;
+
+	/* register for sleep notifications so wake from sleep generates SDL_VIDEOEXPOSE */
+//	QZ_RegisterForSleepNotifications();
+}
+
+
+/* Convert local coordinate to window server (CoreGraphics) coordinate */
+static CGPoint QZ_PrivateLocalToCG(NSPoint* p)
+{
+	CGPoint cgp;
+
+	if (!_cocoa_video_data.fullscreen) {
+		*p = [ _cocoa_video_data.qdview convertPoint:*p toView: nil ];
+		*p = [ _cocoa_video_data.window convertBaseToScreen:*p ];
+		p->y = _cocoa_video_data.device_height - p->y;
+	}
+
+	cgp.x = p->x;
+	cgp.y = p->y;
+
+	return cgp;
+}
+
+static void QZ_WarpCursor(int x, int y)
+{
+	NSPoint p;
+	CGPoint cgp;
+
+	/* Only allow warping when in foreground */
+	if (![ NSApp isActive ]) return;
+
+	p = NSMakePoint(x, y);
+	cgp = QZ_PrivateLocalToCG(&p);
+
+	/* this is the magic call that fixes cursor "freezing" after warp */
+	CGSetLocalEventsSuppressionInterval(0.0);
+	/* Do the actual warp */
+	CGWarpMouseCursorPosition(cgp);
+
+	/* Generate the mouse moved event */
+}
+
+static void QZ_ShowMouse(void)
+{
+	if (!_cocoa_video_data.cursor_visible) {
+		[ NSCursor unhide ];
+		_cocoa_video_data.cursor_visible = true;
+
+		// Hide the openttd cursor when leaving the window
+		if (_cocoa_video_data.isset)
+			UndrawMouseCursor();
+		_cursor.in_window = false;
+	}
+}
+
+static void QZ_HideMouse(void)
+{
+	if (_cocoa_video_data.cursor_visible) {
+#ifndef _DEBUG
+		[ NSCursor hide ];
+#endif
+		_cocoa_video_data.cursor_visible = false;
+
+		// Show the openttd cursor again
+		_cursor.in_window = true;
+	}
+}
+
+
+/******************************************************************************
+ *                             OS X application creation                      *
+ ******************************************************************************/
+
+/* The main class of the application, the application's delegate */
+@implementation OTTDMain
+/* Called when the internal event loop has just started running */
+- (void) applicationDidFinishLaunching: (NSNotification*) note
+{
+	/* Hand off to main application code */
+	QZ_GameLoop();
+
+	/* We're done, thank you for playing */
+	[ NSApp stop:_ottd_main ];
+}
+
+/* Display the in game quit confirmation dialog */
+- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*) sender
+{
+
+	HandleExitGameRequest();
+
+	return NSTerminateCancel; // NSTerminateLater ?
+}
+@end
+
+static void setApplicationMenu(void)
+{
+	/* warning: this code is very odd */
+	NSMenu *appleMenu;
+	NSMenuItem *menuItem;
+	NSString *title;
+	NSString *appName;
+
+	appName = @"OTTD";
+	appleMenu = [[NSMenu alloc] initWithTitle:appName];
+
+	/* Add menu items */
+	title = [@"About " stringByAppendingString:appName];
+	[appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
+
+	[appleMenu addItem:[NSMenuItem separatorItem]];
+
+	title = [@"Hide " stringByAppendingString:appName];
+	[appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
+
+	menuItem = (NSMenuItem*)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
+	[menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
+
+	[appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
+
+	[appleMenu addItem:[NSMenuItem separatorItem]];
+
+	title = [@"Quit " stringByAppendingString:appName];
+	[appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
+
+
+	/* Put menu into the menubar */
+	menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
+	[menuItem setSubmenu:appleMenu];
+	[[NSApp mainMenu] addItem:menuItem];
+
+	/* Tell the application object that this is now the application menu */
+	[NSApp setAppleMenu:appleMenu];
+
+	/* Finally give up our references to the objects */
+	[appleMenu release];
+	[menuItem release];
+}
+
+/* Create a window menu */
+static void setupWindowMenu(void)
+{
+	NSMenu* windowMenu;
+	NSMenuItem* windowMenuItem;
+	NSMenuItem* menuItem;
+
+	windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
+
+	/* "Minimize" item */
+	menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
+	[windowMenu addItem:menuItem];
+	[menuItem release];
+
+	/* Put menu into the menubar */
+	windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
+	[windowMenuItem setSubmenu:windowMenu];
+	[[NSApp mainMenu] addItem:windowMenuItem];
+
+	/* Tell the application object that this is now the window menu */
+	[NSApp setWindowsMenu:windowMenu];
+
+	/* Finally give up our references to the objects */
+	[windowMenu release];
+	[windowMenuItem release];
+}
+
+static void setupApplication(void)
+{
+	CPSProcessSerNum PSN;
+
+	/* Ensure the application object is initialised */
+	[NSApplication sharedApplication];
+
+	/* Tell the dock about us */
+	if (!CPSGetCurrentProcess(&PSN) &&
+			!CPSEnableForegroundOperation(&PSN, 0x03, 0x3C, 0x2C, 0x1103) &&
+			!CPSSetFrontProcess(&PSN)) {
+		[NSApplication sharedApplication];
+	}
+
+	/* Set up the menubar */
+	[NSApp setMainMenu:[[NSMenu alloc] init]];
+	setApplicationMenu();
+	setupWindowMenu();
+
+	/* Create OTTDMain and make it the app delegate */
+	_ottd_main = [[OTTDMain alloc] init];
+	[NSApp setDelegate:_ottd_main];
+}
+
+
+/******************************************************************************
+ *                             Video driver interface                         *
+ ******************************************************************************/
+
+static void CocoaVideoStop(void)
+{
+	if (!_cocoa_video_started) return;
+
+	if (_cocoa_video_data.isset) QZ_UnsetVideoMode();
+
+	[_ottd_main release];
+
+	_cocoa_video_started = false;
+}
+
+static const char *CocoaVideoStart(const char * const *parm)
+{
+	const char *ret;
+
+	if (_cocoa_video_started) return "Already started";
+	_cocoa_video_started = true;
+
+	memset(&_cocoa_video_data, 0, sizeof(_cocoa_video_data));
+
+	setupApplication();
+
+	/* Don't create a window or enter fullscreen if we're just going to show a dialog. */
+	if (_cocoa_video_dialog) return NULL;
+
+	QZ_VideoInit();
+
+	ret = QZ_SetVideoMode(_cur_resolution[0], _cur_resolution[1], _fullscreen);
+	if (ret != NULL) CocoaVideoStop();
+
+	return ret;
+}
+
+static void CocoaVideoMakeDirty(int left, int top, int width, int height)
+{
+	if (_cocoa_video_data.num_dirty_rects < MAX_DIRTY_RECTS) {
+		_cocoa_video_data.dirty_rects[_cocoa_video_data.num_dirty_rects].left = left;
+		_cocoa_video_data.dirty_rects[_cocoa_video_data.num_dirty_rects].top = top;
+		_cocoa_video_data.dirty_rects[_cocoa_video_data.num_dirty_rects].right = left + width;
+		_cocoa_video_data.dirty_rects[_cocoa_video_data.num_dirty_rects].bottom = top + height;
+	}
+	_cocoa_video_data.num_dirty_rects++;
+}
+
+static void CocoaVideoMainLoop(void)
+{
+	/* Start the main event loop */
+	[NSApp run];
+}
+
+static bool CocoaVideoChangeRes(int w, int h)
+{
+	const char *ret = QZ_SetVideoModeAndRestoreOnFailure((uint)w, (uint)h, _cocoa_video_data.fullscreen);
+	if (ret != NULL) {
+		DEBUG(driver, 0, "cocoa_v: CocoaVideoChangeRes failed with message: %s", ret);
+	}
+
+	return ret == NULL;
+}
+
+static void CocoaVideoFullScreen(bool full_screen)
+{
+	const char *ret = QZ_SetVideoModeAndRestoreOnFailure(_cocoa_video_data.width, _cocoa_video_data.height, full_screen);
+	if (ret != NULL) {
+		DEBUG(driver, 0, "cocoa_v: CocoaVideoFullScreen failed with message: %s", ret);
+	}
+
+	_fullscreen = _cocoa_video_data.fullscreen;
+}
+
+const HalVideoDriver _cocoa_video_driver = {
+	CocoaVideoStart,
+	CocoaVideoStop,
+	CocoaVideoMakeDirty,
+	CocoaVideoMainLoop,
+	CocoaVideoChangeRes,
+	CocoaVideoFullScreen,
+};
+
+
+/* This is needed since sometimes assert is called before the videodriver is initialized */
+void CocoaDialog(const char* title, const char* message, const char* buttonLabel)
+{
+	bool wasstarted;
+
+	_cocoa_video_dialog = true;
+
+	wasstarted = _cocoa_video_started;
+	if (!_cocoa_video_started && CocoaVideoStart(NULL) != NULL) {
+		fprintf(stderr, "%s: %s\n", title, message);
+		return;
+	}
+
+	NSRunAlertPanel([NSString stringWithCString: title], [NSString stringWithCString: message], [NSString stringWithCString: buttonLabel], nil, nil);
+
+	if (!wasstarted) CocoaVideoStop();
+
+	_cocoa_video_dialog = false;
+}
+
+
+/* This is needed since OS X applications are started with the working dir set to / when double-clicked */
+void cocoaSetWorkingDirectory(void)
+{
+	char parentdir[MAXPATHLEN];
+	int chdir_ret;
+	CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
+	CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url);
+	if (CFURLGetFileSystemRepresentation(url2, true, (unsigned char*)parentdir, MAXPATHLEN)) {
+		chdir_ret = chdir(parentdir); /* chdir to the binary app's parent */
+		assert(chdir_ret == 0);
+	}
+	CFRelease(url);
+	CFRelease(url2);
+}
+
+/* These are called from main() to prevent a _NSAutoreleaseNoPool error when
+ * exiting before the cocoa video driver has been loaded
+ */
+void cocoaSetupAutoreleasePool(void)
+{
+	_ottd_autorelease_pool = [[NSAutoreleasePool alloc] init];
+}
+
+void cocoaReleaseAutoreleasePool(void)
+{
+	[_ottd_autorelease_pool release];
+}
+
+#endif /* WITH_COCOA */