diff --git a/Changelog.txt b/Changelog.txt
--- a/Changelog.txt
+++ b/Changelog.txt
@@ -1,3 +1,12 @@
+Thu Oct  3 23:59:17 PDT 2013  paul@thev.net
+  * Bump version to 0.5.2.0
+
+Thu Oct  3 23:26:34 PDT 2013  paul@thev.net
+  * Upgrade to glfw C version 2.7.9
+
+Thu Oct  3 23:25:39 PDT 2013  paul@thev.net
+  * Compatibility fix to work with Cabal 1.18
+
 Sat Nov  3 21:41:09 PDT 2012  paul@thev.net
   * Bump version to 0.5.1.0 for release
 
diff --git a/GLFW.cabal b/GLFW.cabal
--- a/GLFW.cabal
+++ b/GLFW.cabal
@@ -1,15 +1,19 @@
 name:          GLFW
-version:       0.5.1.0
+version:       0.5.2.0
 homepage:      http://haskell.org/haskellwiki/GLFW
 maintainer:    Paul H. Liu <paul@thev.net>, Marc Sunet <jeannekamikaze@gmail.com>
-cabal-version: >= 1.10
+cabal-version: >= 1.12
 build-type:    Custom
 category:      Graphics
 synopsis:      A Haskell binding for GLFW
 description:   A Haskell binding for GLFW, a window system independent toolkit
                for writing OpenGL programs. For more information about the C
                library on which this binding is based, please see
-               <http://www.glfw.org>.
+               <http://www.glfw.org>. Note that this binding comes with an 
+               older GLFW C version 2.7.9 due to incompatible API changes 
+               GLFW since 3.0 (for example, the removal of texture functions).
+               If you want to use newer GLFW C versions, install Haskell package
+               GLFW-b instead.
 license:       BSD3
 license-file:  LICENSE
 
diff --git a/README.txt b/README.txt
--- a/README.txt
+++ b/README.txt
@@ -19,7 +19,7 @@
 ============
 
 The package comes together with a (partial) source distribution 
-of GLFW v2.7.2, which is compiled and installed together with
+of GLFW v2.7.9, which is compiled and installed together with
 the Haskell package.
 
 If you already have the Haskell package cabal-install, you can
@@ -62,7 +62,7 @@
 ====
 
 For Windows users, you may have to include GHC's gcc-lib directory 
-in your PATH environment, e.g., c:\ghc\ghc-6.8.3\gcc-lib, before 
+in your PATH environment, e.g., c:\ghc\ghc-7.6.3\gcc-lib, before 
 configuring the GLFW module, otherwise it'll complain about missing
 program for ld.
 
@@ -72,15 +72,15 @@
 command. 
 
 For Mac users, unfortunately interactively running GLFW programs
-from GHCi would result in a crash. The only sensible way is to 
-compile and run the program. On the other hand, it no longer 
-requires the enableGUI trick.
+from GHCi would result in a crash if you use GHC 7.6.3 or older. 
+The only sensible way is to compile and run the program, or use
+GHC 7.8 or newer. 
 
 =============
 Package Usage
 =============
 
-The package is tested with GHC 6.10.2 and GHC 7.0.2 on all
+The package is tested with GHC 7.4.2 and GHC 7.6.3 on all
 three platforms (Linux, Win32/MinGW, and Mac OS X). Though it may
 work with older versions of GHC or even Hugs, they are not tested.
 
@@ -127,4 +127,4 @@
   http://projects.haskell.org/cgi-bin/mailman/listinfo/glfw
 
 --
-Last Updated: Fri Jan 20 PST 2012
+Last Updated: Thu Oct 3 PST 2013
diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
@@ -7,6 +7,7 @@
 import Distribution.Simple.Utils (rawSystemStdInOut, withTempFile)
 import Distribution.Simple.LocalBuildInfo
 import Distribution.Simple.Program
+import Distribution.Simple.Program.Types
 import Distribution.Verbosity
 import Distribution.PackageDescription
 import Distribution.System
@@ -14,9 +15,9 @@
 import System.FilePath
 import System.Directory
 import System.IO (hClose, hPutStr)
-import System.Cmd (rawSystem)
+import System.IO.Error (catchIOError)
 import Data.Maybe (fromJust)
-import Foreign (bitSize)
+import Foreign (sizeOf)
 import Control.Monad (when)
 --import Control.Monad.State 
 --import Control.Monad.Trans.Class (lift)
@@ -51,14 +52,12 @@
       Just cpp_name -> do
         let cpp_name  = fromJust (lookup "x-cc-name" custom_bi)
             c_srcs    = cSources lib_bi
-            mbits     = bitSize (undefined :: Int)
+            mbits     = 8 * sizeOf (undefined :: Int)
             cc_opts   = ("-m" ++ show mbits) : "-S" : ccOptions lib_bi
             inc_dirs  = includeDirs lib_bi
             lib_dirs  = extraLibDirs lib_bi
             bld_dir   = buildDir local_bld_info
-            prog      = ConfiguredProgram { programId = cpp_name, programVersion = Nothing,
-                                            programDefaultArgs = [], programOverrideArgs = [],
-                                            programLocation = FoundOnSystem { locationPath = cpp_name } }
+            prog      = simpleConfiguredProgram cpp_name (FoundOnSystem { locationPath = cpp_name })
         -- Compile C/C++ sources
         putStrLn $ "invoking my compile phase " ++ cpp_name
         objs <- mapM (compileCxx prog cc_opts inc_dirs bld_dir) c_srcs
@@ -164,8 +163,9 @@
         hClose outHandle
         hPutStr inHandle contents
         hClose inHandle
