diff --git a/GLFW-b.cabal b/GLFW-b.cabal
--- a/GLFW-b.cabal
+++ b/GLFW-b.cabal
@@ -1,5 +1,5 @@
 name:         GLFW-b
-version:      0.0.2.2
+version:      0.0.2.3
 
 category:     Graphics
 
@@ -41,7 +41,16 @@
   glfw/lib/cocoa/platform.h
   glfw/lib/win32/platform.h
   glfw/lib/x11/platform.h
-
+  -- We can't explicitly list these as
+  -- C sources so we list them here.
+  glfw/lib/cocoa/cocoa_enable.m
+  glfw/lib/cocoa/cocoa_joystick.m
+  glfw/lib/cocoa/cocoa_fullscreen.m
+  glfw/lib/cocoa/cocoa_time.m
+  glfw/lib/cocoa/cocoa_glext.m
+  glfw/lib/cocoa/cocoa_window.m
+  glfw/lib/cocoa/cocoa_init.m
+  glfw/lib/cocoa/cocoa_thread.c
 -- -- -- -- -- -- -- -- -- --
 
 library
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -1,18 +1,19 @@
-FRAMEWORK = -framework AGL -framework Cocoa -framework OpenGL
-CFLAGS    = -O2 -Iglfw/include -Iglfw/lib -Iglfw/lib/cocoa
-SRC_DIR   = glfw/lib/cocoa
-BUILD_DIR = build
+FRAMEWORK := -framework AGL -framework Cocoa -framework OpenGL
+GLFW_FLAG := -m32 -O2 -Iglfw/include -Iglfw/lib -Iglfw/lib/cocoa $(CFLAGS)
+SRC_DIR   := glfw/lib/cocoa
+GLFW_DIR  := glfw/lib
+BUILD_DIR := build
 