-        (out, err, exitCode) <- rawSystemStdInOut verbosity "cc" (["-c", path, "-o", objPath] ++ flags) Nothing False
-        return (exitCode == ExitSuccess)     
+        let cc = simpleProgramInvocation "cc" (["-c", path, "-o", objPath] ++ flags)
+        -- (out, err, exitCode) <- rawSystemStdInOut verbosity "cc"  Nothing Nothing Nothing False
+        catchIOError (getProgramInvocationOutput verbosity cc >> return True) (\_ -> return False)
 
 progXrandr = unlines
             ["#include <X11/Xlib.h>"
@@ -250,6 +250,5 @@
         a <- m
         return (a, s)
 instance (Monad m) => MonadState s (StateT s m) where
-    get   = StateT $ \s -> return (s, s)                                                                               
+    get   = StateT $ \s -> return (s, s) 
     put s = StateT $ \_ -> return ((), s)
-
diff --git a/glfw/include/GL/glfw.h b/glfw/include/GL/glfw.h
--- a/glfw/include/GL/glfw.h
+++ b/glfw/include/GL/glfw.h
@@ -187,7 +187,7 @@
 
 #define GLFW_VERSION_MAJOR    2
 #define GLFW_VERSION_MINOR    7
-#define GLFW_VERSION_REVISION 5
+#define GLFW_VERSION_REVISION 9
 
 
 /*************************************************************************
diff --git a/glfw/lib/cocoa/cocoa_init.m b/glfw/lib/cocoa/cocoa_init.m
--- a/glfw/lib/cocoa/cocoa_init.m
+++ b/glfw/lib/cocoa/cocoa_init.m
@@ -146,6 +146,8 @@
 
     _glfwInitTimer();
 
+    _glfwInitJoysticks();
+
     _glfwLibrary.eventSource = CGEventSourceCreate( kCGEventSourceStateHIDSystemState );
     if( !_glfwLibrary.eventSource )
     {
@@ -167,7 +169,10 @@
 
 int _glfwPlatformTerminate( void )
 {
-    // TODO: Fail unless this is the main thread
+    if( pthread_self() != _glfwThrd.First.PosixID )
+    {
+        return GL_FALSE;
+    }
 
     glfwCloseWindow();
 
@@ -179,6 +184,8 @@
         CFRelease( _glfwLibrary.eventSource );
         _glfwLibrary.eventSource = NULL;
     }
+
+    _glfwTerminateJoysticks();
 
     [_glfwLibrary.autoreleasePool release];
     _glfwLibrary.autoreleasePool = nil;
diff --git a/glfw/lib/cocoa/cocoa_joystick.m b/glfw/lib/cocoa/cocoa_joystick.m
--- a/glfw/lib/cocoa/cocoa_joystick.m
+++ b/glfw/lib/cocoa/cocoa_joystick.m
@@ -29,7 +29,481 @@
 
 #include "internal.h"
 
+#include <unistd.h>
+#include <ctype.h>
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOCFPlugIn.h>
+#include <IOKit/hid/IOHIDLib.h>
+#include <IOKit/hid/IOHIDKeys.h>
+#include <Kernel/IOKit/hidsystem/IOHIDUsageTables.h>
+
+
+//------------------------------------------------------------------------
+// Joystick state
+//------------------------------------------------------------------------
+
+typedef struct
+{
+    int present;
+    char product[256];
+
+    IOHIDDeviceInterface** interface;
+
+    int numAxes;
+    int numButtons;
+    int numHats;
+
+    CFMutableArrayRef axes;
+    CFMutableArrayRef buttons;
+    CFMutableArrayRef hats;
+
+} _glfwJoystick;
+
+static _glfwJoystick _glfwJoysticks[GLFW_JOYSTICK_LAST + 1];
+
+
+typedef struct
+{
+    IOHIDElementCookie cookie;
+
+    long value;
+
+    long min;
+    long max;
+
+    long minReport;
+    long maxReport;
+
+} _glfwJoystickElement;
+
+
+void GetElementsCFArrayHandler( const void* value, void* parameter );
+
+
+//========================================================================
+// Adds an element to the specified joystick
+//========================================================================
+
+static void addJoystickElement( _glfwJoystick* joystick, CFTypeRef refElement )
+{
+    long elementType, usagePage, usage;
+    CFTypeRef refElementType, refUsagePage, refUsage;
+
+    refElementType = CFDictionaryGetValue( refElement, CFSTR( kIOHIDElementTypeKey ) );
+    refUsagePage = CFDictionaryGetValue( refElement, CFSTR( kIOHIDElementUsagePageKey ) );
+    refUsage = CFDictionaryGetValue( refElement, CFSTR( kIOHIDElementUsageKey ) );
+
+    CFMutableArrayRef elementsArray = NULL;
+
+    CFNumberGetValue( refElementType, kCFNumberLongType, &elementType );
+    CFNumberGetValue( refUsagePage, kCFNumberLongType, &usagePage );
+    CFNumberGetValue( refUsage, kCFNumberLongType, &usage );
+
+    if( elementType == kIOHIDElementTypeInput_Axis ||
+        elementType == kIOHIDElementTypeInput_Button ||
+        elementType == kIOHIDElementTypeInput_Misc )
+    {
+        switch( usagePage ) /* only interested in kHIDPage_GenericDesktop and kHIDPage_Button */
+        {
+            case kHIDPage_GenericDesktop:
+            {
+                switch( usage )
+                {
+                    case kHIDUsage_GD_X:
+                    case kHIDUsage_GD_Y:
+                    case kHIDUsage_GD_Z:
+                    case kHIDUsage_GD_Rx:
+                    case kHIDUsage_GD_Ry:
+                    case kHIDUsage_GD_Rz:
+                    case kHIDUsage_GD_Slider:
+                    case kHIDUsage_GD_Dial:
+                    case kHIDUsage_GD_Wheel:
+                        joystick->numAxes++;
+                        elementsArray = joystick->axes;
+                        break;
+                    case kHIDUsage_GD_Hatswitch:
+                        joystick->numHats++;
+                        elementsArray = joystick->hats;
+                        break;
+                }
+
+                break;
+            }
+
+            case kHIDPage_Button:
+                joystick->numButtons++;
+                elementsArray = joystick->buttons;
+                break;
+            default:
+                break;
+        }
+
+        if( elementsArray )
+        {
+            long number;
+            CFTypeRef refType;
+
+            _glfwJoystickElement* element = (_glfwJoystickElement*) malloc( sizeof( _glfwJoystickElement ) );
+
+            CFArrayAppendValue( elementsArray, element );
+
+            refType = CFDictionaryGetValue( refElement, CFSTR( kIOHIDElementCookieKey ) );
+            if( refType && CFNumberGetValue( refType, kCFNumberLongType, &number ) )
+            {
+                element->cookie = (IOHIDElementCookie) number;
+            }
+
+            refType = CFDictionaryGetValue( refElement, CFSTR( kIOHIDElementMinKey ) );
+            if( refType && CFNumberGetValue( refType, kCFNumberLongType, &number ) )
+            {
+                element->minReport = element->min = number;
+            }
+
+            refType = CFDictionaryGetValue( refElement, CFSTR( kIOHIDElementMaxKey ) );
+            if( refType && CFNumberGetValue( refType, kCFNumberLongType, &number ) )
+            {
+                element->maxReport = element->max = number;
+            }
+        }
+    }
+    else
+    {
+        CFTypeRef refElementTop = CFDictionaryGetValue( refElement, CFSTR( kIOHIDElementKey ) );
+        if( refElementTop )
+        {
+            CFTypeID type = CFGetTypeID( refElementTop );
+            if( type == CFArrayGetTypeID() ) /* if element is an array */
+            {
+                CFRange range = { 0, CFArrayGetCount( refElementTop ) };
+                CFArrayApplyFunction( refElementTop, range, GetElementsCFArrayHandler, joystick );
+            }
+        }
+    }
+}
+
+
+//========================================================================
+// Adds an element to the specified joystick
+//========================================================================
+
+void GetElementsCFArrayHandler( const void* value, void* parameter )
+{
+    if( CFGetTypeID( value ) == CFDictionaryGetTypeID() )
+    {
+        addJoystickElement( (_glfwJoystick*) parameter, (CFTypeRef) value );
+    }
+}
+
+
+//========================================================================
+// Returns the value of the specified element of the specified joystick
+//========================================================================
+
+static long getElementValue( _glfwJoystick* joystick, _glfwJoystickElement* element )
+{
+    IOReturn result = kIOReturnSuccess;
+    IOHIDEventStruct hidEvent;
+    hidEvent.value = 0;
+
+    if( joystick && element && joystick->interface )
+    {
+        result = (*(joystick->interface))->getElementValue( joystick->interface,
+                                                            element->cookie,
+                                                            &hidEvent );
+        if( kIOReturnSuccess == result )
+        {
+            /* record min and max for auto calibration */
+            if( hidEvent.value < element->minReport )
+            {
+                element->minReport = hidEvent.value;
+            }
+            if( hidEvent.value > element->maxReport )
+            {
+                element->maxReport = hidEvent.value;
+            }
+        }
+    }
+
+    /* auto user scale */
+    return (long) hidEvent.value;
+}
+
+
+//========================================================================
+// Removes the specified joystick
+//========================================================================
+
+static void removeJoystick( _glfwJoystick* joystick )
+{
+    int i;
+
+    if( joystick->present )
+    {
+        joystick->present = GL_FALSE;
+
+        for( i = 0;  i < joystick->numAxes;  i++ )
+        {
+            _glfwJoystickElement* axes =
+                (_glfwJoystickElement*) CFArrayGetValueAtIndex( joystick->axes, i );
+            free( axes );
+        }
+        CFArrayRemoveAllValues( joystick->axes );
+        joystick->numAxes = 0;
+
+        for( i = 0;  i < joystick->numButtons;  i++ )
+        {
+            _glfwJoystickElement* button =
+                (_glfwJoystickElement*) CFArrayGetValueAtIndex( joystick->buttons, i );
+            free( button );
+        }
+        CFArrayRemoveAllValues( joystick->buttons );
+        joystick->numButtons = 0;
+
+        for( i = 0;  i < joystick->numHats;  i++ )
+        {
+            _glfwJoystickElement* hat =
+                (_glfwJoystickElement*) CFArrayGetValueAtIndex( joystick->hats, i );
+            free( hat );
+        }
+        CFArrayRemoveAllValues( joystick->hats );
+        joystick->hats = 0;
+
+        (*(joystick->interface))->close( joystick->interface );
+        (*(joystick->interface))->Release( joystick->interface );
+
+        joystick->interface = NULL;
+    }
+}
+
+
+//========================================================================
+// Callback for user-initiated joystick removal
+//========================================================================
+
+static void removalCallback( void* target, IOReturn result, void* refcon, void* sender )
+{
+    removeJoystick( (_glfwJoystick*) refcon );
+}
+
+
+//========================================================================
+// Polls for joystick events and updates GFLW state
+//========================================================================
+
+static void pollJoystickEvents( void )
+{
+    int i;
+    CFIndex j;
+
+    for( i = 0;  i < GLFW_JOYSTICK_LAST + 1;  i++ )
+    {
+        _glfwJoystick* joystick = &_glfwJoysticks[i];
+
+        if( joystick->present )
+        {
+            for( j = 0;  j < joystick->numButtons;  j++ )
+            {
+                _glfwJoystickElement* button =
+                    (_glfwJoystickElement*) CFArrayGetValueAtIndex( joystick->buttons, j );
+                button->value = getElementValue( joystick, button );
+            }
+
+            for( j = 0;  j < joystick->numAxes;  j++ )
+            {
+                _glfwJoystickElement* axes =
+                    (_glfwJoystickElement*) CFArrayGetValueAtIndex( joystick->axes, j );
+                axes->value = getElementValue( joystick, axes );
+            }
+
+            for( j = 0;  j < joystick->numHats;  j++ )
+            {
+                _glfwJoystickElement* hat =
+                    (_glfwJoystickElement*) CFArrayGetValueAtIndex( joystick->hats, j );
+                hat->value = getElementValue( joystick, hat );
+            }
+        }
+    }
+}
+
+
 //************************************************************************
+//****                  GLFW internal functions                       ****
+//************************************************************************
+
+//========================================================================
+// Initialize joystick interface
+//========================================================================
+
+void _glfwInitJoysticks( void )
+{
+    int deviceCounter = 0;
+    IOReturn result = kIOReturnSuccess;
+    mach_port_t masterPort = 0;
+    io_iterator_t objectIterator = 0;
+    CFMutableDictionaryRef hidMatchDictionary = NULL;
+    io_object_t ioHIDDeviceObject = 0;
+
+    result = IOMasterPort( bootstrap_port, &masterPort );
+    hidMatchDictionary = IOServiceMatching( kIOHIDDeviceKey );
+    if( kIOReturnSuccess != result || !hidMatchDictionary )
+    {
+        if( hidMatchDictionary )
+        {
+            CFRelease( hidMatchDictionary );
+        }
+
+        return;
+    }
+
+    result = IOServiceGetMatchingServices( masterPort,
+                                           hidMatchDictionary,
+                                           &objectIterator );
+    if( result != kIOReturnSuccess )
+    {
+        return;
+    }
+
+    if( !objectIterator ) /* there are no joysticks */
+    {
+        return;
+    }
+
+    while( ( ioHIDDeviceObject = IOIteratorNext( objectIterator ) ) )
+    {
+        CFMutableDictionaryRef hidProperties = 0;
+        kern_return_t result;
+        CFTypeRef refCF = 0;
+
+        IOCFPlugInInterface** ppPlugInInterface = NULL;
+        HRESULT plugInResult = S_OK;
+        SInt32 score = 0;
+
+        long usagePage, usage;
+
+        result = IORegistryEntryCreateCFProperties( ioHIDDeviceObject,
+                                                    &hidProperties,
+                                                    kCFAllocatorDefault,
+                                                    kNilOptions );
+
+        if( result != kIOReturnSuccess )
+        {
+            continue;
+        }
+
+        /* Check device type */
+        refCF = CFDictionaryGetValue( hidProperties, CFSTR( kIOHIDPrimaryUsagePageKey ) );
+        if( refCF )
+        {
+            CFNumberGetValue( refCF, kCFNumberLongType, &usagePage );
+            if( usagePage != kHIDPage_GenericDesktop )
+            {
+                /* We are not interested in this device */
+                continue;
+            }
+        }
+
+        refCF = CFDictionaryGetValue( hidProperties, CFSTR( kIOHIDPrimaryUsageKey ) );
+        if( refCF )
+        {
+            CFNumberGetValue( refCF, kCFNumberLongType, &usage );
+
+            if( usage != kHIDUsage_GD_Joystick &&
+                usage != kHIDUsage_GD_GamePad &&
+                usage != kHIDUsage_GD_MultiAxisController )
+            {
+                /* We are not interested in this device */
+                continue;
+            }
+        }
+
+        _glfwJoystick* joystick = &_glfwJoysticks[deviceCounter];
+
+        joystick->present = GL_TRUE;
+
+        result = IOCreatePlugInInterfaceForService( ioHIDDeviceObject,
+                                                    kIOHIDDeviceUserClientTypeID,
+                                                    kIOCFPlugInInterfaceID,
+                                                    &ppPlugInInterface,
+                                                    &score );
+
+        if( kIOReturnSuccess != result )
+        {
+            return;
+        }
+
+        plugInResult = (*ppPlugInInterface)->QueryInterface( ppPlugInInterface,
+                                                             CFUUIDGetUUIDBytes( kIOHIDDeviceInterfaceID ),
+                                                             (void *) &(joystick->interface) );
+
+        if( plugInResult != S_OK )
+        {
+            return;
+        }
+
+        (*ppPlugInInterface)->Release( ppPlugInInterface );
+
+        (*(joystick->interface))->open( joystick->interface, 0 );
+        (*(joystick->interface))->setRemovalCallback( joystick->interface,
+                                                      removalCallback,
+                                                      joystick,
+                                                      joystick );
+
+        /* Get product string */
+        refCF = CFDictionaryGetValue( hidProperties, CFSTR( kIOHIDProductKey ) );
+        if( refCF )
+        {
+            CFStringGetCString( refCF,
+                                (char*) &(joystick->product),
+                                256,
+                                CFStringGetSystemEncoding() );
+        }
+
+        joystick->numAxes = 0;
+        joystick->numButtons = 0;
+        joystick->numHats = 0;
+        joystick->axes = CFArrayCreateMutable( NULL, 0, NULL );
+        joystick->buttons = CFArrayCreateMutable( NULL, 0, NULL );
+        joystick->hats = CFArrayCreateMutable( NULL, 0, NULL );
+
+        CFTypeRef refTopElement = CFDictionaryGetValue( hidProperties,
+                                                        CFSTR( kIOHIDElementKey ) );
+        CFTypeID type = CFGetTypeID( refTopElement );
+        if( type == CFArrayGetTypeID() )
+        {
+            CFRange range = { 0, CFArrayGetCount( refTopElement ) };
+            CFArrayApplyFunction( refTopElement,
+                                  range,
+                                  GetElementsCFArrayHandler,
+                                  (void*) joystick);
+        }
+
+        deviceCounter++;
+    }
+}
+
+
+//========================================================================
+// Close all opened joystick handles
+//========================================================================
+
+void _glfwTerminateJoysticks( void )
+{
+    int i;
+
+    for( i = 0;  i < GLFW_JOYSTICK_LAST + 1;  i++ )
+    {
+        _glfwJoystick* joystick = &_glfwJoysticks[i];
+        removeJoystick( joystick );
+    }
+}
+
+
+//************************************************************************
 //****               Platform implementation functions                ****
 //************************************************************************
 
@@ -39,8 +513,29 @@
 
 int _glfwPlatformGetJoystickParam( int joy, int param )
 {
-    // TODO: Implement this.
-    return 0;
+    if( !_glfwJoysticks[joy].present )
+    {
+        // TODO: Figure out if this is an error
+        return GL_FALSE;
+    }
+
+    switch( param )
+    {
+        case GLFW_PRESENT:
+            return GL_TRUE;
+
+        case GLFW_AXES:
+            return (int) CFArrayGetCount( _glfwJoysticks[joy].axes );
+
+        case GLFW_BUTTONS:
+            return (int) CFArrayGetCount( _glfwJoysticks[joy].buttons ) +
+                   ((int) CFArrayGetCount( _glfwJoysticks[joy].hats )) * 4;
+
+        default:
+            break;
+    }
+
+    return GL_FALSE;
 }
 
 