-OBJ_C_SRC = $(shell find $(SRC_DIR) -name "*.m")
-C_SRC     = $(shell find $(SRC_DIR) -name "*.c")
-GLFW_SRC  = $(shell find glfw/lib -depth 1 -name "*.c")
-SRC       = $(OBJ_C_SRC) $(C_SRC)
-OBJS      = $(addprefix $(BUILD_DIR)/, $(OBJ_C_SRC:.m=.o) $(C_SRC:.c=.o))
+OBJ_C_SRC := $(wildcard $(SRC_DIR)/*.m)
+C_SRC     := $(wildcard $(SRC_DIR)/*.c)
+GLFW_SRC  := $(wildcard $(GLFW_DIR)/*.c)
+OBJS      := $(addprefix $(BUILD_DIR)/, $(OBJ_C_SRC:.m=.o) $(C_SRC:.c=.o))
 
-all: $(BUILD_DIR)/libglfw.a $(BUILD_DIR)/libglfw.dylib
+all: $(BUILD_DIR)/libglfw.a
 
-$(BUILD_DIR)/libglfw.dylib: $(OBJS)
-	$(CC) -dynamiclib $(CFLAGS) -o $@ $(OBJS) $(GLFW_SRC) $(FRAMEWORK)
+# The .dylib was creating more problems than it solved.
+#$(BUILD_DIR)/libglfw.dylib: $(OBJS)
+#	$(CC) -dynamiclib $(GLFW_FLAG) -o $@ $(OBJS) $(GLFW_SRC) $(FRAMEWORK)
 
 $(BUILD_DIR)/libglfw.a: $(OBJS)
 	ar -r -s $@ $(OBJS)
@@ -24,9 +25,9 @@
 $(OBJS): $(BUILD_DIR)/$(SRC_DIR)/.build-tag
 
 $(BUILD_DIR)/%.o : %.c
-	$(CC) -c $(CFLAGS) $< -o $@
+	$(CC) -c $(GLFW_FLAG) $< -o $@
 $(BUILD_DIR)/%.o : %.m
-	$(CC) -c $(CFLAGS) $< -o $@
+	$(CC) -c $(GLFW_FLAG) $< -o $@
 
 .PHONY: clean
 clean:
diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
@@ -97,9 +97,7 @@
           verbosity = fromFlag $ copyVerbosity flags
           copy dest f = installOrdinaryFile verbosity (extraLibDir</>f) (dest</>f)
       maybe (return ()) (copy libPref) (Just libName)
-      maybe (return ()) (copy libPref) (Just sharedName)
     _ -> return ()
 
-libName, sharedName :: FilePath
+libName :: FilePath
 libName = "libglfw.a"
-sharedName = "libglfw.dylib"
diff --git a/glfw/lib/cocoa/cocoa_enable.m b/glfw/lib/cocoa/cocoa_enable.m
new file mode 100644
--- /dev/null
+++ b/glfw/lib/cocoa/cocoa_enable.m
@@ -0,0 +1,52 @@
+//========================================================================
+// GLFW - An OpenGL framework
+// File:        macosx_enable.m
+// Platform:    Mac OS X
+// API Version: 2.7
+// WWW:         http://glfw.sourceforge.net
+//------------------------------------------------------------------------
+// Copyright (c) 2002-2006 Camilla Berglund
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+//    claim that you wrote the original software. If you use this software
+//    in a product, an acknowledgment in the product documentation would
+//    be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such, and must not
+//    be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source
+//    distribution.
+//
+//========================================================================
+
+#include "internal.h"
+
+//************************************************************************
+//****               Platform implementation functions                ****
+//************************************************************************
+
+//========================================================================
+// Enable and disable system keys
+//========================================================================
+
+void _glfwPlatformEnableSystemKeys( void )
+{
+    // This is checked in macosx_window.m; we take no action here
+}
+
+void _glfwPlatformDisableSystemKeys( void )
+{
+    // This is checked in macosx_window.m; we take no action here
+    // I don't think it's really possible to disable stuff like Exposé
+    // except in full-screen mode.
+}
+
diff --git a/glfw/lib/cocoa/cocoa_fullscreen.m b/glfw/lib/cocoa/cocoa_fullscreen.m
new file mode 100644
--- /dev/null
+++ b/glfw/lib/cocoa/cocoa_fullscreen.m
@@ -0,0 +1,103 @@
+//========================================================================
+// GLFW - An OpenGL framework
+// File:        macosx_fullscreen.m
+// Platform:    Mac OS X
+// API Version: 2.7
+// WWW:         http://glfw.sourceforge.net
+//------------------------------------------------------------------------
+// Copyright (c) 2002-2006 Camilla Berglund
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+//    claim that you wrote the original software. If you use this software
+//    in a product, an acknowledgment in the product documentation would
+//    be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such, and must not
+//    be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source
+//    distribution.
+//
+//========================================================================
+
+#include "internal.h"
+
+//========================================================================
+// Check whether the display mode should be included in enumeration
+//========================================================================
+
+static BOOL modeIsGood( NSDictionary *mode )
+{
+    // This is a bit controversial, if you've got something other than an
+    // LCD computer monitor as an output device you might not want these
+    // checks.  You might also want to reject modes which are interlaced,
+    // or TV out.  There is no one-size-fits-all policy that can work here.
+    // This seems like a decent compromise, but certain applications may
+    // wish to patch this...
+    return [[mode objectForKey:(id)kCGDisplayBitsPerPixel] intValue] >= 15 &&
+           [mode objectForKey:(id)kCGDisplayModeIsSafeForHardware] != nil &&
+           [mode objectForKey:(id)kCGDisplayModeIsStretched] == nil;
+}
+
+//========================================================================
+// Convert Core Graphics display mode to GLFW video mode
+//========================================================================
+
+static GLFWvidmode vidmodeFromCGDisplayMode( NSDictionary *mode )
+{
+    unsigned int width = [[mode objectForKey:(id)kCGDisplayWidth] unsignedIntValue];
+    unsigned int height = [[mode objectForKey:(id)kCGDisplayHeight] unsignedIntValue];
+    unsigned int bps = [[mode objectForKey:(id)kCGDisplayBitsPerSample] unsignedIntValue];
+
+    GLFWvidmode result;
+    result.Width = width;
+    result.Height = height;
+    result.RedBits = bps;
+    result.GreenBits = bps;
+    result.BlueBits = bps;
+    return result;
+}
+
+
+//************************************************************************
+//****               Platform implementation functions                ****
+//************************************************************************
+
+//========================================================================
+// Get a list of available video modes
+//========================================================================
+
+int _glfwPlatformGetVideoModes( GLFWvidmode *list, int maxcount )
+{
+    NSArray *modes = (NSArray *)CGDisplayAvailableModes( CGMainDisplayID() );
+
+    unsigned int i, j = 0, n = [modes count];
+    for( i = 0; i < n && i < (unsigned)maxcount; i++ )
+    {
+        NSDictionary *mode = [modes objectAtIndex:i];
+        if( modeIsGood( mode ) )
+        {
+            list[j++] = vidmodeFromCGDisplayMode( mode );
+        }
+    }
+
+    return j;
+}
+
+//========================================================================
+// Get the desktop video mode
+//========================================================================
+
+void _glfwPlatformGetDesktopMode( GLFWvidmode *mode )
+{
+    *mode = vidmodeFromCGDisplayMode( _glfwLibrary.DesktopMode );
+}
+
diff --git a/glfw/lib/cocoa/cocoa_glext.m b/glfw/lib/cocoa/cocoa_glext.m
new file mode 100644
--- /dev/null
+++ b/glfw/lib/cocoa/cocoa_glext.m
@@ -0,0 +1,64 @@
+//========================================================================
+// GLFW - An OpenGL framework
+// File:        macosx_glext.m
+// Platform:    Mac OS X
+// API Version: 2.7
+// WWW:         http://glfw.sourceforge.net
+//------------------------------------------------------------------------
+// Copyright (c) 2002-2006 Camilla Berglund
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+//    claim that you wrote the original software. If you use this software
+//    in a product, an acknowledgment in the product documentation would
+//    be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such, and must not
+//    be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source
+//    distribution.
+//
+//========================================================================
+
+#include "internal.h"
+
+//************************************************************************
+//****               Platform implementation functions                ****
+//************************************************************************
+
+//========================================================================
+// Check if an OpenGL extension is available at runtime
+//========================================================================
+
+int _glfwPlatformExtensionSupported( const char *extension )
+{
+    // There are no AGL, CGL or NSGL extensions.
+    return GL_FALSE;
+}
+
+//========================================================================
+// Get the function pointer to an OpenGL function
+//========================================================================
+
+void * _glfwPlatformGetProcAddress( const char *procname )
+{
+    CFStringRef symbolName = CFStringCreateWithCString( kCFAllocatorDefault,
+                                                        procname,
+                                                        kCFStringEncodingASCII );
+
+    void *symbol = CFBundleGetFunctionPointerForName( _glfwLibrary.OpenGLFramework,
+                                                      symbolName );
+
+    CFRelease( symbolName );
+
+    return symbol;
+}
+
diff --git a/glfw/lib/cocoa/cocoa_init.m b/glfw/lib/cocoa/cocoa_init.m
new file mode 100644
--- /dev/null
+++ b/glfw/lib/cocoa/cocoa_init.m
@@ -0,0 +1,241 @@
+//========================================================================
+// GLFW - An OpenGL framework
+// File:        macosx_init.m
+// Platform:    Mac OS X
+// API Version: 2.7
+// WWW:         http://glfw.sourceforge.net
+//------------------------------------------------------------------------
+// Copyright (c) 2002-2006 Camilla Berglund
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+//    claim that you wrote the original software. If you use this software
+//    in a product, an acknowledgment in the product documentation would
+//    be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such, and must not
+//    be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source
+//    distribution.
+//
+//========================================================================
+
+// Needed for _NSGetProgname
+#include <crt_externs.h>
+
+#include "internal.h"
+
+// Prior to Snow Leopard, we need to use this oddly-named semi-private API
+// to get the application menu working properly.  Need to be careful in
+// case it goes away in a future OS update.
+@interface NSApplication (NSAppleMenu)
+- (void)setAppleMenu:(NSMenu *)m;
+@end
+
+// Keys to search for as potential application names
+NSString *GLFWNameKeys[] =
+{
+    @"CFBundleDisplayName",
+    @"CFBundleName",
+    @"CFBundleExecutable",
+};
+
+//========================================================================
+// Try to figure out what the calling application is called
+//========================================================================
+static NSString *findAppName( void )
+{
+    NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
+
+    unsigned int i;
+    for( i = 0; i < sizeof(GLFWNameKeys) / sizeof(GLFWNameKeys[0]); i++ )
+    {
+        id name = [infoDictionary objectForKey:GLFWNameKeys[i]];
+        if (name &&
+            [name isKindOfClass:[NSString class]] &&
+            ![@"" isEqualToString:name])
+        {
+            return name;
+        }
+    }
+
+    // If we get here, we're unbundled
+    if( !_glfwLibrary.Unbundled )
+    {
+        // Could do this only if we discover we're unbundled, but it should
+        // do no harm...
+        ProcessSerialNumber psn = { 0, kCurrentProcess };
+        TransformProcessType( &psn, kProcessTransformToForegroundApplication );
+
+        // Having the app in front of the terminal window is also generally
+        // handy.  There is an NSApplication API to do this, but...
+        SetFrontProcess( &psn );
+
+        _glfwLibrary.Unbundled = GL_TRUE;
+    }
+
+    char **progname = _NSGetProgname();
+    if( progname && *progname )
+    {
+        // TODO: UTF8?
+        return [NSString stringWithUTF8String:*progname];
+    }
+
+    // Really shouldn't get here
+    return @"GLFW Application";
+}
+
+//========================================================================
+// Set up the menu bar (manually)
+// This is nasty, nasty stuff -- calls to undocumented semi-private APIs that
+// could go away at any moment, lots of stuff that really should be
+// localize(d|able), etc.  Loading a nib would save us this horror, but that
+// doesn't seem like a good thing to require of GLFW's clients.
+//========================================================================
+static void setUpMenuBar( void )
+{
+    NSString *appName = findAppName();
+
+    NSMenu *bar = [[NSMenu alloc] init];
+    [NSApp setMainMenu:bar];
+
+    NSMenuItem *appMenuItem =
+        [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""];
+    NSMenu *appMenu = [[NSMenu alloc] init];
+    [appMenuItem setSubmenu:appMenu];
+
+    [appMenu addItemWithTitle:[NSString stringWithFormat:@"About %@", appName]
+                       action:@selector(orderFrontStandardAboutPanel:)
+                keyEquivalent:@""];
+    [appMenu addItem:[NSMenuItem separatorItem]];
+    NSMenu *servicesMenu = [[NSMenu alloc] init];
+    [NSApp setServicesMenu:servicesMenu];
+    [[appMenu addItemWithTitle:@"Services"
+                       action:NULL
+                keyEquivalent:@""] setSubmenu:servicesMenu];
+    [appMenu addItem:[NSMenuItem separatorItem]];
+    [appMenu addItemWithTitle:[NSString stringWithFormat:@"Hide %@", appName]
+                       action:@selector(hide:)
+                keyEquivalent:@"h"];
+    [[appMenu addItemWithTitle:@"Hide Others"
+                       action:@selector(hideOtherApplications:)
+                keyEquivalent:@"h"]
+        setKeyEquivalentModifierMask:NSAlternateKeyMask | NSCommandKeyMask];
+    [appMenu addItemWithTitle:@"Show All"
+                       action:@selector(unhideAllApplications:)
+                keyEquivalent:@""];
+    [appMenu addItem:[NSMenuItem separatorItem]];
+    [appMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %@", appName]
+                       action:@selector(terminate:)
+                keyEquivalent:@"q"];
+
+    NSMenuItem *windowMenuItem =
+        [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""];
+    NSMenu *windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
+    [NSApp setWindowsMenu:windowMenu];
+    [windowMenuItem setSubmenu:windowMenu];
+
+    [windowMenu addItemWithTitle:@"Miniaturize"
+                          action:@selector(performMiniaturize:)
+                   keyEquivalent:@"m"];
+    [windowMenu addItemWithTitle:@"Zoom"
+                          action:@selector(performZoom:)
+                   keyEquivalent:@""];
+    [windowMenu addItem:[NSMenuItem separatorItem]];
+    [windowMenu addItemWithTitle:@"Bring All to Front"
+                          action:@selector(arrangeInFront:)
+                   keyEquivalent:@""];
+
+    // At least guard the call to private API to avoid an exception if it
+    // goes away.  Hopefully that means the worst we'll break in future is to
+    // look ugly...
+    if( [NSApp respondsToSelector:@selector(setAppleMenu:)] )
+    {
+        [NSApp setAppleMenu:appMenu];
+    }
+}
+
+//========================================================================
+// Initialize GLFW thread package
+//========================================================================
+
+static void initThreads( void )
+{
+    // Initialize critical section handle
+    (void) pthread_mutex_init( &_glfwThrd.CriticalSection, NULL );
+
+    // The first thread (the main thread) has ID 0
+    _glfwThrd.NextID = 0;
+
+    // Fill out information about the main thread (this thread)
+    _glfwThrd.First.ID       = _glfwThrd.NextID ++;
+    _glfwThrd.First.Function = NULL;
+    _glfwThrd.First.PosixID  = pthread_self();
+    _glfwThrd.First.Previous = NULL;
+    _glfwThrd.First.Next     = NULL;
+}
+
+//************************************************************************
+//****               Platform implementation functions                ****
+//************************************************************************
+
+//========================================================================
+// Initialize the GLFW library
+//========================================================================
+
+int _glfwPlatformInit( void )
+{
+    _glfwLibrary.AutoreleasePool = [[NSAutoreleasePool alloc] init];
+
+    // Implicitly create shared NSApplication instance
+    [NSApplication sharedApplication];
+
+    NSString* resourcePath = [[NSBundle mainBundle] resourcePath];
+
+    if( access( [resourcePath cStringUsingEncoding:NSUTF8StringEncoding], R_OK ) == 0 )
+    {
+        chdir( [resourcePath cStringUsingEncoding:NSUTF8StringEncoding] );
+    }
+
+    // Setting up menu bar must go exactly here else weirdness ensues
+    setUpMenuBar();
+
+    [NSApp finishLaunching];
+
+    initThreads();
+
+    _glfwPlatformSetTime( 0.0 );
+
+    _glfwLibrary.DesktopMode =
+	(NSDictionary *)CGDisplayCurrentMode( CGMainDisplayID() );
+
+    return GL_TRUE;
+}
+
+//========================================================================
+// Close window, if open, and shut down GLFW
+//========================================================================
+
+int _glfwPlatformTerminate( void )
+{
+    // TODO: Fail unless this is the main thread
+
+    glfwCloseWindow();
+
+    // TODO: Kill all non-main threads?
+    // TODO: Probably other cleanup
+
+    [_glfwLibrary.AutoreleasePool release];
+    _glfwLibrary.AutoreleasePool = nil;
+
+    return GL_TRUE;
+}
+
diff --git a/glfw/lib/cocoa/cocoa_joystick.m b/glfw/lib/cocoa/cocoa_joystick.m
new file mode 100644
--- /dev/null
+++ b/glfw/lib/cocoa/cocoa_joystick.m
@@ -0,0 +1,66 @@
+//========================================================================
+// GLFW - An OpenGL framework
+// File:        macosx_joystick.m
+// Platform:    Mac OS X
+// API Version: 2.7
+// WWW:         http://glfw.sourceforge.net
+//------------------------------------------------------------------------
+// Copyright (c) 2002-2006 Camilla Berglund
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+//    claim that you wrote the original software. If you use this software
+//    in a product, an acknowledgment in the product documentation would
+//    be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such, and must not
+//    be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source
+//    distribution.
+//
+//========================================================================
+
+#include "internal.h"
+
+//************************************************************************
+//****               Platform implementation functions                ****
+//************************************************************************
+
+//========================================================================
+// Determine joystick capabilities
+//========================================================================
+
+int _glfwPlatformGetJoystickParam( int joy, int param )
+{
+    // TODO: Implement this.
+    return 0;
+}
+
+//========================================================================
+// Get joystick axis positions
+//========================================================================
+
+int _glfwPlatformGetJoystickPos( int joy, float *pos, int numaxes )
+{
+    // TODO: Implement this.
+    return 0;
+}
+
+//========================================================================
+// Get joystick button states
+//========================================================================
+
+int _glfwPlatformGetJoystickButtons( int joy, unsigned char *buttons, int numbuttons )
+{
+    // TODO: Implement this.
+    return 0;
+}
+
diff --git a/glfw/lib/cocoa/cocoa_thread.c b/glfw/lib/cocoa/cocoa_thread.c
new file mode 100644
--- /dev/null
+++ b/glfw/lib/cocoa/cocoa_thread.c
@@ -0,0 +1,416 @@
+//========================================================================
+// GLFW - An OpenGL framework
+// File:        macosx_thread.c
+// Platform:    Mac OS X
+// API Version: 2.7
+// WWW:         http://glfw.sourceforge.net
+//------------------------------------------------------------------------
+// Copyright (c) 2002-2006 Camilla Berglund
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+//    claim that you wrote the original software. If you use this software
+//    in a product, an acknowledgment in the product documentation would
+//    be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such, and must not
+//    be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source
+//    distribution.
+//
+//========================================================================
+
+#include "internal.h"
+
+#include <sys/time.h>
+#include <sys/sysctl.h>
+
+
+//************************************************************************
+//****                  GLFW internal functions                       ****
+//************************************************************************
+
+//========================================================================
+// _glfwNewThread() - This is simply a "wrapper" for calling the user
+// thread function.
+//========================================================================
+
+void * _glfwNewThread( void * arg )
+{
+    GLFWthreadfun threadfun;
+    _GLFWthread   *t;
+
+    // Get pointer to thread information for current thread
+    t = _glfwGetThreadPointer( glfwGetThreadID() );
+    if( t == NULL )
+    {
+        return 0;
+    }
+
+    // Get user thread function pointer
+    threadfun = t->Function;
+
+    // Call the user thread function
+    threadfun( arg );
+
+    // Remove thread from thread list
+    ENTER_THREAD_CRITICAL_SECTION
+        _glfwRemoveThread( t );
+    LEAVE_THREAD_CRITICAL_SECTION
+
+    // When the thread function returns, the thread will die...
+    return NULL;
+}
+
+
+
+//************************************************************************
+//****               Platform implementation functions                ****
+//************************************************************************
+
+//========================================================================
+// _glfwPlatformCreateThread() - Create a new thread
+//========================================================================
+
+GLFWthread _glfwPlatformCreateThread( GLFWthreadfun fun, void *arg )
+{
+    GLFWthread  ID;
+    _GLFWthread *t;
+    int         result;
+
+    // Enter critical section
+    ENTER_THREAD_CRITICAL_SECTION
+
+    // Create a new thread information memory area
+    t = (_GLFWthread *) malloc( sizeof(_GLFWthread) );
+    if( t == NULL )
+    {
+        // Leave critical section
+        LEAVE_THREAD_CRITICAL_SECTION
+        return -1;
+    }
+
+    // Get a new unique thread id
+    ID = _glfwThrd.NextID ++;
+
+    // Store thread information in the thread list
+    t->Function = fun;
+    t->ID       = ID;
+
+    // Create thread
+    result = pthread_create(
+                            &t->PosixID,      // Thread handle
+                            NULL,             // Default thread attributes
+                            _glfwNewThread,   // Thread function (a wrapper function)
+                            (void *)arg       // Argument to thread is user argument
+                            );
+
+    // Did the thread creation fail?
+    if( result != 0 )
+    {
+        free( (void *) t );
+        LEAVE_THREAD_CRITICAL_SECTION
+        return -1;
+    }
+
+    // Append thread to thread list
+    _glfwAppendThread( t );
+
+    // Leave critical section
+    LEAVE_THREAD_CRITICAL_SECTION
+
+    // Return the GLFW thread ID
+    return ID;
+}
+
+
+//========================================================================
+// _glfwPlatformDestroyThread() - Kill a thread. NOTE: THIS IS A VERY
+// DANGEROUS OPERATION, AND SHOULD NOT BE USED EXCEPT IN EXTREME
+// SITUATIONS!
+//========================================================================
+
+void _glfwPlatformDestroyThread( GLFWthread ID )
+{
+    _GLFWthread *t;
+
+    // Enter critical section
+    ENTER_THREAD_CRITICAL_SECTION
+
+    // Get thread information pointer
+    t = _glfwGetThreadPointer( ID );
+    if( t == NULL )
+    {
+        LEAVE_THREAD_CRITICAL_SECTION
+        return;
+    }
+
+    // Simply murder the process, no mercy!
+    pthread_kill( t->PosixID, SIGKILL );
+
+    // Remove thread from thread list
+    _glfwRemoveThread( t );
+
+    // Leave critical section
+    LEAVE_THREAD_CRITICAL_SECTION
+}
+
+
+//========================================================================
+// _glfwPlatformWaitThread() - Wait for a thread to die
+//========================================================================
+
+int _glfwPlatformWaitThread( GLFWthread ID, int waitmode )
+{
+    pthread_t   thread;
+    _GLFWthread *t;
+
+    // Enter critical section
+    ENTER_THREAD_CRITICAL_SECTION
+
+    // Get thread information pointer
+    t = _glfwGetThreadPointer( ID );
+
+    // Is the thread already dead?
+    if( t == NULL )
+    {
+        LEAVE_THREAD_CRITICAL_SECTION
+        return GL_TRUE;
+    }
+
+    // If got this far, the thread is alive => polling returns FALSE
+    if( waitmode == GLFW_NOWAIT )
+    {
+        LEAVE_THREAD_CRITICAL_SECTION
+        return GL_FALSE;
+    }
+
+    // Get thread handle
+    thread = t->PosixID;
+
+    // Leave critical section
+    LEAVE_THREAD_CRITICAL_SECTION
+
+    // Wait for thread to die
+    (void) pthread_join( thread, NULL );
+
+    return GL_TRUE;
+}
+
+
+//========================================================================
+// _glfwPlatformGetThreadID() - Return the thread ID for the current
+// thread
+//========================================================================
+
+GLFWthread _glfwPlatformGetThreadID( void )
+{
+    _GLFWthread *t;
+    GLFWthread  ID = -1;
+    pthread_t   posixID;
+
+    // Get current thread ID
+    posixID = pthread_self();
+
+    // Enter critical section
+    ENTER_THREAD_CRITICAL_SECTION
+
+    // Loop through entire list of threads to find the matching POSIX
+    // thread ID
+    for( t = &_glfwThrd.First; t != NULL; t = t->Next )
+    {
+        if( t->PosixID == posixID )
+        {
+            ID = t->ID;
+            break;
+        }
+    }
+
+    // Leave critical section
+    LEAVE_THREAD_CRITICAL_SECTION
+
+    // Return the found GLFW thread identifier
+    return ID;
+}
+
+
+//========================================================================
+// _glfwPlatformCreateMutex() - Create a mutual exclusion object
+//========================================================================
+
+GLFWmutex _glfwPlatformCreateMutex( void )
+{
+    pthread_mutex_t *mutex;
+
+    // Allocate memory for mutex
+    mutex = (pthread_mutex_t *) malloc( sizeof( pthread_mutex_t ) );
+    if( !mutex )
+    {
+        return NULL;
+    }
+
+    // Initialise a mutex object
+    (void) pthread_mutex_init( mutex, NULL );
+
+    // Cast to GLFWmutex and return
+    return (GLFWmutex) mutex;
+}
+
+
+//========================================================================
+// _glfwPlatformDestroyMutex() - Destroy a mutual exclusion object
+//========================================================================
+
+void _glfwPlatformDestroyMutex( GLFWmutex mutex )
+{
+    // Destroy the mutex object
+    pthread_mutex_destroy( (pthread_mutex_t *) mutex );
+
+    // Free memory for mutex object
+    free( (void *) mutex );
+}
+
+
+//========================================================================
+// _glfwPlatformLockMutex() - Request access to a mutex
+//========================================================================
+
+void _glfwPlatformLockMutex( GLFWmutex mutex )
+{
+    // Wait for mutex to be released
+    (void) pthread_mutex_lock( (pthread_mutex_t *) mutex );
+}
+
+
+//========================================================================
+// _glfwPlatformUnlockMutex() - Release a mutex
+//========================================================================
+
+void _glfwPlatformUnlockMutex( GLFWmutex mutex )
+{
+    // Release mutex
+    pthread_mutex_unlock( (pthread_mutex_t *) mutex );
+}
+
+
+//========================================================================
+// _glfwPlatformCreateCond() - Create a new condition variable object
+//========================================================================
+
+GLFWcond _glfwPlatformCreateCond( void )
+{
+    pthread_cond_t *cond;
+
+    // Allocate memory for condition variable
+    cond = (pthread_cond_t *) malloc( sizeof(pthread_cond_t) );
+    if( !cond )
+    {
+        return NULL;
+    }
+
+    // Initialise condition variable
+    (void) pthread_cond_init( cond, NULL );
+
+    // Cast to GLFWcond and return
+    return (GLFWcond) cond;
+}
+
+
+//========================================================================
+// _glfwPlatformDestroyCond() - Destroy a condition variable object
+//========================================================================
+
+void _glfwPlatformDestroyCond( GLFWcond cond )
+{
+    // Destroy the condition variable object
+    (void) pthread_cond_destroy( (pthread_cond_t *) cond );
+
+    // Free memory for condition variable object
+    free( (void *) cond );
+}
+
+
+//========================================================================
+// _glfwPlatformWaitCond() - Wait for a condition to be raised
+//========================================================================
+
+void _glfwPlatformWaitCond( GLFWcond cond, GLFWmutex mutex,
+                            double timeout )
+{
+    struct timeval  currenttime;
+    struct timespec wait;
+    long dt_sec, dt_usec;
+
+    // Select infinite or timed wait
+    if( timeout >= GLFW_INFINITY )
+    {
+        // Wait for condition (infinite wait)
+        (void) pthread_cond_wait( (pthread_cond_t *) cond,
+                                  (pthread_mutex_t *) mutex );
+    }
+    else
+    {
+        // Set timeout time, relatvie to current time
+        gettimeofday( &currenttime, NULL );
+        dt_sec  = (long) timeout;
+        dt_usec = (long) ((timeout - (double)dt_sec) * 1000000.0);
+        wait.tv_nsec = (currenttime.tv_usec + dt_usec) * 1000L;
+        if( wait.tv_nsec > 1000000000L )
+        {
+            wait.tv_nsec -= 1000000000L;
+            dt_sec ++;
+        }
+        wait.tv_sec  = currenttime.tv_sec + dt_sec;
+
+        // Wait for condition (timed wait)
+        (void) pthread_cond_timedwait( (pthread_cond_t *) cond,
+                                       (pthread_mutex_t *) mutex, &wait );
+    }
+}
+
+
+//========================================================================
+// _glfwPlatformSignalCond() - Signal a condition to one waiting thread
+//========================================================================
+
+void _glfwPlatformSignalCond( GLFWcond cond )
+{
+    // Signal condition
+    (void) pthread_cond_signal( (pthread_cond_t *) cond );
+}
+
+
+//========================================================================
+// _glfwPlatformBroadcastCond() - Broadcast a condition to all waiting
+// threads
+//========================================================================
+
+void _glfwPlatformBroadcastCond( GLFWcond cond )
+{
+    // Broadcast condition
+    (void) pthread_cond_broadcast( (pthread_cond_t *) cond );
+}
+
+
+//========================================================================
+// _glfwPlatformGetNumberOfProcessors() - Return the number of processors
+// in the system.
+//========================================================================
+
+int _glfwPlatformGetNumberOfProcessors( void )
+{
+    int n;
+
+    // Get number of processors online
+    _glfw_numprocessors( n );
+    return n;
+}
+
diff --git a/glfw/lib/cocoa/cocoa_time.m b/glfw/lib/cocoa/cocoa_time.m
new file mode 100644
--- /dev/null
+++ b/glfw/lib/cocoa/cocoa_time.m
@@ -0,0 +1,106 @@
+//========================================================================
+// GLFW - An OpenGL framework
+// File:        macosx_time.m
+// Platform:    Mac OS X
+// API Version: 2.7
+// WWW:         http://glfw.sourceforge.net
+//------------------------------------------------------------------------
+// Copyright (c) 2002-2006 Camilla Berglund
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+//    claim that you wrote the original software. If you use this software
+//    in a product, an acknowledgment in the product documentation would
+//    be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such, and must not
+//    be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source
+//    distribution.
+//
+//========================================================================
+
+#include "internal.h"
+
+#include <sys/time.h>
+
+//************************************************************************
+//****               Platform implementation functions                ****
+//************************************************************************
+
+//========================================================================
+// Return timer value in seconds
+//========================================================================
+
+double _glfwPlatformGetTime( void )
+{
+    return [NSDate timeIntervalSinceReferenceDate] - _glfwLibrary.Timer.t0;
+}
+
+//========================================================================
+// Set timer value in seconds
+//========================================================================
+
+void _glfwPlatformSetTime( double time )
+{
+    _glfwLibrary.Timer.t0 = [NSDate timeIntervalSinceReferenceDate] - time;
+}
+
+//========================================================================
+// Put a thread to sleep for a specified amount of time
+//========================================================================
+
+void _glfwPlatformSleep( double time )
+{
+    if( time == 0.0 )
+    {
+	sched_yield();
+	return;
+    }
+
+    struct timeval  currenttime;
+    struct timespec wait;
+    pthread_mutex_t mutex;
+    pthread_cond_t  cond;
+    long dt_sec, dt_usec;
+
+    // Not all pthread implementations have a pthread_sleep() function. We
+    // do it the portable way, using a timed wait for a condition that we
+    // will never signal. NOTE: The unistd functions sleep/usleep suspends
+    // the entire PROCESS, not a signle thread, which is why we can not
+    // use them to implement glfwSleep.
+
+    // Set timeout time, relatvie to current time
+    gettimeofday( &currenttime, NULL );
+    dt_sec  = (long) time;
+    dt_usec = (long) ((time - (double)dt_sec) * 1000000.0);
+    wait.tv_nsec = (currenttime.tv_usec + dt_usec) * 1000L;
+    if( wait.tv_nsec > 1000000000L )
+    {
+        wait.tv_nsec -= 1000000000L;
+        dt_sec ++;
+    }
+    wait.tv_sec  = currenttime.tv_sec + dt_sec;
+
+    // Initialize condition and mutex objects
+    pthread_mutex_init( &mutex, NULL );
+    pthread_cond_init( &cond, NULL );
+
+    // Do a timed wait
+    pthread_mutex_lock( &mutex );
+    pthread_cond_timedwait( &cond, &mutex, &wait );
+    pthread_mutex_unlock( &mutex );
+
+    // Destroy condition and mutex objects
+    pthread_mutex_destroy( &mutex );
+    pthread_cond_destroy( &cond );
+}
+
diff --git a/glfw/lib/cocoa/cocoa_window.m b/glfw/lib/cocoa/cocoa_window.m
new file mode 100644
--- /dev/null
+++ b/glfw/lib/cocoa/cocoa_window.m
@@ -0,0 +1,880 @@
+//========================================================================
+// GLFW - An OpenGL framework
+// File:        macosx_window.m
+// Platform:    Mac OS X
+// API Version: 2.7
+// WWW:         http://glfw.sourceforge.net
+//------------------------------------------------------------------------
+// Copyright (c) 2002-2006 Camilla Berglund
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+//    claim that you wrote the original software. If you use this software
+//    in a product, an acknowledgment in the product documentation would
+//    be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such, and must not
+//    be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source
+//    distribution.
+//
+//========================================================================
+
+#include "internal.h"
+
+//========================================================================
+// Delegate for window related notifications
+// (but also used as an application delegate)
+//========================================================================
+
+@interface GLFWWindowDelegate : NSObject
+@end
+
+@implementation GLFWWindowDelegate
+
+- (BOOL)windowShouldClose:(id)window
+{
+    if( _glfwWin.windowCloseCallback )
+    {
+        if( !_glfwWin.windowCloseCallback() )
+        {
+            return NO;
+        }
+    }
+
+    // This is horribly ugly, but it works
+    glfwCloseWindow();
+    return NO;
+}
+
+- (void)windowDidResize:(NSNotification *)notification
+{
+    [_glfwWin.context update];
+
+    NSRect contentRect =
+        [_glfwWin.window contentRectForFrameRect:[_glfwWin.window frame]];
+    _glfwWin.width = contentRect.size.width;
+    _glfwWin.height = contentRect.size.height;
+
+    if( _glfwWin.windowSizeCallback )
+    {
+        _glfwWin.windowSizeCallback( _glfwWin.width, _glfwWin.height );
+    }
+}
+
+- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
+{
+    if( _glfwWin.windowCloseCallback )
+    {
+        if( !_glfwWin.windowCloseCallback() )
+        {
+            return NSTerminateCancel;
+        }
+    }
+
+    // This is horribly ugly, but it works
+    glfwCloseWindow();
+    return NSTerminateCancel;
+}
+
+@end
+
+// TODO: Need to find mappings for F13-F15, volume down/up/mute, and eject.
+static const unsigned int MAC_TO_GLFW_KEYCODE_MAPPING[128] =
+{
+    /* 00 */ 'A',
+    /* 01 */ 'S',
+    /* 02 */ 'D',
+    /* 03 */ 'F',
+    /* 04 */ 'H',
+    /* 05 */ 'G',
+    /* 06 */ 'Z',
+    /* 07 */ 'X',
+    /* 08 */ 'C',
+    /* 09 */ 'V',
+    /* 0a */ -1,
+    /* 0b */ 'B',
+    /* 0c */ 'Q',
+    /* 0d */ 'W',
+    /* 0e */ 'E',
+    /* 0f */ 'R',
+    /* 10 */ 'Y',
+    /* 11 */ 'T',
+    /* 12 */ '1',
+    /* 13 */ '2',
+    /* 14 */ '3',
+    /* 15 */ '4',
+    /* 16 */ '6',
+    /* 17 */ '5',
+    /* 18 */ GLFW_KEY_KP_EQUAL,
+    /* 19 */ '9',
+    /* 1a */ '7',
+    /* 1b */ '-',
+    /* 1c */ '8',
+    /* 1d */ '0',
+    /* 1e */ ']',
+    /* 1f */ 'O',
+    /* 20 */ 'U',
+    /* 21 */ '[',
+    /* 22 */ 'I',
+    /* 23 */ 'P',
+    /* 24 */ GLFW_KEY_ENTER,
+    /* 25 */ 'L',
+    /* 26 */ 'J',
+    /* 27 */ '\'',
+    /* 28 */ 'K',
+    /* 29 */ ';',
+    /* 2a */ '\\',
+    /* 2b */ ',',
+    /* 2c */ '/',
+    /* 2d */ 'N',
+    /* 2e */ 'M',
+    /* 2f */ '.',
+    /* 30 */ GLFW_KEY_TAB,
+    /* 31 */ GLFW_KEY_SPACE,
+    /* 32 */ '`',
+    /* 33 */ GLFW_KEY_BACKSPACE,
+    /* 34 */ -1,
+    /* 35 */ GLFW_KEY_ESC,
+    /* 36 */ GLFW_KEY_RSUPER,
+    /* 37 */ GLFW_KEY_LSUPER,
+    /* 38 */ GLFW_KEY_LSHIFT,
+    /* 39 */ GLFW_KEY_CAPS_LOCK,
+    /* 3a */ GLFW_KEY_LALT,
+    /* 3b */ GLFW_KEY_LCTRL,
+    /* 3c */ GLFW_KEY_RSHIFT,
+    /* 3d */ GLFW_KEY_RALT,
+    /* 3e */ GLFW_KEY_RCTRL,
+    /* 3f */ -1,
+    /* 40 */ -1,
+    /* 41 */ GLFW_KEY_KP_DECIMAL,
+    /* 42 */ -1,
+    /* 43 */ GLFW_KEY_KP_MULTIPLY,
+    /* 44 */ -1,
+    /* 45 */ GLFW_KEY_KP_ADD,
+    /* 46 */ -1,
+    /* 47 */ -1,
+    /* 48 */ -1,
+    /* 49 */ -1,
+    /* 4a */ -1,
+    /* 4b */ GLFW_KEY_KP_DIVIDE,
+    /* 4c */ GLFW_KEY_KP_ENTER,
+    /* 4d */ -1,
+    /* 4e */ GLFW_KEY_KP_SUBTRACT,
+    /* 4f */ -1,
+    /* 50 */ -1,
+    /* 51 */ -1,
+    /* 52 */ GLFW_KEY_KP_0,
+    /* 53 */ GLFW_KEY_KP_1,
+    /* 54 */ GLFW_KEY_KP_2,
+    /* 55 */ GLFW_KEY_KP_3,
+    /* 56 */ GLFW_KEY_KP_4,
+    /* 57 */ GLFW_KEY_KP_5,
+    /* 58 */ GLFW_KEY_KP_6,
+    /* 59 */ GLFW_KEY_KP_7,
+    /* 5a */ -1,
+    /* 5b */ GLFW_KEY_KP_8,
+    /* 5c */ GLFW_KEY_KP_9,
+    /* 5d */ -1,
+    /* 5e */ -1,
+    /* 5f */ -1,
+    /* 60 */ GLFW_KEY_F5,
+    /* 61 */ GLFW_KEY_F6,
+    /* 62 */ GLFW_KEY_F7,
+    /* 63 */ GLFW_KEY_F3,
+    /* 64 */ GLFW_KEY_F8,
+    /* 65 */ -1,
+    /* 66 */ -1,
+    /* 67 */ -1,
+    /* 68 */ -1,
+    /* 69 */ GLFW_KEY_F13,
+    /* 6a */ GLFW_KEY_F16,
+    /* 6b */ -1,
+    /* 6c */ -1,
+    /* 6d */ -1,
+    /* 6e */ -1,
+    /* 6f */ -1,
+    /* 70 */ -1,
+    /* 71 */ -1,
+    /* 72 */ GLFW_KEY_INSERT,
+    /* 73 */ GLFW_KEY_HOME,
+    /* 74 */ GLFW_KEY_PAGEUP,
+    /* 75 */ GLFW_KEY_DEL,
+    /* 76 */ GLFW_KEY_F4,
+    /* 77 */ GLFW_KEY_END,
+    /* 78 */ GLFW_KEY_F2,
+    /* 79 */ GLFW_KEY_PAGEDOWN,
+    /* 7a */ GLFW_KEY_F1,
+    /* 7b */ GLFW_KEY_LEFT,
+    /* 7c */ GLFW_KEY_RIGHT,
+    /* 7d */ GLFW_KEY_DOWN,
+    /* 7e */ GLFW_KEY_UP,
+    /* 7f */ -1,
+};
+
+//========================================================================
+// Converts a Mac OS X keycode to a GLFW keycode
+//========================================================================
+
+static int convertMacKeyCode( unsigned int macKeyCode )
+{
+    if( macKeyCode >= 128 )
+    {
+        return -1;
+    }
+
+    // This treats keycodes as *positional*; that is, we'll return 'a'
+    // for the key left of 's', even on an AZERTY keyboard.  The charInput
+    // function should still get 'q' though.
+    return MAC_TO_GLFW_KEYCODE_MAPPING[macKeyCode];
+}
+
+//========================================================================
+// Content view class for the GLFW window
+//========================================================================
+
+@interface GLFWContentView : NSView
+@end
+
+@implementation GLFWContentView
+
+- (BOOL)isOpaque
+{
+    return YES;
+}
+
+- (BOOL)canBecomeKeyView
+{
+    return YES;
+}
+
+- (BOOL)acceptsFirstResponder
+{
+    return YES;
+}
+
+- (void)mouseDown:(NSEvent *)event
+{
+    _glfwInputMouseClick( GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS );
+}
+
+- (void)mouseDragged:(NSEvent *)event
+{
+    [self mouseMoved:event];
+}
+
+- (void)mouseUp:(NSEvent *)event
+{
+    _glfwInputMouseClick( GLFW_MOUSE_BUTTON_LEFT, GLFW_RELEASE );
+}
+
+- (void)mouseMoved:(NSEvent *)event
+{
+    if( _glfwWin.mouseLock )
+    {
+        _glfwInput.MousePosX += [event deltaX];
+        _glfwInput.MousePosY -= [event deltaY];
+    }
+    else
+    {
+        NSPoint p = [event locationInWindow];
+
+        // Cocoa coordinate system has origin at lower left
+        _glfwInput.MousePosX = p.x;
+        _glfwInput.MousePosY = [[_glfwWin.window contentView] bounds].size.height - p.y;
+    }
+
+    if( _glfwWin.mousePosCallback )
+    {
+        _glfwWin.mousePosCallback( _glfwInput.MousePosX, _glfwInput.MousePosY );
+    }
+}
+
+- (void)rightMouseDown:(NSEvent *)event
+{
+    _glfwInputMouseClick( GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS );
+}
+
+- (void)rightMouseDragged:(NSEvent *)event
+{
+    [self mouseMoved:event];
+}
+
+- (void)rightMouseUp:(NSEvent *)event
+{
+    _glfwInputMouseClick( GLFW_MOUSE_BUTTON_RIGHT, GLFW_RELEASE );
+}
+
+- (void)otherMouseDown:(NSEvent *)event
+{
+    _glfwInputMouseClick( [event buttonNumber], GLFW_PRESS );
+}
+
+- (void)otherMouseDragged:(NSEvent *)event
+{
+    [self mouseMoved:event];
+}
+
+- (void)otherMouseUp:(NSEvent *)event
+{
+    _glfwInputMouseClick( [event buttonNumber], GLFW_RELEASE );
+}
+
+- (void)keyDown:(NSEvent *)event
+{
+    NSUInteger length;
+    NSString* characters;
+    int i, code = convertMacKeyCode( [event keyCode] );
+
+    if( code != -1 )
+    {
+        _glfwInputKey( code, GLFW_PRESS );
+
+        if( [event modifierFlags] & NSCommandKeyMask )
+        {
+            if( !_glfwWin.sysKeysDisabled )
+            {
+                [super keyDown:event];
+            }
+        }
+        else
+        {
+            characters = [event characters];
+            length = [characters length];
+
+            for( i = 0;  i < length;  i++ )
+            {
+                _glfwInputChar( [characters characterAtIndex:i], GLFW_PRESS );
+            }
+        }
+    }
+}
+
+- (void)flagsChanged:(NSEvent *)event
+{
+    unsigned int newModifierFlags = [event modifierFlags];
+    int mode;
+
+    if( newModifierFlags > _glfwWin.modifierFlags )
+    {
+        mode = GLFW_PRESS;
+    }
+    else
+    {
+        mode = GLFW_RELEASE;
+    }
+
+    _glfwWin.modifierFlags = newModifierFlags;
+    _glfwInputKey( MAC_TO_GLFW_KEYCODE_MAPPING[[event keyCode]], mode );
+}
+
+- (void)keyUp:(NSEvent *)event
+{
+    NSUInteger length;
+    NSString* characters;
+    int i, code = convertMacKeyCode( [event keyCode] );
+
+    if( code != -1 )
+    {
+        _glfwInputKey( code, GLFW_RELEASE );
+
+        characters = [event characters];
+        length = [characters length];
+
+        for( i = 0;  i < length;  i++ )
+        {
+            _glfwInputChar( [characters characterAtIndex:i], GLFW_RELEASE );
+        }
+    }
+}
+
+- (void)scrollWheel:(NSEvent *)event
+{
+    _glfwInput.WheelPosFloating += [event deltaY];
+    _glfwInput.WheelPos = lrint(_glfwInput.WheelPosFloating);
+
+    if( _glfwWin.mouseWheelCallback )
+    {
+        _glfwWin.mouseWheelCallback( _glfwInput.WheelPos );
+    }
+}
+
+@end
+
+//************************************************************************
+//****               Platform implementation functions                ****
+//************************************************************************
+
+//========================================================================
+// Here is where the window is created, and the OpenGL rendering context is
+// created
+//========================================================================
+
+int  _glfwPlatformOpenWindow( int width, int height,
+                              const _GLFWwndconfig *wndconfig,
+                              const _GLFWfbconfig *fbconfig )
+{
+    int colorBits;
+
+    _glfwWin.pixelFormat = nil;
+    _glfwWin.window = nil;
+    _glfwWin.context = nil;
+    _glfwWin.delegate = nil;
+
+    _glfwWin.delegate = [[GLFWWindowDelegate alloc] init];
+    if( _glfwWin.delegate == nil )
+    {
+        _glfwPlatformCloseWindow();
+        return GL_FALSE;
+    }
+
+    [NSApp setDelegate:_glfwWin.delegate];
+
+    // Mac OS X needs non-zero color size, so set resonable values
+    colorBits = fbconfig->redBits + fbconfig->greenBits + fbconfig->blueBits;
+    if( colorBits == 0 )
+    {
+        colorBits = 24;
+    }
+    else if( colorBits < 15 )
+    {
+        colorBits = 15;
+    }
+
+    // Ignored hints:
+    // OpenGLMajor, OpenGLMinor, OpenGLForward:
+    //     pending Mac OS X support for OpenGL 3.x
+    // OpenGLDebug
+    //     pending it meaning anything on Mac OS X
+
+    // Don't use accumulation buffer support; it's not accelerated
+    // Aux buffers probably aren't accelerated either
+
+    CFDictionaryRef fullscreenMode = NULL;
+    if( wndconfig->mode == GLFW_FULLSCREEN )
+    {
+        fullscreenMode =
+            // I think it's safe to pass 0 to the refresh rate for this function
+            // rather than conditionalizing the code to call the version which
+            // doesn't specify refresh...
+            CGDisplayBestModeForParametersAndRefreshRateWithProperty(
+            CGMainDisplayID(),
+            colorBits + fbconfig->alphaBits,
+            width,
+            height,
+            wndconfig->refreshRate,
+            // Controversial, see macosx_fullscreen.m for discussion
+            kCGDisplayModeIsSafeForHardware,
+            NULL);
+
+        width = [[(id)fullscreenMode objectForKey:(id)kCGDisplayWidth] intValue];
+        height = [[(id)fullscreenMode objectForKey:(id)kCGDisplayHeight] intValue];
+    }
+
+    unsigned int styleMask = 0;
+    if( wndconfig->mode == GLFW_WINDOW )
+    {
+        styleMask = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask;
+
+        if( !wndconfig->windowNoResize )
+        {
+            styleMask |= NSResizableWindowMask;
+        }
+    }
+    else
+    {
+        styleMask = NSBorderlessWindowMask;
+    }
+
+    _glfwWin.window = [[NSWindow alloc]
+        initWithContentRect:NSMakeRect(0, 0, width, height)
+                      styleMask:styleMask
+                        backing:NSBackingStoreBuffered
+                          defer:NO];
+    [_glfwWin.window setContentView:[[GLFWContentView alloc] init]];
+    [_glfwWin.window setDelegate:_glfwWin.delegate];
+    [_glfwWin.window setAcceptsMouseMovedEvents:YES];
+    [_glfwWin.window center];
+
+    if( wndconfig->mode == GLFW_FULLSCREEN )
+    {
+        CGCaptureAllDisplays();
+        CGDisplaySwitchToMode( CGMainDisplayID(), fullscreenMode );
+    }
+
+    unsigned int attribute_count = 0;
+#define ADD_ATTR(x) attributes[attribute_count++] = x
+#define ADD_ATTR2(x, y) (void)({ ADD_ATTR(x); ADD_ATTR(y); })
+#define MAX_ATTRS 24 // urgh
+    NSOpenGLPixelFormatAttribute attributes[MAX_ATTRS];
+
+    ADD_ATTR( NSOpenGLPFADoubleBuffer );
+
+    if( wndconfig->mode == GLFW_FULLSCREEN )
+    {
+        ADD_ATTR( NSOpenGLPFAFullScreen );
+        ADD_ATTR( NSOpenGLPFANoRecovery );
+        ADD_ATTR2( NSOpenGLPFAScreenMask,
+                   CGDisplayIDToOpenGLDisplayMask( CGMainDisplayID() ) );
+    }
+
+    ADD_ATTR2( NSOpenGLPFAColorSize, colorBits );
+
+    if( fbconfig->alphaBits > 0)
+    {
+        ADD_ATTR2( NSOpenGLPFAAlphaSize, fbconfig->alphaBits );
+    }
+
+    if( fbconfig->depthBits > 0)
+    {
+        ADD_ATTR2( NSOpenGLPFADepthSize, fbconfig->depthBits );
+    }
+
+    if( fbconfig->stencilBits > 0)
+    {
+        ADD_ATTR2( NSOpenGLPFAStencilSize, fbconfig->stencilBits );
+    }
+
+    int accumBits = fbconfig->accumRedBits + fbconfig->accumGreenBits +
+                    fbconfig->accumBlueBits + fbconfig->accumAlphaBits;
+
+    if( accumBits > 0)
+    {
+        ADD_ATTR2( NSOpenGLPFAAccumSize, accumBits );
+    }
+
+    if( fbconfig->auxBuffers > 0)
+    {
+        ADD_ATTR2( NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers );
+    }
+
+    if( fbconfig->stereo)
+    {
+        ADD_ATTR( NSOpenGLPFAStereo );
+    }
+
+    if( fbconfig->samples > 0)
+    {
+        ADD_ATTR2( NSOpenGLPFASampleBuffers, 1 );
+        ADD_ATTR2( NSOpenGLPFASamples, fbconfig->samples );
+    }
+
+    ADD_ATTR(0);
+
+    _glfwWin.pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
+    if( _glfwWin.pixelFormat == nil )
+    {
+        _glfwPlatformCloseWindow();
+        return GL_FALSE;
+    }
+
+    _glfwWin.context = [[NSOpenGLContext alloc] initWithFormat:_glfwWin.pixelFormat
+                                                  shareContext:nil];
+    if( _glfwWin.context == nil )
+    {
+        _glfwPlatformCloseWindow();
+        return GL_FALSE;
+    }
+
+    [_glfwWin.window makeKeyAndOrderFront:nil];
+    [_glfwWin.context setView:[_glfwWin.window contentView]];
+
+    if( wndconfig->mode == GLFW_FULLSCREEN )
+    {
+        // TODO: Make this work on pre-Leopard systems
+        [[_glfwWin.window contentView] enterFullScreenMode:[NSScreen mainScreen]
+                                               withOptions:nil];
+    }
+
+    [_glfwWin.context makeCurrentContext];
+
+    NSPoint point = [[NSCursor currentCursor] hotSpot];
+    _glfwInput.MousePosX = point.x;
+    _glfwInput.MousePosY = point.y;
+
+    return GL_TRUE;
+}
+
+//========================================================================
+// Properly kill the window / video display
+//========================================================================
+
+void _glfwPlatformCloseWindow( void )
+{
+    [_glfwWin.window orderOut:nil];
+
+    if( _glfwWin.fullscreen )
+    {
+        [[_glfwWin.window contentView] exitFullScreenModeWithOptions:nil];
+        CGDisplaySwitchToMode( CGMainDisplayID(),
+                               (CFDictionaryRef)_glfwLibrary.DesktopMode );
+        CGReleaseAllDisplays();
+    }
+
+    [_glfwWin.pixelFormat release];
+    _glfwWin.pixelFormat = nil;
+
+    [NSOpenGLContext clearCurrentContext];
+    [_glfwWin.context release];
+    _glfwWin.context = nil;
+
+    [_glfwWin.window setDelegate:nil];
+    [NSApp setDelegate:nil];
+    [_glfwWin.delegate release];
+    _glfwWin.delegate = nil;
+
+    [_glfwWin.window close];
+    _glfwWin.window = nil;
+
+    // TODO: Probably more cleanup
+}
+
+//========================================================================
+// Set the window title
+//========================================================================
+
+void _glfwPlatformSetWindowTitle( const char *title )
+{
+    [_glfwWin.window setTitle:[NSString stringWithCString:title
+                     encoding:NSISOLatin1StringEncoding]];
+}
+
+//========================================================================
+// Set the window size
+//========================================================================
+
+void _glfwPlatformSetWindowSize( int width, int height )
+{
+    [_glfwWin.window setContentSize:NSMakeSize(width, height)];
+}
+
+//========================================================================
+// Set the window position
+//========================================================================
+
+void _glfwPlatformSetWindowPos( int x, int y )
+{
+    NSRect contentRect = [_glfwWin.window contentRectForFrameRect:[_glfwWin.window frame]];
+
+    // We assume here that the client code wants to position the window within the
+    // screen the window currently occupies
+    NSRect screenRect = [[_glfwWin.window screen] visibleFrame];
+    contentRect.origin = NSMakePoint(screenRect.origin.x + x,
+                                     screenRect.origin.y + screenRect.size.height -
+                                         y - contentRect.size.height);
+
+    [_glfwWin.window setFrame:[_glfwWin.window frameRectForContentRect:contentRect]
+                      display:YES];
+}
+
+//========================================================================
+// Iconify the window
+//========================================================================
+
+void _glfwPlatformIconifyWindow( void )
+{
+    [_glfwWin.window miniaturize:nil];
+}
+
+//========================================================================
+// Restore (un-iconify) the window
+//========================================================================
+
+void _glfwPlatformRestoreWindow( void )
+{
+    [_glfwWin.window deminiaturize:nil];
+}
+
+//========================================================================
+// Swap buffers
+//========================================================================
+
+void _glfwPlatformSwapBuffers( void )
+{
+    // ARP appears to be unnecessary, but this is future-proof
+    [_glfwWin.context flushBuffer];
+}
+
+//========================================================================
+// Set double buffering swap interval
+//========================================================================
+
+void _glfwPlatformSwapInterval( int interval )
+{
+    GLint sync = interval;
+    [_glfwWin.context setValues:&sync forParameter:NSOpenGLCPSwapInterval];
+}
+
+//========================================================================
+// Write back window parameters into GLFW window structure
+//========================================================================
+
+void _glfwPlatformRefreshWindowParams( void )
+{
+    GLint value;
+
+    // Since GLFW 2.x doesn't understand screens, we use virtual screen zero
+
+    [_glfwWin.pixelFormat getValues:&value
+                       forAttribute:NSOpenGLPFAAccelerated
+                   forVirtualScreen:0];
+    _glfwWin.accelerated = value;
+
+    [_glfwWin.pixelFormat getValues:&value
+                       forAttribute:NSOpenGLPFAAlphaSize
+                   forVirtualScreen:0];
+    _glfwWin.alphaBits = value;
+
+    // It seems that the color size includes the size of the alpha channel
+    [_glfwWin.pixelFormat getValues:&value
+                       forAttribute:NSOpenGLPFAColorSize
+                   forVirtualScreen:0];
+    value -= _glfwWin.alphaBits;
+    _glfwWin.redBits = value / 3;
+    _glfwWin.greenBits = value / 3;
+    _glfwWin.blueBits = value / 3;
+
+    [_glfwWin.pixelFormat getValues:&value
+                       forAttribute:NSOpenGLPFADepthSize
+                   forVirtualScreen:0];
+    _glfwWin.depthBits = value;
+
+    [_glfwWin.pixelFormat getValues:&value
+                       forAttribute:NSOpenGLPFAStencilSize
+                   forVirtualScreen:0];
+    _glfwWin.stencilBits = value;
+
+    [_glfwWin.pixelFormat getValues:&value
+                       forAttribute:NSOpenGLPFAAccumSize
+                   forVirtualScreen:0];
+    _glfwWin.accumRedBits = value / 3;
+    _glfwWin.accumGreenBits = value / 3;
+    _glfwWin.accumBlueBits = value / 3;
+
+    // TODO: Figure out what to set this value to
+    _glfwWin.accumAlphaBits = 0;
+
+    [_glfwWin.pixelFormat getValues:&value
+                       forAttribute:NSOpenGLPFAAuxBuffers
+                   forVirtualScreen:0];
+    _glfwWin.auxBuffers = value;
+
+    [_glfwWin.pixelFormat getValues:&value
+                       forAttribute:NSOpenGLPFAStereo
+                   forVirtualScreen:0];
+    _glfwWin.stereo = value;
+
+    [_glfwWin.pixelFormat getValues:&value
+                       forAttribute:NSOpenGLPFASamples
+                   forVirtualScreen:0];
+    _glfwWin.samples = value;
+
+    // These are forced to false as long as Mac OS X lacks support for OpenGL 3.0+
+    _glfwWin.glForward = GL_FALSE;
+    _glfwWin.glDebug = GL_FALSE;
+    _glfwWin.glProfile = 0;
+}
+
+//========================================================================
+// Poll for new window and input events
+//========================================================================
+
+void _glfwPlatformPollEvents( void )
+{
+    NSEvent *event;
+
+    do
+    {
+        event = [NSApp nextEventMatchingMask:NSAnyEventMask
+                                   untilDate:[NSDate distantPast]
+                                      inMode:NSDefaultRunLoopMode
+                                     dequeue:YES];
+
+        if (event)
+        {
+            [NSApp sendEvent:event];
+        }
+    }
+    while (event);
+
+    [_glfwLibrary.AutoreleasePool drain];
+    _glfwLibrary.AutoreleasePool = [[NSAutoreleasePool alloc] init];
+}
+
+//========================================================================
+// Wait for new window and input events
+//========================================================================
+
+void _glfwPlatformWaitEvents( void )
+{
+    // I wanted to pass NO to dequeue:, and rely on PollEvents to
+    // dequeue and send.  For reasons not at all clear to me, passing
+    // NO to dequeue: causes this method never to return.
+    NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask
+                                        untilDate:[NSDate distantFuture]
+                                           inMode:NSDefaultRunLoopMode
+                                          dequeue:YES];
+    [NSApp sendEvent:event];
+
+    _glfwPlatformPollEvents();
+}
+
+//========================================================================
+// Hide mouse cursor (lock it)
+//========================================================================
+
+void _glfwPlatformHideMouseCursor( void )
+{
+    [NSCursor hide];
+    CGAssociateMouseAndMouseCursorPosition( false );
+}
+
+//========================================================================
+// Show mouse cursor (unlock it)
+//========================================================================
+
+void _glfwPlatformShowMouseCursor( void )
+{
+    [NSCursor unhide];
+    CGAssociateMouseAndMouseCursorPosition( true );
+}
+
+//========================================================================
+// Set physical mouse cursor position
+//========================================================================
+
+void _glfwPlatformSetMouseCursorPos( int x, int y )
+{
+    // The library seems to assume that after calling this the mouse won't move,
+    // but obviously it will, and escape the app's window, and activate other apps,
+    // and other badness in pain.  I think the API's just silly, but maybe I'm
+    // misunderstanding it...
+
+    // Also, (x, y) are window coords...
+
+    // Also, it doesn't seem possible to write this robustly without
+    // calculating the maximum y coordinate of all screens, since Cocoa's
+    // "global coordinates" are upside down from CG's...
+
+    // Without this (once per app run, but it's convenient to do it here)
+    // events will be suppressed for a default of 0.25 seconds after we
+    // move the cursor.
+    CGSetLocalEventsSuppressionInterval( 0.0 );
+
+    NSPoint localPoint = NSMakePoint( x, y );
+    NSPoint globalPoint = [_glfwWin.window convertBaseToScreen:localPoint];
+    CGPoint mainScreenOrigin = CGDisplayBounds( CGMainDisplayID() ).origin;
+    double mainScreenHeight = CGDisplayBounds( CGMainDisplayID() ).size.height;
+    CGPoint targetPoint = CGPointMake( globalPoint.x - mainScreenOrigin.x,
+                                       mainScreenHeight - globalPoint.y - mainScreenOrigin.y );
+    CGDisplayMoveCursorToPoint( CGMainDisplayID(), targetPoint );
+}
+