@@ -50,8 +545,51 @@
 
 int _glfwPlatformGetJoystickPos( int joy, float *pos, int numaxes )
 {
-    // TODO: Implement this.
-    return 0;
+    int i;
+
+    if( joy < GLFW_JOYSTICK_1 || joy > GLFW_JOYSTICK_LAST )
+    {
+        return 0;
+    }
+
+    _glfwJoystick joystick = _glfwJoysticks[joy];
+
+    if( !joystick.present )
+    {
+        // TODO: Figure out if this is an error
+        return 0;
+    }
+
+    numaxes = numaxes < joystick.numAxes ? numaxes : joystick.numAxes;
+
+    // Update joystick state
+    pollJoystickEvents();
+
+    for( i = 0;  i < numaxes;  i++ )
+    {
+        _glfwJoystickElement* axes =
+            (_glfwJoystickElement*) CFArrayGetValueAtIndex( joystick.axes, i );
+
+        long readScale = axes->maxReport - axes->minReport;
+
+        if( readScale == 0 )
+        {
+            pos[i] = axes->value;
+        }
+        else
+        {
+            pos[i] = (2.0f * (axes->value - axes->minReport) / readScale) - 1.0f;
+        }
+
+        //printf("%ld, %ld, %ld\n", axes->value, axes->minReport, axes->maxReport);
+
+        if( i & 1 )
+        {
+            pos[i] = -pos[i];
+        }
+    }
+
+    return numaxes;
 }
 
 
@@ -61,7 +599,50 @@
 
 int _glfwPlatformGetJoystickButtons( int joy, unsigned char *buttons, int numbuttons )
 {
-    // TODO: Implement this.
-    return 0;
+    int i, j, button;
+
+    if( joy < GLFW_JOYSTICK_1 || joy > GLFW_JOYSTICK_LAST )
+    {
+        return 0;
+    }
+
+    _glfwJoystick joystick = _glfwJoysticks[joy];
+
+    if( !joystick.present )
+    {
+        // TODO: Figure out if this is an error
+        return 0;
+    }
+
+    // Update joystick state
+    pollJoystickEvents();
+
+    for( button = 0;  button < numbuttons && button < joystick.numButtons;  button++ )
+    {
+        _glfwJoystickElement* element = (_glfwJoystickElement*) CFArrayGetValueAtIndex( joystick.buttons, button );
+        buttons[button] = element->value ? GLFW_PRESS : GLFW_RELEASE;
+    }
+
+    // Virtual buttons - Inject data from hats
+    // Each hat is exposed as 4 buttons which exposes 8 directions with concurrent button presses
+
+    const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 }; // Bit fields of button presses for each direction, including nil
+
+    for( i = 0;  i < joystick.numHats;  i++ )
+    {
+        _glfwJoystickElement* hat = (_glfwJoystickElement*) CFArrayGetValueAtIndex( joystick.hats, i );
+        int value = hat->value;
+        if( value < 0 || value > 8 )
+        {
+            value = 8;
+        }
+
+        for( j = 0;  j < 4 && button < numbuttons;  j++ )
+        {
+            buttons[button++] = directions[value] & (1 << j) ? GLFW_PRESS : GLFW_RELEASE;
+        }
+    }
+
+    return button;
 }
 
diff --git a/glfw/lib/cocoa/cocoa_window.m b/glfw/lib/cocoa/cocoa_window.m
--- a/glfw/lib/cocoa/cocoa_window.m
+++ b/glfw/lib/cocoa/cocoa_window.m
@@ -253,6 +253,18 @@
     }
 }
 
+- (void)windowDidMove:(NSNotification *)notification
+{
+    NSPoint point = [_glfwWin.window mouseLocationOutsideOfEventStream];
+    _glfwInput.MousePosX = lround(floor(point.x));
+    _glfwInput.MousePosY = _glfwWin.height - lround(ceil(point.y));
+
+    if( _glfwWin.mousePosCallback )
+    {
+        _glfwWin.mousePosCallback( _glfwInput.MousePosX, _glfwInput.MousePosY );
+    }
+}
+
 - (void)windowDidMiniaturize:(NSNotification *)notification
 {
     _glfwWin.iconified = GL_TRUE;
@@ -494,7 +506,7 @@
 
         // Cocoa coordinate system has origin at lower left
         _glfwInput.MousePosX = p.x;
-        _glfwInput.MousePosY = [[_glfwWin.window contentView] bounds].size.height - p.y;
+        _glfwInput.MousePosY = _glfwWin.height - p.y;
     }
 
     if( _glfwWin.mousePosCallback )
@@ -733,6 +745,11 @@
     [_glfwWin.window setAcceptsMouseMovedEvents:YES];
     [_glfwWin.window center];
 
+    if( [_glfwWin.window respondsToSelector:@selector(setRestorable:)] )
+    {
+        [_glfwWin.window setRestorable:NO];
+    }
+
     if( wndconfig->mode == GLFW_FULLSCREEN )
     {
         _glfwLibrary.originalMode = (NSDictionary*)
@@ -752,7 +769,10 @@
 
     if( wndconfig->mode == GLFW_FULLSCREEN )
     {
+#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
         ADD_ATTR( NSOpenGLPFAFullScreen );
+#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
+
         ADD_ATTR( NSOpenGLPFANoRecovery );
         ADD_ATTR2( NSOpenGLPFAScreenMask,
                    CGDisplayIDToOpenGLDisplayMask( CGMainDisplayID() ) );
@@ -833,9 +853,9 @@
 
     [_glfwWin.context makeCurrentContext];
 
-    NSPoint point = [[NSCursor currentCursor] hotSpot];
+    NSPoint point = [_glfwWin.window mouseLocationOutsideOfEventStream];
     _glfwInput.MousePosX = point.x;
-    _glfwInput.MousePosY = point.y;
+    _glfwInput.MousePosY = _glfwWin.height - point.y;
 
     return GL_TRUE;
 }
@@ -1022,8 +1042,6 @@
                        forAttribute:NSOpenGLPFASamples
                    forVirtualScreen:0];
     _glfwWin.samples = value;
-
-    _glfwWin.glDebug = GL_FALSE;
 }
 
 
@@ -1101,23 +1119,21 @@
 
 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...
-
-    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 );
+    if( _glfwWin.fullscreen )
+    {
+        CGPoint globalPoint = CGPointMake( x, y );
+        CGDisplayMoveCursorToPoint( CGMainDisplayID(), globalPoint );
+    }
+    else
+    {
+        NSPoint localPoint = NSMakePoint( x, _glfwWin.height - y - 1 );
+        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 );
+    }
 }
 
diff --git a/glfw/lib/cocoa/platform.h b/glfw/lib/cocoa/platform.h
--- a/glfw/lib/cocoa/platform.h
+++ b/glfw/lib/cocoa/platform.h
@@ -261,5 +261,8 @@
 // Time
 void _glfwInitTimer( void );
 
+// Joystick
+void _glfwInitJoysticks( void );
+void _glfwTerminateJoysticks( void );
 
 #endif // _platform_h_
diff --git a/glfw/lib/enable.c b/glfw/lib/enable.c
--- a/glfw/lib/enable.c
+++ b/glfw/lib/enable.c
@@ -48,23 +48,26 @@
         return;
     }
 
-    // Show mouse cursor
-    _glfwPlatformShowMouseCursor();
-
-    centerPosX = _glfwWin.width / 2;
-    centerPosY = _glfwWin.height / 2;
-
-    if( centerPosX != _glfwInput.MousePosX || centerPosY != _glfwInput.MousePosY )
+    if( _glfwWin.active )
     {
-        _glfwPlatformSetMouseCursorPos( centerPosX, centerPosY );
+        // Show mouse cursor
+        _glfwPlatformShowMouseCursor();
 
-        _glfwInput.MousePosX = centerPosX;
-        _glfwInput.MousePosY = centerPosY;
+        centerPosX = _glfwWin.width / 2;
+        centerPosY = _glfwWin.height / 2;
 
-        if( _glfwWin.mousePosCallback )
+        if( centerPosX != _glfwInput.MousePosX || centerPosY != _glfwInput.MousePosY )
         {
-            _glfwWin.mousePosCallback( _glfwInput.MousePosX,
-                                       _glfwInput.MousePosY );
+            _glfwPlatformSetMouseCursorPos( centerPosX, centerPosY );
+
+            _glfwInput.MousePosX = centerPosX;
+            _glfwInput.MousePosY = centerPosY;
+
+            if( _glfwWin.mousePosCallback )
+            {
+                _glfwWin.mousePosCallback( _glfwInput.MousePosX,
+                                        _glfwInput.MousePosY );
+            }
         }
     }
 
@@ -84,11 +87,10 @@
     }
 
     // Hide mouse cursor
-    _glfwPlatformHideMouseCursor();
-
-    // Move cursor to the middle of the window
-    _glfwPlatformSetMouseCursorPos( _glfwWin.width >> 1,
-                                    _glfwWin.height >> 1 );
+    if( _glfwWin.active )
+    {
+        _glfwPlatformHideMouseCursor();
+    }
 
     // From now on the mouse is locked
     _glfwWin.mouseLock = GL_TRUE;
diff --git a/glfw/lib/win32/platform.h b/glfw/lib/win32/platform.h
--- a/glfw/lib/win32/platform.h
+++ b/glfw/lib/win32/platform.h
@@ -369,9 +369,8 @@
     GLboolean                      has_WGL_ARB_create_context_profile;
 
     // Various platform specific internal variables
-    int       oldMouseLock;    // Old mouse-lock flag (used for remembering
-                               // mouse-lock state when iconifying)
-    int       oldMouseLockValid;
+    int       mouseLockActive;    // Whether the mouse cursor enable is applied
+                                  // to the actual system cursor
     int       desiredRefreshRate; // Desired vertical monitor refresh rate
 
 };
diff --git a/glfw/lib/win32/win32_init.c b/glfw/lib/win32/win32_init.c
--- a/glfw/lib/win32/win32_init.c
+++ b/glfw/lib/win32/win32_init.c
@@ -350,7 +350,7 @@
 
     // Restore FOREGROUNDLOCKTIMEOUT system setting
     SystemParametersInfo( SPI_SETFOREGROUNDLOCKTIMEOUT, 0,
-                          (LPVOID) _glfwLibrary.Sys.foregroundLockTimeout,
+                          (LPVOID) (INT_PTR) _glfwLibrary.Sys.foregroundLockTimeout,
                           SPIF_SENDCHANGE );
 
     return GL_TRUE;
diff --git a/glfw/lib/win32/win32_window.c b/glfw/lib/win32/win32_window.c
--- a/glfw/lib/win32/win32_window.c
+++ b/glfw/lib/win32/win32_window.c
@@ -42,6 +42,20 @@
 
 
 //========================================================================
+// Updates the cursor clip rect
+//========================================================================
+
+static void updateClipRect( void )
+{
+    RECT clipRect;
+    GetClientRect( _glfwWin.window, &clipRect );
+    ClientToScreen( _glfwWin.window, (POINT*) &clipRect.left );
+    ClientToScreen( _glfwWin.window, (POINT*) &clipRect.right );
+    ClipCursor( &clipRect );
+}
+
+
+//========================================================================
 // Enable/disable minimize/restore animations
 //========================================================================
 
@@ -154,7 +168,7 @@
 
 static _GLFWfbconfig *getFBConfigs( unsigned int *found )
 {
-    _GLFWfbconfig *result;
+    _GLFWfbconfig *fbconfigs;
     PIXELFORMATDESCRIPTOR pfd;
     int i, count;
 
@@ -175,8 +189,8 @@
         return NULL;
     }
 
-    result = (_GLFWfbconfig*) malloc( sizeof( _GLFWfbconfig ) * count );
-    if( !result )
+    fbconfigs = (_GLFWfbconfig*) malloc( sizeof( _GLFWfbconfig ) * count );
+    if( !fbconfigs )
     {
         fprintf(stderr, "Out of memory");
         return NULL;
@@ -184,6 +198,8 @@
 
     for( i = 1;  i <= count;  i++ )
     {
+        _GLFWfbconfig *fbconfig = fbconfigs + *found;
+
         if( _glfwWin.has_WGL_ARB_pixel_format )
         {
             // Get pixel format attributes through WGL_ARB_pixel_format
@@ -209,29 +225,29 @@
                 continue;
             }
 
-            result[*found].redBits = getPixelFormatAttrib( i, WGL_RED_BITS_ARB );
-            result[*found].greenBits = getPixelFormatAttrib( i, WGL_GREEN_BITS_ARB );
-            result[*found].blueBits = getPixelFormatAttrib( i, WGL_BLUE_BITS_ARB );
-            result[*found].alphaBits = getPixelFormatAttrib( i, WGL_ALPHA_BITS_ARB );
+            fbconfig->redBits = getPixelFormatAttrib( i, WGL_RED_BITS_ARB );
+            fbconfig->greenBits = getPixelFormatAttrib( i, WGL_GREEN_BITS_ARB );
+            fbconfig->blueBits = getPixelFormatAttrib( i, WGL_BLUE_BITS_ARB );
+            fbconfig->alphaBits = getPixelFormatAttrib( i, WGL_ALPHA_BITS_ARB );
 
-            result[*found].depthBits = getPixelFormatAttrib( i, WGL_DEPTH_BITS_ARB );
-            result[*found].stencilBits = getPixelFormatAttrib( i, WGL_STENCIL_BITS_ARB );
+            fbconfig->depthBits = getPixelFormatAttrib( i, WGL_DEPTH_BITS_ARB );
+            fbconfig->stencilBits = getPixelFormatAttrib( i, WGL_STENCIL_BITS_ARB );
 
-            result[*found].accumRedBits = getPixelFormatAttrib( i, WGL_ACCUM_RED_BITS_ARB );
-            result[*found].accumGreenBits = getPixelFormatAttrib( i, WGL_ACCUM_GREEN_BITS_ARB );
-            result[*found].accumBlueBits = getPixelFormatAttrib( i, WGL_ACCUM_BLUE_BITS_ARB );
-            result[*found].accumAlphaBits = getPixelFormatAttrib( i, WGL_ACCUM_ALPHA_BITS_ARB );
+            fbconfig->accumRedBits = getPixelFormatAttrib( i, WGL_ACCUM_RED_BITS_ARB );
+            fbconfig->accumGreenBits = getPixelFormatAttrib( i, WGL_ACCUM_GREEN_BITS_ARB );
+            fbconfig->accumBlueBits = getPixelFormatAttrib( i, WGL_ACCUM_BLUE_BITS_ARB );
+            fbconfig->accumAlphaBits = getPixelFormatAttrib( i, WGL_ACCUM_ALPHA_BITS_ARB );
 
-            result[*found].auxBuffers = getPixelFormatAttrib( i, WGL_AUX_BUFFERS_ARB );
-            result[*found].stereo = getPixelFormatAttrib( i, WGL_STEREO_ARB );
+            fbconfig->auxBuffers = getPixelFormatAttrib( i, WGL_AUX_BUFFERS_ARB );
+            fbconfig->stereo = getPixelFormatAttrib( i, WGL_STEREO_ARB );
 
             if( _glfwWin.has_WGL_ARB_multisample )
             {
-                result[*found].samples = getPixelFormatAttrib( i, WGL_SAMPLES_ARB );
+                fbconfig->samples = getPixelFormatAttrib( i, WGL_SAMPLES_ARB );
             }
             else
             {
-                result[*found].samples = 0;
+                fbconfig->samples = 0;
             }
         }
         else
@@ -254,6 +270,8 @@
             if( !( pfd.dwFlags & PFD_GENERIC_ACCELERATED ) &&
                 ( pfd.dwFlags & PFD_GENERIC_FORMAT ) )
             {
+                // If this is true, this pixel format is only supported by the
+                // generic software implementation
                 continue;
             }
 
@@ -263,32 +281,38 @@
                 continue;
             }
 
-            result[*found].redBits = pfd.cRedBits;
-            result[*found].greenBits = pfd.cGreenBits;
-            result[*found].blueBits = pfd.cBlueBits;
-            result[*found].alphaBits = pfd.cAlphaBits;
+            fbconfig->redBits = pfd.cRedBits;
+            fbconfig->greenBits = pfd.cGreenBits;
+            fbconfig->blueBits = pfd.cBlueBits;
+            fbconfig->alphaBits = pfd.cAlphaBits;
 
-            result[*found].depthBits = pfd.cDepthBits;
-            result[*found].stencilBits = pfd.cStencilBits;
+            fbconfig->depthBits = pfd.cDepthBits;
+            fbconfig->stencilBits = pfd.cStencilBits;
 
-            result[*found].accumRedBits = pfd.cAccumRedBits;
-            result[*found].accumGreenBits = pfd.cAccumGreenBits;
-            result[*found].accumBlueBits = pfd.cAccumBlueBits;
-            result[*found].accumAlphaBits = pfd.cAccumAlphaBits;
+            fbconfig->accumRedBits = pfd.cAccumRedBits;
+            fbconfig->accumGreenBits = pfd.cAccumGreenBits;
+            fbconfig->accumBlueBits = pfd.cAccumBlueBits;
+            fbconfig->accumAlphaBits = pfd.cAccumAlphaBits;
 
-            result[*found].auxBuffers = pfd.cAuxBuffers;
-            result[*found].stereo = ( pfd.dwFlags & PFD_STEREO ) ? GL_TRUE : GL_FALSE;
+            fbconfig->auxBuffers = pfd.cAuxBuffers;
+            fbconfig->stereo = ( pfd.dwFlags & PFD_STEREO ) ? GL_TRUE : GL_FALSE;
 
             // PFD pixel formats do not support FSAA
-            result[*found].samples = 0;
+            fbconfig->samples = 0;
         }
 
-        result[*found].platformID = i;
+        fbconfig->platformID = i;
 
         (*found)++;
     }
 
-    return result;
+    if( *found == 0 )
+    {
+        free( fbconfigs );
+        return NULL;
+    }
+
+    return fbconfigs;
 }
 
 
@@ -370,6 +394,11 @@
         {
             return GL_FALSE;
         }
+
+        // Copy the debug context hint as there's no way of verifying it
+        // This is the only code path capable of creating a debug context,
+        // so leave it as false (from the earlier memset) otherwise
+        _glfwWin.glDebug = wndconfig->glDebug;
     }
     else
     {
@@ -659,19 +688,26 @@
 static LRESULT CALLBACK windowProc( HWND hWnd, UINT uMsg,
                                     WPARAM wParam, LPARAM lParam )
 {
-    int wheelDelta, iconified;
+    int wheelDelta;
 
     switch( uMsg )
     {
         // Window activate message? (iconification?)
         case WM_ACTIVATE:
         {
-            _glfwWin.active = LOWORD(wParam) != WA_INACTIVE ? GL_TRUE : GL_FALSE;
+            int activated = (LOWORD(wParam) != WA_INACTIVE) ? GL_TRUE : GL_FALSE;
+            int iconified = HIWORD(wParam) ? GL_TRUE : GL_FALSE;
 
-            iconified = HIWORD(wParam) ? GL_TRUE : GL_FALSE;
+            if( activated && iconified )
+            {
+                // This is a workaround for window iconification using the
+                // taskbar leading to windows being told they're focused and
+                // iconified and then never told they're defocused
+                activated = GL_FALSE;
+            }
 
             // Were we deactivated/iconified?
-            if( (!_glfwWin.active || iconified) && !_glfwWin.iconified )
+            if( !activated && _glfwWin.active )
             {
                 _glfwInputDeactivation();
 
@@ -691,14 +727,12 @@
                 }
 
                 // Unlock mouse if locked
-                if( !_glfwWin.oldMouseLockValid )
+                if( _glfwWin.mouseLock )
                 {
-                    _glfwWin.oldMouseLock = _glfwWin.mouseLock;
-                    _glfwWin.oldMouseLockValid = GL_TRUE;
-                    glfwEnable( GLFW_MOUSE_CURSOR );
+                    _glfwPlatformShowMouseCursor();
                 }
             }
-            else if( _glfwWin.active || !iconified )
+            else if( activated && !_glfwWin.active )
             {
                 // If we are in fullscreen mode we need to maximize
                 if( _glfwWin.opened && _glfwWin.fullscreen && _glfwWin.iconified )
@@ -721,13 +755,13 @@
                 }
 
                 // Lock mouse, if necessary
-                if( _glfwWin.oldMouseLockValid && _glfwWin.oldMouseLock )
+                if( _glfwWin.mouseLock )
                 {
-                    glfwDisable( GLFW_MOUSE_CURSOR );
+                    _glfwPlatformHideMouseCursor();
                 }
-                _glfwWin.oldMouseLockValid = GL_FALSE;
             }
 
+            _glfwWin.active = activated;
             _glfwWin.iconified = iconified;
             return 0;
         }
@@ -865,8 +899,15 @@
             if( NewMouseX != _glfwInput.OldMouseX ||
                 NewMouseY != _glfwInput.OldMouseY )
             {
+                _glfwInput.MouseMoved = GL_TRUE;
+
                 if( _glfwWin.mouseLock )
                 {
+                    if( !_glfwWin.active )
+                    {
+                        return 0;
+                    }
+
                     _glfwInput.MousePosX += NewMouseX -
                                             _glfwInput.OldMouseX;
                     _glfwInput.MousePosY += NewMouseY -
@@ -879,7 +920,6 @@
                 }
                 _glfwInput.OldMouseX = NewMouseX;
                 _glfwInput.OldMouseY = NewMouseY;
-                _glfwInput.MouseMoved = GL_TRUE;
 
                 if( _glfwWin.mousePosCallback )
                 {
@@ -914,11 +954,7 @@
             // If the mouse is locked, update the clipping rect
             if( _glfwWin.mouseLock )
             {
-                RECT ClipWindowRect;
-                if( GetWindowRect( _glfwWin.window, &ClipWindowRect ) )
-                {
-                    ClipCursor( &ClipWindowRect );
-                }
+                updateClipRect();
             }
 
             if( _glfwWin.windowSizeCallback )
@@ -933,11 +969,7 @@
             // If the mouse is locked, update the clipping rect
             if( _glfwWin.mouseLock )
             {
-                RECT ClipWindowRect;
-                if( GetWindowRect( _glfwWin.window, &ClipWindowRect ) )
-                {
-                    ClipCursor( &ClipWindowRect );
-                }
+                updateClipRect();
             }
             return 0;
         }
@@ -991,23 +1023,20 @@
 
 //========================================================================
 // Initialize WGL-specific extensions
-// This function is called once before initial context creation, i.e. before
-// any WGL extensions could be present.  This is done in order to have both
-// extension variable clearing and loading in the same place, hopefully
-// decreasing the possibility of forgetting to add one without the other.
 //========================================================================
 
 static void initWGLExtensions( void )
 {
-    // This needs to include every function pointer loaded below
+    // This needs to include every function pointer loaded below, because
+    // context re-creation means we cannot assume the struct has been cleared
     _glfwWin.SwapIntervalEXT = NULL;
     _glfwWin.GetPixelFormatAttribivARB = NULL;
     _glfwWin.GetExtensionsStringARB = NULL;
     _glfwWin.GetExtensionsStringEXT = NULL;
     _glfwWin.CreateContextAttribsARB = NULL;
 
-    // This needs to include every extension used below except for
-    // WGL_ARB_extensions_string and WGL_EXT_extensions_string
+    // This needs to include every extension boolean used below, because context
+    // re-creation means we cannot assume the struct has been cleared
     _glfwWin.has_WGL_EXT_swap_control = GL_FALSE;
     _glfwWin.has_WGL_ARB_pixel_format = GL_FALSE;
     _glfwWin.has_WGL_ARB_multisample = GL_FALSE;
@@ -1143,7 +1172,7 @@
     _glfwWin.window = NULL;
 
     // Set common window styles
-    dwStyle   = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE;
+    dwStyle   = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
     dwExStyle = WS_EX_APPWINDOW;
 
     // Set window style, depending on fullscreen mode
@@ -1316,8 +1345,6 @@
                            wndconfig->refreshRate );
     }
 
-    initWGLExtensions();
-
     if( !createWindow( wndconfig, fbconfig ) )
     {
         fprintf( stderr, "Failed to create GLFW window\n" );
@@ -1338,6 +1365,17 @@
         }
     }
 
+    if( wndconfig->glDebug )
+    {
+        // Debug contexts are not a hard constraint, so we don't fail here if
+        // the extension isn't available
+
+        if( _glfwWin.has_WGL_ARB_create_context )
+        {
+            recreateContext = GL_TRUE;
+        }
+    }
+
     if( wndconfig->glMajor > 2 )
     {
         if ( wndconfig->glMajor != _glfwWin.glMajor ||
@@ -1410,6 +1448,7 @@
                       SWP_NOMOVE | SWP_NOSIZE );
     }
 
+    ShowWindow( _glfwWin.window, SW_SHOWNORMAL );
     setForegroundWindow( _glfwWin.window );
     SetFocus( _glfwWin.window );
 
@@ -1553,14 +1592,6 @@
         // Change display settings to the desktop resolution
         ChangeDisplaySettings( NULL, CDS_FULLSCREEN );
     }
-
-    // Unlock mouse
-    if( !_glfwWin.oldMouseLockValid )
-    {
-        _glfwWin.oldMouseLock = _glfwWin.mouseLock;
-        _glfwWin.oldMouseLockValid = GL_TRUE;
-        glfwEnable( GLFW_MOUSE_CURSOR );
-    }
 }
 
 
@@ -1587,13 +1618,6 @@
 
     // Window is no longer iconified
     _glfwWin.iconified = GL_FALSE;
-
-    // Lock mouse, if necessary
-    if( _glfwWin.oldMouseLockValid && _glfwWin.oldMouseLock )
-    {
-        glfwDisable( GLFW_MOUSE_CURSOR );
-    }
-    _glfwWin.oldMouseLockValid = GL_FALSE;
 }
 
 
@@ -1730,16 +1754,6 @@
     // Flag: mouse was not moved (will be changed by _glfwGetNextEvent if
     // there was a mouse move event)
     _glfwInput.MouseMoved = GL_FALSE;
-    if( _glfwWin.mouseLock )
-    {
-        _glfwInput.OldMouseX = _glfwWin.width/2;
-        _glfwInput.OldMouseY = _glfwWin.height/2;
-    }
-    else
-    {
-        _glfwInput.OldMouseX = _glfwInput.MousePosX;
-        _glfwInput.OldMouseY = _glfwInput.MousePosY;
-    }
 
     // Check for new window messages
     while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
@@ -1783,7 +1797,7 @@
     }
 
     // Did we have mouse movement in locked cursor mode?
-    if( _glfwInput.MouseMoved && _glfwWin.mouseLock )
+    if( _glfwInput.MouseMoved && _glfwWin.active && _glfwWin.mouseLock )
     {
         _glfwPlatformSetMouseCursorPos( _glfwWin.width / 2,
                                         _glfwWin.height / 2 );
@@ -1820,18 +1834,23 @@
 
 void _glfwPlatformHideMouseCursor( void )
 {
-    RECT ClipWindowRect;
+    if( _glfwWin.mouseLockActive )
+    {
+        return;
+    }
 
+    // Move cursor to the middle of the window
+    _glfwPlatformSetMouseCursorPos( _glfwWin.width / 2, _glfwWin.height / 2 );
+
     ShowCursor( FALSE );
 
     // Clip cursor to the window
-    if( GetWindowRect( _glfwWin.window, &ClipWindowRect ) )
-    {
-        ClipCursor( &ClipWindowRect );
-    }
+    updateClipRect();
 
     // Capture cursor to user window
     SetCapture( _glfwWin.window );
+
+    _glfwWin.mouseLockActive = GL_TRUE;
 }
 
 
@@ -1841,6 +1860,11 @@
 
 void _glfwPlatformShowMouseCursor( void )
 {
+    if( !_glfwWin.mouseLockActive )
+    {
+        return;
+    }
+
     // Un-capture cursor
     ReleaseCapture();
 
@@ -1848,6 +1872,8 @@
     ClipCursor( NULL );
 
     ShowCursor( TRUE );
+
+    _glfwWin.mouseLockActive = GL_FALSE;
 }
 
 
@@ -1863,6 +1889,9 @@
     pos.x = x;
     pos.y = y;
     ClientToScreen( _glfwWin.window, &pos );
+
+    _glfwInput.OldMouseX = x;
+    _glfwInput.OldMouseY = y;
 
     SetCursorPos( pos.x, pos.y );
 }
diff --git a/glfw/lib/x11/platform.h b/glfw/lib/x11/platform.h
--- a/glfw/lib/x11/platform.h
+++ b/glfw/lib/x11/platform.h
@@ -129,6 +129,20 @@
 typedef intptr_t GLFWintptr;
 
 
+#ifndef GLX_EXT_swap_control
+
+typedef void (*PFNGLXSWAPINTERVALEXTPROC)(Display*,GLXDrawable,int);
+
+#endif /*GLX_MESA_swap_control*/
+
+
+#ifndef GLX_MESA_swap_control
+
+typedef int (*PFNGLXSWAPINTERVALMESAPROC)(int);
+
+#endif /*GLX_MESA_swap_control*/
+
+
 #ifndef GLX_SGI_swap_control
 
 // Function signature for GLX_SGI_swap_control
@@ -282,6 +296,8 @@
     Cursor        cursor;            // Invisible cursor for hidden cursor
 
     // GLX extensions
+    PFNGLXSWAPINTERVALEXTPROC             SwapIntervalEXT;
+    PFNGLXSWAPINTERVALMESAPROC            SwapIntervalMESA;
     PFNGLXSWAPINTERVALSGIPROC             SwapIntervalSGI;
     PFNGLXGETFBCONFIGATTRIBSGIXPROC       GetFBConfigAttribSGIX;
     PFNGLXCHOOSEFBCONFIGSGIXPROC          ChooseFBConfigSGIX;
@@ -289,6 +305,8 @@
     PFNGLXGETVISUALFROMFBCONFIGSGIXPROC   GetVisualFromFBConfigSGIX;
     PFNGLXCREATECONTEXTATTRIBSARBPROC     CreateContextAttribsARB;
     GLboolean   has_GLX_SGIX_fbconfig;
+    GLboolean   has_GLX_EXT_swap_control;
+    GLboolean   has_GLX_MESA_swap_control;
     GLboolean   has_GLX_SGI_swap_control;
     GLboolean   has_GLX_ARB_multisample;
     GLboolean   has_GLX_ARB_create_context;
@@ -375,8 +393,11 @@
 
     Display        *display;
 
-    // Server-side GLX version
-    int             glxMajor, glxMinor;
+    struct {
+        int         versionMajor, versionMinor;
+        int         eventBase;
+        int         errorBase;
+    } GLX;
 
     struct {
         int         available;
diff --git a/glfw/lib/x11/x11_init.c b/glfw/lib/x11/x11_init.c
--- a/glfw/lib/x11/x11_init.c
+++ b/glfw/lib/x11/x11_init.c
@@ -177,7 +177,9 @@
 
     // Fullscreen & screen saver settings
     // Check if GLX is supported on this display
-    if( !glXQueryExtension( _glfwLibrary.display, NULL, NULL ) )
+    if( !glXQueryExtension( _glfwLibrary.display,
+                            &_glfwLibrary.GLX.errorBase,
+                            &_glfwLibrary.GLX.eventBase))
     {
         fprintf(stderr, "GLX not supported\n");
         return GL_FALSE;
@@ -185,8 +187,8 @@
 
     // Retrieve GLX version
     if( !glXQueryVersion( _glfwLibrary.display,
-                          &_glfwLibrary.glxMajor,
-                          &_glfwLibrary.glxMinor ) )
+                          &_glfwLibrary.GLX.versionMajor,
+                          &_glfwLibrary.GLX.versionMinor ) )
     {
         fprintf(stderr, "Unable to query GLX version\n");
         return GL_FALSE;
diff --git a/glfw/lib/x11/x11_window.c b/glfw/lib/x11/x11_window.c
--- a/glfw/lib/x11/x11_window.c
+++ b/glfw/lib/x11/x11_window.c
@@ -46,7 +46,18 @@
 #define _NET_WM_STATE_ADD           1
 #define _NET_WM_STATE_TOGGLE        2
 
+#ifndef GLXBadProfileARB
+ #define GLXBadProfileARB 13
+#endif
 
+
+//========================================================================
+// The X error code as provided to the X error handler
+//========================================================================
+
+static unsigned long _glfwErrorCode = Success;
+
+
 //************************************************************************
 //****                  GLFW internal functions                       ****
 //************************************************************************
@@ -58,6 +69,7 @@
 
 static int errorHandler( Display *display, XErrorEvent *event )
 {
+    _glfwErrorCode = event->error_code;
     return 0;
 }
 
@@ -428,10 +440,11 @@
     GLXFBConfig *fbconfigs;
     _GLFWfbconfig *result;
     int i, count = 0;
+    GLboolean trustWindowBit = GL_TRUE;
 
     *found = 0;
 
-    if( _glfwLibrary.glxMajor == 1 && _glfwLibrary.glxMinor < 3 )
+    if( _glfwLibrary.GLX.versionMajor == 1 && _glfwLibrary.GLX.versionMinor < 3 )
     {
         if( !_glfwWin.has_GLX_SGIX_fbconfig )
         {
@@ -440,6 +453,14 @@
         }
     }
 
+    if( strcmp( glXGetClientString( _glfwLibrary.display, GLX_VENDOR ),
+                "Chromium" ) == 0 )
+    {
+        // This is a (hopefully temporary) workaround for Chromium (VirtualBox
+        // GL) not setting the window bit on any GLXFBConfigs
+        trustWindowBit = GL_FALSE;
+    }
+
     if( _glfwWin.has_GLX_SGIX_fbconfig )
     {
         fbconfigs = _glfwWin.ChooseFBConfigSGIX( _glfwLibrary.display,
@@ -486,8 +507,11 @@
 
         if( !( getFBConfigAttrib( fbconfigs[i], GLX_DRAWABLE_TYPE ) & GLX_WINDOW_BIT ) )
         {
-            // Only consider window GLXFBConfigs
-            continue;
+            if( trustWindowBit )
+            {
+                // Only consider window GLXFBConfigs
+                continue;
+            }
         }
 
         result[*found].redBits = getFBConfigAttrib( fbconfigs[i], GLX_RED_SIZE );
@@ -527,6 +551,31 @@
 
 
 //========================================================================
+// Create the OpenGL context using the legacy interface
+//========================================================================
+
+static GLXContext createLegacyContext( GLXFBConfig fbconfig )
+{
+    if( _glfwWin.has_GLX_SGIX_fbconfig )
+    {
+        return _glfwWin.CreateContextWithConfigSGIX( _glfwLibrary.display,
+                                                     fbconfig,
+                                                     GLX_RGBA_TYPE,
+                                                     NULL,
+                                                     True );
+    }
+    else
+    {
+        return glXCreateNewContext( _glfwLibrary.display,
+                                    fbconfig,
+                                    GLX_RGBA_TYPE,
+                                    NULL,
+                                    True );
+    }
+}
+
+
+//========================================================================
 // Create the OpenGL context
 //========================================================================
 
@@ -654,25 +703,28 @@
 
         // We are done, so unset the error handler again (see above)
         XSetErrorHandler( NULL );
+
+        if( _glfwWin.context == NULL )
+        {
+            // HACK: This is a fallback for the broken Mesa implementation of
+            // GLX_ARB_create_context_profile, which fails default 1.0 context
+            // creation with a GLXBadProfileARB error in violation of the spec
+            if( _glfwErrorCode == _glfwLibrary.GLX.errorBase + GLXBadProfileARB &&
+                wndconfig->glProfile == 0 &&
+                wndconfig->glForward == GL_FALSE )
+            {
+                _glfwWin.context = createLegacyContext( *fbconfig );
+            }
+        }
+
+        // Copy the debug context hint as there's no way of verifying it
+        // This is the only code path capable of creating a debug context,
+        // so leave it as false (from the earlier memset) otherwise
+        _glfwWin.glDebug = wndconfig->glDebug;
     }
     else
     {
-        if( _glfwWin.has_GLX_SGIX_fbconfig )
-        {
-            _glfwWin.context = _glfwWin.CreateContextWithConfigSGIX( _glfwLibrary.display,
-                                                                     *fbconfig,
-                                                                     GLX_RGBA_TYPE,
-                                                                     NULL,
-                                                                     True );
-        }
-        else
-        {
-            _glfwWin.context = glXCreateNewContext( _glfwLibrary.display,
-                                                    *fbconfig,
-                                                    GLX_RGBA_TYPE,
-                                                    NULL,
-                                                    True );
-        }
+        _glfwWin.context = createLegacyContext( *fbconfig );
     }
 
     XFree( fbconfig );
@@ -698,6 +750,8 @@
 static void initGLXExtensions( void )
 {
     // This needs to include every function pointer loaded below
+    _glfwWin.SwapIntervalEXT             = NULL;
+    _glfwWin.SwapIntervalMESA            = NULL;
     _glfwWin.SwapIntervalSGI             = NULL;
     _glfwWin.GetFBConfigAttribSGIX       = NULL;
     _glfwWin.ChooseFBConfigSGIX          = NULL;
@@ -707,11 +761,35 @@
 
     // This needs to include every extension used below
     _glfwWin.has_GLX_SGIX_fbconfig              = GL_FALSE;
+    _glfwWin.has_GLX_EXT_swap_control           = GL_FALSE;
+    _glfwWin.has_GLX_MESA_swap_control          = GL_FALSE;
     _glfwWin.has_GLX_SGI_swap_control           = GL_FALSE;
     _glfwWin.has_GLX_ARB_multisample            = GL_FALSE;
     _glfwWin.has_GLX_ARB_create_context         = GL_FALSE;
     _glfwWin.has_GLX_ARB_create_context_profile = GL_FALSE;
 
+    if( _glfwPlatformExtensionSupported( "GLX_EXT_swap_control" ) )
+    {
+        _glfwWin.SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)
+            _glfwPlatformGetProcAddress( "glXSwapIntervalEXT" );
+
+        if( _glfwWin.SwapIntervalEXT )
+        {
+            _glfwWin.has_GLX_EXT_swap_control = GL_TRUE;
+        }
+    }
+
+    if( _glfwPlatformExtensionSupported( "GLX_MESA_swap_control" ) )
+    {
+        _glfwWin.SwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC)
+            _glfwPlatformGetProcAddress( "glXSwapIntervalMESA" );
+
+        if( _glfwWin.SwapIntervalMESA )
+        {
+            _glfwWin.has_GLX_MESA_swap_control = GL_TRUE;
+        }
+    }
+
     if( _glfwPlatformExtensionSupported( "GLX_SGI_swap_control" ) )
     {
         _glfwWin.SwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)
@@ -1521,6 +1599,8 @@
         XFreeCursor( _glfwLibrary.display, _glfwWin.cursor );
         _glfwWin.cursor = (Cursor) 0;
     }
+
+    XFlush( _glfwLibrary.display );
 }
 
 
@@ -1543,7 +1623,6 @@
 void _glfwPlatformSetWindowSize( int width, int height )
 {
     int     mode = 0, rate, sizeChanged = GL_FALSE;
-    XSizeHints *sizehints;
 
     rate = _glfwWin.refreshRate;
 
@@ -1557,14 +1636,14 @@
     {
         // Update window size restrictions to match new window size
 
-        sizehints = XAllocSizeHints();
-        sizehints->flags = 0;
+        XSizeHints *hints = XAllocSizeHints();
 
-        sizehints->min_width  = sizehints->max_width  = width;
-        sizehints->min_height = sizehints->max_height = height;
+        hints->flags |= (PMinSize | PMaxSize);
+        hints->min_width  = hints->max_width  = width;
+        hints->min_height = hints->max_height = height;
 
-        XSetWMNormalHints( _glfwLibrary.display, _glfwWin.window, sizehints );
-        XFree( sizehints );
+        XSetWMNormalHints( _glfwLibrary.display, _glfwWin.window, hints );
+        XFree( hints );
     }
 
     // Change window size before changing fullscreen mode?
@@ -1649,10 +1728,23 @@
 
 void _glfwPlatformSwapInterval( int interval )
 {
-    if( _glfwWin.has_GLX_SGI_swap_control )
+    if( _glfwWin.has_GLX_EXT_swap_control )
     {
-        _glfwWin.SwapIntervalSGI( interval );
+        _glfwWin.SwapIntervalEXT( _glfwLibrary.display,
+                                  _glfwWin.window,
+                                  interval );
     }
+    else if( _glfwWin.has_GLX_MESA_swap_control )
+    {
+        _glfwWin.SwapIntervalMESA( interval );
+    }
+    else if( _glfwWin.has_GLX_SGI_swap_control )
+    {
+        if( interval > 0 )
+        {
+            _glfwWin.SwapIntervalSGI( interval );
+        }
+    }
 }
 
 
@@ -1838,6 +1930,9 @@
             _glfwWin.pointerGrabbed = GL_TRUE;
         }
     }
+
+    // Move cursor to the middle of the window
+    _glfwPlatformSetMouseCursorPos( _glfwWin.width / 2, _glfwWin.height / 2 );
 }
 
 
