diff --git a/Bindings/GLFW.hsc b/Bindings/GLFW.hsc
--- a/Bindings/GLFW.hsc
+++ b/Bindings/GLFW.hsc
@@ -7,6 +7,7 @@
 
 #include <bindings.dsl.h>
 #include <GLFW/glfw3.h>
+
 #ifdef ExposeNative
   #warning "You are compiling glfw using the native access functions. BEWARE."
 
@@ -22,8 +23,16 @@
 
   #elif defined(__linux__)
 
-    #define GLFW_EXPOSE_NATIVE_X11
-    #define GLFW_EXPOSE_NATIVE_GLX
+    #if defined(BINDINGS_GLFW_USE_X11)
+      #define GLFW_EXPOSE_NATIVE_X11
+      #define GLFW_EXPOSE_NATIVE_GLX
+    #elif defined(BINDINGS_GLFW_USE_WAYLAND)
+      #define GLFW_EXPOSE_NATIVE_WAYLAND
+      #define GLFW_EXPOSE_NATIVE_EGL
+    #elif defined(BINDINGS_GLFW_USE_MIR)
+      #define GLFW_EXPOSE_NATIVE_MIR
+      #define GLFW_EXPOSE_NATIVE_EGL
+    #endif
 
   #endif
 
@@ -36,19 +45,19 @@
 module Bindings.GLFW where
 
 import Prelude (Eq, IO, Num, Show)
-import Prelude (($), return)
+import Prelude (($), return, error, (++))
 
 import Data.Data        (Data)
+import Data.Int         (Int32)
+import Data.Word        (Word32, Word64)
 import Data.Typeable    (Typeable)
 import Foreign.C.Types  (CChar, CUChar, CUShort)
-import Foreign.C.Types  (CDouble(..), CFloat(..), CInt(..), CUInt(..))
-import Foreign.Ptr      (FunPtr, Ptr, plusPtr)
+import Foreign.C.Types  (CDouble(..), CFloat(..), CInt(..), CUInt(..), CULong(..))
+import Foreign.C.String (CString)
+import Foreign.Ptr      (FunPtr, nullFunPtr, Ptr, plusPtr)
 import Foreign.Storable (Storable(..))
 --------------------------------------------------------------------------------
 
-#num GL_FALSE
-#num GL_TRUE
-
 #num GLFW_VERSION_MAJOR
 #num GLFW_VERSION_MINOR
 #num GLFW_VERSION_REVISION
@@ -406,6 +415,14 @@
 #num GLFW_HAND_CURSOR
 #num GLFW_HRESIZE_CURSOR
 #num GLFW_VRESIZE_CURSOR
+#num GLFW_DONT_CARE
+#num GLFW_DOUBLEBUFFER
+#num GLFW_AUTO_ICONIFY
+#num GLFW_FLOATING
+#num GLFW_CONTEXT_RELEASE_BEHAVIOR
+#num GLFW_ANY_RELEASE_BEHAVIOR
+#num GLFW_RELEASE_BEHAVIOR_FLUSH
+#num GLFW_RELEASE_BEHAVIOR_NONE
 
 #starttype GLFWimage
 #field width  , CInt
@@ -418,9 +435,288 @@
 deriving instance Data     C'GLFWcursor
 
 #callback GLFWdropfun , Ptr <GLFWwindow> -> CInt -> Ptr (Ptr CChar) -> IO ()
+#callback GLFWcharmodsfun , Ptr <GLFWwindow> -> CUInt -> CInt -> IO ()
 
 #ccall glfwCreateCursor , Ptr <GLFWimage> -> CInt -> CInt -> IO (Ptr <GLFWcursor>)
 #ccall glfwCreateStandardCursor , CInt -> IO (Ptr <GLFWcursor>)
 #ccall glfwSetCursor , Ptr <GLFWwindow> -> Ptr <GLFWcursor> -> IO ()
 #ccall glfwDestroyCursor , Ptr <GLFWcursor> -> IO ()
 #ccall glfwSetDropCallback , Ptr <GLFWwindow> -> <GLFWdropfun> -> IO <GLFWdropfun>
+#ccall glfwSetCharModsCallback , Ptr <GLFWwindow> -> <GLFWcharmodsfun> -> IO <GLFWcharmodsfun>
+#ccall glfwGetWindowFrameSize , Ptr <GLFWwindow> -> Ptr CInt -> Ptr CInt -> Ptr CInt -> Ptr CInt -> IO ()
+
+--------------------------------------------------------------------------------
+-- GLFW 3.2 additions
+--------------------------------------------------------------------------------
+
+#num GLFW_NO_API
+#num GLFW_CONTEXT_CREATION_API
+#num GLFW_NATIVE_CONTEXT_API
+#num GLFW_EGL_CONTEXT_API
+#num GLFW_CONTEXT_NO_ERROR
+#num GLFW_TRUE
+#num GLFW_FALSE
+#num GLFW_MAXIMIZED
+
+#ccall glfwFocusWindow , Ptr <GLFWwindow> -> IO ()
+#ccall glfwMaximizeWindow , Ptr <GLFWwindow> -> IO ()
+#ccall glfwSetWindowMonitor , Ptr <GLFWwindow> -> Ptr <GLFWmonitor> -> CInt -> CInt -> CInt -> CInt -> CInt -> IO ()
+#ccall glfwSetWindowIcon , Ptr <GLFWwindow> -> CInt -> Ptr <GLFWimage> -> IO ()
+#ccall glfwWaitEventsTimeout , CDouble -> IO ()
+#ccall glfwSetWindowSizeLimits , Ptr <GLFWwindow> -> CInt -> CInt -> CInt -> CInt -> IO ()
+#ccall glfwSetWindowAspectRatio , Ptr <GLFWwindow> -> CInt -> CInt -> IO ()
+#ccall glfwGetKeyName , CInt -> CInt -> IO CString
+#ccall glfwGetTimerValue , IO (CULong)
+#ccall glfwGetTimerFrequency , IO (CULong)
+
+#callback GLFWjoystickfun , CInt -> CInt -> IO ()
+#ccall glfwSetJoystickCallback , <GLFWjoystickfun> -> IO <GLFWjoystickfun>
+
+#ccall glfwVulkanSupported , IO CInt
+#ccall glfwGetRequiredInstanceExtensions , Ptr Word32 -> IO (Ptr CString)
+
+-- GLFW prevents the declaration of some of the Vulkan functions in its header
+-- glfw3.h if it cannot find the required Vulkan headers. As of now (4/2018),
+-- these functions are still *defined* in vulkan.c, which is built regardless of
+-- whether or not the Vulkan headers were found. Internally, the required types
+-- are defined locally in order to make the build work, and h2c will still link
+-- against them without a problem. Whether or not you have a valid Vulkan
+-- implementation might not be clear though. Nothing is preventing the glfw3
+-- authors from hiding the Vulkan functions without valid headers, which could
+-- cause some pain in the future, so use the following functions with caution.
+-- See commit @521d161af85047 for a way to deal with this more annoyingly.
+#ccall glfwGetInstanceProcAddress               , Ptr vkInstance -> CString -> IO (FunPtr vkProc)
+#ccall glfwGetPhysicalDevicePresentationSupport , Ptr vkInstance -> Ptr vkPhysicalDevice -> Word32 -> IO CInt
+#ccall glfwCreateWindowSurface                  , Ptr vkInstance -> Ptr <GLFWwindow> -> Ptr vkAllocationCallbacks -> Ptr vkSurfaceKHR -> IO Int32
+
+
+--------------------------------------------------------------------------------
+-- Native APIs
+--------------------------------------------------------------------------------
+
+#if defined(GLFW_EXPOSE_NATIVE_WIN32)
+#ccall glfwGetWin32Adapter , Ptr <GLFWwindow> -> IO CString
+#ccall glfwGetWin32Monitor , Ptr <GLFWwindow> -> IO (Ptr ())
+#ccall glfwGetWin32Window  , Ptr <GLFWwindow> -> IO (Ptr ())
+#else
+
+p'glfwGetWin32Adapter :: FunPtr (Ptr C'GLFWwindow -> IO CString)
+p'glfwGetWin32Adapter = nullFunPtr
+
+c'glfwGetWin32Adapter :: Ptr C'GLFWwindow -> IO CString
+c'glfwGetWin32Adapter =
+  error $ "c'glfwGetWin32Adapter undefined! -- "
+       ++ "Did you use the wrong glfw3native API?"
+
+p'glfwGetWin32Monitor :: FunPtr (Ptr C'GLFWwindow -> IO (Ptr ()))
+p'glfwGetWin32Monitor = nullFunPtr
+
+c'glfwGetWin32Monitor :: Ptr C'GLFWwindow -> IO (Ptr ())
+c'glfwGetWin32Monitor =
+  error $ "c'glfwGetWin32Monitor undefined! -- "
+       ++ "Did you use the wrong glfw3native API?"
+
+p'glfwGetWin32Window :: FunPtr (Ptr C'GLFWwindow -> IO (Ptr ()))
+p'glfwGetWin32Window = nullFunPtr
+
+c'glfwGetWin32Window ::  Ptr C'GLFWwindow -> IO (Ptr ())
+c'glfwGetWin32Window =
+  error $ "c'glfwGetWin32Window undefined! -- "
+       ++ "Did you use the wrong glfw3native API?"
+#endif
+
+#if defined(GLFW_EXPOSE_NATIVE_WGL)
+#ccall glfwGetWGLContext , Ptr <GLFWwindow> -> IO (Ptr ())
+#else
+p'glfwGetWGLContext :: FunPtr (Ptr C'GLFWwindow -> IO (Ptr ()))
+p'glfwGetWGLContext = nullFunPtr
+
+c'glfwGetWGLContext :: Ptr C'GLFWwindow -> IO (Ptr ())
+c'glfwGetWGLContext =
+  error $ "c'glfwGetWGLContext undefined! -- "
+       ++ "Did you use the wrong glfw3native API?"
+#endif
+
+#if defined(GLFW_EXPOSE_NATIVE_COCOA)
+#ccall glfwGetCocoaMonitor , Ptr <GLFWwindow> -> IO (Ptr Word32)
+#ccall glfwGetCocoaWindow , Ptr <GLFWwindow> -> IO (Ptr ())
+#else
+p'glfwGetCocoaMonitor :: FunPtr (Ptr C'GLFWwindow -> IO (Ptr Word32))
+p'glfwGetCocoaMonitor = nullFunPtr
+
+c'glfwGetCocoaMonitor :: Ptr C'GLFWwindow -> IO (Ptr Word32)
+c'glfwGetCocoaMonitor =
+  error $ "c'glfwGetCocoaMonitor undefined! -- "
+       ++ "Did you use the wrong glfw3native API?"
+
+p'glfwGetCocoaWindow :: FunPtr (Ptr C'GLFWwindow -> IO (Ptr ()))
+p'glfwGetCocoaWindow = nullFunPtr
+
+c'glfwGetCocoaWindow :: Ptr C'GLFWwindow -> IO (Ptr ())
+c'glfwGetCocoaWindow =
+  error $ "c'glfwGetCocoaWindow undefined! -- "
+       ++ "Did you use the wrong glfw3native API?"
+#endif
+
+#if defined(GLFW_EXPOSE_NATIVE_NSGL)
+#ccall glfwGetNSGLContext , Ptr <GLFWwindow> -> IO (Ptr ())
+#else
+p'glfwGetNSGLContext :: FunPtr (Ptr C'GLFWwindow -> IO (Ptr ()))
+p'glfwGetNSGLContext = nullFunPtr
+
+c'glfwGetNSGLContext :: Ptr C'GLFWwindow -> IO (Ptr ())
+c'glfwGetNSGLContext =
+  error $ "c'glfwGetNSGLContext undefined! -- "
+       ++ "Did you use the wrong glfw3native API?"
+#endif
+
+#if defined(GLFW_EXPOSE_NATIVE_X11)
+#ccall glfwGetX11Display , Ptr <GLFWwindow> -> IO (Ptr display)
+#ccall glfwGetX11Adapter , Ptr <GLFWwindow> -> IO Word64
+#ccall glfwGetX11Monitor , Ptr <GLFWwindow> -> IO Word64
+#ccall glfwGetX11Window  , Ptr <GLFWwindow> -> IO Word64
+#else
+p'glfwGetX11Display :: FunPtr (Ptr C'GLFWwindow -> IO (Ptr display))
+p'glfwGetX11Display = nullFunPtr
+
+c'glfwGetX11Display :: Ptr C'GLFWwindow -> IO (Ptr display)
+c'glfwGetX11Display =
+  error $ "c'glfwGetX11Display undefined! -- "
+       ++ "Did you use the wrong glfw3native API?"
+
+p'glfwGetX11Adapter :: FunPtr (Ptr C'GLFWwindow -> IO Word64)
+p'glfwGetX11Adapter = nullFunPtr
+
+c'glfwGetX11Adapter :: Ptr C'GLFWwindow -> IO Word64
+c'glfwGetX11Adapter =
+  error $ "c'glfwGetX11Adapter undefined! -- "
+       ++ "Did you use the wrong glfw3native API?"
+
+p'glfwGetX11Monitor :: FunPtr (Ptr C'GLFWwindow -> IO Word64)
+p'glfwGetX11Monitor = nullFunPtr
+
+c'glfwGetX11Monitor :: Ptr C'GLFWwindow -> IO Word64
+c'glfwGetX11Monitor =
+  error $ "c'glfwGetX11Monitor undefined! -- "
+       ++ "Did you use the wrong glfw3native API?"
+
+p'glfwGetX11Window :: FunPtr (Ptr C'GLFWwindow -> IO Word64)
+p'glfwGetX11Window = nullFunPtr
+
+c'glfwGetX11Window ::  Ptr C'GLFWwindow -> IO Word64
+c'glfwGetX11Window =
+  error $ "c'glfwGetX11Window undefined! -- "
+       ++ "Did you use the wrong glfw3native API?"
+#endif
+
+#if defined(GLFW_EXPOSE_NATIVE_GLX)
+#ccall glfwGetGLXContext , Ptr <GLFWwindow> -> IO (Ptr ())
+#ccall glfwGetGLXWindow  , Ptr <GLFWwindow> -> IO Word64
+#else
+p'glfwGetGLXContext :: FunPtr (Ptr C'GLFWwindow -> IO (Ptr ()))
+p'glfwGetGLXContext = nullFunPtr
+
+c'glfwGetGLXContext :: Ptr C'GLFWwindow -> IO (Ptr ())
+c'glfwGetGLXContext =
+  error $ "c'glfwGetGLXContext undefined! -- "
+       ++ "Did you use the wrong glfw3native API?"
+
+p'glfwGetGLXWindow :: FunPtr (Ptr C'GLFWwindow -> IO Word64)
+p'glfwGetGLXWindow = nullFunPtr
+
+c'glfwGetGLXWindow ::  Ptr C'GLFWwindow -> IO Word64
+c'glfwGetGLXWindow =
+  error $ "c'glfwGetGLXWindow undefined! -- "
+       ++ "Did you use the wrong glfw3native API?"
+#endif
+
+#if defined(GLFW_EXPOSE_NATIVE_WAYLAND)
+#ccall glfwGetWaylandDisplay , IO (Ptr wl_display)
+#ccall glfwGetWaylandMonitor , Ptr <GLFWwindow> -> IO (Ptr wl_output)
+#ccall glfwGetWaylandWindow , Ptr <GLFWwindow> -> IO (Ptr wl_surface)
+#else
+p'glfwGetWaylandDisplay :: FunPtr (IO (Ptr wl_display))
+p'glfwGetWaylandDisplay = nullFunPtr
+
+c'glfwGetWaylandDisplay :: IO (Ptr wl_display)
+c'glfwGetWaylandDisplay =
+  error $ "c'glfwGetWaylandDisplay undefined! -- "
+       ++ "Did you use the wrong glfw3native API?"
+
+p'glfwGetWaylandMonitor :: FunPtr (Ptr C'GLFWwindow -> IO (Ptr wl_output))
+p'glfwGetWaylandMonitor = nullFunPtr
+
+c'glfwGetWaylandMonitor :: Ptr C'GLFWwindow -> IO (Ptr wl_output)
+c'glfwGetWaylandMonitor =
+  error $ "c'glfwGetWaylandMonitor undefined! -- "
+       ++ "Did you use the wrong glfw3native API?"
+
+p'glfwGetWaylandWindow :: FunPtr (Ptr C'GLFWwindow -> IO (Ptr wl_surface))
+p'glfwGetWaylandWindow = nullFunPtr
+
+c'glfwGetWaylandWindow :: Ptr C'GLFWwindow -> IO (Ptr wl_surface)
+c'glfwGetWaylandWindow =
+  error $ "c'glfwGetWaylandWindow undefined! -- "
+       ++ "Did you use the wrong glfw3native API?"
+#endif
+
+#if defined(GLFW_EXPOSE_NATIVE_MIR)
+#ccall glfwGetMirDisplay , IO (Ptr mir_connection)
+#ccall glfwGetMirMonitor , Ptr <GLFWwindow> -> IO CInt
+#ccall glfwGetMirWindow , Ptr <GLFWwindow> -> IO (Ptr mir_surface)
+#else
+p'glfwGetMirDisplay :: FunPtr (IO (Ptr mir_connection))
+p'glfwGetMirDisplay = nullFunPtr
+
+c'glfwGetMirDisplay :: IO (Ptr mir_connection)
+c'glfwGetMirDisplay =
+  error $ "c'glfwGetMirDisplay undefined! -- "
+       ++ "Did you use the wrong glfw3native API?"
+
+p'glfwGetMirMonitor :: FunPtr (Ptr C'GLFWwindow -> IO CInt)
+p'glfwGetMirMonitor = nullFunPtr
+
+c'glfwGetMirMonitor :: Ptr C'GLFWwindow -> IO CInt
+c'glfwGetMirMonitor =
+  error $ "c'glfwGetMirMonitor undefined! -- "
+       ++ "Did you use the wrong glfw3native API?"
+
+p'glfwGetMirWindow :: FunPtr (Ptr C'GLFWwindow -> IO (Ptr mir_surface))
+p'glfwGetMirWindow = nullFunPtr
+
+c'glfwGetMirWindow :: Ptr C'GLFWwindow -> IO (Ptr mir_surface)
+c'glfwGetMirWindow =
+  error $ "c'glfwGetMirWindow undefined! -- "
+       ++ "Did you use the wrong glfw3native API?"
+#endif
+
+#if defined(GLFW_EXPOSE_NATIVE_EGL)
+#ccall glfwGetEGLDisplay , IO (Ptr ())
+#ccall glfwGetEGLContext , Ptr <GLFWwindow> -> IO (Ptr ())
+#ccall glfwGetEGLSurface , Ptr <GLFWwindow> -> IO (Ptr ())
+#else
+p'glfwGetEGLDisplay :: FunPtr (IO (Ptr ()))
+p'glfwGetEGLDisplay = nullFunPtr
+
+c'glfwGetEGLDisplay :: IO (Ptr ())
+c'glfwGetEGLDisplay =
+  error $ "c'glfwGetEGLDisplay undefined! -- "
+       ++ "Did you use the wrong glfw3native API?"
+
+p'glfwGetEGLContext :: FunPtr (Ptr C'GLFWwindow -> IO (Ptr ()))
+p'glfwGetEGLContext = nullFunPtr
+
+c'glfwGetEGLContext :: Ptr C'GLFWwindow -> IO (Ptr ())
+c'glfwGetEGLContext =
+  error $ "c'glfwGetEGLContext undefined! -- "
+       ++ "Did you use the wrong glfw3native API?"
+
+p'glfwGetEGLSurface :: FunPtr (Ptr C'GLFWwindow -> IO (Ptr ()))
+p'glfwGetEGLSurface = nullFunPtr
+
+c'glfwGetEGLSurface :: Ptr C'GLFWwindow -> IO (Ptr ())
+c'glfwGetEGLSurface =
+  error $ "c'glfwGetEGLSurface undefined! -- "
+       ++ "Did you use the wrong glfw3native API?"
+
+#endif
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -9,30 +9,20 @@
 library for creating windows with OpenGL contexts and managing input and
 events.
 
-The binding is to [GLFW 3.1 released 2015-01-18][3].
+The binding is to [GLFW 3.2.1 released 2016-08-18][3].
 
-*These bindings are too low-level for normal use.* For higher-level GLFW
-bindings, see [GLFW-b][4].
+*These bindings are a lot lower level than intended for normal use.*
+For higher-level GLFW bindings, see [GLFW-b][4].
 
 ## Contributing
 
-This package uses git-flow as development model, in short that means that:
-
-1. New features should be added to "develop" branch.
-2. "master" branch is reserved for stable releases.
-3. Patches for bugs related with previous releases should always be done in
-    "hotfixes" branch.
-4. All merge commits to master from "hotfixes" should be done
-    using the "--no-ff" flag and from "develop" should avoid merging commits.
-
-Until we have a defined road-map we are going to leave out "release
-"branches" and "feature branches". For more information about this development
-model please refer to [this site.][5]
+1. To add a new feature or fix a bug, please start a new branch with a
+   meaningful name (not "feature").
+2. "master" branch is reserved as the current up-to-date working tree.
 
-Thanks you, and happy coding.
+Thank you, and happy coding.
 
 [1]: http://www.haskell.org/
 [2]: http://www.glfw.org/
-[3]: http://www.glfw.org/Version-3.1-released.html
+[3]: http://www.glfw.org/Version-3.2.1-released.html
 [4]: https://github.com/bsl/GLFW-b
-[5]: http://nvie.com/posts/a-successful-git-branching-model/
diff --git a/Test.hs b/Test.hs
--- a/Test.hs
+++ b/Test.hs
@@ -4,13 +4,14 @@
 import Data.Char             (isAscii)
 import Data.List             (intercalate, isPrefixOf)
 import Foreign.C.String      (peekCString, withCString)
+import Foreign.C.Types       (CDouble(..))
 import Foreign.Marshal.Alloc (alloca)
 import Foreign.Marshal.Array (peekArray)
-import Foreign.Ptr           (Ptr, nullPtr)
+import Foreign.Ptr           (Ptr, nullPtr, nullFunPtr)
 import Foreign.Storable      (Storable(..))
 
 -- HUnit
-import Test.HUnit ((@?=), assertBool, assertFailure)
+import Test.HUnit ((@?=), (@?), assertBool, assertFailure)
 
 -- test-framework
 import Test.Framework (Test, defaultMain, testGroup)
@@ -39,11 +40,19 @@
 
     p'mon <- c'glfwGetPrimaryMonitor
 
-    c'glfwWindowHint c'GLFW_VISIBLE c'GL_FALSE
+    c'glfwWindowHint c'GLFW_VISIBLE c'GLFW_FALSE
     p'win <- withCString "bindings-GLFW test" $ \p'title ->
       c'glfwCreateWindow 100 100 p'title nullPtr nullPtr
     c'glfwMakeContextCurrent p'win
 
+    -- Mostly check for compiling
+    cmcb <- mk'GLFWcharmodsfun $ \win x y ->
+        putStrLn $ "Got char mods callback! " ++ show (win, x, y)
+    _ <- c'glfwSetCharModsCallback p'win cmcb
+    jcb <- mk'GLFWjoystickfun $ \x y ->
+        putStrLn $ "Got joystick callback! " ++ show (x, y)
+    _ <- c'glfwSetJoystickCallback jcb
+
     defaultMain $ tests p'mon p'win
 
     -- TODO because of how defaultMain works, this code is not reached
@@ -54,7 +63,7 @@
 
 versionMajor, versionMinor, versionRevision :: Int
 versionMajor    = 3
-versionMinor    = 1
+versionMinor    = 2
 versionRevision = 1
 
 giveItTime :: IO ()
@@ -114,30 +123,43 @@
       -- , testCase "gamma ramp"                 $ test_glfwGamma_ramp p'mon
       ]
     , testGroup "Window handling"
-      [ testCase "glfwDefaultWindowHints"   test_glfwDefaultWindowHints
-      , testCase "window close flag"      $ test_window_close_flag p'win
-      , testCase "glfwSetWindowTitle"     $ test_glfwSetWindowTitle p'win
-      , testCase "window pos"             $ test_window_pos p'win
-      , testCase "window size"            $ test_window_size p'win
-      , testCase "glfwGetFramebufferSize" $ test_glfwGetFramebufferSize p'win
-      , testCase "iconification"          $ test_iconification p'win
-      -- , testCase "show/hide"              $ test_show_hide p'win
-      , testCase "glfwGetWindowMonitor"   $ test_glfwGetWindowMonitor p'win p'mon
-      , testCase "cursor pos"             $ test_cursor_pos p'win
-      , testCase "glfwGetWindowAttrib"    $ test_glfwGetWindowAttrib p'win
-      , testCase "glfwPollEvents"           test_glfwPollEvents
-      , testCase "glfwWaitEvents"           test_glfwWaitEvents
+      [ testCase "glfwDefaultWindowHints"       test_glfwDefaultWindowHints
+      , testCase "glfwGetWindowAttrib"        $ test_glfwGetWindowAttrib p'win
+      , testCase "window close flag"          $ test_window_close_flag p'win
+      , testCase "glfwSetWindowTitle"         $ test_glfwSetWindowTitle p'win
+      , testCase "window pos"                 $ test_window_pos p'win
+      , testCase "window size"                $ test_window_size p'win
+      , testCase "glfwGetWindowFrameSize"     $ test_glfwGetWindowFrameSize p'win
+      , testCase "glfwGetFramebufferSize"     $ test_glfwGetFramebufferSize p'win
+      , testCase "iconification"              $ test_iconification p'win
+      -- , testCase "show/hide"                  $ test_show_hide p'win
+      , testCase "glfwGetWindowMonitor"       $ test_glfwGetWindowMonitor p'win p'mon
+      , testCase "glfwSetWindowMonitor"       $ test_glfwSetWindowMonitor p'win p'mon
+      , testCase "glfwSetWindowIcon"          $ test_glfwSetWindowIcon p'win
+      , testCase "glfwMaximizeWindow"         $ test_glfwMaximizeWindow p'win
+      , testCase "glfwSetWindowSizeLimits"    $ test_glfwSetWindowSizeLimits p'win
+      , testCase "glfwSetWindowAspectRatio"   $ test_glfwSetWindowAspectRatio p'win
+      , testCase "glfwFocusWindow"            $ test_glfwFocusWindow p'win
+      , testCase "cursor pos"                 $ test_cursor_pos p'win
+      , testCase "glfwPollEvents"               test_glfwPollEvents
+      , testCase "glfwWaitEvents"               test_glfwWaitEvents
+      , testCase "glfwWaitEventsTimeout"        test_glfwWaitEventsTimeout
       ]
     , testGroup "Input handling"
       [ testCase "glfwJoystickPresent"    test_glfwJoystickPresent
       , testCase "glfwGetJoystickAxes"    test_glfwGetJoystickAxes
       , testCase "glfwGetJoystickButtons" test_glfwGetJoystickButtons
       , testCase "glfwGetJoystickName"    test_glfwGetJoystickName
+      , testCase "glfwGetKeyName"         test_glfwGetKeyName
       ]
     , testGroup "Time"
       [ testCase "glfwGetTime" test_glfwGetTime
       , testCase "glfwSetTime" test_glfwSetTime
       ]
+    , testGroup "Timers"
+      [ testCase "glfwGetTimerValue"         test_glfwGetTimerValue
+      , testCase "glfwSetTimerFrequency"     test_glfwGetTimerFrequency
+      ]
     , testGroup "Context"
       [ testCase "glfwGetCurrentContext"  $ test_glfwGetCurrentContext p'win
       , testCase "glfwSwapBuffers"        $ test_glfwSwapBuffers p'win
@@ -147,6 +169,13 @@
     , testGroup "Clipboard"
       [ testCase "clipboard" $ test_clipboard p'win
       ]
+    , testGroup "Vulkan"
+      [ testCase "glfwVulkanSupported"                          test_glfwVulkanSupported
+      , testCase "glfwGetRequiredInstanceExtensions"            test_glfwGetRequiredInstanceExtensions
+      , testCase "glfwGetInstanceProcAddress"                   test_glfwGetInstanceProcAddress
+      , testCase "glfwGetPhysicalDevicePresentationSupport"     test_glfwGetPhysicalDevicePresentationSupport
+      , testCase "glfwCreateWindowSurface"                    $ test_glfwCreateWindowSurface p'win
+      ]
     ]
 
 --------------------------------------------------------------------------------
@@ -275,15 +304,15 @@
 test_window_close_flag :: Ptr C'GLFWwindow -> IO ()
 test_window_close_flag p'win = do
     r0 <- c'glfwWindowShouldClose p'win
-    r0 @?= c'GL_FALSE
+    r0 @?= c'GLFW_FALSE
 
-    c'glfwSetWindowShouldClose p'win c'GL_TRUE
+    c'glfwSetWindowShouldClose p'win c'GLFW_TRUE
     r1 <- c'glfwWindowShouldClose p'win
-    r1 @?= c'GL_TRUE
+    r1 @?= c'GLFW_TRUE
 
-    c'glfwSetWindowShouldClose p'win c'GL_FALSE
+    c'glfwSetWindowShouldClose p'win c'GLFW_FALSE
     r2 <- c'glfwWindowShouldClose p'win
-    r2 @?= c'GL_FALSE
+    r2 @?= c'GLFW_FALSE
 
 test_glfwSetWindowTitle :: Ptr C'GLFWwindow -> IO ()
 test_glfwSetWindowTitle p'win =
@@ -309,6 +338,7 @@
     setGet :: Int -> Int -> IO (Int, Int, Int, Int)
     setGet x0 y0 = do
         c'glfwSetWindowPos p'win (fromIntegral x0) (fromIntegral y0)
+        c'glfwSwapBuffers p'win
         giveItTime
         alloca $ \p'x1 ->
           alloca $ \p'y1 -> do
@@ -320,8 +350,8 @@
 
 test_window_size :: Ptr C'GLFWwindow -> IO ()
 test_window_size p'win = do
-    let w = 17
-        h = 37
+    let w = 177
+        h = 372
     c'glfwSetWindowSize p'win w h
     giveItTime
     alloca $ \p'w' ->
@@ -332,6 +362,15 @@
           w' @?= w
           h' @?= h
 
+-- Really all we can say here is that we likely have a title bar, so just check
+-- that the 'frame' around the top edge is > 0.
+test_glfwGetWindowFrameSize :: Ptr C'GLFWwindow -> IO ()
+test_glfwGetWindowFrameSize p'win =
+    alloca $ \p'win_frame_top -> do
+        c'glfwGetWindowFrameSize p'win nullPtr p'win_frame_top nullPtr nullPtr
+        top <- peek p'win_frame_top
+        assertBool "Window has no frame width up top!" $ top > 0
+
 test_glfwGetFramebufferSize :: Ptr C'GLFWwindow -> IO ()
 test_glfwGetFramebufferSize p'win =
     alloca $ \p'w  ->
@@ -344,88 +383,146 @@
         h  <- peek p'h
         fw <- peek p'fw
         fh <- peek p'fh
-        fw @?= w
-        fh @?= h
+        ((fw `mod` w) == 0) @? "Framebuffer width multiple of window's"
+        ((fh `mod` h) == 0) @? "Framebuffer height multiple of window's"
 
 test_iconification :: Ptr C'GLFWwindow -> IO ()
 test_iconification p'win = do
+    c'glfwShowWindow p'win
     r0 <- c'glfwGetWindowAttrib p'win c'GLFW_ICONIFIED
-    r0 @?= c'GL_FALSE
+    r0 @?= c'GLFW_FALSE
 
     c'glfwIconifyWindow p'win
     giveItTime
 
     r1 <- c'glfwGetWindowAttrib p'win c'GLFW_ICONIFIED
-    r1 @?= c'GL_TRUE
+    r1 @?= c'GLFW_TRUE
 
     c'glfwRestoreWindow p'win
+    c'glfwHideWindow p'win
 
 -- test_show_hide :: Ptr C'GLFWwindow -> IO ()
 -- test_show_hide p'win = do
 --     v0 <- c'glfwGetWindowAttrib p'win c'GLFW_VISIBLE
---     v0 @?= c'GL_FALSE
+--     v0 @?= c'GLFW_FALSE
 
 --     c'glfwShowWindow p'win
 --     giveItTime
 --     v1 <- c'glfwGetWindowAttrib p'win c'GLFW_VISIBLE
---     v1 @?= c'GL_TRUE
+--     v1 @?= c'GLFW_TRUE
 
 --     c'glfwHideWindow p'win
 --     giveItTime
 --     v2 <- c'glfwGetWindowAttrib p'win c'GLFW_VISIBLE
---     v2 @?= c'GL_FALSE
+--     v2 @?= c'GLFW_FALSE
 
 test_glfwGetWindowMonitor :: Ptr C'GLFWwindow -> Ptr C'GLFWmonitor -> IO ()
 test_glfwGetWindowMonitor p'win _ = do
     p'mon <- c'glfwGetWindowMonitor p'win
     p'mon @?= nullPtr
 
+test_glfwSetWindowMonitor :: Ptr C'GLFWwindow -> Ptr C'GLFWmonitor -> IO ()
+test_glfwSetWindowMonitor p'win _ = do
+    c'glfwSetWindowMonitor p'win nullPtr 0 0 100 100 60
+
+test_glfwSetWindowIcon :: Ptr C'GLFWwindow -> IO ()
+test_glfwSetWindowIcon p'win = do
+    c'glfwSetWindowIcon p'win 0 nullPtr
+
+test_glfwSetWindowSizeLimits :: Ptr C'GLFWwindow -> IO ()
+test_glfwSetWindowSizeLimits p'win = do
+    c'glfwSetWindowSizeLimits p'win 640 480 1024 768
+
+test_glfwSetWindowAspectRatio :: Ptr C'GLFWwindow -> IO ()
+test_glfwSetWindowAspectRatio p'win = do
+    c'glfwSetWindowAspectRatio p'win c'GLFW_DONT_CARE c'GLFW_DONT_CARE
+
+test_glfwFocusWindow :: Ptr C'GLFWwindow -> IO ()
+test_glfwFocusWindow = c'glfwFocusWindow
+
+-- NOTE: This test seems to fail in X11. This might be due to the asynchronous
+-- nature of focus events in X. We may be able to fix it by waiting for the focus
+-- event before setting the cursor position.
 test_cursor_pos :: Ptr C'GLFWwindow -> IO ()
 test_cursor_pos p'win =
     alloca $ \p'w   ->
     alloca $ \p'h   ->
     alloca $ \p'cx' ->
     alloca $ \p'cy' -> do
+        c'glfwShowWindow p'win
         c'glfwGetWindowSize p'win p'w p'h
         w <- peek p'w
         h <- peek p'h
-        let cx = fromIntegral w / 2
-            cy = fromIntegral h / 2
+
+        -- Make sure we use integral coordinates here so that we don't run into
+        -- platform-dependent differences.
+        let cx :: CDouble
+            cy :: CDouble
+            (cx, cy) = (fromIntegral $ w `div` 2, fromIntegral $ h `div` 2)
+
+        -- !HACK! Poll events seems to be necessary on OS X,
+        -- before /and/ after glfwSetCursorPos, otherwise, the
+        -- windowing system likely never receives the cursor update. This is
+        -- reflected in the C version of GLFW as well, we just call it here in
+        -- order to have a more robust test.
+
+        c'glfwPollEvents
+
         c'glfwSetCursorPos p'win cx cy
-        giveItTime
+
+        c'glfwPollEvents -- !HACK! see comment above
+
         c'glfwGetCursorPos p'win p'cx' p'cy'
         cx' <- peek p'cx'
         cy' <- peek p'cy'
         cx' @?= cx
         cy' @?= cy
+        c'glfwHideWindow p'win
 
 test_glfwGetWindowAttrib :: Ptr C'GLFWwindow -> IO ()
 test_glfwGetWindowAttrib p'win = do
     let pairs =
-          [ ( c'GLFW_FOCUSED,    c'GL_FALSE        )
-          , ( c'GLFW_ICONIFIED,  c'GL_FALSE        )
-          , ( c'GLFW_RESIZABLE,  c'GL_TRUE         )
-          , ( c'GLFW_DECORATED,  c'GL_TRUE         )
+          [ ( c'GLFW_FOCUSED,    c'GLFW_FALSE        )
+          , ( c'GLFW_ICONIFIED,  c'GLFW_FALSE        )
+          , ( c'GLFW_RESIZABLE,  c'GLFW_TRUE         )
+          , ( c'GLFW_DECORATED,  c'GLFW_TRUE         )
           , ( c'GLFW_CLIENT_API, c'GLFW_OPENGL_API )
           ]
     rs <- mapM (c'glfwGetWindowAttrib p'win . fst) pairs
     rs @?= map snd pairs
 
+test_glfwMaximizeWindow :: Ptr C'GLFWwindow -> IO ()
+test_glfwMaximizeWindow p'win = do
+    c'glfwShowWindow p'win
+    startsMaximized <- c'glfwGetWindowAttrib p'win c'GLFW_MAXIMIZED
+    startsMaximized @?= c'GLFW_FALSE
+
+    c'glfwMaximizeWindow p'win
+    giveItTime
+
+    isMaximized <- c'glfwGetWindowAttrib p'win c'GLFW_MAXIMIZED
+    isMaximized @?= c'GLFW_TRUE
+    c'glfwHideWindow p'win
+
 test_glfwPollEvents :: IO ()
 test_glfwPollEvents =
     c'glfwPollEvents
 
 test_glfwWaitEvents :: IO ()
-test_glfwWaitEvents =
-    c'glfwWaitEvents
+test_glfwWaitEvents = c'glfwPostEmptyEvent >> c'glfwWaitEvents
 
+test_glfwWaitEventsTimeout :: IO ()
+test_glfwWaitEventsTimeout =
+    -- to not slow down the test too much we set the timeout to 0.001 second :
+    c'glfwWaitEventsTimeout 0.001
+
 --------------------------------------------------------------------------------
 
 test_glfwJoystickPresent :: IO ()
 test_glfwJoystickPresent = do
     _ <- c'glfwJoystickPresent c'GLFW_JOYSTICK_1
     r <- c'glfwJoystickPresent c'GLFW_JOYSTICK_16
-    r @?= c'GL_FALSE
+    r @?= c'GLFW_FALSE
 
 test_glfwGetJoystickAxes :: IO ()
 test_glfwGetJoystickAxes =
@@ -461,6 +558,14 @@
             name <- peekCString p'name
             assertBool "" $ not $ null name
 
+test_glfwGetKeyName :: IO ()
+test_glfwGetKeyName =
+    forM_ [c'GLFW_KEY_SLASH, c'GLFW_KEY_PERIOD] $ \k -> do
+        p'name <- c'glfwGetKeyName k 0
+        when (p'name /= nullPtr) $ do
+            name <- peekCString p'name
+            assertBool "" $ not $ null name
+
 --------------------------------------------------------------------------------
 
 test_glfwGetTime :: IO ()
@@ -477,6 +582,18 @@
 
 --------------------------------------------------------------------------------
 
+test_glfwGetTimerValue :: IO ()
+test_glfwGetTimerValue = do
+    val <- c'glfwGetTimerValue
+    assertBool "" $ val > 0
+
+test_glfwGetTimerFrequency :: IO ()
+test_glfwGetTimerFrequency = do
+    freq <- c'glfwGetTimerFrequency
+    assertBool "" $ freq > 0
+
+--------------------------------------------------------------------------------
+
 test_glfwGetCurrentContext :: Ptr C'GLFWwindow -> IO ()
 test_glfwGetCurrentContext p'win = do
     p'win' <- c'glfwGetCurrentContext
@@ -493,8 +610,8 @@
 test_glfwExtensionSupported :: IO ()
 test_glfwExtensionSupported = do
     let pairs =
-          [ ( "GL_ARB_multisample", c'GL_TRUE  )
-          , ( "bogus",              c'GL_FALSE )
+          [ ( "GL_ARB_multisample", c'GLFW_TRUE  )
+          , ( "bogus",              c'GLFW_FALSE )
           ]
     rs <- forM (map fst pairs) $ \ext ->
       withCString ext c'glfwExtensionSupported
@@ -514,11 +631,67 @@
     setGet s = do
         withCString s $ \p's ->
           c'glfwSetClipboardString p'win p's
+        threadDelay 100000  -- Give it a little time
         p's' <- c'glfwGetClipboardString p'win
         if p's' == nullPtr
           then return ""
           else peekCString p's'
 
 --------------------------------------------------------------------------------
+
+test_glfwVulkanSupported :: IO ()
+test_glfwVulkanSupported =
+    -- Just test that it doesn't error. If it does, then we have a problem, but
+    -- some platforms (like OS X) don't actually support vulkan.
+    c'glfwVulkanSupported >> return ()
+
+test_glfwGetRequiredInstanceExtensions :: IO ()
+test_glfwGetRequiredInstanceExtensions = do
+    support <- c'glfwVulkanSupported
+    if (support == 1)
+        then alloca $ \p'count ->
+            c'glfwGetRequiredInstanceExtensions p'count >> return ()
+        else return ()
+
+test_glfwGetInstanceProcAddress :: IO ()
+test_glfwGetInstanceProcAddress = do
+    support <- c'glfwVulkanSupported
+    if support == 1
+    then do
+        shouldBeNull <- withCString "notafunction" $
+                        \s -> c'glfwGetInstanceProcAddress nullPtr s
+        shouldBeNull @?= nullFunPtr
+        assertBool "Function pointer is defined!" $
+          p'glfwGetInstanceProcAddress /= nullFunPtr
+    else return ()
+
+test_glfwGetPhysicalDevicePresentationSupport :: IO ()
+test_glfwGetPhysicalDevicePresentationSupport = do
+    -- We don't really have the proper types to test this function
+    support <- c'glfwVulkanSupported
+    if support == 1
+    then do
+        shouldBeFalse <-
+          c'glfwGetPhysicalDevicePresentationSupport nullPtr nullPtr 0
+        shouldBeFalse @?= c'GLFW_FALSE
+        assertBool "Function pointer is defined!" $
+          p'glfwGetPhysicalDevicePresentationSupport /= nullFunPtr
+    else return ()
+
+test_glfwCreateWindowSurface :: Ptr C'GLFWwindow -> IO ()
+test_glfwCreateWindowSurface p'win = do
+    -- We don't really have the proper types to test this function
+    support <- c'glfwVulkanSupported
+    if support == 1
+    then do
+        alloca $ \p'surface -> do
+          let resPtr = p'surface :: Ptr ()
+          shouldNotBeSuccessful <-
+            c'glfwCreateWindowSurface nullPtr p'win nullPtr resPtr
+          assertBool "c'glfwCreateSurface was successful??" $
+            shouldNotBeSuccessful /= 0
+        assertBool "Function pointer is defined!" $
+          p'glfwCreateWindowSurface /= nullFunPtr
+    else return ()
 
 {-# ANN module "HLint: ignore Use camelCase" #-}
diff --git a/bindings-GLFW.cabal b/bindings-GLFW.cabal
--- a/bindings-GLFW.cabal
+++ b/bindings-GLFW.cabal
@@ -1,5 +1,5 @@
 name:         bindings-GLFW
-version:      3.1.2.4
+version:      3.2.1.0
 category:     Graphics
 
 author:       Brian Lewis <brian@lorf.org>
@@ -126,6 +126,7 @@
       glfw/src/input.c
       glfw/src/monitor.c
       glfw/src/window.c
+      glfw/src/vulkan.c
 
     cc-options: -D_GLFW_USE_CONFIG_H
 
@@ -133,25 +134,27 @@
       include-dirs:
         glfw/include/os/unix-like
       c-sources:
+        glfw/src/glx_context.c
+        glfw/src/egl_context.c
         glfw/src/xkb_unicode.c
         glfw/src/linux_joystick.c
         glfw/src/posix_time.c
         glfw/src/posix_tls.c
       if flag(X)
+        cc-options: -DBINDINGS_GLFW_USE_X11
         c-sources:
-          glfw/src/glx_context.c
           glfw/src/x11_init.c
           glfw/src/x11_monitor.c
           glfw/src/x11_window.c
       if flag(Wayland)
+        cc-options: -DBINDINGS_GLFW_USE_WAYLAND
         c-sources:
-          glfw/src/egl_context.c
           glfw/src/wl_init.c
           glfw/src/wl_monitor.c
           glfw/src/wl_window.c
       if flag(Mir)
+        cc-options: -DBINDINGS_GLFW_USE_MIR
         c-sources:
-          glfw/src/egl_context.c
           glfw/src/mir_init.c
           glfw/src/mir_monitor.c
           glfw/src/mir_window.c
@@ -170,10 +173,10 @@
       include-dirs:
          glfw/include/os/darwin
       c-sources:
-         glfw/src/mach_time.c
+         glfw/src/cocoa_time.c
          glfw/src/posix_tls.c
          glfw/src/cocoa_init.m
-         glfw/src/iokit_joystick.m
+         glfw/src/cocoa_joystick.m
          glfw/src/cocoa_monitor.m
          glfw/src/cocoa_window.m
          glfw/src/nsgl_context.m
@@ -189,8 +192,9 @@
       include-dirs:
         glfw/include/os/windows
       c-sources:
+        glfw/src/egl_context.c
         glfw/src/win32_init.c
-        glfw/src/winmm_joystick.c
+        glfw/src/win32_joystick.c
         glfw/src/win32_monitor.c
         glfw/src/win32_time.c
         glfw/src/win32_window.c
@@ -202,7 +206,6 @@
 
   if flag(ExposeNative)
     cc-options: -DExposeNative
-
 --------------------------------------------------------------------------------
 
 test-suite main
diff --git a/glfw/include/GLFW/glfw3.h b/glfw/include/GLFW/glfw3.h
--- a/glfw/include/GLFW/glfw3.h
+++ b/glfw/include/GLFW/glfw3.h
@@ -1,3335 +1,4224 @@
 /*************************************************************************
- * GLFW 3.1 - www.glfw.org
- * A library for OpenGL, window and input
- *------------------------------------------------------------------------
- * Copyright (c) 2002-2006 Marcus Geelnard
- * Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
- *
- * 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.
- *
- *************************************************************************/
-
-#ifndef _glfw3_h_
-#define _glfw3_h_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/*************************************************************************
- * Doxygen documentation
- *************************************************************************/
-
-/*! @defgroup context Context handling
- *
- *  This is the reference documentation for context related functions.  For more
- *  information, see the @ref context.
- */
-/*! @defgroup init Initialization, version and errors
- *
- *  This is the reference documentation for initialization and termination of
- *  the library, version management and error handling.  For more information,
- *  see the @ref intro.
- */
-/*! @defgroup input Input handling
- *
- *  This is the reference documentation for input related functions and types.
- *  For more information, see the @ref input.
- */
-/*! @defgroup monitor Monitor handling
- *
- *  This is the reference documentation for monitor related functions and types.
- *  For more information, see the @ref monitor.
- */
-/*! @defgroup window Window handling
- *
- *  This is the reference documentation for window related functions and types,
- *  including creation, deletion and event polling.  For more information, see
- *  the @ref window.
- */
-
-
-/*************************************************************************
- * Global definitions
- *************************************************************************/
-
-/* ------------------- BEGIN SYSTEM/COMPILER SPECIFIC -------------------- */
-
-/* Please report any problems that you find with your compiler, which may
- * be solved in this section! There are several compilers that I have not
- * been able to test this file with yet.
- *
- * First: If we are we on Windows, we want a single define for it (_WIN32)
- * (Note: For Cygwin the compiler flag -mwin32 should be used, but to
- * make sure that things run smoothly for Cygwin users, we add __CYGWIN__
- * to the list of "valid Win32 identifiers", which removes the need for
- * -mwin32)
- */
-#if !defined(_WIN32) && (defined(__WIN32__) || defined(WIN32) || defined(__CYGWIN__))
- #define _WIN32
-#endif /* _WIN32 */
-
-/* In order for extension support to be portable, we need to define an
- * OpenGL function call method. We use the keyword APIENTRY, which is
- * defined for Win32. (Note: Windows also needs this for <GL/gl.h>)
- */
-#ifndef APIENTRY
- #ifdef _WIN32
-  #define APIENTRY __stdcall
- #else
-  #define APIENTRY
- #endif
-#endif /* APIENTRY */
-
-/* The following three defines are here solely to make some Windows-based
- * <GL/gl.h> files happy. Theoretically we could include <windows.h>, but
- * it has the major drawback of severely polluting our namespace.
- */
-
-/* Under Windows, we need WINGDIAPI defined */
-#if !defined(WINGDIAPI) && defined(_WIN32)
- #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__POCC__)
-  /* Microsoft Visual C++, Borland C++ Builder and Pelles C */
-  #define WINGDIAPI __declspec(dllimport)
- #elif defined(__LCC__)
-  /* LCC-Win32 */
-  #define WINGDIAPI __stdcall
- #else
-  /* Others (e.g. MinGW, Cygwin) */
-  #define WINGDIAPI extern
- #endif
- #define GLFW_WINGDIAPI_DEFINED
-#endif /* WINGDIAPI */
-
-/* Some <GL/glu.h> files also need CALLBACK defined */
-#if !defined(CALLBACK) && defined(_WIN32)
- #if defined(_MSC_VER)
-  /* Microsoft Visual C++ */
-  #if (defined(_M_MRX000) || defined(_M_IX86) || defined(_M_ALPHA) || defined(_M_PPC)) && !defined(MIDL_PASS)
-   #define CALLBACK __stdcall
-  #else
-   #define CALLBACK
-  #endif
- #else
-  /* Other Windows compilers */
-  #define CALLBACK __stdcall
- #endif
- #define GLFW_CALLBACK_DEFINED
-#endif /* CALLBACK */
-
-/* Most GL/glu.h variants on Windows need wchar_t
- * OpenGL/gl.h blocks the definition of ptrdiff_t by glext.h on OS X */
-#if !defined(GLFW_INCLUDE_NONE)
- #include <stddef.h>
-#endif
-
-/* Include the chosen client API headers.
- */
-#if defined(__APPLE_CC__)
- #if defined(GLFW_INCLUDE_GLCOREARB)
-  #include <OpenGL/gl3.h>
-  #if defined(GLFW_INCLUDE_GLEXT)
-   #include <OpenGL/gl3ext.h>
-  #endif
- #elif !defined(GLFW_INCLUDE_NONE)
-  #if !defined(GLFW_INCLUDE_GLEXT)
-   #define GL_GLEXT_LEGACY
-  #endif
-  #include <OpenGL/gl.h>
- #endif
- #if defined(GLFW_INCLUDE_GLU)
-  #include <OpenGL/glu.h>
- #endif
-#else
- #if defined(GLFW_INCLUDE_GLCOREARB)
-  #include <GL/glcorearb.h>
- #elif defined(GLFW_INCLUDE_ES1)
-  #include <GLES/gl.h>
-  #if defined(GLFW_INCLUDE_GLEXT)
-   #include <GLES/glext.h>
-  #endif
- #elif defined(GLFW_INCLUDE_ES2)
-  #include <GLES2/gl2.h>
-  #if defined(GLFW_INCLUDE_GLEXT)
-   #include <GLES2/gl2ext.h>
-  #endif
- #elif defined(GLFW_INCLUDE_ES3)
-  #include <GLES3/gl3.h>
-  #if defined(GLFW_INCLUDE_GLEXT)
-   #include <GLES3/gl2ext.h>
-  #endif
- #elif defined(GLFW_INCLUDE_ES31)
-  #include <GLES3/gl31.h>
-  #if defined(GLFW_INCLUDE_GLEXT)
-   #include <GLES3/gl2ext.h>
-  #endif
- #elif !defined(GLFW_INCLUDE_NONE)
-  #include <GL/gl.h>
-  #if defined(GLFW_INCLUDE_GLEXT)
-   #include <GL/glext.h>
-  #endif
- #endif
- #if defined(GLFW_INCLUDE_GLU)
-  #include <GL/glu.h>
- #endif
-#endif
-
-#if defined(GLFW_DLL) && defined(_GLFW_BUILD_DLL)
- /* GLFW_DLL must be defined by applications that are linking against the DLL
-  * version of the GLFW library.  _GLFW_BUILD_DLL is defined by the GLFW
-  * configuration header when compiling the DLL version of the library.
-  */
- #error "You must not have both GLFW_DLL and _GLFW_BUILD_DLL defined"
-#endif
-
-/* GLFWAPI is used to declare public API functions for export
- * from the DLL / shared library / dynamic library.
- */
-#if defined(_WIN32) && defined(_GLFW_BUILD_DLL)
- /* We are building GLFW as a Win32 DLL */
- #define GLFWAPI __declspec(dllexport)
-#elif defined(_WIN32) && defined(GLFW_DLL)
- /* We are calling GLFW as a Win32 DLL */
- #if defined(__LCC__)
-  #define GLFWAPI extern
- #else
-  #define GLFWAPI __declspec(dllimport)
- #endif
-#elif defined(__GNUC__) && defined(_GLFW_BUILD_DLL)
- /* We are building GLFW as a shared / dynamic library */
- #define GLFWAPI __attribute__((visibility("default")))
-#else
- /* We are building or calling GLFW as a static library */
- #define GLFWAPI
-#endif
-
-/* -------------------- END SYSTEM/COMPILER SPECIFIC --------------------- */
-
-
-/*************************************************************************
- * GLFW API tokens
- *************************************************************************/
-
-/*! @name GLFW version macros
- *  @{ */
-/*! @brief The major version number of the GLFW library.
- *
- *  This is incremented when the API is changed in non-compatible ways.
- *  @ingroup init
- */
-#define GLFW_VERSION_MAJOR          3
-/*! @brief The minor version number of the GLFW library.
- *
- *  This is incremented when features are added to the API but it remains
- *  backward-compatible.
- *  @ingroup init
- */
-#define GLFW_VERSION_MINOR          1
-/*! @brief The revision number of the GLFW library.
- *
- *  This is incremented when a bug fix release is made that does not contain any
- *  API changes.
- *  @ingroup init
- */
-#define GLFW_VERSION_REVISION       1
-/*! @} */
-
-/*! @name Key and button actions
- *  @{ */
-/*! @brief The key or mouse button was released.
- *
- *  The key or mouse button was released.
- *
- *  @ingroup input
- */
-#define GLFW_RELEASE                0
-/*! @brief The key or mouse button was pressed.
- *
- *  The key or mouse button was pressed.
- *
- *  @ingroup input
- */
-#define GLFW_PRESS                  1
-/*! @brief The key was held down until it repeated.
- *
- *  The key was held down until it repeated.
- *
- *  @ingroup input
- */
-#define GLFW_REPEAT                 2
-/*! @} */
-
-/*! @defgroup keys Keyboard keys
- *
- *  See [key input](@ref input_key) for how these are used.
- *
- *  These key codes are inspired by the _USB HID Usage Tables v1.12_ (p. 53-60),
- *  but re-arranged to map to 7-bit ASCII for printable keys (function keys are
- *  put in the 256+ range).
- *
- *  The naming of the key codes follow these rules:
- *   - The US keyboard layout is used
- *   - Names of printable alpha-numeric characters are used (e.g. "A", "R",
- *     "3", etc.)
- *   - For non-alphanumeric characters, Unicode:ish names are used (e.g.
- *     "COMMA", "LEFT_SQUARE_BRACKET", etc.). Note that some names do not
- *     correspond to the Unicode standard (usually for brevity)
- *   - Keys that lack a clear US mapping are named "WORLD_x"
- *   - For non-printable keys, custom names are used (e.g. "F4",
- *     "BACKSPACE", etc.)
- *
- *  @ingroup input
- *  @{
- */
-
-/* The unknown key */
-#define GLFW_KEY_UNKNOWN            -1
-
-/* Printable keys */
-#define GLFW_KEY_SPACE              32
-#define GLFW_KEY_APOSTROPHE         39  /* ' */
-#define GLFW_KEY_COMMA              44  /* , */
-#define GLFW_KEY_MINUS              45  /* - */
-#define GLFW_KEY_PERIOD             46  /* . */
-#define GLFW_KEY_SLASH              47  /* / */
-#define GLFW_KEY_0                  48
-#define GLFW_KEY_1                  49
-#define GLFW_KEY_2                  50
-#define GLFW_KEY_3                  51
-#define GLFW_KEY_4                  52
-#define GLFW_KEY_5                  53
-#define GLFW_KEY_6                  54
-#define GLFW_KEY_7                  55
-#define GLFW_KEY_8                  56
-#define GLFW_KEY_9                  57
-#define GLFW_KEY_SEMICOLON          59  /* ; */
-#define GLFW_KEY_EQUAL              61  /* = */
-#define GLFW_KEY_A                  65
-#define GLFW_KEY_B                  66
-#define GLFW_KEY_C                  67
-#define GLFW_KEY_D                  68
-#define GLFW_KEY_E                  69
-#define GLFW_KEY_F                  70
-#define GLFW_KEY_G                  71
-#define GLFW_KEY_H                  72
-#define GLFW_KEY_I                  73
-#define GLFW_KEY_J                  74
-#define GLFW_KEY_K                  75
-#define GLFW_KEY_L                  76
-#define GLFW_KEY_M                  77
-#define GLFW_KEY_N                  78
-#define GLFW_KEY_O                  79
-#define GLFW_KEY_P                  80
-#define GLFW_KEY_Q                  81
-#define GLFW_KEY_R                  82
-#define GLFW_KEY_S                  83
-#define GLFW_KEY_T                  84
-#define GLFW_KEY_U                  85
-#define GLFW_KEY_V                  86
-#define GLFW_KEY_W                  87
-#define GLFW_KEY_X                  88
-#define GLFW_KEY_Y                  89
-#define GLFW_KEY_Z                  90
-#define GLFW_KEY_LEFT_BRACKET       91  /* [ */
-#define GLFW_KEY_BACKSLASH          92  /* \ */
-#define GLFW_KEY_RIGHT_BRACKET      93  /* ] */
-#define GLFW_KEY_GRAVE_ACCENT       96  /* ` */
-#define GLFW_KEY_WORLD_1            161 /* non-US #1 */
-#define GLFW_KEY_WORLD_2            162 /* non-US #2 */
-
-/* Function keys */
-#define GLFW_KEY_ESCAPE             256
-#define GLFW_KEY_ENTER              257
-#define GLFW_KEY_TAB                258
-#define GLFW_KEY_BACKSPACE          259
-#define GLFW_KEY_INSERT             260
-#define GLFW_KEY_DELETE             261
-#define GLFW_KEY_RIGHT              262
-#define GLFW_KEY_LEFT               263
-#define GLFW_KEY_DOWN               264
-#define GLFW_KEY_UP                 265
-#define GLFW_KEY_PAGE_UP            266
-#define GLFW_KEY_PAGE_DOWN          267
-#define GLFW_KEY_HOME               268
-#define GLFW_KEY_END                269
-#define GLFW_KEY_CAPS_LOCK          280
-#define GLFW_KEY_SCROLL_LOCK        281
-#define GLFW_KEY_NUM_LOCK           282
-#define GLFW_KEY_PRINT_SCREEN       283
-#define GLFW_KEY_PAUSE              284
-#define GLFW_KEY_F1                 290
-#define GLFW_KEY_F2                 291
-#define GLFW_KEY_F3                 292
-#define GLFW_KEY_F4                 293
-#define GLFW_KEY_F5                 294
-#define GLFW_KEY_F6                 295
-#define GLFW_KEY_F7                 296
-#define GLFW_KEY_F8                 297
-#define GLFW_KEY_F9                 298
-#define GLFW_KEY_F10                299
-#define GLFW_KEY_F11                300
-#define GLFW_KEY_F12                301
-#define GLFW_KEY_F13                302
-#define GLFW_KEY_F14                303
-#define GLFW_KEY_F15                304
-#define GLFW_KEY_F16                305
-#define GLFW_KEY_F17                306
-#define GLFW_KEY_F18                307
-#define GLFW_KEY_F19                308
-#define GLFW_KEY_F20                309
-#define GLFW_KEY_F21                310
-#define GLFW_KEY_F22                311
-#define GLFW_KEY_F23                312
-#define GLFW_KEY_F24                313
-#define GLFW_KEY_F25                314
-#define GLFW_KEY_KP_0               320
-#define GLFW_KEY_KP_1               321
-#define GLFW_KEY_KP_2               322
-#define GLFW_KEY_KP_3               323
-#define GLFW_KEY_KP_4               324
-#define GLFW_KEY_KP_5               325
-#define GLFW_KEY_KP_6               326
-#define GLFW_KEY_KP_7               327
-#define GLFW_KEY_KP_8               328
-#define GLFW_KEY_KP_9               329
-#define GLFW_KEY_KP_DECIMAL         330
-#define GLFW_KEY_KP_DIVIDE          331
-#define GLFW_KEY_KP_MULTIPLY        332
-#define GLFW_KEY_KP_SUBTRACT        333
-#define GLFW_KEY_KP_ADD             334
-#define GLFW_KEY_KP_ENTER           335
-#define GLFW_KEY_KP_EQUAL           336
-#define GLFW_KEY_LEFT_SHIFT         340
-#define GLFW_KEY_LEFT_CONTROL       341
-#define GLFW_KEY_LEFT_ALT           342
-#define GLFW_KEY_LEFT_SUPER         343
-#define GLFW_KEY_RIGHT_SHIFT        344
-#define GLFW_KEY_RIGHT_CONTROL      345
-#define GLFW_KEY_RIGHT_ALT          346
-#define GLFW_KEY_RIGHT_SUPER        347
-#define GLFW_KEY_MENU               348
-#define GLFW_KEY_LAST               GLFW_KEY_MENU
-
-/*! @} */
-
-/*! @defgroup mods Modifier key flags
- *
- *  See [key input](@ref input_key) for how these are used.
- *
- *  @ingroup input
- *  @{ */
-
-/*! @brief If this bit is set one or more Shift keys were held down.
- */
-#define GLFW_MOD_SHIFT           0x0001
-/*! @brief If this bit is set one or more Control keys were held down.
- */
-#define GLFW_MOD_CONTROL         0x0002
-/*! @brief If this bit is set one or more Alt keys were held down.
- */
-#define GLFW_MOD_ALT             0x0004
-/*! @brief If this bit is set one or more Super keys were held down.
- */
-#define GLFW_MOD_SUPER           0x0008
-
-/*! @} */
-
-/*! @defgroup buttons Mouse buttons
- *
- *  See [mouse button input](@ref input_mouse_button) for how these are used.
- *
- *  @ingroup input
- *  @{ */
-#define GLFW_MOUSE_BUTTON_1         0
-#define GLFW_MOUSE_BUTTON_2         1
-#define GLFW_MOUSE_BUTTON_3         2
-#define GLFW_MOUSE_BUTTON_4         3
-#define GLFW_MOUSE_BUTTON_5         4
-#define GLFW_MOUSE_BUTTON_6         5
-#define GLFW_MOUSE_BUTTON_7         6
-#define GLFW_MOUSE_BUTTON_8         7
-#define GLFW_MOUSE_BUTTON_LAST      GLFW_MOUSE_BUTTON_8
-#define GLFW_MOUSE_BUTTON_LEFT      GLFW_MOUSE_BUTTON_1
-#define GLFW_MOUSE_BUTTON_RIGHT     GLFW_MOUSE_BUTTON_2
-#define GLFW_MOUSE_BUTTON_MIDDLE    GLFW_MOUSE_BUTTON_3
-/*! @} */
-
-/*! @defgroup joysticks Joysticks
- *
- *  See [joystick input](@ref joystick) for how these are used.
- *
- *  @ingroup input
- *  @{ */
-#define GLFW_JOYSTICK_1             0
-#define GLFW_JOYSTICK_2             1
-#define GLFW_JOYSTICK_3             2
-#define GLFW_JOYSTICK_4             3
-#define GLFW_JOYSTICK_5             4
-#define GLFW_JOYSTICK_6             5
-#define GLFW_JOYSTICK_7             6
-#define GLFW_JOYSTICK_8             7
-#define GLFW_JOYSTICK_9             8
-#define GLFW_JOYSTICK_10            9
-#define GLFW_JOYSTICK_11            10
-#define GLFW_JOYSTICK_12            11
-#define GLFW_JOYSTICK_13            12
-#define GLFW_JOYSTICK_14            13
-#define GLFW_JOYSTICK_15            14
-#define GLFW_JOYSTICK_16            15
-#define GLFW_JOYSTICK_LAST          GLFW_JOYSTICK_16
-/*! @} */
-
-/*! @defgroup errors Error codes
- *
- *  See [error handling](@ref error_handling) for how these are used.
- *
- *  @ingroup init
- *  @{ */
-/*! @brief GLFW has not been initialized.
- *
- *  This occurs if a GLFW function was called that may not be called unless the
- *  library is [initialized](@ref intro_init).
- *
- *  @par Analysis
- *  Application programmer error.  Initialize GLFW before calling any function
- *  that requires initialization.
- */
-#define GLFW_NOT_INITIALIZED        0x00010001
-/*! @brief No context is current for this thread.
- *
- *  This occurs if a GLFW function was called that needs and operates on the
- *  current OpenGL or OpenGL ES context but no context is current on the calling
- *  thread.  One such function is @ref glfwSwapInterval.
- *
- *  @par Analysis
- *  Application programmer error.  Ensure a context is current before calling
- *  functions that require a current context.
- */
-#define GLFW_NO_CURRENT_CONTEXT     0x00010002
-/*! @brief One of the arguments to the function was an invalid enum value.
- *
- *  One of the arguments to the function was an invalid enum value, for example
- *  requesting [GLFW_RED_BITS](@ref window_hints_fb) with @ref
- *  glfwGetWindowAttrib.
- *
- *  @par Analysis
- *  Application programmer error.  Fix the offending call.
- */
-#define GLFW_INVALID_ENUM           0x00010003
-/*! @brief One of the arguments to the function was an invalid value.
- *
- *  One of the arguments to the function was an invalid value, for example
- *  requesting a non-existent OpenGL or OpenGL ES version like 2.7.
- *
- *  Requesting a valid but unavailable OpenGL or OpenGL ES version will instead
- *  result in a @ref GLFW_VERSION_UNAVAILABLE error.
- *
- *  @par Analysis
- *  Application programmer error.  Fix the offending call.
- */
-#define GLFW_INVALID_VALUE          0x00010004
-/*! @brief A memory allocation failed.
- *
- *  A memory allocation failed.
- *
- *  @par Analysis
- *  A bug in GLFW or the underlying operating system.  Report the bug to our
- *  [issue tracker](https://github.com/glfw/glfw/issues).
- */
-#define GLFW_OUT_OF_MEMORY          0x00010005
-/*! @brief GLFW could not find support for the requested client API on the
- *  system.
- *
- *  GLFW could not find support for the requested client API on the system.
- *
- *  @par Analysis
- *  The installed graphics driver does not support the requested client API, or
- *  does not support it via the chosen context creation backend.  Below are
- *  a few examples.
- *
- *  @par
- *  Some pre-installed Windows graphics drivers do not support OpenGL.  AMD only
- *  supports OpenGL ES via EGL, while Nvidia and Intel only supports it via
- *  a WGL or GLX extension.  OS X does not provide OpenGL ES at all.  The Mesa
- *  EGL, OpenGL and OpenGL ES libraries do not interface with the Nvidia binary
- *  driver.
- */
-#define GLFW_API_UNAVAILABLE        0x00010006
-/*! @brief The requested OpenGL or OpenGL ES version is not available.
- *
- *  The requested OpenGL or OpenGL ES version (including any requested profile
- *  or context option) is not available on this machine.
- *
- *  @par Analysis
- *  The machine does not support your requirements.  If your application is
- *  sufficiently flexible, downgrade your requirements and try again.
- *  Otherwise, inform the user that their machine does not match your
- *  requirements.
- *
- *  @par
- *  Future invalid OpenGL and OpenGL ES versions, for example OpenGL 4.8 if 5.0
- *  comes out before the 4.x series gets that far, also fail with this error and
- *  not @ref GLFW_INVALID_VALUE, because GLFW cannot know what future versions
- *  will exist.
- */
-#define GLFW_VERSION_UNAVAILABLE    0x00010007
-/*! @brief A platform-specific error occurred that does not match any of the
- *  more specific categories.
- *
- *  A platform-specific error occurred that does not match any of the more
- *  specific categories.
- *
- *  @par Analysis
- *  A bug in GLFW or the underlying operating system.  Report the bug to our
- *  [issue tracker](https://github.com/glfw/glfw/issues).
- */
-#define GLFW_PLATFORM_ERROR         0x00010008
-/*! @brief The requested format is not supported or available.
- *
- *  If emitted during window creation, the requested pixel format is not
- *  supported.
- *
- *  If emitted when querying the clipboard, the contents of the clipboard could
- *  not be converted to the requested format.
- *
- *  @par Analysis
- *  If emitted during window creation, one or more
- *  [hard constraints](@ref window_hints_hard) did not match any of the
- *  available pixel formats.  If your application is sufficiently flexible,
- *  downgrade your requirements and try again.  Otherwise, inform the user that
- *  their machine does not match your requirements.
- *
- *  @par
- *  If emitted when querying the clipboard, ignore the error or report it to
- *  the user, as appropriate.
- */
-#define GLFW_FORMAT_UNAVAILABLE     0x00010009
-/*! @} */
-
-#define GLFW_FOCUSED                0x00020001
-#define GLFW_ICONIFIED              0x00020002
-#define GLFW_RESIZABLE              0x00020003
-#define GLFW_VISIBLE                0x00020004
-#define GLFW_DECORATED              0x00020005
-#define GLFW_AUTO_ICONIFY           0x00020006
-#define GLFW_FLOATING               0x00020007
-
-#define GLFW_RED_BITS               0x00021001
-#define GLFW_GREEN_BITS             0x00021002
-#define GLFW_BLUE_BITS              0x00021003
-#define GLFW_ALPHA_BITS             0x00021004
-#define GLFW_DEPTH_BITS             0x00021005
-#define GLFW_STENCIL_BITS           0x00021006
-#define GLFW_ACCUM_RED_BITS         0x00021007
-#define GLFW_ACCUM_GREEN_BITS       0x00021008
-#define GLFW_ACCUM_BLUE_BITS        0x00021009
-#define GLFW_ACCUM_ALPHA_BITS       0x0002100A
-#define GLFW_AUX_BUFFERS            0x0002100B
-#define GLFW_STEREO                 0x0002100C
-#define GLFW_SAMPLES                0x0002100D
-#define GLFW_SRGB_CAPABLE           0x0002100E
-#define GLFW_REFRESH_RATE           0x0002100F
-#define GLFW_DOUBLEBUFFER           0x00021010
-
-#define GLFW_CLIENT_API             0x00022001
-#define GLFW_CONTEXT_VERSION_MAJOR  0x00022002
-#define GLFW_CONTEXT_VERSION_MINOR  0x00022003
-#define GLFW_CONTEXT_REVISION       0x00022004
-#define GLFW_CONTEXT_ROBUSTNESS     0x00022005
-#define GLFW_OPENGL_FORWARD_COMPAT  0x00022006
-#define GLFW_OPENGL_DEBUG_CONTEXT   0x00022007
-#define GLFW_OPENGL_PROFILE         0x00022008
-#define GLFW_CONTEXT_RELEASE_BEHAVIOR 0x00022009
-
-#define GLFW_OPENGL_API             0x00030001
-#define GLFW_OPENGL_ES_API          0x00030002
-
-#define GLFW_NO_ROBUSTNESS                   0
-#define GLFW_NO_RESET_NOTIFICATION  0x00031001
-#define GLFW_LOSE_CONTEXT_ON_RESET  0x00031002
-
-#define GLFW_OPENGL_ANY_PROFILE              0
-#define GLFW_OPENGL_CORE_PROFILE    0x00032001
-#define GLFW_OPENGL_COMPAT_PROFILE  0x00032002
-
-#define GLFW_CURSOR                 0x00033001
-#define GLFW_STICKY_KEYS            0x00033002
-#define GLFW_STICKY_MOUSE_BUTTONS   0x00033003
-
-#define GLFW_CURSOR_NORMAL          0x00034001
-#define GLFW_CURSOR_HIDDEN          0x00034002
-#define GLFW_CURSOR_DISABLED        0x00034003
-
-#define GLFW_ANY_RELEASE_BEHAVIOR            0
-#define GLFW_RELEASE_BEHAVIOR_FLUSH 0x00035001
-#define GLFW_RELEASE_BEHAVIOR_NONE  0x00035002
-
-/*! @defgroup shapes Standard cursor shapes
- *
- *  See [standard cursor creation](@ref cursor_standard) for how these are used.
- *
- *  @ingroup input
- *  @{ */
-
-/*! @brief The regular arrow cursor shape.
- *
- *  The regular arrow cursor.
- */
-#define GLFW_ARROW_CURSOR           0x00036001
-/*! @brief The text input I-beam cursor shape.
- *
- *  The text input I-beam cursor shape.
- */
-#define GLFW_IBEAM_CURSOR           0x00036002
-/*! @brief The crosshair shape.
- *
- *  The crosshair shape.
- */
-#define GLFW_CROSSHAIR_CURSOR       0x00036003
-/*! @brief The hand shape.
- *
- *  The hand shape.
- */
-#define GLFW_HAND_CURSOR            0x00036004
-/*! @brief The horizontal resize arrow shape.
- *
- *  The horizontal resize arrow shape.
- */
-#define GLFW_HRESIZE_CURSOR         0x00036005
-/*! @brief The vertical resize arrow shape.
- *
- *  The vertical resize arrow shape.
- */
-#define GLFW_VRESIZE_CURSOR         0x00036006
-/*! @} */
-
-#define GLFW_CONNECTED              0x00040001
-#define GLFW_DISCONNECTED           0x00040002
-
-#define GLFW_DONT_CARE              -1
-
-
-/*************************************************************************
- * GLFW API types
- *************************************************************************/
-
-/*! @brief Client API function pointer type.
- *
- *  Generic function pointer used for returning client API function pointers
- *  without forcing a cast from a regular pointer.
- *
- *  @ingroup context
- */
-typedef void (*GLFWglproc)(void);
-
-/*! @brief Opaque monitor object.
- *
- *  Opaque monitor object.
- *
- *  @ingroup monitor
- */
-typedef struct GLFWmonitor GLFWmonitor;
-
-/*! @brief Opaque window object.
- *
- *  Opaque window object.
- *
- *  @ingroup window
- */
-typedef struct GLFWwindow GLFWwindow;
-
-/*! @brief Opaque cursor object.
- *
- *  Opaque cursor object.
- *
- *  @ingroup cursor
- */
-typedef struct GLFWcursor GLFWcursor;
-
-/*! @brief The function signature for error callbacks.
- *
- *  This is the function signature for error callback functions.
- *
- *  @param[in] error An [error code](@ref errors).
- *  @param[in] description A UTF-8 encoded string describing the error.
- *
- *  @sa glfwSetErrorCallback
- *
- *  @ingroup init
- */
-typedef void (* GLFWerrorfun)(int,const char*);
-
-/*! @brief The function signature for window position callbacks.
- *
- *  This is the function signature for window position callback functions.
- *
- *  @param[in] window The window that was moved.
- *  @param[in] xpos The new x-coordinate, in screen coordinates, of the
- *  upper-left corner of the client area of the window.
- *  @param[in] ypos The new y-coordinate, in screen coordinates, of the
- *  upper-left corner of the client area of the window.
- *
- *  @sa glfwSetWindowPosCallback
- *
- *  @ingroup window
- */
-typedef void (* GLFWwindowposfun)(GLFWwindow*,int,int);
-
-/*! @brief The function signature for window resize callbacks.
- *
- *  This is the function signature for window size callback functions.
- *
- *  @param[in] window The window that was resized.
- *  @param[in] width The new width, in screen coordinates, of the window.
- *  @param[in] height The new height, in screen coordinates, of the window.
- *
- *  @sa glfwSetWindowSizeCallback
- *
- *  @ingroup window
- */
-typedef void (* GLFWwindowsizefun)(GLFWwindow*,int,int);
-
-/*! @brief The function signature for window close callbacks.
- *
- *  This is the function signature for window close callback functions.
- *
- *  @param[in] window The window that the user attempted to close.
- *
- *  @sa glfwSetWindowCloseCallback
- *
- *  @ingroup window
- */
-typedef void (* GLFWwindowclosefun)(GLFWwindow*);
-
-/*! @brief The function signature for window content refresh callbacks.
- *
- *  This is the function signature for window refresh callback functions.
- *
- *  @param[in] window The window whose content needs to be refreshed.
- *
- *  @sa glfwSetWindowRefreshCallback
- *
- *  @ingroup window
- */
-typedef void (* GLFWwindowrefreshfun)(GLFWwindow*);
-
-/*! @brief The function signature for window focus/defocus callbacks.
- *
- *  This is the function signature for window focus callback functions.
- *
- *  @param[in] window The window that gained or lost input focus.
- *  @param[in] focused `GL_TRUE` if the window was given input focus, or
- *  `GL_FALSE` if it lost it.
- *
- *  @sa glfwSetWindowFocusCallback
- *
- *  @ingroup window
- */
-typedef void (* GLFWwindowfocusfun)(GLFWwindow*,int);
-
-/*! @brief The function signature for window iconify/restore callbacks.
- *
- *  This is the function signature for window iconify/restore callback
- *  functions.
- *
- *  @param[in] window The window that was iconified or restored.
- *  @param[in] iconified `GL_TRUE` if the window was iconified, or `GL_FALSE`
- *  if it was restored.
- *
- *  @sa glfwSetWindowIconifyCallback
- *
- *  @ingroup window
- */
-typedef void (* GLFWwindowiconifyfun)(GLFWwindow*,int);
-
-/*! @brief The function signature for framebuffer resize callbacks.
- *
- *  This is the function signature for framebuffer resize callback
- *  functions.
- *
- *  @param[in] window The window whose framebuffer was resized.
- *  @param[in] width The new width, in pixels, of the framebuffer.
- *  @param[in] height The new height, in pixels, of the framebuffer.
- *
- *  @sa glfwSetFramebufferSizeCallback
- *
- *  @ingroup window
- */
-typedef void (* GLFWframebuffersizefun)(GLFWwindow*,int,int);
-
-/*! @brief The function signature for mouse button callbacks.
- *
- *  This is the function signature for mouse button callback functions.
- *
- *  @param[in] window The window that received the event.
- *  @param[in] button The [mouse button](@ref buttons) that was pressed or
- *  released.
- *  @param[in] action One of `GLFW_PRESS` or `GLFW_RELEASE`.
- *  @param[in] mods Bit field describing which [modifier keys](@ref mods) were
- *  held down.
- *
- *  @sa glfwSetMouseButtonCallback
- *
- *  @ingroup input
- */
-typedef void (* GLFWmousebuttonfun)(GLFWwindow*,int,int,int);
-
-/*! @brief The function signature for cursor position callbacks.
- *
- *  This is the function signature for cursor position callback functions.
- *
- *  @param[in] window The window that received the event.
- *  @param[in] xpos The new x-coordinate, in screen coordinates, of the cursor.
- *  @param[in] ypos The new y-coordinate, in screen coordinates, of the cursor.
- *
- *  @sa glfwSetCursorPosCallback
- *
- *  @ingroup input
- */
-typedef void (* GLFWcursorposfun)(GLFWwindow*,double,double);
-
-/*! @brief The function signature for cursor enter/leave callbacks.
- *
- *  This is the function signature for cursor enter/leave callback functions.
- *
- *  @param[in] window The window that received the event.
- *  @param[in] entered `GL_TRUE` if the cursor entered the window's client
- *  area, or `GL_FALSE` if it left it.
- *
- *  @sa glfwSetCursorEnterCallback
- *
- *  @ingroup input
- */
-typedef void (* GLFWcursorenterfun)(GLFWwindow*,int);
-
-/*! @brief The function signature for scroll callbacks.
- *
- *  This is the function signature for scroll callback functions.
- *
- *  @param[in] window The window that received the event.
- *  @param[in] xoffset The scroll offset along the x-axis.
- *  @param[in] yoffset The scroll offset along the y-axis.
- *
- *  @sa glfwSetScrollCallback
- *
- *  @ingroup input
- */
-typedef void (* GLFWscrollfun)(GLFWwindow*,double,double);
-
-/*! @brief The function signature for keyboard key callbacks.
- *
- *  This is the function signature for keyboard key callback functions.
- *
- *  @param[in] window The window that received the event.
- *  @param[in] key The [keyboard key](@ref keys) that was pressed or released.
- *  @param[in] scancode The system-specific scancode of the key.
- *  @param[in] action `GLFW_PRESS`, `GLFW_RELEASE` or `GLFW_REPEAT`.
- *  @param[in] mods Bit field describing which [modifier keys](@ref mods) were
- *  held down.
- *
- *  @sa glfwSetKeyCallback
- *
- *  @ingroup input
- */
-typedef void (* GLFWkeyfun)(GLFWwindow*,int,int,int,int);
-
-/*! @brief The function signature for Unicode character callbacks.
- *
- *  This is the function signature for Unicode character callback functions.
- *
- *  @param[in] window The window that received the event.
- *  @param[in] codepoint The Unicode code point of the character.
- *
- *  @sa glfwSetCharCallback
- *
- *  @ingroup input
- */
-typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int);
-
-/*! @brief The function signature for Unicode character with modifiers
- *  callbacks.
- *
- *  This is the function signature for Unicode character with modifiers callback
- *  functions.  It is called for each input character, regardless of what
- *  modifier keys are held down.
- *
- *  @param[in] window The window that received the event.
- *  @param[in] codepoint The Unicode code point of the character.
- *  @param[in] mods Bit field describing which [modifier keys](@ref mods) were
- *  held down.
- *
- *  @sa glfwSetCharModsCallback
- *
- *  @ingroup input
- */
-typedef void (* GLFWcharmodsfun)(GLFWwindow*,unsigned int,int);
-
-/*! @brief The function signature for file drop callbacks.
- *
- *  This is the function signature for file drop callbacks.
- *
- *  @param[in] window The window that received the event.
- *  @param[in] count The number of dropped files.
- *  @param[in] paths The UTF-8 encoded file and/or directory path names.
- *
- *  @sa glfwSetDropCallback
- *
- *  @ingroup input
- */
-typedef void (* GLFWdropfun)(GLFWwindow*,int,const char**);
-
-/*! @brief The function signature for monitor configuration callbacks.
- *
- *  This is the function signature for monitor configuration callback functions.
- *
- *  @param[in] monitor The monitor that was connected or disconnected.
- *  @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`.
- *
- *  @sa glfwSetMonitorCallback
- *
- *  @ingroup monitor
- */
-typedef void (* GLFWmonitorfun)(GLFWmonitor*,int);
-
-/*! @brief Video mode type.
- *
- *  This describes a single video mode.
- *
- *  @ingroup monitor
- */
-typedef struct GLFWvidmode
-{
-    /*! The width, in screen coordinates, of the video mode.
-     */
-    int width;
-    /*! The height, in screen coordinates, of the video mode.
-     */
-    int height;
-    /*! The bit depth of the red channel of the video mode.
-     */
-    int redBits;
-    /*! The bit depth of the green channel of the video mode.
-     */
-    int greenBits;
-    /*! The bit depth of the blue channel of the video mode.
-     */
-    int blueBits;
-    /*! The refresh rate, in Hz, of the video mode.
-     */
-    int refreshRate;
-} GLFWvidmode;
-
-/*! @brief Gamma ramp.
- *
- *  This describes the gamma ramp for a monitor.
- *
- *  @sa glfwGetGammaRamp glfwSetGammaRamp
- *
- *  @ingroup monitor
- */
-typedef struct GLFWgammaramp
-{
-    /*! An array of value describing the response of the red channel.
-     */
-    unsigned short* red;
-    /*! An array of value describing the response of the green channel.
-     */
-    unsigned short* green;
-    /*! An array of value describing the response of the blue channel.
-     */
-    unsigned short* blue;
-    /*! The number of elements in each array.
-     */
-    unsigned int size;
-} GLFWgammaramp;
-
-/*! @brief Image data.
- */
-typedef struct GLFWimage
-{
-    /*! The width, in pixels, of this image.
-     */
-    int width;
-    /*! The height, in pixels, of this image.
-     */
-    int height;
-    /*! The pixel data of this image, arranged left-to-right, top-to-bottom.
-     */
-    unsigned char* pixels;
-} GLFWimage;
-
-
-/*************************************************************************
- * GLFW API functions
- *************************************************************************/
-
-/*! @brief Initializes the GLFW library.
- *
- *  This function initializes the GLFW library.  Before most GLFW functions can
- *  be used, GLFW must be initialized, and before an application terminates GLFW
- *  should be terminated in order to free any resources allocated during or
- *  after initialization.
- *
- *  If this function fails, it calls @ref glfwTerminate before returning.  If it
- *  succeeds, you should call @ref glfwTerminate before the application exits.
- *
- *  Additional calls to this function after successful initialization but before
- *  termination will return `GL_TRUE` immediately.
- *
- *  @return `GL_TRUE` if successful, or `GL_FALSE` if an
- *  [error](@ref error_handling) occurred.
- *
- *  @remarks __OS X:__ This function will change the current directory of the
- *  application to the `Contents/Resources` subdirectory of the application's
- *  bundle, if present.  This can be disabled with a
- *  [compile-time option](@ref compile_options_osx).
- *
- *  @remarks __X11:__ If the `LC_CTYPE` category of the current locale is set to
- *  `"C"` then the environment's locale will be applied to that category.  This
- *  is done because character input will not function when `LC_CTYPE` is set to
- *  `"C"`.  If another locale was set before this function was called, it will
- *  be left untouched.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref intro_init
- *  @sa glfwTerminate
- *
- *  @since Added in GLFW 1.0.
- *
- *  @ingroup init
- */
-GLFWAPI int glfwInit(void);
-
-/*! @brief Terminates the GLFW library.
- *
- *  This function destroys all remaining windows and cursors, restores any
- *  modified gamma ramps and frees any other allocated resources.  Once this
- *  function is called, you must again call @ref glfwInit successfully before
- *  you will be able to use most GLFW functions.
- *
- *  If GLFW has been successfully initialized, this function should be called
- *  before the application exits.  If initialization fails, there is no need to
- *  call this function, as it is called by @ref glfwInit before it returns
- *  failure.
- *
- *  @remarks This function may be called before @ref glfwInit.
- *
- *  @warning No window's context may be current on another thread when this
- *  function is called.
- *
- *  @par Reentrancy
- *  This function may not be called from a callback.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref intro_init
- *  @sa glfwInit
- *
- *  @since Added in GLFW 1.0.
- *
- *  @ingroup init
- */
-GLFWAPI void glfwTerminate(void);
-
-/*! @brief Retrieves the version of the GLFW library.
- *
- *  This function retrieves the major, minor and revision numbers of the GLFW
- *  library.  It is intended for when you are using GLFW as a shared library and
- *  want to ensure that you are using the minimum required version.
- *
- *  Any or all of the version arguments may be `NULL`.  This function always
- *  succeeds.
- *
- *  @param[out] major Where to store the major version number, or `NULL`.
- *  @param[out] minor Where to store the minor version number, or `NULL`.
- *  @param[out] rev Where to store the revision number, or `NULL`.
- *
- *  @remarks This function may be called before @ref glfwInit.
- *
- *  @par Thread Safety
- *  This function may be called from any thread.
- *
- *  @sa @ref intro_version
- *  @sa glfwGetVersionString
- *
- *  @since Added in GLFW 1.0.
- *
- *  @ingroup init
- */
-GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev);
-
-/*! @brief Returns a string describing the compile-time configuration.
- *
- *  This function returns the compile-time generated
- *  [version string](@ref intro_version_string) of the GLFW library binary.  It
- *  describes the version, platform, compiler and any platform-specific
- *  compile-time options.
- *
- *  __Do not use the version string__ to parse the GLFW library version.  The
- *  @ref glfwGetVersion function already provides the version of the running
- *  library binary.
- *
- *  This function always succeeds.
- *
- *  @return The GLFW version string.
- *
- *  @remarks This function may be called before @ref glfwInit.
- *
- *  @par Pointer Lifetime
- *  The returned string is static and compile-time generated.
- *
- *  @par Thread Safety
- *  This function may be called from any thread.
- *
- *  @sa @ref intro_version
- *  @sa glfwGetVersion
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup init
- */
-GLFWAPI const char* glfwGetVersionString(void);
-
-/*! @brief Sets the error callback.
- *
- *  This function sets the error callback, which is called with an error code
- *  and a human-readable description each time a GLFW error occurs.
- *
- *  The error callback is called on the thread where the error occurred.  If you
- *  are using GLFW from multiple threads, your error callback needs to be
- *  written accordingly.
- *
- *  Because the description string may have been generated specifically for that
- *  error, it is not guaranteed to be valid after the callback has returned.  If
- *  you wish to use it after the callback returns, you need to make a copy.
- *
- *  Once set, the error callback remains set even after the library has been
- *  terminated.
- *
- *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
- *  callback.
- *  @return The previously set callback, or `NULL` if no callback was set.
- *
- *  @remarks This function may be called before @ref glfwInit.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref error_handling
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup init
- */
-GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun);
-
-/*! @brief Returns the currently connected monitors.
- *
- *  This function returns an array of handles for all currently connected
- *  monitors.
- *
- *  @param[out] count Where to store the number of monitors in the returned
- *  array.  This is set to zero if an error occurred.
- *  @return An array of monitor handles, or `NULL` if an
- *  [error](@ref error_handling) occurred.
- *
- *  @par Pointer Lifetime
- *  The returned array is allocated and freed by GLFW.  You should not free it
- *  yourself.  It is guaranteed to be valid only until the monitor configuration
- *  changes or the library is terminated.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref monitor_monitors
- *  @sa @ref monitor_event
- *  @sa glfwGetPrimaryMonitor
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup monitor
- */
-GLFWAPI GLFWmonitor** glfwGetMonitors(int* count);
-
-/*! @brief Returns the primary monitor.
- *
- *  This function returns the primary monitor.  This is usually the monitor
- *  where elements like the Windows task bar or the OS X menu bar is located.
- *
- *  @return The primary monitor, or `NULL` if an [error](@ref error_handling)
- *  occurred.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref monitor_monitors
- *  @sa glfwGetMonitors
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup monitor
- */
-GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void);
-
-/*! @brief Returns the position of the monitor's viewport on the virtual screen.
- *
- *  This function returns the position, in screen coordinates, of the upper-left
- *  corner of the specified monitor.
- *
- *  Any or all of the position arguments may be `NULL`.  If an error occurs, all
- *  non-`NULL` position arguments will be set to zero.
- *
- *  @param[in] monitor The monitor to query.
- *  @param[out] xpos Where to store the monitor x-coordinate, or `NULL`.
- *  @param[out] ypos Where to store the monitor y-coordinate, or `NULL`.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref monitor_properties
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup monitor
- */
-GLFWAPI void glfwGetMonitorPos(GLFWmonitor* monitor, int* xpos, int* ypos);
-
-/*! @brief Returns the physical size of the monitor.
- *
- *  This function returns the size, in millimetres, of the display area of the
- *  specified monitor.
- *
- *  Some systems do not provide accurate monitor size information, either
- *  because the monitor
- *  [EDID](https://en.wikipedia.org/wiki/Extended_display_identification_data)
- *  data is incorrect or because the driver does not report it accurately.
- *
- *  Any or all of the size arguments may be `NULL`.  If an error occurs, all
- *  non-`NULL` size arguments will be set to zero.
- *
- *  @param[in] monitor The monitor to query.
- *  @param[out] widthMM Where to store the width, in millimetres, of the
- *  monitor's display area, or `NULL`.
- *  @param[out] heightMM Where to store the height, in millimetres, of the
- *  monitor's display area, or `NULL`.
- *
- *  @remarks __Windows:__ The OS calculates the returned physical size from the
- *  current resolution and system DPI instead of querying the monitor EDID data.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref monitor_properties
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup monitor
- */
-GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* monitor, int* widthMM, int* heightMM);
-
-/*! @brief Returns the name of the specified monitor.
- *
- *  This function returns a human-readable name, encoded as UTF-8, of the
- *  specified monitor.  The name typically reflects the make and model of the
- *  monitor and is not guaranteed to be unique among the connected monitors.
- *
- *  @param[in] monitor The monitor to query.
- *  @return The UTF-8 encoded name of the monitor, or `NULL` if an
- *  [error](@ref error_handling) occurred.
- *
- *  @par Pointer Lifetime
- *  The returned string is allocated and freed by GLFW.  You should not free it
- *  yourself.  It is valid until the specified monitor is disconnected or the
- *  library is terminated.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref monitor_properties
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup monitor
- */
-GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* monitor);
-
-/*! @brief Sets the monitor configuration callback.
- *
- *  This function sets the monitor configuration callback, or removes the
- *  currently set callback.  This is called when a monitor is connected to or
- *  disconnected from the system.
- *
- *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
- *  callback.
- *  @return The previously set callback, or `NULL` if no callback was set or the
- *  library had not been [initialized](@ref intro_init).
- *
- *  @bug __X11:__ This callback is not yet called on monitor configuration
- *  changes.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref monitor_event
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup monitor
- */
-GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun);
-
-/*! @brief Returns the available video modes for the specified monitor.
- *
- *  This function returns an array of all video modes supported by the specified
- *  monitor.  The returned array is sorted in ascending order, first by color
- *  bit depth (the sum of all channel depths) and then by resolution area (the
- *  product of width and height).
- *
- *  @param[in] monitor The monitor to query.
- *  @param[out] count Where to store the number of video modes in the returned
- *  array.  This is set to zero if an error occurred.
- *  @return An array of video modes, or `NULL` if an
- *  [error](@ref error_handling) occurred.
- *
- *  @par Pointer Lifetime
- *  The returned array is allocated and freed by GLFW.  You should not free it
- *  yourself.  It is valid until the specified monitor is disconnected, this
- *  function is called again for that monitor or the library is terminated.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref monitor_modes
- *  @sa glfwGetVideoMode
- *
- *  @since Added in GLFW 1.0.
- *
- *  @par
- *  __GLFW 3:__ Changed to return an array of modes for a specific monitor.
- *
- *  @ingroup monitor
- */
-GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* monitor, int* count);
-
-/*! @brief Returns the current mode of the specified monitor.
- *
- *  This function returns the current video mode of the specified monitor.  If
- *  you have created a full screen window for that monitor, the return value
- *  will depend on whether that window is iconified.
- *
- *  @param[in] monitor The monitor to query.
- *  @return The current mode of the monitor, or `NULL` if an
- *  [error](@ref error_handling) occurred.
- *
- *  @par Pointer Lifetime
- *  The returned array is allocated and freed by GLFW.  You should not free it
- *  yourself.  It is valid until the specified monitor is disconnected or the
- *  library is terminated.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref monitor_modes
- *  @sa glfwGetVideoModes
- *
- *  @since Added in GLFW 3.0.  Replaces `glfwGetDesktopMode`.
- *
- *  @ingroup monitor
- */
-GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor);
-
-/*! @brief Generates a gamma ramp and sets it for the specified monitor.
- *
- *  This function generates a 256-element gamma ramp from the specified exponent
- *  and then calls @ref glfwSetGammaRamp with it.
- *
- *  @param[in] monitor The monitor whose gamma ramp to set.
- *  @param[in] gamma The desired exponent.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref monitor_gamma
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup monitor
- */
-GLFWAPI void glfwSetGamma(GLFWmonitor* monitor, float gamma);
-
-/*! @brief Returns the current gamma ramp for the specified monitor.
- *
- *  This function returns the current gamma ramp of the specified monitor.
- *
- *  @param[in] monitor The monitor to query.
- *  @return The current gamma ramp, or `NULL` if an
- *  [error](@ref error_handling) occurred.
- *
- *  @par Pointer Lifetime
- *  The returned structure and its arrays are allocated and freed by GLFW.  You
- *  should not free them yourself.  They are valid until the specified monitor
- *  is disconnected, this function is called again for that monitor or the
- *  library is terminated.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref monitor_gamma
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup monitor
- */
-GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* monitor);
-
-/*! @brief Sets the current gamma ramp for the specified monitor.
- *
- *  This function sets the current gamma ramp for the specified monitor.  The
- *  original gamma ramp for that monitor is saved by GLFW the first time this
- *  function is called and is restored by @ref glfwTerminate.
- *
- *  @param[in] monitor The monitor whose gamma ramp to set.
- *  @param[in] ramp The gamma ramp to use.
- *
- *  @note Gamma ramp sizes other than 256 are not supported by all hardware.
- *
- *  @par Pointer Lifetime
- *  The specified gamma ramp is copied before this function returns.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref monitor_gamma
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup monitor
- */
-GLFWAPI void glfwSetGammaRamp(GLFWmonitor* monitor, const GLFWgammaramp* ramp);
-
-/*! @brief Resets all window hints to their default values.
- *
- *  This function resets all window hints to their
- *  [default values](@ref window_hints_values).
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref window_hints
- *  @sa glfwWindowHint
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup window
- */
-GLFWAPI void glfwDefaultWindowHints(void);
-
-/*! @brief Sets the specified window hint to the desired value.
- *
- *  This function sets hints for the next call to @ref glfwCreateWindow.  The
- *  hints, once set, retain their values until changed by a call to @ref
- *  glfwWindowHint or @ref glfwDefaultWindowHints, or until the library is
- *  terminated.
- *
- *  @param[in] target The [window hint](@ref window_hints) to set.
- *  @param[in] hint The new value of the window hint.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref window_hints
- *  @sa glfwDefaultWindowHints
- *
- *  @since Added in GLFW 3.0.  Replaces `glfwOpenWindowHint`.
- *
- *  @ingroup window
- */
-GLFWAPI void glfwWindowHint(int target, int hint);
-
-/*! @brief Creates a window and its associated context.
- *
- *  This function creates a window and its associated OpenGL or OpenGL ES
- *  context.  Most of the options controlling how the window and its context
- *  should be created are specified with [window hints](@ref window_hints).
- *
- *  Successful creation does not change which context is current.  Before you
- *  can use the newly created context, you need to
- *  [make it current](@ref context_current).  For information about the `share`
- *  parameter, see @ref context_sharing.
- *
- *  The created window, framebuffer and context may differ from what you
- *  requested, as not all parameters and hints are
- *  [hard constraints](@ref window_hints_hard).  This includes the size of the
- *  window, especially for full screen windows.  To query the actual attributes
- *  of the created window, framebuffer and context, use queries like @ref
- *  glfwGetWindowAttrib and @ref glfwGetWindowSize.
- *
- *  To create a full screen window, you need to specify the monitor the window
- *  will cover.  If no monitor is specified, windowed mode will be used.  Unless
- *  you have a way for the user to choose a specific monitor, it is recommended
- *  that you pick the primary monitor.  For more information on how to query
- *  connected monitors, see @ref monitor_monitors.
- *
- *  For full screen windows, the specified size becomes the resolution of the
- *  window's _desired video mode_.  As long as a full screen window has input
- *  focus, the supported video mode most closely matching the desired video mode
- *  is set for the specified monitor.  For more information about full screen
- *  windows, including the creation of so called _windowed full screen_ or
- *  _borderless full screen_ windows, see @ref window_windowed_full_screen.
- *
- *  By default, newly created windows use the placement recommended by the
- *  window system.  To create the window at a specific position, make it
- *  initially invisible using the [GLFW_VISIBLE](@ref window_hints_wnd) window
- *  hint, set its [position](@ref window_pos) and then [show](@ref window_hide)
- *  it.
- *
- *  If a full screen window has input focus, the screensaver is prohibited from
- *  starting.
- *
- *  Window systems put limits on window sizes.  Very large or very small window
- *  dimensions may be overridden by the window system on creation.  Check the
- *  actual [size](@ref window_size) after creation.
- *
- *  The [swap interval](@ref buffer_swap) is not set during window creation and
- *  the initial value may vary depending on driver settings and defaults.
- *
- *  @param[in] width The desired width, in screen coordinates, of the window.
- *  This must be greater than zero.
- *  @param[in] height The desired height, in screen coordinates, of the window.
- *  This must be greater than zero.
- *  @param[in] title The initial, UTF-8 encoded window title.
- *  @param[in] monitor The monitor to use for full screen mode, or `NULL` to use
- *  windowed mode.
- *  @param[in] share The window whose context to share resources with, or `NULL`
- *  to not share resources.
- *  @return The handle of the created window, or `NULL` if an
- *  [error](@ref error_handling) occurred.
- *
- *  @remarks __Windows:__ Window creation will fail if the Microsoft GDI
- *  software OpenGL implementation is the only one available.
- *
- *  @remarks __Windows:__ If the executable has an icon resource named
- *  `GLFW_ICON,` it will be set as the icon for the window.  If no such icon is
- *  present, the `IDI_WINLOGO` icon will be used instead.
- *
- *  @remarks __Windows:__ The context to share resources with may not be current
- *  on any other thread.
- *
- *  @remarks __OS X:__ The GLFW window has no icon, as it is not a document
- *  window, but the dock icon will be the same as the application bundle's icon.
- *  For more information on bundles, see the
- *  [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/)
- *  in the Mac Developer Library.
- *
- *  @remarks __OS X:__ The first time a window is created the menu bar is
- *  populated with common commands like Hide, Quit and About.  The About entry
- *  opens a minimal about dialog with information from the application's bundle.
- *  The menu bar can be disabled with a
- *  [compile-time option](@ref compile_options_osx).
- *
- *  @remarks __X11:__ There is no mechanism for setting the window icon yet.
- *
- *  @remarks __X11:__ Some window managers will not respect the placement of
- *  initially hidden windows.
- *
- *  @par Reentrancy
- *  This function may not be called from a callback.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref window_creation
- *  @sa glfwDestroyWindow
- *
- *  @since Added in GLFW 3.0.  Replaces `glfwOpenWindow`.
- *
- *  @ingroup window
- */
-GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, GLFWmonitor* monitor, GLFWwindow* share);
-
-/*! @brief Destroys the specified window and its context.
- *
- *  This function destroys the specified window and its context.  On calling
- *  this function, no further callbacks will be called for that window.
- *
- *  If the context of the specified window is current on the main thread, it is
- *  detached before being destroyed.
- *
- *  @param[in] window The window to destroy.
- *
- *  @note The context of the specified window must not be current on any other
- *  thread when this function is called.
- *
- *  @par Reentrancy
- *  This function may not be called from a callback.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref window_creation
- *  @sa glfwCreateWindow
- *
- *  @since Added in GLFW 3.0.  Replaces `glfwCloseWindow`.
- *
- *  @ingroup window
- */
-GLFWAPI void glfwDestroyWindow(GLFWwindow* window);
-
-/*! @brief Checks the close flag of the specified window.
- *
- *  This function returns the value of the close flag of the specified window.
- *
- *  @param[in] window The window to query.
- *  @return The value of the close flag.
- *
- *  @par Thread Safety
- *  This function may be called from any thread.  Access is not synchronized.
- *
- *  @sa @ref window_close
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup window
- */
-GLFWAPI int glfwWindowShouldClose(GLFWwindow* window);
-
-/*! @brief Sets the close flag of the specified window.
- *
- *  This function sets the value of the close flag of the specified window.
- *  This can be used to override the user's attempt to close the window, or
- *  to signal that it should be closed.
- *
- *  @param[in] window The window whose flag to change.
- *  @param[in] value The new value.
- *
- *  @par Thread Safety
- *  This function may be called from any thread.  Access is not synchronized.
- *
- *  @sa @ref window_close
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup window
- */
-GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* window, int value);
-
-/*! @brief Sets the title of the specified window.
- *
- *  This function sets the window title, encoded as UTF-8, of the specified
- *  window.
- *
- *  @param[in] window The window whose title to change.
- *  @param[in] title The UTF-8 encoded window title.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref window_title
- *
- *  @since Added in GLFW 1.0.
- *
- *  @par
- *  __GLFW 3:__ Added window handle parameter.
- *
- *  @ingroup window
- */
-GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title);
-
-/*! @brief Retrieves the position of the client area of the specified window.
- *
- *  This function retrieves the position, in screen coordinates, of the
- *  upper-left corner of the client area of the specified window.
- *
- *  Any or all of the position arguments may be `NULL`.  If an error occurs, all
- *  non-`NULL` position arguments will be set to zero.
- *
- *  @param[in] window The window to query.
- *  @param[out] xpos Where to store the x-coordinate of the upper-left corner of
- *  the client area, or `NULL`.
- *  @param[out] ypos Where to store the y-coordinate of the upper-left corner of
- *  the client area, or `NULL`.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref window_pos
- *  @sa glfwSetWindowPos
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup window
- */
-GLFWAPI void glfwGetWindowPos(GLFWwindow* window, int* xpos, int* ypos);
-
-/*! @brief Sets the position of the client area of the specified window.
- *
- *  This function sets the position, in screen coordinates, of the upper-left
- *  corner of the client area of the specified windowed mode window.  If the
- *  window is a full screen window, this function does nothing.
- *
- *  __Do not use this function__ to move an already visible window unless you
- *  have very good reasons for doing so, as it will confuse and annoy the user.
- *
- *  The window manager may put limits on what positions are allowed.  GLFW
- *  cannot and should not override these limits.
- *
- *  @param[in] window The window to query.
- *  @param[in] xpos The x-coordinate of the upper-left corner of the client area.
- *  @param[in] ypos The y-coordinate of the upper-left corner of the client area.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref window_pos
- *  @sa glfwGetWindowPos
- *
- *  @since Added in GLFW 1.0.
- *
- *  @par
- *  __GLFW 3:__ Added window handle parameter.
- *
- *  @ingroup window
- */
-GLFWAPI void glfwSetWindowPos(GLFWwindow* window, int xpos, int ypos);
-
-/*! @brief Retrieves the size of the client area of the specified window.
- *
- *  This function retrieves the size, in screen coordinates, of the client area
- *  of the specified window.  If you wish to retrieve the size of the
- *  framebuffer of the window in pixels, see @ref glfwGetFramebufferSize.
- *
- *  Any or all of the size arguments may be `NULL`.  If an error occurs, all
- *  non-`NULL` size arguments will be set to zero.
- *
- *  @param[in] window The window whose size to retrieve.
- *  @param[out] width Where to store the width, in screen coordinates, of the
- *  client area, or `NULL`.
- *  @param[out] height Where to store the height, in screen coordinates, of the
- *  client area, or `NULL`.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref window_size
- *  @sa glfwSetWindowSize
- *
- *  @since Added in GLFW 1.0.
- *
- *  @par
- *  __GLFW 3:__ Added window handle parameter.
- *
- *  @ingroup window
- */
-GLFWAPI void glfwGetWindowSize(GLFWwindow* window, int* width, int* height);
-
-/*! @brief Sets the size of the client area of the specified window.
- *
- *  This function sets the size, in screen coordinates, of the client area of
- *  the specified window.
- *
- *  For full screen windows, this function selects and switches to the resolution
- *  closest to the specified size, without affecting the window's context.  As
- *  the context is unaffected, the bit depths of the framebuffer remain
- *  unchanged.
- *
- *  The window manager may put limits on what sizes are allowed.  GLFW cannot
- *  and should not override these limits.
- *
- *  @param[in] window The window to resize.
- *  @param[in] width The desired width of the specified window.
- *  @param[in] height The desired height of the specified window.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref window_size
- *  @sa glfwGetWindowSize
- *
- *  @since Added in GLFW 1.0.
- *
- *  @par
- *  __GLFW 3:__ Added window handle parameter.
- *
- *  @ingroup window
- */
-GLFWAPI void glfwSetWindowSize(GLFWwindow* window, int width, int height);
-
-/*! @brief Retrieves the size of the framebuffer of the specified window.
- *
- *  This function retrieves the size, in pixels, of the framebuffer of the
- *  specified window.  If you wish to retrieve the size of the window in screen
- *  coordinates, see @ref glfwGetWindowSize.
- *
- *  Any or all of the size arguments may be `NULL`.  If an error occurs, all
- *  non-`NULL` size arguments will be set to zero.
- *
- *  @param[in] window The window whose framebuffer to query.
- *  @param[out] width Where to store the width, in pixels, of the framebuffer,
- *  or `NULL`.
- *  @param[out] height Where to store the height, in pixels, of the framebuffer,
- *  or `NULL`.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref window_fbsize
- *  @sa glfwSetFramebufferSizeCallback
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup window
- */
-GLFWAPI void glfwGetFramebufferSize(GLFWwindow* window, int* width, int* height);
-
-/*! @brief Retrieves the size of the frame of the window.
- *
- *  This function retrieves the size, in screen coordinates, of each edge of the
- *  frame of the specified window.  This size includes the title bar, if the
- *  window has one.  The size of the frame may vary depending on the
- *  [window-related hints](@ref window_hints_wnd) used to create it.
- *
- *  Because this function retrieves the size of each window frame edge and not
- *  the offset along a particular coordinate axis, the retrieved values will
- *  always be zero or positive.
- *
- *  Any or all of the size arguments may be `NULL`.  If an error occurs, all
- *  non-`NULL` size arguments will be set to zero.
- *
- *  @param[in] window The window whose frame size to query.
- *  @param[out] left Where to store the size, in screen coordinates, of the left
- *  edge of the window frame, or `NULL`.
- *  @param[out] top Where to store the size, in screen coordinates, of the top
- *  edge of the window frame, or `NULL`.
- *  @param[out] right Where to store the size, in screen coordinates, of the
- *  right edge of the window frame, or `NULL`.
- *  @param[out] bottom Where to store the size, in screen coordinates, of the
- *  bottom edge of the window frame, or `NULL`.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref window_size
- *
- *  @since Added in GLFW 3.1.
- *
- *  @ingroup window
- */
-GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* window, int* left, int* top, int* right, int* bottom);
-
-/*! @brief Iconifies the specified window.
- *
- *  This function iconifies (minimizes) the specified window if it was
- *  previously restored.  If the window is already iconified, this function does
- *  nothing.
- *
- *  If the specified window is a full screen window, the original monitor
- *  resolution is restored until the window is restored.
- *
- *  @param[in] window The window to iconify.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref window_iconify
- *  @sa glfwRestoreWindow
- *
- *  @since Added in GLFW 2.1.
- *
- *  @par
- *  __GLFW 3:__ Added window handle parameter.
- *
- *  @ingroup window
- */
-GLFWAPI void glfwIconifyWindow(GLFWwindow* window);
-
-/*! @brief Restores the specified window.
- *
- *  This function restores the specified window if it was previously iconified
- *  (minimized).  If the window is already restored, this function does nothing.
- *
- *  If the specified window is a full screen window, the resolution chosen for
- *  the window is restored on the selected monitor.
- *
- *  @param[in] window The window to restore.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref window_iconify
- *  @sa glfwIconifyWindow
- *
- *  @since Added in GLFW 2.1.
- *
- *  @par
- *  __GLFW 3:__ Added window handle parameter.
- *
- *  @ingroup window
- */
-GLFWAPI void glfwRestoreWindow(GLFWwindow* window);
-
-/*! @brief Makes the specified window visible.
- *
- *  This function makes the specified window visible if it was previously
- *  hidden.  If the window is already visible or is in full screen mode, this
- *  function does nothing.
- *
- *  @param[in] window The window to make visible.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref window_hide
- *  @sa glfwHideWindow
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup window
- */
-GLFWAPI void glfwShowWindow(GLFWwindow* window);
-
-/*! @brief Hides the specified window.
- *
- *  This function hides the specified window if it was previously visible.  If
- *  the window is already hidden or is in full screen mode, this function does
- *  nothing.
- *
- *  @param[in] window The window to hide.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref window_hide
- *  @sa glfwShowWindow
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup window
- */
-GLFWAPI void glfwHideWindow(GLFWwindow* window);
-
-/*! @brief Returns the monitor that the window uses for full screen mode.
- *
- *  This function returns the handle of the monitor that the specified window is
- *  in full screen on.
- *
- *  @param[in] window The window to query.
- *  @return The monitor, or `NULL` if the window is in windowed mode or an error
- *  occurred.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref window_monitor
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup window
- */
-GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window);
-
-/*! @brief Returns an attribute of the specified window.
- *
- *  This function returns the value of an attribute of the specified window or
- *  its OpenGL or OpenGL ES context.
- *
- *  @param[in] window The window to query.
- *  @param[in] attrib The [window attribute](@ref window_attribs) whose value to
- *  return.
- *  @return The value of the attribute, or zero if an
- *  [error](@ref error_handling) occurred.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref window_attribs
- *
- *  @since Added in GLFW 3.0.  Replaces `glfwGetWindowParam` and
- *  `glfwGetGLVersion`.
- *
- *  @ingroup window
- */
-GLFWAPI int glfwGetWindowAttrib(GLFWwindow* window, int attrib);
-
-/*! @brief Sets the user pointer of the specified window.
- *
- *  This function sets the user-defined pointer of the specified window.  The
- *  current value is retained until the window is destroyed.  The initial value
- *  is `NULL`.
- *
- *  @param[in] window The window whose pointer to set.
- *  @param[in] pointer The new value.
- *
- *  @par Thread Safety
- *  This function may be called from any thread.  Access is not synchronized.
- *
- *  @sa @ref window_userptr
- *  @sa glfwGetWindowUserPointer
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup window
- */
-GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* window, void* pointer);
-
-/*! @brief Returns the user pointer of the specified window.
- *
- *  This function returns the current value of the user-defined pointer of the
- *  specified window.  The initial value is `NULL`.
- *
- *  @param[in] window The window whose pointer to return.
- *
- *  @par Thread Safety
- *  This function may be called from any thread.  Access is not synchronized.
- *
- *  @sa @ref window_userptr
- *  @sa glfwSetWindowUserPointer
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup window
- */
-GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* window);
-
-/*! @brief Sets the position callback for the specified window.
- *
- *  This function sets the position callback of the specified window, which is
- *  called when the window is moved.  The callback is provided with the screen
- *  position of the upper-left corner of the client area of the window.
- *
- *  @param[in] window The window whose callback to set.
- *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
- *  callback.
- *  @return The previously set callback, or `NULL` if no callback was set or the
- *  library had not been [initialized](@ref intro_init).
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref window_pos
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup window
- */
-GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* window, GLFWwindowposfun cbfun);
-
-/*! @brief Sets the size callback for the specified window.
- *
- *  This function sets the size callback of the specified window, which is
- *  called when the window is resized.  The callback is provided with the size,
- *  in screen coordinates, of the client area of the window.
- *
- *  @param[in] window The window whose callback to set.
- *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
- *  callback.
- *  @return The previously set callback, or `NULL` if no callback was set or the
- *  library had not been [initialized](@ref intro_init).
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref window_size
- *
- *  @since Added in GLFW 1.0.
- *
- *  @par
- *  __GLFW 3:__ Added window handle parameter.  Updated callback signature.
- *
- *  @ingroup window
- */
-GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* window, GLFWwindowsizefun cbfun);
-
-/*! @brief Sets the close callback for the specified window.
- *
- *  This function sets the close callback of the specified window, which is
- *  called when the user attempts to close the window, for example by clicking
- *  the close widget in the title bar.
- *
- *  The close flag is set before this callback is called, but you can modify it
- *  at any time with @ref glfwSetWindowShouldClose.
- *
- *  The close callback is not triggered by @ref glfwDestroyWindow.
- *
- *  @param[in] window The window whose callback to set.
- *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
- *  callback.
- *  @return The previously set callback, or `NULL` if no callback was set or the
- *  library had not been [initialized](@ref intro_init).
- *
- *  @remarks __OS X:__ Selecting Quit from the application menu will
- *  trigger the close callback for all windows.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref window_close
- *
- *  @since Added in GLFW 2.5.
- *
- *  @par
- *  __GLFW 3:__ Added window handle parameter.  Updated callback signature.
- *
- *  @ingroup window
- */
-GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* window, GLFWwindowclosefun cbfun);
-
-/*! @brief Sets the refresh callback for the specified window.
- *
- *  This function sets the refresh callback of the specified window, which is
- *  called when the client area of the window needs to be redrawn, for example
- *  if the window has been exposed after having been covered by another window.
- *
- *  On compositing window systems such as Aero, Compiz or Aqua, where the window
- *  contents are saved off-screen, this callback may be called only very
- *  infrequently or never at all.
- *
- *  @param[in] window The window whose callback to set.
- *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
- *  callback.
- *  @return The previously set callback, or `NULL` if no callback was set or the
- *  library had not been [initialized](@ref intro_init).
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref window_refresh
- *
- *  @since Added in GLFW 2.5.
- *
- *  @par
- *  __GLFW 3:__ Added window handle parameter.  Updated callback signature.
- *
- *  @ingroup window
- */
-GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* window, GLFWwindowrefreshfun cbfun);
-
-/*! @brief Sets the focus callback for the specified window.
- *
- *  This function sets the focus callback of the specified window, which is
- *  called when the window gains or loses input focus.
- *
- *  After the focus callback is called for a window that lost input focus,
- *  synthetic key and mouse button release events will be generated for all such
- *  that had been pressed.  For more information, see @ref glfwSetKeyCallback
- *  and @ref glfwSetMouseButtonCallback.
- *
- *  @param[in] window The window whose callback to set.
- *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
- *  callback.
- *  @return The previously set callback, or `NULL` if no callback was set or the
- *  library had not been [initialized](@ref intro_init).
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref window_focus
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup window
- */
-GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* window, GLFWwindowfocusfun cbfun);
-
-/*! @brief Sets the iconify callback for the specified window.
- *
- *  This function sets the iconification callback of the specified window, which
- *  is called when the window is iconified or restored.
- *
- *  @param[in] window The window whose callback to set.
- *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
- *  callback.
- *  @return The previously set callback, or `NULL` if no callback was set or the
- *  library had not been [initialized](@ref intro_init).
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref window_iconify
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup window
- */
-GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* window, GLFWwindowiconifyfun cbfun);
-
-/*! @brief Sets the framebuffer resize callback for the specified window.
- *
- *  This function sets the framebuffer resize callback of the specified window,
- *  which is called when the framebuffer of the specified window is resized.
- *
- *  @param[in] window The window whose callback to set.
- *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
- *  callback.
- *  @return The previously set callback, or `NULL` if no callback was set or the
- *  library had not been [initialized](@ref intro_init).
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref window_fbsize
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup window
- */
-GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* window, GLFWframebuffersizefun cbfun);
-
-/*! @brief Processes all pending events.
- *
- *  This function processes only those events that are already in the event
- *  queue and then returns immediately.  Processing events will cause the window
- *  and input callbacks associated with those events to be called.
- *
- *  On some platforms, a window move, resize or menu operation will cause event
- *  processing to block.  This is due to how event processing is designed on
- *  those platforms.  You can use the
- *  [window refresh callback](@ref window_refresh) to redraw the contents of
- *  your window when necessary during such operations.
- *
- *  On some platforms, certain events are sent directly to the application
- *  without going through the event queue, causing callbacks to be called
- *  outside of a call to one of the event processing functions.
- *
- *  Event processing is not required for joystick input to work.
- *
- *  @par Reentrancy
- *  This function may not be called from a callback.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref events
- *  @sa glfwWaitEvents
- *
- *  @since Added in GLFW 1.0.
- *
- *  @ingroup window
- */
-GLFWAPI void glfwPollEvents(void);
-
-/*! @brief Waits until events are queued and processes them.
- *
- *  This function puts the calling thread to sleep until at least one event is
- *  available in the event queue.  Once one or more events are available,
- *  it behaves exactly like @ref glfwPollEvents, i.e. the events in the queue
- *  are processed and the function then returns immediately.  Processing events
- *  will cause the window and input callbacks associated with those events to be
- *  called.
- *
- *  Since not all events are associated with callbacks, this function may return
- *  without a callback having been called even if you are monitoring all
- *  callbacks.
- *
- *  On some platforms, a window move, resize or menu operation will cause event
- *  processing to block.  This is due to how event processing is designed on
- *  those platforms.  You can use the
- *  [window refresh callback](@ref window_refresh) to redraw the contents of
- *  your window when necessary during such operations.
- *
- *  On some platforms, certain callbacks may be called outside of a call to one
- *  of the event processing functions.
- *
- *  If no windows exist, this function returns immediately.  For synchronization
- *  of threads in applications that do not create windows, use your threading
- *  library of choice.
- *
- *  Event processing is not required for joystick input to work.
- *
- *  @par Reentrancy
- *  This function may not be called from a callback.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref events
- *  @sa glfwPollEvents
- *
- *  @since Added in GLFW 2.5.
- *
- *  @ingroup window
- */
-GLFWAPI void glfwWaitEvents(void);
-
-/*! @brief Posts an empty event to the event queue.
- *
- *  This function posts an empty event from the current thread to the event
- *  queue, causing @ref glfwWaitEvents to return.
- *
- *  If no windows exist, this function returns immediately.  For synchronization
- *  of threads in applications that do not create windows, use your threading
- *  library of choice.
- *
- *  @par Thread Safety
- *  This function may be called from any thread.
- *
- *  @sa @ref events
- *  @sa glfwWaitEvents
- *
- *  @since Added in GLFW 3.1.
- *
- *  @ingroup window
- */
-GLFWAPI void glfwPostEmptyEvent(void);
-
-/*! @brief Returns the value of an input option for the specified window.
- *
- *  This function returns the value of an input option for the specified window.
- *  The mode must be one of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or
- *  `GLFW_STICKY_MOUSE_BUTTONS`.
- *
- *  @param[in] window The window to query.
- *  @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or
- *  `GLFW_STICKY_MOUSE_BUTTONS`.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa glfwSetInputMode
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup input
- */
-GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode);
-
-/*! @brief Sets an input option for the specified window.
- *
- *  This function sets an input mode option for the specified window.  The mode
- *  must be one of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or
- *  `GLFW_STICKY_MOUSE_BUTTONS`.
- *
- *  If the mode is `GLFW_CURSOR`, the value must be one of the following cursor
- *  modes:
- *  - `GLFW_CURSOR_NORMAL` makes the cursor visible and behaving normally.
- *  - `GLFW_CURSOR_HIDDEN` makes the cursor invisible when it is over the client
- *    area of the window but does not restrict the cursor from leaving.
- *  - `GLFW_CURSOR_DISABLED` hides and grabs the cursor, providing virtual
- *    and unlimited cursor movement.  This is useful for implementing for
- *    example 3D camera controls.
- *
- *  If the mode is `GLFW_STICKY_KEYS`, the value must be either `GL_TRUE` to
- *  enable sticky keys, or `GL_FALSE` to disable it.  If sticky keys are
- *  enabled, a key press will ensure that @ref glfwGetKey returns `GLFW_PRESS`
- *  the next time it is called even if the key had been released before the
- *  call.  This is useful when you are only interested in whether keys have been
- *  pressed but not when or in which order.
- *
- *  If the mode is `GLFW_STICKY_MOUSE_BUTTONS`, the value must be either
- *  `GL_TRUE` to enable sticky mouse buttons, or `GL_FALSE` to disable it.  If
- *  sticky mouse buttons are enabled, a mouse button press will ensure that @ref
- *  glfwGetMouseButton returns `GLFW_PRESS` the next time it is called even if
- *  the mouse button had been released before the call.  This is useful when you
- *  are only interested in whether mouse buttons have been pressed but not when
- *  or in which order.
- *
- *  @param[in] window The window whose input mode to set.
- *  @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or
- *  `GLFW_STICKY_MOUSE_BUTTONS`.
- *  @param[in] value The new value of the specified input mode.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa glfwGetInputMode
- *
- *  @since Added in GLFW 3.0.  Replaces `glfwEnable` and `glfwDisable`.
- *
- *  @ingroup input
- */
-GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value);
-
-/*! @brief Returns the last reported state of a keyboard key for the specified
- *  window.
- *
- *  This function returns the last state reported for the specified key to the
- *  specified window.  The returned state is one of `GLFW_PRESS` or
- *  `GLFW_RELEASE`.  The higher-level action `GLFW_REPEAT` is only reported to
- *  the key callback.
- *
- *  If the `GLFW_STICKY_KEYS` input mode is enabled, this function returns
- *  `GLFW_PRESS` the first time you call it for a key that was pressed, even if
- *  that key has already been released.
- *
- *  The key functions deal with physical keys, with [key tokens](@ref keys)
- *  named after their use on the standard US keyboard layout.  If you want to
- *  input text, use the Unicode character callback instead.
- *
- *  The [modifier key bit masks](@ref mods) are not key tokens and cannot be
- *  used with this function.
- *
- *  @param[in] window The desired window.
- *  @param[in] key The desired [keyboard key](@ref keys).  `GLFW_KEY_UNKNOWN` is
- *  not a valid key for this function.
- *  @return One of `GLFW_PRESS` or `GLFW_RELEASE`.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref input_key
- *
- *  @since Added in GLFW 1.0.
- *
- *  @par
- *  __GLFW 3:__ Added window handle parameter.
- *
- *  @ingroup input
- */
-GLFWAPI int glfwGetKey(GLFWwindow* window, int key);
-
-/*! @brief Returns the last reported state of a mouse button for the specified
- *  window.
- *
- *  This function returns the last state reported for the specified mouse button
- *  to the specified window.  The returned state is one of `GLFW_PRESS` or
- *  `GLFW_RELEASE`.
- *
- *  If the `GLFW_STICKY_MOUSE_BUTTONS` input mode is enabled, this function
- *  `GLFW_PRESS` the first time you call it for a mouse button that was pressed,
- *  even if that mouse button has already been released.
- *
- *  @param[in] window The desired window.
- *  @param[in] button The desired [mouse button](@ref buttons).
- *  @return One of `GLFW_PRESS` or `GLFW_RELEASE`.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref input_mouse_button
- *
- *  @since Added in GLFW 1.0.
- *
- *  @par
- *  __GLFW 3:__ Added window handle parameter.
- *
- *  @ingroup input
- */
-GLFWAPI int glfwGetMouseButton(GLFWwindow* window, int button);
-
-/*! @brief Retrieves the position of the cursor relative to the client area of
- *  the window.
- *
- *  This function returns the position of the cursor, in screen coordinates,
- *  relative to the upper-left corner of the client area of the specified
- *  window.
- *
- *  If the cursor is disabled (with `GLFW_CURSOR_DISABLED`) then the cursor
- *  position is unbounded and limited only by the minimum and maximum values of
- *  a `double`.
- *
- *  The coordinate can be converted to their integer equivalents with the
- *  `floor` function.  Casting directly to an integer type works for positive
- *  coordinates, but fails for negative ones.
- *
- *  Any or all of the position arguments may be `NULL`.  If an error occurs, all
- *  non-`NULL` position arguments will be set to zero.
- *
- *  @param[in] window The desired window.
- *  @param[out] xpos Where to store the cursor x-coordinate, relative to the
- *  left edge of the client area, or `NULL`.
- *  @param[out] ypos Where to store the cursor y-coordinate, relative to the to
- *  top edge of the client area, or `NULL`.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref cursor_pos
- *  @sa glfwSetCursorPos
- *
- *  @since Added in GLFW 3.0.  Replaces `glfwGetMousePos`.
- *
- *  @ingroup input
- */
-GLFWAPI void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos);
-
-/*! @brief Sets the position of the cursor, relative to the client area of the
- *  window.
- *
- *  This function sets the position, in screen coordinates, of the cursor
- *  relative to the upper-left corner of the client area of the specified
- *  window.  The window must have input focus.  If the window does not have
- *  input focus when this function is called, it fails silently.
- *
- *  __Do not use this function__ to implement things like camera controls.  GLFW
- *  already provides the `GLFW_CURSOR_DISABLED` cursor mode that hides the
- *  cursor, transparently re-centers it and provides unconstrained cursor
- *  motion.  See @ref glfwSetInputMode for more information.
- *
- *  If the cursor mode is `GLFW_CURSOR_DISABLED` then the cursor position is
- *  unconstrained and limited only by the minimum and maximum values of
- *  a `double`.
- *
- *  @param[in] window The desired window.
- *  @param[in] xpos The desired x-coordinate, relative to the left edge of the
- *  client area.
- *  @param[in] ypos The desired y-coordinate, relative to the top edge of the
- *  client area.
- *
- *  @remarks __X11:__ Due to the asynchronous nature of a modern X desktop, it
- *  may take a moment for the window focus event to arrive.  This means you will
- *  not be able to set the cursor position directly after window creation.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref cursor_pos
- *  @sa glfwGetCursorPos
- *
- *  @since Added in GLFW 3.0.  Replaces `glfwSetMousePos`.
- *
- *  @ingroup input
- */
-GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos);
-
-/*! @brief Creates a custom cursor.
- *
- *  Creates a new custom cursor image that can be set for a window with @ref
- *  glfwSetCursor.  The cursor can be destroyed with @ref glfwDestroyCursor.
- *  Any remaining cursors are destroyed by @ref glfwTerminate.
- *
- *  The pixels are 32-bit little-endian RGBA, i.e. eight bits per channel.  They
- *  are arranged canonically as packed sequential rows, starting from the
- *  top-left corner.
- *
- *  The cursor hotspot is specified in pixels, relative to the upper-left corner
- *  of the cursor image.  Like all other coordinate systems in GLFW, the X-axis
- *  points to the right and the Y-axis points down.
- *
- *  @param[in] image The desired cursor image.
- *  @param[in] xhot The desired x-coordinate, in pixels, of the cursor hotspot.
- *  @param[in] yhot The desired y-coordinate, in pixels, of the cursor hotspot.
- *
- *  @return The handle of the created cursor, or `NULL` if an
- *  [error](@ref error_handling) occurred.
- *
- *  @par Pointer Lifetime
- *  The specified image data is copied before this function returns.
- *
- *  @par Reentrancy
- *  This function may not be called from a callback.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref cursor_object
- *  @sa glfwDestroyCursor
- *  @sa glfwCreateStandardCursor
- *
- *  @since Added in GLFW 3.1.
- *
- *  @ingroup input
- */
-GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot);
-
-/*! @brief Creates a cursor with a standard shape.
- *
- *  Returns a cursor with a [standard shape](@ref shapes), that can be set for
- *  a window with @ref glfwSetCursor.
- *
- *  @param[in] shape One of the [standard shapes](@ref shapes).
- *
- *  @return A new cursor ready to use or `NULL` if an
- *  [error](@ref error_handling) occurred.
- *
- *  @par Reentrancy
- *  This function may not be called from a callback.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref cursor_object
- *  @sa glfwCreateCursor
- *
- *  @since Added in GLFW 3.1.
- *
- *  @ingroup input
- */
-GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape);
-
-/*! @brief Destroys a cursor.
- *
- *  This function destroys a cursor previously created with @ref
- *  glfwCreateCursor.  Any remaining cursors will be destroyed by @ref
- *  glfwTerminate.
- *
- *  @param[in] cursor The cursor object to destroy.
- *
- *  @par Reentrancy
- *  This function may not be called from a callback.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref cursor_object
- *  @sa glfwCreateCursor
- *
- *  @since Added in GLFW 3.1.
- *
- *  @ingroup input
- */
-GLFWAPI void glfwDestroyCursor(GLFWcursor* cursor);
-
-/*! @brief Sets the cursor for the window.
- *
- *  This function sets the cursor image to be used when the cursor is over the
- *  client area of the specified window.  The set cursor will only be visible
- *  when the [cursor mode](@ref cursor_mode) of the window is
- *  `GLFW_CURSOR_NORMAL`.
- *
- *  On some platforms, the set cursor may not be visible unless the window also
- *  has input focus.
- *
- *  @param[in] window The window to set the cursor for.
- *  @param[in] cursor The cursor to set, or `NULL` to switch back to the default
- *  arrow cursor.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref cursor_object
- *
- *  @since Added in GLFW 3.1.
- *
- *  @ingroup input
- */
-GLFWAPI void glfwSetCursor(GLFWwindow* window, GLFWcursor* cursor);
-
-/*! @brief Sets the key callback.
- *
- *  This function sets the key callback of the specified window, which is called
- *  when a key is pressed, repeated or released.
- *
- *  The key functions deal with physical keys, with layout independent
- *  [key tokens](@ref keys) named after their values in the standard US keyboard
- *  layout.  If you want to input text, use the
- *  [character callback](@ref glfwSetCharCallback) instead.
- *
- *  When a window loses input focus, it will generate synthetic key release
- *  events for all pressed keys.  You can tell these events from user-generated
- *  events by the fact that the synthetic ones are generated after the focus
- *  loss event has been processed, i.e. after the
- *  [window focus callback](@ref glfwSetWindowFocusCallback) has been called.
- *
- *  The scancode of a key is specific to that platform or sometimes even to that
- *  machine.  Scancodes are intended to allow users to bind keys that don't have
- *  a GLFW key token.  Such keys have `key` set to `GLFW_KEY_UNKNOWN`, their
- *  state is not saved and so it cannot be queried with @ref glfwGetKey.
- *
- *  Sometimes GLFW needs to generate synthetic key events, in which case the
- *  scancode may be zero.
- *
- *  @param[in] window The window whose callback to set.
- *  @param[in] cbfun The new key callback, or `NULL` to remove the currently
- *  set callback.
- *  @return The previously set callback, or `NULL` if no callback was set or the
- *  library had not been [initialized](@ref intro_init).
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref input_key
- *
- *  @since Added in GLFW 1.0.
- *
- *  @par
- *  __GLFW 3:__ Added window handle parameter.  Updated callback signature.
- *
- *  @ingroup input
- */
-GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun cbfun);
-
-/*! @brief Sets the Unicode character callback.
- *
- *  This function sets the character callback of the specified window, which is
- *  called when a Unicode character is input.
- *
- *  The character callback is intended for Unicode text input.  As it deals with
- *  characters, it is keyboard layout dependent, whereas the
- *  [key callback](@ref glfwSetKeyCallback) is not.  Characters do not map 1:1
- *  to physical keys, as a key may produce zero, one or more characters.  If you
- *  want to know whether a specific physical key was pressed or released, see
- *  the key callback instead.
- *
- *  The character callback behaves as system text input normally does and will
- *  not be called if modifier keys are held down that would prevent normal text
- *  input on that platform, for example a Super (Command) key on OS X or Alt key
- *  on Windows.  There is a
- *  [character with modifiers callback](@ref glfwSetCharModsCallback) that
- *  receives these events.
- *
- *  @param[in] window The window whose callback to set.
- *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
- *  callback.
- *  @return The previously set callback, or `NULL` if no callback was set or the
- *  library had not been [initialized](@ref intro_init).
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref input_char
- *
- *  @since Added in GLFW 2.4.
- *
- *  @par
- *  __GLFW 3:__ Added window handle parameter.  Updated callback signature.
- *
- *  @ingroup input
- */
-GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun cbfun);
-
-/*! @brief Sets the Unicode character with modifiers callback.
- *
- *  This function sets the character with modifiers callback of the specified
- *  window, which is called when a Unicode character is input regardless of what
- *  modifier keys are used.
- *
- *  The character with modifiers callback is intended for implementing custom
- *  Unicode character input.  For regular Unicode text input, see the
- *  [character callback](@ref glfwSetCharCallback).  Like the character
- *  callback, the character with modifiers callback deals with characters and is
- *  keyboard layout dependent.  Characters do not map 1:1 to physical keys, as
- *  a key may produce zero, one or more characters.  If you want to know whether
- *  a specific physical key was pressed or released, see the
- *  [key callback](@ref glfwSetKeyCallback) instead.
- *
- *  @param[in] window The window whose callback to set.
- *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
- *  callback.
- *  @return The previously set callback, or `NULL` if no callback was set or an
- *  error occurred.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref input_char
- *
- *  @since Added in GLFW 3.1.
- *
- *  @ingroup input
- */
-GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmodsfun cbfun);
-
-/*! @brief Sets the mouse button callback.
- *
- *  This function sets the mouse button callback of the specified window, which
- *  is called when a mouse button is pressed or released.
- *
- *  When a window loses input focus, it will generate synthetic mouse button
- *  release events for all pressed mouse buttons.  You can tell these events
- *  from user-generated events by the fact that the synthetic ones are generated
- *  after the focus loss event has been processed, i.e. after the
- *  [window focus callback](@ref glfwSetWindowFocusCallback) has been called.
- *
- *  @param[in] window The window whose callback to set.
- *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
- *  callback.
- *  @return The previously set callback, or `NULL` if no callback was set or the
- *  library had not been [initialized](@ref intro_init).
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref input_mouse_button
- *
- *  @since Added in GLFW 1.0.
- *
- *  @par
- *  __GLFW 3:__ Added window handle parameter.  Updated callback signature.
- *
- *  @ingroup input
- */
-GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* window, GLFWmousebuttonfun cbfun);
-
-/*! @brief Sets the cursor position callback.
- *
- *  This function sets the cursor position callback of the specified window,
- *  which is called when the cursor is moved.  The callback is provided with the
- *  position, in screen coordinates, relative to the upper-left corner of the
- *  client area of the window.
- *
- *  @param[in] window The window whose callback to set.
- *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
- *  callback.
- *  @return The previously set callback, or `NULL` if no callback was set or the
- *  library had not been [initialized](@ref intro_init).
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref cursor_pos
- *
- *  @since Added in GLFW 3.0.  Replaces `glfwSetMousePosCallback`.
- *
- *  @ingroup input
- */
-GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* window, GLFWcursorposfun cbfun);
-
-/*! @brief Sets the cursor enter/exit callback.
- *
- *  This function sets the cursor boundary crossing callback of the specified
- *  window, which is called when the cursor enters or leaves the client area of
- *  the window.
- *
- *  @param[in] window The window whose callback to set.
- *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
- *  callback.
- *  @return The previously set callback, or `NULL` if no callback was set or the
- *  library had not been [initialized](@ref intro_init).
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref cursor_enter
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup input
- */
-GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* window, GLFWcursorenterfun cbfun);
-
-/*! @brief Sets the scroll callback.
- *
- *  This function sets the scroll callback of the specified window, which is
- *  called when a scrolling device is used, such as a mouse wheel or scrolling
- *  area of a touchpad.
- *
- *  The scroll callback receives all scrolling input, like that from a mouse
- *  wheel or a touchpad scrolling area.
- *
- *  @param[in] window The window whose callback to set.
- *  @param[in] cbfun The new scroll callback, or `NULL` to remove the currently
- *  set callback.
- *  @return The previously set callback, or `NULL` if no callback was set or the
- *  library had not been [initialized](@ref intro_init).
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref scrolling
- *
- *  @since Added in GLFW 3.0.  Replaces `glfwSetMouseWheelCallback`.
- *
- *  @ingroup input
- */
-GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun cbfun);
-
-/*! @brief Sets the file drop callback.
- *
- *  This function sets the file drop callback of the specified window, which is
- *  called when one or more dragged files are dropped on the window.
- *
- *  Because the path array and its strings may have been generated specifically
- *  for that event, they are not guaranteed to be valid after the callback has
- *  returned.  If you wish to use them after the callback returns, you need to
- *  make a deep copy.
- *
- *  @param[in] window The window whose callback to set.
- *  @param[in] cbfun The new file drop callback, or `NULL` to remove the
- *  currently set callback.
- *  @return The previously set callback, or `NULL` if no callback was set or the
- *  library had not been [initialized](@ref intro_init).
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref path_drop
- *
- *  @since Added in GLFW 3.1.
- *
- *  @ingroup input
- */
-GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* window, GLFWdropfun cbfun);
-
-/*! @brief Returns whether the specified joystick is present.
- *
- *  This function returns whether the specified joystick is present.
- *
- *  @param[in] joy The [joystick](@ref joysticks) to query.
- *  @return `GL_TRUE` if the joystick is present, or `GL_FALSE` otherwise.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref joystick
- *
- *  @since Added in GLFW 3.0.  Replaces `glfwGetJoystickParam`.
- *
- *  @ingroup input
- */
-GLFWAPI int glfwJoystickPresent(int joy);
-
-/*! @brief Returns the values of all axes of the specified joystick.
- *
- *  This function returns the values of all axes of the specified joystick.
- *  Each element in the array is a value between -1.0 and 1.0.
- *
- *  @param[in] joy The [joystick](@ref joysticks) to query.
- *  @param[out] count Where to store the number of axis values in the returned
- *  array.  This is set to zero if an error occurred.
- *  @return An array of axis values, or `NULL` if the joystick is not present.
- *
- *  @par Pointer Lifetime
- *  The returned array is allocated and freed by GLFW.  You should not free it
- *  yourself.  It is valid until the specified joystick is disconnected, this
- *  function is called again for that joystick or the library is terminated.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref joystick_axis
- *
- *  @since Added in GLFW 3.0.  Replaces `glfwGetJoystickPos`.
- *
- *  @ingroup input
- */
-GLFWAPI const float* glfwGetJoystickAxes(int joy, int* count);
-
-/*! @brief Returns the state of all buttons of the specified joystick.
- *
- *  This function returns the state of all buttons of the specified joystick.
- *  Each element in the array is either `GLFW_PRESS` or `GLFW_RELEASE`.
- *
- *  @param[in] joy The [joystick](@ref joysticks) to query.
- *  @param[out] count Where to store the number of button states in the returned
- *  array.  This is set to zero if an error occurred.
- *  @return An array of button states, or `NULL` if the joystick is not present.
- *
- *  @par Pointer Lifetime
- *  The returned array is allocated and freed by GLFW.  You should not free it
- *  yourself.  It is valid until the specified joystick is disconnected, this
- *  function is called again for that joystick or the library is terminated.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref joystick_button
- *
- *  @since Added in GLFW 2.2.
- *
- *  @par
- *  __GLFW 3:__ Changed to return a dynamic array.
- *
- *  @ingroup input
- */
-GLFWAPI const unsigned char* glfwGetJoystickButtons(int joy, int* count);
-
-/*! @brief Returns the name of the specified joystick.
- *
- *  This function returns the name, encoded as UTF-8, of the specified joystick.
- *  The returned string is allocated and freed by GLFW.  You should not free it
- *  yourself.
- *
- *  @param[in] joy The [joystick](@ref joysticks) to query.
- *  @return The UTF-8 encoded name of the joystick, or `NULL` if the joystick
- *  is not present.
- *
- *  @par Pointer Lifetime
- *  The returned string is allocated and freed by GLFW.  You should not free it
- *  yourself.  It is valid until the specified joystick is disconnected, this
- *  function is called again for that joystick or the library is terminated.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref joystick_name
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup input
- */
-GLFWAPI const char* glfwGetJoystickName(int joy);
-
-/*! @brief Sets the clipboard to the specified string.
- *
- *  This function sets the system clipboard to the specified, UTF-8 encoded
- *  string.
- *
- *  @param[in] window The window that will own the clipboard contents.
- *  @param[in] string A UTF-8 encoded string.
- *
- *  @par Pointer Lifetime
- *  The specified string is copied before this function returns.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref clipboard
- *  @sa glfwGetClipboardString
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup input
- */
-GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string);
-
-/*! @brief Returns the contents of the clipboard as a string.
- *
- *  This function returns the contents of the system clipboard, if it contains
- *  or is convertible to a UTF-8 encoded string.
- *
- *  @param[in] window The window that will request the clipboard contents.
- *  @return The contents of the clipboard as a UTF-8 encoded string, or `NULL`
- *  if an [error](@ref error_handling) occurred.
- *
- *  @par Pointer Lifetime
- *  The returned string is allocated and freed by GLFW.  You should not free it
- *  yourself.  It is valid until the next call to @ref
- *  glfwGetClipboardString or @ref glfwSetClipboardString, or until the library
- *  is terminated.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref clipboard
- *  @sa glfwSetClipboardString
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup input
- */
-GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window);
-
-/*! @brief Returns the value of the GLFW timer.
- *
- *  This function returns the value of the GLFW timer.  Unless the timer has
- *  been set using @ref glfwSetTime, the timer measures time elapsed since GLFW
- *  was initialized.
- *
- *  The resolution of the timer is system dependent, but is usually on the order
- *  of a few micro- or nanoseconds.  It uses the highest-resolution monotonic
- *  time source on each supported platform.
- *
- *  @return The current value, in seconds, or zero if an
- *  [error](@ref error_handling) occurred.
- *
- *  @par Thread Safety
- *  This function may be called from any thread.  Access is not synchronized.
- *
- *  @sa @ref time
- *
- *  @since Added in GLFW 1.0.
- *
- *  @ingroup input
- */
-GLFWAPI double glfwGetTime(void);
-
-/*! @brief Sets the GLFW timer.
- *
- *  This function sets the value of the GLFW timer.  It then continues to count
- *  up from that value.  The value must be a positive finite number.
- *
- *  @param[in] time The new value, in seconds.
- *
- *  @par Thread Safety
- *  This function may only be called from the main thread.
- *
- *  @sa @ref time
- *
- *  @since Added in GLFW 2.2.
- *
- *  @ingroup input
- */
-GLFWAPI void glfwSetTime(double time);
-
-/*! @brief Makes the context of the specified window current for the calling
- *  thread.
- *
- *  This function makes the OpenGL or OpenGL ES context of the specified window
- *  current on the calling thread.  A context can only be made current on
- *  a single thread at a time and each thread can have only a single current
- *  context at a time.
- *
- *  By default, making a context non-current implicitly forces a pipeline flush.
- *  On machines that support `GL_KHR_context_flush_control`, you can control
- *  whether a context performs this flush by setting the
- *  [GLFW_CONTEXT_RELEASE_BEHAVIOR](@ref window_hints_ctx) window hint.
- *
- *  @param[in] window The window whose context to make current, or `NULL` to
- *  detach the current context.
- *
- *  @par Thread Safety
- *  This function may be called from any thread.
- *
- *  @sa @ref context_current
- *  @sa glfwGetCurrentContext
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup context
- */
-GLFWAPI void glfwMakeContextCurrent(GLFWwindow* window);
-
-/*! @brief Returns the window whose context is current on the calling thread.
- *
- *  This function returns the window whose OpenGL or OpenGL ES context is
- *  current on the calling thread.
- *
- *  @return The window whose context is current, or `NULL` if no window's
- *  context is current.
- *
- *  @par Thread Safety
- *  This function may be called from any thread.
- *
- *  @sa @ref context_current
- *  @sa glfwMakeContextCurrent
- *
- *  @since Added in GLFW 3.0.
- *
- *  @ingroup context
- */
-GLFWAPI GLFWwindow* glfwGetCurrentContext(void);
-
-/*! @brief Swaps the front and back buffers of the specified window.
- *
- *  This function swaps the front and back buffers of the specified window.  If
- *  the swap interval is greater than zero, the GPU driver waits the specified
- *  number of screen updates before swapping the buffers.
- *
- *  @param[in] window The window whose buffers to swap.
- *
- *  @par Thread Safety
- *  This function may be called from any thread.
- *
- *  @sa @ref buffer_swap
- *  @sa glfwSwapInterval
- *
- *  @since Added in GLFW 1.0.
- *
- *  @par
- *  __GLFW 3:__ Added window handle parameter.
- *
- *  @ingroup window
- */
-GLFWAPI void glfwSwapBuffers(GLFWwindow* window);
-
-/*! @brief Sets the swap interval for the current context.
- *
- *  This function sets the swap interval for the current context, i.e. the
- *  number of screen updates to wait from the time @ref glfwSwapBuffers was
- *  called before swapping the buffers and returning.  This is sometimes called
- *  _vertical synchronization_, _vertical retrace synchronization_ or just
- *  _vsync_.
- *
- *  Contexts that support either of the `WGL_EXT_swap_control_tear` and
- *  `GLX_EXT_swap_control_tear` extensions also accept negative swap intervals,
- *  which allow the driver to swap even if a frame arrives a little bit late.
- *  You can check for the presence of these extensions using @ref
- *  glfwExtensionSupported.  For more information about swap tearing, see the
- *  extension specifications.
- *
- *  A context must be current on the calling thread.  Calling this function
- *  without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error.
- *
- *  @param[in] interval The minimum number of screen updates to wait for
- *  until the buffers are swapped by @ref glfwSwapBuffers.
- *
- *  @remarks This function is not called during context creation, leaving the
- *  swap interval set to whatever is the default on that platform.  This is done
- *  because some swap interval extensions used by GLFW do not allow the swap
- *  interval to be reset to zero once it has been set to a non-zero value.
- *
- *  @remarks Some GPU drivers do not honor the requested swap interval, either
- *  because of a user setting that overrides the application's request or due to
- *  bugs in the driver.
- *
- *  @par Thread Safety
- *  This function may be called from any thread.
- *
- *  @sa @ref buffer_swap
- *  @sa glfwSwapBuffers
- *
- *  @since Added in GLFW 1.0.
- *
- *  @ingroup context
- */
-GLFWAPI void glfwSwapInterval(int interval);
-
-/*! @brief Returns whether the specified extension is available.
- *
- *  This function returns whether the specified
- *  [client API extension](@ref context_glext) is supported by the current
- *  OpenGL or OpenGL ES context.  It searches both for OpenGL and OpenGL ES
- *  extension and platform-specific context creation API extensions.
- *
- *  A context must be current on the calling thread.  Calling this function
- *  without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error.
- *
- *  As this functions retrieves and searches one or more extension strings each
- *  call, it is recommended that you cache its results if it is going to be used
- *  frequently.  The extension strings will not change during the lifetime of
- *  a context, so there is no danger in doing this.
- *
- *  @param[in] extension The ASCII encoded name of the extension.
- *  @return `GL_TRUE` if the extension is available, or `GL_FALSE` otherwise.
- *
- *  @par Thread Safety
- *  This function may be called from any thread.
- *
- *  @sa @ref context_glext
- *  @sa glfwGetProcAddress
- *
- *  @since Added in GLFW 1.0.
- *
- *  @ingroup context
- */
-GLFWAPI int glfwExtensionSupported(const char* extension);
-
-/*! @brief Returns the address of the specified function for the current
- *  context.
- *
- *  This function returns the address of the specified
- *  [core or extension function](@ref context_glext), if it is supported
- *  by the current context.
- *
- *  A context must be current on the calling thread.  Calling this function
- *  without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error.
- *
- *  @param[in] procname The ASCII encoded name of the function.
- *  @return The address of the function, or `NULL` if the function is
- *  unavailable or an [error](@ref error_handling) occurred.
- *
- *  @remarks The addresses of a given function is not guaranteed to be the same
- *  between contexts.
- *
- *  @remarks This function may return a non-`NULL` address despite the
- *  associated version or extension not being available.  Always check the
- *  context version or extension string presence first.
- *
- *  @par Pointer Lifetime
- *  The returned function pointer is valid until the context is destroyed or the
- *  library is terminated.
- *
- *  @par Thread Safety
- *  This function may be called from any thread.
- *
- *  @sa @ref context_glext
- *  @sa glfwExtensionSupported
- *
- *  @since Added in GLFW 1.0.
- *
- *  @ingroup context
- */
-GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname);
+ * GLFW 3.2 - www.glfw.org
+ * A library for OpenGL, window and input
+ *------------------------------------------------------------------------
+ * Copyright (c) 2002-2006 Marcus Geelnard
+ * Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
+ *
+ * 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.
+ *
+ *************************************************************************/
+
+#ifndef _glfw3_h_
+#define _glfw3_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*************************************************************************
+ * Doxygen documentation
+ *************************************************************************/
+
+/*! @file glfw3.h
+ *  @brief The header of the GLFW 3 API.
+ *
+ *  This is the header file of the GLFW 3 API.  It defines all its types and
+ *  declares all its functions.
+ *
+ *  For more information about how to use this file, see @ref build_include.
+ */
+/*! @defgroup context Context reference
+ *
+ *  This is the reference documentation for OpenGL and OpenGL ES context related
+ *  functions.  For more task-oriented information, see the @ref context_guide.
+ */
+/*! @defgroup vulkan Vulkan reference
+ *
+ *  This is the reference documentation for Vulkan related functions and types.
+ *  For more task-oriented information, see the @ref vulkan_guide.
+ */
+/*! @defgroup init Initialization, version and error reference
+ *
+ *  This is the reference documentation for initialization and termination of
+ *  the library, version management and error handling.  For more task-oriented
+ *  information, see the @ref intro_guide.
+ */
+/*! @defgroup input Input reference
+ *
+ *  This is the reference documentation for input related functions and types.
+ *  For more task-oriented information, see the @ref input_guide.
+ */
+/*! @defgroup monitor Monitor reference
+ *
+ *  This is the reference documentation for monitor related functions and types.
+ *  For more task-oriented information, see the @ref monitor_guide.
+ */
+/*! @defgroup window Window reference
+ *
+ *  This is the reference documentation for window related functions and types,
+ *  including creation, deletion and event polling.  For more task-oriented
+ *  information, see the @ref window_guide.
+ */
+
+
+/*************************************************************************
+ * Compiler- and platform-specific preprocessor work
+ *************************************************************************/
+
+/* If we are we on Windows, we want a single define for it.
+ */
+#if !defined(_WIN32) && (defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__))
+ #define _WIN32
+#endif /* _WIN32 */
+
+/* It is customary to use APIENTRY for OpenGL function pointer declarations on
+ * all platforms.  Additionally, the Windows OpenGL header needs APIENTRY.
+ */
+#ifndef APIENTRY
+ #ifdef _WIN32
+  #define APIENTRY __stdcall
+ #else
+  #define APIENTRY
+ #endif
+#endif /* APIENTRY */
+
+/* Some Windows OpenGL headers need this.
+ */
+#if !defined(WINGDIAPI) && defined(_WIN32)
+ #define WINGDIAPI __declspec(dllimport)
+ #define GLFW_WINGDIAPI_DEFINED
+#endif /* WINGDIAPI */
+
+/* Some Windows GLU headers need this.
+ */
+#if !defined(CALLBACK) && defined(_WIN32)
+ #define CALLBACK __stdcall
+ #define GLFW_CALLBACK_DEFINED
+#endif /* CALLBACK */
+
+/* Include because most Windows GLU headers need wchar_t and
+ * the OS X OpenGL header blocks the definition of ptrdiff_t by glext.h.
+ * Include it unconditionally to avoid surprising side-effects.
+ */
+#include <stddef.h>
+
+/* Include because it is needed by Vulkan and related functions.
+ */
+#include <stdint.h>
+
+/* Include the chosen client API headers.
+ */
+#if defined(__APPLE__)
+ #if defined(GLFW_INCLUDE_GLCOREARB)
+  #include <OpenGL/gl3.h>
+  #if defined(GLFW_INCLUDE_GLEXT)
+   #include <OpenGL/gl3ext.h>
+  #endif
+ #elif !defined(GLFW_INCLUDE_NONE)
+  #if !defined(GLFW_INCLUDE_GLEXT)
+   #define GL_GLEXT_LEGACY
+  #endif
+  #include <OpenGL/gl.h>
+ #endif
+ #if defined(GLFW_INCLUDE_GLU)
+  #include <OpenGL/glu.h>
+ #endif
+#else
+ #if defined(GLFW_INCLUDE_GLCOREARB)
+  #include <GL/glcorearb.h>
+ #elif defined(GLFW_INCLUDE_ES1)
+  #include <GLES/gl.h>
+  #if defined(GLFW_INCLUDE_GLEXT)
+   #include <GLES/glext.h>
+  #endif
+ #elif defined(GLFW_INCLUDE_ES2)
+  #include <GLES2/gl2.h>
+  #if defined(GLFW_INCLUDE_GLEXT)
+   #include <GLES2/gl2ext.h>
+  #endif
+ #elif defined(GLFW_INCLUDE_ES3)
+  #include <GLES3/gl3.h>
+  #if defined(GLFW_INCLUDE_GLEXT)
+   #include <GLES2/gl2ext.h>
+  #endif
+ #elif defined(GLFW_INCLUDE_ES31)
+  #include <GLES3/gl31.h>
+  #if defined(GLFW_INCLUDE_GLEXT)
+   #include <GLES2/gl2ext.h>
+  #endif
+ #elif defined(GLFW_INCLUDE_VULKAN)
+  #include <vulkan/vulkan.h>
+ #elif !defined(GLFW_INCLUDE_NONE)
+  #include <GL/gl.h>
+  #if defined(GLFW_INCLUDE_GLEXT)
+   #include <GL/glext.h>
+  #endif
+ #endif
+ #if defined(GLFW_INCLUDE_GLU)
+  #include <GL/glu.h>
+ #endif
+#endif
+
+#if defined(GLFW_DLL) && defined(_GLFW_BUILD_DLL)
+ /* GLFW_DLL must be defined by applications that are linking against the DLL
+  * version of the GLFW library.  _GLFW_BUILD_DLL is defined by the GLFW
+  * configuration header when compiling the DLL version of the library.
+  */
+ #error "You must not have both GLFW_DLL and _GLFW_BUILD_DLL defined"
+#endif
+
+/* GLFWAPI is used to declare public API functions for export
+ * from the DLL / shared library / dynamic library.
+ */
+#if defined(_WIN32) && defined(_GLFW_BUILD_DLL)
+ /* We are building GLFW as a Win32 DLL */
+ #define GLFWAPI __declspec(dllexport)
+#elif defined(_WIN32) && defined(GLFW_DLL)
+ /* We are calling GLFW as a Win32 DLL */
+ #define GLFWAPI __declspec(dllimport)
+#elif defined(__GNUC__) && defined(_GLFW_BUILD_DLL)
+ /* We are building GLFW as a shared / dynamic library */
+ #define GLFWAPI __attribute__((visibility("default")))
+#else
+ /* We are building or calling GLFW as a static library */
+ #define GLFWAPI
+#endif
+
+
+/*************************************************************************
+ * GLFW API tokens
+ *************************************************************************/
+
+/*! @name GLFW version macros
+ *  @{ */
+/*! @brief The major version number of the GLFW library.
+ *
+ *  This is incremented when the API is changed in non-compatible ways.
+ *  @ingroup init
+ */
+#define GLFW_VERSION_MAJOR          3
+/*! @brief The minor version number of the GLFW library.
+ *
+ *  This is incremented when features are added to the API but it remains
+ *  backward-compatible.
+ *  @ingroup init
+ */
+#define GLFW_VERSION_MINOR          2
+/*! @brief The revision number of the GLFW library.
+ *
+ *  This is incremented when a bug fix release is made that does not contain any
+ *  API changes.
+ *  @ingroup init
+ */
+#define GLFW_VERSION_REVISION       1
+/*! @} */
+
+/*! @name Boolean values
+ *  @{ */
+/*! @brief One.
+ *
+ *  One.  Seriously.  You don't _need_ to use this symbol in your code.  It's
+ *  just semantic sugar for the number 1.  You can use `1` or `true` or `_True`
+ *  or `GL_TRUE` or whatever you want.
+ */
+#define GLFW_TRUE                   1
+/*! @brief Zero.
+ *
+ *  Zero.  Seriously.  You don't _need_ to use this symbol in your code.  It's
+ *  just just semantic sugar for the number 0.  You can use `0` or `false` or
+ *  `_False` or `GL_FALSE` or whatever you want.
+ */
+#define GLFW_FALSE                  0
+/*! @} */
+
+/*! @name Key and button actions
+ *  @{ */
+/*! @brief The key or mouse button was released.
+ *
+ *  The key or mouse button was released.
+ *
+ *  @ingroup input
+ */
+#define GLFW_RELEASE                0
+/*! @brief The key or mouse button was pressed.
+ *
+ *  The key or mouse button was pressed.
+ *
+ *  @ingroup input
+ */
+#define GLFW_PRESS                  1
+/*! @brief The key was held down until it repeated.
+ *
+ *  The key was held down until it repeated.
+ *
+ *  @ingroup input
+ */
+#define GLFW_REPEAT                 2
+/*! @} */
+
+/*! @defgroup keys Keyboard keys
+ *
+ *  See [key input](@ref input_key) for how these are used.
+ *
+ *  These key codes are inspired by the _USB HID Usage Tables v1.12_ (p. 53-60),
+ *  but re-arranged to map to 7-bit ASCII for printable keys (function keys are
+ *  put in the 256+ range).
+ *
+ *  The naming of the key codes follow these rules:
+ *   - The US keyboard layout is used
+ *   - Names of printable alpha-numeric characters are used (e.g. "A", "R",
+ *     "3", etc.)
+ *   - For non-alphanumeric characters, Unicode:ish names are used (e.g.
+ *     "COMMA", "LEFT_SQUARE_BRACKET", etc.). Note that some names do not
+ *     correspond to the Unicode standard (usually for brevity)
+ *   - Keys that lack a clear US mapping are named "WORLD_x"
+ *   - For non-printable keys, custom names are used (e.g. "F4",
+ *     "BACKSPACE", etc.)
+ *
+ *  @ingroup input
+ *  @{
+ */
+
+/* The unknown key */
+#define GLFW_KEY_UNKNOWN            -1
+
+/* Printable keys */
+#define GLFW_KEY_SPACE              32
+#define GLFW_KEY_APOSTROPHE         39  /* ' */
+#define GLFW_KEY_COMMA              44  /* , */
+#define GLFW_KEY_MINUS              45  /* - */
+#define GLFW_KEY_PERIOD             46  /* . */
+#define GLFW_KEY_SLASH              47  /* / */
+#define GLFW_KEY_0                  48
+#define GLFW_KEY_1                  49
+#define GLFW_KEY_2                  50
+#define GLFW_KEY_3                  51
+#define GLFW_KEY_4                  52
+#define GLFW_KEY_5                  53
+#define GLFW_KEY_6                  54
+#define GLFW_KEY_7                  55
+#define GLFW_KEY_8                  56
+#define GLFW_KEY_9                  57
+#define GLFW_KEY_SEMICOLON          59  /* ; */
+#define GLFW_KEY_EQUAL              61  /* = */
+#define GLFW_KEY_A                  65
+#define GLFW_KEY_B                  66
+#define GLFW_KEY_C                  67
+#define GLFW_KEY_D                  68
+#define GLFW_KEY_E                  69
+#define GLFW_KEY_F                  70
+#define GLFW_KEY_G                  71
+#define GLFW_KEY_H                  72
+#define GLFW_KEY_I                  73
+#define GLFW_KEY_J                  74
+#define GLFW_KEY_K                  75
+#define GLFW_KEY_L                  76
+#define GLFW_KEY_M                  77
+#define GLFW_KEY_N                  78
+#define GLFW_KEY_O                  79
+#define GLFW_KEY_P                  80
+#define GLFW_KEY_Q                  81
+#define GLFW_KEY_R                  82
+#define GLFW_KEY_S                  83
+#define GLFW_KEY_T                  84
+#define GLFW_KEY_U                  85
+#define GLFW_KEY_V                  86
+#define GLFW_KEY_W                  87
+#define GLFW_KEY_X                  88
+#define GLFW_KEY_Y                  89
+#define GLFW_KEY_Z                  90
+#define GLFW_KEY_LEFT_BRACKET       91  /* [ */
+#define GLFW_KEY_BACKSLASH          92  /* \ */
+#define GLFW_KEY_RIGHT_BRACKET      93  /* ] */
+#define GLFW_KEY_GRAVE_ACCENT       96  /* ` */
+#define GLFW_KEY_WORLD_1            161 /* non-US #1 */
+#define GLFW_KEY_WORLD_2            162 /* non-US #2 */
+
+/* Function keys */
+#define GLFW_KEY_ESCAPE             256
+#define GLFW_KEY_ENTER              257
+#define GLFW_KEY_TAB                258
+#define GLFW_KEY_BACKSPACE          259
+#define GLFW_KEY_INSERT             260
+#define GLFW_KEY_DELETE             261
+#define GLFW_KEY_RIGHT              262
+#define GLFW_KEY_LEFT               263
+#define GLFW_KEY_DOWN               264
+#define GLFW_KEY_UP                 265
+#define GLFW_KEY_PAGE_UP            266
+#define GLFW_KEY_PAGE_DOWN          267
+#define GLFW_KEY_HOME               268
+#define GLFW_KEY_END                269
+#define GLFW_KEY_CAPS_LOCK          280
+#define GLFW_KEY_SCROLL_LOCK        281
+#define GLFW_KEY_NUM_LOCK           282
+#define GLFW_KEY_PRINT_SCREEN       283
+#define GLFW_KEY_PAUSE              284
+#define GLFW_KEY_F1                 290
+#define GLFW_KEY_F2                 291
+#define GLFW_KEY_F3                 292
+#define GLFW_KEY_F4                 293
+#define GLFW_KEY_F5                 294
+#define GLFW_KEY_F6                 295
+#define GLFW_KEY_F7                 296
+#define GLFW_KEY_F8                 297
+#define GLFW_KEY_F9                 298
+#define GLFW_KEY_F10                299
+#define GLFW_KEY_F11                300
+#define GLFW_KEY_F12                301
+#define GLFW_KEY_F13                302
+#define GLFW_KEY_F14                303
+#define GLFW_KEY_F15                304
+#define GLFW_KEY_F16                305
+#define GLFW_KEY_F17                306
+#define GLFW_KEY_F18                307
+#define GLFW_KEY_F19                308
+#define GLFW_KEY_F20                309
+#define GLFW_KEY_F21                310
+#define GLFW_KEY_F22                311
+#define GLFW_KEY_F23                312
+#define GLFW_KEY_F24                313
+#define GLFW_KEY_F25                314
+#define GLFW_KEY_KP_0               320
+#define GLFW_KEY_KP_1               321
+#define GLFW_KEY_KP_2               322
+#define GLFW_KEY_KP_3               323
+#define GLFW_KEY_KP_4               324
+#define GLFW_KEY_KP_5               325
+#define GLFW_KEY_KP_6               326
+#define GLFW_KEY_KP_7               327
+#define GLFW_KEY_KP_8               328
+#define GLFW_KEY_KP_9               329
+#define GLFW_KEY_KP_DECIMAL         330
+#define GLFW_KEY_KP_DIVIDE          331
+#define GLFW_KEY_KP_MULTIPLY        332
+#define GLFW_KEY_KP_SUBTRACT        333
+#define GLFW_KEY_KP_ADD             334
+#define GLFW_KEY_KP_ENTER           335
+#define GLFW_KEY_KP_EQUAL           336
+#define GLFW_KEY_LEFT_SHIFT         340
+#define GLFW_KEY_LEFT_CONTROL       341
+#define GLFW_KEY_LEFT_ALT           342
+#define GLFW_KEY_LEFT_SUPER         343
+#define GLFW_KEY_RIGHT_SHIFT        344
+#define GLFW_KEY_RIGHT_CONTROL      345
+#define GLFW_KEY_RIGHT_ALT          346
+#define GLFW_KEY_RIGHT_SUPER        347
+#define GLFW_KEY_MENU               348
+
+#define GLFW_KEY_LAST               GLFW_KEY_MENU
+
+/*! @} */
+
+/*! @defgroup mods Modifier key flags
+ *
+ *  See [key input](@ref input_key) for how these are used.
+ *
+ *  @ingroup input
+ *  @{ */
+
+/*! @brief If this bit is set one or more Shift keys were held down.
+ */
+#define GLFW_MOD_SHIFT           0x0001
+/*! @brief If this bit is set one or more Control keys were held down.
+ */
+#define GLFW_MOD_CONTROL         0x0002
+/*! @brief If this bit is set one or more Alt keys were held down.
+ */
+#define GLFW_MOD_ALT             0x0004
+/*! @brief If this bit is set one or more Super keys were held down.
+ */
+#define GLFW_MOD_SUPER           0x0008
+
+/*! @} */
+
+/*! @defgroup buttons Mouse buttons
+ *
+ *  See [mouse button input](@ref input_mouse_button) for how these are used.
+ *
+ *  @ingroup input
+ *  @{ */
+#define GLFW_MOUSE_BUTTON_1         0
+#define GLFW_MOUSE_BUTTON_2         1
+#define GLFW_MOUSE_BUTTON_3         2
+#define GLFW_MOUSE_BUTTON_4         3
+#define GLFW_MOUSE_BUTTON_5         4
+#define GLFW_MOUSE_BUTTON_6         5
+#define GLFW_MOUSE_BUTTON_7         6
+#define GLFW_MOUSE_BUTTON_8         7
+#define GLFW_MOUSE_BUTTON_LAST      GLFW_MOUSE_BUTTON_8
+#define GLFW_MOUSE_BUTTON_LEFT      GLFW_MOUSE_BUTTON_1
+#define GLFW_MOUSE_BUTTON_RIGHT     GLFW_MOUSE_BUTTON_2
+#define GLFW_MOUSE_BUTTON_MIDDLE    GLFW_MOUSE_BUTTON_3
+/*! @} */
+
+/*! @defgroup joysticks Joysticks
+ *
+ *  See [joystick input](@ref joystick) for how these are used.
+ *
+ *  @ingroup input
+ *  @{ */
+#define GLFW_JOYSTICK_1             0
+#define GLFW_JOYSTICK_2             1
+#define GLFW_JOYSTICK_3             2
+#define GLFW_JOYSTICK_4             3
+#define GLFW_JOYSTICK_5             4
+#define GLFW_JOYSTICK_6             5
+#define GLFW_JOYSTICK_7             6
+#define GLFW_JOYSTICK_8             7
+#define GLFW_JOYSTICK_9             8
+#define GLFW_JOYSTICK_10            9
+#define GLFW_JOYSTICK_11            10
+#define GLFW_JOYSTICK_12            11
+#define GLFW_JOYSTICK_13            12
+#define GLFW_JOYSTICK_14            13
+#define GLFW_JOYSTICK_15            14
+#define GLFW_JOYSTICK_16            15
+#define GLFW_JOYSTICK_LAST          GLFW_JOYSTICK_16
+/*! @} */
+
+/*! @defgroup errors Error codes
+ *
+ *  See [error handling](@ref error_handling) for how these are used.
+ *
+ *  @ingroup init
+ *  @{ */
+/*! @brief GLFW has not been initialized.
+ *
+ *  This occurs if a GLFW function was called that must not be called unless the
+ *  library is [initialized](@ref intro_init).
+ *
+ *  @analysis Application programmer error.  Initialize GLFW before calling any
+ *  function that requires initialization.
+ */
+#define GLFW_NOT_INITIALIZED        0x00010001
+/*! @brief No context is current for this thread.
+ *
+ *  This occurs if a GLFW function was called that needs and operates on the
+ *  current OpenGL or OpenGL ES context but no context is current on the calling
+ *  thread.  One such function is @ref glfwSwapInterval.
+ *
+ *  @analysis Application programmer error.  Ensure a context is current before
+ *  calling functions that require a current context.
+ */
+#define GLFW_NO_CURRENT_CONTEXT     0x00010002
+/*! @brief One of the arguments to the function was an invalid enum value.
+ *
+ *  One of the arguments to the function was an invalid enum value, for example
+ *  requesting [GLFW_RED_BITS](@ref window_hints_fb) with @ref
+ *  glfwGetWindowAttrib.
+ *
+ *  @analysis Application programmer error.  Fix the offending call.
+ */
+#define GLFW_INVALID_ENUM           0x00010003
+/*! @brief One of the arguments to the function was an invalid value.
+ *
+ *  One of the arguments to the function was an invalid value, for example
+ *  requesting a non-existent OpenGL or OpenGL ES version like 2.7.
+ *
+ *  Requesting a valid but unavailable OpenGL or OpenGL ES version will instead
+ *  result in a @ref GLFW_VERSION_UNAVAILABLE error.
+ *
+ *  @analysis Application programmer error.  Fix the offending call.
+ */
+#define GLFW_INVALID_VALUE          0x00010004
+/*! @brief A memory allocation failed.
+ *
+ *  A memory allocation failed.
+ *
+ *  @analysis A bug in GLFW or the underlying operating system.  Report the bug
+ *  to our [issue tracker](https://github.com/glfw/glfw/issues).
+ */
+#define GLFW_OUT_OF_MEMORY          0x00010005
+/*! @brief GLFW could not find support for the requested API on the system.
+ *
+ *  GLFW could not find support for the requested API on the system.
+ *
+ *  @analysis The installed graphics driver does not support the requested
+ *  API, or does not support it via the chosen context creation backend.
+ *  Below are a few examples.
+ *
+ *  @par
+ *  Some pre-installed Windows graphics drivers do not support OpenGL.  AMD only
+ *  supports OpenGL ES via EGL, while Nvidia and Intel only support it via
+ *  a WGL or GLX extension.  OS X does not provide OpenGL ES at all.  The Mesa
+ *  EGL, OpenGL and OpenGL ES libraries do not interface with the Nvidia binary
+ *  driver.  Older graphics drivers do not support Vulkan.
+ */
+#define GLFW_API_UNAVAILABLE        0x00010006
+/*! @brief The requested OpenGL or OpenGL ES version is not available.
+ *
+ *  The requested OpenGL or OpenGL ES version (including any requested context
+ *  or framebuffer hints) is not available on this machine.
+ *
+ *  @analysis The machine does not support your requirements.  If your
+ *  application is sufficiently flexible, downgrade your requirements and try
+ *  again.  Otherwise, inform the user that their machine does not match your
+ *  requirements.
+ *
+ *  @par
+ *  Future invalid OpenGL and OpenGL ES versions, for example OpenGL 4.8 if 5.0
+ *  comes out before the 4.x series gets that far, also fail with this error and
+ *  not @ref GLFW_INVALID_VALUE, because GLFW cannot know what future versions
+ *  will exist.
+ */
+#define GLFW_VERSION_UNAVAILABLE    0x00010007
+/*! @brief A platform-specific error occurred that does not match any of the
+ *  more specific categories.
+ *
+ *  A platform-specific error occurred that does not match any of the more
+ *  specific categories.
+ *
+ *  @analysis A bug or configuration error in GLFW, the underlying operating
+ *  system or its drivers, or a lack of required resources.  Report the issue to
+ *  our [issue tracker](https://github.com/glfw/glfw/issues).
+ */
+#define GLFW_PLATFORM_ERROR         0x00010008
+/*! @brief The requested format is not supported or available.
+ *
+ *  If emitted during window creation, the requested pixel format is not
+ *  supported.
+ *
+ *  If emitted when querying the clipboard, the contents of the clipboard could
+ *  not be converted to the requested format.
+ *
+ *  @analysis If emitted during window creation, one or more
+ *  [hard constraints](@ref window_hints_hard) did not match any of the
+ *  available pixel formats.  If your application is sufficiently flexible,
+ *  downgrade your requirements and try again.  Otherwise, inform the user that
+ *  their machine does not match your requirements.
+ *
+ *  @par
+ *  If emitted when querying the clipboard, ignore the error or report it to
+ *  the user, as appropriate.
+ */
+#define GLFW_FORMAT_UNAVAILABLE     0x00010009
+/*! @brief The specified window does not have an OpenGL or OpenGL ES context.
+ *
+ *  A window that does not have an OpenGL or OpenGL ES context was passed to
+ *  a function that requires it to have one.
+ *
+ *  @analysis Application programmer error.  Fix the offending call.
+ */
+#define GLFW_NO_WINDOW_CONTEXT      0x0001000A
+/*! @} */
+
+#define GLFW_FOCUSED                0x00020001
+#define GLFW_ICONIFIED              0x00020002
+#define GLFW_RESIZABLE              0x00020003
+#define GLFW_VISIBLE                0x00020004
+#define GLFW_DECORATED              0x00020005
+#define GLFW_AUTO_ICONIFY           0x00020006
+#define GLFW_FLOATING               0x00020007
+#define GLFW_MAXIMIZED              0x00020008
+
+#define GLFW_RED_BITS               0x00021001
+#define GLFW_GREEN_BITS             0x00021002
+#define GLFW_BLUE_BITS              0x00021003
+#define GLFW_ALPHA_BITS             0x00021004
+#define GLFW_DEPTH_BITS             0x00021005
+#define GLFW_STENCIL_BITS           0x00021006
+#define GLFW_ACCUM_RED_BITS         0x00021007
+#define GLFW_ACCUM_GREEN_BITS       0x00021008
+#define GLFW_ACCUM_BLUE_BITS        0x00021009
+#define GLFW_ACCUM_ALPHA_BITS       0x0002100A
+#define GLFW_AUX_BUFFERS            0x0002100B
+#define GLFW_STEREO                 0x0002100C
+#define GLFW_SAMPLES                0x0002100D
+#define GLFW_SRGB_CAPABLE           0x0002100E
+#define GLFW_REFRESH_RATE           0x0002100F
+#define GLFW_DOUBLEBUFFER           0x00021010
+
+#define GLFW_CLIENT_API             0x00022001
+#define GLFW_CONTEXT_VERSION_MAJOR  0x00022002
+#define GLFW_CONTEXT_VERSION_MINOR  0x00022003
+#define GLFW_CONTEXT_REVISION       0x00022004
+#define GLFW_CONTEXT_ROBUSTNESS     0x00022005
+#define GLFW_OPENGL_FORWARD_COMPAT  0x00022006
+#define GLFW_OPENGL_DEBUG_CONTEXT   0x00022007
+#define GLFW_OPENGL_PROFILE         0x00022008
+#define GLFW_CONTEXT_RELEASE_BEHAVIOR 0x00022009
+#define GLFW_CONTEXT_NO_ERROR       0x0002200A
+#define GLFW_CONTEXT_CREATION_API   0x0002200B
+
+#define GLFW_NO_API                          0
+#define GLFW_OPENGL_API             0x00030001
+#define GLFW_OPENGL_ES_API          0x00030002
+
+#define GLFW_NO_ROBUSTNESS                   0
+#define GLFW_NO_RESET_NOTIFICATION  0x00031001
+#define GLFW_LOSE_CONTEXT_ON_RESET  0x00031002
+
+#define GLFW_OPENGL_ANY_PROFILE              0
+#define GLFW_OPENGL_CORE_PROFILE    0x00032001
+#define GLFW_OPENGL_COMPAT_PROFILE  0x00032002
+
+#define GLFW_CURSOR                 0x00033001
+#define GLFW_STICKY_KEYS            0x00033002
+#define GLFW_STICKY_MOUSE_BUTTONS   0x00033003
+
+#define GLFW_CURSOR_NORMAL          0x00034001
+#define GLFW_CURSOR_HIDDEN          0x00034002
+#define GLFW_CURSOR_DISABLED        0x00034003
+
+#define GLFW_ANY_RELEASE_BEHAVIOR            0
+#define GLFW_RELEASE_BEHAVIOR_FLUSH 0x00035001
+#define GLFW_RELEASE_BEHAVIOR_NONE  0x00035002
+
+#define GLFW_NATIVE_CONTEXT_API     0x00036001
+#define GLFW_EGL_CONTEXT_API        0x00036002
+
+/*! @defgroup shapes Standard cursor shapes
+ *
+ *  See [standard cursor creation](@ref cursor_standard) for how these are used.
+ *
+ *  @ingroup input
+ *  @{ */
+
+/*! @brief The regular arrow cursor shape.
+ *
+ *  The regular arrow cursor.
+ */
+#define GLFW_ARROW_CURSOR           0x00036001
+/*! @brief The text input I-beam cursor shape.
+ *
+ *  The text input I-beam cursor shape.
+ */
+#define GLFW_IBEAM_CURSOR           0x00036002
+/*! @brief The crosshair shape.
+ *
+ *  The crosshair shape.
+ */
+#define GLFW_CROSSHAIR_CURSOR       0x00036003
+/*! @brief The hand shape.
+ *
+ *  The hand shape.
+ */
+#define GLFW_HAND_CURSOR            0x00036004
+/*! @brief The horizontal resize arrow shape.
+ *
+ *  The horizontal resize arrow shape.
+ */
+#define GLFW_HRESIZE_CURSOR         0x00036005
+/*! @brief The vertical resize arrow shape.
+ *
+ *  The vertical resize arrow shape.
+ */
+#define GLFW_VRESIZE_CURSOR         0x00036006
+/*! @} */
+
+#define GLFW_CONNECTED              0x00040001
+#define GLFW_DISCONNECTED           0x00040002
+
+#define GLFW_DONT_CARE              -1
+
+
+/*************************************************************************
+ * GLFW API types
+ *************************************************************************/
+
+/*! @brief Client API function pointer type.
+ *
+ *  Generic function pointer used for returning client API function pointers
+ *  without forcing a cast from a regular pointer.
+ *
+ *  @sa @ref context_glext
+ *  @sa glfwGetProcAddress
+ *
+ *  @since Added in version 3.0.
+ 
+ *  @ingroup context
+ */
+typedef void (*GLFWglproc)(void);
+
+/*! @brief Vulkan API function pointer type.
+ *
+ *  Generic function pointer used for returning Vulkan API function pointers
+ *  without forcing a cast from a regular pointer.
+ *
+ *  @sa @ref vulkan_proc
+ *  @sa glfwGetInstanceProcAddress
+ *
+ *  @since Added in version 3.2.
+ *
+ *  @ingroup vulkan
+ */
+typedef void (*GLFWvkproc)(void);
+
+/*! @brief Opaque monitor object.
+ *
+ *  Opaque monitor object.
+ *
+ *  @see @ref monitor_object
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup monitor
+ */
+typedef struct GLFWmonitor GLFWmonitor;
+
+/*! @brief Opaque window object.
+ *
+ *  Opaque window object.
+ *
+ *  @see @ref window_object
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup window
+ */
+typedef struct GLFWwindow GLFWwindow;
+
+/*! @brief Opaque cursor object.
+ *
+ *  Opaque cursor object.
+ *
+ *  @see @ref cursor_object
+ *
+ *  @since Added in version 3.1.
+ *
+ *  @ingroup cursor
+ */
+typedef struct GLFWcursor GLFWcursor;
+
+/*! @brief The function signature for error callbacks.
+ *
+ *  This is the function signature for error callback functions.
+ *
+ *  @param[in] error An [error code](@ref errors).
+ *  @param[in] description A UTF-8 encoded string describing the error.
+ *
+ *  @sa @ref error_handling
+ *  @sa glfwSetErrorCallback
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup init
+ */
+typedef void (* GLFWerrorfun)(int,const char*);
+
+/*! @brief The function signature for window position callbacks.
+ *
+ *  This is the function signature for window position callback functions.
+ *
+ *  @param[in] window The window that was moved.
+ *  @param[in] xpos The new x-coordinate, in screen coordinates, of the
+ *  upper-left corner of the client area of the window.
+ *  @param[in] ypos The new y-coordinate, in screen coordinates, of the
+ *  upper-left corner of the client area of the window.
+ *
+ *  @sa @ref window_pos
+ *  @sa glfwSetWindowPosCallback
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup window
+ */
+typedef void (* GLFWwindowposfun)(GLFWwindow*,int,int);
+
+/*! @brief The function signature for window resize callbacks.
+ *
+ *  This is the function signature for window size callback functions.
+ *
+ *  @param[in] window The window that was resized.
+ *  @param[in] width The new width, in screen coordinates, of the window.
+ *  @param[in] height The new height, in screen coordinates, of the window.
+ *
+ *  @sa @ref window_size
+ *  @sa glfwSetWindowSizeCallback
+ *
+ *  @since Added in version 1.0.
+ *  @glfw3 Added window handle parameter.
+ *
+ *  @ingroup window
+ */
+typedef void (* GLFWwindowsizefun)(GLFWwindow*,int,int);
+
+/*! @brief The function signature for window close callbacks.
+ *
+ *  This is the function signature for window close callback functions.
+ *
+ *  @param[in] window The window that the user attempted to close.
+ *
+ *  @sa @ref window_close
+ *  @sa glfwSetWindowCloseCallback
+ *
+ *  @since Added in version 2.5.
+ *  @glfw3 Added window handle parameter.
+ *
+ *  @ingroup window
+ */
+typedef void (* GLFWwindowclosefun)(GLFWwindow*);
+
+/*! @brief The function signature for window content refresh callbacks.
+ *
+ *  This is the function signature for window refresh callback functions.
+ *
+ *  @param[in] window The window whose content needs to be refreshed.
+ *
+ *  @sa @ref window_refresh
+ *  @sa glfwSetWindowRefreshCallback
+ *
+ *  @since Added in version 2.5.
+ *  @glfw3 Added window handle parameter.
+ *
+ *  @ingroup window
+ */
+typedef void (* GLFWwindowrefreshfun)(GLFWwindow*);
+
+/*! @brief The function signature for window focus/defocus callbacks.
+ *
+ *  This is the function signature for window focus callback functions.
+ *
+ *  @param[in] window The window that gained or lost input focus.
+ *  @param[in] focused `GLFW_TRUE` if the window was given input focus, or
+ *  `GLFW_FALSE` if it lost it.
+ *
+ *  @sa @ref window_focus
+ *  @sa glfwSetWindowFocusCallback
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup window
+ */
+typedef void (* GLFWwindowfocusfun)(GLFWwindow*,int);
+
+/*! @brief The function signature for window iconify/restore callbacks.
+ *
+ *  This is the function signature for window iconify/restore callback
+ *  functions.
+ *
+ *  @param[in] window The window that was iconified or restored.
+ *  @param[in] iconified `GLFW_TRUE` if the window was iconified, or
+ *  `GLFW_FALSE` if it was restored.
+ *
+ *  @sa @ref window_iconify
+ *  @sa glfwSetWindowIconifyCallback
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup window
+ */
+typedef void (* GLFWwindowiconifyfun)(GLFWwindow*,int);
+
+/*! @brief The function signature for framebuffer resize callbacks.
+ *
+ *  This is the function signature for framebuffer resize callback
+ *  functions.
+ *
+ *  @param[in] window The window whose framebuffer was resized.
+ *  @param[in] width The new width, in pixels, of the framebuffer.
+ *  @param[in] height The new height, in pixels, of the framebuffer.
+ *
+ *  @sa @ref window_fbsize
+ *  @sa glfwSetFramebufferSizeCallback
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup window
+ */
+typedef void (* GLFWframebuffersizefun)(GLFWwindow*,int,int);
+
+/*! @brief The function signature for mouse button callbacks.
+ *
+ *  This is the function signature for mouse button callback functions.
+ *
+ *  @param[in] window The window that received the event.
+ *  @param[in] button The [mouse button](@ref buttons) that was pressed or
+ *  released.
+ *  @param[in] action One of `GLFW_PRESS` or `GLFW_RELEASE`.
+ *  @param[in] mods Bit field describing which [modifier keys](@ref mods) were
+ *  held down.
+ *
+ *  @sa @ref input_mouse_button
+ *  @sa glfwSetMouseButtonCallback
+ *
+ *  @since Added in version 1.0.
+ *  @glfw3 Added window handle and modifier mask parameters.
+ *
+ *  @ingroup input
+ */
+typedef void (* GLFWmousebuttonfun)(GLFWwindow*,int,int,int);
+
+/*! @brief The function signature for cursor position callbacks.
+ *
+ *  This is the function signature for cursor position callback functions.
+ *
+ *  @param[in] window The window that received the event.
+ *  @param[in] xpos The new cursor x-coordinate, relative to the left edge of
+ *  the client area.
+ *  @param[in] ypos The new cursor y-coordinate, relative to the top edge of the
+ *  client area.
+ *
+ *  @sa @ref cursor_pos
+ *  @sa glfwSetCursorPosCallback
+ *
+ *  @since Added in version 3.0.  Replaces `GLFWmouseposfun`.
+ *
+ *  @ingroup input
+ */
+typedef void (* GLFWcursorposfun)(GLFWwindow*,double,double);
+
+/*! @brief The function signature for cursor enter/leave callbacks.
+ *
+ *  This is the function signature for cursor enter/leave callback functions.
+ *
+ *  @param[in] window The window that received the event.
+ *  @param[in] entered `GLFW_TRUE` if the cursor entered the window's client
+ *  area, or `GLFW_FALSE` if it left it.
+ *
+ *  @sa @ref cursor_enter
+ *  @sa glfwSetCursorEnterCallback
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup input
+ */
+typedef void (* GLFWcursorenterfun)(GLFWwindow*,int);
+
+/*! @brief The function signature for scroll callbacks.
+ *
+ *  This is the function signature for scroll callback functions.
+ *
+ *  @param[in] window The window that received the event.
+ *  @param[in] xoffset The scroll offset along the x-axis.
+ *  @param[in] yoffset The scroll offset along the y-axis.
+ *
+ *  @sa @ref scrolling
+ *  @sa glfwSetScrollCallback
+ *
+ *  @since Added in version 3.0.  Replaces `GLFWmousewheelfun`.
+ *
+ *  @ingroup input
+ */
+typedef void (* GLFWscrollfun)(GLFWwindow*,double,double);
+
+/*! @brief The function signature for keyboard key callbacks.
+ *
+ *  This is the function signature for keyboard key callback functions.
+ *
+ *  @param[in] window The window that received the event.
+ *  @param[in] key The [keyboard key](@ref keys) that was pressed or released.
+ *  @param[in] scancode The system-specific scancode of the key.
+ *  @param[in] action `GLFW_PRESS`, `GLFW_RELEASE` or `GLFW_REPEAT`.
+ *  @param[in] mods Bit field describing which [modifier keys](@ref mods) were
+ *  held down.
+ *
+ *  @sa @ref input_key
+ *  @sa glfwSetKeyCallback
+ *
+ *  @since Added in version 1.0.
+ *  @glfw3 Added window handle, scancode and modifier mask parameters.
+ *
+ *  @ingroup input
+ */
+typedef void (* GLFWkeyfun)(GLFWwindow*,int,int,int,int);
+
+/*! @brief The function signature for Unicode character callbacks.
+ *
+ *  This is the function signature for Unicode character callback functions.
+ *
+ *  @param[in] window The window that received the event.
+ *  @param[in] codepoint The Unicode code point of the character.
+ *
+ *  @sa @ref input_char
+ *  @sa glfwSetCharCallback
+ *
+ *  @since Added in version 2.4.
+ *  @glfw3 Added window handle parameter.
+ *
+ *  @ingroup input
+ */
+typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int);
+
+/*! @brief The function signature for Unicode character with modifiers
+ *  callbacks.
+ *
+ *  This is the function signature for Unicode character with modifiers callback
+ *  functions.  It is called for each input character, regardless of what
+ *  modifier keys are held down.
+ *
+ *  @param[in] window The window that received the event.
+ *  @param[in] codepoint The Unicode code point of the character.
+ *  @param[in] mods Bit field describing which [modifier keys](@ref mods) were
+ *  held down.
+ *
+ *  @sa @ref input_char
+ *  @sa glfwSetCharModsCallback
+ *
+ *  @since Added in version 3.1.
+ *
+ *  @ingroup input
+ */
+typedef void (* GLFWcharmodsfun)(GLFWwindow*,unsigned int,int);
+
+/*! @brief The function signature for file drop callbacks.
+ *
+ *  This is the function signature for file drop callbacks.
+ *
+ *  @param[in] window The window that received the event.
+ *  @param[in] count The number of dropped files.
+ *  @param[in] paths The UTF-8 encoded file and/or directory path names.
+ *
+ *  @sa @ref path_drop
+ *  @sa glfwSetDropCallback
+ *
+ *  @since Added in version 3.1.
+ *
+ *  @ingroup input
+ */
+typedef void (* GLFWdropfun)(GLFWwindow*,int,const char**);
+
+/*! @brief The function signature for monitor configuration callbacks.
+ *
+ *  This is the function signature for monitor configuration callback functions.
+ *
+ *  @param[in] monitor The monitor that was connected or disconnected.
+ *  @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`.
+ *
+ *  @sa @ref monitor_event
+ *  @sa glfwSetMonitorCallback
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup monitor
+ */
+typedef void (* GLFWmonitorfun)(GLFWmonitor*,int);
+
+/*! @brief The function signature for joystick configuration callbacks.
+ *
+ *  This is the function signature for joystick configuration callback
+ *  functions.
+ *
+ *  @param[in] joy The joystick that was connected or disconnected.
+ *  @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`.
+ *
+ *  @sa @ref joystick_event
+ *  @sa glfwSetJoystickCallback
+ *
+ *  @since Added in version 3.2.
+ *
+ *  @ingroup input
+ */
+typedef void (* GLFWjoystickfun)(int,int);
+
+/*! @brief Video mode type.
+ *
+ *  This describes a single video mode.
+ *
+ *  @sa @ref monitor_modes
+ *  @sa glfwGetVideoMode glfwGetVideoModes
+ *
+ *  @since Added in version 1.0.
+ *  @glfw3 Added refresh rate member.
+ *
+ *  @ingroup monitor
+ */
+typedef struct GLFWvidmode
+{
+    /*! The width, in screen coordinates, of the video mode.
+     */
+    int width;
+    /*! The height, in screen coordinates, of the video mode.
+     */
+    int height;
+    /*! The bit depth of the red channel of the video mode.
+     */
+    int redBits;
+    /*! The bit depth of the green channel of the video mode.
+     */
+    int greenBits;
+    /*! The bit depth of the blue channel of the video mode.
+     */
+    int blueBits;
+    /*! The refresh rate, in Hz, of the video mode.
+     */
+    int refreshRate;
+} GLFWvidmode;
+
+/*! @brief Gamma ramp.
+ *
+ *  This describes the gamma ramp for a monitor.
+ *
+ *  @sa @ref monitor_gamma
+ *  @sa glfwGetGammaRamp glfwSetGammaRamp
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup monitor
+ */
+typedef struct GLFWgammaramp
+{
+    /*! An array of value describing the response of the red channel.
+     */
+    unsigned short* red;
+    /*! An array of value describing the response of the green channel.
+     */
+    unsigned short* green;
+    /*! An array of value describing the response of the blue channel.
+     */
+    unsigned short* blue;
+    /*! The number of elements in each array.
+     */
+    unsigned int size;
+} GLFWgammaramp;
+
+/*! @brief Image data.
+ *
+ *  @sa @ref cursor_custom
+ *  @sa @ref window_icon
+ *
+ *  @since Added in version 2.1.
+ *  @glfw3 Removed format and bytes-per-pixel members.
+ */
+typedef struct GLFWimage
+{
+    /*! The width, in pixels, of this image.
+     */
+    int width;
+    /*! The height, in pixels, of this image.
+     */
+    int height;
+    /*! The pixel data of this image, arranged left-to-right, top-to-bottom.
+     */
+    unsigned char* pixels;
+} GLFWimage;
+
+
+/*************************************************************************
+ * GLFW API functions
+ *************************************************************************/
+
+/*! @brief Initializes the GLFW library.
+ *
+ *  This function initializes the GLFW library.  Before most GLFW functions can
+ *  be used, GLFW must be initialized, and before an application terminates GLFW
+ *  should be terminated in order to free any resources allocated during or
+ *  after initialization.
+ *
+ *  If this function fails, it calls @ref glfwTerminate before returning.  If it
+ *  succeeds, you should call @ref glfwTerminate before the application exits.
+ *
+ *  Additional calls to this function after successful initialization but before
+ *  termination will return `GLFW_TRUE` immediately.
+ *
+ *  @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an
+ *  [error](@ref error_handling) occurred.
+ *
+ *  @errors Possible errors include @ref GLFW_PLATFORM_ERROR.
+ *
+ *  @remark @osx This function will change the current directory of the
+ *  application to the `Contents/Resources` subdirectory of the application's
+ *  bundle, if present.  This can be disabled with a
+ *  [compile-time option](@ref compile_options_osx).
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref intro_init
+ *  @sa glfwTerminate
+ *
+ *  @since Added in version 1.0.
+ *
+ *  @ingroup init
+ */
+GLFWAPI int glfwInit(void);
+
+/*! @brief Terminates the GLFW library.
+ *
+ *  This function destroys all remaining windows and cursors, restores any
+ *  modified gamma ramps and frees any other allocated resources.  Once this
+ *  function is called, you must again call @ref glfwInit successfully before
+ *  you will be able to use most GLFW functions.
+ *
+ *  If GLFW has been successfully initialized, this function should be called
+ *  before the application exits.  If initialization fails, there is no need to
+ *  call this function, as it is called by @ref glfwInit before it returns
+ *  failure.
+ *
+ *  @errors Possible errors include @ref GLFW_PLATFORM_ERROR.
+ *
+ *  @remark This function may be called before @ref glfwInit.
+ *
+ *  @warning The contexts of any remaining windows must not be current on any
+ *  other thread when this function is called.
+ *
+ *  @reentrancy This function must not be called from a callback.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref intro_init
+ *  @sa glfwInit
+ *
+ *  @since Added in version 1.0.
+ *
+ *  @ingroup init
+ */
+GLFWAPI void glfwTerminate(void);
+
+/*! @brief Retrieves the version of the GLFW library.
+ *
+ *  This function retrieves the major, minor and revision numbers of the GLFW
+ *  library.  It is intended for when you are using GLFW as a shared library and
+ *  want to ensure that you are using the minimum required version.
+ *
+ *  Any or all of the version arguments may be `NULL`.
+ *
+ *  @param[out] major Where to store the major version number, or `NULL`.
+ *  @param[out] minor Where to store the minor version number, or `NULL`.
+ *  @param[out] rev Where to store the revision number, or `NULL`.
+ *
+ *  @errors None.
+ *
+ *  @remark This function may be called before @ref glfwInit.
+ *
+ *  @thread_safety This function may be called from any thread.
+ *
+ *  @sa @ref intro_version
+ *  @sa glfwGetVersionString
+ *
+ *  @since Added in version 1.0.
+ *
+ *  @ingroup init
+ */
+GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev);
+
+/*! @brief Returns a string describing the compile-time configuration.
+ *
+ *  This function returns the compile-time generated
+ *  [version string](@ref intro_version_string) of the GLFW library binary.  It
+ *  describes the version, platform, compiler and any platform-specific
+ *  compile-time options.  It should not be confused with the OpenGL or OpenGL
+ *  ES version string, queried with `glGetString`.
+ *
+ *  __Do not use the version string__ to parse the GLFW library version.  The
+ *  @ref glfwGetVersion function provides the version of the running library
+ *  binary in numerical format.
+ *
+ *  @return The ASCII encoded GLFW version string.
+ *
+ *  @errors None.
+ *
+ *  @remark This function may be called before @ref glfwInit.
+ *
+ *  @pointer_lifetime The returned string is static and compile-time generated.
+ *
+ *  @thread_safety This function may be called from any thread.
+ *
+ *  @sa @ref intro_version
+ *  @sa glfwGetVersion
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup init
+ */
+GLFWAPI const char* glfwGetVersionString(void);
+
+/*! @brief Sets the error callback.
+ *
+ *  This function sets the error callback, which is called with an error code
+ *  and a human-readable description each time a GLFW error occurs.
+ *
+ *  The error callback is called on the thread where the error occurred.  If you
+ *  are using GLFW from multiple threads, your error callback needs to be
+ *  written accordingly.
+ *
+ *  Because the description string may have been generated specifically for that
+ *  error, it is not guaranteed to be valid after the callback has returned.  If
+ *  you wish to use it after the callback returns, you need to make a copy.
+ *
+ *  Once set, the error callback remains set even after the library has been
+ *  terminated.
+ *
+ *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ *  callback.
+ *  @return The previously set callback, or `NULL` if no callback was set.
+ *
+ *  @errors None.
+ *
+ *  @remark This function may be called before @ref glfwInit.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref error_handling
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup init
+ */
+GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun);
+
+/*! @brief Returns the currently connected monitors.
+ *
+ *  This function returns an array of handles for all currently connected
+ *  monitors.  The primary monitor is always first in the returned array.  If no
+ *  monitors were found, this function returns `NULL`.
+ *
+ *  @param[out] count Where to store the number of monitors in the returned
+ *  array.  This is set to zero if an error occurred.
+ *  @return An array of monitor handles, or `NULL` if no monitors were found or
+ *  if an [error](@ref error_handling) occurred.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @pointer_lifetime The returned array is allocated and freed by GLFW.  You
+ *  should not free it yourself.  It is guaranteed to be valid only until the
+ *  monitor configuration changes or the library is terminated.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref monitor_monitors
+ *  @sa @ref monitor_event
+ *  @sa glfwGetPrimaryMonitor
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup monitor
+ */
+GLFWAPI GLFWmonitor** glfwGetMonitors(int* count);
+
+/*! @brief Returns the primary monitor.
+ *
+ *  This function returns the primary monitor.  This is usually the monitor
+ *  where elements like the task bar or global menu bar are located.
+ *
+ *  @return The primary monitor, or `NULL` if no monitors were found or if an
+ *  [error](@ref error_handling) occurred.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @remark The primary monitor is always first in the array returned by @ref
+ *  glfwGetMonitors.
+ *
+ *  @sa @ref monitor_monitors
+ *  @sa glfwGetMonitors
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup monitor
+ */
+GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void);
+
+/*! @brief Returns the position of the monitor's viewport on the virtual screen.
+ *
+ *  This function returns the position, in screen coordinates, of the upper-left
+ *  corner of the specified monitor.
+ *
+ *  Any or all of the position arguments may be `NULL`.  If an error occurs, all
+ *  non-`NULL` position arguments will be set to zero.
+ *
+ *  @param[in] monitor The monitor to query.
+ *  @param[out] xpos Where to store the monitor x-coordinate, or `NULL`.
+ *  @param[out] ypos Where to store the monitor y-coordinate, or `NULL`.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref monitor_properties
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup monitor
+ */
+GLFWAPI void glfwGetMonitorPos(GLFWmonitor* monitor, int* xpos, int* ypos);
+
+/*! @brief Returns the physical size of the monitor.
+ *
+ *  This function returns the size, in millimetres, of the display area of the
+ *  specified monitor.
+ *
+ *  Some systems do not provide accurate monitor size information, either
+ *  because the monitor
+ *  [EDID](https://en.wikipedia.org/wiki/Extended_display_identification_data)
+ *  data is incorrect or because the driver does not report it accurately.
+ *
+ *  Any or all of the size arguments may be `NULL`.  If an error occurs, all
+ *  non-`NULL` size arguments will be set to zero.
+ *
+ *  @param[in] monitor The monitor to query.
+ *  @param[out] widthMM Where to store the width, in millimetres, of the
+ *  monitor's display area, or `NULL`.
+ *  @param[out] heightMM Where to store the height, in millimetres, of the
+ *  monitor's display area, or `NULL`.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @remark @win32 calculates the returned physical size from the
+ *  current resolution and system DPI instead of querying the monitor EDID data.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref monitor_properties
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup monitor
+ */
+GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* monitor, int* widthMM, int* heightMM);
+
+/*! @brief Returns the name of the specified monitor.
+ *
+ *  This function returns a human-readable name, encoded as UTF-8, of the
+ *  specified monitor.  The name typically reflects the make and model of the
+ *  monitor and is not guaranteed to be unique among the connected monitors.
+ *
+ *  @param[in] monitor The monitor to query.
+ *  @return The UTF-8 encoded name of the monitor, or `NULL` if an
+ *  [error](@ref error_handling) occurred.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @pointer_lifetime The returned string is allocated and freed by GLFW.  You
+ *  should not free it yourself.  It is valid until the specified monitor is
+ *  disconnected or the library is terminated.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref monitor_properties
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup monitor
+ */
+GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* monitor);
+
+/*! @brief Sets the monitor configuration callback.
+ *
+ *  This function sets the monitor configuration callback, or removes the
+ *  currently set callback.  This is called when a monitor is connected to or
+ *  disconnected from the system.
+ *
+ *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ *  callback.
+ *  @return The previously set callback, or `NULL` if no callback was set or the
+ *  library had not been [initialized](@ref intro_init).
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref monitor_event
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup monitor
+ */
+GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun);
+
+/*! @brief Returns the available video modes for the specified monitor.
+ *
+ *  This function returns an array of all video modes supported by the specified
+ *  monitor.  The returned array is sorted in ascending order, first by color
+ *  bit depth (the sum of all channel depths) and then by resolution area (the
+ *  product of width and height).
+ *
+ *  @param[in] monitor The monitor to query.
+ *  @param[out] count Where to store the number of video modes in the returned
+ *  array.  This is set to zero if an error occurred.
+ *  @return An array of video modes, or `NULL` if an
+ *  [error](@ref error_handling) occurred.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @pointer_lifetime The returned array is allocated and freed by GLFW.  You
+ *  should not free it yourself.  It is valid until the specified monitor is
+ *  disconnected, this function is called again for that monitor or the library
+ *  is terminated.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref monitor_modes
+ *  @sa glfwGetVideoMode
+ *
+ *  @since Added in version 1.0.
+ *  @glfw3 Changed to return an array of modes for a specific monitor.
+ *
+ *  @ingroup monitor
+ */
+GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* monitor, int* count);
+
+/*! @brief Returns the current mode of the specified monitor.
+ *
+ *  This function returns the current video mode of the specified monitor.  If
+ *  you have created a full screen window for that monitor, the return value
+ *  will depend on whether that window is iconified.
+ *
+ *  @param[in] monitor The monitor to query.
+ *  @return The current mode of the monitor, or `NULL` if an
+ *  [error](@ref error_handling) occurred.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @pointer_lifetime The returned array is allocated and freed by GLFW.  You
+ *  should not free it yourself.  It is valid until the specified monitor is
+ *  disconnected or the library is terminated.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref monitor_modes
+ *  @sa glfwGetVideoModes
+ *
+ *  @since Added in version 3.0.  Replaces `glfwGetDesktopMode`.
+ *
+ *  @ingroup monitor
+ */
+GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor);
+
+/*! @brief Generates a gamma ramp and sets it for the specified monitor.
+ *
+ *  This function generates a 256-element gamma ramp from the specified exponent
+ *  and then calls @ref glfwSetGammaRamp with it.  The value must be a finite
+ *  number greater than zero.
+ *
+ *  @param[in] monitor The monitor whose gamma ramp to set.
+ *  @param[in] gamma The desired exponent.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ *  GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref monitor_gamma
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup monitor
+ */
+GLFWAPI void glfwSetGamma(GLFWmonitor* monitor, float gamma);
+
+/*! @brief Returns the current gamma ramp for the specified monitor.
+ *
+ *  This function returns the current gamma ramp of the specified monitor.
+ *
+ *  @param[in] monitor The monitor to query.
+ *  @return The current gamma ramp, or `NULL` if an
+ *  [error](@ref error_handling) occurred.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @pointer_lifetime The returned structure and its arrays are allocated and
+ *  freed by GLFW.  You should not free them yourself.  They are valid until the
+ *  specified monitor is disconnected, this function is called again for that
+ *  monitor or the library is terminated.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref monitor_gamma
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup monitor
+ */
+GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* monitor);
+
+/*! @brief Sets the current gamma ramp for the specified monitor.
+ *
+ *  This function sets the current gamma ramp for the specified monitor.  The
+ *  original gamma ramp for that monitor is saved by GLFW the first time this
+ *  function is called and is restored by @ref glfwTerminate.
+ *
+ *  @param[in] monitor The monitor whose gamma ramp to set.
+ *  @param[in] ramp The gamma ramp to use.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @remark Gamma ramp sizes other than 256 are not supported by all platforms
+ *  or graphics hardware.
+ *
+ *  @remark @win32 The gamma ramp size must be 256.
+ *
+ *  @pointer_lifetime The specified gamma ramp is copied before this function
+ *  returns.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref monitor_gamma
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup monitor
+ */
+GLFWAPI void glfwSetGammaRamp(GLFWmonitor* monitor, const GLFWgammaramp* ramp);
+
+/*! @brief Resets all window hints to their default values.
+ *
+ *  This function resets all window hints to their
+ *  [default values](@ref window_hints_values).
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_hints
+ *  @sa glfwWindowHint
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup window
+ */
+GLFWAPI void glfwDefaultWindowHints(void);
+
+/*! @brief Sets the specified window hint to the desired value.
+ *
+ *  This function sets hints for the next call to @ref glfwCreateWindow.  The
+ *  hints, once set, retain their values until changed by a call to @ref
+ *  glfwWindowHint or @ref glfwDefaultWindowHints, or until the library is
+ *  terminated.
+ *
+ *  This function does not check whether the specified hint values are valid.
+ *  If you set hints to invalid values this will instead be reported by the next
+ *  call to @ref glfwCreateWindow.
+ *
+ *  @param[in] hint The [window hint](@ref window_hints) to set.
+ *  @param[in] value The new value of the window hint.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_INVALID_ENUM.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_hints
+ *  @sa glfwDefaultWindowHints
+ *
+ *  @since Added in version 3.0.  Replaces `glfwOpenWindowHint`.
+ *
+ *  @ingroup window
+ */
+GLFWAPI void glfwWindowHint(int hint, int value);
+
+/*! @brief Creates a window and its associated context.
+ *
+ *  This function creates a window and its associated OpenGL or OpenGL ES
+ *  context.  Most of the options controlling how the window and its context
+ *  should be created are specified with [window hints](@ref window_hints).
+ *
+ *  Successful creation does not change which context is current.  Before you
+ *  can use the newly created context, you need to
+ *  [make it current](@ref context_current).  For information about the `share`
+ *  parameter, see @ref context_sharing.
+ *
+ *  The created window, framebuffer and context may differ from what you
+ *  requested, as not all parameters and hints are
+ *  [hard constraints](@ref window_hints_hard).  This includes the size of the
+ *  window, especially for full screen windows.  To query the actual attributes
+ *  of the created window, framebuffer and context, see @ref
+ *  glfwGetWindowAttrib, @ref glfwGetWindowSize and @ref glfwGetFramebufferSize.
+ *
+ *  To create a full screen window, you need to specify the monitor the window
+ *  will cover.  If no monitor is specified, the window will be windowed mode.
+ *  Unless you have a way for the user to choose a specific monitor, it is
+ *  recommended that you pick the primary monitor.  For more information on how
+ *  to query connected monitors, see @ref monitor_monitors.
+ *
+ *  For full screen windows, the specified size becomes the resolution of the
+ *  window's _desired video mode_.  As long as a full screen window is not
+ *  iconified, the supported video mode most closely matching the desired video
+ *  mode is set for the specified monitor.  For more information about full
+ *  screen windows, including the creation of so called _windowed full screen_
+ *  or _borderless full screen_ windows, see @ref window_windowed_full_screen.
+ *
+ *  Once you have created the window, you can switch it between windowed and
+ *  full screen mode with @ref glfwSetWindowMonitor.  If the window has an
+ *  OpenGL or OpenGL ES context, it will be unaffected.
+ *
+ *  By default, newly created windows use the placement recommended by the
+ *  window system.  To create the window at a specific position, make it
+ *  initially invisible using the [GLFW_VISIBLE](@ref window_hints_wnd) window
+ *  hint, set its [position](@ref window_pos) and then [show](@ref window_hide)
+ *  it.
+ *
+ *  As long as at least one full screen window is not iconified, the screensaver
+ *  is prohibited from starting.
+ *
+ *  Window systems put limits on window sizes.  Very large or very small window
+ *  dimensions may be overridden by the window system on creation.  Check the
+ *  actual [size](@ref window_size) after creation.
+ *
+ *  The [swap interval](@ref buffer_swap) is not set during window creation and
+ *  the initial value may vary depending on driver settings and defaults.
+ *
+ *  @param[in] width The desired width, in screen coordinates, of the window.
+ *  This must be greater than zero.
+ *  @param[in] height The desired height, in screen coordinates, of the window.
+ *  This must be greater than zero.
+ *  @param[in] title The initial, UTF-8 encoded window title.
+ *  @param[in] monitor The monitor to use for full screen mode, or `NULL` for
+ *  windowed mode.
+ *  @param[in] share The window whose context to share resources with, or `NULL`
+ *  to not share resources.
+ *  @return The handle of the created window, or `NULL` if an
+ *  [error](@ref error_handling) occurred.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ *  GLFW_INVALID_ENUM, @ref GLFW_INVALID_VALUE, @ref GLFW_API_UNAVAILABLE, @ref
+ *  GLFW_VERSION_UNAVAILABLE, @ref GLFW_FORMAT_UNAVAILABLE and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @remark @win32 Window creation will fail if the Microsoft GDI software
+ *  OpenGL implementation is the only one available.
+ *
+ *  @remark @win32 If the executable has an icon resource named `GLFW_ICON,` it
+ *  will be set as the initial icon for the window.  If no such icon is present,
+ *  the `IDI_WINLOGO` icon will be used instead.  To set a different icon, see
+ *  @ref glfwSetWindowIcon.
+ *
+ *  @remark @win32 The context to share resources with must not be current on
+ *  any other thread.
+ *
+ *  @remark @osx The GLFW window has no icon, as it is not a document
+ *  window, but the dock icon will be the same as the application bundle's icon.
+ *  For more information on bundles, see the
+ *  [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/)
+ *  in the Mac Developer Library.
+ *
+ *  @remark @osx The first time a window is created the menu bar is populated
+ *  with common commands like Hide, Quit and About.  The About entry opens
+ *  a minimal about dialog with information from the application's bundle.  The
+ *  menu bar can be disabled with a
+ *  [compile-time option](@ref compile_options_osx).
+ *
+ *  @remark @osx On OS X 10.10 and later the window frame will not be rendered
+ *  at full resolution on Retina displays unless the `NSHighResolutionCapable`
+ *  key is enabled in the application bundle's `Info.plist`.  For more
+ *  information, see
+ *  [High Resolution Guidelines for OS X](https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html)
+ *  in the Mac Developer Library.  The GLFW test and example programs use
+ *  a custom `Info.plist` template for this, which can be found as
+ *  `CMake/MacOSXBundleInfo.plist.in` in the source tree.
+ *
+ *  @remark @x11 Some window managers will not respect the placement of
+ *  initially hidden windows.
+ *
+ *  @remark @x11 Due to the asynchronous nature of X11, it may take a moment for
+ *  a window to reach its requested state.  This means you may not be able to
+ *  query the final size, position or other attributes directly after window
+ *  creation.
+ *
+ *  @reentrancy This function must not be called from a callback.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_creation
+ *  @sa glfwDestroyWindow
+ *
+ *  @since Added in version 3.0.  Replaces `glfwOpenWindow`.
+ *
+ *  @ingroup window
+ */
+GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, GLFWmonitor* monitor, GLFWwindow* share);
+
+/*! @brief Destroys the specified window and its context.
+ *
+ *  This function destroys the specified window and its context.  On calling
+ *  this function, no further callbacks will be called for that window.
+ *
+ *  If the context of the specified window is current on the main thread, it is
+ *  detached before being destroyed.
+ *
+ *  @param[in] window The window to destroy.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @note The context of the specified window must not be current on any other
+ *  thread when this function is called.
+ *
+ *  @reentrancy This function must not be called from a callback.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_creation
+ *  @sa glfwCreateWindow
+ *
+ *  @since Added in version 3.0.  Replaces `glfwCloseWindow`.
+ *
+ *  @ingroup window
+ */
+GLFWAPI void glfwDestroyWindow(GLFWwindow* window);
+
+/*! @brief Checks the close flag of the specified window.
+ *
+ *  This function returns the value of the close flag of the specified window.
+ *
+ *  @param[in] window The window to query.
+ *  @return The value of the close flag.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function may be called from any thread.  Access is not
+ *  synchronized.
+ *
+ *  @sa @ref window_close
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup window
+ */
+GLFWAPI int glfwWindowShouldClose(GLFWwindow* window);
+
+/*! @brief Sets the close flag of the specified window.
+ *
+ *  This function sets the value of the close flag of the specified window.
+ *  This can be used to override the user's attempt to close the window, or
+ *  to signal that it should be closed.
+ *
+ *  @param[in] window The window whose flag to change.
+ *  @param[in] value The new value.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function may be called from any thread.  Access is not
+ *  synchronized.
+ *
+ *  @sa @ref window_close
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup window
+ */
+GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* window, int value);
+
+/*! @brief Sets the title of the specified window.
+ *
+ *  This function sets the window title, encoded as UTF-8, of the specified
+ *  window.
+ *
+ *  @param[in] window The window whose title to change.
+ *  @param[in] title The UTF-8 encoded window title.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @remark @osx The window title will not be updated until the next time you
+ *  process events.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_title
+ *
+ *  @since Added in version 1.0.
+ *  @glfw3 Added window handle parameter.
+ *
+ *  @ingroup window
+ */
+GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title);
+
+/*! @brief Sets the icon for the specified window.
+ *
+ *  This function sets the icon of the specified window.  If passed an array of
+ *  candidate images, those of or closest to the sizes desired by the system are
+ *  selected.  If no images are specified, the window reverts to its default
+ *  icon.
+ *
+ *  The desired image sizes varies depending on platform and system settings.
+ *  The selected images will be rescaled as needed.  Good sizes include 16x16,
+ *  32x32 and 48x48.
+ *
+ *  @param[in] window The window whose icon to set.
+ *  @param[in] count The number of images in the specified array, or zero to
+ *  revert to the default window icon.
+ *  @param[in] images The images to create the icon from.  This is ignored if
+ *  count is zero.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @pointer_lifetime The specified image data is copied before this function
+ *  returns.
+ *
+ *  @remark @osx The GLFW window has no icon, as it is not a document
+ *  window, so this function does nothing.  The dock icon will be the same as
+ *  the application bundle's icon.  For more information on bundles, see the
+ *  [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/)
+ *  in the Mac Developer Library.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_icon
+ *
+ *  @since Added in version 3.2.
+ *
+ *  @ingroup window
+ */
+GLFWAPI void glfwSetWindowIcon(GLFWwindow* window, int count, const GLFWimage* images);
+
+/*! @brief Retrieves the position of the client area of the specified window.
+ *
+ *  This function retrieves the position, in screen coordinates, of the
+ *  upper-left corner of the client area of the specified window.
+ *
+ *  Any or all of the position arguments may be `NULL`.  If an error occurs, all
+ *  non-`NULL` position arguments will be set to zero.
+ *
+ *  @param[in] window The window to query.
+ *  @param[out] xpos Where to store the x-coordinate of the upper-left corner of
+ *  the client area, or `NULL`.
+ *  @param[out] ypos Where to store the y-coordinate of the upper-left corner of
+ *  the client area, or `NULL`.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_pos
+ *  @sa glfwSetWindowPos
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup window
+ */
+GLFWAPI void glfwGetWindowPos(GLFWwindow* window, int* xpos, int* ypos);
+
+/*! @brief Sets the position of the client area of the specified window.
+ *
+ *  This function sets the position, in screen coordinates, of the upper-left
+ *  corner of the client area of the specified windowed mode window.  If the
+ *  window is a full screen window, this function does nothing.
+ *
+ *  __Do not use this function__ to move an already visible window unless you
+ *  have very good reasons for doing so, as it will confuse and annoy the user.
+ *
+ *  The window manager may put limits on what positions are allowed.  GLFW
+ *  cannot and should not override these limits.
+ *
+ *  @param[in] window The window to query.
+ *  @param[in] xpos The x-coordinate of the upper-left corner of the client area.
+ *  @param[in] ypos The y-coordinate of the upper-left corner of the client area.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_pos
+ *  @sa glfwGetWindowPos
+ *
+ *  @since Added in version 1.0.
+ *  @glfw3 Added window handle parameter.
+ *
+ *  @ingroup window
+ */
+GLFWAPI void glfwSetWindowPos(GLFWwindow* window, int xpos, int ypos);
+
+/*! @brief Retrieves the size of the client area of the specified window.
+ *
+ *  This function retrieves the size, in screen coordinates, of the client area
+ *  of the specified window.  If you wish to retrieve the size of the
+ *  framebuffer of the window in pixels, see @ref glfwGetFramebufferSize.
+ *
+ *  Any or all of the size arguments may be `NULL`.  If an error occurs, all
+ *  non-`NULL` size arguments will be set to zero.
+ *
+ *  @param[in] window The window whose size to retrieve.
+ *  @param[out] width Where to store the width, in screen coordinates, of the
+ *  client area, or `NULL`.
+ *  @param[out] height Where to store the height, in screen coordinates, of the
+ *  client area, or `NULL`.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_size
+ *  @sa glfwSetWindowSize
+ *
+ *  @since Added in version 1.0.
+ *  @glfw3 Added window handle parameter.
+ *
+ *  @ingroup window
+ */
+GLFWAPI void glfwGetWindowSize(GLFWwindow* window, int* width, int* height);
+
+/*! @brief Sets the size limits of the specified window.
+ *
+ *  This function sets the size limits of the client area of the specified
+ *  window.  If the window is full screen, the size limits only take effect
+ *  once it is made windowed.  If the window is not resizable, this function
+ *  does nothing.
+ *
+ *  The size limits are applied immediately to a windowed mode window and may
+ *  cause it to be resized.
+ *
+ *  The maximum dimensions must be greater than or equal to the minimum
+ *  dimensions and all must be greater than or equal to zero.
+ *
+ *  @param[in] window The window to set limits for.
+ *  @param[in] minwidth The minimum width, in screen coordinates, of the client
+ *  area, or `GLFW_DONT_CARE`.
+ *  @param[in] minheight The minimum height, in screen coordinates, of the
+ *  client area, or `GLFW_DONT_CARE`.
+ *  @param[in] maxwidth The maximum width, in screen coordinates, of the client
+ *  area, or `GLFW_DONT_CARE`.
+ *  @param[in] maxheight The maximum height, in screen coordinates, of the
+ *  client area, or `GLFW_DONT_CARE`.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ *  GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR.
+ *
+ *  @remark If you set size limits and an aspect ratio that conflict, the
+ *  results are undefined.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_sizelimits
+ *  @sa glfwSetWindowAspectRatio
+ *
+ *  @since Added in version 3.2.
+ *
+ *  @ingroup window
+ */
+GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight);
+
+/*! @brief Sets the aspect ratio of the specified window.
+ *
+ *  This function sets the required aspect ratio of the client area of the
+ *  specified window.  If the window is full screen, the aspect ratio only takes
+ *  effect once it is made windowed.  If the window is not resizable, this
+ *  function does nothing.
+ *
+ *  The aspect ratio is specified as a numerator and a denominator and both
+ *  values must be greater than zero.  For example, the common 16:9 aspect ratio
+ *  is specified as 16 and 9, respectively.
+ *
+ *  If the numerator and denominator is set to `GLFW_DONT_CARE` then the aspect
+ *  ratio limit is disabled.
+ *
+ *  The aspect ratio is applied immediately to a windowed mode window and may
+ *  cause it to be resized.
+ *
+ *  @param[in] window The window to set limits for.
+ *  @param[in] numer The numerator of the desired aspect ratio, or
+ *  `GLFW_DONT_CARE`.
+ *  @param[in] denom The denominator of the desired aspect ratio, or
+ *  `GLFW_DONT_CARE`.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ *  GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR.
+ *
+ *  @remark If you set size limits and an aspect ratio that conflict, the
+ *  results are undefined.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_sizelimits
+ *  @sa glfwSetWindowSizeLimits
+ *
+ *  @since Added in version 3.2.
+ *
+ *  @ingroup window
+ */
+GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* window, int numer, int denom);
+
+/*! @brief Sets the size of the client area of the specified window.
+ *
+ *  This function sets the size, in screen coordinates, of the client area of
+ *  the specified window.
+ *
+ *  For full screen windows, this function updates the resolution of its desired
+ *  video mode and switches to the video mode closest to it, without affecting
+ *  the window's context.  As the context is unaffected, the bit depths of the
+ *  framebuffer remain unchanged.
+ *
+ *  If you wish to update the refresh rate of the desired video mode in addition
+ *  to its resolution, see @ref glfwSetWindowMonitor.
+ *
+ *  The window manager may put limits on what sizes are allowed.  GLFW cannot
+ *  and should not override these limits.
+ *
+ *  @param[in] window The window to resize.
+ *  @param[in] width The desired width, in screen coordinates, of the window
+ *  client area.
+ *  @param[in] height The desired height, in screen coordinates, of the window
+ *  client area.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_size
+ *  @sa glfwGetWindowSize
+ *  @sa glfwSetWindowMonitor
+ *
+ *  @since Added in version 1.0.
+ *  @glfw3 Added window handle parameter.
+ *
+ *  @ingroup window
+ */
+GLFWAPI void glfwSetWindowSize(GLFWwindow* window, int width, int height);
+
+/*! @brief Retrieves the size of the framebuffer of the specified window.
+ *
+ *  This function retrieves the size, in pixels, of the framebuffer of the
+ *  specified window.  If you wish to retrieve the size of the window in screen
+ *  coordinates, see @ref glfwGetWindowSize.
+ *
+ *  Any or all of the size arguments may be `NULL`.  If an error occurs, all
+ *  non-`NULL` size arguments will be set to zero.
+ *
+ *  @param[in] window The window whose framebuffer to query.
+ *  @param[out] width Where to store the width, in pixels, of the framebuffer,
+ *  or `NULL`.
+ *  @param[out] height Where to store the height, in pixels, of the framebuffer,
+ *  or `NULL`.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_fbsize
+ *  @sa glfwSetFramebufferSizeCallback
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup window
+ */
+GLFWAPI void glfwGetFramebufferSize(GLFWwindow* window, int* width, int* height);
+
+/*! @brief Retrieves the size of the frame of the window.
+ *
+ *  This function retrieves the size, in screen coordinates, of each edge of the
+ *  frame of the specified window.  This size includes the title bar, if the
+ *  window has one.  The size of the frame may vary depending on the
+ *  [window-related hints](@ref window_hints_wnd) used to create it.
+ *
+ *  Because this function retrieves the size of each window frame edge and not
+ *  the offset along a particular coordinate axis, the retrieved values will
+ *  always be zero or positive.
+ *
+ *  Any or all of the size arguments may be `NULL`.  If an error occurs, all
+ *  non-`NULL` size arguments will be set to zero.
+ *
+ *  @param[in] window The window whose frame size to query.
+ *  @param[out] left Where to store the size, in screen coordinates, of the left
+ *  edge of the window frame, or `NULL`.
+ *  @param[out] top Where to store the size, in screen coordinates, of the top
+ *  edge of the window frame, or `NULL`.
+ *  @param[out] right Where to store the size, in screen coordinates, of the
+ *  right edge of the window frame, or `NULL`.
+ *  @param[out] bottom Where to store the size, in screen coordinates, of the
+ *  bottom edge of the window frame, or `NULL`.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_size
+ *
+ *  @since Added in version 3.1.
+ *
+ *  @ingroup window
+ */
+GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* window, int* left, int* top, int* right, int* bottom);
+
+/*! @brief Iconifies the specified window.
+ *
+ *  This function iconifies (minimizes) the specified window if it was
+ *  previously restored.  If the window is already iconified, this function does
+ *  nothing.
+ *
+ *  If the specified window is a full screen window, the original monitor
+ *  resolution is restored until the window is restored.
+ *
+ *  @param[in] window The window to iconify.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_iconify
+ *  @sa glfwRestoreWindow
+ *  @sa glfwMaximizeWindow
+ *
+ *  @since Added in version 2.1.
+ *  @glfw3 Added window handle parameter.
+ *
+ *  @ingroup window
+ */
+GLFWAPI void glfwIconifyWindow(GLFWwindow* window);
+
+/*! @brief Restores the specified window.
+ *
+ *  This function restores the specified window if it was previously iconified
+ *  (minimized) or maximized.  If the window is already restored, this function
+ *  does nothing.
+ *
+ *  If the specified window is a full screen window, the resolution chosen for
+ *  the window is restored on the selected monitor.
+ *
+ *  @param[in] window The window to restore.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_iconify
+ *  @sa glfwIconifyWindow
+ *  @sa glfwMaximizeWindow
+ *
+ *  @since Added in version 2.1.
+ *  @glfw3 Added window handle parameter.
+ *
+ *  @ingroup window
+ */
+GLFWAPI void glfwRestoreWindow(GLFWwindow* window);
+
+/*! @brief Maximizes the specified window.
+ *
+ *  This function maximizes the specified window if it was previously not
+ *  maximized.  If the window is already maximized, this function does nothing.
+ *
+ *  If the specified window is a full screen window, this function does nothing.
+ *
+ *  @param[in] window The window to maximize.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @par Thread Safety
+ *  This function may only be called from the main thread.
+ *
+ *  @sa @ref window_iconify
+ *  @sa glfwIconifyWindow
+ *  @sa glfwRestoreWindow
+ *
+ *  @since Added in GLFW 3.2.
+ *
+ *  @ingroup window
+ */
+GLFWAPI void glfwMaximizeWindow(GLFWwindow* window);
+
+/*! @brief Makes the specified window visible.
+ *
+ *  This function makes the specified window visible if it was previously
+ *  hidden.  If the window is already visible or is in full screen mode, this
+ *  function does nothing.
+ *
+ *  @param[in] window The window to make visible.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_hide
+ *  @sa glfwHideWindow
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup window
+ */
+GLFWAPI void glfwShowWindow(GLFWwindow* window);
+
+/*! @brief Hides the specified window.
+ *
+ *  This function hides the specified window if it was previously visible.  If
+ *  the window is already hidden or is in full screen mode, this function does
+ *  nothing.
+ *
+ *  @param[in] window The window to hide.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_hide
+ *  @sa glfwShowWindow
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup window
+ */
+GLFWAPI void glfwHideWindow(GLFWwindow* window);
+
+/*! @brief Brings the specified window to front and sets input focus.
+ *
+ *  This function brings the specified window to front and sets input focus.
+ *  The window should already be visible and not iconified.
+ *
+ *  By default, both windowed and full screen mode windows are focused when
+ *  initially created.  Set the [GLFW_FOCUSED](@ref window_hints_wnd) to disable
+ *  this behavior.
+ *
+ *  __Do not use this function__ to steal focus from other applications unless
+ *  you are certain that is what the user wants.  Focus stealing can be
+ *  extremely disruptive.
+ *
+ *  @param[in] window The window to give input focus.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_focus
+ *
+ *  @since Added in version 3.2.
+ *
+ *  @ingroup window
+ */
+GLFWAPI void glfwFocusWindow(GLFWwindow* window);
+
+/*! @brief Returns the monitor that the window uses for full screen mode.
+ *
+ *  This function returns the handle of the monitor that the specified window is
+ *  in full screen on.
+ *
+ *  @param[in] window The window to query.
+ *  @return The monitor, or `NULL` if the window is in windowed mode or an
+ *  [error](@ref error_handling) occurred.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_monitor
+ *  @sa glfwSetWindowMonitor
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup window
+ */
+GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window);
+
+/*! @brief Sets the mode, monitor, video mode and placement of a window.
+ *
+ *  This function sets the monitor that the window uses for full screen mode or,
+ *  if the monitor is `NULL`, makes it windowed mode.
+ *
+ *  When setting a monitor, this function updates the width, height and refresh
+ *  rate of the desired video mode and switches to the video mode closest to it.
+ *  The window position is ignored when setting a monitor.
+ *
+ *  When the monitor is `NULL`, the position, width and height are used to
+ *  place the window client area.  The refresh rate is ignored when no monitor
+ *  is specified.
+ *
+ *  If you only wish to update the resolution of a full screen window or the
+ *  size of a windowed mode window, see @ref glfwSetWindowSize.
+ *
+ *  When a window transitions from full screen to windowed mode, this function
+ *  restores any previous window settings such as whether it is decorated,
+ *  floating, resizable, has size or aspect ratio limits, etc..
+ *
+ *  @param[in] window The window whose monitor, size or video mode to set.
+ *  @param[in] monitor The desired monitor, or `NULL` to set windowed mode.
+ *  @param[in] xpos The desired x-coordinate of the upper-left corner of the
+ *  client area.
+ *  @param[in] ypos The desired y-coordinate of the upper-left corner of the
+ *  client area.
+ *  @param[in] width The desired with, in screen coordinates, of the client area
+ *  or video mode.
+ *  @param[in] height The desired height, in screen coordinates, of the client
+ *  area or video mode.
+ *  @param[in] refreshRate The desired refresh rate, in Hz, of the video mode,
+ *  or `GLFW_DONT_CARE`.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_monitor
+ *  @sa @ref window_full_screen
+ *  @sa glfwGetWindowMonitor
+ *  @sa glfwSetWindowSize
+ *
+ *  @since Added in version 3.2.
+ *
+ *  @ingroup window
+ */
+GLFWAPI void glfwSetWindowMonitor(GLFWwindow* window, GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate);
+
+/*! @brief Returns an attribute of the specified window.
+ *
+ *  This function returns the value of an attribute of the specified window or
+ *  its OpenGL or OpenGL ES context.
+ *
+ *  @param[in] window The window to query.
+ *  @param[in] attrib The [window attribute](@ref window_attribs) whose value to
+ *  return.
+ *  @return The value of the attribute, or zero if an
+ *  [error](@ref error_handling) occurred.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ *  GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR.
+ *
+ *  @remark Framebuffer related hints are not window attributes.  See @ref
+ *  window_attribs_fb for more information.
+ *
+ *  @remark Zero is a valid value for many window and context related
+ *  attributes so you cannot use a return value of zero as an indication of
+ *  errors.  However, this function should not fail as long as it is passed
+ *  valid arguments and the library has been [initialized](@ref intro_init).
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_attribs
+ *
+ *  @since Added in version 3.0.  Replaces `glfwGetWindowParam` and
+ *  `glfwGetGLVersion`.
+ *
+ *  @ingroup window
+ */
+GLFWAPI int glfwGetWindowAttrib(GLFWwindow* window, int attrib);
+
+/*! @brief Sets the user pointer of the specified window.
+ *
+ *  This function sets the user-defined pointer of the specified window.  The
+ *  current value is retained until the window is destroyed.  The initial value
+ *  is `NULL`.
+ *
+ *  @param[in] window The window whose pointer to set.
+ *  @param[in] pointer The new value.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function may be called from any thread.  Access is not
+ *  synchronized.
+ *
+ *  @sa @ref window_userptr
+ *  @sa glfwGetWindowUserPointer
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup window
+ */
+GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* window, void* pointer);
+
+/*! @brief Returns the user pointer of the specified window.
+ *
+ *  This function returns the current value of the user-defined pointer of the
+ *  specified window.  The initial value is `NULL`.
+ *
+ *  @param[in] window The window whose pointer to return.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function may be called from any thread.  Access is not
+ *  synchronized.
+ *
+ *  @sa @ref window_userptr
+ *  @sa glfwSetWindowUserPointer
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup window
+ */
+GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* window);
+
+/*! @brief Sets the position callback for the specified window.
+ *
+ *  This function sets the position callback of the specified window, which is
+ *  called when the window is moved.  The callback is provided with the screen
+ *  position of the upper-left corner of the client area of the window.
+ *
+ *  @param[in] window The window whose callback to set.
+ *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ *  callback.
+ *  @return The previously set callback, or `NULL` if no callback was set or the
+ *  library had not been [initialized](@ref intro_init).
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_pos
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup window
+ */
+GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* window, GLFWwindowposfun cbfun);
+
+/*! @brief Sets the size callback for the specified window.
+ *
+ *  This function sets the size callback of the specified window, which is
+ *  called when the window is resized.  The callback is provided with the size,
+ *  in screen coordinates, of the client area of the window.
+ *
+ *  @param[in] window The window whose callback to set.
+ *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ *  callback.
+ *  @return The previously set callback, or `NULL` if no callback was set or the
+ *  library had not been [initialized](@ref intro_init).
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_size
+ *
+ *  @since Added in version 1.0.
+ *  @glfw3 Added window handle parameter and return value.
+ *
+ *  @ingroup window
+ */
+GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* window, GLFWwindowsizefun cbfun);
+
+/*! @brief Sets the close callback for the specified window.
+ *
+ *  This function sets the close callback of the specified window, which is
+ *  called when the user attempts to close the window, for example by clicking
+ *  the close widget in the title bar.
+ *
+ *  The close flag is set before this callback is called, but you can modify it
+ *  at any time with @ref glfwSetWindowShouldClose.
+ *
+ *  The close callback is not triggered by @ref glfwDestroyWindow.
+ *
+ *  @param[in] window The window whose callback to set.
+ *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ *  callback.
+ *  @return The previously set callback, or `NULL` if no callback was set or the
+ *  library had not been [initialized](@ref intro_init).
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @remark @osx Selecting Quit from the application menu will trigger the close
+ *  callback for all windows.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_close
+ *
+ *  @since Added in version 2.5.
+ *  @glfw3 Added window handle parameter and return value.
+ *
+ *  @ingroup window
+ */
+GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* window, GLFWwindowclosefun cbfun);
+
+/*! @brief Sets the refresh callback for the specified window.
+ *
+ *  This function sets the refresh callback of the specified window, which is
+ *  called when the client area of the window needs to be redrawn, for example
+ *  if the window has been exposed after having been covered by another window.
+ *
+ *  On compositing window systems such as Aero, Compiz or Aqua, where the window
+ *  contents are saved off-screen, this callback may be called only very
+ *  infrequently or never at all.
+ *
+ *  @param[in] window The window whose callback to set.
+ *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ *  callback.
+ *  @return The previously set callback, or `NULL` if no callback was set or the
+ *  library had not been [initialized](@ref intro_init).
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_refresh
+ *
+ *  @since Added in version 2.5.
+ *  @glfw3 Added window handle parameter and return value.
+ *
+ *  @ingroup window
+ */
+GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* window, GLFWwindowrefreshfun cbfun);
+
+/*! @brief Sets the focus callback for the specified window.
+ *
+ *  This function sets the focus callback of the specified window, which is
+ *  called when the window gains or loses input focus.
+ *
+ *  After the focus callback is called for a window that lost input focus,
+ *  synthetic key and mouse button release events will be generated for all such
+ *  that had been pressed.  For more information, see @ref glfwSetKeyCallback
+ *  and @ref glfwSetMouseButtonCallback.
+ *
+ *  @param[in] window The window whose callback to set.
+ *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ *  callback.
+ *  @return The previously set callback, or `NULL` if no callback was set or the
+ *  library had not been [initialized](@ref intro_init).
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_focus
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup window
+ */
+GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* window, GLFWwindowfocusfun cbfun);
+
+/*! @brief Sets the iconify callback for the specified window.
+ *
+ *  This function sets the iconification callback of the specified window, which
+ *  is called when the window is iconified or restored.
+ *
+ *  @param[in] window The window whose callback to set.
+ *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ *  callback.
+ *  @return The previously set callback, or `NULL` if no callback was set or the
+ *  library had not been [initialized](@ref intro_init).
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_iconify
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup window
+ */
+GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* window, GLFWwindowiconifyfun cbfun);
+
+/*! @brief Sets the framebuffer resize callback for the specified window.
+ *
+ *  This function sets the framebuffer resize callback of the specified window,
+ *  which is called when the framebuffer of the specified window is resized.
+ *
+ *  @param[in] window The window whose callback to set.
+ *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ *  callback.
+ *  @return The previously set callback, or `NULL` if no callback was set or the
+ *  library had not been [initialized](@ref intro_init).
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref window_fbsize
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup window
+ */
+GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* window, GLFWframebuffersizefun cbfun);
+
+/*! @brief Processes all pending events.
+ *
+ *  This function processes only those events that are already in the event
+ *  queue and then returns immediately.  Processing events will cause the window
+ *  and input callbacks associated with those events to be called.
+ *
+ *  On some platforms, a window move, resize or menu operation will cause event
+ *  processing to block.  This is due to how event processing is designed on
+ *  those platforms.  You can use the
+ *  [window refresh callback](@ref window_refresh) to redraw the contents of
+ *  your window when necessary during such operations.
+ *
+ *  On some platforms, certain events are sent directly to the application
+ *  without going through the event queue, causing callbacks to be called
+ *  outside of a call to one of the event processing functions.
+ *
+ *  Event processing is not required for joystick input to work.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @reentrancy This function must not be called from a callback.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref events
+ *  @sa glfwWaitEvents
+ *  @sa glfwWaitEventsTimeout
+ *
+ *  @since Added in version 1.0.
+ *
+ *  @ingroup window
+ */
+GLFWAPI void glfwPollEvents(void);
+
+/*! @brief Waits until events are queued and processes them.
+ *
+ *  This function puts the calling thread to sleep until at least one event is
+ *  available in the event queue.  Once one or more events are available,
+ *  it behaves exactly like @ref glfwPollEvents, i.e. the events in the queue
+ *  are processed and the function then returns immediately.  Processing events
+ *  will cause the window and input callbacks associated with those events to be
+ *  called.
+ *
+ *  Since not all events are associated with callbacks, this function may return
+ *  without a callback having been called even if you are monitoring all
+ *  callbacks.
+ *
+ *  On some platforms, a window move, resize or menu operation will cause event
+ *  processing to block.  This is due to how event processing is designed on
+ *  those platforms.  You can use the
+ *  [window refresh callback](@ref window_refresh) to redraw the contents of
+ *  your window when necessary during such operations.
+ *
+ *  On some platforms, certain callbacks may be called outside of a call to one
+ *  of the event processing functions.
+ *
+ *  If no windows exist, this function returns immediately.  For synchronization
+ *  of threads in applications that do not create windows, use your threading
+ *  library of choice.
+ *
+ *  Event processing is not required for joystick input to work.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @reentrancy This function must not be called from a callback.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref events
+ *  @sa glfwPollEvents
+ *  @sa glfwWaitEventsTimeout
+ *
+ *  @since Added in version 2.5.
+ *
+ *  @ingroup window
+ */
+GLFWAPI void glfwWaitEvents(void);
+
+/*! @brief Waits with timeout until events are queued and processes them.
+ *
+ *  This function puts the calling thread to sleep until at least one event is
+ *  available in the event queue, or until the specified timeout is reached.  If
+ *  one or more events are available, it behaves exactly like @ref
+ *  glfwPollEvents, i.e. the events in the queue are processed and the function
+ *  then returns immediately.  Processing events will cause the window and input
+ *  callbacks associated with those events to be called.
+ *
+ *  The timeout value must be a positive finite number.
+ *
+ *  Since not all events are associated with callbacks, this function may return
+ *  without a callback having been called even if you are monitoring all
+ *  callbacks.
+ *
+ *  On some platforms, a window move, resize or menu operation will cause event
+ *  processing to block.  This is due to how event processing is designed on
+ *  those platforms.  You can use the
+ *  [window refresh callback](@ref window_refresh) to redraw the contents of
+ *  your window when necessary during such operations.
+ *
+ *  On some platforms, certain callbacks may be called outside of a call to one
+ *  of the event processing functions.
+ *
+ *  If no windows exist, this function returns immediately.  For synchronization
+ *  of threads in applications that do not create windows, use your threading
+ *  library of choice.
+ *
+ *  Event processing is not required for joystick input to work.
+ *
+ *  @param[in] timeout The maximum amount of time, in seconds, to wait.
+ *
+ *  @reentrancy This function must not be called from a callback.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref events
+ *  @sa glfwPollEvents
+ *  @sa glfwWaitEvents
+ *
+ *  @since Added in version 3.2.
+ *
+ *  @ingroup window
+ */
+GLFWAPI void glfwWaitEventsTimeout(double timeout);
+
+/*! @brief Posts an empty event to the event queue.
+ *
+ *  This function posts an empty event from the current thread to the event
+ *  queue, causing @ref glfwWaitEvents or @ref glfwWaitEventsTimeout to return.
+ *
+ *  If no windows exist, this function returns immediately.  For synchronization
+ *  of threads in applications that do not create windows, use your threading
+ *  library of choice.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @thread_safety This function may be called from any thread.
+ *
+ *  @sa @ref events
+ *  @sa glfwWaitEvents
+ *  @sa glfwWaitEventsTimeout
+ *
+ *  @since Added in version 3.1.
+ *
+ *  @ingroup window
+ */
+GLFWAPI void glfwPostEmptyEvent(void);
+
+/*! @brief Returns the value of an input option for the specified window.
+ *
+ *  This function returns the value of an input option for the specified window.
+ *  The mode must be one of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or
+ *  `GLFW_STICKY_MOUSE_BUTTONS`.
+ *
+ *  @param[in] window The window to query.
+ *  @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or
+ *  `GLFW_STICKY_MOUSE_BUTTONS`.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_INVALID_ENUM.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa glfwSetInputMode
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup input
+ */
+GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode);
+
+/*! @brief Sets an input option for the specified window.
+ *
+ *  This function sets an input mode option for the specified window.  The mode
+ *  must be one of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or
+ *  `GLFW_STICKY_MOUSE_BUTTONS`.
+ *
+ *  If the mode is `GLFW_CURSOR`, the value must be one of the following cursor
+ *  modes:
+ *  - `GLFW_CURSOR_NORMAL` makes the cursor visible and behaving normally.
+ *  - `GLFW_CURSOR_HIDDEN` makes the cursor invisible when it is over the client
+ *    area of the window but does not restrict the cursor from leaving.
+ *  - `GLFW_CURSOR_DISABLED` hides and grabs the cursor, providing virtual
+ *    and unlimited cursor movement.  This is useful for implementing for
+ *    example 3D camera controls.
+ *
+ *  If the mode is `GLFW_STICKY_KEYS`, the value must be either `GLFW_TRUE` to
+ *  enable sticky keys, or `GLFW_FALSE` to disable it.  If sticky keys are
+ *  enabled, a key press will ensure that @ref glfwGetKey returns `GLFW_PRESS`
+ *  the next time it is called even if the key had been released before the
+ *  call.  This is useful when you are only interested in whether keys have been
+ *  pressed but not when or in which order.
+ *
+ *  If the mode is `GLFW_STICKY_MOUSE_BUTTONS`, the value must be either
+ *  `GLFW_TRUE` to enable sticky mouse buttons, or `GLFW_FALSE` to disable it.
+ *  If sticky mouse buttons are enabled, a mouse button press will ensure that
+ *  @ref glfwGetMouseButton returns `GLFW_PRESS` the next time it is called even
+ *  if the mouse button had been released before the call.  This is useful when
+ *  you are only interested in whether mouse buttons have been pressed but not
+ *  when or in which order.
+ *
+ *  @param[in] window The window whose input mode to set.
+ *  @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or
+ *  `GLFW_STICKY_MOUSE_BUTTONS`.
+ *  @param[in] value The new value of the specified input mode.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ *  GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa glfwGetInputMode
+ *
+ *  @since Added in version 3.0.  Replaces `glfwEnable` and `glfwDisable`.
+ *
+ *  @ingroup input
+ */
+GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value);
+
+/*! @brief Returns the localized name of the specified printable key.
+ *
+ *  This function returns the localized name of the specified printable key.
+ *  This is intended for displaying key bindings to the user.
+ *
+ *  If the key is `GLFW_KEY_UNKNOWN`, the scancode is used instead, otherwise
+ *  the scancode is ignored.  If a non-printable key or (if the key is
+ *  `GLFW_KEY_UNKNOWN`) a scancode that maps to a non-printable key is
+ *  specified, this function returns `NULL`.          
+ *
+ *  This behavior allows you to pass in the arguments passed to the
+ *  [key callback](@ref input_key) without modification.
+ *
+ *  The printable keys are:
+ *  - `GLFW_KEY_APOSTROPHE`
+ *  - `GLFW_KEY_COMMA`
+ *  - `GLFW_KEY_MINUS`
+ *  - `GLFW_KEY_PERIOD`
+ *  - `GLFW_KEY_SLASH`
+ *  - `GLFW_KEY_SEMICOLON`
+ *  - `GLFW_KEY_EQUAL`
+ *  - `GLFW_KEY_LEFT_BRACKET`
+ *  - `GLFW_KEY_RIGHT_BRACKET`
+ *  - `GLFW_KEY_BACKSLASH`
+ *  - `GLFW_KEY_WORLD_1`
+ *  - `GLFW_KEY_WORLD_2`
+ *  - `GLFW_KEY_0` to `GLFW_KEY_9`
+ *  - `GLFW_KEY_A` to `GLFW_KEY_Z`
+ *  - `GLFW_KEY_KP_0` to `GLFW_KEY_KP_9`
+ *  - `GLFW_KEY_KP_DECIMAL`
+ *  - `GLFW_KEY_KP_DIVIDE`
+ *  - `GLFW_KEY_KP_MULTIPLY`
+ *  - `GLFW_KEY_KP_SUBTRACT`
+ *  - `GLFW_KEY_KP_ADD`
+ *  - `GLFW_KEY_KP_EQUAL`
+ *
+ *  @param[in] key The key to query, or `GLFW_KEY_UNKNOWN`.
+ *  @param[in] scancode The scancode of the key to query.
+ *  @return The localized name of the key, or `NULL`.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @pointer_lifetime The returned string is allocated and freed by GLFW.  You
+ *  should not free it yourself.  It is valid until the next call to @ref
+ *  glfwGetKeyName, or until the library is terminated.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref input_key_name
+ *
+ *  @since Added in version 3.2.
+ *
+ *  @ingroup input
+ */
+GLFWAPI const char* glfwGetKeyName(int key, int scancode);
+
+/*! @brief Returns the last reported state of a keyboard key for the specified
+ *  window.
+ *
+ *  This function returns the last state reported for the specified key to the
+ *  specified window.  The returned state is one of `GLFW_PRESS` or
+ *  `GLFW_RELEASE`.  The higher-level action `GLFW_REPEAT` is only reported to
+ *  the key callback.
+ *
+ *  If the `GLFW_STICKY_KEYS` input mode is enabled, this function returns
+ *  `GLFW_PRESS` the first time you call it for a key that was pressed, even if
+ *  that key has already been released.
+ *
+ *  The key functions deal with physical keys, with [key tokens](@ref keys)
+ *  named after their use on the standard US keyboard layout.  If you want to
+ *  input text, use the Unicode character callback instead.
+ *
+ *  The [modifier key bit masks](@ref mods) are not key tokens and cannot be
+ *  used with this function.
+ *
+ *  __Do not use this function__ to implement [text input](@ref input_char).
+ *
+ *  @param[in] window The desired window.
+ *  @param[in] key The desired [keyboard key](@ref keys).  `GLFW_KEY_UNKNOWN` is
+ *  not a valid key for this function.
+ *  @return One of `GLFW_PRESS` or `GLFW_RELEASE`.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_INVALID_ENUM.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref input_key
+ *
+ *  @since Added in version 1.0.
+ *  @glfw3 Added window handle parameter.
+ *
+ *  @ingroup input
+ */
+GLFWAPI int glfwGetKey(GLFWwindow* window, int key);
+
+/*! @brief Returns the last reported state of a mouse button for the specified
+ *  window.
+ *
+ *  This function returns the last state reported for the specified mouse button
+ *  to the specified window.  The returned state is one of `GLFW_PRESS` or
+ *  `GLFW_RELEASE`.
+ *
+ *  If the `GLFW_STICKY_MOUSE_BUTTONS` input mode is enabled, this function
+ *  `GLFW_PRESS` the first time you call it for a mouse button that was pressed,
+ *  even if that mouse button has already been released.
+ *
+ *  @param[in] window The desired window.
+ *  @param[in] button The desired [mouse button](@ref buttons).
+ *  @return One of `GLFW_PRESS` or `GLFW_RELEASE`.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_INVALID_ENUM.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref input_mouse_button
+ *
+ *  @since Added in version 1.0.
+ *  @glfw3 Added window handle parameter.
+ *
+ *  @ingroup input
+ */
+GLFWAPI int glfwGetMouseButton(GLFWwindow* window, int button);
+
+/*! @brief Retrieves the position of the cursor relative to the client area of
+ *  the window.
+ *
+ *  This function returns the position of the cursor, in screen coordinates,
+ *  relative to the upper-left corner of the client area of the specified
+ *  window.
+ *
+ *  If the cursor is disabled (with `GLFW_CURSOR_DISABLED`) then the cursor
+ *  position is unbounded and limited only by the minimum and maximum values of
+ *  a `double`.
+ *
+ *  The coordinate can be converted to their integer equivalents with the
+ *  `floor` function.  Casting directly to an integer type works for positive
+ *  coordinates, but fails for negative ones.
+ *
+ *  Any or all of the position arguments may be `NULL`.  If an error occurs, all
+ *  non-`NULL` position arguments will be set to zero.
+ *
+ *  @param[in] window The desired window.
+ *  @param[out] xpos Where to store the cursor x-coordinate, relative to the
+ *  left edge of the client area, or `NULL`.
+ *  @param[out] ypos Where to store the cursor y-coordinate, relative to the to
+ *  top edge of the client area, or `NULL`.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref cursor_pos
+ *  @sa glfwSetCursorPos
+ *
+ *  @since Added in version 3.0.  Replaces `glfwGetMousePos`.
+ *
+ *  @ingroup input
+ */
+GLFWAPI void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos);
+
+/*! @brief Sets the position of the cursor, relative to the client area of the
+ *  window.
+ *
+ *  This function sets the position, in screen coordinates, of the cursor
+ *  relative to the upper-left corner of the client area of the specified
+ *  window.  The window must have input focus.  If the window does not have
+ *  input focus when this function is called, it fails silently.
+ *
+ *  __Do not use this function__ to implement things like camera controls.  GLFW
+ *  already provides the `GLFW_CURSOR_DISABLED` cursor mode that hides the
+ *  cursor, transparently re-centers it and provides unconstrained cursor
+ *  motion.  See @ref glfwSetInputMode for more information.
+ *
+ *  If the cursor mode is `GLFW_CURSOR_DISABLED` then the cursor position is
+ *  unconstrained and limited only by the minimum and maximum values of
+ *  a `double`.
+ *
+ *  @param[in] window The desired window.
+ *  @param[in] xpos The desired x-coordinate, relative to the left edge of the
+ *  client area.
+ *  @param[in] ypos The desired y-coordinate, relative to the top edge of the
+ *  client area.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref cursor_pos
+ *  @sa glfwGetCursorPos
+ *
+ *  @since Added in version 3.0.  Replaces `glfwSetMousePos`.
+ *
+ *  @ingroup input
+ */
+GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos);
+
+/*! @brief Creates a custom cursor.
+ *
+ *  Creates a new custom cursor image that can be set for a window with @ref
+ *  glfwSetCursor.  The cursor can be destroyed with @ref glfwDestroyCursor.
+ *  Any remaining cursors are destroyed by @ref glfwTerminate.
+ *
+ *  The pixels are 32-bit, little-endian, non-premultiplied RGBA, i.e. eight
+ *  bits per channel.  They are arranged canonically as packed sequential rows,
+ *  starting from the top-left corner.
+ *
+ *  The cursor hotspot is specified in pixels, relative to the upper-left corner
+ *  of the cursor image.  Like all other coordinate systems in GLFW, the X-axis
+ *  points to the right and the Y-axis points down.
+ *
+ *  @param[in] image The desired cursor image.
+ *  @param[in] xhot The desired x-coordinate, in pixels, of the cursor hotspot.
+ *  @param[in] yhot The desired y-coordinate, in pixels, of the cursor hotspot.
+ *  @return The handle of the created cursor, or `NULL` if an
+ *  [error](@ref error_handling) occurred.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @pointer_lifetime The specified image data is copied before this function
+ *  returns.
+ *
+ *  @reentrancy This function must not be called from a callback.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref cursor_object
+ *  @sa glfwDestroyCursor
+ *  @sa glfwCreateStandardCursor
+ *
+ *  @since Added in version 3.1.
+ *
+ *  @ingroup input
+ */
+GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot);
+
+/*! @brief Creates a cursor with a standard shape.
+ *
+ *  Returns a cursor with a [standard shape](@ref shapes), that can be set for
+ *  a window with @ref glfwSetCursor.
+ *
+ *  @param[in] shape One of the [standard shapes](@ref shapes).
+ *  @return A new cursor ready to use or `NULL` if an
+ *  [error](@ref error_handling) occurred.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ *  GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR.
+ *
+ *  @reentrancy This function must not be called from a callback.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref cursor_object
+ *  @sa glfwCreateCursor
+ *
+ *  @since Added in version 3.1.
+ *
+ *  @ingroup input
+ */
+GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape);
+
+/*! @brief Destroys a cursor.
+ *
+ *  This function destroys a cursor previously created with @ref
+ *  glfwCreateCursor.  Any remaining cursors will be destroyed by @ref
+ *  glfwTerminate.
+ *
+ *  @param[in] cursor The cursor object to destroy.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @reentrancy This function must not be called from a callback.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref cursor_object
+ *  @sa glfwCreateCursor
+ *
+ *  @since Added in version 3.1.
+ *
+ *  @ingroup input
+ */
+GLFWAPI void glfwDestroyCursor(GLFWcursor* cursor);
+
+/*! @brief Sets the cursor for the window.
+ *
+ *  This function sets the cursor image to be used when the cursor is over the
+ *  client area of the specified window.  The set cursor will only be visible
+ *  when the [cursor mode](@ref cursor_mode) of the window is
+ *  `GLFW_CURSOR_NORMAL`.
+ *
+ *  On some platforms, the set cursor may not be visible unless the window also
+ *  has input focus.
+ *
+ *  @param[in] window The window to set the cursor for.
+ *  @param[in] cursor The cursor to set, or `NULL` to switch back to the default
+ *  arrow cursor.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref cursor_object
+ *
+ *  @since Added in version 3.1.
+ *
+ *  @ingroup input
+ */
+GLFWAPI void glfwSetCursor(GLFWwindow* window, GLFWcursor* cursor);
+
+/*! @brief Sets the key callback.
+ *
+ *  This function sets the key callback of the specified window, which is called
+ *  when a key is pressed, repeated or released.
+ *
+ *  The key functions deal with physical keys, with layout independent
+ *  [key tokens](@ref keys) named after their values in the standard US keyboard
+ *  layout.  If you want to input text, use the
+ *  [character callback](@ref glfwSetCharCallback) instead.
+ *
+ *  When a window loses input focus, it will generate synthetic key release
+ *  events for all pressed keys.  You can tell these events from user-generated
+ *  events by the fact that the synthetic ones are generated after the focus
+ *  loss event has been processed, i.e. after the
+ *  [window focus callback](@ref glfwSetWindowFocusCallback) has been called.
+ *
+ *  The scancode of a key is specific to that platform or sometimes even to that
+ *  machine.  Scancodes are intended to allow users to bind keys that don't have
+ *  a GLFW key token.  Such keys have `key` set to `GLFW_KEY_UNKNOWN`, their
+ *  state is not saved and so it cannot be queried with @ref glfwGetKey.
+ *
+ *  Sometimes GLFW needs to generate synthetic key events, in which case the
+ *  scancode may be zero.
+ *
+ *  @param[in] window The window whose callback to set.
+ *  @param[in] cbfun The new key callback, or `NULL` to remove the currently
+ *  set callback.
+ *  @return The previously set callback, or `NULL` if no callback was set or the
+ *  library had not been [initialized](@ref intro_init).
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref input_key
+ *
+ *  @since Added in version 1.0.
+ *  @glfw3 Added window handle parameter and return value.
+ *
+ *  @ingroup input
+ */
+GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun cbfun);
+
+/*! @brief Sets the Unicode character callback.
+ *
+ *  This function sets the character callback of the specified window, which is
+ *  called when a Unicode character is input.
+ *
+ *  The character callback is intended for Unicode text input.  As it deals with
+ *  characters, it is keyboard layout dependent, whereas the
+ *  [key callback](@ref glfwSetKeyCallback) is not.  Characters do not map 1:1
+ *  to physical keys, as a key may produce zero, one or more characters.  If you
+ *  want to know whether a specific physical key was pressed or released, see
+ *  the key callback instead.
+ *
+ *  The character callback behaves as system text input normally does and will
+ *  not be called if modifier keys are held down that would prevent normal text
+ *  input on that platform, for example a Super (Command) key on OS X or Alt key
+ *  on Windows.  There is a
+ *  [character with modifiers callback](@ref glfwSetCharModsCallback) that
+ *  receives these events.
+ *
+ *  @param[in] window The window whose callback to set.
+ *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ *  callback.
+ *  @return The previously set callback, or `NULL` if no callback was set or the
+ *  library had not been [initialized](@ref intro_init).
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref input_char
+ *
+ *  @since Added in version 2.4.
+ *  @glfw3 Added window handle parameter and return value.
+ *
+ *  @ingroup input
+ */
+GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun cbfun);
+
+/*! @brief Sets the Unicode character with modifiers callback.
+ *
+ *  This function sets the character with modifiers callback of the specified
+ *  window, which is called when a Unicode character is input regardless of what
+ *  modifier keys are used.
+ *
+ *  The character with modifiers callback is intended for implementing custom
+ *  Unicode character input.  For regular Unicode text input, see the
+ *  [character callback](@ref glfwSetCharCallback).  Like the character
+ *  callback, the character with modifiers callback deals with characters and is
+ *  keyboard layout dependent.  Characters do not map 1:1 to physical keys, as
+ *  a key may produce zero, one or more characters.  If you want to know whether
+ *  a specific physical key was pressed or released, see the
+ *  [key callback](@ref glfwSetKeyCallback) instead.
+ *
+ *  @param[in] window The window whose callback to set.
+ *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ *  callback.
+ *  @return The previously set callback, or `NULL` if no callback was set or an
+ *  [error](@ref error_handling) occurred.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref input_char
+ *
+ *  @since Added in version 3.1.
+ *
+ *  @ingroup input
+ */
+GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmodsfun cbfun);
+
+/*! @brief Sets the mouse button callback.
+ *
+ *  This function sets the mouse button callback of the specified window, which
+ *  is called when a mouse button is pressed or released.
+ *
+ *  When a window loses input focus, it will generate synthetic mouse button
+ *  release events for all pressed mouse buttons.  You can tell these events
+ *  from user-generated events by the fact that the synthetic ones are generated
+ *  after the focus loss event has been processed, i.e. after the
+ *  [window focus callback](@ref glfwSetWindowFocusCallback) has been called.
+ *
+ *  @param[in] window The window whose callback to set.
+ *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ *  callback.
+ *  @return The previously set callback, or `NULL` if no callback was set or the
+ *  library had not been [initialized](@ref intro_init).
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref input_mouse_button
+ *
+ *  @since Added in version 1.0.
+ *  @glfw3 Added window handle parameter and return value.
+ *
+ *  @ingroup input
+ */
+GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* window, GLFWmousebuttonfun cbfun);
+
+/*! @brief Sets the cursor position callback.
+ *
+ *  This function sets the cursor position callback of the specified window,
+ *  which is called when the cursor is moved.  The callback is provided with the
+ *  position, in screen coordinates, relative to the upper-left corner of the
+ *  client area of the window.
+ *
+ *  @param[in] window The window whose callback to set.
+ *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ *  callback.
+ *  @return The previously set callback, or `NULL` if no callback was set or the
+ *  library had not been [initialized](@ref intro_init).
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref cursor_pos
+ *
+ *  @since Added in version 3.0.  Replaces `glfwSetMousePosCallback`.
+ *
+ *  @ingroup input
+ */
+GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* window, GLFWcursorposfun cbfun);
+
+/*! @brief Sets the cursor enter/exit callback.
+ *
+ *  This function sets the cursor boundary crossing callback of the specified
+ *  window, which is called when the cursor enters or leaves the client area of
+ *  the window.
+ *
+ *  @param[in] window The window whose callback to set.
+ *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ *  callback.
+ *  @return The previously set callback, or `NULL` if no callback was set or the
+ *  library had not been [initialized](@ref intro_init).
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref cursor_enter
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup input
+ */
+GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* window, GLFWcursorenterfun cbfun);
+
+/*! @brief Sets the scroll callback.
+ *
+ *  This function sets the scroll callback of the specified window, which is
+ *  called when a scrolling device is used, such as a mouse wheel or scrolling
+ *  area of a touchpad.
+ *
+ *  The scroll callback receives all scrolling input, like that from a mouse
+ *  wheel or a touchpad scrolling area.
+ *
+ *  @param[in] window The window whose callback to set.
+ *  @param[in] cbfun The new scroll callback, or `NULL` to remove the currently
+ *  set callback.
+ *  @return The previously set callback, or `NULL` if no callback was set or the
+ *  library had not been [initialized](@ref intro_init).
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref scrolling
+ *
+ *  @since Added in version 3.0.  Replaces `glfwSetMouseWheelCallback`.
+ *
+ *  @ingroup input
+ */
+GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun cbfun);
+
+/*! @brief Sets the file drop callback.
+ *
+ *  This function sets the file drop callback of the specified window, which is
+ *  called when one or more dragged files are dropped on the window.
+ *
+ *  Because the path array and its strings may have been generated specifically
+ *  for that event, they are not guaranteed to be valid after the callback has
+ *  returned.  If you wish to use them after the callback returns, you need to
+ *  make a deep copy.
+ *
+ *  @param[in] window The window whose callback to set.
+ *  @param[in] cbfun The new file drop callback, or `NULL` to remove the
+ *  currently set callback.
+ *  @return The previously set callback, or `NULL` if no callback was set or the
+ *  library had not been [initialized](@ref intro_init).
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref path_drop
+ *
+ *  @since Added in version 3.1.
+ *
+ *  @ingroup input
+ */
+GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* window, GLFWdropfun cbfun);
+
+/*! @brief Returns whether the specified joystick is present.
+ *
+ *  This function returns whether the specified joystick is present.
+ *
+ *  @param[in] joy The [joystick](@ref joysticks) to query.
+ *  @return `GLFW_TRUE` if the joystick is present, or `GLFW_FALSE` otherwise.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ *  GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref joystick
+ *
+ *  @since Added in version 3.0.  Replaces `glfwGetJoystickParam`.
+ *
+ *  @ingroup input
+ */
+GLFWAPI int glfwJoystickPresent(int joy);
+
+/*! @brief Returns the values of all axes of the specified joystick.
+ *
+ *  This function returns the values of all axes of the specified joystick.
+ *  Each element in the array is a value between -1.0 and 1.0.
+ *
+ *  Querying a joystick slot with no device present is not an error, but will
+ *  cause this function to return `NULL`.  Call @ref glfwJoystickPresent to
+ *  check device presence.
+ *
+ *  @param[in] joy The [joystick](@ref joysticks) to query.
+ *  @param[out] count Where to store the number of axis values in the returned
+ *  array.  This is set to zero if the joystick is not present or an error
+ *  occurred.
+ *  @return An array of axis values, or `NULL` if the joystick is not present or
+ *  an [error](@ref error_handling) occurred.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ *  GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR.
+ *
+ *  @pointer_lifetime The returned array is allocated and freed by GLFW.  You
+ *  should not free it yourself.  It is valid until the specified joystick is
+ *  disconnected, this function is called again for that joystick or the library
+ *  is terminated.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref joystick_axis
+ *
+ *  @since Added in version 3.0.  Replaces `glfwGetJoystickPos`.
+ *
+ *  @ingroup input
+ */
+GLFWAPI const float* glfwGetJoystickAxes(int joy, int* count);
+
+/*! @brief Returns the state of all buttons of the specified joystick.
+ *
+ *  This function returns the state of all buttons of the specified joystick.
+ *  Each element in the array is either `GLFW_PRESS` or `GLFW_RELEASE`.
+ *
+ *  Querying a joystick slot with no device present is not an error, but will
+ *  cause this function to return `NULL`.  Call @ref glfwJoystickPresent to
+ *  check device presence.
+ *
+ *  @param[in] joy The [joystick](@ref joysticks) to query.
+ *  @param[out] count Where to store the number of button states in the returned
+ *  array.  This is set to zero if the joystick is not present or an error
+ *  occurred.
+ *  @return An array of button states, or `NULL` if the joystick is not present
+ *  or an [error](@ref error_handling) occurred.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ *  GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR.
+ *
+ *  @pointer_lifetime The returned array is allocated and freed by GLFW.  You
+ *  should not free it yourself.  It is valid until the specified joystick is
+ *  disconnected, this function is called again for that joystick or the library
+ *  is terminated.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref joystick_button
+ *
+ *  @since Added in version 2.2.
+ *  @glfw3 Changed to return a dynamic array.
+ *
+ *  @ingroup input
+ */
+GLFWAPI const unsigned char* glfwGetJoystickButtons(int joy, int* count);
+
+/*! @brief Returns the name of the specified joystick.
+ *
+ *  This function returns the name, encoded as UTF-8, of the specified joystick.
+ *  The returned string is allocated and freed by GLFW.  You should not free it
+ *  yourself.
+ *
+ *  Querying a joystick slot with no device present is not an error, but will
+ *  cause this function to return `NULL`.  Call @ref glfwJoystickPresent to
+ *  check device presence.
+ *
+ *  @param[in] joy The [joystick](@ref joysticks) to query.
+ *  @return The UTF-8 encoded name of the joystick, or `NULL` if the joystick
+ *  is not present or an [error](@ref error_handling) occurred.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ *  GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR.
+ *
+ *  @pointer_lifetime The returned string is allocated and freed by GLFW.  You
+ *  should not free it yourself.  It is valid until the specified joystick is
+ *  disconnected, this function is called again for that joystick or the library
+ *  is terminated.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref joystick_name
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup input
+ */
+GLFWAPI const char* glfwGetJoystickName(int joy);
+
+/*! @brief Sets the joystick configuration callback.
+ *
+ *  This function sets the joystick configuration callback, or removes the
+ *  currently set callback.  This is called when a joystick is connected to or
+ *  disconnected from the system.
+ *
+ *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ *  callback.
+ *  @return The previously set callback, or `NULL` if no callback was set or the
+ *  library had not been [initialized](@ref intro_init).
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref joystick_event
+ *
+ *  @since Added in version 3.2.
+ *
+ *  @ingroup input
+ */
+GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun);
+
+/*! @brief Sets the clipboard to the specified string.
+ *
+ *  This function sets the system clipboard to the specified, UTF-8 encoded
+ *  string.
+ *
+ *  @param[in] window The window that will own the clipboard contents.
+ *  @param[in] string A UTF-8 encoded string.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @pointer_lifetime The specified string is copied before this function
+ *  returns.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref clipboard
+ *  @sa glfwGetClipboardString
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup input
+ */
+GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string);
+
+/*! @brief Returns the contents of the clipboard as a string.
+ *
+ *  This function returns the contents of the system clipboard, if it contains
+ *  or is convertible to a UTF-8 encoded string.  If the clipboard is empty or
+ *  if its contents cannot be converted, `NULL` is returned and a @ref
+ *  GLFW_FORMAT_UNAVAILABLE error is generated.
+ *
+ *  @param[in] window The window that will request the clipboard contents.
+ *  @return The contents of the clipboard as a UTF-8 encoded string, or `NULL`
+ *  if an [error](@ref error_handling) occurred.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @pointer_lifetime The returned string is allocated and freed by GLFW.  You
+ *  should not free it yourself.  It is valid until the next call to @ref
+ *  glfwGetClipboardString or @ref glfwSetClipboardString, or until the library
+ *  is terminated.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref clipboard
+ *  @sa glfwSetClipboardString
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup input
+ */
+GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window);
+
+/*! @brief Returns the value of the GLFW timer.
+ *
+ *  This function returns the value of the GLFW timer.  Unless the timer has
+ *  been set using @ref glfwSetTime, the timer measures time elapsed since GLFW
+ *  was initialized.
+ *
+ *  The resolution of the timer is system dependent, but is usually on the order
+ *  of a few micro- or nanoseconds.  It uses the highest-resolution monotonic
+ *  time source on each supported platform.
+ *
+ *  @return The current value, in seconds, or zero if an
+ *  [error](@ref error_handling) occurred.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function may be called from any thread.  Reading and
+ *  writing of the internal timer offset is not atomic, so it needs to be
+ *  externally synchronized with calls to @ref glfwSetTime.
+ *
+ *  @sa @ref time
+ *
+ *  @since Added in version 1.0.
+ *
+ *  @ingroup input
+ */
+GLFWAPI double glfwGetTime(void);
+
+/*! @brief Sets the GLFW timer.
+ *
+ *  This function sets the value of the GLFW timer.  It then continues to count
+ *  up from that value.  The value must be a positive finite number less than
+ *  or equal to 18446744073.0, which is approximately 584.5 years.
+ *
+ *  @param[in] time The new value, in seconds.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_INVALID_VALUE.
+ *
+ *  @remark The upper limit of the timer is calculated as
+ *  floor((2<sup>64</sup> - 1) / 10<sup>9</sup>) and is due to implementations
+ *  storing nanoseconds in 64 bits.  The limit may be increased in the future.
+ *
+ *  @thread_safety This function may be called from any thread.  Reading and
+ *  writing of the internal timer offset is not atomic, so it needs to be
+ *  externally synchronized with calls to @ref glfwGetTime.
+ *
+ *  @sa @ref time
+ *
+ *  @since Added in version 2.2.
+ *
+ *  @ingroup input
+ */
+GLFWAPI void glfwSetTime(double time);
+
+/*! @brief Returns the current value of the raw timer.
+ *
+ *  This function returns the current value of the raw timer, measured in
+ *  1&nbsp;/&nbsp;frequency seconds.  To get the frequency, call @ref
+ *  glfwGetTimerFrequency.
+ *
+ *  @return The value of the timer, or zero if an 
+ *  [error](@ref error_handling) occurred.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function may be called from any thread.
+ *
+ *  @sa @ref time
+ *  @sa glfwGetTimerFrequency
+ *
+ *  @since Added in version 3.2.
+ *
+ *  @ingroup input
+ */
+GLFWAPI uint64_t glfwGetTimerValue(void);
+
+/*! @brief Returns the frequency, in Hz, of the raw timer.
+ *
+ *  This function returns the frequency, in Hz, of the raw timer.
+ *
+ *  @return The frequency of the timer, in Hz, or zero if an
+ *  [error](@ref error_handling) occurred.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function may be called from any thread.
+ *
+ *  @sa @ref time
+ *  @sa glfwGetTimerValue
+ *
+ *  @since Added in version 3.2.
+ *
+ *  @ingroup input
+ */
+GLFWAPI uint64_t glfwGetTimerFrequency(void);
+
+/*! @brief Makes the context of the specified window current for the calling
+ *  thread.
+ *
+ *  This function makes the OpenGL or OpenGL ES context of the specified window
+ *  current on the calling thread.  A context can only be made current on
+ *  a single thread at a time and each thread can have only a single current
+ *  context at a time.
+ *
+ *  By default, making a context non-current implicitly forces a pipeline flush.
+ *  On machines that support `GL_KHR_context_flush_control`, you can control
+ *  whether a context performs this flush by setting the
+ *  [GLFW_CONTEXT_RELEASE_BEHAVIOR](@ref window_hints_ctx) window hint.
+ *
+ *  The specified window must have an OpenGL or OpenGL ES context.  Specifying
+ *  a window without a context will generate a @ref GLFW_NO_WINDOW_CONTEXT
+ *  error.
+ *
+ *  @param[in] window The window whose context to make current, or `NULL` to
+ *  detach the current context.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ *  GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR.
+ *
+ *  @thread_safety This function may be called from any thread.
+ *
+ *  @sa @ref context_current
+ *  @sa glfwGetCurrentContext
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup context
+ */
+GLFWAPI void glfwMakeContextCurrent(GLFWwindow* window);
+
+/*! @brief Returns the window whose context is current on the calling thread.
+ *
+ *  This function returns the window whose OpenGL or OpenGL ES context is
+ *  current on the calling thread.
+ *
+ *  @return The window whose context is current, or `NULL` if no window's
+ *  context is current.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function may be called from any thread.
+ *
+ *  @sa @ref context_current
+ *  @sa glfwMakeContextCurrent
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup context
+ */
+GLFWAPI GLFWwindow* glfwGetCurrentContext(void);
+
+/*! @brief Swaps the front and back buffers of the specified window.
+ *
+ *  This function swaps the front and back buffers of the specified window when
+ *  rendering with OpenGL or OpenGL ES.  If the swap interval is greater than
+ *  zero, the GPU driver waits the specified number of screen updates before
+ *  swapping the buffers.
+ *
+ *  The specified window must have an OpenGL or OpenGL ES context.  Specifying
+ *  a window without a context will generate a @ref GLFW_NO_WINDOW_CONTEXT
+ *  error.
+ *
+ *  This function does not apply to Vulkan.  If you are rendering with Vulkan,
+ *  see `vkQueuePresentKHR` instead.
+ *
+ *  @param[in] window The window whose buffers to swap.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ *  GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR.
+ *
+ *  @remark __EGL:__ The context of the specified window must be current on the
+ *  calling thread.
+ *
+ *  @thread_safety This function may be called from any thread.
+ *
+ *  @sa @ref buffer_swap
+ *  @sa glfwSwapInterval
+ *
+ *  @since Added in version 1.0.
+ *  @glfw3 Added window handle parameter.
+ *
+ *  @ingroup window
+ */
+GLFWAPI void glfwSwapBuffers(GLFWwindow* window);
+
+/*! @brief Sets the swap interval for the current context.
+ *
+ *  This function sets the swap interval for the current OpenGL or OpenGL ES
+ *  context, i.e. the number of screen updates to wait from the time @ref
+ *  glfwSwapBuffers was called before swapping the buffers and returning.  This
+ *  is sometimes called _vertical synchronization_, _vertical retrace
+ *  synchronization_ or just _vsync_.
+ *
+ *  Contexts that support either of the `WGL_EXT_swap_control_tear` and
+ *  `GLX_EXT_swap_control_tear` extensions also accept negative swap intervals,
+ *  which allow the driver to swap even if a frame arrives a little bit late.
+ *  You can check for the presence of these extensions using @ref
+ *  glfwExtensionSupported.  For more information about swap tearing, see the
+ *  extension specifications.
+ *
+ *  A context must be current on the calling thread.  Calling this function
+ *  without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error.
+ *
+ *  This function does not apply to Vulkan.  If you are rendering with Vulkan,
+ *  see the present mode of your swapchain instead.
+ *
+ *  @param[in] interval The minimum number of screen updates to wait for
+ *  until the buffers are swapped by @ref glfwSwapBuffers.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ *  GLFW_NO_CURRENT_CONTEXT and @ref GLFW_PLATFORM_ERROR.
+ *
+ *  @remark This function is not called during context creation, leaving the
+ *  swap interval set to whatever is the default on that platform.  This is done
+ *  because some swap interval extensions used by GLFW do not allow the swap
+ *  interval to be reset to zero once it has been set to a non-zero value.
+ *
+ *  @remark Some GPU drivers do not honor the requested swap interval, either
+ *  because of a user setting that overrides the application's request or due to
+ *  bugs in the driver.
+ *
+ *  @thread_safety This function may be called from any thread.
+ *
+ *  @sa @ref buffer_swap
+ *  @sa glfwSwapBuffers
+ *
+ *  @since Added in version 1.0.
+ *
+ *  @ingroup context
+ */
+GLFWAPI void glfwSwapInterval(int interval);
+
+/*! @brief Returns whether the specified extension is available.
+ *
+ *  This function returns whether the specified
+ *  [API extension](@ref context_glext) is supported by the current OpenGL or
+ *  OpenGL ES context.  It searches both for client API extension and context
+ *  creation API extensions.
+ *
+ *  A context must be current on the calling thread.  Calling this function
+ *  without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error.
+ *
+ *  As this functions retrieves and searches one or more extension strings each
+ *  call, it is recommended that you cache its results if it is going to be used
+ *  frequently.  The extension strings will not change during the lifetime of
+ *  a context, so there is no danger in doing this.
+ *
+ *  This function does not apply to Vulkan.  If you are using Vulkan, see @ref
+ *  glfwGetRequiredInstanceExtensions, `vkEnumerateInstanceExtensionProperties`
+ *  and `vkEnumerateDeviceExtensionProperties` instead.
+ *
+ *  @param[in] extension The ASCII encoded name of the extension.
+ *  @return `GLFW_TRUE` if the extension is available, or `GLFW_FALSE`
+ *  otherwise.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ *  GLFW_NO_CURRENT_CONTEXT, @ref GLFW_INVALID_VALUE and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @thread_safety This function may be called from any thread.
+ *
+ *  @sa @ref context_glext
+ *  @sa glfwGetProcAddress
+ *
+ *  @since Added in version 1.0.
+ *
+ *  @ingroup context
+ */
+GLFWAPI int glfwExtensionSupported(const char* extension);
+
+/*! @brief Returns the address of the specified function for the current
+ *  context.
+ *
+ *  This function returns the address of the specified OpenGL or OpenGL ES
+ *  [core or extension function](@ref context_glext), if it is supported
+ *  by the current context.
+ *
+ *  A context must be current on the calling thread.  Calling this function
+ *  without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error.
+ *
+ *  This function does not apply to Vulkan.  If you are rendering with Vulkan,
+ *  see @ref glfwGetInstanceProcAddress, `vkGetInstanceProcAddr` and
+ *  `vkGetDeviceProcAddr` instead.
+ *
+ *  @param[in] procname The ASCII encoded name of the function.
+ *  @return The address of the function, or `NULL` if an
+ *  [error](@ref error_handling) occurred.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ *  GLFW_NO_CURRENT_CONTEXT and @ref GLFW_PLATFORM_ERROR.
+ *
+ *  @remark The address of a given function is not guaranteed to be the same
+ *  between contexts.
+ *
+ *  @remark This function may return a non-`NULL` address despite the
+ *  associated version or extension not being available.  Always check the
+ *  context version or extension string first.
+ *
+ *  @pointer_lifetime The returned function pointer is valid until the context
+ *  is destroyed or the library is terminated.
+ *
+ *  @thread_safety This function may be called from any thread.
+ *
+ *  @sa @ref context_glext
+ *  @sa glfwExtensionSupported
+ *
+ *  @since Added in version 1.0.
+ *
+ *  @ingroup context
+ */
+GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname);
+
+/*! @brief Returns whether the Vulkan loader has been found.
+ *
+ *  This function returns whether the Vulkan loader has been found.  This check
+ *  is performed by @ref glfwInit.
+ *
+ *  The availability of a Vulkan loader does not by itself guarantee that window
+ *  surface creation or even device creation is possible.  Call @ref
+ *  glfwGetRequiredInstanceExtensions to check whether the extensions necessary
+ *  for Vulkan surface creation are available and @ref
+ *  glfwGetPhysicalDevicePresentationSupport to check whether a queue family of
+ *  a physical device supports image presentation.
+ *
+ *  @return `GLFW_TRUE` if Vulkan is available, or `GLFW_FALSE` otherwise.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function may be called from any thread.
+ *
+ *  @sa @ref vulkan_support
+ *
+ *  @since Added in version 3.2.
+ *
+ *  @ingroup vulkan
+ */
+GLFWAPI int glfwVulkanSupported(void);
+
+/*! @brief Returns the Vulkan instance extensions required by GLFW.
+ *
+ *  This function returns an array of names of Vulkan instance extensions required
+ *  by GLFW for creating Vulkan surfaces for GLFW windows.  If successful, the
+ *  list will always contains `VK_KHR_surface`, so if you don't require any
+ *  additional extensions you can pass this list directly to the
+ *  `VkInstanceCreateInfo` struct.
+ *
+ *  If Vulkan is not available on the machine, this function returns `NULL` and
+ *  generates a @ref GLFW_API_UNAVAILABLE error.  Call @ref glfwVulkanSupported
+ *  to check whether Vulkan is available.
+ *
+ *  If Vulkan is available but no set of extensions allowing window surface
+ *  creation was found, this function returns `NULL`.  You may still use Vulkan
+ *  for off-screen rendering and compute work.
+ *
+ *  @param[out] count Where to store the number of extensions in the returned
+ *  array.  This is set to zero if an error occurred.
+ *  @return An array of ASCII encoded extension names, or `NULL` if an
+ *  [error](@ref error_handling) occurred.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_API_UNAVAILABLE.
+ *
+ *  @remarks Additional extensions may be required by future versions of GLFW.
+ *  You should check if any extensions you wish to enable are already in the
+ *  returned array, as it is an error to specify an extension more than once in
+ *  the `VkInstanceCreateInfo` struct.
+ *
+ *  @pointer_lifetime The returned array is allocated and freed by GLFW.  You
+ *  should not free it yourself.  It is guaranteed to be valid only until the
+ *  library is terminated.
+ *
+ *  @thread_safety This function may be called from any thread.
+ *
+ *  @sa @ref vulkan_ext
+ *  @sa glfwCreateWindowSurface
+ *
+ *  @since Added in version 3.2.
+ *
+ *  @ingroup vulkan
+ */
+GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count);
+
+#if defined(VK_VERSION_1_0)
+
+/*! @brief Returns the address of the specified Vulkan instance function.
+ *
+ *  This function returns the address of the specified Vulkan core or extension
+ *  function for the specified instance.  If instance is set to `NULL` it can
+ *  return any function exported from the Vulkan loader, including at least the
+ *  following functions:
+ *
+ *  - `vkEnumerateInstanceExtensionProperties`
+ *  - `vkEnumerateInstanceLayerProperties`
+ *  - `vkCreateInstance`
+ *  - `vkGetInstanceProcAddr`
+ *
+ *  If Vulkan is not available on the machine, this function returns `NULL` and
+ *  generates a @ref GLFW_API_UNAVAILABLE error.  Call @ref glfwVulkanSupported
+ *  to check whether Vulkan is available.
+ *
+ *  This function is equivalent to calling `vkGetInstanceProcAddr` with
+ *  a platform-specific query of the Vulkan loader as a fallback.
+ *
+ *  @param[in] instance The Vulkan instance to query, or `NULL` to retrieve
+ *  functions related to instance creation.
+ *  @param[in] procname The ASCII encoded name of the function.
+ *  @return The address of the function, or `NULL` if an
+ *  [error](@ref error_handling) occurred.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_API_UNAVAILABLE.
+ *
+ *  @pointer_lifetime The returned function pointer is valid until the library
+ *  is terminated.
+ *
+ *  @thread_safety This function may be called from any thread.
+ *
+ *  @sa @ref vulkan_proc
+ *
+ *  @since Added in version 3.2.
+ *
+ *  @ingroup vulkan
+ */
+GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance, const char* procname);
+
+/*! @brief Returns whether the specified queue family can present images.
+ *
+ *  This function returns whether the specified queue family of the specified
+ *  physical device supports presentation to the platform GLFW was built for.
+ *
+ *  If Vulkan or the required window surface creation instance extensions are
+ *  not available on the machine, or if the specified instance was not created
+ *  with the required extensions, this function returns `GLFW_FALSE` and
+ *  generates a @ref GLFW_API_UNAVAILABLE error.  Call @ref glfwVulkanSupported
+ *  to check whether Vulkan is available and @ref
+ *  glfwGetRequiredInstanceExtensions to check what instance extensions are
+ *  required.
+ *
+ *  @param[in] instance The instance that the physical device belongs to.
+ *  @param[in] device The physical device that the queue family belongs to.
+ *  @param[in] queuefamily The index of the queue family to query.
+ *  @return `GLFW_TRUE` if the queue family supports presentation, or
+ *  `GLFW_FALSE` otherwise.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ *  GLFW_API_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR.
+ *
+ *  @thread_safety This function may be called from any thread.  For
+ *  synchronization details of Vulkan objects, see the Vulkan specification.
+ *
+ *  @sa @ref vulkan_present
+ *
+ *  @since Added in version 3.2.
+ *
+ *  @ingroup vulkan
+ */
+GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily);
+
+/*! @brief Creates a Vulkan surface for the specified window.
+ *
+ *  This function creates a Vulkan surface for the specified window.
+ *
+ *  If the Vulkan loader was not found at initialization, this function returns
+ *  `VK_ERROR_INITIALIZATION_FAILED` and generates a @ref GLFW_API_UNAVAILABLE
+ *  error.  Call @ref glfwVulkanSupported to check whether the Vulkan loader was
+ *  found.
+ *
+ *  If the required window surface creation instance extensions are not
+ *  available or if the specified instance was not created with these extensions
+ *  enabled, this function returns `VK_ERROR_EXTENSION_NOT_PRESENT` and
+ *  generates a @ref GLFW_API_UNAVAILABLE error.  Call @ref
+ *  glfwGetRequiredInstanceExtensions to check what instance extensions are
+ *  required.
+ *
+ *  The window surface must be destroyed before the specified Vulkan instance.
+ *  It is the responsibility of the caller to destroy the window surface.  GLFW
+ *  does not destroy it for you.  Call `vkDestroySurfaceKHR` to destroy the
+ *  surface.
+ *
+ *  @param[in] instance The Vulkan instance to create the surface in.
+ *  @param[in] window The window to create the surface for.
+ *  @param[in] allocator The allocator to use, or `NULL` to use the default
+ *  allocator.
+ *  @param[out] surface Where to store the handle of the surface.  This is set
+ *  to `VK_NULL_HANDLE` if an error occurred.
+ *  @return `VK_SUCCESS` if successful, or a Vulkan error code if an
+ *  [error](@ref error_handling) occurred.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ *  GLFW_API_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR.
+ *
+ *  @remarks If an error occurs before the creation call is made, GLFW returns
+ *  the Vulkan error code most appropriate for the error.  Appropriate use of
+ *  @ref glfwVulkanSupported and @ref glfwGetRequiredInstanceExtensions should
+ *  eliminate almost all occurrences of these errors.
+ *
+ *  @thread_safety This function may be called from any thread.  For
+ *  synchronization details of Vulkan objects, see the Vulkan specification.
+ *
+ *  @sa @ref vulkan_surface
+ *  @sa glfwGetRequiredInstanceExtensions
+ *
+ *  @since Added in version 3.2.
+ *
+ *  @ingroup vulkan
+ */
+GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface);
+
+#endif /*VK_VERSION_1_0*/
 
 
 /*************************************************************************
diff --git a/glfw/include/GLFW/glfw3native.h b/glfw/include/GLFW/glfw3native.h
--- a/glfw/include/GLFW/glfw3native.h
+++ b/glfw/include/GLFW/glfw3native.h
@@ -1,9 +1,9 @@
 /*************************************************************************
- * GLFW 3.1 - www.glfw.org
+ * GLFW 3.2 - www.glfw.org
  * A library for OpenGL, window and input
  *------------------------------------------------------------------------
  * Copyright (c) 2002-2006 Marcus Geelnard
- * Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+ * Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
  *
  * This software is provided 'as-is', without any express or implied
  * warranty. In no event will the authors be held liable for any damages
@@ -38,20 +38,30 @@
  * Doxygen documentation
  *************************************************************************/
 
+/*! @file glfw3native.h
+ *  @brief The header of the native access functions.
+ *
+ *  This is the header file of the native access functions.  See @ref native for
+ *  more information.
+ */
 /*! @defgroup native Native access
  *
  *  **By using the native access functions you assert that you know what you're
  *  doing and how to fix problems caused by using them.  If you don't, you
  *  shouldn't be using them.**
  *
- *  Before the inclusion of @ref glfw3native.h, you must define exactly one
- *  window system API macro and exactly one context creation API macro.  Failure
- *  to do this will cause a compile-time error.
+ *  Before the inclusion of @ref glfw3native.h, you may define exactly one
+ *  window system API macro and zero or more context creation API macros.
  *
+ *  The chosen backends must match those the library was compiled for.  Failure
+ *  to do this will cause a link-time error.
+ *
  *  The available window API macros are:
  *  * `GLFW_EXPOSE_NATIVE_WIN32`
  *  * `GLFW_EXPOSE_NATIVE_COCOA`
  *  * `GLFW_EXPOSE_NATIVE_X11`
+ *  * `GLFW_EXPOSE_NATIVE_WAYLAND`
+ *  * `GLFW_EXPOSE_NATIVE_MIR`
  *
  *  The available context API macros are:
  *  * `GLFW_EXPOSE_NATIVE_WGL`
@@ -86,20 +96,23 @@
 #elif defined(GLFW_EXPOSE_NATIVE_X11)
  #include <X11/Xlib.h>
  #include <X11/extensions/Xrandr.h>
-#else
- #error "No window API selected"
+#elif defined(GLFW_EXPOSE_NATIVE_WAYLAND)
+ #include <wayland-client.h>
+#elif defined(GLFW_EXPOSE_NATIVE_MIR)
+ #include <mir_toolkit/mir_client_library.h>
 #endif
 
 #if defined(GLFW_EXPOSE_NATIVE_WGL)
  /* WGL is declared by windows.h */
-#elif defined(GLFW_EXPOSE_NATIVE_NSGL)
+#endif
+#if defined(GLFW_EXPOSE_NATIVE_NSGL)
  /* NSGL is declared by Cocoa.h */
-#elif defined(GLFW_EXPOSE_NATIVE_GLX)
+#endif
+#if defined(GLFW_EXPOSE_NATIVE_GLX)
  #include <GL/glx.h>
-#elif defined(GLFW_EXPOSE_NATIVE_EGL)
+#endif
+#if defined(GLFW_EXPOSE_NATIVE_EGL)
  #include <EGL/egl.h>
-#else
- #error "No context API selected"
 #endif
 
 
@@ -114,11 +127,10 @@
  *  of the specified monitor, or `NULL` if an [error](@ref error_handling)
  *  occurred.
  *
- *  @par Thread Safety
- *  This function may be called from any thread.  Access is not synchronized.
+ *  @thread_safety This function may be called from any thread.  Access is not
+ *  synchronized.
  *
- *  @par History
- *  Added in GLFW 3.1.
+ *  @since Added in version 3.1.
  *
  *  @ingroup native
  */
@@ -130,11 +142,10 @@
  *  `\\.\DISPLAY1\Monitor0`) of the specified monitor, or `NULL` if an
  *  [error](@ref error_handling) occurred.
  *
- *  @par Thread Safety
- *  This function may be called from any thread.  Access is not synchronized.
+ *  @thread_safety This function may be called from any thread.  Access is not
+ *  synchronized.
  *
- *  @par History
- *  Added in GLFW 3.1.
+ *  @since Added in version 3.1.
  *
  *  @ingroup native
  */
@@ -145,11 +156,10 @@
  *  @return The `HWND` of the specified window, or `NULL` if an
  *  [error](@ref error_handling) occurred.
  *
- *  @par Thread Safety
- *  This function may be called from any thread.  Access is not synchronized.
+ *  @thread_safety This function may be called from any thread.  Access is not
+ *  synchronized.
  *
- *  @par History
- *  Added in GLFW 3.0.
+ *  @since Added in version 3.0.
  *
  *  @ingroup native
  */
@@ -162,11 +172,10 @@
  *  @return The `HGLRC` of the specified window, or `NULL` if an
  *  [error](@ref error_handling) occurred.
  *
- *  @par Thread Safety
- *  This function may be called from any thread.  Access is not synchronized.
+ *  @thread_safety This function may be called from any thread.  Access is not
+ *  synchronized.
  *
- *  @par History
- *  Added in GLFW 3.0.
+ *  @since Added in version 3.0.
  *
  *  @ingroup native
  */
@@ -179,11 +188,10 @@
  *  @return The `CGDirectDisplayID` of the specified monitor, or
  *  `kCGNullDirectDisplay` if an [error](@ref error_handling) occurred.
  *
- *  @par Thread Safety
- *  This function may be called from any thread.  Access is not synchronized.
+ *  @thread_safety This function may be called from any thread.  Access is not
+ *  synchronized.
  *
- *  @par History
- *  Added in GLFW 3.1.
+ *  @since Added in version 3.1.
  *
  *  @ingroup native
  */
@@ -194,11 +202,10 @@
  *  @return The `NSWindow` of the specified window, or `nil` if an
  *  [error](@ref error_handling) occurred.
  *
- *  @par Thread Safety
- *  This function may be called from any thread.  Access is not synchronized.
+ *  @thread_safety This function may be called from any thread.  Access is not
+ *  synchronized.
  *
- *  @par History
- *  Added in GLFW 3.0.
+ *  @since Added in version 3.0.
  *
  *  @ingroup native
  */
@@ -211,11 +218,10 @@
  *  @return The `NSOpenGLContext` of the specified window, or `nil` if an
  *  [error](@ref error_handling) occurred.
  *
- *  @par Thread Safety
- *  This function may be called from any thread.  Access is not synchronized.
+ *  @thread_safety This function may be called from any thread.  Access is not
+ *  synchronized.
  *
- *  @par History
- *  Added in GLFW 3.0.
+ *  @since Added in version 3.0.
  *
  *  @ingroup native
  */
@@ -228,11 +234,10 @@
  *  @return The `Display` used by GLFW, or `NULL` if an
  *  [error](@ref error_handling) occurred.
  *
- *  @par Thread Safety
- *  This function may be called from any thread.  Access is not synchronized.
+ *  @thread_safety This function may be called from any thread.  Access is not
+ *  synchronized.
  *
- *  @par History
- *  Added in GLFW 3.0.
+ *  @since Added in version 3.0.
  *
  *  @ingroup native
  */
@@ -243,11 +248,10 @@
  *  @return The `RRCrtc` of the specified monitor, or `None` if an
  *  [error](@ref error_handling) occurred.
  *
- *  @par Thread Safety
- *  This function may be called from any thread.  Access is not synchronized.
+ *  @thread_safety This function may be called from any thread.  Access is not
+ *  synchronized.
  *
- *  @par History
- *  Added in GLFW 3.1.
+ *  @since Added in version 3.1.
  *
  *  @ingroup native
  */
@@ -258,11 +262,10 @@
  *  @return The `RROutput` of the specified monitor, or `None` if an
  *  [error](@ref error_handling) occurred.
  *
- *  @par Thread Safety
- *  This function may be called from any thread.  Access is not synchronized.
+ *  @thread_safety This function may be called from any thread.  Access is not
+ *  synchronized.
  *
- *  @par History
- *  Added in GLFW 3.1.
+ *  @since Added in version 3.1.
  *
  *  @ingroup native
  */
@@ -273,11 +276,10 @@
  *  @return The `Window` of the specified window, or `None` if an
  *  [error](@ref error_handling) occurred.
  *
- *  @par Thread Safety
- *  This function may be called from any thread.  Access is not synchronized.
+ *  @thread_safety This function may be called from any thread.  Access is not
+ *  synchronized.
  *
- *  @par History
- *  Added in GLFW 3.0.
+ *  @since Added in version 3.0.
  *
  *  @ingroup native
  */
@@ -290,28 +292,128 @@
  *  @return The `GLXContext` of the specified window, or `NULL` if an
  *  [error](@ref error_handling) occurred.
  *
- *  @par Thread Safety
- *  This function may be called from any thread.  Access is not synchronized.
+ *  @thread_safety This function may be called from any thread.  Access is not
+ *  synchronized.
  *
- *  @par History
- *  Added in GLFW 3.0.
+ *  @since Added in version 3.0.
  *
  *  @ingroup native
  */
 GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* window);
+
+/*! @brief Returns the `GLXWindow` of the specified window.
+ *
+ *  @return The `GLXWindow` of the specified window, or `None` if an
+ *  [error](@ref error_handling) occurred.
+ *
+ *  @thread_safety This function may be called from any thread.  Access is not
+ *  synchronized.
+ *
+ *  @since Added in version 3.2.
+ *
+ *  @ingroup native
+ */
+GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* window);
 #endif
 
+#if defined(GLFW_EXPOSE_NATIVE_WAYLAND)
+/*! @brief Returns the `struct wl_display*` used by GLFW.
+ *
+ *  @return The `struct wl_display*` used by GLFW, or `NULL` if an
+ *  [error](@ref error_handling) occurred.
+ *
+ *  @thread_safety This function may be called from any thread.  Access is not
+ *  synchronized.
+ *
+ *  @since Added in version 3.2.
+ *
+ *  @ingroup native
+ */
+GLFWAPI struct wl_display* glfwGetWaylandDisplay(void);
+
+/*! @brief Returns the `struct wl_output*` of the specified monitor.
+ *
+ *  @return The `struct wl_output*` of the specified monitor, or `NULL` if an
+ *  [error](@ref error_handling) occurred.
+ *
+ *  @thread_safety This function may be called from any thread.  Access is not
+ *  synchronized.
+ *
+ *  @since Added in version 3.2.
+ *
+ *  @ingroup native
+ */
+GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor);
+
+/*! @brief Returns the main `struct wl_surface*` of the specified window.
+ *
+ *  @return The main `struct wl_surface*` of the specified window, or `NULL` if
+ *  an [error](@ref error_handling) occurred.
+ *
+ *  @thread_safety This function may be called from any thread.  Access is not
+ *  synchronized.
+ *
+ *  @since Added in version 3.2.
+ *
+ *  @ingroup native
+ */
+GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window);
+#endif
+
+#if defined(GLFW_EXPOSE_NATIVE_MIR)
+/*! @brief Returns the `MirConnection*` used by GLFW.
+ *
+ *  @return The `MirConnection*` used by GLFW, or `NULL` if an
+ *  [error](@ref error_handling) occurred.
+ *
+ *  @thread_safety This function may be called from any thread.  Access is not
+ *  synchronized.
+ *
+ *  @since Added in version 3.2.
+ *
+ *  @ingroup native
+ */
+GLFWAPI MirConnection* glfwGetMirDisplay(void);
+
+/*! @brief Returns the Mir output ID of the specified monitor.
+ *
+ *  @return The Mir output ID of the specified monitor, or zero if an
+ *  [error](@ref error_handling) occurred.
+ *
+ *  @thread_safety This function may be called from any thread.  Access is not
+ *  synchronized.
+ *
+ *  @since Added in version 3.2.
+ *
+ *  @ingroup native
+ */
+GLFWAPI int glfwGetMirMonitor(GLFWmonitor* monitor);
+
+/*! @brief Returns the `MirSurface*` of the specified window.
+ *
+ *  @return The `MirSurface*` of the specified window, or `NULL` if an
+ *  [error](@ref error_handling) occurred.
+ *
+ *  @thread_safety This function may be called from any thread.  Access is not
+ *  synchronized.
+ *
+ *  @since Added in version 3.2.
+ *
+ *  @ingroup native
+ */
+GLFWAPI MirSurface* glfwGetMirWindow(GLFWwindow* window);
+#endif
+
 #if defined(GLFW_EXPOSE_NATIVE_EGL)
 /*! @brief Returns the `EGLDisplay` used by GLFW.
  *
  *  @return The `EGLDisplay` used by GLFW, or `EGL_NO_DISPLAY` if an
  *  [error](@ref error_handling) occurred.
  *
- *  @par Thread Safety
- *  This function may be called from any thread.  Access is not synchronized.
+ *  @thread_safety This function may be called from any thread.  Access is not
+ *  synchronized.
  *
- *  @par History
- *  Added in GLFW 3.0.
+ *  @since Added in version 3.0.
  *
  *  @ingroup native
  */
@@ -322,11 +424,10 @@
  *  @return The `EGLContext` of the specified window, or `EGL_NO_CONTEXT` if an
  *  [error](@ref error_handling) occurred.
  *
- *  @par Thread Safety
- *  This function may be called from any thread.  Access is not synchronized.
+ *  @thread_safety This function may be called from any thread.  Access is not
+ *  synchronized.
  *
- *  @par History
- *  Added in GLFW 3.0.
+ *  @since Added in version 3.0.
  *
  *  @ingroup native
  */
@@ -337,11 +438,10 @@
  *  @return The `EGLSurface` of the specified window, or `EGL_NO_SURFACE` if an
  *  [error](@ref error_handling) occurred.
  *
- *  @par Thread Safety
- *  This function may be called from any thread.  Access is not synchronized.
+ *  @thread_safety This function may be called from any thread.  Access is not
+ *  synchronized.
  *
- *  @par History
- *  Added in GLFW 3.0.
+ *  @since Added in version 3.0.
  *
  *  @ingroup native
  */
diff --git a/glfw/src/cocoa_init.m b/glfw/src/cocoa_init.m
--- a/glfw/src/cocoa_init.m
+++ b/glfw/src/cocoa_init.m
@@ -1,7 +1,7 @@
 //========================================================================
-// GLFW 3.1 OS X - www.glfw.org
+// GLFW 3.2 OS X - www.glfw.org
 //------------------------------------------------------------------------
-// Copyright (c) 2009-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2009-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -72,7 +72,10 @@
 //
 static void createKeyTables(void)
 {
+    int scancode;
+
     memset(_glfw.ns.publicKeys, -1, sizeof(_glfw.ns.publicKeys));
+    memset(_glfw.ns.nativeKeys, -1, sizeof(_glfw.ns.nativeKeys));
 
     _glfw.ns.publicKeys[0x1D] = GLFW_KEY_0;
     _glfw.ns.publicKeys[0x12] = GLFW_KEY_1;
@@ -188,9 +191,107 @@
     _glfw.ns.publicKeys[0x51] = GLFW_KEY_KP_EQUAL;
     _glfw.ns.publicKeys[0x43] = GLFW_KEY_KP_MULTIPLY;
     _glfw.ns.publicKeys[0x4E] = GLFW_KEY_KP_SUBTRACT;
+
+    for (scancode = 0;  scancode < 256;  scancode++)
+    {
+        // Store the reverse translation for faster key name lookup
+        if (_glfw.ns.publicKeys[scancode] >= 0)
+            _glfw.ns.nativeKeys[_glfw.ns.publicKeys[scancode]] = scancode;
+    }
 }
 
+// Retrieve Unicode data for the current keyboard layout
+//
+static GLFWbool updateUnicodeDataNS(void)
+{
+    if (_glfw.ns.inputSource)
+    {
+        CFRelease(_glfw.ns.inputSource);
+        _glfw.ns.inputSource = NULL;
+        _glfw.ns.unicodeData = nil;
+    }
 
+    _glfw.ns.inputSource = TISCopyCurrentKeyboardLayoutInputSource();
+    if (!_glfw.ns.inputSource)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Cocoa: Failed to retrieve keyboard layout input source");
+        return GLFW_FALSE;
+    }
+
+    _glfw.ns.unicodeData = TISGetInputSourceProperty(_glfw.ns.inputSource,
+                                                     kTISPropertyUnicodeKeyLayoutData);
+    if (!_glfw.ns.unicodeData)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Cocoa: Failed to retrieve keyboard layout Unicode data");
+        return GLFW_FALSE;
+    }
+
+    return GLFW_TRUE;
+}
+
+// Load HIToolbox.framework and the TIS symbols we need from it
+//
+static GLFWbool initializeTIS(void)
+{
+    // This works only because Cocoa has already loaded it properly
+    _glfw.ns.tis.bundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.HIToolbox"));
+    if (!_glfw.ns.tis.bundle)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Cocoa: Failed to load HIToolbox.framework");
+        return GLFW_FALSE;
+    }
+
+    CFStringRef* kPropertyUnicodeKeyLayoutData =
+        CFBundleGetDataPointerForName(_glfw.ns.tis.bundle,
+                                      CFSTR("kTISPropertyUnicodeKeyLayoutData"));
+    CFStringRef* kNotifySelectedKeyboardInputSourceChanged =
+        CFBundleGetDataPointerForName(_glfw.ns.tis.bundle,
+                                      CFSTR("kTISNotifySelectedKeyboardInputSourceChanged"));
+    _glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource =
+        CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
+                                          CFSTR("TISCopyCurrentKeyboardLayoutInputSource"));
+    _glfw.ns.tis.GetInputSourceProperty =
+        CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
+                                          CFSTR("TISGetInputSourceProperty"));
+    _glfw.ns.tis.GetKbdType =
+        CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
+                                          CFSTR("LMGetKbdType"));
+
+    if (!kPropertyUnicodeKeyLayoutData ||
+        !kNotifySelectedKeyboardInputSourceChanged ||
+        !TISCopyCurrentKeyboardLayoutInputSource ||
+        !TISGetInputSourceProperty ||
+        !LMGetKbdType)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Cocoa: Failed to load TIS API symbols");
+        return GLFW_FALSE;
+    }
+
+    _glfw.ns.tis.kPropertyUnicodeKeyLayoutData =
+        *kPropertyUnicodeKeyLayoutData;
+    _glfw.ns.tis.kNotifySelectedKeyboardInputSourceChanged =
+        *kNotifySelectedKeyboardInputSourceChanged;
+
+    return updateUnicodeDataNS();
+}
+
+@interface GLFWLayoutListener : NSObject
+@end
+
+@implementation GLFWLayoutListener
+
+- (void)selectedKeyboardInputSourceChanged:(NSObject* )object
+{
+    updateUnicodeDataNS();
+}
+
+@end
+
+
 //////////////////////////////////////////////////////////////////////////
 //////                       GLFW platform API                      //////
 //////////////////////////////////////////////////////////////////////////
@@ -199,6 +300,13 @@
 {
     _glfw.ns.autoreleasePool = [[NSAutoreleasePool alloc] init];
 
+    _glfw.ns.listener = [[GLFWLayoutListener alloc] init];
+    [[NSDistributedNotificationCenter defaultCenter]
+        addObserver:_glfw.ns.listener
+           selector:@selector(selectedKeyboardInputSourceChanged:)
+               name:(__bridge NSString*)kTISNotifySelectedKeyboardInputSourceChanged
+             object:nil];
+
 #if defined(_GLFW_USE_CHDIR)
     changeToResourcesDirectory();
 #endif
@@ -207,21 +315,31 @@
 
     _glfw.ns.eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
     if (!_glfw.ns.eventSource)
-        return GL_FALSE;
+        return GLFW_FALSE;
 
     CGEventSourceSetLocalEventsSuppressionInterval(_glfw.ns.eventSource, 0.0);
 
-    if (!_glfwInitContextAPI())
-        return GL_FALSE;
+    if (!initializeTIS())
+        return GLFW_FALSE;
 
-    _glfwInitTimer();
-    _glfwInitJoysticks();
+    if (!_glfwInitThreadLocalStoragePOSIX())
+        return GLFW_FALSE;
 
-    return GL_TRUE;
+    _glfwInitTimerNS();
+    _glfwInitJoysticksNS();
+
+    return GLFW_TRUE;
 }
 
 void _glfwPlatformTerminate(void)
 {
+    if (_glfw.ns.inputSource)
+    {
+        CFRelease(_glfw.ns.inputSource);
+        _glfw.ns.inputSource = NULL;
+        _glfw.ns.unicodeData = nil;
+    }
+
     if (_glfw.ns.eventSource)
     {
         CFRelease(_glfw.ns.eventSource);
@@ -235,24 +353,34 @@
         _glfw.ns.delegate = nil;
     }
 
-    [_glfw.ns.autoreleasePool release];
-    _glfw.ns.autoreleasePool = nil;
+    if (_glfw.ns.listener)
+    {
+        [[NSDistributedNotificationCenter defaultCenter]
+            removeObserver:_glfw.ns.listener
+                      name:(__bridge NSString*)kTISNotifySelectedKeyboardInputSourceChanged
+                    object:nil];
+        [[NSDistributedNotificationCenter defaultCenter]
+            removeObserver:_glfw.ns.listener];
+        [_glfw.ns.listener release];
+        _glfw.ns.listener = nil;
+    }
 
     [_glfw.ns.cursor release];
     _glfw.ns.cursor = nil;
 
     free(_glfw.ns.clipboardString);
 
-    _glfwTerminateJoysticks();
-    _glfwTerminateContextAPI();
+    _glfwTerminateNSGL();
+    _glfwTerminateJoysticksNS();
+    _glfwTerminateThreadLocalStoragePOSIX();
+
+    [_glfw.ns.autoreleasePool release];
+    _glfw.ns.autoreleasePool = nil;
 }
 
 const char* _glfwPlatformGetVersionString(void)
 {
-    const char* version = _GLFW_VERSION_NUMBER " Cocoa"
-#if defined(_GLFW_NSGL)
-        " NSGL"
-#endif
+    return _GLFW_VERSION_NUMBER " Cocoa NSGL"
 #if defined(_GLFW_USE_CHDIR)
         " chdir"
 #endif
@@ -266,7 +394,5 @@
         " dynamic"
 #endif
         ;
-
-    return version;
 }
 
diff --git a/glfw/src/cocoa_joystick.h b/glfw/src/cocoa_joystick.h
new file mode 100644
--- /dev/null
+++ b/glfw/src/cocoa_joystick.h
@@ -0,0 +1,60 @@
+//========================================================================
+// GLFW 3.2 Cocoa - www.glfw.org
+//------------------------------------------------------------------------
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
+//
+// 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.
+//
+//========================================================================
+
+#ifndef _glfw3_cocoa_joystick_h_
+#define _glfw3_cocoa_joystick_h_
+
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOCFPlugIn.h>
+#include <IOKit/hid/IOHIDLib.h>
+#include <IOKit/hid/IOHIDKeys.h>
+
+#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE \
+    _GLFWjoystickNS ns_js[GLFW_JOYSTICK_LAST + 1]
+
+
+// Cocoa-specific per-joystick data
+//
+typedef struct _GLFWjoystickNS
+{
+    GLFWbool        present;
+    char            name[256];
+
+    IOHIDDeviceRef deviceRef;
+
+    CFMutableArrayRef axisElements;
+    CFMutableArrayRef buttonElements;
+    CFMutableArrayRef hatElements;
+
+    float*          axes;
+    unsigned char*  buttons;
+} _GLFWjoystickNS;
+
+
+void _glfwInitJoysticksNS(void);
+void _glfwTerminateJoysticksNS(void);
+
+#endif // _glfw3_cocoa_joystick_h_
diff --git a/glfw/src/cocoa_joystick.m b/glfw/src/cocoa_joystick.m
new file mode 100644
--- /dev/null
+++ b/glfw/src/cocoa_joystick.m
@@ -0,0 +1,511 @@
+//========================================================================
+// GLFW 3.2 Cocoa - www.glfw.org
+//------------------------------------------------------------------------
+// Copyright (c) 2009-2016 Camilla Berglund <elmindreda@glfw.org>
+// Copyright (c) 2012 Torsten Walluhn <tw@mad-cad.net>
+//
+// 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 <unistd.h>
+#include <ctype.h>
+#include <string.h>
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <Kernel/IOKit/hidsystem/IOHIDUsageTables.h>
+
+
+// Joystick element information
+//
+typedef struct _GLFWjoyelementNS
+{
+    IOHIDElementRef elementRef;
+
+    long min;
+    long max;
+
+    long minReport;
+    long maxReport;
+
+} _GLFWjoyelementNS;
+
+
+static void getElementsCFArrayHandler(const void* value, void* parameter);
+
+// Adds an element to the specified joystick
+//
+static void addJoystickElement(_GLFWjoystickNS* js,
+                               IOHIDElementRef elementRef)
+{
+    IOHIDElementType elementType;
+    long usagePage, usage;
+    CFMutableArrayRef elementsArray = NULL;
+
+    elementType = IOHIDElementGetType(elementRef);
+    usagePage = IOHIDElementGetUsagePage(elementRef);
+    usage = IOHIDElementGetUsage(elementRef);
+
+    if ((elementType != kIOHIDElementTypeInput_Axis) &&
+        (elementType != kIOHIDElementTypeInput_Button) &&
+        (elementType != kIOHIDElementTypeInput_Misc))
+    {
+        return;
+    }
+
+    switch (usagePage)
+    {
+        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:
+                    elementsArray = js->axisElements;
+                    break;
+                case kHIDUsage_GD_Hatswitch:
+                    elementsArray = js->hatElements;
+                    break;
+            }
+
+            break;
+        }
+
+        case kHIDPage_Button:
+            elementsArray = js->buttonElements;
+            break;
+        default:
+            break;
+    }
+
+    if (elementsArray)
+    {
+        _GLFWjoyelementNS* element = calloc(1, sizeof(_GLFWjoyelementNS));
+
+        CFArrayAppendValue(elementsArray, element);
+
+        element->elementRef = elementRef;
+
+        element->minReport = IOHIDElementGetLogicalMin(elementRef);
+        element->maxReport = IOHIDElementGetLogicalMax(elementRef);
+    }
+}
+
+// Adds an element to the specified joystick
+//
+static void getElementsCFArrayHandler(const void* value, void* parameter)
+{
+    if (CFGetTypeID(value) == IOHIDElementGetTypeID())
+    {
+        addJoystickElement((_GLFWjoystickNS*) parameter,
+                           (IOHIDElementRef) value);
+    }
+}
+
+// Returns the value of the specified element of the specified joystick
+//
+static long getElementValue(_GLFWjoystickNS* js, _GLFWjoyelementNS* element)
+{
+    IOReturn result = kIOReturnSuccess;
+    IOHIDValueRef valueRef;
+    long value = 0;
+
+    if (js && element && js->deviceRef)
+    {
+        result = IOHIDDeviceGetValue(js->deviceRef,
+                                     element->elementRef,
+                                     &valueRef);
+
+        if (kIOReturnSuccess == result)
+        {
+            value = IOHIDValueGetIntegerValue(valueRef);
+
+            // Record min and max for auto calibration
+            if (value < element->minReport)
+                element->minReport = value;
+            if (value > element->maxReport)
+                element->maxReport = value;
+        }
+    }
+
+    // Auto user scale
+    return value;
+}
+
+// Removes the specified joystick
+//
+static void removeJoystick(_GLFWjoystickNS* js)
+{
+    int i;
+
+    if (!js->present)
+        return;
+
+    for (i = 0;  i < CFArrayGetCount(js->axisElements);  i++)
+        free((void*) CFArrayGetValueAtIndex(js->axisElements, i));
+    CFArrayRemoveAllValues(js->axisElements);
+    CFRelease(js->axisElements);
+
+    for (i = 0;  i < CFArrayGetCount(js->buttonElements);  i++)
+        free((void*) CFArrayGetValueAtIndex(js->buttonElements, i));
+    CFArrayRemoveAllValues(js->buttonElements);
+    CFRelease(js->buttonElements);
+
+    for (i = 0;  i < CFArrayGetCount(js->hatElements);  i++)
+        free((void*) CFArrayGetValueAtIndex(js->hatElements, i));
+    CFArrayRemoveAllValues(js->hatElements);
+    CFRelease(js->hatElements);
+
+    free(js->axes);
+    free(js->buttons);
+
+    memset(js, 0, sizeof(_GLFWjoystickNS));
+
+    _glfwInputJoystickChange(js - _glfw.ns_js, GLFW_DISCONNECTED);
+}
+
+// Polls for joystick axis events and updates GLFW state
+//
+static GLFWbool pollJoystickAxisEvents(_GLFWjoystickNS* js)
+{
+    CFIndex i;
+
+    if (!js->present)
+        return GLFW_FALSE;
+
+    for (i = 0;  i < CFArrayGetCount(js->axisElements);  i++)
+    {
+        _GLFWjoyelementNS* axis = (_GLFWjoyelementNS*)
+            CFArrayGetValueAtIndex(js->axisElements, i);
+
+        long value = getElementValue(js, axis);
+        long readScale = axis->maxReport - axis->minReport;
+
+        if (readScale == 0)
+            js->axes[i] = value;
+        else
+            js->axes[i] = (2.f * (value - axis->minReport) / readScale) - 1.f;
+    }
+
+    return GLFW_TRUE;
+}
+
+// Polls for joystick button events and updates GLFW state
+//
+static GLFWbool pollJoystickButtonEvents(_GLFWjoystickNS* js)
+{
+    CFIndex i;
+    int buttonIndex = 0;
+
+    if (!js->present)
+        return GLFW_FALSE;
+
+    for (i = 0;  i < CFArrayGetCount(js->buttonElements);  i++)
+    {
+        _GLFWjoyelementNS* button = (_GLFWjoyelementNS*)
+            CFArrayGetValueAtIndex(js->buttonElements, i);
+
+        if (getElementValue(js, button))
+            js->buttons[buttonIndex++] = GLFW_PRESS;
+        else
+            js->buttons[buttonIndex++] = GLFW_RELEASE;
+    }
+
+    for (i = 0;  i < CFArrayGetCount(js->hatElements);  i++)
+    {
+        _GLFWjoyelementNS* hat = (_GLFWjoyelementNS*)
+            CFArrayGetValueAtIndex(js->hatElements, i);
+
+        // Bit fields of button presses for each direction, including nil
+        const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 };
+
+        long j, value = getElementValue(js, hat);
+        if (value < 0 || value > 8)
+            value = 8;
+
+        for (j = 0;  j < 4;  j++)
+        {
+            if (directions[value] & (1 << j))
+                js->buttons[buttonIndex++] = GLFW_PRESS;
+            else
+                js->buttons[buttonIndex++] = GLFW_RELEASE;
+        }
+    }
+
+    return GLFW_TRUE;
+}
+
+// Callback for user-initiated joystick addition
+//
+static void matchCallback(void* context,
+                          IOReturn result,
+                          void* sender,
+                          IOHIDDeviceRef deviceRef)
+{
+    _GLFWjoystickNS* js;
+    int joy;
+
+    for (joy = GLFW_JOYSTICK_1;  joy <= GLFW_JOYSTICK_LAST;  joy++)
+    {
+        if (_glfw.ns_js[joy].present && _glfw.ns_js[joy].deviceRef == deviceRef)
+            return;
+    }
+
+    for (joy = GLFW_JOYSTICK_1;  joy <= GLFW_JOYSTICK_LAST;  joy++)
+    {
+        if (!_glfw.ns_js[joy].present)
+            break;
+    }
+
+    if (joy > GLFW_JOYSTICK_LAST)
+        return;
+
+    js = _glfw.ns_js + joy;
+    js->present = GLFW_TRUE;
+    js->deviceRef = deviceRef;
+
+    CFStringRef name = IOHIDDeviceGetProperty(deviceRef,
+                                              CFSTR(kIOHIDProductKey));
+    if (name)
+    {
+        CFStringGetCString(name,
+                           js->name,
+                           sizeof(js->name),
+                           kCFStringEncodingUTF8);
+    }
+    else
+        strncpy(js->name, "Unknown", sizeof(js->name));
+
+    js->axisElements = CFArrayCreateMutable(NULL, 0, NULL);
+    js->buttonElements = CFArrayCreateMutable(NULL, 0, NULL);
+    js->hatElements = CFArrayCreateMutable(NULL, 0, NULL);
+
+    CFArrayRef arrayRef = IOHIDDeviceCopyMatchingElements(deviceRef,
+                                                          NULL,
+                                                          kIOHIDOptionsTypeNone);
+    CFRange range = { 0, CFArrayGetCount(arrayRef) };
+    CFArrayApplyFunction(arrayRef,
+                         range,
+                         getElementsCFArrayHandler,
+                         (void*) js);
+
+    CFRelease(arrayRef);
+
+    js->axes = calloc(CFArrayGetCount(js->axisElements), sizeof(float));
+    js->buttons = calloc(CFArrayGetCount(js->buttonElements) +
+                         CFArrayGetCount(js->hatElements) * 4, 1);
+
+    _glfwInputJoystickChange(joy, GLFW_CONNECTED);
+}
+
+// Callback for user-initiated joystick removal
+//
+static void removeCallback(void* context,
+                           IOReturn result,
+                           void* sender,
+                           IOHIDDeviceRef deviceRef)
+{
+    int joy;
+
+    for (joy = GLFW_JOYSTICK_1;  joy <= GLFW_JOYSTICK_LAST;  joy++)
+    {
+        if (_glfw.ns_js[joy].deviceRef == deviceRef)
+        {
+            removeJoystick(_glfw.ns_js + joy);
+            break;
+        }
+    }
+}
+
+// Creates a dictionary to match against devices with the specified usage page
+// and usage
+//
+static CFMutableDictionaryRef createMatchingDictionary(long usagePage,
+                                                       long usage)
+{
+    CFMutableDictionaryRef result =
+        CFDictionaryCreateMutable(kCFAllocatorDefault,
+                                  0,
+                                  &kCFTypeDictionaryKeyCallBacks,
+                                  &kCFTypeDictionaryValueCallBacks);
+
+    if (result)
+    {
+        CFNumberRef pageRef = CFNumberCreate(kCFAllocatorDefault,
+                                             kCFNumberLongType,
+                                             &usagePage);
+        if (pageRef)
+        {
+            CFDictionarySetValue(result,
+                                 CFSTR(kIOHIDDeviceUsagePageKey),
+                                 pageRef);
+            CFRelease(pageRef);
+
+            CFNumberRef usageRef = CFNumberCreate(kCFAllocatorDefault,
+                                                  kCFNumberLongType,
+                                                  &usage);
+            if (usageRef)
+            {
+                CFDictionarySetValue(result,
+                                     CFSTR(kIOHIDDeviceUsageKey),
+                                     usageRef);
+                CFRelease(usageRef);
+            }
+        }
+    }
+
+    return result;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                       GLFW internal API                      //////
+//////////////////////////////////////////////////////////////////////////
+
+// Initialize joystick interface
+//
+void _glfwInitJoysticksNS(void)
+{
+    CFMutableArrayRef matchingCFArrayRef;
+
+    _glfw.ns.hidManager = IOHIDManagerCreate(kCFAllocatorDefault,
+                                             kIOHIDOptionsTypeNone);
+
+    matchingCFArrayRef = CFArrayCreateMutable(kCFAllocatorDefault,
+                                              0,
+                                              &kCFTypeArrayCallBacks);
+    if (matchingCFArrayRef)
+    {
+        CFDictionaryRef matchingCFDictRef =
+            createMatchingDictionary(kHIDPage_GenericDesktop,
+                                     kHIDUsage_GD_Joystick);
+        if (matchingCFDictRef)
+        {
+            CFArrayAppendValue(matchingCFArrayRef, matchingCFDictRef);
+            CFRelease(matchingCFDictRef);
+        }
+
+        matchingCFDictRef = createMatchingDictionary(kHIDPage_GenericDesktop,
+                                                     kHIDUsage_GD_GamePad);
+        if (matchingCFDictRef)
+        {
+            CFArrayAppendValue(matchingCFArrayRef, matchingCFDictRef);
+            CFRelease(matchingCFDictRef);
+        }
+
+        matchingCFDictRef =
+            createMatchingDictionary(kHIDPage_GenericDesktop,
+                                     kHIDUsage_GD_MultiAxisController);
+        if (matchingCFDictRef)
+        {
+            CFArrayAppendValue(matchingCFArrayRef, matchingCFDictRef);
+            CFRelease(matchingCFDictRef);
+        }
+
+        IOHIDManagerSetDeviceMatchingMultiple(_glfw.ns.hidManager,
+                                              matchingCFArrayRef);
+        CFRelease(matchingCFArrayRef);
+    }
+
+    IOHIDManagerRegisterDeviceMatchingCallback(_glfw.ns.hidManager,
+                                               &matchCallback, NULL);
+    IOHIDManagerRegisterDeviceRemovalCallback(_glfw.ns.hidManager,
+                                              &removeCallback, NULL);
+
+    IOHIDManagerScheduleWithRunLoop(_glfw.ns.hidManager,
+                                    CFRunLoopGetMain(),
+                                    kCFRunLoopDefaultMode);
+
+    IOHIDManagerOpen(_glfw.ns.hidManager, kIOHIDOptionsTypeNone);
+
+    // Execute the run loop once in order to register any initially-attached
+    // joysticks
+    CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false);
+}
+
+// Close all opened joystick handles
+//
+void _glfwTerminateJoysticksNS(void)
+{
+    int joy;
+
+    for (joy = GLFW_JOYSTICK_1;  joy <= GLFW_JOYSTICK_LAST;  joy++)
+    {
+        _GLFWjoystickNS* js = _glfw.ns_js + joy;
+        removeJoystick(js);
+    }
+
+    CFRelease(_glfw.ns.hidManager);
+    _glfw.ns.hidManager = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                       GLFW platform API                      //////
+//////////////////////////////////////////////////////////////////////////
+
+int _glfwPlatformJoystickPresent(int joy)
+{
+    _GLFWjoystickNS* js = _glfw.ns_js + joy;
+    return js->present;
+}
+
+const float* _glfwPlatformGetJoystickAxes(int joy, int* count)
+{
+    _GLFWjoystickNS* js = _glfw.ns_js + joy;
+    if (!pollJoystickAxisEvents(js))
+        return NULL;
+
+    *count = (int) CFArrayGetCount(js->axisElements);
+    return js->axes;
+}
+
+const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
+{
+    _GLFWjoystickNS* js = _glfw.ns_js + joy;
+    if (!pollJoystickButtonEvents(js))
+        return NULL;
+
+    *count = (int) CFArrayGetCount(js->buttonElements) +
+             (int) CFArrayGetCount(js->hatElements) * 4;
+    return js->buttons;
+}
+
+const char* _glfwPlatformGetJoystickName(int joy)
+{
+    _GLFWjoystickNS* js = _glfw.ns_js + joy;
+    if (!js->present)
+        return NULL;
+
+    return js->name;
+}
+
diff --git a/glfw/src/cocoa_monitor.m b/glfw/src/cocoa_monitor.m
--- a/glfw/src/cocoa_monitor.m
+++ b/glfw/src/cocoa_monitor.m
@@ -1,8 +1,8 @@
 //========================================================================
-// GLFW 3.1 OS X - www.glfw.org
+// GLFW 3.2 OS X - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -28,11 +28,9 @@
 #include "internal.h"
 
 #include <stdlib.h>
-#include <stdlib.h>
 #include <limits.h>
 
 #include <IOKit/graphics/IOGraphicsLib.h>
-#include <IOKit/graphics/IOGraphicsLib.h>
 #include <CoreVideo/CVBase.h>
 #include <CoreVideo/CVDisplayLink.h>
 #include <ApplicationServices/ApplicationServices.h>
@@ -57,7 +55,8 @@
                                                  (const void**) &value))
     {
         // This may happen if a desktop Mac is running headless
-        _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to retrieve display name");
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Cocoa: Failed to retrieve display name");
 
         CFRelease(info);
         return strdup("Unknown");
@@ -65,7 +64,7 @@
 
     size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value),
                                              kCFStringEncodingUTF8);
-    name = calloc(size + 1, sizeof(char));
+    name = calloc(size + 1, 1);
     CFStringGetCString(value, name, size, kCFStringEncodingUTF8);
 
     CFRelease(info);
@@ -75,28 +74,28 @@
 
 // Check whether the display mode should be included in enumeration
 //
-static GLboolean modeIsGood(CGDisplayModeRef mode)
+static GLFWbool modeIsGood(CGDisplayModeRef mode)
 {
     uint32_t flags = CGDisplayModeGetIOFlags(mode);
     if (!(flags & kDisplayModeValidFlag) || !(flags & kDisplayModeSafeFlag))
-        return GL_FALSE;
+        return GLFW_FALSE;
 
     if (flags & kDisplayModeInterlacedFlag)
-        return GL_FALSE;
+        return GLFW_FALSE;
 
     if (flags & kDisplayModeStretchedFlag)
-        return GL_FALSE;
+        return GLFW_FALSE;
 
     CFStringRef format = CGDisplayModeCopyPixelEncoding(mode);
     if (CFStringCompare(format, CFSTR(IO16BitDirectPixels), 0) &&
         CFStringCompare(format, CFSTR(IO32BitDirectPixels), 0))
     {
         CFRelease(format);
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
 
     CFRelease(format);
-    return GL_TRUE;
+    return GLFW_TRUE;
 }
 
 // Convert Core Graphics display mode to GLFW video mode
@@ -165,7 +164,7 @@
 
 // Change the current video mode
 //
-GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired)
+GLFWbool _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired)
 {
     CFArrayRef modes;
     CFIndex count, i;
@@ -177,7 +176,7 @@
     best = _glfwChooseVideoMode(monitor, desired);
     _glfwPlatformGetVideoMode(monitor, &current);
     if (_glfwCompareVideoModes(&current, best) == 0)
-        return GL_TRUE;
+        return GLFW_TRUE;
 
     CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
 
@@ -215,15 +214,15 @@
     {
         _glfwInputError(GLFW_PLATFORM_ERROR,
                         "Cocoa: Monitor mode list changed");
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
 
-    return GL_TRUE;
+    return GLFW_TRUE;
 }
 
 // Restore the previously saved (original) video mode
 //
-void _glfwRestoreVideoMode(_GLFWmonitor* monitor)
+void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor)
 {
     if (monitor->ns.previousMode)
     {
@@ -251,53 +250,29 @@
     *count = 0;
 
     CGGetOnlineDisplayList(0, NULL, &displayCount);
-
     displays = calloc(displayCount, sizeof(CGDirectDisplayID));
     monitors = calloc(displayCount, sizeof(_GLFWmonitor*));
 
     CGGetOnlineDisplayList(displayCount, displays, &displayCount);
 
-    NSArray* screens = [NSScreen screens];
-
     for (i = 0;  i < displayCount;  i++)
     {
-        int j;
+        _GLFWmonitor* monitor;
 
         if (CGDisplayIsAsleep(displays[i]))
             continue;
 
-        CGDirectDisplayID screenDisplayID = CGDisplayMirrorsDisplay(displays[i]);
-        if (screenDisplayID == kCGNullDirectDisplay)
-            screenDisplayID = displays[i];
-
         const CGSize size = CGDisplayScreenSize(displays[i]);
         char* name = getDisplayName(displays[i]);
 
-        monitors[found] = _glfwAllocMonitor(name, size.width, size.height);
-        monitors[found]->ns.displayID = displays[i];
+        monitor = _glfwAllocMonitor(name, size.width, size.height);
+        monitor->ns.displayID  = displays[i];
+        monitor->ns.unitNumber = CGDisplayUnitNumber(displays[i]);
 
         free(name);
 
-        for (j = 0;  j < [screens count];  j++)
-        {
-            NSScreen* screen = [screens objectAtIndex:j];
-            NSDictionary* dictionary = [screen deviceDescription];
-            NSNumber* number = [dictionary objectForKey:@"NSScreenNumber"];
-
-            if ([number unsignedIntegerValue] == screenDisplayID)
-            {
-                monitors[found]->ns.screen = screen;
-                break;
-            }
-        }
-
-        if (monitors[found]->ns.screen)
-            found++;
-        else
-        {
-            _glfwFreeMonitor(monitors[found]);
-            monitors[found] = NULL;
-        }
+        found++;
+        monitors[found - 1] = monitor;
     }
 
     free(displays);
@@ -306,9 +281,11 @@
     return monitors;
 }
 
-GLboolean _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
+GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
 {
-    return first->ns.displayID == second->ns.displayID;
+    // HACK: Compare unit numbers instead of display IDs to work around display
+    //       replacement on machines with automatic graphics switching
+    return first->ns.unitNumber == second->ns.unitNumber;
 }
 
 void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
@@ -321,22 +298,22 @@
         *ypos = (int) bounds.origin.y;
 }
 
-GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
+GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
 {
     CFArrayRef modes;
-    CFIndex count, i, j;
+    CFIndex found, i, j;
     GLFWvidmode* result;
     CVDisplayLinkRef link;
 
+    *count = 0;
+
     CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
 
     modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL);
-    count = CFArrayGetCount(modes);
-
-    result = calloc(count, sizeof(GLFWvidmode));
-    *found = 0;
+    found = CFArrayGetCount(modes);
+    result = calloc(found, sizeof(GLFWvidmode));
 
-    for (i = 0;  i < count;  i++)
+    for (i = 0;  i < found;  i++)
     {
         CGDisplayModeRef dm = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i);
         if (!modeIsGood(dm))
@@ -344,24 +321,21 @@
 
         const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, link);
 
-        for (j = 0;  j < *found;  j++)
+        for (j = 0;  j < *count;  j++)
         {
             if (_glfwCompareVideoModes(result + j, &mode) == 0)
                 break;
         }
 
-        if (i < *found)
-        {
-            // This is a duplicate, so skip it
+        // Skip duplicate modes
+        if (i < *count)
             continue;
-        }
 
-        result[*found] = mode;
-        (*found)++;
+        (*count)++;
+        result[*count - 1] = mode;
     }
 
     CFRelease(modes);
-
     CVDisplayLinkRelease(link);
     return result;
 }
diff --git a/glfw/src/cocoa_platform.h b/glfw/src/cocoa_platform.h
--- a/glfw/src/cocoa_platform.h
+++ b/glfw/src/cocoa_platform.h
@@ -1,7 +1,7 @@
 //========================================================================
-// GLFW 3.1 OS X - www.glfw.org
+// GLFW 3.2 OS X - www.glfw.org
 //------------------------------------------------------------------------
-// Copyright (c) 2009-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2009-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -24,28 +24,28 @@
 //
 //========================================================================
 
-#ifndef _cocoa_platform_h_
-#define _cocoa_platform_h_
-
+#ifndef _glfw3_cocoa_platform_h_
+#define _glfw3_cocoa_platform_h_
 
 #include <stdint.h>
+#include <dlfcn.h>
 
 #if defined(__OBJC__)
+#import <Carbon/Carbon.h>
 #import <Cocoa/Cocoa.h>
 #else
+#include <Carbon/Carbon.h>
 #include <ApplicationServices/ApplicationServices.h>
 typedef void* id;
 #endif
 
 #include "posix_tls.h"
-
-#if defined(_GLFW_NSGL)
- #include "nsgl_context.h"
-#else
- #error "No supported context creation API selected"
-#endif
+#include "cocoa_joystick.h"
+#include "nsgl_context.h"
 
-#include "iokit_joystick.h"
+#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
+#define _glfw_dlclose(handle) dlclose(handle)
+#define _glfw_dlsym(handle, name) dlsym(handle, name)
 
 #define _GLFW_PLATFORM_WINDOW_STATE         _GLFWwindowNS  ns
 #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryNS ns
@@ -53,38 +53,67 @@
 #define _GLFW_PLATFORM_MONITOR_STATE        _GLFWmonitorNS ns
 #define _GLFW_PLATFORM_CURSOR_STATE         _GLFWcursorNS  ns
 
+#define _GLFW_EGL_CONTEXT_STATE
+#define _GLFW_EGL_LIBRARY_CONTEXT_STATE
 
+// HIToolbox.framework pointer typedefs
+#define kTISPropertyUnicodeKeyLayoutData _glfw.ns.tis.kPropertyUnicodeKeyLayoutData
+#define kTISNotifySelectedKeyboardInputSourceChanged _glfw.ns.tis.kNotifySelectedKeyboardInputSourceChanged
+typedef TISInputSourceRef (*PFN_TISCopyCurrentKeyboardLayoutInputSource)(void);
+#define TISCopyCurrentKeyboardLayoutInputSource _glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource
+typedef void* (*PFN_TISGetInputSourceProperty)(TISInputSourceRef,CFStringRef);
+#define TISGetInputSourceProperty _glfw.ns.tis.GetInputSourceProperty
+typedef UInt8 (*PFN_LMGetKbdType)(void);
+#define LMGetKbdType _glfw.ns.tis.GetKbdType
+
+
 // Cocoa-specific per-window data
 //
 typedef struct _GLFWwindowNS
 {
     id              object;
-    id	            delegate;
+    id              delegate;
     id              view;
-    unsigned int    modifierFlags;
 
     // The total sum of the distances the cursor has been warped
     // since the last cursor motion event was processed
     // This is kept to counteract Cocoa doing the same internally
-    double          warpDeltaX, warpDeltaY;
+    double          cursorWarpDeltaX, cursorWarpDeltaY;
 
 } _GLFWwindowNS;
 
-
 // Cocoa-specific global data
 //
 typedef struct _GLFWlibraryNS
 {
-    CGEventSourceRef eventSource;
-    id              delegate;
-    id              autoreleasePool;
-    id              cursor;
+    CGEventSourceRef    eventSource;
+    id                  delegate;
+    id                  autoreleasePool;
+    id                  cursor;
+    TISInputSourceRef   inputSource;
+    IOHIDManagerRef     hidManager;
+    id                  unicodeData;
+    id                  listener;
 
-    short int       publicKeys[256];
-    char*           clipboardString;
+    char                keyName[64];
+    short int           publicKeys[256];
+    short int           nativeKeys[GLFW_KEY_LAST + 1];
+    char*               clipboardString;
+    // Where to place the cursor when re-enabled
+    double              restoreCursorPosX, restoreCursorPosY;
+    // The window whose disabled cursor mode is active
+    _GLFWwindow*        disabledCursorWindow;
 
-} _GLFWlibraryNS;
+    struct {
+        CFBundleRef     bundle;
+        PFN_TISCopyCurrentKeyboardLayoutInputSource CopyCurrentKeyboardLayoutInputSource;
+        PFN_TISGetInputSourceProperty GetInputSourceProperty;
+        PFN_LMGetKbdType GetKbdType;
+        CFStringRef     kPropertyUnicodeKeyLayoutData;
+        CFStringRef     kNotifySelectedKeyboardInputSourceChanged;
+    } tis;
 
+} _GLFWlibraryNS;
 
 // Cocoa-specific per-monitor data
 //
@@ -92,11 +121,10 @@
 {
     CGDirectDisplayID   displayID;
     CGDisplayModeRef    previousMode;
-    id                  screen;
+    uint32_t            unitNumber;
 
 } _GLFWmonitorNS;
 
-
 // Cocoa-specific per-cursor data
 //
 typedef struct _GLFWcursorNS
@@ -105,20 +133,18 @@
 
 } _GLFWcursorNS;
 
-
 // Cocoa-specific global timer data
 //
 typedef struct _GLFWtimeNS
 {
-    double          base;
-    double          resolution;
+    uint64_t        frequency;
 
 } _GLFWtimeNS;
 
 
-void _glfwInitTimer(void);
+void _glfwInitTimerNS(void);
 
-GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired);
-void _glfwRestoreVideoMode(_GLFWmonitor* monitor);
+GLFWbool _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired);
+void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor);
 
-#endif // _cocoa_platform_h_
+#endif // _glfw3_cocoa_platform_h_
diff --git a/glfw/src/cocoa_time.c b/glfw/src/cocoa_time.c
new file mode 100644
--- /dev/null
+++ b/glfw/src/cocoa_time.c
@@ -0,0 +1,60 @@
+//========================================================================
+// GLFW 3.2 OS X - www.glfw.org
+//------------------------------------------------------------------------
+// Copyright (c) 2009-2016 Camilla Berglund <elmindreda@glfw.org>
+//
+// 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 <mach/mach_time.h>
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                       GLFW internal API                      //////
+//////////////////////////////////////////////////////////////////////////
+
+// Initialise timer
+//
+void _glfwInitTimerNS(void)
+{
+    mach_timebase_info_data_t info;
+    mach_timebase_info(&info);
+
+    _glfw.ns_time.frequency = (info.denom * 1e9) / info.numer;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                       GLFW platform API                      //////
+//////////////////////////////////////////////////////////////////////////
+
+uint64_t _glfwPlatformGetTimerValue(void)
+{
+    return mach_absolute_time();
+}
+
+uint64_t _glfwPlatformGetTimerFrequency(void)
+{
+    return _glfw.ns_time.frequency;
+}
+
diff --git a/glfw/src/cocoa_window.m b/glfw/src/cocoa_window.m
--- a/glfw/src/cocoa_window.m
+++ b/glfw/src/cocoa_window.m
@@ -1,7 +1,7 @@
 //========================================================================
-// GLFW 3.1 OS X - www.glfw.org
+// GLFW 3.2 OS X - www.glfw.org
 //------------------------------------------------------------------------
-// Copyright (c) 2009-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2009-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -26,6 +26,7 @@
 
 #include "internal.h"
 
+#include <float.h>
 #include <string.h>
 
 // Needed for _NSGetProgname
@@ -55,6 +56,26 @@
     return nil;
 }
 
+// Returns the style mask corresponding to the window settings
+//
+static NSUInteger getStyleMask(_GLFWwindow* window)
+{
+    NSUInteger styleMask = 0;
+
+    if (window->monitor || !window->decorated)
+        styleMask |= NSBorderlessWindowMask;
+    else
+    {
+        styleMask |= NSTitledWindowMask | NSClosableWindowMask |
+                     NSMiniaturizableWindowMask;
+
+        if (window->resizable)
+            styleMask |= NSResizableWindowMask;
+    }
+
+    return styleMask;
+}
+
 // Center the cursor in the view of the window
 //
 static void centerCursor(_GLFWwindow *window)
@@ -64,10 +85,18 @@
     _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0);
 }
 
-// Update the cursor to match the specified cursor mode
+// Returns whether the cursor is in the client area of the specified window
 //
-static void updateModeCursor(_GLFWwindow* window)
+static GLFWbool cursorInClientArea(_GLFWwindow* window)
 {
+    const NSPoint pos = [window->ns.object mouseLocationOutsideOfEventStream];
+    return [window->ns.view mouse:pos inRect:[window->ns.view frame]];
+}
+
+// Updates the cursor image according to its cursor mode
+//
+static void updateCursorImage(_GLFWwindow* window)
+{
     if (window->cursorMode == GLFW_CURSOR_NORMAL)
     {
         if (window->cursor)
@@ -79,51 +108,98 @@
         [(NSCursor*) _glfw.ns.cursor set];
 }
 
-// Enter full screen mode
+// Transforms the specified y-coordinate between the CG display and NS screen
+// coordinate systems
 //
-static GLboolean enterFullscreenMode(_GLFWwindow* window)
+static float transformY(float y)
 {
-    GLboolean status;
+    return CGDisplayBounds(CGMainDisplayID()).size.height - y;
+}
 
-    status = _glfwSetVideoMode(window->monitor, &window->videoMode);
+// Make the specified window and its video mode active on its monitor
+//
+static GLFWbool acquireMonitor(_GLFWwindow* window)
+{
+    const GLFWbool status = _glfwSetVideoModeNS(window->monitor, &window->videoMode);
+    const CGRect bounds = CGDisplayBounds(window->monitor->ns.displayID);
+    const NSRect frame = NSMakeRect(bounds.origin.x,
+                                    transformY(bounds.origin.y + bounds.size.height),
+                                    bounds.size.width,
+                                    bounds.size.height);
 
-    // NOTE: The window is resized despite mode setting failure to make
-    //       glfwSetWindowSize more robust
-    [window->ns.object setFrame:[window->monitor->ns.screen frame]
-                        display:YES];
+    [window->ns.object setFrame:frame display:YES];
 
+    _glfwInputMonitorWindowChange(window->monitor, window);
     return status;
 }
 
-// Leave full screen mode
+// Remove the window and restore the original video mode
 //
-static void leaveFullscreenMode(_GLFWwindow* window)
+static void releaseMonitor(_GLFWwindow* window)
 {
-    _glfwRestoreVideoMode(window->monitor);
+    if (window->monitor->window != window)
+        return;
+
+    _glfwInputMonitorWindowChange(window->monitor, NULL);
+    _glfwRestoreVideoModeNS(window->monitor);
 }
 
-// Transforms the specified y-coordinate between the CG display and NS screen
-// coordinate systems
+// Translates OS X key modifiers into GLFW ones
 //
-static float transformY(float y)
+static int translateFlags(NSUInteger flags)
 {
-    const float height = CGDisplayBounds(CGMainDisplayID()).size.height;
-    return height - y;
+    int mods = 0;
+
+    if (flags & NSShiftKeyMask)
+        mods |= GLFW_MOD_SHIFT;
+    if (flags & NSControlKeyMask)
+        mods |= GLFW_MOD_CONTROL;
+    if (flags & NSAlternateKeyMask)
+        mods |= GLFW_MOD_ALT;
+    if (flags & NSCommandKeyMask)
+        mods |= GLFW_MOD_SUPER;
+
+    return mods;
 }
 
-// Returns the backing rect of the specified window
+// Translates a OS X keycode to a GLFW keycode
 //
-static NSRect convertRectToBacking(_GLFWwindow* window, NSRect contentRect)
+static int translateKey(unsigned int key)
 {
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
-    if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6)
-        return [window->ns.view convertRectToBacking:contentRect];
-    else
-#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
-        return contentRect;
+    if (key >= sizeof(_glfw.ns.publicKeys) / sizeof(_glfw.ns.publicKeys[0]))
+        return GLFW_KEY_UNKNOWN;
+
+    return _glfw.ns.publicKeys[key];
 }
 
+// Translate a GLFW keycode to a Cocoa modifier flag
+//
+static NSUInteger translateKeyToModifierFlag(int key)
+{
+    switch (key)
+    {
+        case GLFW_KEY_LEFT_SHIFT:
+        case GLFW_KEY_RIGHT_SHIFT:
+            return NSShiftKeyMask;
+        case GLFW_KEY_LEFT_CONTROL:
+        case GLFW_KEY_RIGHT_CONTROL:
+            return NSControlKeyMask;
+        case GLFW_KEY_LEFT_ALT:
+        case GLFW_KEY_RIGHT_ALT:
+            return NSAlternateKeyMask;
+        case GLFW_KEY_LEFT_SUPER:
+        case GLFW_KEY_RIGHT_SUPER:
+            return NSCommandKeyMask;
+    }
 
+    return 0;
+}
+
+// Defines a constant for empty ranges in NSTextInputClient
+//
+static const NSRange kEmptyRange = { NSNotFound, 0 };
+
+
 //------------------------------------------------------------------------
 // Delegate for window related notifications
 //------------------------------------------------------------------------
@@ -156,27 +232,26 @@
 
 - (void)windowDidResize:(NSNotification *)notification
 {
-    if (_glfw.focusedWindow == window &&
-        window->cursorMode == GLFW_CURSOR_DISABLED)
-    {
+    if (window->context.client != GLFW_NO_API)
+        [window->context.nsgl.object update];
+
+    if (_glfw.ns.disabledCursorWindow == window)
         centerCursor(window);
-    }
 
     const NSRect contentRect = [window->ns.view frame];
-    const NSRect fbRect = convertRectToBacking(window, contentRect);
+    const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect];
 
     _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height);
     _glfwInputWindowSize(window, contentRect.size.width, contentRect.size.height);
-    _glfwInputWindowDamage(window);
 }
 
 - (void)windowDidMove:(NSNotification *)notification
 {
-    if (_glfw.focusedWindow == window &&
-        window->cursorMode == GLFW_CURSOR_DISABLED)
-    {
+    if (window->context.client != GLFW_NO_API)
+        [window->context.nsgl.object update];
+
+    if (_glfw.ns.disabledCursorWindow == window)
         centerCursor(window);
-    }
 
     int x, y;
     _glfwPlatformGetWindowPos(window, &x, &y);
@@ -185,35 +260,35 @@
 
 - (void)windowDidMiniaturize:(NSNotification *)notification
 {
-    _glfwInputWindowIconify(window, GL_TRUE);
+    if (window->monitor)
+        releaseMonitor(window);
+
+    _glfwInputWindowIconify(window, GLFW_TRUE);
 }
 
 - (void)windowDidDeminiaturize:(NSNotification *)notification
 {
-    _glfwInputWindowIconify(window, GL_FALSE);
+    if (window->monitor)
+        acquireMonitor(window);
+
+    _glfwInputWindowIconify(window, GLFW_FALSE);
 }
 
 - (void)windowDidBecomeKey:(NSNotification *)notification
 {
-    if (window->monitor)
-        enterFullscreenMode(window);
-
-    if (_glfw.focusedWindow == window &&
-        window->cursorMode == GLFW_CURSOR_DISABLED)
-    {
+    if (_glfw.ns.disabledCursorWindow == window)
         centerCursor(window);
-    }
 
-    _glfwInputWindowFocus(window, GL_TRUE);
-    _glfwPlatformApplyCursorMode(window);
+    _glfwInputWindowFocus(window, GLFW_TRUE);
+    _glfwPlatformSetCursorMode(window, window->cursorMode);
 }
 
 - (void)windowDidResignKey:(NSNotification *)notification
 {
-    if (window->monitor)
-        leaveFullscreenMode(window);
+    if (window->monitor && window->autoIconify)
+        _glfwPlatformIconifyWindow(window);
 
-    _glfwInputWindowFocus(window, GL_FALSE);
+    _glfwInputWindowFocus(window, GLFW_FALSE);
 }
 
 @end
@@ -250,45 +325,26 @@
     _glfwPlatformPostEmptyEvent();
 }
 
-@end
-
-// Translates OS X key modifiers into GLFW ones
-//
-static int translateFlags(NSUInteger flags)
+- (void)applicationDidHide:(NSNotification *)notification
 {
-    int mods = 0;
-
-    if (flags & NSShiftKeyMask)
-        mods |= GLFW_MOD_SHIFT;
-    if (flags & NSControlKeyMask)
-        mods |= GLFW_MOD_CONTROL;
-    if (flags & NSAlternateKeyMask)
-        mods |= GLFW_MOD_ALT;
-    if (flags & NSCommandKeyMask)
-        mods |= GLFW_MOD_SUPER;
+    int i;
 
-    return mods;
+    for (i = 0;  i < _glfw.monitorCount;  i++)
+        _glfwRestoreVideoModeNS(_glfw.monitors[i]);
 }
 
-// Translates a OS X keycode to a GLFW keycode
-//
-static int translateKey(unsigned int key)
-{
-    if (key >= sizeof(_glfw.ns.publicKeys) / sizeof(_glfw.ns.publicKeys[0]))
-        return GLFW_KEY_UNKNOWN;
-
-    return _glfw.ns.publicKeys[key];
-}
+@end
 
 
 //------------------------------------------------------------------------
 // Content view class for the GLFW window
 //------------------------------------------------------------------------
 
-@interface GLFWContentView : NSOpenGLView
+@interface GLFWContentView : NSView <NSTextInputClient>
 {
     _GLFWwindow* window;
     NSTrackingArea* trackingArea;
+    NSMutableAttributedString* markedText;
 }
 
 - (id)initWithGlfwWindow:(_GLFWwindow *)initWindow;
@@ -313,12 +369,12 @@
 
 - (id)initWithGlfwWindow:(_GLFWwindow *)initWindow
 {
-    self = [super initWithFrame:NSMakeRect(0, 0, 1, 1)
-                    pixelFormat:nil];
+    self = [super init];
     if (self != nil)
     {
         window = initWindow;
         trackingArea = nil;
+        markedText = [[NSMutableAttributedString alloc] init];
 
         [self updateTrackingAreas];
         [self registerForDraggedTypes:[NSArray arrayWithObjects:
@@ -328,9 +384,10 @@
     return self;
 }
 
--(void)dealloc
+- (void)dealloc
 {
     [trackingArea release];
+    [markedText release];
     [super dealloc];
 }
 
@@ -351,7 +408,7 @@
 
 - (void)cursorUpdate:(NSEvent *)event
 {
-    updateModeCursor(window);
+    updateCursorImage(window);
 }
 
 - (void)mouseDown:(NSEvent *)event
@@ -379,20 +436,23 @@
 {
     if (window->cursorMode == GLFW_CURSOR_DISABLED)
     {
-        _glfwInputCursorMotion(window,
-                               [event deltaX] - window->ns.warpDeltaX,
-                               [event deltaY] - window->ns.warpDeltaY);
+        const double dx = [event deltaX] - window->ns.cursorWarpDeltaX;
+        const double dy = [event deltaY] - window->ns.cursorWarpDeltaY;
+
+        _glfwInputCursorPos(window,
+                            window->virtualCursorPosX + dx,
+                            window->virtualCursorPosY + dy);
     }
     else
     {
         const NSRect contentRect = [window->ns.view frame];
         const NSPoint pos = [event locationInWindow];
 
-        _glfwInputCursorMotion(window, pos.x, contentRect.size.height - pos.y);
+        _glfwInputCursorPos(window, pos.x, contentRect.size.height - pos.y);
     }
 
-    window->ns.warpDeltaX = 0;
-    window->ns.warpDeltaY = 0;
+    window->ns.cursorWarpDeltaX = 0;
+    window->ns.cursorWarpDeltaY = 0;
 }
 
 - (void)rightMouseDown:(NSEvent *)event
@@ -439,20 +499,24 @@
 
 - (void)mouseExited:(NSEvent *)event
 {
-    _glfwInputCursorEnter(window, GL_FALSE);
+    _glfwInputCursorEnter(window, GLFW_FALSE);
 }
 
 - (void)mouseEntered:(NSEvent *)event
 {
-    _glfwInputCursorEnter(window, GL_TRUE);
+    _glfwInputCursorEnter(window, GLFW_TRUE);
 }
 
 - (void)viewDidChangeBackingProperties
 {
     const NSRect contentRect = [window->ns.view frame];
-    const NSRect fbRect = convertRectToBacking(window, contentRect);
+    const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect];
 
     _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height);
+}
+
+- (void)drawRect:(NSRect)rect
+{
     _glfwInputWindowDamage(window);
 }
 
@@ -487,18 +551,7 @@
 
     _glfwInputKey(window, key, [event keyCode], GLFW_PRESS, mods);
 
-    NSString* characters = [event characters];
-    NSUInteger i, length = [characters length];
-    const int plain = !(mods & GLFW_MOD_SUPER);
-
-    for (i = 0;  i < length;  i++)
-    {
-        const unichar codepoint = [characters characterAtIndex:i];
-        if ((codepoint & 0xff00) == 0xf700)
-            continue;
-
-        _glfwInputChar(window, codepoint, mods, plain);
-    }
+    [self interpretKeyEvents:[NSArray arrayWithObject:event]];
 }
 
 - (void)flagsChanged:(NSEvent *)event
@@ -508,21 +561,18 @@
         [event modifierFlags] & NSDeviceIndependentModifierFlagsMask;
     const int key = translateKey([event keyCode]);
     const int mods = translateFlags(modifierFlags);
+    const NSUInteger keyFlag = translateKeyToModifierFlag(key);
 
-    if (modifierFlags == window->ns.modifierFlags)
+    if (keyFlag & modifierFlags)
     {
         if (window->keys[key] == GLFW_PRESS)
             action = GLFW_RELEASE;
         else
             action = GLFW_PRESS;
     }
-    else if (modifierFlags > window->ns.modifierFlags)
-        action = GLFW_PRESS;
     else
         action = GLFW_RELEASE;
 
-    window->ns.modifierFlags = modifierFlags;
-
     _glfwInputKey(window, key, [event keyCode], action, mods);
 }
 
@@ -537,23 +587,13 @@
 {
     double deltaX, deltaY;
 
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
-    if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6)
-    {
-        deltaX = [event scrollingDeltaX];
-        deltaY = [event scrollingDeltaY];
+    deltaX = [event scrollingDeltaX];
+    deltaY = [event scrollingDeltaY];
 
-        if ([event hasPreciseScrollingDeltas])
-        {
-            deltaX *= 0.1;
-            deltaY *= 0.1;
-        }
-    }
-    else
-#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
+    if ([event hasPreciseScrollingDeltas])
     {
-        deltaX = [event deltaX];
-        deltaY = [event deltaY];
+        deltaX *= 0.1;
+        deltaY *= 0.1;
     }
 
     if (fabs(deltaX) > 0.0 || fabs(deltaY) > 0.0)
@@ -584,9 +624,9 @@
     NSArray* files = [pasteboard propertyListForType:NSFilenamesPboardType];
 
     const NSRect contentRect = [window->ns.view frame];
-    _glfwInputCursorMotion(window,
-                           [sender draggingLocation].x,
-                           contentRect.size.height - [sender draggingLocation].y);
+    _glfwInputCursorPos(window,
+                        [sender draggingLocation].x,
+                        contentRect.size.height - [sender draggingLocation].y);
 
     const int count = [files count];
     if (count)
@@ -613,6 +653,92 @@
     [self setNeedsDisplay:YES];
 }
 
+- (BOOL)hasMarkedText
+{
+    return [markedText length] > 0;
+}
+
+- (NSRange)markedRange
+{
+    if ([markedText length] > 0)
+        return NSMakeRange(0, [markedText length] - 1);
+    else
+        return kEmptyRange;
+}
+
+- (NSRange)selectedRange
+{
+    return kEmptyRange;
+}
+
+- (void)setMarkedText:(id)string
+        selectedRange:(NSRange)selectedRange
+     replacementRange:(NSRange)replacementRange
+{
+    if ([string isKindOfClass:[NSAttributedString class]])
+        [markedText initWithAttributedString:string];
+    else
+        [markedText initWithString:string];
+}
+
+- (void)unmarkText
+{
+    [[markedText mutableString] setString:@""];
+}
+
+- (NSArray*)validAttributesForMarkedText
+{
+    return [NSArray array];
+}
+
+- (NSAttributedString*)attributedSubstringForProposedRange:(NSRange)range
+                                               actualRange:(NSRangePointer)actualRange
+{
+    return nil;
+}
+
+- (NSUInteger)characterIndexForPoint:(NSPoint)point
+{
+    return 0;
+}
+
+- (NSRect)firstRectForCharacterRange:(NSRange)range
+                         actualRange:(NSRangePointer)actualRange
+{
+    int xpos, ypos;
+    _glfwPlatformGetWindowPos(window, &xpos, &ypos);
+    const NSRect contentRect = [window->ns.view frame];
+    return NSMakeRect(xpos, transformY(ypos + contentRect.size.height), 0.0, 0.0);
+}
+
+- (void)insertText:(id)string replacementRange:(NSRange)replacementRange
+{
+    NSString* characters;
+    NSEvent* event = [NSApp currentEvent];
+    const int mods = translateFlags([event modifierFlags]);
+    const int plain = !(mods & GLFW_MOD_SUPER);
+
+    if ([string isKindOfClass:[NSAttributedString class]])
+        characters = [string string];
+    else
+        characters = (NSString*) string;
+
+    NSUInteger i, length = [characters length];
+
+    for (i = 0;  i < length;  i++)
+    {
+        const unichar codepoint = [characters characterAtIndex:i];
+        if ((codepoint & 0xff00) == 0xf700)
+            continue;
+
+        _glfwInputChar(window, codepoint, mods, plain);
+    }
+}
+
+- (void)doCommandBySelector:(SEL)selector
+{
+}
+
 @end
 
 
@@ -654,6 +780,12 @@
         [super sendEvent:event];
 }
 
+
+// No-op thread entry point
+//
+- (void)doNothing:(id)object
+{
+}
 @end
 
 #if defined(_GLFW_USE_MENUBAR)
@@ -719,6 +851,7 @@
     [[appMenu addItemWithTitle:@"Services"
                        action:NULL
                 keyEquivalent:@""] setSubmenu:servicesMenu];
+    [servicesMenu release];
     [appMenu addItem:[NSMenuItem separatorItem]];
     [appMenu addItemWithTitle:[NSString stringWithFormat:@"Hide %@", appName]
                        action:@selector(hide:)
@@ -737,6 +870,7 @@
 
     NSMenuItem* windowMenuItem =
         [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""];
+    [bar release];
     NSMenu* windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
     [NSApp setWindowsMenu:windowMenu];
     [windowMenuItem setSubmenu:windowMenu];
@@ -752,18 +886,12 @@
                           action:@selector(arrangeInFront:)
                    keyEquivalent:@""];
 
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
-    if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6)
-    {
-        // TODO: Make this appear at the bottom of the menu (for consistency)
-
-        [windowMenu addItem:[NSMenuItem separatorItem]];
-        [[windowMenu addItemWithTitle:@"Enter Full Screen"
-                               action:@selector(toggleFullScreen:)
-                        keyEquivalent:@"f"]
-            setKeyEquivalentModifierMask:NSControlKeyMask | NSCommandKeyMask];
-    }
-#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
+    // TODO: Make this appear at the bottom of the menu (for consistency)
+    [windowMenu addItem:[NSMenuItem separatorItem]];
+    [[windowMenu addItemWithTitle:@"Enter Full Screen"
+                           action:@selector(toggleFullScreen:)
+                    keyEquivalent:@"f"]
+     setKeyEquivalentModifierMask:NSControlKeyMask | NSCommandKeyMask];
 
     // Prior to Snow Leopard, we need to use this oddly-named semi-private API
     // to get the application menu working properly.
@@ -775,14 +903,19 @@
 
 // Initialize the Cocoa Application Kit
 //
-static GLboolean initializeAppKit(void)
+static GLFWbool initializeAppKit(void)
 {
     if (NSApp)
-        return GL_TRUE;
+        return GLFW_TRUE;
 
     // Implicitly create shared NSApplication instance
     [GLFWApplication sharedApplication];
 
+    // Make Cocoa enter multi-threaded mode
+    [NSThread detachNewThreadSelector:@selector(doNothing:)
+                             toTarget:NSApp
+                           withObject:nil];
+
     // In case we are unbundled, make us a proper UI application
     [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
 
@@ -800,91 +933,85 @@
     {
         _glfwInputError(GLFW_PLATFORM_ERROR,
                         "Cocoa: Failed to create application delegate");
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
 
     [NSApp setDelegate:_glfw.ns.delegate];
     [NSApp run];
 
-    return GL_TRUE;
+    return GLFW_TRUE;
 }
 
 // Create the Cocoa window
 //
-static GLboolean createWindow(_GLFWwindow* window,
-                              const _GLFWwndconfig* wndconfig)
+static GLFWbool createNativeWindow(_GLFWwindow* window,
+                                   const _GLFWwndconfig* wndconfig)
 {
     window->ns.delegate = [[GLFWWindowDelegate alloc] initWithGlfwWindow:window];
     if (window->ns.delegate == nil)
     {
         _glfwInputError(GLFW_PLATFORM_ERROR,
                         "Cocoa: Failed to create window delegate");
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
 
-    unsigned int styleMask = 0;
+    NSRect contentRect;
 
-    if (wndconfig->monitor || !wndconfig->decorated)
-        styleMask = NSBorderlessWindowMask;
-    else
+    if (window->monitor)
     {
-        styleMask = NSTitledWindowMask | NSClosableWindowMask |
-                    NSMiniaturizableWindowMask;
-
-        if (wndconfig->resizable)
-            styleMask |= NSResizableWindowMask;
-    }
+        GLFWvidmode mode;
+        int xpos, ypos;
 
-    NSRect contentRect;
+        _glfwPlatformGetVideoMode(window->monitor, &mode);
+        _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos);
 
-    if (wndconfig->monitor)
-        contentRect = [wndconfig->monitor->ns.screen frame];
+        contentRect = NSMakeRect(xpos, ypos, mode.width, mode.height);
+    }
     else
         contentRect = NSMakeRect(0, 0, wndconfig->width, wndconfig->height);
 
     window->ns.object = [[GLFWWindow alloc]
         initWithContentRect:contentRect
-                  styleMask:styleMask
+                  styleMask:getStyleMask(window)
                     backing:NSBackingStoreBuffered
                       defer:NO];
 
     if (window->ns.object == nil)
     {
         _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to create window");
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
 
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
-    if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6)
-    {
-        if (wndconfig->resizable)
-            [window->ns.object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
-    }
-#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
-
-    if (wndconfig->monitor)
-    {
+    if (window->monitor)
         [window->ns.object setLevel:NSMainMenuWindowLevel + 1];
-        [window->ns.object setHidesOnDeactivate:YES];
-    }
     else
     {
         [window->ns.object center];
 
+        if (wndconfig->resizable)
+            [window->ns.object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
+
         if (wndconfig->floating)
             [window->ns.object setLevel:NSFloatingWindowLevel];
+
+        if (wndconfig->maximized)
+            [window->ns.object zoom:nil];
     }
 
+    window->ns.view = [[GLFWContentView alloc] initWithGlfwWindow:window];
+
+#if defined(_GLFW_USE_RETINA)
+    [window->ns.view setWantsBestResolutionOpenGLSurface:YES];
+#endif /*_GLFW_USE_RETINA*/
+
+    [window->ns.object makeFirstResponder:window->ns.view];
     [window->ns.object setTitle:[NSString stringWithUTF8String:wndconfig->title]];
     [window->ns.object setDelegate:window->ns.delegate];
     [window->ns.object setAcceptsMouseMovedEvents:YES];
-
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
-    if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6)
-        [window->ns.object setRestorable:NO];
-#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
+    [window->ns.object setContentView:window->ns.view];
+    [window->ns.object setRestorable:NO];
 
-    return GL_TRUE;
+    return GLFW_TRUE;
 }
 
 
@@ -898,50 +1025,52 @@
                               const _GLFWfbconfig* fbconfig)
 {
     if (!initializeAppKit())
-        return GL_FALSE;
-
-    if (!createWindow(window, wndconfig))
-        return GL_FALSE;
-
-    if (!_glfwCreateContext(window, ctxconfig, fbconfig))
-        return GL_FALSE;
-
-    window->ns.view = [[GLFWContentView alloc] initWithGlfwWindow:window];
+        return GLFW_FALSE;
 
-#if defined(_GLFW_USE_RETINA)
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
-    if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6)
-        [window->ns.view setWantsBestResolutionOpenGLSurface:YES];
-#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
-#endif /*_GLFW_USE_RETINA*/
+    if (!createNativeWindow(window, wndconfig))
+        return GLFW_FALSE;
 
-    [window->ns.object setContentView:window->ns.view];
-    // NOTE: If you set the pixel format before the context it creates another
-    //       context, only to have it destroyed by the next line
-    //       We cannot use the view to create the context because that interface
-    //       does not support context resource sharing
-    [window->ns.view setOpenGLContext:window->nsgl.context];
-    [window->ns.view setPixelFormat:window->nsgl.pixelFormat];
-    [window->nsgl.context setView:window->ns.view];
+    if (ctxconfig->client != GLFW_NO_API)
+    {
+        if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API)
+        {
+            if (!_glfwInitNSGL())
+                return GLFW_FALSE;
+            if (!_glfwCreateContextNSGL(window, ctxconfig, fbconfig))
+                return GLFW_FALSE;
+        }
+        else
+        {
+            _glfwInputError(GLFW_API_UNAVAILABLE, "Cocoa: EGL not available");
+            return GLFW_FALSE;
+        }
+    }
 
-    if (wndconfig->monitor)
+    if (window->monitor)
     {
         _glfwPlatformShowWindow(window);
-        if (!enterFullscreenMode(window))
-            return GL_FALSE;
+        _glfwPlatformFocusWindow(window);
+        if (!acquireMonitor(window))
+            return GLFW_FALSE;
+
+        centerCursor(window);
     }
 
-    return GL_TRUE;
+    return GLFW_TRUE;
 }
 
 void _glfwPlatformDestroyWindow(_GLFWwindow* window)
 {
+    if (_glfw.ns.disabledCursorWindow == window)
+        _glfw.ns.disabledCursorWindow = NULL;
+
     [window->ns.object orderOut:nil];
 
     if (window->monitor)
-        leaveFullscreenMode(window);
+        releaseMonitor(window);
 
-    _glfwDestroyContext(window);
+    if (window->context.destroy)
+        window->context.destroy(window);
 
     [window->ns.object setDelegate:nil];
     [window->ns.delegate release];
@@ -952,6 +1081,9 @@
 
     [window->ns.object close];
     window->ns.object = nil;
+
+    [_glfw.ns.autoreleasePool drain];
+    _glfw.ns.autoreleasePool = [[NSAutoreleasePool alloc] init];
 }
 
 void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char *title)
@@ -959,6 +1091,12 @@
     [window->ns.object setTitle:[NSString stringWithUTF8String:title]];
 }
 
+void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
+                                int count, const GLFWimage* images)
+{
+    // Regular windows do not have icons
+}
+
 void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
 {
     const NSRect contentRect =
@@ -991,15 +1129,41 @@
 void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
 {
     if (window->monitor)
-        enterFullscreenMode(window);
+    {
+        if (window->monitor->window == window)
+            acquireMonitor(window);
+    }
     else
         [window->ns.object setContentSize:NSMakeSize(width, height)];
 }
 
+void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
+                                      int minwidth, int minheight,
+                                      int maxwidth, int maxheight)
+{
+    if (minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE)
+        [window->ns.object setContentMinSize:NSMakeSize(0, 0)];
+    else
+        [window->ns.object setContentMinSize:NSMakeSize(minwidth, minheight)];
+
+    if (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE)
+        [window->ns.object setContentMaxSize:NSMakeSize(DBL_MAX, DBL_MAX)];
+    else
+        [window->ns.object setContentMaxSize:NSMakeSize(maxwidth, maxheight)];
+}
+
+void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom)
+{
+    if (numer == GLFW_DONT_CARE || denom == GLFW_DONT_CARE)
+        [window->ns.object setContentAspectRatio:NSMakeSize(0, 0)];
+    else
+        [window->ns.object setContentAspectRatio:NSMakeSize(numer, denom)];
+}
+
 void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height)
 {
     const NSRect contentRect = [window->ns.view frame];
-    const NSRect fbRect = convertRectToBacking(window, contentRect);
+    const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect];
 
     if (width)
         *width = (int) fbRect.size.width;
@@ -1033,11 +1197,30 @@
 
 void _glfwPlatformRestoreWindow(_GLFWwindow* window)
 {
-    [window->ns.object deminiaturize:nil];
+    if ([window->ns.object isMiniaturized])
+        [window->ns.object deminiaturize:nil];
+    else if ([window->ns.object isZoomed])
+        [window->ns.object zoom:nil];
 }
 
+void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
+{
+    if (![window->ns.object isZoomed])
+        [window->ns.object zoom:nil];
+}
+
 void _glfwPlatformShowWindow(_GLFWwindow* window)
 {
+    [window->ns.object orderFront:nil];
+}
+
+void _glfwPlatformHideWindow(_GLFWwindow* window)
+{
+    [window->ns.object orderOut:nil];
+}
+
+void _glfwPlatformFocusWindow(_GLFWwindow* window)
+{
     // Make us the active application
     // HACK: This has been moved here from initializeAppKit to prevent
     //       applications using only hidden windows from being activated, but
@@ -1047,14 +1230,101 @@
     [window->ns.object makeKeyAndOrderFront:nil];
 }
 
-void _glfwPlatformUnhideWindow(_GLFWwindow* window)
+void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
+                                   _GLFWmonitor* monitor,
+                                   int xpos, int ypos,
+                                   int width, int height,
+                                   int refreshRate)
 {
-    [window->ns.object orderFront:nil];
-}
+    if (window->monitor == monitor)
+    {
+        if (monitor)
+        {
+            if (monitor->window == window)
+                acquireMonitor(window);
+        }
+        else
+        {
+            const NSRect contentRect =
+                NSMakeRect(xpos, transformY(ypos + height), width, height);
+            const NSRect frameRect =
+                [window->ns.object frameRectForContentRect:contentRect
+                                                 styleMask:getStyleMask(window)];
 
-void _glfwPlatformHideWindow(_GLFWwindow* window)
-{
-    [window->ns.object orderOut:nil];
+            [window->ns.object setFrame:frameRect display:YES];
+        }
+
+        return;
+    }
+
+    if (window->monitor)
+        releaseMonitor(window);
+
+    _glfwInputWindowMonitorChange(window, monitor);
+
+    const NSUInteger styleMask = getStyleMask(window);
+    [window->ns.object setStyleMask:styleMask];
+    [window->ns.object makeFirstResponder:window->ns.view];
+
+    NSRect contentRect;
+
+    if (monitor)
+    {
+        GLFWvidmode mode;
+
+        _glfwPlatformGetVideoMode(window->monitor, &mode);
+        _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos);
+
+        contentRect = NSMakeRect(xpos, transformY(ypos + mode.height),
+                                    mode.width, mode.height);
+    }
+    else
+    {
+        contentRect = NSMakeRect(xpos, transformY(ypos + height),
+                                    width, height);
+    }
+
+    NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect
+                                                        styleMask:styleMask];
+    [window->ns.object setFrame:frameRect display:YES];
+
+    if (monitor)
+    {
+        [window->ns.object setLevel:NSMainMenuWindowLevel + 1];
+        [window->ns.object setHasShadow:NO];
+
+        acquireMonitor(window);
+    }
+    else
+    {
+        if (window->numer != GLFW_DONT_CARE &&
+            window->denom != GLFW_DONT_CARE)
+        {
+            [window->ns.object setContentAspectRatio:NSMakeSize(window->numer,
+                                                                window->denom)];
+        }
+
+        if (window->minwidth != GLFW_DONT_CARE &&
+            window->minheight != GLFW_DONT_CARE)
+        {
+            [window->ns.object setContentMinSize:NSMakeSize(window->minwidth,
+                                                            window->minheight)];
+        }
+
+        if (window->maxwidth != GLFW_DONT_CARE &&
+            window->maxheight != GLFW_DONT_CARE)
+        {
+            [window->ns.object setContentMaxSize:NSMakeSize(window->maxwidth,
+                                                            window->maxheight)];
+        }
+
+        if (window->floating)
+            [window->ns.object setLevel:NSFloatingWindowLevel];
+        else
+            [window->ns.object setLevel:NSNormalWindowLevel];
+
+        [window->ns.object setHasShadow:YES];
+    }
 }
 
 int _glfwPlatformWindowFocused(_GLFWwindow* window)
@@ -1072,6 +1342,11 @@
     return [window->ns.object isVisible];
 }
 
+int _glfwPlatformWindowMaximized(_GLFWwindow* window)
+{
+    return [window->ns.object isZoomed];
+}
+
 void _glfwPlatformPollEvents(void)
 {
     for (;;)
@@ -1104,6 +1379,19 @@
     _glfwPlatformPollEvents();
 }
 
+void _glfwPlatformWaitEventsTimeout(double timeout)
+{
+    NSDate* date = [NSDate dateWithTimeIntervalSinceNow:timeout];
+    NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
+                                        untilDate:date
+                                           inMode:NSDefaultRunLoopMode
+                                          dequeue:YES];
+    if (event)
+        [NSApp sendEvent:event];
+
+    _glfwPlatformPollEvents();
+}
+
 void _glfwPlatformPostEmptyEvent(void)
 {
     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
@@ -1133,13 +1421,13 @@
 
 void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
 {
-    updateModeCursor(window);
+    updateCursorImage(window);
 
     const NSRect contentRect = [window->ns.view frame];
     const NSPoint pos = [window->ns.object mouseLocationOutsideOfEventStream];
 
-    window->ns.warpDeltaX += x - pos.x;
-    window->ns.warpDeltaY += y - contentRect.size.height + pos.y;
+    window->ns.cursorWarpDeltaX += x - pos.x;
+    window->ns.cursorWarpDeltaY += y - contentRect.size.height + pos.y;
 
     if (window->monitor)
     {
@@ -1148,24 +1436,81 @@
     }
     else
     {
-        const NSPoint localPoint = NSMakePoint(x, contentRect.size.height - y - 1);
-        const NSPoint globalPoint = [window->ns.object convertBaseToScreen:localPoint];
+        const NSRect localRect = NSMakeRect(x, contentRect.size.height - y - 1, 0, 0);
+        const NSRect globalRect = [window->ns.object convertRectToScreen:localRect];
+        const NSPoint globalPoint = globalRect.origin;
 
         CGWarpMouseCursorPosition(CGPointMake(globalPoint.x,
                                               transformY(globalPoint.y)));
     }
 }
 
-void _glfwPlatformApplyCursorMode(_GLFWwindow* window)
+void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
 {
-    updateModeCursor(window);
-
-    if (window->cursorMode == GLFW_CURSOR_DISABLED)
+    if (mode == GLFW_CURSOR_DISABLED)
+    {
+        _glfw.ns.disabledCursorWindow = window;
+        _glfwPlatformGetCursorPos(window,
+                                  &_glfw.ns.restoreCursorPosX,
+                                  &_glfw.ns.restoreCursorPosY);
+        centerCursor(window);
         CGAssociateMouseAndMouseCursorPosition(false);
-    else
+    }
+    else if (_glfw.ns.disabledCursorWindow == window)
+    {
+        _glfw.ns.disabledCursorWindow = NULL;
         CGAssociateMouseAndMouseCursorPosition(true);
+        _glfwPlatformSetCursorPos(window,
+                                  _glfw.ns.restoreCursorPosX,
+                                  _glfw.ns.restoreCursorPosY);
+    }
+
+    if (cursorInClientArea(window))
+        updateCursorImage(window);
 }
 
+const char* _glfwPlatformGetKeyName(int key, int scancode)
+{
+    if (key != GLFW_KEY_UNKNOWN)
+        scancode = _glfw.ns.nativeKeys[key];
+
+    if (!_glfwIsPrintable(_glfw.ns.publicKeys[scancode]))
+        return NULL;
+
+    UInt32 deadKeyState = 0;
+    UniChar characters[8];
+    UniCharCount characterCount = 0;
+
+    if (UCKeyTranslate([(NSData*) _glfw.ns.unicodeData bytes],
+                       scancode,
+                       kUCKeyActionDisplay,
+                       0,
+                       LMGetKbdType(),
+                       kUCKeyTranslateNoDeadKeysBit,
+                       &deadKeyState,
+                       sizeof(characters) / sizeof(characters[0]),
+                       &characterCount,
+                       characters) != noErr)
+    {
+        return NULL;
+    }
+
+    if (!characterCount)
+        return NULL;
+
+    CFStringRef string = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault,
+                                                            characters,
+                                                            characterCount,
+                                                            kCFAllocatorNull);
+    CFStringGetCString(string,
+                       _glfw.ns.keyName,
+                       sizeof(_glfw.ns.keyName),
+                       kCFStringEncodingUTF8);
+    CFRelease(string);
+
+    return _glfw.ns.keyName;
+}
+
 int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
                               const GLFWimage* image,
                               int xhot, int yhot)
@@ -1173,6 +1518,9 @@
     NSImage* native;
     NSBitmapImageRep* rep;
 
+    if (!initializeAppKit())
+        return GLFW_FALSE;
+
     rep = [[NSBitmapImageRep alloc]
         initWithBitmapDataPlanes:NULL
                       pixelsWide:image->width
@@ -1187,12 +1535,12 @@
                     bitsPerPixel:32];
 
     if (rep == nil)
-        return GL_FALSE;
+        return GLFW_FALSE;
 
     memcpy([rep bitmapData], image->pixels, image->width * image->height * 4);
 
     native = [[NSImage alloc] initWithSize:NSMakeSize(image->width, image->height)];
-    [native addRepresentation: rep];
+    [native addRepresentation:rep];
 
     cursor->ns.object = [[NSCursor alloc] initWithImage:native
                                                 hotSpot:NSMakePoint(xhot, yhot)];
@@ -1201,22 +1549,26 @@
     [rep release];
 
     if (cursor->ns.object == nil)
-        return GL_FALSE;
+        return GLFW_FALSE;
 
-    return GL_TRUE;
+    return GLFW_TRUE;
 }
 
 int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
 {
+    if (!initializeAppKit())
+        return GLFW_FALSE;
+
     cursor->ns.object = getStandardCursor(shape);
     if (!cursor->ns.object)
     {
-        _glfwInputError(GLFW_INVALID_ENUM, "Cocoa: Invalid standard cursor");
-        return GL_FALSE;
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Cocoa: Failed to retrieve standard cursor");
+        return GLFW_FALSE;
     }
 
     [cursor->ns.object retain];
-    return GL_TRUE;
+    return GLFW_TRUE;
 }
 
 void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
@@ -1227,16 +1579,8 @@
 
 void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
 {
-    const NSPoint pos = [window->ns.object mouseLocationOutsideOfEventStream];
-
-    if (window->cursorMode == GLFW_CURSOR_NORMAL &&
-        [window->ns.view mouse:pos inRect:[window->ns.view frame]])
-    {
-        if (cursor)
-            [(NSCursor*) cursor->ns.object set];
-        else
-            [[NSCursor arrowCursor] set];
-    }
+    if (cursorInClientArea(window))
+        updateCursorImage(window);
 }
 
 void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
@@ -1255,7 +1599,8 @@
 
     if (![[pasteboard types] containsObject:NSStringPboardType])
     {
-        _glfwInputError(GLFW_FORMAT_UNAVAILABLE, NULL);
+        _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
+                        "Cocoa: Failed to retrieve string from pasteboard");
         return NULL;
     }
 
@@ -1271,6 +1616,27 @@
     _glfw.ns.clipboardString = strdup([object UTF8String]);
 
     return _glfw.ns.clipboardString;
+}
+
+char** _glfwPlatformGetRequiredInstanceExtensions(uint32_t* count)
+{
+    *count = 0;
+    return NULL;
+}
+
+int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
+                                                      VkPhysicalDevice device,
+                                                      uint32_t queuefamily)
+{
+    return GLFW_FALSE;
+}
+
+VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
+                                          _GLFWwindow* window,
+                                          const VkAllocationCallbacks* allocator,
+                                          VkSurfaceKHR* surface)
+{
+    return VK_ERROR_EXTENSION_NOT_PRESENT;
 }
 
 
diff --git a/glfw/src/context.c b/glfw/src/context.c
--- a/glfw/src/context.c
+++ b/glfw/src/context.c
@@ -1,8 +1,8 @@
 //========================================================================
-// GLFW 3.1 - www.glfw.org
+// GLFW 3.2 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -27,74 +27,40 @@
 
 #include "internal.h"
 
+#include <assert.h>
 #include <stdio.h>
 #include <string.h>
 #include <limits.h>
 #include <stdio.h>
 
 
-// Parses the client API version string and extracts the version number
-//
-static GLboolean parseVersionString(int* api, int* major, int* minor, int* rev)
-{
-    int i;
-    const char* version;
-    const char* prefixes[] =
-    {
-        "OpenGL ES-CM ",
-        "OpenGL ES-CL ",
-        "OpenGL ES ",
-        NULL
-    };
-
-    *api = GLFW_OPENGL_API;
-
-    version = (const char*) glGetString(GL_VERSION);
-    if (!version)
-    {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "Failed to retrieve context version string");
-        return GL_FALSE;
-    }
-
-    for (i = 0;  prefixes[i];  i++)
-    {
-        const size_t length = strlen(prefixes[i]);
-
-        if (strncmp(version, prefixes[i], length) == 0)
-        {
-            version += length;
-            *api = GLFW_OPENGL_ES_API;
-            break;
-        }
-    }
-
-    if (!sscanf(version, "%d.%d.%d", major, minor, rev))
-    {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "No version found in context version string");
-        return GL_FALSE;
-    }
-
-    return GL_TRUE;
-}
-
-
 //////////////////////////////////////////////////////////////////////////
 //////                       GLFW internal API                      //////
 //////////////////////////////////////////////////////////////////////////
 
-GLboolean _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
+GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
 {
-    if (ctxconfig->api != GLFW_OPENGL_API &&
-        ctxconfig->api != GLFW_OPENGL_ES_API)
+    if (ctxconfig->source != GLFW_NATIVE_CONTEXT_API &&
+        ctxconfig->source != GLFW_EGL_CONTEXT_API)
     {
-        _glfwInputError(GLFW_INVALID_ENUM, "Invalid client API requested");
-        return GL_FALSE;
+        _glfwInputError(GLFW_INVALID_ENUM,
+                        "Invalid context creation API %i",
+                        ctxconfig->source);
+        return GLFW_FALSE;
     }
 
-    if (ctxconfig->api == GLFW_OPENGL_API)
+    if (ctxconfig->client != GLFW_NO_API &&
+        ctxconfig->client != GLFW_OPENGL_API &&
+        ctxconfig->client != GLFW_OPENGL_ES_API)
     {
+        _glfwInputError(GLFW_INVALID_ENUM,
+                        "Invalid client API %i",
+                        ctxconfig->client);
+        return GLFW_FALSE;
+    }
+
+    if (ctxconfig->client == GLFW_OPENGL_API)
+    {
         if ((ctxconfig->major < 1 || ctxconfig->minor < 0) ||
             (ctxconfig->major == 1 && ctxconfig->minor > 5) ||
             (ctxconfig->major == 2 && ctxconfig->minor > 1) ||
@@ -104,15 +70,12 @@
             // OpenGL 1.x series ended with version 1.5
             // OpenGL 2.x series ended with version 2.1
             // OpenGL 3.x series ended with version 3.3
+            // For now, let everything else through
 
             _glfwInputError(GLFW_INVALID_VALUE,
-                            "Invalid OpenGL version %i.%i requested",
+                            "Invalid OpenGL version %i.%i",
                             ctxconfig->major, ctxconfig->minor);
-            return GL_FALSE;
-        }
-        else
-        {
-            // For now, let everything else through
+            return GLFW_FALSE;
         }
 
         if (ctxconfig->profile)
@@ -121,33 +84,32 @@
                 ctxconfig->profile != GLFW_OPENGL_COMPAT_PROFILE)
             {
                 _glfwInputError(GLFW_INVALID_ENUM,
-                                "Invalid OpenGL profile requested");
-                return GL_FALSE;
+                                "Invalid OpenGL profile %i",
+                                ctxconfig->profile);
+                return GLFW_FALSE;
             }
 
-            if (ctxconfig->major < 3 ||
+            if (ctxconfig->major <= 2 ||
                 (ctxconfig->major == 3 && ctxconfig->minor < 2))
             {
                 // Desktop OpenGL context profiles are only defined for version 3.2
                 // and above
 
                 _glfwInputError(GLFW_INVALID_VALUE,
-                                "Context profiles only exist for "
-                                "OpenGL version 3.2 and above");
-                return GL_FALSE;
+                                "Context profiles are only defined for OpenGL version 3.2 and above");
+                return GLFW_FALSE;
             }
         }
 
-        if (ctxconfig->forward && ctxconfig->major < 3)
+        if (ctxconfig->forward && ctxconfig->major <= 2)
         {
             // Forward-compatible contexts are only defined for OpenGL version 3.0 and above
             _glfwInputError(GLFW_INVALID_VALUE,
-                            "Forward compatibility only exist for OpenGL "
-                            "version 3.0 and above");
-            return GL_FALSE;
+                            "Forward-compatibility is only defined for OpenGL version 3.0 and above");
+            return GLFW_FALSE;
         }
     }
-    else if (ctxconfig->api == GLFW_OPENGL_ES_API)
+    else if (ctxconfig->client == GLFW_OPENGL_ES_API)
     {
         if (ctxconfig->major < 1 || ctxconfig->minor < 0 ||
             (ctxconfig->major == 1 && ctxconfig->minor > 1) ||
@@ -156,31 +118,12 @@
             // OpenGL ES 1.0 is the smallest valid version
             // OpenGL ES 1.x series ended with version 1.1
             // OpenGL ES 2.x series ended with version 2.0
-
-            _glfwInputError(GLFW_INVALID_VALUE,
-                            "Invalid OpenGL ES version %i.%i requested",
-                            ctxconfig->major, ctxconfig->minor);
-            return GL_FALSE;
-        }
-        else
-        {
             // For now, let everything else through
-        }
 
-        if (ctxconfig->profile)
-        {
-            // OpenGL ES does not support profiles
             _glfwInputError(GLFW_INVALID_VALUE,
-                            "Context profiles are not supported by OpenGL ES");
-            return GL_FALSE;
-        }
-
-        if (ctxconfig->forward)
-        {
-            // OpenGL ES does not support forward-compatibility
-            _glfwInputError(GLFW_INVALID_VALUE,
-                            "Forward compatibility is not supported by OpenGL ES");
-            return GL_FALSE;
+                            "Invalid OpenGL ES version %i.%i",
+                            ctxconfig->major, ctxconfig->minor);
+            return GLFW_FALSE;
         }
     }
 
@@ -189,9 +132,10 @@
         if (ctxconfig->robustness != GLFW_NO_RESET_NOTIFICATION &&
             ctxconfig->robustness != GLFW_LOSE_CONTEXT_ON_RESET)
         {
-            _glfwInputError(GLFW_INVALID_VALUE,
-                            "Invalid context robustness mode requested");
-            return GL_FALSE;
+            _glfwInputError(GLFW_INVALID_ENUM,
+                            "Invalid context robustness mode %i",
+                            ctxconfig->robustness);
+            return GLFW_FALSE;
         }
     }
 
@@ -200,13 +144,14 @@
         if (ctxconfig->release != GLFW_RELEASE_BEHAVIOR_NONE &&
             ctxconfig->release != GLFW_RELEASE_BEHAVIOR_FLUSH)
         {
-            _glfwInputError(GLFW_INVALID_VALUE,
-                            "Invalid context release behavior requested");
-            return GL_FALSE;
+            _glfwInputError(GLFW_INVALID_ENUM,
+                            "Invalid context release behavior %i",
+                            ctxconfig->release);
+            return GLFW_FALSE;
         }
     }
 
-    return GL_TRUE;
+    return GLFW_TRUE;
 }
 
 const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired,
@@ -372,63 +317,159 @@
     return closest;
 }
 
-GLboolean _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig)
+GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig)
 {
-    _GLFWwindow* window = _glfwPlatformGetCurrentContext();
+    int i;
+    _GLFWwindow* window;
+    const char* version;
+    const char* prefixes[] =
+    {
+        "OpenGL ES-CM ",
+        "OpenGL ES-CL ",
+        "OpenGL ES ",
+        NULL
+    };
 
-    if (!parseVersionString(&window->context.api,
-                            &window->context.major,
-                            &window->context.minor,
-                            &window->context.revision))
+    window = _glfwPlatformGetCurrentContext();
+
+    window->context.source = ctxconfig->source;
+    window->context.client = GLFW_OPENGL_API;
+
+    window->context.GetIntegerv = (PFNGLGETINTEGERVPROC)
+        window->context.getProcAddress("glGetIntegerv");
+    window->context.GetString = (PFNGLGETSTRINGPROC)
+        window->context.getProcAddress("glGetString");
+    if (!window->context.GetIntegerv || !window->context.GetString)
     {
-        return GL_FALSE;
+        _glfwInputError(GLFW_PLATFORM_ERROR, "Entry point retrieval is broken");
+        return GLFW_FALSE;
     }
 
-#if defined(_GLFW_USE_OPENGL)
-    if (window->context.major > 2)
+    version = (const char*) window->context.GetString(GL_VERSION);
+    if (!version)
     {
+        if (ctxconfig->client == GLFW_OPENGL_API)
+        {
+            _glfwInputError(GLFW_PLATFORM_ERROR,
+                            "OpenGL version string retrieval is broken");
+        }
+        else
+        {
+            _glfwInputError(GLFW_PLATFORM_ERROR,
+                            "OpenGL ES version string retrieval is broken");
+        }
+
+        return GLFW_FALSE;
+    }
+
+    for (i = 0;  prefixes[i];  i++)
+    {
+        const size_t length = strlen(prefixes[i]);
+
+        if (strncmp(version, prefixes[i], length) == 0)
+        {
+            version += length;
+            window->context.client = GLFW_OPENGL_ES_API;
+            break;
+        }
+    }
+
+    if (!sscanf(version, "%d.%d.%d",
+                &window->context.major,
+                &window->context.minor,
+                &window->context.revision))
+    {
+        if (window->context.client == GLFW_OPENGL_API)
+        {
+            _glfwInputError(GLFW_PLATFORM_ERROR,
+                            "No version found in OpenGL version string");
+        }
+        else
+        {
+            _glfwInputError(GLFW_PLATFORM_ERROR,
+                            "No version found in OpenGL ES version string");
+        }
+
+        return GLFW_FALSE;
+    }
+
+    if (window->context.major < ctxconfig->major ||
+        (window->context.major == ctxconfig->major &&
+         window->context.minor < ctxconfig->minor))
+    {
+        // The desired OpenGL version is greater than the actual version
+        // This only happens if the machine lacks {GLX|WGL}_ARB_create_context
+        // /and/ the user has requested an OpenGL version greater than 1.0
+
+        // For API consistency, we emulate the behavior of the
+        // {GLX|WGL}_ARB_create_context extension and fail here
+
+        if (window->context.client == GLFW_OPENGL_API)
+        {
+            _glfwInputError(GLFW_VERSION_UNAVAILABLE,
+                            "Requested OpenGL version %i.%i, got version %i.%i",
+                            ctxconfig->major, ctxconfig->minor,
+                            window->context.major, window->context.minor);
+        }
+        else
+        {
+            _glfwInputError(GLFW_VERSION_UNAVAILABLE,
+                            "Requested OpenGL ES version %i.%i, got version %i.%i",
+                            ctxconfig->major, ctxconfig->minor,
+                            window->context.major, window->context.minor);
+        }
+
+        return GLFW_FALSE;
+    }
+
+    if (window->context.major >= 3)
+    {
         // OpenGL 3.0+ uses a different function for extension string retrieval
         // We cache it here instead of in glfwExtensionSupported mostly to alert
         // users as early as possible that their build may be broken
 
-        window->GetStringi = (PFNGLGETSTRINGIPROC) glfwGetProcAddress("glGetStringi");
-        if (!window->GetStringi)
+        window->context.GetStringi = (PFNGLGETSTRINGIPROC)
+            window->context.getProcAddress("glGetStringi");
+        if (!window->context.GetStringi)
         {
             _glfwInputError(GLFW_PLATFORM_ERROR,
                             "Entry point retrieval is broken");
-            return GL_FALSE;
+            return GLFW_FALSE;
         }
     }
 
-    if (window->context.api == GLFW_OPENGL_API)
+    if (window->context.client == GLFW_OPENGL_API)
     {
         // Read back context flags (OpenGL 3.0 and above)
         if (window->context.major >= 3)
         {
             GLint flags;
-            glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
+            window->context.GetIntegerv(GL_CONTEXT_FLAGS, &flags);
 
             if (flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT)
-                window->context.forward = GL_TRUE;
+                window->context.forward = GLFW_TRUE;
 
             if (flags & GL_CONTEXT_FLAG_DEBUG_BIT)
-                window->context.debug = GL_TRUE;
+                window->context.debug = GLFW_TRUE;
             else if (glfwExtensionSupported("GL_ARB_debug_output") &&
                      ctxconfig->debug)
             {
                 // HACK: This is a workaround for older drivers (pre KHR_debug)
                 //       not setting the debug bit in the context flags for
                 //       debug contexts
-                window->context.debug = GL_TRUE;
+                window->context.debug = GLFW_TRUE;
             }
+
+            if (flags & GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR)
+                window->context.noerror = GLFW_TRUE;
         }
 
         // Read back OpenGL context profile (OpenGL 3.2 and above)
-        if (window->context.major > 3 ||
+        if (window->context.major >= 4 ||
             (window->context.major == 3 && window->context.minor >= 2))
         {
             GLint mask;
-            glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask);
+            window->context.GetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask);
 
             if (mask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
                 window->context.profile = GLFW_OPENGL_COMPAT_PROFILE;
@@ -451,7 +492,8 @@
             //       only present from 3.0 while the extension applies from 1.1
 
             GLint strategy;
-            glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, &strategy);
+            window->context.GetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB,
+                                        &strategy);
 
             if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB)
                 window->context.robustness = GLFW_LOSE_CONTEXT_ON_RESET;
@@ -468,7 +510,8 @@
             //       one, so we can reuse them here
 
             GLint strategy;
-            glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, &strategy);
+            window->context.GetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB,
+                                        &strategy);
 
             if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB)
                 window->context.robustness = GLFW_LOSE_CONTEXT_ON_RESET;
@@ -480,55 +523,38 @@
     if (glfwExtensionSupported("GL_KHR_context_flush_control"))
     {
         GLint behavior;
-        glGetIntegerv(GL_CONTEXT_RELEASE_BEHAVIOR, &behavior);
+        window->context.GetIntegerv(GL_CONTEXT_RELEASE_BEHAVIOR, &behavior);
 
         if (behavior == GL_NONE)
             window->context.release = GLFW_RELEASE_BEHAVIOR_NONE;
         else if (behavior == GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH)
             window->context.release = GLFW_RELEASE_BEHAVIOR_FLUSH;
     }
-#endif // _GLFW_USE_OPENGL
 
-    return GL_TRUE;
-}
-
-GLboolean _glfwIsValidContext(const _GLFWctxconfig* ctxconfig)
-{
-    _GLFWwindow* window = _glfwPlatformGetCurrentContext();
-
-    if (window->context.major < ctxconfig->major ||
-        (window->context.major == ctxconfig->major &&
-         window->context.minor < ctxconfig->minor))
+    // Clearing the front buffer to black to avoid garbage pixels left over from
+    // previous uses of our bit of VRAM
     {
-        // The desired OpenGL version is greater than the actual version
-        // This only happens if the machine lacks {GLX|WGL}_ARB_create_context
-        // /and/ the user has requested an OpenGL version greater than 1.0
-
-        // For API consistency, we emulate the behavior of the
-        // {GLX|WGL}_ARB_create_context extension and fail here
-
-        _glfwInputError(GLFW_VERSION_UNAVAILABLE, NULL);
-        return GL_FALSE;
+        PFNGLCLEARPROC glClear = (PFNGLCLEARPROC)
+            window->context.getProcAddress("glClear");
+        glClear(GL_COLOR_BUFFER_BIT);
+        window->context.swapBuffers(window);
     }
 
-    return GL_TRUE;
+    return GLFW_TRUE;
 }
 
-int _glfwStringInExtensionString(const char* string, const GLubyte* extensions)
+GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions)
 {
-    const GLubyte* start;
-    GLubyte* where;
-    GLubyte* terminator;
+    const char* start = extensions;
 
-    // It takes a bit of care to be fool-proof about parsing the
-    // OpenGL extensions string. Don't be fooled by sub-strings,
-    // etc.
-    start = extensions;
     for (;;)
     {
-        where = (GLubyte*) strstr((const char*) start, string);
+        const char* where;
+        const char* terminator;
+
+        where = strstr(start, string);
         if (!where)
-            return GL_FALSE;
+            return GLFW_FALSE;
 
         terminator = where + strlen(string);
         if (where == start || *(where - 1) == ' ')
@@ -540,7 +566,7 @@
         start = terminator;
     }
 
-    return GL_TRUE;
+    return GLFW_TRUE;
 }
 
 
@@ -551,13 +577,24 @@
 GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    _GLFWwindow* previous = _glfwPlatformGetCurrentContext();
 
     _GLFW_REQUIRE_INIT();
 
-    if (_glfwPlatformGetCurrentContext() == window)
+    if (window && window->context.client == GLFW_NO_API)
+    {
+        _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
         return;
+    }
 
-    _glfwPlatformMakeContextCurrent(window);
+    if (previous)
+    {
+        if (!window || window->context.source != previous->context.source)
+            previous->context.makeCurrent(NULL);
+    }
+
+    if (window)
+        window->context.makeCurrent(window);
 }
 
 GLFWAPI GLFWwindow* glfwGetCurrentContext(void)
@@ -569,43 +606,56 @@
 GLFWAPI void glfwSwapBuffers(GLFWwindow* handle)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _GLFW_REQUIRE_INIT();
-    _glfwPlatformSwapBuffers(window);
+
+    if (window->context.client == GLFW_NO_API)
+    {
+        _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
+        return;
+    }
+
+    window->context.swapBuffers(window);
 }
 
 GLFWAPI void glfwSwapInterval(int interval)
 {
+    _GLFWwindow* window;
+
     _GLFW_REQUIRE_INIT();
 
-    if (!_glfwPlatformGetCurrentContext())
+    window = _glfwPlatformGetCurrentContext();
+    if (!window)
     {
         _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL);
         return;
     }
 
-    _glfwPlatformSwapInterval(interval);
+    window->context.swapInterval(interval);
 }
 
 GLFWAPI int glfwExtensionSupported(const char* extension)
 {
     _GLFWwindow* window;
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(GL_FALSE);
+    assert(extension != NULL);
 
+    _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
+
     window = _glfwPlatformGetCurrentContext();
     if (!window)
     {
         _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL);
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
 
     if (*extension == '\0')
     {
-        _glfwInputError(GLFW_INVALID_VALUE, NULL);
-        return GL_FALSE;
+        _glfwInputError(GLFW_INVALID_VALUE, "Extension name is empty string");
+        return GLFW_FALSE;
     }
 
-#if defined(_GLFW_USE_OPENGL)
     if (window->context.major >= 3)
     {
         int i;
@@ -613,53 +663,58 @@
 
         // Check if extension is in the modern OpenGL extensions string list
 
-        glGetIntegerv(GL_NUM_EXTENSIONS, &count);
+        window->context.GetIntegerv(GL_NUM_EXTENSIONS, &count);
 
         for (i = 0;  i < count;  i++)
         {
-            const char* en = (const char*) window->GetStringi(GL_EXTENSIONS, i);
+            const char* en = (const char*)
+                window->context.GetStringi(GL_EXTENSIONS, i);
             if (!en)
             {
                 _glfwInputError(GLFW_PLATFORM_ERROR,
-                                "Failed to retrieve extension string %i", i);
-                return GL_FALSE;
+                                "Extension string retrieval is broken");
+                return GLFW_FALSE;
             }
 
             if (strcmp(en, extension) == 0)
-                return GL_TRUE;
+                return GLFW_TRUE;
         }
     }
     else
-#endif // _GLFW_USE_OPENGL
     {
         // Check if extension is in the old style OpenGL extensions string
 
-        const GLubyte* extensions = glGetString(GL_EXTENSIONS);
+        const char* extensions = (const char*)
+            window->context.GetString(GL_EXTENSIONS);
         if (!extensions)
         {
             _glfwInputError(GLFW_PLATFORM_ERROR,
-                            "Failed to retrieve extension string");
-            return GL_FALSE;
+                            "Extension string retrieval is broken");
+            return GLFW_FALSE;
         }
 
         if (_glfwStringInExtensionString(extension, extensions))
-            return GL_TRUE;
+            return GLFW_TRUE;
     }
 
     // Check if extension is in the platform-specific string
-    return _glfwPlatformExtensionSupported(extension);
+    return window->context.extensionSupported(extension);
 }
 
 GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname)
 {
+    _GLFWwindow* window;
+    assert(procname != NULL);
+
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
 
-    if (!_glfwPlatformGetCurrentContext())
+    window = _glfwPlatformGetCurrentContext();
+    if (!window)
     {
         _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL);
         return NULL;
     }
 
-    return _glfwPlatformGetProcAddress(procname);
+    return window->context.getProcAddress(procname);
 }
 
diff --git a/glfw/src/egl_context.c b/glfw/src/egl_context.c
--- a/glfw/src/egl_context.c
+++ b/glfw/src/egl_context.c
@@ -1,8 +1,8 @@
 //========================================================================
-// GLFW 3.1 EGL - www.glfw.org
+// GLFW 3.2 EGL - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -28,13 +28,14 @@
 #include "internal.h"
 
 #include <stdio.h>
+#include <string.h>
 #include <stdlib.h>
 #include <assert.h>
 
 
 // Return a description of the specified EGL error
 //
-static const char* getErrorString(EGLint error)
+static const char* getEGLErrorString(EGLint error)
 {
     switch (error)
     {
@@ -47,54 +48,46 @@
         case EGL_BAD_ALLOC:
             return "EGL failed to allocate resources for the requested operation";
         case EGL_BAD_ATTRIBUTE:
-            return "An unrecognized attribute or attribute value was passed "
-                   "in the attribute list";
+            return "An unrecognized attribute or attribute value was passed in the attribute list";
         case EGL_BAD_CONTEXT:
-            return "An EGLContext argument does not name a valid EGL "
-                   "rendering context";
+            return "An EGLContext argument does not name a valid EGL rendering context";
         case EGL_BAD_CONFIG:
-            return "An EGLConfig argument does not name a valid EGL frame "
-                   "buffer configuration";
+            return "An EGLConfig argument does not name a valid EGL frame buffer configuration";
         case EGL_BAD_CURRENT_SURFACE:
-            return "The current surface of the calling thread is a window, pixel "
-                   "buffer or pixmap that is no longer valid";
+            return "The current surface of the calling thread is a window, pixel buffer or pixmap that is no longer valid";
         case EGL_BAD_DISPLAY:
-            return "An EGLDisplay argument does not name a valid EGL display "
-                   "connection";
+            return "An EGLDisplay argument does not name a valid EGL display connection";
         case EGL_BAD_SURFACE:
-            return "An EGLSurface argument does not name a valid surface "
-                   "configured for GL rendering";
+            return "An EGLSurface argument does not name a valid surface configured for GL rendering";
         case EGL_BAD_MATCH:
             return "Arguments are inconsistent";
         case EGL_BAD_PARAMETER:
             return "One or more argument values are invalid";
         case EGL_BAD_NATIVE_PIXMAP:
-            return "A NativePixmapType argument does not refer to a valid "
-                   "native pixmap";
+            return "A NativePixmapType argument does not refer to a valid native pixmap";
         case EGL_BAD_NATIVE_WINDOW:
-            return "A NativeWindowType argument does not refer to a valid "
-                   "native window";
+            return "A NativeWindowType argument does not refer to a valid native window";
         case EGL_CONTEXT_LOST:
             return "The application must destroy all contexts and reinitialise";
+        default:
+            return "ERROR: UNKNOWN EGL ERROR";
     }
-
-    return "UNKNOWN EGL ERROR";
 }
 
 // Returns the specified attribute of the specified EGLConfig
 //
-static int getConfigAttrib(EGLConfig config, int attrib)
+static int getEGLConfigAttrib(EGLConfig config, int attrib)
 {
     int value;
     eglGetConfigAttrib(_glfw.egl.display, config, attrib, &value);
     return value;
 }
 
-// Return a list of available and usable framebuffer configs
+// Return the EGLConfig most closely matching the specified hints
 //
-static GLboolean chooseFBConfigs(const _GLFWctxconfig* ctxconfig,
-                                 const _GLFWfbconfig* desired,
-                                 EGLConfig* result)
+static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
+                                const _GLFWfbconfig* desired,
+                                EGLConfig* result)
 {
     EGLConfig* nativeConfigs;
     _GLFWfbconfig* usableConfigs;
@@ -105,7 +98,7 @@
     if (!nativeCount)
     {
         _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: No EGLConfigs returned");
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
 
     nativeConfigs = calloc(nativeCount, sizeof(EGLConfig));
@@ -119,114 +112,312 @@
         const EGLConfig n = nativeConfigs[i];
         _GLFWfbconfig* u = usableConfigs + usableCount;
 
-#if defined(_GLFW_X11)
-        if (!getConfigAttrib(n, EGL_NATIVE_VISUAL_ID))
-        {
-            // Only consider EGLConfigs with associated visuals
+        // Only consider RGB(A) EGLConfigs
+        if (!(getEGLConfigAttrib(n, EGL_COLOR_BUFFER_TYPE) & EGL_RGB_BUFFER))
             continue;
-        }
-#endif // _GLFW_X11
 
-        if (!(getConfigAttrib(n, EGL_COLOR_BUFFER_TYPE) & EGL_RGB_BUFFER))
-        {
-            // Only consider RGB(A) EGLConfigs
+        // Only consider window EGLConfigs
+        if (!(getEGLConfigAttrib(n, EGL_SURFACE_TYPE) & EGL_WINDOW_BIT))
             continue;
-        }
 
-        if (!(getConfigAttrib(n, EGL_SURFACE_TYPE) & EGL_WINDOW_BIT))
-        {
-            // Only consider window EGLConfigs
+#if defined(_GLFW_X11)
+        // Only consider EGLConfigs with associated Visuals
+        if (!getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID))
             continue;
-        }
+#endif // _GLFW_X11
 
-        if (ctxconfig->api == GLFW_OPENGL_ES_API)
+        if (ctxconfig->client == GLFW_OPENGL_ES_API)
         {
             if (ctxconfig->major == 1)
             {
-                if (!(getConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES_BIT))
+                if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES_BIT))
                     continue;
             }
             else
             {
-                if (!(getConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT))
+                if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT))
                     continue;
             }
         }
-        else if (ctxconfig->api == GLFW_OPENGL_API)
+        else if (ctxconfig->client == GLFW_OPENGL_API)
         {
-            if (!(getConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_BIT))
+            if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_BIT))
                 continue;
         }
 
-        u->redBits = getConfigAttrib(n, EGL_RED_SIZE);
-        u->greenBits = getConfigAttrib(n, EGL_GREEN_SIZE);
-        u->blueBits = getConfigAttrib(n, EGL_BLUE_SIZE);
+        u->redBits = getEGLConfigAttrib(n, EGL_RED_SIZE);
+        u->greenBits = getEGLConfigAttrib(n, EGL_GREEN_SIZE);
+        u->blueBits = getEGLConfigAttrib(n, EGL_BLUE_SIZE);
 
-        u->alphaBits = getConfigAttrib(n, EGL_ALPHA_SIZE);
-        u->depthBits = getConfigAttrib(n, EGL_DEPTH_SIZE);
-        u->stencilBits = getConfigAttrib(n, EGL_STENCIL_SIZE);
+        u->alphaBits = getEGLConfigAttrib(n, EGL_ALPHA_SIZE);
+        u->depthBits = getEGLConfigAttrib(n, EGL_DEPTH_SIZE);
+        u->stencilBits = getEGLConfigAttrib(n, EGL_STENCIL_SIZE);
 
-        u->samples = getConfigAttrib(n, EGL_SAMPLES);
-        u->doublebuffer = GL_TRUE;
+        u->samples = getEGLConfigAttrib(n, EGL_SAMPLES);
+        u->doublebuffer = GLFW_TRUE;
 
-        u->egl = n;
+        u->handle = (uintptr_t) n;
         usableCount++;
     }
 
     closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount);
     if (closest)
-        *result = closest->egl;
+        *result = (EGLConfig) closest->handle;
 
     free(nativeConfigs);
     free(usableConfigs);
 
-    return closest ? GL_TRUE : GL_FALSE;
+    return closest != NULL;
 }
 
+static void makeContextCurrentEGL(_GLFWwindow* window)
+{
+    if (window)
+    {
+        if (!eglMakeCurrent(_glfw.egl.display,
+                            window->context.egl.surface,
+                            window->context.egl.surface,
+                            window->context.egl.handle))
+        {
+            _glfwInputError(GLFW_PLATFORM_ERROR,
+                            "EGL: Failed to make context current: %s",
+                            getEGLErrorString(eglGetError()));
+            return;
+        }
+    }
+    else
+    {
+        if (!eglMakeCurrent(_glfw.egl.display,
+                            EGL_NO_SURFACE,
+                            EGL_NO_SURFACE,
+                            EGL_NO_CONTEXT))
+        {
+            _glfwInputError(GLFW_PLATFORM_ERROR,
+                            "EGL: Failed to clear current context: %s",
+                            getEGLErrorString(eglGetError()));
+            return;
+        }
+    }
 
+    _glfwPlatformSetCurrentContext(window);
+}
+
+static void swapBuffersEGL(_GLFWwindow* window)
+{
+    if (window != _glfwPlatformGetCurrentContext())
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "EGL: The context must be current on the calling thread when swapping buffers");
+        return;
+    }
+
+    eglSwapBuffers(_glfw.egl.display, window->context.egl.surface);
+}
+
+static void swapIntervalEGL(int interval)
+{
+    eglSwapInterval(_glfw.egl.display, interval);
+}
+
+static int extensionSupportedEGL(const char* extension)
+{
+    const char* extensions = eglQueryString(_glfw.egl.display, EGL_EXTENSIONS);
+    if (extensions)
+    {
+        if (_glfwStringInExtensionString(extension, extensions))
+            return GLFW_TRUE;
+    }
+
+    return GLFW_FALSE;
+}
+
+static GLFWglproc getProcAddressEGL(const char* procname)
+{
+    _GLFWwindow* window = _glfwPlatformGetCurrentContext();
+
+    if (window->context.egl.client)
+    {
+        GLFWglproc proc = (GLFWglproc) _glfw_dlsym(window->context.egl.client,
+                                                   procname);
+        if (proc)
+            return proc;
+    }
+
+    return eglGetProcAddress(procname);
+}
+
+static void destroyContextEGL(_GLFWwindow* window)
+{
+#if defined(_GLFW_X11)
+    // NOTE: Do not unload libGL.so.1 while the X11 display is still open,
+    //       as it will make XCloseDisplay segfault
+    if (window->context.client != GLFW_OPENGL_API)
+#endif // _GLFW_X11
+    {
+        if (window->context.egl.client)
+        {
+            _glfw_dlclose(window->context.egl.client);
+            window->context.egl.client = NULL;
+        }
+    }
+
+    if (window->context.egl.surface)
+    {
+        eglDestroySurface(_glfw.egl.display, window->context.egl.surface);
+        window->context.egl.surface = EGL_NO_SURFACE;
+    }
+
+    if (window->context.egl.handle)
+    {
+        eglDestroyContext(_glfw.egl.display, window->context.egl.handle);
+        window->context.egl.handle = EGL_NO_CONTEXT;
+    }
+}
+
+
 //////////////////////////////////////////////////////////////////////////
 //////                       GLFW internal API                      //////
 //////////////////////////////////////////////////////////////////////////
 
 // Initialize EGL
 //
-int _glfwInitContextAPI(void)
+GLFWbool _glfwInitEGL(void)
 {
-    if (!_glfwInitTLS())
-        return GL_FALSE;
+    int i;
+    const char* sonames[] =
+    {
+#if defined(_GLFW_WIN32)
+        "libEGL.dll",
+        "EGL.dll",
+#elif defined(_GLFW_COCOA)
+        "libEGL.dylib",
+#else
+        "libEGL.so.1",
+#endif
+        NULL
+    };
 
-    _glfw.egl.display = eglGetDisplay((EGLNativeDisplayType)_GLFW_EGL_NATIVE_DISPLAY);
+    if (_glfw.egl.handle)
+        return GLFW_TRUE;
+
+    for (i = 0;  sonames[i];  i++)
+    {
+        _glfw.egl.handle = _glfw_dlopen(sonames[i]);
+        if (_glfw.egl.handle)
+            break;
+    }
+
+    if (!_glfw.egl.handle)
+    {
+        _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Library not found");
+        return GLFW_FALSE;
+    }
+
+    _glfw.egl.prefix = (strncmp(sonames[i], "lib", 3) == 0);
+
+    _glfw.egl.GetConfigAttrib = (PFNEGLGETCONFIGATTRIBPROC)
+        _glfw_dlsym(_glfw.egl.handle, "eglGetConfigAttrib");
+    _glfw.egl.GetConfigs = (PFNEGLGETCONFIGSPROC)
+        _glfw_dlsym(_glfw.egl.handle, "eglGetConfigs");
+    _glfw.egl.GetDisplay = (PFNEGLGETDISPLAYPROC)
+        _glfw_dlsym(_glfw.egl.handle, "eglGetDisplay");
+    _glfw.egl.GetError = (PFNEGLGETERRORPROC)
+        _glfw_dlsym(_glfw.egl.handle, "eglGetError");
+    _glfw.egl.Initialize = (PFNEGLINITIALIZEPROC)
+        _glfw_dlsym(_glfw.egl.handle, "eglInitialize");
+    _glfw.egl.Terminate = (PFNEGLTERMINATEPROC)
+        _glfw_dlsym(_glfw.egl.handle, "eglTerminate");
+    _glfw.egl.BindAPI = (PFNEGLBINDAPIPROC)
+        _glfw_dlsym(_glfw.egl.handle, "eglBindAPI");
+    _glfw.egl.CreateContext = (PFNEGLCREATECONTEXTPROC)
+        _glfw_dlsym(_glfw.egl.handle, "eglCreateContext");
+    _glfw.egl.DestroySurface = (PFNEGLDESTROYSURFACEPROC)
+        _glfw_dlsym(_glfw.egl.handle, "eglDestroySurface");
+    _glfw.egl.DestroyContext = (PFNEGLDESTROYCONTEXTPROC)
+        _glfw_dlsym(_glfw.egl.handle, "eglDestroyContext");
+    _glfw.egl.CreateWindowSurface = (PFNEGLCREATEWINDOWSURFACEPROC)
+        _glfw_dlsym(_glfw.egl.handle, "eglCreateWindowSurface");
+    _glfw.egl.MakeCurrent = (PFNEGLMAKECURRENTPROC)
+        _glfw_dlsym(_glfw.egl.handle, "eglMakeCurrent");
+    _glfw.egl.SwapBuffers = (PFNEGLSWAPBUFFERSPROC)
+        _glfw_dlsym(_glfw.egl.handle, "eglSwapBuffers");
+    _glfw.egl.SwapInterval = (PFNEGLSWAPINTERVALPROC)
+        _glfw_dlsym(_glfw.egl.handle, "eglSwapInterval");
+    _glfw.egl.QueryString = (PFNEGLQUERYSTRINGPROC)
+        _glfw_dlsym(_glfw.egl.handle, "eglQueryString");
+    _glfw.egl.GetProcAddress = (PFNEGLGETPROCADDRESSPROC)
+        _glfw_dlsym(_glfw.egl.handle, "eglGetProcAddress");
+
+    if (!_glfw.egl.GetConfigAttrib ||
+        !_glfw.egl.GetConfigs ||
+        !_glfw.egl.GetDisplay ||
+        !_glfw.egl.GetError ||
+        !_glfw.egl.Initialize ||
+        !_glfw.egl.Terminate ||
+        !_glfw.egl.BindAPI ||
+        !_glfw.egl.CreateContext ||
+        !_glfw.egl.DestroySurface ||
+        !_glfw.egl.DestroyContext ||
+        !_glfw.egl.CreateWindowSurface ||
+        !_glfw.egl.MakeCurrent ||
+        !_glfw.egl.SwapBuffers ||
+        !_glfw.egl.SwapInterval ||
+        !_glfw.egl.QueryString ||
+        !_glfw.egl.GetProcAddress)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "EGL: Failed to load required entry points");
+
+        _glfwTerminateEGL();
+        return GLFW_FALSE;
+    }
+
+    _glfw.egl.display = eglGetDisplay(_GLFW_EGL_NATIVE_DISPLAY);
     if (_glfw.egl.display == EGL_NO_DISPLAY)
     {
         _glfwInputError(GLFW_API_UNAVAILABLE,
                         "EGL: Failed to get EGL display: %s",
-                        getErrorString(eglGetError()));
-        return GL_FALSE;
+                        getEGLErrorString(eglGetError()));
+
+        _glfwTerminateEGL();
+        return GLFW_FALSE;
     }
 
-    if (!eglInitialize(_glfw.egl.display,
-                       &_glfw.egl.versionMajor,
-                       &_glfw.egl.versionMinor))
+    if (!eglInitialize(_glfw.egl.display, &_glfw.egl.major, &_glfw.egl.minor))
     {
         _glfwInputError(GLFW_API_UNAVAILABLE,
                         "EGL: Failed to initialize EGL: %s",
-                        getErrorString(eglGetError()));
-        return GL_FALSE;
+                        getEGLErrorString(eglGetError()));
+
+        _glfwTerminateEGL();
+        return GLFW_FALSE;
     }
 
-    if (_glfwPlatformExtensionSupported("EGL_KHR_create_context"))
-        _glfw.egl.KHR_create_context = GL_TRUE;
+    _glfw.egl.KHR_create_context =
+        extensionSupportedEGL("EGL_KHR_create_context");
+    _glfw.egl.KHR_create_context_no_error =
+        extensionSupportedEGL("EGL_KHR_create_context_no_error");
+    _glfw.egl.KHR_gl_colorspace =
+        extensionSupportedEGL("EGL_KHR_gl_colorspace");
 
-    return GL_TRUE;
+    return GLFW_TRUE;
 }
 
 // Terminate EGL
 //
-void _glfwTerminateContextAPI(void)
+void _glfwTerminateEGL(void)
 {
-    eglTerminate(_glfw.egl.display);
+    if (_glfw.egl.display)
+    {
+        eglTerminate(_glfw.egl.display);
+        _glfw.egl.display = EGL_NO_DISPLAY;
+    }
 
-    _glfwTerminateTLS();
+    if (_glfw.egl.handle)
+    {
+        _glfw_dlclose(_glfw.egl.handle);
+        _glfw.egl.handle = NULL;
+    }
 }
 
 #define setEGLattrib(attribName, attribValue) \
@@ -238,118 +429,87 @@
 
 // Create the OpenGL or OpenGL ES context
 //
-int _glfwCreateContext(_GLFWwindow* window,
-                       const _GLFWctxconfig* ctxconfig,
-                       const _GLFWfbconfig* fbconfig)
+GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
+                               const _GLFWctxconfig* ctxconfig,
+                               const _GLFWfbconfig* fbconfig)
 {
-    int attribs[40];
+    EGLint attribs[40];
     EGLConfig config;
     EGLContext share = NULL;
 
+    if (!_glfw.egl.display)
+    {
+        _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: API not available");
+        return GLFW_FALSE;
+    }
+
     if (ctxconfig->share)
-        share = ctxconfig->share->egl.context;
+        share = ctxconfig->share->context.egl.handle;
 
-    if (!chooseFBConfigs(ctxconfig, fbconfig, &config))
+    if (!chooseEGLConfig(ctxconfig, fbconfig, &config))
     {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
+        _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
                         "EGL: Failed to find a suitable EGLConfig");
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
 
-#if defined(_GLFW_X11)
-    // Retrieve the visual corresponding to the chosen EGL config
-    {
-        EGLint count = 0;
-        int mask;
-        EGLint redBits, greenBits, blueBits, alphaBits, visualID = 0;
-        XVisualInfo info;
-
-        eglGetConfigAttrib(_glfw.egl.display, config,
-                           EGL_NATIVE_VISUAL_ID, &visualID);
-
-        info.screen = _glfw.x11.screen;
-        mask = VisualScreenMask;
-
-        if (visualID)
-        {
-            // The X window visual must match the EGL config
-            info.visualid = visualID;
-            mask |= VisualIDMask;
-        }
-        else
-        {
-            // some EGL drivers don't implement the EGL_NATIVE_VISUAL_ID
-            // attribute, so attempt to find the closest match.
-
-            eglGetConfigAttrib(_glfw.egl.display, config,
-                               EGL_RED_SIZE, &redBits);
-            eglGetConfigAttrib(_glfw.egl.display, config,
-                               EGL_GREEN_SIZE, &greenBits);
-            eglGetConfigAttrib(_glfw.egl.display, config,
-                               EGL_BLUE_SIZE, &blueBits);
-            eglGetConfigAttrib(_glfw.egl.display, config,
-                               EGL_ALPHA_SIZE, &alphaBits);
-
-            info.depth = redBits + greenBits + blueBits + alphaBits;
-            mask |= VisualDepthMask;
-        }
-
-        window->egl.visual = XGetVisualInfo(_glfw.x11.display,
-                                            mask, &info, &count);
-        if (!window->egl.visual)
-        {
-            _glfwInputError(GLFW_PLATFORM_ERROR,
-                            "EGL: Failed to retrieve visual for EGLConfig");
-            return GL_FALSE;
-        }
-    }
-#endif // _GLFW_X11
-
-    if (ctxconfig->api == GLFW_OPENGL_ES_API)
+    if (ctxconfig->client == GLFW_OPENGL_ES_API)
     {
         if (!eglBindAPI(EGL_OPENGL_ES_API))
         {
-            _glfwInputError(GLFW_PLATFORM_ERROR,
+            _glfwInputError(GLFW_API_UNAVAILABLE,
                             "EGL: Failed to bind OpenGL ES: %s",
-                            getErrorString(eglGetError()));
-            return GL_FALSE;
+                            getEGLErrorString(eglGetError()));
+            return GLFW_FALSE;
         }
     }
     else
     {
         if (!eglBindAPI(EGL_OPENGL_API))
         {
-            _glfwInputError(GLFW_PLATFORM_ERROR,
+            _glfwInputError(GLFW_API_UNAVAILABLE,
                             "EGL: Failed to bind OpenGL: %s",
-                            getErrorString(eglGetError()));
-            return GL_FALSE;
+                            getEGLErrorString(eglGetError()));
+            return GLFW_FALSE;
         }
     }
 
     if (_glfw.egl.KHR_create_context)
     {
-        int index = 0, mask = 0, flags = 0, strategy = 0;
+        int index = 0, mask = 0, flags = 0;
 
-        if (ctxconfig->api == GLFW_OPENGL_API)
+        if (ctxconfig->client == GLFW_OPENGL_API)
         {
+            if (ctxconfig->forward)
+                flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
+
             if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
                 mask |= EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
             else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
                 mask |= EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR;
 
-            if (ctxconfig->forward)
-                flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
-
-            if (ctxconfig->debug)
-                flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
+            if (_glfw.egl.KHR_create_context_no_error)
+            {
+                if (ctxconfig->noerror)
+                    flags |= EGL_CONTEXT_OPENGL_NO_ERROR_KHR;
+            }
         }
 
+        if (ctxconfig->debug)
+            flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
+
         if (ctxconfig->robustness)
         {
             if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
-                strategy = EGL_NO_RESET_NOTIFICATION_KHR;
+            {
+                setEGLattrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR,
+                             EGL_NO_RESET_NOTIFICATION_KHR);
+            }
             else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
-                strategy = EGL_LOSE_CONTEXT_ON_RESET_KHR;
+            {
+                setEGLattrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR,
+                             EGL_LOSE_CONTEXT_ON_RESET_KHR);
+            }
 
             flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
         }
@@ -366,16 +526,13 @@
         if (flags)
             setEGLattrib(EGL_CONTEXT_FLAGS_KHR, flags);
 
-        if (strategy)
-            setEGLattrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, strategy);
-
         setEGLattrib(EGL_NONE, EGL_NONE);
     }
     else
     {
         int index = 0;
 
-        if (ctxconfig->api == GLFW_OPENGL_ES_API)
+        if (ctxconfig->client == GLFW_OPENGL_ES_API)
             setEGLattrib(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major);
 
         setEGLattrib(EGL_NONE, EGL_NONE);
@@ -384,127 +541,169 @@
     // Context release behaviors (GL_KHR_context_flush_control) are not yet
     // supported on EGL but are not a hard constraint, so ignore and continue
 
-    window->egl.context = eglCreateContext(_glfw.egl.display,
-                                           config, share, attribs);
+    window->context.egl.handle = eglCreateContext(_glfw.egl.display,
+                                                  config, share, attribs);
 
-    if (window->egl.context == EGL_NO_CONTEXT)
+    if (window->context.egl.handle == EGL_NO_CONTEXT)
     {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
+        _glfwInputError(GLFW_VERSION_UNAVAILABLE,
                         "EGL: Failed to create context: %s",
-                        getErrorString(eglGetError()));
-        return GL_FALSE;
+                        getEGLErrorString(eglGetError()));
+        return GLFW_FALSE;
     }
 
-    window->egl.config = config;
-
-    return GL_TRUE;
-}
+    // Set up attributes for surface creation
+    {
+        int index = 0;
 
-#undef setEGLattrib
+        if (fbconfig->sRGB)
+        {
+            if (_glfw.egl.KHR_gl_colorspace)
+            {
+                setEGLattrib(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR);
+            }
+        }
 
-// Destroy the OpenGL context
-//
-void _glfwDestroyContext(_GLFWwindow* window)
-{
-#if defined(_GLFW_X11)
-    if (window->egl.visual)
-    {
-       XFree(window->egl.visual);
-       window->egl.visual = NULL;
+        setEGLattrib(EGL_NONE, EGL_NONE);
     }
-#endif // _GLFW_X11
 
-    if (window->egl.surface)
+    window->context.egl.surface =
+        eglCreateWindowSurface(_glfw.egl.display,
+                               config,
+                               _GLFW_EGL_NATIVE_WINDOW,
+                               attribs);
+    if (window->context.egl.surface == EGL_NO_SURFACE)
     {
-        eglDestroySurface(_glfw.egl.display, window->egl.surface);
-        window->egl.surface = EGL_NO_SURFACE;
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "EGL: Failed to create window surface: %s",
+                        getEGLErrorString(eglGetError()));
+        return GLFW_FALSE;
     }
 
-    if (window->egl.context)
-    {
-        eglDestroyContext(_glfw.egl.display, window->egl.context);
-        window->egl.context = EGL_NO_CONTEXT;
-    }
-}
+    window->context.egl.config = config;
 
-// Analyzes the specified context for possible recreation
-//
-int _glfwAnalyzeContext(const _GLFWwindow* window,
-                        const _GLFWctxconfig* ctxconfig,
-                        const _GLFWfbconfig* fbconfig)
-{
+    // Load the appropriate client library
+    {
+        int i;
+        const char** sonames;
+        const char* es1sonames[] =
+        {
 #if defined(_GLFW_WIN32)
-    return _GLFW_RECREATION_NOT_NEEDED;
+            "GLESv1_CM.dll",
+            "libGLES_CM.dll",
+#elif defined(_GLFW_COCOA)
+            "libGLESv1_CM.dylib",
 #else
-    return 0;
+            "libGLESv1_CM.so.1",
+            "libGLES_CM.so.1",
 #endif
-}
-
+            NULL
+        };
+        const char* es2sonames[] =
+        {
+#if defined(_GLFW_WIN32)
+            "GLESv2.dll",
+            "libGLESv2.dll",
+#elif defined(_GLFW_COCOA)
+            "libGLESv2.dylib",
+#else
+            "libGLESv2.so.2",
+#endif
+            NULL
+        };
+        const char* glsonames[] =
+        {
+#if defined(_GLFW_WIN32)
+#elif defined(_GLFW_COCOA)
+#else
+            "libGL.so.1",
+#endif
+            NULL
+        };
 
-//////////////////////////////////////////////////////////////////////////
-//////                       GLFW platform API                      //////
-//////////////////////////////////////////////////////////////////////////
+        if (ctxconfig->client == GLFW_OPENGL_ES_API)
+        {
+            if (ctxconfig->major == 1)
+                sonames = es1sonames;
+            else
+                sonames = es2sonames;
+        }
+        else
+            sonames = glsonames;
 
-void _glfwPlatformMakeContextCurrent(_GLFWwindow* window)
-{
-    if (window)
-    {
-        if (window->egl.surface == EGL_NO_SURFACE)
+        for (i = 0;  sonames[i];  i++)
         {
-            window->egl.surface = eglCreateWindowSurface(_glfw.egl.display,
-                                                         window->egl.config,
-                                                         (EGLNativeWindowType)_GLFW_EGL_NATIVE_WINDOW,
-                                                         NULL);
-            if (window->egl.surface == EGL_NO_SURFACE)
-            {
-                _glfwInputError(GLFW_PLATFORM_ERROR,
-                                "EGL: Failed to create window surface: %s",
-                                getErrorString(eglGetError()));
-            }
+            // HACK: Match presence of lib prefix to increase chance of finding
+            //       a matching pair in the jungle that is Win32 EGL/GLES
+            if (_glfw.egl.prefix != (strncmp(sonames[i], "lib", 3) == 0))
+                continue;
+
+            window->context.egl.client = _glfw_dlopen(sonames[i]);
+            if (window->context.egl.client)
+                break;
         }
 
-        eglMakeCurrent(_glfw.egl.display,
-                       window->egl.surface,
-                       window->egl.surface,
-                       window->egl.context);
-    }
-    else
-    {
-        eglMakeCurrent(_glfw.egl.display,
-                       EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+        if (!window->context.egl.client)
+        {
+            _glfwInputError(GLFW_API_UNAVAILABLE,
+                            "EGL: Failed to load client library");
+            return GLFW_FALSE;
+        }
     }
 
-    _glfwSetCurrentContext(window);
-}
+    window->context.makeCurrent = makeContextCurrentEGL;
+    window->context.swapBuffers = swapBuffersEGL;
+    window->context.swapInterval = swapIntervalEGL;
+    window->context.extensionSupported = extensionSupportedEGL;
+    window->context.getProcAddress = getProcAddressEGL;
+    window->context.destroy = destroyContextEGL;
 
-void _glfwPlatformSwapBuffers(_GLFWwindow* window)
-{
-    eglSwapBuffers(_glfw.egl.display, window->egl.surface);
+    return GLFW_TRUE;
 }
 
-void _glfwPlatformSwapInterval(int interval)
-{
-    eglSwapInterval(_glfw.egl.display, interval);
-}
+#undef setEGLattrib
 
-int _glfwPlatformExtensionSupported(const char* extension)
+// Returns the Visual and depth of the chosen EGLConfig
+//
+#if defined(_GLFW_X11)
+GLFWbool _glfwChooseVisualEGL(const _GLFWctxconfig* ctxconfig,
+                              const _GLFWfbconfig* fbconfig,
+                              Visual** visual, int* depth)
 {
-    const char* extensions;
+    XVisualInfo* result;
+    XVisualInfo desired;
+    EGLConfig native;
+    EGLint visualID = 0, count = 0;
+    const long vimask = VisualScreenMask | VisualIDMask;
 
-    extensions = eglQueryString(_glfw.egl.display, EGL_EXTENSIONS);
-    if (extensions != NULL)
+    if (!chooseEGLConfig(ctxconfig, fbconfig, &native))
     {
-        if (_glfwStringInExtensionString(extension, (unsigned char*) extensions))
-            return GL_TRUE;
+        _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
+                        "EGL: Failed to find a suitable EGLConfig");
+        return GLFW_FALSE;
     }
 
-    return GL_FALSE;
-}
+    eglGetConfigAttrib(_glfw.egl.display, native,
+                       EGL_NATIVE_VISUAL_ID, &visualID);
 
-GLFWglproc _glfwPlatformGetProcAddress(const char* procname)
-{
-    return eglGetProcAddress(procname);
+    desired.screen = _glfw.x11.screen;
+    desired.visualid = visualID;
+
+    result = XGetVisualInfo(_glfw.x11.display, vimask, &desired, &count);
+    if (!result)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "EGL: Failed to retrieve Visual for EGLConfig");
+        return GLFW_FALSE;
+    }
+
+    *visual = result->visual;
+    *depth = result->depth;
+
+    XFree(result);
+    return GLFW_TRUE;
 }
+#endif // _GLFW_X11
 
 
 //////////////////////////////////////////////////////////////////////////
@@ -521,13 +720,27 @@
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_CONTEXT);
-    return window->egl.context;
+
+    if (window->context.client == GLFW_NO_API)
+    {
+        _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
+        return EGL_NO_CONTEXT;
+    }
+
+    return window->context.egl.handle;
 }
 
 GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* handle)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_SURFACE);
-    return window->egl.surface;
+
+    if (window->context.client == GLFW_NO_API)
+    {
+        _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
+        return EGL_NO_SURFACE;
+    }
+
+    return window->context.egl.surface;
 }
 
diff --git a/glfw/src/egl_context.h b/glfw/src/egl_context.h
--- a/glfw/src/egl_context.h
+++ b/glfw/src/egl_context.h
@@ -1,8 +1,8 @@
 //========================================================================
-// GLFW 3.1 EGL - www.glfw.org
+// GLFW 3.2 EGL - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -25,61 +25,189 @@
 //
 //========================================================================
 
-#ifndef _egl_context_h_
-#define _egl_context_h_
+#ifndef _glfw3_egl_context_h_
+#define _glfw3_egl_context_h_
 
-#include <EGL/egl.h>
+#if defined(_GLFW_USE_EGLPLATFORM_H)
+ #include <EGL/eglplatform.h>
+#elif defined(_GLFW_WIN32)
+ #define EGLAPIENTRY __stdcall
+typedef HDC EGLNativeDisplayType;
+typedef HWND EGLNativeWindowType;
+#elif defined(_GLFW_X11)
+ #define EGLAPIENTRY
+typedef Display* EGLNativeDisplayType;
+typedef Window EGLNativeWindowType;
+#elif defined(_GLFW_WAYLAND)
+ #define EGLAPIENTRY
+typedef struct wl_display* EGLNativeDisplayType;
+typedef struct wl_egl_window* EGLNativeWindowType;
+#elif defined(_GLFW_MIR)
+ #define EGLAPIENTRY
+typedef MirEGLNativeDisplayType EGLNativeDisplayType;
+typedef MirEGLNativeWindowType EGLNativeWindowType;
+#else
+ #error "No supported EGL platform selected"
+#endif
 
-// This path may need to be changed if you build GLFW using your own setup
-// We ship and use our own copy of eglext.h since GLFW uses fairly new
-// extensions and not all operating systems come with an up-to-date version
-#include "../deps/EGL/eglext.h"
+#define EGL_SUCCESS	0x3000
+#define EGL_NOT_INITIALIZED	0x3001
+#define EGL_BAD_ACCESS 0x3002
+#define EGL_BAD_ALLOC 0x3003
+#define EGL_BAD_ATTRIBUTE 0x3004
+#define EGL_BAD_CONFIG 0x3005
+#define EGL_BAD_CONTEXT	0x3006
+#define EGL_BAD_CURRENT_SURFACE	0x3007
+#define EGL_BAD_DISPLAY	0x3008
+#define EGL_BAD_MATCH 0x3009
+#define EGL_BAD_NATIVE_PIXMAP 0x300a
+#define EGL_BAD_NATIVE_WINDOW 0x300b
+#define EGL_BAD_PARAMETER 0x300c
+#define EGL_BAD_SURFACE	0x300d
+#define EGL_CONTEXT_LOST 0x300e
+#define EGL_COLOR_BUFFER_TYPE 0x303f
+#define EGL_RGB_BUFFER 0x308e
+#define EGL_SURFACE_TYPE 0x3033
+#define EGL_WINDOW_BIT 0x0004
+#define EGL_RENDERABLE_TYPE	0x3040
+#define EGL_OPENGL_ES_BIT 0x0001
+#define EGL_OPENGL_ES2_BIT 0x0004
+#define EGL_OPENGL_BIT 0x0008
+#define EGL_ALPHA_SIZE 0x3021
+#define EGL_BLUE_SIZE 0x3022
+#define EGL_GREEN_SIZE 0x3023
+#define EGL_RED_SIZE 0x3024
+#define EGL_DEPTH_SIZE 0x3025
+#define EGL_STENCIL_SIZE 0x3026
+#define EGL_SAMPLES	0x3031
+#define EGL_OPENGL_ES_API 0x30a0
+#define EGL_OPENGL_API 0x30a2
+#define EGL_NONE 0x3038
+#define EGL_EXTENSIONS 0x3055
+#define EGL_CONTEXT_CLIENT_VERSION 0x3098
+#define EGL_NATIVE_VISUAL_ID 0x302e
+#define EGL_NO_SURFACE ((EGLSurface) 0)
+#define EGL_NO_DISPLAY ((EGLDisplay) 0)
+#define EGL_NO_CONTEXT ((EGLContext) 0)
+#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType) 0)
 
-// Do we have support for dlopen/dlsym?
-#if defined(_GLFW_HAS_DLOPEN)
- #include <dlfcn.h>
-#endif
+#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002
+#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001
+#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002
+#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001
+#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31bd
+#define EGL_NO_RESET_NOTIFICATION_KHR 0x31be
+#define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31bf
+#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004
+#define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098
+#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30fb
+#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30fd
+#define EGL_CONTEXT_FLAGS_KHR 0x30fc
+#define EGL_CONTEXT_OPENGL_NO_ERROR_KHR 0x31b3
+#define EGL_GL_COLORSPACE_KHR 0x309d
+#define EGL_GL_COLORSPACE_SRGB_KHR 0x3089
 
-#define _GLFW_PLATFORM_FBCONFIG                 EGLConfig       egl
-#define _GLFW_PLATFORM_CONTEXT_STATE            _GLFWcontextEGL egl
-#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE    _GLFWlibraryEGL egl
+typedef int EGLint;
+typedef unsigned int EGLBoolean;
+typedef unsigned int EGLenum;
+typedef void* EGLConfig;
+typedef void* EGLContext;
+typedef void* EGLDisplay;
+typedef void* EGLSurface;
 
+// EGL function pointer typedefs
+typedef EGLBoolean (EGLAPIENTRY * PFNEGLGETCONFIGATTRIBPROC)(EGLDisplay,EGLConfig,EGLint,EGLint*);
+typedef EGLBoolean (EGLAPIENTRY * PFNEGLGETCONFIGSPROC)(EGLDisplay,EGLConfig*,EGLint,EGLint*);
+typedef EGLDisplay (EGLAPIENTRY * PFNEGLGETDISPLAYPROC)(EGLNativeDisplayType);
+typedef EGLint (EGLAPIENTRY * PFNEGLGETERRORPROC)(void);
+typedef EGLBoolean (EGLAPIENTRY * PFNEGLINITIALIZEPROC)(EGLDisplay,EGLint*,EGLint*);
+typedef EGLBoolean (EGLAPIENTRY * PFNEGLTERMINATEPROC)(EGLDisplay);
+typedef EGLBoolean (EGLAPIENTRY * PFNEGLBINDAPIPROC)(EGLenum);
+typedef EGLContext (EGLAPIENTRY * PFNEGLCREATECONTEXTPROC)(EGLDisplay,EGLConfig,EGLContext,const EGLint*);
+typedef EGLBoolean (EGLAPIENTRY * PFNEGLDESTROYSURFACEPROC)(EGLDisplay,EGLSurface);
+typedef EGLBoolean (EGLAPIENTRY * PFNEGLDESTROYCONTEXTPROC)(EGLDisplay,EGLContext);
+typedef EGLSurface (EGLAPIENTRY * PFNEGLCREATEWINDOWSURFACEPROC)(EGLDisplay,EGLConfig,EGLNativeWindowType,const EGLint*);
+typedef EGLBoolean (EGLAPIENTRY * PFNEGLMAKECURRENTPROC)(EGLDisplay,EGLSurface,EGLSurface,EGLContext);
+typedef EGLBoolean (EGLAPIENTRY * PFNEGLSWAPBUFFERSPROC)(EGLDisplay,EGLSurface);
+typedef EGLBoolean (EGLAPIENTRY * PFNEGLSWAPINTERVALPROC)(EGLDisplay,EGLint);
+typedef const char* (EGLAPIENTRY * PFNEGLQUERYSTRINGPROC)(EGLDisplay,EGLint);
+typedef GLFWglproc (EGLAPIENTRY * PFNEGLGETPROCADDRESSPROC)(const char*);
+#define eglGetConfigAttrib _glfw.egl.GetConfigAttrib
+#define eglGetConfigs _glfw.egl.GetConfigs
+#define eglGetDisplay _glfw.egl.GetDisplay
+#define eglGetError _glfw.egl.GetError
+#define eglInitialize _glfw.egl.Initialize
+#define eglTerminate _glfw.egl.Terminate
+#define eglBindAPI _glfw.egl.BindAPI
+#define eglCreateContext _glfw.egl.CreateContext
+#define eglDestroySurface _glfw.egl.DestroySurface
+#define eglDestroyContext _glfw.egl.DestroyContext
+#define eglCreateWindowSurface _glfw.egl.CreateWindowSurface
+#define eglMakeCurrent _glfw.egl.MakeCurrent
+#define eglSwapBuffers _glfw.egl.SwapBuffers
+#define eglSwapInterval _glfw.egl.SwapInterval
+#define eglQueryString _glfw.egl.QueryString
+#define eglGetProcAddress _glfw.egl.GetProcAddress
 
+#define _GLFW_EGL_CONTEXT_STATE            _GLFWcontextEGL egl
+#define _GLFW_EGL_LIBRARY_CONTEXT_STATE    _GLFWlibraryEGL egl
+
+
 // EGL-specific per-context data
 //
 typedef struct _GLFWcontextEGL
 {
-   EGLConfig      config;
-   EGLContext     context;
-   EGLSurface     surface;
+   EGLConfig        config;
+   EGLContext       handle;
+   EGLSurface       surface;
 
-#if defined(_GLFW_X11)
-   XVisualInfo*   visual;
-#endif
+   void*            client;
 
 } _GLFWcontextEGL;
 
-
 // EGL-specific global data
 //
 typedef struct _GLFWlibraryEGL
 {
     EGLDisplay      display;
-    EGLint          versionMajor, versionMinor;
+    EGLint          major, minor;
+    GLFWbool        prefix;
 
-    GLboolean       KHR_create_context;
+    GLFWbool        KHR_create_context;
+    GLFWbool        KHR_create_context_no_error;
+    GLFWbool        KHR_gl_colorspace;
 
+    void*           handle;
+
+    PFNEGLGETCONFIGATTRIBPROC       GetConfigAttrib;
+    PFNEGLGETCONFIGSPROC            GetConfigs;
+    PFNEGLGETDISPLAYPROC            GetDisplay;
+    PFNEGLGETERRORPROC              GetError;
+    PFNEGLINITIALIZEPROC            Initialize;
+    PFNEGLTERMINATEPROC             Terminate;
+    PFNEGLBINDAPIPROC               BindAPI;
+    PFNEGLCREATECONTEXTPROC         CreateContext;
+    PFNEGLDESTROYSURFACEPROC        DestroySurface;
+    PFNEGLDESTROYCONTEXTPROC        DestroyContext;
+    PFNEGLCREATEWINDOWSURFACEPROC   CreateWindowSurface;
+    PFNEGLMAKECURRENTPROC           MakeCurrent;
+    PFNEGLSWAPBUFFERSPROC           SwapBuffers;
+    PFNEGLSWAPINTERVALPROC          SwapInterval;
+    PFNEGLQUERYSTRINGPROC           QueryString;
+    PFNEGLGETPROCADDRESSPROC        GetProcAddress;
+
 } _GLFWlibraryEGL;
 
 
-int _glfwInitContextAPI(void);
-void _glfwTerminateContextAPI(void);
-int _glfwCreateContext(_GLFWwindow* window,
-                       const _GLFWctxconfig* ctxconfig,
-                       const _GLFWfbconfig* fbconfig);
-void _glfwDestroyContext(_GLFWwindow* window);
-int _glfwAnalyzeContext(const _GLFWwindow* window,
-                        const _GLFWctxconfig* ctxconfig,
-                        const _GLFWfbconfig* fbconfig);
+GLFWbool _glfwInitEGL(void);
+void _glfwTerminateEGL(void);
+GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
+                               const _GLFWctxconfig* ctxconfig,
+                               const _GLFWfbconfig* fbconfig);
+#if defined(_GLFW_X11)
+GLFWbool _glfwChooseVisualEGL(const _GLFWctxconfig* ctxconfig,
+                              const _GLFWfbconfig* fbconfig,
+                              Visual** visual, int* depth);
+#endif /*_GLFW_X11*/
 
-#endif // _egl_context_h_
+#endif // _glfw3_egl_context_h_
diff --git a/glfw/src/glx_context.c b/glfw/src/glx_context.c
--- a/glfw/src/glx_context.c
+++ b/glfw/src/glx_context.c
@@ -1,8 +1,8 @@
 //========================================================================
-// GLFW 3.1 GLX - www.glfw.org
+// GLFW 3.2 GLX - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -31,11 +31,6 @@
 #include <stdlib.h>
 #include <assert.h>
 
-
-// This is the only glXGetProcAddress variant not declared by glxext.h
-void (*glXGetProcAddressEXT(const GLubyte* procName))();
-
-
 #ifndef GLXBadProfileARB
  #define GLXBadProfileARB 13
 #endif
@@ -43,38 +38,36 @@
 
 // Returns the specified attribute of the specified GLXFBConfig
 //
-static int getFBConfigAttrib(GLXFBConfig fbconfig, int attrib)
+static int getGLXFBConfigAttrib(GLXFBConfig fbconfig, int attrib)
 {
     int value;
     glXGetFBConfigAttrib(_glfw.x11.display, fbconfig, attrib, &value);
     return value;
 }
 
-// Return a list of available and usable framebuffer configs
+// Return the GLXFBConfig most closely matching the specified hints
 //
-static GLboolean chooseFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* result)
+static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* result)
 {
     GLXFBConfig* nativeConfigs;
     _GLFWfbconfig* usableConfigs;
     const _GLFWfbconfig* closest;
     int i, nativeCount, usableCount;
     const char* vendor;
-    GLboolean trustWindowBit = GL_TRUE;
+    GLFWbool trustWindowBit = GLFW_TRUE;
 
+    // HACK: This is a (hopefully temporary) workaround for Chromium
+    //       (VirtualBox GL) not setting the window bit on any GLXFBConfigs
     vendor = glXGetClientString(_glfw.x11.display, GLX_VENDOR);
     if (strcmp(vendor, "Chromium") == 0)
-    {
-        // HACK: This is a (hopefully temporary) workaround for Chromium
-        //       (VirtualBox GL) not setting the window bit on any GLXFBConfigs
-        trustWindowBit = GL_FALSE;
-    }
+        trustWindowBit = GLFW_FALSE;
 
-    nativeConfigs = glXGetFBConfigs(_glfw.x11.display, _glfw.x11.screen,
-                                    &nativeCount);
+    nativeConfigs =
+        glXGetFBConfigs(_glfw.x11.display, _glfw.x11.screen, &nativeCount);
     if (!nativeCount)
     {
         _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: No GLXFBConfigs returned");
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
 
     usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig));
@@ -85,72 +78,62 @@
         const GLXFBConfig n = nativeConfigs[i];
         _GLFWfbconfig* u = usableConfigs + usableCount;
 
-        if (!getFBConfigAttrib(n, GLX_VISUAL_ID))
-        {
-            // Only consider GLXFBConfigs with associated visuals
+        // Only consider RGBA GLXFBConfigs
+        if (!(getGLXFBConfigAttrib(n, GLX_RENDER_TYPE) & GLX_RGBA_BIT))
             continue;
-        }
 
-        if (!(getFBConfigAttrib(n, GLX_RENDER_TYPE) & GLX_RGBA_BIT))
-        {
-            // Only consider RGBA GLXFBConfigs
-            continue;
-        }
-
-        if (!(getFBConfigAttrib(n, GLX_DRAWABLE_TYPE) & GLX_WINDOW_BIT))
+        // Only consider window GLXFBConfigs
+        if (!(getGLXFBConfigAttrib(n, GLX_DRAWABLE_TYPE) & GLX_WINDOW_BIT))
         {
             if (trustWindowBit)
-            {
-                // Only consider window GLXFBConfigs
                 continue;
-            }
         }
 
-        u->redBits = getFBConfigAttrib(n, GLX_RED_SIZE);
-        u->greenBits = getFBConfigAttrib(n, GLX_GREEN_SIZE);
-        u->blueBits = getFBConfigAttrib(n, GLX_BLUE_SIZE);
+        u->redBits = getGLXFBConfigAttrib(n, GLX_RED_SIZE);
+        u->greenBits = getGLXFBConfigAttrib(n, GLX_GREEN_SIZE);
+        u->blueBits = getGLXFBConfigAttrib(n, GLX_BLUE_SIZE);
 
-        u->alphaBits = getFBConfigAttrib(n, GLX_ALPHA_SIZE);
-        u->depthBits = getFBConfigAttrib(n, GLX_DEPTH_SIZE);
-        u->stencilBits = getFBConfigAttrib(n, GLX_STENCIL_SIZE);
+        u->alphaBits = getGLXFBConfigAttrib(n, GLX_ALPHA_SIZE);
+        u->depthBits = getGLXFBConfigAttrib(n, GLX_DEPTH_SIZE);
+        u->stencilBits = getGLXFBConfigAttrib(n, GLX_STENCIL_SIZE);
 
-        u->accumRedBits = getFBConfigAttrib(n, GLX_ACCUM_RED_SIZE);
-        u->accumGreenBits = getFBConfigAttrib(n, GLX_ACCUM_GREEN_SIZE);
-        u->accumBlueBits = getFBConfigAttrib(n, GLX_ACCUM_BLUE_SIZE);
-        u->accumAlphaBits = getFBConfigAttrib(n, GLX_ACCUM_ALPHA_SIZE);
+        u->accumRedBits = getGLXFBConfigAttrib(n, GLX_ACCUM_RED_SIZE);
+        u->accumGreenBits = getGLXFBConfigAttrib(n, GLX_ACCUM_GREEN_SIZE);
+        u->accumBlueBits = getGLXFBConfigAttrib(n, GLX_ACCUM_BLUE_SIZE);
+        u->accumAlphaBits = getGLXFBConfigAttrib(n, GLX_ACCUM_ALPHA_SIZE);
 
-        u->auxBuffers = getFBConfigAttrib(n, GLX_AUX_BUFFERS);
+        u->auxBuffers = getGLXFBConfigAttrib(n, GLX_AUX_BUFFERS);
 
-        if (getFBConfigAttrib(n, GLX_STEREO))
-            u->stereo = GL_TRUE;
-        if (getFBConfigAttrib(n, GLX_DOUBLEBUFFER))
-            u->doublebuffer = GL_TRUE;
+        if (getGLXFBConfigAttrib(n, GLX_STEREO))
+            u->stereo = GLFW_TRUE;
+        if (getGLXFBConfigAttrib(n, GLX_DOUBLEBUFFER))
+            u->doublebuffer = GLFW_TRUE;
 
         if (_glfw.glx.ARB_multisample)
-            u->samples = getFBConfigAttrib(n, GLX_SAMPLES);
+            u->samples = getGLXFBConfigAttrib(n, GLX_SAMPLES);
 
-        if (_glfw.glx.ARB_framebuffer_sRGB)
-            u->sRGB = getFBConfigAttrib(n, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB);
+        if (_glfw.glx.ARB_framebuffer_sRGB || _glfw.glx.EXT_framebuffer_sRGB)
+            u->sRGB = getGLXFBConfigAttrib(n, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB);
 
-        u->glx = n;
+        u->handle = (uintptr_t) n;
         usableCount++;
     }
 
     closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount);
     if (closest)
-        *result = closest->glx;
+        *result = (GLXFBConfig) closest->handle;
 
     XFree(nativeConfigs);
     free(usableConfigs);
 
-    return closest ? GL_TRUE : GL_FALSE;
+    return closest != NULL;
 }
 
 // Create the OpenGL context using legacy API
 //
-static GLXContext createLegacyContext(_GLFWwindow* window,
-                                      GLXFBConfig fbconfig,
-                                      GLXContext share)
+static GLXContext createLegacyContextGLX(_GLFWwindow* window,
+                                         GLXFBConfig fbconfig,
+                                         GLXContext share)
 {
     return glXCreateNewContext(_glfw.x11.display,
                                fbconfig,
@@ -159,122 +142,279 @@
                                True);
 }
 
+static void makeContextCurrentGLX(_GLFWwindow* window)
+{
+    if (window)
+    {
+        if (!glXMakeCurrent(_glfw.x11.display,
+                            window->context.glx.window,
+                            window->context.glx.handle))
+        {
+            _glfwInputError(GLFW_PLATFORM_ERROR,
+                            "GLX: Failed to make context current");
+            return;
+        }
+    }
+    else
+    {
+        if (!glXMakeCurrent(_glfw.x11.display, None, NULL))
+        {
+            _glfwInputError(GLFW_PLATFORM_ERROR,
+                            "GLX: Failed to clear current context");
+            return;
+        }
+    }
 
+    _glfwPlatformSetCurrentContext(window);
+}
+
+static void swapBuffersGLX(_GLFWwindow* window)
+{
+    glXSwapBuffers(_glfw.x11.display, window->context.glx.window);
+}
+
+static void swapIntervalGLX(int interval)
+{
+    _GLFWwindow* window = _glfwPlatformGetCurrentContext();
+
+    if (_glfw.glx.EXT_swap_control)
+    {
+        _glfw.glx.SwapIntervalEXT(_glfw.x11.display,
+                                  window->context.glx.window,
+                                  interval);
+    }
+    else if (_glfw.glx.MESA_swap_control)
+        _glfw.glx.SwapIntervalMESA(interval);
+    else if (_glfw.glx.SGI_swap_control)
+    {
+        if (interval > 0)
+            _glfw.glx.SwapIntervalSGI(interval);
+    }
+}
+
+static int extensionSupportedGLX(const char* extension)
+{
+    const char* extensions =
+        glXQueryExtensionsString(_glfw.x11.display, _glfw.x11.screen);
+    if (extensions)
+    {
+        if (_glfwStringInExtensionString(extension, extensions))
+            return GLFW_TRUE;
+    }
+
+    return GLFW_FALSE;
+}
+
+static GLFWglproc getProcAddressGLX(const char* procname)
+{
+    if (_glfw.glx.GetProcAddress)
+        return _glfw.glx.GetProcAddress((const GLubyte*) procname);
+    else if (_glfw.glx.GetProcAddressARB)
+        return _glfw.glx.GetProcAddressARB((const GLubyte*) procname);
+    else
+        return dlsym(_glfw.glx.handle, procname);
+}
+
+// Destroy the OpenGL context
+//
+static void destroyContextGLX(_GLFWwindow* window)
+{
+    if (window->context.glx.window)
+    {
+        glXDestroyWindow(_glfw.x11.display, window->context.glx.window);
+        window->context.glx.window = None;
+    }
+
+    if (window->context.glx.handle)
+    {
+        glXDestroyContext(_glfw.x11.display, window->context.glx.handle);
+        window->context.glx.handle = NULL;
+    }
+}
+
+
 //////////////////////////////////////////////////////////////////////////
 //////                       GLFW internal API                      //////
 //////////////////////////////////////////////////////////////////////////
 
 // Initialize GLX
 //
-int _glfwInitContextAPI(void)
+GLFWbool _glfwInitGLX(void)
 {
-    if (!_glfwInitTLS())
-        return GL_FALSE;
+    int i;
+    const char* sonames[] =
+    {
+#if defined(__CYGWIN__)
+        "libGL-1.so",
+#else
+        "libGL.so.1",
+        "libGL.so",
+#endif
+        NULL
+    };
 
-#ifdef _GLFW_DLOPEN_LIBGL
-    _glfw.glx.libGL = dlopen("libGL.so.1", RTLD_LAZY | RTLD_GLOBAL);
-    if (!_glfw.glx.libGL)
+    if (_glfw.glx.handle)
+        return GLFW_TRUE;
+
+    for (i = 0;  sonames[i];  i++)
     {
-        _glfwInputError(GLFW_PLATFORM_ERROR, "GLX: Failed to find libGL");
-        return GL_FALSE;
+        _glfw.glx.handle = dlopen(sonames[i], RTLD_LAZY | RTLD_GLOBAL);
+        if (_glfw.glx.handle)
+            break;
     }
-#endif
 
+    if (!_glfw.glx.handle)
+    {
+        _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: Failed to load GLX");
+        return GLFW_FALSE;
+    }
+
+    _glfw.glx.GetFBConfigs =
+        dlsym(_glfw.glx.handle, "glXGetFBConfigs");
+    _glfw.glx.GetFBConfigAttrib =
+        dlsym(_glfw.glx.handle, "glXGetFBConfigAttrib");
+    _glfw.glx.GetClientString =
+        dlsym(_glfw.glx.handle, "glXGetClientString");
+    _glfw.glx.QueryExtension =
+        dlsym(_glfw.glx.handle, "glXQueryExtension");
+    _glfw.glx.QueryVersion =
+        dlsym(_glfw.glx.handle, "glXQueryVersion");
+    _glfw.glx.DestroyContext =
+        dlsym(_glfw.glx.handle, "glXDestroyContext");
+    _glfw.glx.MakeCurrent =
+        dlsym(_glfw.glx.handle, "glXMakeCurrent");
+    _glfw.glx.SwapBuffers =
+        dlsym(_glfw.glx.handle, "glXSwapBuffers");
+    _glfw.glx.QueryExtensionsString =
+        dlsym(_glfw.glx.handle, "glXQueryExtensionsString");
+    _glfw.glx.CreateNewContext =
+        dlsym(_glfw.glx.handle, "glXCreateNewContext");
+    _glfw.glx.CreateWindow =
+        dlsym(_glfw.glx.handle, "glXCreateWindow");
+    _glfw.glx.DestroyWindow =
+        dlsym(_glfw.glx.handle, "glXDestroyWindow");
+    _glfw.glx.GetProcAddress =
+        dlsym(_glfw.glx.handle, "glXGetProcAddress");
+    _glfw.glx.GetProcAddressARB =
+        dlsym(_glfw.glx.handle, "glXGetProcAddressARB");
+    _glfw.glx.GetVisualFromFBConfig =
+        dlsym(_glfw.glx.handle, "glXGetVisualFromFBConfig");
+
+    if (!_glfw.glx.GetFBConfigs ||
+        !_glfw.glx.GetFBConfigAttrib ||
+        !_glfw.glx.GetClientString ||
+        !_glfw.glx.QueryExtension ||
+        !_glfw.glx.QueryVersion ||
+        !_glfw.glx.DestroyContext ||
+        !_glfw.glx.MakeCurrent ||
+        !_glfw.glx.SwapBuffers ||
+        !_glfw.glx.QueryExtensionsString ||
+        !_glfw.glx.CreateNewContext ||
+        !_glfw.glx.CreateWindow ||
+        !_glfw.glx.DestroyWindow ||
+        !_glfw.glx.GetProcAddress ||
+        !_glfw.glx.GetProcAddressARB ||
+        !_glfw.glx.GetVisualFromFBConfig)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "GLX: Failed to load required entry points");
+        return GLFW_FALSE;
+    }
+
     if (!glXQueryExtension(_glfw.x11.display,
                            &_glfw.glx.errorBase,
                            &_glfw.glx.eventBase))
     {
         _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: GLX extension not found");
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
 
-    if (!glXQueryVersion(_glfw.x11.display,
-                         &_glfw.glx.versionMajor,
-                         &_glfw.glx.versionMinor))
+    if (!glXQueryVersion(_glfw.x11.display, &_glfw.glx.major, &_glfw.glx.minor))
     {
         _glfwInputError(GLFW_API_UNAVAILABLE,
                         "GLX: Failed to query GLX version");
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
 
-    if (_glfw.glx.versionMajor == 1 && _glfw.glx.versionMinor < 3)
+    if (_glfw.glx.major == 1 && _glfw.glx.minor < 3)
     {
         _glfwInputError(GLFW_API_UNAVAILABLE,
                         "GLX: GLX version 1.3 is required");
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
 
-    if (_glfwPlatformExtensionSupported("GLX_EXT_swap_control"))
+    if (extensionSupportedGLX("GLX_EXT_swap_control"))
     {
         _glfw.glx.SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)
-            _glfwPlatformGetProcAddress("glXSwapIntervalEXT");
+            getProcAddressGLX("glXSwapIntervalEXT");
 
         if (_glfw.glx.SwapIntervalEXT)
-            _glfw.glx.EXT_swap_control = GL_TRUE;
+            _glfw.glx.EXT_swap_control = GLFW_TRUE;
     }
 
-    if (_glfwPlatformExtensionSupported("GLX_SGI_swap_control"))
+    if (extensionSupportedGLX("GLX_SGI_swap_control"))
     {
         _glfw.glx.SwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)
-            _glfwPlatformGetProcAddress("glXSwapIntervalSGI");
+            getProcAddressGLX("glXSwapIntervalSGI");
 
         if (_glfw.glx.SwapIntervalSGI)
-            _glfw.glx.SGI_swap_control = GL_TRUE;
+            _glfw.glx.SGI_swap_control = GLFW_TRUE;
     }
 
-    if (_glfwPlatformExtensionSupported("GLX_MESA_swap_control"))
+    if (extensionSupportedGLX("GLX_MESA_swap_control"))
     {
         _glfw.glx.SwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC)
-            _glfwPlatformGetProcAddress("glXSwapIntervalMESA");
+            getProcAddressGLX("glXSwapIntervalMESA");
 
         if (_glfw.glx.SwapIntervalMESA)
-            _glfw.glx.MESA_swap_control = GL_TRUE;
+            _glfw.glx.MESA_swap_control = GLFW_TRUE;
     }
 
-    if (_glfwPlatformExtensionSupported("GLX_ARB_multisample"))
-        _glfw.glx.ARB_multisample = GL_TRUE;
+    if (extensionSupportedGLX("GLX_ARB_multisample"))
+        _glfw.glx.ARB_multisample = GLFW_TRUE;
 
-    if (_glfwPlatformExtensionSupported("GLX_ARB_framebuffer_sRGB"))
-        _glfw.glx.ARB_framebuffer_sRGB = GL_TRUE;
+    if (extensionSupportedGLX("GLX_ARB_framebuffer_sRGB"))
+        _glfw.glx.ARB_framebuffer_sRGB = GLFW_TRUE;
 
-    if (_glfwPlatformExtensionSupported("GLX_ARB_create_context"))
+    if (extensionSupportedGLX("GLX_EXT_framebuffer_sRGB"))
+        _glfw.glx.EXT_framebuffer_sRGB = GLFW_TRUE;
+
+    if (extensionSupportedGLX("GLX_ARB_create_context"))
     {
         _glfw.glx.CreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)
-            _glfwPlatformGetProcAddress("glXCreateContextAttribsARB");
+            getProcAddressGLX("glXCreateContextAttribsARB");
 
         if (_glfw.glx.CreateContextAttribsARB)
-            _glfw.glx.ARB_create_context = GL_TRUE;
+            _glfw.glx.ARB_create_context = GLFW_TRUE;
     }
 
-    if (_glfwPlatformExtensionSupported("GLX_ARB_create_context_robustness"))
-        _glfw.glx.ARB_create_context_robustness = GL_TRUE;
+    if (extensionSupportedGLX("GLX_ARB_create_context_robustness"))
+        _glfw.glx.ARB_create_context_robustness = GLFW_TRUE;
 
-    if (_glfwPlatformExtensionSupported("GLX_ARB_create_context_profile"))
-        _glfw.glx.ARB_create_context_profile = GL_TRUE;
+    if (extensionSupportedGLX("GLX_ARB_create_context_profile"))
+        _glfw.glx.ARB_create_context_profile = GLFW_TRUE;
 
-    if (_glfwPlatformExtensionSupported("GLX_EXT_create_context_es2_profile"))
-        _glfw.glx.EXT_create_context_es2_profile = GL_TRUE;
+    if (extensionSupportedGLX("GLX_EXT_create_context_es2_profile"))
+        _glfw.glx.EXT_create_context_es2_profile = GLFW_TRUE;
 
-    if (_glfwPlatformExtensionSupported("GLX_ARB_context_flush_control"))
-        _glfw.glx.ARB_context_flush_control = GL_TRUE;
+    if (extensionSupportedGLX("GLX_ARB_context_flush_control"))
+        _glfw.glx.ARB_context_flush_control = GLFW_TRUE;
 
-    return GL_TRUE;
+    return GLFW_TRUE;
 }
 
 // Terminate GLX
 //
-void _glfwTerminateContextAPI(void)
+void _glfwTerminateGLX(void)
 {
-    // Unload libGL.so if necessary
-#ifdef _GLFW_DLOPEN_LIBGL
-    if (_glfw.glx.libGL != NULL)
+    // NOTE: This function must not call any X11 functions, as it is called
+    //       after XCloseDisplay (see _glfwPlatformTerminate for details)
+
+    if (_glfw.glx.handle)
     {
-        dlclose(_glfw.glx.libGL);
-        _glfw.glx.libGL = NULL;
+        dlclose(_glfw.glx.handle);
+        _glfw.glx.handle = NULL;
     }
-#endif
-
-    _glfwTerminateTLS();
 }
 
 #define setGLXattrib(attribName, attribValue) \
@@ -286,43 +426,33 @@
 
 // Create the OpenGL or OpenGL ES context
 //
-int _glfwCreateContext(_GLFWwindow* window,
-                       const _GLFWctxconfig* ctxconfig,
-                       const _GLFWfbconfig* fbconfig)
+GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
+                               const _GLFWctxconfig* ctxconfig,
+                               const _GLFWfbconfig* fbconfig)
 {
     int attribs[40];
-    GLXFBConfig native;
+    GLXFBConfig native = NULL;
     GLXContext share = NULL;
 
     if (ctxconfig->share)
-        share = ctxconfig->share->glx.context;
+        share = ctxconfig->share->context.glx.handle;
 
-    if (!chooseFBConfig(fbconfig, &native))
+    if (!chooseGLXFBConfig(fbconfig, &native))
     {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
+        _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
                         "GLX: Failed to find a suitable GLXFBConfig");
-        return GL_FALSE;
-    }
-
-    // Retrieve the corresponding visual
-    window->glx.visual = glXGetVisualFromFBConfig(_glfw.x11.display, native);
-    if (!window->glx.visual)
-    {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "GLX: Failed to retrieve visual for GLXFBConfig");
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
 
-    if (ctxconfig->api == GLFW_OPENGL_ES_API)
+    if (ctxconfig->client == GLFW_OPENGL_ES_API)
     {
         if (!_glfw.glx.ARB_create_context ||
             !_glfw.glx.ARB_create_context_profile ||
             !_glfw.glx.EXT_create_context_es2_profile)
         {
             _glfwInputError(GLFW_API_UNAVAILABLE,
-                            "GLX: OpenGL ES requested but "
-                            "GLX_EXT_create_context_es2_profile is unavailable");
-            return GL_FALSE;
+                            "GLX: OpenGL ES requested but GLX_EXT_create_context_es2_profile is unavailable");
+            return GLFW_FALSE;
         }
     }
 
@@ -331,9 +461,8 @@
         if (!_glfw.glx.ARB_create_context)
         {
             _glfwInputError(GLFW_VERSION_UNAVAILABLE,
-                            "GLX: Forward compatibility requested but "
-                            "GLX_ARB_create_context_profile is unavailable");
-            return GL_FALSE;
+                            "GLX: Forward compatibility requested but GLX_ARB_create_context_profile is unavailable");
+            return GLFW_FALSE;
         }
     }
 
@@ -343,45 +472,49 @@
             !_glfw.glx.ARB_create_context_profile)
         {
             _glfwInputError(GLFW_VERSION_UNAVAILABLE,
-                            "GLX: An OpenGL profile requested but "
-                            "GLX_ARB_create_context_profile is unavailable");
-            return GL_FALSE;
+                            "GLX: An OpenGL profile requested but GLX_ARB_create_context_profile is unavailable");
+            return GLFW_FALSE;
         }
     }
 
-    _glfwGrabXErrorHandler();
+    _glfwGrabErrorHandlerX11();
 
     if (_glfw.glx.ARB_create_context)
     {
-        int index = 0, mask = 0, flags = 0, strategy = 0;
+        int index = 0, mask = 0, flags = 0;
 
-        if (ctxconfig->api == GLFW_OPENGL_API)
+        if (ctxconfig->client == GLFW_OPENGL_API)
         {
             if (ctxconfig->forward)
                 flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
 
-            if (ctxconfig->debug)
-                flags |= GLX_CONTEXT_DEBUG_BIT_ARB;
-
-            if (ctxconfig->profile)
-            {
-                if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
-                    mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
-                else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
-                    mask |= GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
-            }
+            if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
+                mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
+            else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
+                mask |= GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
         }
         else
             mask |= GLX_CONTEXT_ES2_PROFILE_BIT_EXT;
 
+        if (ctxconfig->debug)
+            flags |= GLX_CONTEXT_DEBUG_BIT_ARB;
+        if (ctxconfig->noerror)
+            flags |= GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR;
+
         if (ctxconfig->robustness)
         {
             if (_glfw.glx.ARB_create_context_robustness)
             {
                 if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
-                    strategy = GLX_NO_RESET_NOTIFICATION_ARB;
+                {
+                    setGLXattrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
+                                 GLX_NO_RESET_NOTIFICATION_ARB);
+                }
                 else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
-                    strategy = GLX_LOSE_CONTEXT_ON_RESET_ARB;
+                {
+                    setGLXattrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
+                                 GLX_LOSE_CONTEXT_ON_RESET_ARB);
+                }
 
                 flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB;
             }
@@ -404,12 +537,11 @@
             }
         }
 
+        // NOTE: Only request an explicitly versioned context when necessary, as
+        //       explicitly requesting version 1.0 does not always return the
+        //       highest version supported by the driver
         if (ctxconfig->major != 1 || ctxconfig->minor != 0)
         {
-            // NOTE: Only request an explicitly versioned context when
-            //       necessary, as explicitly requesting version 1.0 does not
-            //       always return the highest available version
-
             setGLXattrib(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major);
             setGLXattrib(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor);
         }
@@ -420,128 +552,94 @@
         if (flags)
             setGLXattrib(GLX_CONTEXT_FLAGS_ARB, flags);
 
-        if (strategy)
-            setGLXattrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, strategy);
-
         setGLXattrib(None, None);
 
-        window->glx.context =
+        window->context.glx.handle =
             _glfw.glx.CreateContextAttribsARB(_glfw.x11.display,
                                               native,
                                               share,
                                               True,
                                               attribs);
 
-        if (!window->glx.context)
+        // HACK: This is a fallback for broken versions of the Mesa
+        //       implementation of GLX_ARB_create_context_profile that fail
+        //       default 1.0 context creation with a GLXBadProfileARB error in
+        //       violation of the extension spec
+        if (!window->context.glx.handle)
         {
-            // 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 extension spec
             if (_glfw.x11.errorCode == _glfw.glx.errorBase + GLXBadProfileARB &&
-                ctxconfig->api == GLFW_OPENGL_API &&
+                ctxconfig->client == GLFW_OPENGL_API &&
                 ctxconfig->profile == GLFW_OPENGL_ANY_PROFILE &&
-                ctxconfig->forward == GL_FALSE)
+                ctxconfig->forward == GLFW_FALSE)
             {
-                window->glx.context = createLegacyContext(window, native, share);
+                window->context.glx.handle =
+                    createLegacyContextGLX(window, native, share);
             }
         }
     }
     else
-        window->glx.context = createLegacyContext(window, native, share);
-
-    _glfwReleaseXErrorHandler();
-
-    if (!window->glx.context)
     {
-        _glfwInputXError(GLFW_PLATFORM_ERROR, "GLX: Failed to create context");
-        return GL_FALSE;
+        window->context.glx.handle =
+            createLegacyContextGLX(window, native, share);
     }
 
-    return GL_TRUE;
-}
-
-#undef setGLXattrib
+    _glfwReleaseErrorHandlerX11();
 
-// Destroy the OpenGL context
-//
-void _glfwDestroyContext(_GLFWwindow* window)
-{
-    if (window->glx.visual)
+    if (!window->context.glx.handle)
     {
-        XFree(window->glx.visual);
-        window->glx.visual = NULL;
+        _glfwInputErrorX11(GLFW_VERSION_UNAVAILABLE, "GLX: Failed to create context");
+        return GLFW_FALSE;
     }
 
-    if (window->glx.context)
+    window->context.glx.window =
+        glXCreateWindow(_glfw.x11.display, native, window->x11.handle, NULL);
+    if (!window->context.glx.window)
     {
-        glXDestroyContext(_glfw.x11.display, window->glx.context);
-        window->glx.context = NULL;
+        _glfwInputError(GLFW_PLATFORM_ERROR, "GLX: Failed to create window");
+        return GLFW_FALSE;
     }
-}
 
-
-//////////////////////////////////////////////////////////////////////////
-//////                       GLFW platform API                      //////
-//////////////////////////////////////////////////////////////////////////
-
-void _glfwPlatformMakeContextCurrent(_GLFWwindow* window)
-{
-    if (window)
-    {
-        glXMakeCurrent(_glfw.x11.display,
-                       window->x11.handle,
-                       window->glx.context);
-    }
-    else
-        glXMakeCurrent(_glfw.x11.display, None, NULL);
+    window->context.makeCurrent = makeContextCurrentGLX;
+    window->context.swapBuffers = swapBuffersGLX;
+    window->context.swapInterval = swapIntervalGLX;
+    window->context.extensionSupported = extensionSupportedGLX;
+    window->context.getProcAddress = getProcAddressGLX;
+    window->context.destroy = destroyContextGLX;
 
-    _glfwSetCurrentContext(window);
+    return GLFW_TRUE;
 }
 
-void _glfwPlatformSwapBuffers(_GLFWwindow* window)
-{
-    glXSwapBuffers(_glfw.x11.display, window->x11.handle);
-}
+#undef setGLXattrib
 
-void _glfwPlatformSwapInterval(int interval)
+// Returns the Visual and depth of the chosen GLXFBConfig
+//
+GLFWbool _glfwChooseVisualGLX(const _GLFWctxconfig* ctxconfig,
+                              const _GLFWfbconfig* fbconfig,
+                              Visual** visual, int* depth)
 {
-    _GLFWwindow* window = _glfwPlatformGetCurrentContext();
+    GLXFBConfig native;
+    XVisualInfo* result;
 
-    if (_glfw.glx.EXT_swap_control)
-    {
-        _glfw.glx.SwapIntervalEXT(_glfw.x11.display,
-                                  window->x11.handle,
-                                  interval);
-    }
-    else if (_glfw.glx.MESA_swap_control)
-        _glfw.glx.SwapIntervalMESA(interval);
-    else if (_glfw.glx.SGI_swap_control)
+    if (!chooseGLXFBConfig(fbconfig, &native))
     {
-        if (interval > 0)
-            _glfw.glx.SwapIntervalSGI(interval);
+        _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
+                        "GLX: Failed to find a suitable GLXFBConfig");
+        return GLFW_FALSE;
     }
-}
 
-int _glfwPlatformExtensionSupported(const char* extension)
-{
-    const GLubyte* extensions;
-
-    // Get list of GLX extensions
-    extensions = (const GLubyte*) glXQueryExtensionsString(_glfw.x11.display,
-                                                           _glfw.x11.screen);
-    if (extensions != NULL)
+    result = glXGetVisualFromFBConfig(_glfw.x11.display, native);
+    if (!result)
     {
-        if (_glfwStringInExtensionString(extension, extensions))
-            return GL_TRUE;
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "GLX: Failed to retrieve Visual for GLXFBConfig");
+        return GLFW_FALSE;
     }
 
-    return GL_FALSE;
-}
+    *visual = result->visual;
+    *depth = result->depth;
 
-GLFWglproc _glfwPlatformGetProcAddress(const char* procname)
-{
-    return _glfw_glXGetProcAddress((const GLubyte*) procname);
+    XFree(result);
+    return GLFW_TRUE;
 }
 
 
@@ -553,6 +651,27 @@
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
-    return window->glx.context;
+
+    if (window->context.client == GLFW_NO_API)
+    {
+        _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
+        return NULL;
+    }
+
+    return window->context.glx.handle;
+}
+
+GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* handle)
+{
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    _GLFW_REQUIRE_INIT_OR_RETURN(None);
+
+    if (window->context.client == GLFW_NO_API)
+    {
+        _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
+        return None;
+    }
+
+    return window->context.glx.window;
 }
 
diff --git a/glfw/src/glx_context.h b/glfw/src/glx_context.h
--- a/glfw/src/glx_context.h
+++ b/glfw/src/glx_context.h
@@ -1,8 +1,8 @@
 //========================================================================
-// GLFW 3.1 GLX - www.glfw.org
+// GLFW 3.2 GLX - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -25,96 +25,158 @@
 //
 //========================================================================
 
-#ifndef _glx_context_h_
-#define _glx_context_h_
+#ifndef _glfw3_glx_context_h_
+#define _glfw3_glx_context_h_
 
-#define GLX_GLXEXT_LEGACY
-#include <GL/glx.h>
+#define GLX_VENDOR 1
+#define GLX_RGBA_BIT 0x00000001
+#define GLX_WINDOW_BIT 0x00000001
+#define GLX_DRAWABLE_TYPE 0x8010
+#define GLX_RENDER_TYPE	0x8011
+#define GLX_RGBA_TYPE 0x8014
+#define GLX_DOUBLEBUFFER 5
+#define GLX_STEREO 6
+#define GLX_AUX_BUFFERS	7
+#define GLX_RED_SIZE 8
+#define GLX_GREEN_SIZE 9
+#define GLX_BLUE_SIZE 10
+#define GLX_ALPHA_SIZE 11
+#define GLX_DEPTH_SIZE 12
+#define GLX_STENCIL_SIZE 13
+#define GLX_ACCUM_RED_SIZE 14
+#define GLX_ACCUM_GREEN_SIZE 15
+#define GLX_ACCUM_BLUE_SIZE	16
+#define GLX_ACCUM_ALPHA_SIZE 17
+#define GLX_SAMPLES 0x186a1
+#define GLX_VISUAL_ID 0x800b
 
-// This path may need to be changed if you build GLFW using your own setup
-// We ship and use our own copy of glxext.h since GLFW uses fairly new
-// extensions and not all operating systems come with an up-to-date version
-#include "../deps/GL/glxext.h"
+#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20b2
+#define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001
+#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
+#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
+#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126
+#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
+#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
+#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
+#define GLX_CONTEXT_FLAGS_ARB 0x2094
+#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
+#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
+#define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252
+#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
+#define GLX_NO_RESET_NOTIFICATION_ARB 0x8261
+#define GLX_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
+#define GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0
+#define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
 
-// Do we have support for dlopen/dlsym?
-#if defined(_GLFW_HAS_DLOPEN)
- #include <dlfcn.h>
-#endif
+typedef XID GLXWindow;
+typedef XID GLXDrawable;
+typedef struct __GLXFBConfig* GLXFBConfig;
+typedef struct __GLXcontext* GLXContext;
+typedef void (*__GLXextproc)(void);
 
-// We support four different ways for getting addresses for GL/GLX
-// extension functions: glXGetProcAddress, glXGetProcAddressARB,
-// glXGetProcAddressEXT, and dlsym
-#if defined(_GLFW_HAS_GLXGETPROCADDRESSARB)
- #define _glfw_glXGetProcAddress(x) glXGetProcAddressARB(x)
-#elif defined(_GLFW_HAS_GLXGETPROCADDRESS)
- #define _glfw_glXGetProcAddress(x) glXGetProcAddress(x)
-#elif defined(_GLFW_HAS_GLXGETPROCADDRESSEXT)
- #define _glfw_glXGetProcAddress(x) glXGetProcAddressEXT(x)
-#elif defined(_GLFW_HAS_DLOPEN)
- #define _glfw_glXGetProcAddress(x) dlsym(_glfw.glx.libGL, x)
- #define _GLFW_DLOPEN_LIBGL
-#else
- #error "No OpenGL entry point retrieval mechanism was enabled"
-#endif
+typedef int (*PFNGLXGETFBCONFIGATTRIBPROC)(Display*,GLXFBConfig,int,int*);
+typedef const char* (*PFNGLXGETCLIENTSTRINGPROC)(Display*,int);
+typedef Bool (*PFNGLXQUERYEXTENSIONPROC)(Display*,int*,int*);
+typedef Bool (*PFNGLXQUERYVERSIONPROC)(Display*,int*,int*);
+typedef void (*PFNGLXDESTROYCONTEXTPROC)(Display*,GLXContext);
+typedef Bool (*PFNGLXMAKECURRENTPROC)(Display*,GLXDrawable,GLXContext);
+typedef void (*PFNGLXSWAPBUFFERSPROC)(Display*,GLXDrawable);
+typedef const char* (*PFNGLXQUERYEXTENSIONSSTRINGPROC)(Display*,int);
+typedef GLXFBConfig* (*PFNGLXGETFBCONFIGSPROC)(Display*,int,int*);
+typedef GLXContext (*PFNGLXCREATENEWCONTEXTPROC)(Display*,GLXFBConfig,int,GLXContext,Bool);
+typedef __GLXextproc (* PFNGLXGETPROCADDRESSPROC)(const GLubyte *procName);
+typedef int (*PFNGLXSWAPINTERVALMESAPROC)(int);
+typedef int (*PFNGLXSWAPINTERVALSGIPROC)(int);
+typedef void (*PFNGLXSWAPINTERVALEXTPROC)(Display*,GLXDrawable,int);
+typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSARBPROC)(Display*,GLXFBConfig,GLXContext,Bool,const int*);
+typedef XVisualInfo* (*PFNGLXGETVISUALFROMFBCONFIGPROC)(Display*,GLXFBConfig);
+typedef GLXWindow (*PFNGLXCREATEWINDOWPROC)(Display*,GLXFBConfig,Window,const int*);
+typedef void (*PFNGLXDESTROYWINDOWPROC)(Display*,GLXWindow);
 
-#define _GLFW_PLATFORM_FBCONFIG                 GLXFBConfig     glx
+// libGL.so function pointer typedefs
+#define glXGetFBConfigs _glfw.glx.GetFBConfigs
+#define glXGetFBConfigAttrib _glfw.glx.GetFBConfigAttrib
+#define glXGetClientString _glfw.glx.GetClientString
+#define glXQueryExtension _glfw.glx.QueryExtension
+#define glXQueryVersion _glfw.glx.QueryVersion
+#define glXDestroyContext _glfw.glx.DestroyContext
+#define glXMakeCurrent _glfw.glx.MakeCurrent
+#define glXSwapBuffers _glfw.glx.SwapBuffers
+#define glXQueryExtensionsString _glfw.glx.QueryExtensionsString
+#define glXCreateNewContext _glfw.glx.CreateNewContext
+#define glXGetVisualFromFBConfig _glfw.glx.GetVisualFromFBConfig
+#define glXCreateWindow _glfw.glx.CreateWindow
+#define glXDestroyWindow _glfw.glx.DestroyWindow
+
 #define _GLFW_PLATFORM_CONTEXT_STATE            _GLFWcontextGLX glx
 #define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE    _GLFWlibraryGLX glx
 
-#ifndef GLX_MESA_swap_control
-typedef int (*PFNGLXSWAPINTERVALMESAPROC)(int);
-#endif
 
-
 // GLX-specific per-context data
 //
 typedef struct _GLFWcontextGLX
 {
-    // Rendering context
-    GLXContext      context;
-    // Visual of selected GLXFBConfig
-    XVisualInfo*    visual;
+    GLXContext      handle;
+    GLXWindow       window;
 
 } _GLFWcontextGLX;
 
-
 // GLX-specific global data
 //
 typedef struct _GLFWlibraryGLX
 {
-    int             versionMajor, versionMinor;
+    int             major, minor;
     int             eventBase;
     int             errorBase;
 
-    // GLX extensions
-    PFNGLXSWAPINTERVALSGIPROC             SwapIntervalSGI;
-    PFNGLXSWAPINTERVALEXTPROC             SwapIntervalEXT;
-    PFNGLXSWAPINTERVALMESAPROC            SwapIntervalMESA;
-    PFNGLXCREATECONTEXTATTRIBSARBPROC     CreateContextAttribsARB;
-    GLboolean       SGI_swap_control;
-    GLboolean       EXT_swap_control;
-    GLboolean       MESA_swap_control;
-    GLboolean       ARB_multisample;
-    GLboolean       ARB_framebuffer_sRGB;
-    GLboolean       ARB_create_context;
-    GLboolean       ARB_create_context_profile;
-    GLboolean       ARB_create_context_robustness;
-    GLboolean       EXT_create_context_es2_profile;
-    GLboolean       ARB_context_flush_control;
+    // dlopen handle for libGL.so.1
+    void*           handle;
 
-#if defined(_GLFW_DLOPEN_LIBGL)
-    // dlopen handle for libGL.so (for glfwGetProcAddress)
-    void*           libGL;
-#endif
+    // GLX 1.3 functions
+    PFNGLXGETFBCONFIGSPROC              GetFBConfigs;
+    PFNGLXGETFBCONFIGATTRIBPROC         GetFBConfigAttrib;
+    PFNGLXGETCLIENTSTRINGPROC           GetClientString;
+    PFNGLXQUERYEXTENSIONPROC            QueryExtension;
+    PFNGLXQUERYVERSIONPROC              QueryVersion;
+    PFNGLXDESTROYCONTEXTPROC            DestroyContext;
+    PFNGLXMAKECURRENTPROC               MakeCurrent;
+    PFNGLXSWAPBUFFERSPROC               SwapBuffers;
+    PFNGLXQUERYEXTENSIONSSTRINGPROC     QueryExtensionsString;
+    PFNGLXCREATENEWCONTEXTPROC          CreateNewContext;
+    PFNGLXGETVISUALFROMFBCONFIGPROC     GetVisualFromFBConfig;
+    PFNGLXCREATEWINDOWPROC              CreateWindow;
+    PFNGLXDESTROYWINDOWPROC             DestroyWindow;
 
+    // GLX 1.4 and extension functions
+    PFNGLXGETPROCADDRESSPROC            GetProcAddress;
+    PFNGLXGETPROCADDRESSPROC            GetProcAddressARB;
+    PFNGLXSWAPINTERVALSGIPROC           SwapIntervalSGI;
+    PFNGLXSWAPINTERVALEXTPROC           SwapIntervalEXT;
+    PFNGLXSWAPINTERVALMESAPROC          SwapIntervalMESA;
+    PFNGLXCREATECONTEXTATTRIBSARBPROC   CreateContextAttribsARB;
+    GLFWbool        SGI_swap_control;
+    GLFWbool        EXT_swap_control;
+    GLFWbool        MESA_swap_control;
+    GLFWbool        ARB_multisample;
+    GLFWbool        ARB_framebuffer_sRGB;
+    GLFWbool        EXT_framebuffer_sRGB;
+    GLFWbool        ARB_create_context;
+    GLFWbool        ARB_create_context_profile;
+    GLFWbool        ARB_create_context_robustness;
+    GLFWbool        EXT_create_context_es2_profile;
+    GLFWbool        ARB_context_flush_control;
+
 } _GLFWlibraryGLX;
 
 
-int _glfwInitContextAPI(void);
-void _glfwTerminateContextAPI(void);
-int _glfwCreateContext(_GLFWwindow* window,
-                       const _GLFWctxconfig* ctxconfig,
-                       const _GLFWfbconfig* fbconfig);
-void _glfwDestroyContext(_GLFWwindow* window);
+GLFWbool _glfwInitGLX(void);
+void _glfwTerminateGLX(void);
+GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
+                               const _GLFWctxconfig* ctxconfig,
+                               const _GLFWfbconfig* fbconfig);
+void _glfwDestroyContextGLX(_GLFWwindow* window);
+GLFWbool _glfwChooseVisualGLX(const _GLFWctxconfig* ctxconfig,
+                              const _GLFWfbconfig* fbconfig,
+                              Visual** visual, int* depth);
 
-#endif // _glx_context_h_
+#endif // _glfw3_glx_context_h_
diff --git a/glfw/src/init.c b/glfw/src/init.c
--- a/glfw/src/init.c
+++ b/glfw/src/init.c
@@ -1,8 +1,8 @@
 //========================================================================
-// GLFW 3.1 - www.glfw.org
+// GLFW 3.2 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -33,13 +33,13 @@
 #include <stdarg.h>
 
 
-// The three global variables below comprise all global data in GLFW, except for
-// various static const translation tables.  Any other global variable is a bug.
+// The three global variables below comprise all global data in GLFW.
+// Any other global variable is a bug.
 
 // Global state shared between compilation units of GLFW
 // These are documented in internal.h
 //
-GLboolean _glfwInitialized = GL_FALSE;
+GLFWbool _glfwInitialized = GLFW_FALSE;
 _GLFWlibrary _glfw;
 
 // This is outside of _glfw so it can be initialized and usable before
@@ -65,16 +65,18 @@
         case GLFW_OUT_OF_MEMORY:
             return "Out of memory";
         case GLFW_API_UNAVAILABLE:
-            return "The requested client API is unavailable";
+            return "The requested API is unavailable";
         case GLFW_VERSION_UNAVAILABLE:
-            return "The requested client API version is unavailable";
+            return "The requested API version is unavailable";
         case GLFW_PLATFORM_ERROR:
             return "A platform-specific error occurred";
         case GLFW_FORMAT_UNAVAILABLE:
             return "The requested format is unavailable";
+        case GLFW_NO_WINDOW_CONTEXT:
+            return "The specified window has no context";
+        default:
+            return "ERROR: UNKNOWN GLFW ERROR";
     }
-
-    return "ERROR: UNKNOWN ERROR TOKEN PASSED TO glfwErrorString";
 }
 
 
@@ -86,7 +88,7 @@
 {
     if (_glfwErrorCallback)
     {
-        char buffer[16384];
+        char buffer[8192];
         const char* description;
 
         if (format)
@@ -118,30 +120,25 @@
 GLFWAPI int glfwInit(void)
 {
     if (_glfwInitialized)
-        return GL_TRUE;
+        return GLFW_TRUE;
 
     memset(&_glfw, 0, sizeof(_glfw));
 
     if (!_glfwPlatformInit())
     {
         _glfwPlatformTerminate();
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
 
     _glfw.monitors = _glfwPlatformGetMonitors(&_glfw.monitorCount);
-    if (!_glfw.monitorCount)
-    {
-        _glfwInputError(GLFW_PLATFORM_ERROR, "No monitors found");
-        _glfwPlatformTerminate();
-        return GL_FALSE;
-    }
+    _glfwInitialized = GLFW_TRUE;
 
-    _glfwInitialized = GL_TRUE;
+    _glfw.timerOffset = _glfwPlatformGetTimerValue();
 
     // Not all window hints have zero as their default value
     glfwDefaultWindowHints();
 
-    return GL_TRUE;
+    return GLFW_TRUE;
 }
 
 GLFWAPI void glfwTerminate(void)
@@ -166,6 +163,8 @@
             _glfwPlatformSetGammaRamp(monitor, &monitor->originalRamp);
     }
 
+    _glfwTerminateVulkan();
+
     _glfwFreeMonitors(_glfw.monitors, _glfw.monitorCount);
     _glfw.monitors = NULL;
     _glfw.monitorCount = 0;
@@ -173,7 +172,7 @@
     _glfwPlatformTerminate();
 
     memset(&_glfw, 0, sizeof(_glfw));
-    _glfwInitialized = GL_FALSE;
+    _glfwInitialized = GLFW_FALSE;
 }
 
 GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev)
diff --git a/glfw/src/input.c b/glfw/src/input.c
--- a/glfw/src/input.c
+++ b/glfw/src/input.c
@@ -1,8 +1,8 @@
 //========================================================================
-// GLFW 3.1 - www.glfw.org
+// GLFW 3.2 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -27,107 +27,14 @@
 
 #include "internal.h"
 
-#include <stdlib.h>
+#include <assert.h>
 #include <float.h>
-#if defined(_MSC_VER)
- #include <malloc.h>
-#endif
+#include <stdlib.h>
 
 // Internal key state used for sticky keys
 #define _GLFW_STICK 3
 
 
-// Sets the cursor mode for the specified window
-//
-static void setCursorMode(_GLFWwindow* window, int newMode)
-{
-    const int oldMode = window->cursorMode;
-
-    if (newMode != GLFW_CURSOR_NORMAL &&
-        newMode != GLFW_CURSOR_HIDDEN &&
-        newMode != GLFW_CURSOR_DISABLED)
-    {
-        _glfwInputError(GLFW_INVALID_ENUM, NULL);
-        return;
-    }
-
-    if (oldMode == newMode)
-        return;
-
-    window->cursorMode = newMode;
-
-    if (_glfw.focusedWindow == window)
-    {
-        if (oldMode == GLFW_CURSOR_DISABLED)
-        {
-            _glfwPlatformSetCursorPos(window,
-                                      _glfw.cursorPosX,
-                                      _glfw.cursorPosY);
-        }
-        else if (newMode == GLFW_CURSOR_DISABLED)
-        {
-            int width, height;
-
-            _glfwPlatformGetCursorPos(window,
-                                      &_glfw.cursorPosX,
-                                      &_glfw.cursorPosY);
-
-            window->cursorPosX = _glfw.cursorPosX;
-            window->cursorPosY = _glfw.cursorPosY;
-
-            _glfwPlatformGetWindowSize(window, &width, &height);
-            _glfwPlatformSetCursorPos(window, width / 2, height / 2);
-        }
-
-        _glfwPlatformApplyCursorMode(window);
-    }
-}
-
-// Set sticky keys mode for the specified window
-//
-static void setStickyKeys(_GLFWwindow* window, int enabled)
-{
-    if (window->stickyKeys == enabled)
-        return;
-
-    if (!enabled)
-    {
-        int i;
-
-        // Release all sticky keys
-        for (i = 0;  i <= GLFW_KEY_LAST;  i++)
-        {
-            if (window->keys[i] == _GLFW_STICK)
-                window->keys[i] = GLFW_RELEASE;
-        }
-    }
-
-    window->stickyKeys = enabled;
-}
-
-// Set sticky mouse buttons mode for the specified window
-//
-static void setStickyMouseButtons(_GLFWwindow* window, int enabled)
-{
-    if (window->stickyMouseButtons == enabled)
-        return;
-
-    if (!enabled)
-    {
-        int i;
-
-        // Release all sticky mouse buttons
-        for (i = 0;  i <= GLFW_MOUSE_BUTTON_LAST;  i++)
-        {
-            if (window->mouseButtons[i] == _GLFW_STICK)
-                window->mouseButtons[i] = GLFW_RELEASE;
-        }
-    }
-
-    window->stickyMouseButtons = enabled;
-}
-
-
 //////////////////////////////////////////////////////////////////////////
 //////                         GLFW event API                       //////
 //////////////////////////////////////////////////////////////////////////
@@ -136,13 +43,13 @@
 {
     if (key >= 0 && key <= GLFW_KEY_LAST)
     {
-        GLboolean repeated = GL_FALSE;
+        GLFWbool repeated = GLFW_FALSE;
 
         if (action == GLFW_RELEASE && window->keys[key] == GLFW_RELEASE)
             return;
 
         if (action == GLFW_PRESS && window->keys[key] == GLFW_PRESS)
-            repeated = GL_TRUE;
+            repeated = GLFW_TRUE;
 
         if (action == GLFW_RELEASE && window->stickyKeys)
             window->keys[key] = _GLFW_STICK;
@@ -157,7 +64,7 @@
         window->callbacks.key((GLFWwindow*) window, key, scancode, action, mods);
 }
 
-void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, int plain)
+void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, GLFWbool plain)
 {
     if (codepoint < 32 || (codepoint > 126 && codepoint < 160))
         return;
@@ -193,25 +100,19 @@
         window->callbacks.mouseButton((GLFWwindow*) window, button, action, mods);
 }
 
-void _glfwInputCursorMotion(_GLFWwindow* window, double x, double y)
+void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos)
 {
-    if (window->cursorMode == GLFW_CURSOR_DISABLED)
-    {
-        if (x == 0.0 && y == 0.0)
-            return;
-
-        window->cursorPosX += x;
-        window->cursorPosY += y;
+    if (window->virtualCursorPosX == xpos && window->virtualCursorPosY == ypos)
+        return;
 
-        x = window->cursorPosX;
-        y = window->cursorPosY;
-    }
+    window->virtualCursorPosX = xpos;
+    window->virtualCursorPosY = ypos;
 
     if (window->callbacks.cursorPos)
-        window->callbacks.cursorPos((GLFWwindow*) window, x, y);
+        window->callbacks.cursorPos((GLFWwindow*) window, xpos, ypos);
 }
 
-void _glfwInputCursorEnter(_GLFWwindow* window, int entered)
+void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered)
 {
     if (window->callbacks.cursorEnter)
         window->callbacks.cursorEnter((GLFWwindow*) window, entered);
@@ -223,14 +124,33 @@
         window->callbacks.drop((GLFWwindow*) window, count, paths);
 }
 
+void _glfwInputJoystickChange(int joy, int event)
+{
+    if (_glfw.callbacks.joystick)
+        _glfw.callbacks.joystick(joy, event);
+}
 
+
 //////////////////////////////////////////////////////////////////////////
+//////                       GLFW internal API                      //////
+//////////////////////////////////////////////////////////////////////////
+
+GLFWbool _glfwIsPrintable(int key)
+{
+    return (key >= GLFW_KEY_APOSTROPHE && key <= GLFW_KEY_WORLD_2) ||
+           (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_ADD) ||
+           key == GLFW_KEY_KP_EQUAL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
 //////                        GLFW public API                       //////
 //////////////////////////////////////////////////////////////////////////
 
 GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
 
     _GLFW_REQUIRE_INIT_OR_RETURN(0);
 
@@ -243,7 +163,7 @@
         case GLFW_STICKY_MOUSE_BUTTONS:
             return window->stickyMouseButtons;
         default:
-            _glfwInputError(GLFW_INVALID_ENUM, NULL);
+            _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode %i", mode);
             return 0;
     }
 }
@@ -251,35 +171,101 @@
 GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
 
     _GLFW_REQUIRE_INIT();
 
     switch (mode)
     {
         case GLFW_CURSOR:
-            setCursorMode(window, value);
-            break;
+        {
+            if (value != GLFW_CURSOR_NORMAL &&
+                value != GLFW_CURSOR_HIDDEN &&
+                value != GLFW_CURSOR_DISABLED)
+            {
+                _glfwInputError(GLFW_INVALID_ENUM,
+                                "Invalid cursor mode %i",
+                                value);
+                return;
+            }
+
+            if (window->cursorMode == value)
+                return;
+
+            window->cursorMode = value;
+
+            _glfwPlatformGetCursorPos(window,
+                                      &window->virtualCursorPosX,
+                                      &window->virtualCursorPosY);
+
+            if (_glfwPlatformWindowFocused(window))
+                _glfwPlatformSetCursorMode(window, value);
+
+            return;
+        }
+
         case GLFW_STICKY_KEYS:
-            setStickyKeys(window, value ? GL_TRUE : GL_FALSE);
-            break;
+        {
+            if (window->stickyKeys == value)
+                return;
+
+            if (!value)
+            {
+                int i;
+
+                // Release all sticky keys
+                for (i = 0;  i <= GLFW_KEY_LAST;  i++)
+                {
+                    if (window->keys[i] == _GLFW_STICK)
+                        window->keys[i] = GLFW_RELEASE;
+                }
+            }
+
+            window->stickyKeys = value ? GLFW_TRUE : GLFW_FALSE;
+            return;
+        }
+
         case GLFW_STICKY_MOUSE_BUTTONS:
-            setStickyMouseButtons(window, value ? GL_TRUE : GL_FALSE);
-            break;
-        default:
-            _glfwInputError(GLFW_INVALID_ENUM, NULL);
-            break;
+        {
+            if (window->stickyMouseButtons == value)
+                return;
+
+            if (!value)
+            {
+                int i;
+
+                // Release all sticky mouse buttons
+                for (i = 0;  i <= GLFW_MOUSE_BUTTON_LAST;  i++)
+                {
+                    if (window->mouseButtons[i] == _GLFW_STICK)
+                        window->mouseButtons[i] = GLFW_RELEASE;
+                }
+            }
+
+            window->stickyMouseButtons = value ? GLFW_TRUE : GLFW_FALSE;
+            return;
+        }
     }
+
+    _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode %i", mode);
 }
 
+GLFWAPI const char* glfwGetKeyName(int key, int scancode)
+{
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+    return _glfwPlatformGetKeyName(key, scancode);
+}
+
 GLFWAPI int glfwGetKey(GLFWwindow* handle, int key)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
 
     _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE);
 
-    if (key < 0 || key > GLFW_KEY_LAST)
+    if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST)
     {
-        _glfwInputError(GLFW_INVALID_ENUM, "The specified key is invalid");
+        _glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key);
         return GLFW_RELEASE;
     }
 
@@ -296,13 +282,13 @@
 GLFWAPI int glfwGetMouseButton(GLFWwindow* handle, int button)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
 
     _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE);
 
-    if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST)
+    if (button < GLFW_MOUSE_BUTTON_1 || button > GLFW_MOUSE_BUTTON_LAST)
     {
-        _glfwInputError(GLFW_INVALID_ENUM,
-                        "The specified mouse button is invalid");
+        _glfwInputError(GLFW_INVALID_ENUM, "Invalid mouse button %i", button);
         return GLFW_RELEASE;
     }
 
@@ -319,6 +305,7 @@
 GLFWAPI void glfwGetCursorPos(GLFWwindow* handle, double* xpos, double* ypos)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
 
     if (xpos)
         *xpos = 0;
@@ -330,9 +317,9 @@
     if (window->cursorMode == GLFW_CURSOR_DISABLED)
     {
         if (xpos)
-            *xpos = window->cursorPosX;
+            *xpos = window->virtualCursorPosX;
         if (ypos)
-            *ypos = window->cursorPosY;
+            *ypos = window->virtualCursorPosY;
     }
     else
         _glfwPlatformGetCursorPos(window, xpos, ypos);
@@ -341,17 +328,27 @@
 GLFWAPI void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
 
     _GLFW_REQUIRE_INIT();
 
-    if (_glfw.focusedWindow != window)
+    if (xpos != xpos || xpos < -DBL_MAX || xpos > DBL_MAX ||
+        ypos != ypos || ypos < -DBL_MAX || ypos > DBL_MAX)
+    {
+        _glfwInputError(GLFW_INVALID_VALUE,
+                        "Invalid cursor position %f %f",
+                        xpos, ypos);
         return;
+    }
 
+    if (!_glfwPlatformWindowFocused(window))
+        return;
+
     if (window->cursorMode == GLFW_CURSOR_DISABLED)
     {
         // Only update the accumulated position if the cursor is disabled
-        window->cursorPosX = xpos;
-        window->cursorPosY = ypos;
+        window->virtualCursorPosX = xpos;
+        window->virtualCursorPosY = ypos;
     }
     else
     {
@@ -364,6 +361,8 @@
 {
     _GLFWcursor* cursor;
 
+    assert(image != NULL);
+
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
 
     cursor = calloc(1, sizeof(_GLFWcursor));
@@ -385,6 +384,17 @@
 
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
 
+    if (shape != GLFW_ARROW_CURSOR &&
+        shape != GLFW_IBEAM_CURSOR &&
+        shape != GLFW_CROSSHAIR_CURSOR &&
+        shape != GLFW_HAND_CURSOR &&
+        shape != GLFW_HRESIZE_CURSOR &&
+        shape != GLFW_VRESIZE_CURSOR)
+    {
+        _glfwInputError(GLFW_INVALID_ENUM, "Invalid standard cursor %i", shape);
+        return NULL;
+    }
+
     cursor = calloc(1, sizeof(_GLFWcursor));
     cursor->next = _glfw.cursorListHead;
     _glfw.cursorListHead = cursor;
@@ -437,17 +447,20 @@
 {
     _GLFWwindow* window = (_GLFWwindow*) windowHandle;
     _GLFWcursor* cursor = (_GLFWcursor*) cursorHandle;
+    assert(window != NULL);
 
     _GLFW_REQUIRE_INIT();
 
-    _glfwPlatformSetCursor(window, cursor);
-
     window->cursor = cursor;
+
+    _glfwPlatformSetCursor(window, cursor);
 }
 
 GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP_POINTERS(window->callbacks.key, cbfun);
     return cbfun;
@@ -456,6 +469,8 @@
 GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* handle, GLFWcharfun cbfun)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP_POINTERS(window->callbacks.character, cbfun);
     return cbfun;
@@ -464,6 +479,8 @@
 GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* handle, GLFWcharmodsfun cbfun)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP_POINTERS(window->callbacks.charmods, cbfun);
     return cbfun;
@@ -473,6 +490,8 @@
                                                       GLFWmousebuttonfun cbfun)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP_POINTERS(window->callbacks.mouseButton, cbfun);
     return cbfun;
@@ -482,6 +501,8 @@
                                                   GLFWcursorposfun cbfun)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP_POINTERS(window->callbacks.cursorPos, cbfun);
     return cbfun;
@@ -491,6 +512,8 @@
                                                       GLFWcursorenterfun cbfun)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP_POINTERS(window->callbacks.cursorEnter, cbfun);
     return cbfun;
@@ -500,6 +523,8 @@
                                             GLFWscrollfun cbfun)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP_POINTERS(window->callbacks.scroll, cbfun);
     return cbfun;
@@ -508,6 +533,8 @@
 GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP_POINTERS(window->callbacks.drop, cbfun);
     return cbfun;
@@ -519,7 +546,7 @@
 
     if (joy < 0 || joy > GLFW_JOYSTICK_LAST)
     {
-        _glfwInputError(GLFW_INVALID_ENUM, NULL);
+        _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", joy);
         return 0;
     }
 
@@ -528,13 +555,14 @@
 
 GLFWAPI const float* glfwGetJoystickAxes(int joy, int* count)
 {
+    assert(count != NULL);
     *count = 0;
 
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
 
     if (joy < 0 || joy > GLFW_JOYSTICK_LAST)
     {
-        _glfwInputError(GLFW_INVALID_ENUM, NULL);
+        _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", joy);
         return NULL;
     }
 
@@ -543,13 +571,14 @@
 
 GLFWAPI const unsigned char* glfwGetJoystickButtons(int joy, int* count)
 {
+    assert(count != NULL);
     *count = 0;
 
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
 
     if (joy < 0 || joy > GLFW_JOYSTICK_LAST)
     {
-        _glfwInputError(GLFW_INVALID_ENUM, NULL);
+        _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", joy);
         return NULL;
     }
 
@@ -562,16 +591,26 @@
 
     if (joy < 0 || joy > GLFW_JOYSTICK_LAST)
     {
-        _glfwInputError(GLFW_INVALID_ENUM, NULL);
+        _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", joy);
         return NULL;
     }
 
     return _glfwPlatformGetJoystickName(joy);
 }
 
+GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun)
+{
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+    _GLFW_SWAP_POINTERS(_glfw.callbacks.joystick, cbfun);
+    return cbfun;
+}
+
 GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+    assert(string != NULL);
+
     _GLFW_REQUIRE_INIT();
     _glfwPlatformSetClipboardString(window, string);
 }
@@ -579,6 +618,8 @@
 GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     return _glfwPlatformGetClipboardString(window);
 }
@@ -586,19 +627,33 @@
 GLFWAPI double glfwGetTime(void)
 {
     _GLFW_REQUIRE_INIT_OR_RETURN(0.0);
-    return _glfwPlatformGetTime();
+    return (double) (_glfwPlatformGetTimerValue() - _glfw.timerOffset) /
+        _glfwPlatformGetTimerFrequency();
 }
 
 GLFWAPI void glfwSetTime(double time)
 {
     _GLFW_REQUIRE_INIT();
 
-    if (time != time || time - DBL_MAX == time || time < 0.0)
+    if (time != time || time < 0.0 || time > 18446744073.0)
     {
-        _glfwInputError(GLFW_INVALID_VALUE, "Invalid time");
+        _glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", time);
         return;
     }
 
-    _glfwPlatformSetTime(time);
+    _glfw.timerOffset = _glfwPlatformGetTimerValue() -
+        (uint64_t) (time * _glfwPlatformGetTimerFrequency());
+}
+
+GLFWAPI uint64_t glfwGetTimerValue(void)
+{
+    _GLFW_REQUIRE_INIT_OR_RETURN(0);
+    return _glfwPlatformGetTimerValue();
+}
+
+GLFWAPI uint64_t glfwGetTimerFrequency(void)
+{
+    _GLFW_REQUIRE_INIT_OR_RETURN(0);
+    return _glfwPlatformGetTimerFrequency();
 }
 
diff --git a/glfw/src/internal.h b/glfw/src/internal.h
--- a/glfw/src/internal.h
+++ b/glfw/src/internal.h
@@ -1,8 +1,8 @@
 //========================================================================
-// GLFW 3.1 - www.glfw.org
+// GLFW 3.2 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -25,47 +25,142 @@
 //
 //========================================================================
 
-#ifndef _internal_h_
-#define _internal_h_
+#ifndef _glfw3_internal_h_
+#define _glfw3_internal_h_
 
 
 #if defined(_GLFW_USE_CONFIG_H)
  #include "glfw_config.h"
 #endif
 
-#define _GLFW_VERSION_NUMBER "3.1.1"
-
-#if defined(_GLFW_USE_OPENGL)
- // This is the default for glfw3.h
-#elif defined(_GLFW_USE_GLESV1)
- #define GLFW_INCLUDE_ES1
-#elif defined(_GLFW_USE_GLESV2)
- #define GLFW_INCLUDE_ES2
-#else
- #error "No supported client library selected"
+#if defined(GLFW_INCLUDE_GLCOREARB) || \
+    defined(GLFW_INCLUDE_ES1)       || \
+    defined(GLFW_INCLUDE_ES2)       || \
+    defined(GLFW_INCLUDE_ES3)       || \
+    defined(GLFW_INCLUDE_NONE)      || \
+    defined(GLFW_INCLUDE_GLEXT)     || \
+    defined(GLFW_INCLUDE_GLU)       || \
+    defined(GLFW_INCLUDE_VULKAN)    || \
+    defined(GLFW_DLL)
+ #error "You must not define any header option macros when compiling GLFW"
 #endif
 
-// Disable the inclusion of the platform glext.h by gl.h to allow proper
-// inclusion of our own, newer glext.h below
-#define GL_GLEXT_LEGACY
-
+#define GLFW_INCLUDE_NONE
 #include "../include/GLFW/glfw3.h"
 
-#if defined(_GLFW_USE_OPENGL)
- // This path may need to be changed if you build GLFW using your own setup
- // GLFW comes with its own copy of glext.h since it uses fairly new extensions
- // and not all development environments come with an up-to-date version
- #include "../deps/GL/glext.h"
-#endif
+typedef int GLFWbool;
 
 typedef struct _GLFWwndconfig   _GLFWwndconfig;
 typedef struct _GLFWctxconfig   _GLFWctxconfig;
 typedef struct _GLFWfbconfig    _GLFWfbconfig;
+typedef struct _GLFWcontext     _GLFWcontext;
 typedef struct _GLFWwindow      _GLFWwindow;
 typedef struct _GLFWlibrary     _GLFWlibrary;
 typedef struct _GLFWmonitor     _GLFWmonitor;
 typedef struct _GLFWcursor      _GLFWcursor;
 
+typedef void (* _GLFWmakecontextcurrentfun)(_GLFWwindow*);
+typedef void (* _GLFWswapbuffersfun)(_GLFWwindow*);
+typedef void (* _GLFWswapintervalfun)(int);
+typedef int (* _GLFWextensionsupportedfun)(const char*);
+typedef GLFWglproc (* _GLFWgetprocaddressfun)(const char*);
+typedef void (* _GLFWdestroycontextfun)(_GLFWwindow*);
+
+#define GL_VERSION 0x1f02
+#define GL_NONE	0
+#define GL_COLOR_BUFFER_BIT	0x00004000
+#define GL_EXTENSIONS 0x1f03
+#define GL_NUM_EXTENSIONS 0x821d
+#define GL_CONTEXT_FLAGS 0x821e
+#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001
+#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
+#define GL_CONTEXT_PROFILE_MASK 0x9126
+#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
+#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001
+#define GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
+#define GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252
+#define GL_NO_RESET_NOTIFICATION_ARB 0x8261
+#define GL_CONTEXT_RELEASE_BEHAVIOR 0x82fb
+#define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82fc
+#define GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR 0x00000008
+
+typedef int	GLint;
+typedef unsigned int GLuint;
+typedef unsigned int GLenum;
+typedef unsigned int GLbitfield;
+typedef unsigned char GLubyte;
+
+typedef void (APIENTRY * PFNGLCLEARPROC)(GLbitfield);
+typedef const GLubyte* (APIENTRY * PFNGLGETSTRINGPROC)(GLenum);
+typedef void (APIENTRY * PFNGLGETINTEGERVPROC)(GLenum,GLint*);
+typedef const GLubyte* (APIENTRY * PFNGLGETSTRINGIPROC)(GLenum,GLuint);
+
+#define VK_NULL_HANDLE 0
+
+typedef void* VkInstance;
+typedef void* VkPhysicalDevice;
+typedef uint64_t VkSurfaceKHR;
+typedef uint32_t VkFlags;
+typedef uint32_t VkBool32;
+
+typedef enum VkStructureType
+{
+    VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000,
+    VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000,
+    VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000,
+    VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR = 1000007000,
+    VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000,
+    VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF
+} VkStructureType;
+
+typedef enum VkResult
+{
+    VK_SUCCESS = 0,
+    VK_NOT_READY = 1,
+    VK_TIMEOUT = 2,
+    VK_EVENT_SET = 3,
+    VK_EVENT_RESET = 4,
+    VK_INCOMPLETE = 5,
+    VK_ERROR_OUT_OF_HOST_MEMORY = -1,
+    VK_ERROR_OUT_OF_DEVICE_MEMORY = -2,
+    VK_ERROR_INITIALIZATION_FAILED = -3,
+    VK_ERROR_DEVICE_LOST = -4,
+    VK_ERROR_MEMORY_MAP_FAILED = -5,
+    VK_ERROR_LAYER_NOT_PRESENT = -6,
+    VK_ERROR_EXTENSION_NOT_PRESENT = -7,
+    VK_ERROR_FEATURE_NOT_PRESENT = -8,
+    VK_ERROR_INCOMPATIBLE_DRIVER = -9,
+    VK_ERROR_TOO_MANY_OBJECTS = -10,
+    VK_ERROR_FORMAT_NOT_SUPPORTED = -11,
+    VK_ERROR_SURFACE_LOST_KHR = -1000000000,
+    VK_SUBOPTIMAL_KHR = 1000001003,
+    VK_ERROR_OUT_OF_DATE_KHR = -1000001004,
+    VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001,
+    VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001,
+    VK_ERROR_VALIDATION_FAILED_EXT = -1000011001,
+    VK_RESULT_MAX_ENUM = 0x7FFFFFFF
+} VkResult;
+
+typedef struct VkAllocationCallbacks VkAllocationCallbacks;
+
+typedef struct VkExtensionProperties
+{
+    char            extensionName[256];
+    uint32_t        specVersion;
+} VkExtensionProperties;
+
+typedef void (APIENTRY * PFN_vkVoidFunction)(void);
+
+#if defined(_GLFW_VULKAN_STATIC)
+  PFN_vkVoidFunction vkGetInstanceProcAddr(VkInstance,const char*);
+  VkResult vkEnumerateInstanceExtensionProperties(const char*,uint32_t*,VkExtensionProperties*);
+#else
+  typedef PFN_vkVoidFunction (APIENTRY * PFN_vkGetInstanceProcAddr)(VkInstance,const char*);
+  typedef VkResult (APIENTRY * PFN_vkEnumerateInstanceExtensionProperties)(const char*,uint32_t*,VkExtensionProperties*);
+  #define vkEnumerateInstanceExtensionProperties _glfw.vk.EnumerateInstanceExtensionProperties
+  #define vkGetInstanceProcAddr _glfw.vk.GetInstanceProcAddr
+#endif
+
 #if defined(_GLFW_COCOA)
  #include "cocoa_platform.h"
 #elif defined(_GLFW_WIN32)
@@ -103,7 +198,7 @@
  *  @brief Various utility functions for internal use.
  *
  *  These functions are shared code and may be used by any part of GLFW
- *  Each platform may add its own utility functions, but those may only be
+ *  Each platform may add its own utility functions, but those must only be
  *  called by the platform-specific code
  */
 
@@ -112,6 +207,13 @@
 // Helper macros
 //========================================================================
 
+// Constructs a version number string from the public header macros
+#define _GLFW_CONCAT_VERSION(m, n, r) #m "." #n "." #r
+#define _GLFW_MAKE_VERSION(m, n, r) _GLFW_CONCAT_VERSION(m, n, r)
+#define _GLFW_VERSION_NUMBER _GLFW_MAKE_VERSION(GLFW_VERSION_MAJOR, \
+                                                GLFW_VERSION_MINOR, \
+                                                GLFW_VERSION_REVISION)
+
 // Checks for whether the library has been initialized
 #define _GLFW_REQUIRE_INIT()                         \
     if (!_glfwInitialized)                           \
@@ -151,16 +253,15 @@
     int           width;
     int           height;
     const char*   title;
-    GLboolean     resizable;
-    GLboolean     visible;
-    GLboolean     decorated;
-    GLboolean     focused;
-    GLboolean     autoIconify;
-    GLboolean     floating;
-    _GLFWmonitor* monitor;
+    GLFWbool      resizable;
+    GLFWbool      visible;
+    GLFWbool      decorated;
+    GLFWbool      focused;
+    GLFWbool      autoIconify;
+    GLFWbool      floating;
+    GLFWbool      maximized;
 };
 
-
 /*! @brief Context configuration.
  *
  *  Parameters relating to the creation of the context but not directly related
@@ -169,18 +270,19 @@
  */
 struct _GLFWctxconfig
 {
-    int           api;
+    int           client;
+    int           source;
     int           major;
     int           minor;
-    GLboolean     forward;
-    GLboolean     debug;
+    GLFWbool      forward;
+    GLFWbool      debug;
+    GLFWbool      noerror;
     int           profile;
     int           robustness;
     int           release;
     _GLFWwindow*  share;
 };
 
-
 /*! @brief Framebuffer configuration.
  *
  *  This describes buffers and their sizes.  It also contains
@@ -202,16 +304,42 @@
     int         accumBlueBits;
     int         accumAlphaBits;
     int         auxBuffers;
-    int         stereo;
+    GLFWbool    stereo;
     int         samples;
-    int         sRGB;
-    int         doublebuffer;
+    GLFWbool    sRGB;
+    GLFWbool    doublebuffer;
+    uintptr_t   handle;
+};
 
+/*! @brief Context structure.
+ */
+struct _GLFWcontext
+{
+    int                 client;
+    int                 source;
+    int                 major, minor, revision;
+    GLFWbool            forward, debug, noerror;
+    int                 profile;
+    int                 robustness;
+    int                 release;
+
+    PFNGLGETSTRINGIPROC GetStringi;
+    PFNGLGETINTEGERVPROC GetIntegerv;
+    PFNGLGETSTRINGPROC  GetString;
+
+    _GLFWmakecontextcurrentfun  makeCurrent;
+    _GLFWswapbuffersfun         swapBuffers;
+    _GLFWswapintervalfun        swapInterval;
+    _GLFWextensionsupportedfun  extensionSupported;
+    _GLFWgetprocaddressfun      getProcAddress;
+    _GLFWdestroycontextfun      destroy;
+
     // This is defined in the context API's context.h
-    _GLFW_PLATFORM_FBCONFIG;
+    _GLFW_PLATFORM_CONTEXT_STATE;
+    // This is defined in egl_context.h
+    _GLFW_EGL_CONTEXT_STATE;
 };
 
-
 /*! @brief Window and context structure.
  */
 struct _GLFWwindow
@@ -219,37 +347,29 @@
     struct _GLFWwindow* next;
 
     // Window settings and state
-    GLboolean           resizable;
-    GLboolean           decorated;
-    GLboolean           autoIconify;
-    GLboolean           floating;
-    GLboolean           closed;
+    GLFWbool            resizable;
+    GLFWbool            decorated;
+    GLFWbool            autoIconify;
+    GLFWbool            floating;
+    GLFWbool            closed;
     void*               userPointer;
     GLFWvidmode         videoMode;
     _GLFWmonitor*       monitor;
     _GLFWcursor*        cursor;
 
-    // Window input state
-    GLboolean           stickyKeys;
-    GLboolean           stickyMouseButtons;
-    double              cursorPosX, cursorPosY;
+    int                 minwidth, minheight;
+    int                 maxwidth, maxheight;
+    int                 numer, denom;
+
+    GLFWbool            stickyKeys;
+    GLFWbool            stickyMouseButtons;
     int                 cursorMode;
     char                mouseButtons[GLFW_MOUSE_BUTTON_LAST + 1];
     char                keys[GLFW_KEY_LAST + 1];
-
-    // OpenGL extensions and context attributes
-    struct {
-        int             api;
-        int             major, minor, revision;
-        GLboolean       forward, debug;
-        int             profile;
-        int             robustness;
-        int             release;
-    } context;
+    // Virtual cursor position when cursor is disabled
+    double              virtualCursorPosX, virtualCursorPosY;
 
-#if defined(_GLFW_USE_OPENGL)
-    PFNGLGETSTRINGIPROC GetStringi;
-#endif
+    _GLFWcontext        context;
 
     struct {
         GLFWwindowposfun        pos;
@@ -271,11 +391,8 @@
 
     // This is defined in the window API's platform.h
     _GLFW_PLATFORM_WINDOW_STATE;
-    // This is defined in the context API's context.h
-    _GLFW_PLATFORM_CONTEXT_STATE;
 };
 
-
 /*! @brief Monitor structure.
  */
 struct _GLFWmonitor
@@ -285,6 +402,9 @@
     // Physical dimensions in millimeters.
     int             widthMM, heightMM;
 
+    // The window whose video mode is current on this monitor
+    _GLFWwindow*    window;
+
     GLFWvidmode*    modes;
     int             modeCount;
     GLFWvidmode     currentMode;
@@ -296,7 +416,6 @@
     _GLFW_PLATFORM_MONITOR_STATE;
 };
 
-
 /*! @brief Cursor structure
  */
 struct _GLFWcursor
@@ -312,50 +431,41 @@
 struct _GLFWlibrary
 {
     struct {
-        int         redBits;
-        int         greenBits;
-        int         blueBits;
-        int         alphaBits;
-        int         depthBits;
-        int         stencilBits;
-        int         accumRedBits;
-        int         accumGreenBits;
-        int         accumBlueBits;
-        int         accumAlphaBits;
-        int         auxBuffers;
-        int         stereo;
-        int         resizable;
-        int         visible;
-        int         decorated;
-        int         focused;
-        int         autoIconify;
-        int         floating;
-        int         samples;
-        int         sRGB;
-        int         refreshRate;
-        int         doublebuffer;
-        int         api;
-        int         major;
-        int         minor;
-        int         forward;
-        int         debug;
-        int         profile;
-        int         robustness;
-        int         release;
+        _GLFWfbconfig   framebuffer;
+        _GLFWwndconfig  window;
+        _GLFWctxconfig  context;
+        int             refreshRate;
     } hints;
 
-    double          cursorPosX, cursorPosY;
+    _GLFWcursor*        cursorListHead;
 
-    _GLFWcursor*    cursorListHead;
+    _GLFWwindow*        windowListHead;
 
-    _GLFWwindow*    windowListHead;
-    _GLFWwindow*    focusedWindow;
+    _GLFWmonitor**      monitors;
+    int                 monitorCount;
 
-    _GLFWmonitor**  monitors;
-    int             monitorCount;
+    uint64_t            timerOffset;
 
     struct {
+        GLFWbool        available;
+        void*           handle;
+        char**          extensions;
+        uint32_t        extensionCount;
+#if !defined(_GLFW_VULKAN_STATIC)
+        PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties;
+        PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
+#endif
+        GLFWbool        KHR_surface;
+        GLFWbool        KHR_win32_surface;
+        GLFWbool        KHR_xlib_surface;
+        GLFWbool        KHR_xcb_surface;
+        GLFWbool        KHR_wayland_surface;
+        GLFWbool        KHR_mir_surface;
+    } vk;
+
+    struct {
         GLFWmonitorfun  monitor;
+        GLFWjoystickfun joystick;
     } callbacks;
 
     // This is defined in the window API's platform.h
@@ -368,6 +478,8 @@
     _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE;
     // This is defined in the platform's tls.h
     _GLFW_PLATFORM_LIBRARY_TLS_STATE;
+    // This is defined in egl_context.h
+    _GLFW_EGL_LIBRARY_CONTEXT_STATE;
 };
 
 
@@ -377,7 +489,7 @@
 
 /*! @brief Flag indicating whether GLFW has been successfully initialized.
  */
-extern GLboolean _glfwInitialized;
+extern GLFWbool _glfwInitialized;
 
 /*! @brief All global data protected by @ref _glfwInitialized.
  *  This should only be touched after a call to @ref glfwInit that has not been
@@ -391,7 +503,7 @@
 //========================================================================
 
 /*! @brief Initializes the platform-specific part of the library.
- *  @return `GL_TRUE` if successful, or `GL_FALSE` if an error occurred.
+ *  @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an error occurred.
  *  @ingroup platform
  */
 int _glfwPlatformInit(void);
@@ -420,12 +532,17 @@
  */
 void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos);
 
-/*! @brief Applies the cursor mode of the specified window to the system.
- *  @param[in] window The window whose cursor mode to apply.
+/*! @brief Sets the specified cursor mode of the specified window.
+ *  @param[in] window The window whose cursor mode to set.
  *  @ingroup platform
  */
-void _glfwPlatformApplyCursorMode(_GLFWwindow* window);
+void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode);
 
+/*! @copydoc glfwGetKeyName
+ *  @ingroup platform
+ */
+const char* _glfwPlatformGetKeyName(int key, int scancode);
+
 /*! @copydoc glfwGetMonitors
  *  @ingroup platform
  */
@@ -435,11 +552,11 @@
  *
  *  @param[in] first The first monitor.
  *  @param[in] second The second monitor.
- *  @return @c GL_TRUE if the monitor objects represent the same monitor, or @c
- *  GL_FALSE otherwise.
+ *  @return @c GLFW_TRUE if the monitor objects represent the same monitor, or
+ *  @c GLFW_FALSE otherwise.
  *  @ingroup platform
  */
-GLboolean _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second);
+GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second);
 
 /*! @copydoc glfwGetMonitorPos
  *  @ingroup platform
@@ -498,15 +615,15 @@
  */
 const char* _glfwPlatformGetJoystickName(int joy);
 
-/*! @copydoc glfwGetTime
+/*! @copydoc glfwGetTimerValue
  *  @ingroup platform
  */
-double _glfwPlatformGetTime(void);
+uint64_t _glfwPlatformGetTimerValue(void);
 
-/*! @copydoc glfwSetTime
+/*! @copydoc glfwGetTimerFrequency
  *  @ingroup platform
  */
-void _glfwPlatformSetTime(double time);
+uint64_t _glfwPlatformGetTimerFrequency(void);
 
 /*! @ingroup platform
  */
@@ -524,6 +641,11 @@
  */
 void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title);
 
+/*! @copydoc glfwSetWindowIcon
+ *  @ingroup platform
+ */
+void _glfwPlatformSetWindowIcon(_GLFWwindow* window, int count, const GLFWimage* images);
+
 /*! @copydoc glfwGetWindowPos
  *  @ingroup platform
  */
@@ -544,6 +666,16 @@
  */
 void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height);
 
+/*! @copydoc glfwSetWindowSizeLimits
+ *  @ingroup platform
+ */
+void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight);
+
+/*! @copydoc glfwSetWindowAspectRatio
+ *  @ingroup platform
+ */
+void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom);
+
 /*! @copydoc glfwGetFramebufferSize
  *  @ingroup platform
  */
@@ -564,20 +696,31 @@
  */
 void _glfwPlatformRestoreWindow(_GLFWwindow* window);
 
-/*! @copydoc glfwShowWindow
+/*! @copydoc glfwMaximizeWindow
  *  @ingroup platform
  */
-void _glfwPlatformShowWindow(_GLFWwindow* window);
+void _glfwPlatformMaximizeWindow(_GLFWwindow* window);
 
-/*! @ingroup platform
+/*! @copydoc glfwShowWindow
+ *  @ingroup platform
  */
-void _glfwPlatformUnhideWindow(_GLFWwindow* window);
+void _glfwPlatformShowWindow(_GLFWwindow* window);
 
 /*! @copydoc glfwHideWindow
  *  @ingroup platform
  */
 void _glfwPlatformHideWindow(_GLFWwindow* window);
 
+/*! @copydoc glfwFocusWindow
+ *  @ingroup platform
+ */
+void _glfwPlatformFocusWindow(_GLFWwindow* window);
+
+/*! @copydoc glfwSetWindowMonitor
+ *  @ingroup platform
+ */
+void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate);
+
 /*! @brief Returns whether the window is focused.
  *  @ingroup platform
  */
@@ -593,6 +736,11 @@
  */
 int _glfwPlatformWindowVisible(_GLFWwindow* window);
 
+/*! @brief Returns whether the window is maximized.
+ *  @ingroup platform
+ */
+int _glfwPlatformWindowMaximized(_GLFWwindow* window);
+
 /*! @copydoc glfwPollEvents
  *  @ingroup platform
  */
@@ -603,41 +751,25 @@
  */
 void _glfwPlatformWaitEvents(void);
 
+/*! @copydoc glfwWaitEventsTimeout
+ *  @ingroup platform
+ */
+void _glfwPlatformWaitEventsTimeout(double timeout);
+
 /*! @copydoc glfwPostEmptyEvent
  *  @ingroup platform
  */
 void _glfwPlatformPostEmptyEvent(void);
 
-/*! @copydoc glfwMakeContextCurrent
- *  @ingroup platform
+/*! @ingroup platform
  */
-void _glfwPlatformMakeContextCurrent(_GLFWwindow* window);
+void _glfwPlatformSetCurrentContext(_GLFWwindow* context);
 
 /*! @copydoc glfwGetCurrentContext
  *  @ingroup platform
  */
 _GLFWwindow* _glfwPlatformGetCurrentContext(void);
 
-/*! @copydoc glfwSwapBuffers
- *  @ingroup platform
- */
-void _glfwPlatformSwapBuffers(_GLFWwindow* window);
-
-/*! @copydoc glfwSwapInterval
- *  @ingroup platform
- */
-void _glfwPlatformSwapInterval(int interval);
-
-/*! @copydoc glfwExtensionSupported
- *  @ingroup platform
- */
-int _glfwPlatformExtensionSupported(const char* extension);
-
-/*! @copydoc glfwGetProcAddress
- *  @ingroup platform
- */
-GLFWglproc _glfwPlatformGetProcAddress(const char* procname);
-
 /*! @copydoc glfwCreateCursor
  *  @ingroup platform
  */
@@ -658,18 +790,30 @@
  */
 void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor);
 
+/*! @ingroup platform
+ */
+char** _glfwPlatformGetRequiredInstanceExtensions(uint32_t* count);
 
+/*! @ingroup platform
+ */
+int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily);
+
+/*! @ingroup platform
+ */
+VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface);
+
+
 //========================================================================
 // Event API functions
 //========================================================================
 
 /*! @brief Notifies shared code of a window focus event.
  *  @param[in] window The window that received the event.
- *  @param[in] focused `GL_TRUE` if the window received focus, or `GL_FALSE`
+ *  @param[in] focused `GLFW_TRUE` if the window received focus, or `GLFW_FALSE`
  *  if it lost focus.
  *  @ingroup event
  */
-void _glfwInputWindowFocus(_GLFWwindow* window, GLboolean focused);
+void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused);
 
 /*! @brief Notifies shared code of a window movement event.
  *  @param[in] window The window that received the event.
@@ -697,11 +841,11 @@
 
 /*! @brief Notifies shared code of a window iconification event.
  *  @param[in] window The window that received the event.
- *  @param[in] iconified `GL_TRUE` if the window was iconified, or `GL_FALSE`
- *  if it was restored.
+ *  @param[in] iconified `GLFW_TRUE` if the window was iconified, or
+ *  `GLFW_FALSE` if it was restored.
  *  @ingroup event
  */
-void _glfwInputWindowIconify(_GLFWwindow* window, int iconified);
+void _glfwInputWindowIconify(_GLFWwindow* window, GLFWbool iconified);
 
 /*! @brief Notifies shared code of a window damage event.
  *  @param[in] window The window that received the event.
@@ -714,6 +858,8 @@
  */
 void _glfwInputWindowCloseRequest(_GLFWwindow* window);
 
+void _glfwInputWindowMonitorChange(_GLFWwindow* window, _GLFWmonitor* monitor);
+
 /*! @brief Notifies shared code of a physical key event.
  *  @param[in] window The window that received the event.
  *  @param[in] key The key that was pressed or released.
@@ -728,19 +874,19 @@
  *  @param[in] window The window that received the event.
  *  @param[in] codepoint The Unicode code point of the input character.
  *  @param[in] mods Bit field describing which modifier keys were held down.
- *  @param[in] plain `GL_TRUE` if the character is regular text input, or
- *  `GL_FALSE` otherwise.
+ *  @param[in] plain `GLFW_TRUE` if the character is regular text input, or
+ *  `GLFW_FALSE` otherwise.
  *  @ingroup event
  */
-void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, int plain);
+void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, GLFWbool plain);
 
 /*! @brief Notifies shared code of a scroll event.
  *  @param[in] window The window that received the event.
- *  @param[in] x The scroll offset along the x-axis.
- *  @param[in] y The scroll offset along the y-axis.
+ *  @param[in] xoffset The scroll offset along the x-axis.
+ *  @param[in] yoffset The scroll offset along the y-axis.
  *  @ingroup event
  */
-void _glfwInputScroll(_GLFWwindow* window, double x, double y);
+void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset);
 
 /*! @brief Notifies shared code of a mouse button click event.
  *  @param[in] window The window that received the event.
@@ -752,33 +898,41 @@
 
 /*! @brief Notifies shared code of a cursor motion event.
  *  @param[in] window The window that received the event.
- *  @param[in] x The new x-coordinate of the cursor, relative to the left edge
- *  of the client area of the window.
- *  @param[in] y The new y-coordinate of the cursor, relative to the top edge
+ *  @param[in] xpos The new x-coordinate of the cursor, relative to the left
+ *  edge of the client area of the window.
+ *  @param[in] ypos The new y-coordinate of the cursor, relative to the top edge
  *  of the client area of the window.
  *  @ingroup event
  */
-void _glfwInputCursorMotion(_GLFWwindow* window, double x, double y);
+void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos);
 
 /*! @brief Notifies shared code of a cursor enter/leave event.
  *  @param[in] window The window that received the event.
- *  @param[in] entered `GL_TRUE` if the cursor entered the client area of the
- *  window, or `GL_FALSE` if it left it.
+ *  @param[in] entered `GLFW_TRUE` if the cursor entered the client area of the
+ *  window, or `GLFW_FALSE` if it left it.
  *  @ingroup event
  */
-void _glfwInputCursorEnter(_GLFWwindow* window, int entered);
+void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered);
 
 /*! @ingroup event
  */
 void _glfwInputMonitorChange(void);
 
+/*! @ingroup event
+ */
+void _glfwInputMonitorWindowChange(_GLFWmonitor* monitor, _GLFWwindow* window);
+
 /*! @brief Notifies shared code of an error.
  *  @param[in] error The error code most suitable for the error.
  *  @param[in] format The `printf` style format string of the error
  *  description.
  *  @ingroup event
  */
+#if defined(__GNUC__)
+void _glfwInputError(int error, const char* format, ...) __attribute__((format(printf, 2, 3)));
+#else
 void _glfwInputError(int error, const char* format, ...);
+#endif
 
 /*! @brief Notifies dropped object over window.
  *  @param[in] window The window that received the event.
@@ -788,7 +942,14 @@
  */
 void _glfwInputDrop(_GLFWwindow* window, int count, const char** names);
 
+/*! @brief Notifies shared code of a joystick connection/disconnection event.
+ *  @param[in] joy The joystick that was connected or disconnected.
+ *  @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`.
+ *  @ingroup event
+ */
+void _glfwInputJoystickChange(int joy, int event);
 
+
 //========================================================================
 // Utility functions
 //========================================================================
@@ -811,10 +972,10 @@
 /*! @brief Searches an extension string for the specified extension.
  *  @param[in] string The extension string to search.
  *  @param[in] extensions The extension to search for.
- *  @return `GL_TRUE` if the extension was found, or `GL_FALSE` otherwise.
+ *  @return `GLFW_TRUE` if the extension was found, or `GLFW_FALSE` otherwise.
  *  @ingroup utility
  */
-int _glfwStringInExtensionString(const char* string, const GLubyte* extensions);
+GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions);
 
 /*! @brief Chooses the framebuffer config that best matches the desired one.
  *  @param[in] desired The desired framebuffer config.
@@ -830,14 +991,15 @@
 
 /*! @brief Retrieves the attributes of the current context.
  *  @param[in] ctxconfig The desired context attributes.
- *  @return `GL_TRUE` if successful, or `GL_FALSE` if the context is unusable.
+ *  @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if the context is
+ *  unusable.
  *  @ingroup utility
  */
-GLboolean _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig);
+GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig);
 
 /*! @brief Checks whether the desired context attributes are valid.
  *  @param[in] ctxconfig The context attributes to check.
- *  @return `GL_TRUE` if the context attributes are valid, or `GL_FALSE`
+ *  @return `GLFW_TRUE` if the context attributes are valid, or `GLFW_FALSE`
  *  otherwise.
  *  @ingroup utility
  *
@@ -845,16 +1007,7 @@
  *  exists and whether all relevant options have supported and non-conflicting
  *  values.
  */
-GLboolean _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig);
-
-/*! @brief Checks whether the current context fulfils the specified hard
- *  constraints.
- *  @param[in] ctxconfig The desired context attributes.
- *  @return `GL_TRUE` if the context fulfils the hard constraints, or `GL_FALSE`
- *  otherwise.
- *  @ingroup utility
- */
-GLboolean _glfwIsValidContext(const _GLFWctxconfig* ctxconfig);
+GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig);
 
 /*! @ingroup utility
  */
@@ -883,4 +1036,20 @@
   */
 void _glfwFreeMonitors(_GLFWmonitor** monitors, int count);
 
-#endif // _internal_h_
+/*! @ingroup utility
+ */
+GLFWbool _glfwIsPrintable(int key);
+
+/*! @ingroup utility
+ */
+GLFWbool _glfwInitVulkan(void);
+
+/*! @ingroup utility
+ */
+void _glfwTerminateVulkan(void);
+
+/*! @ingroup utility
+ */
+const char* _glfwGetVulkanResultString(VkResult result);
+
+#endif // _glfw3_internal_h_
diff --git a/glfw/src/iokit_joystick.h b/glfw/src/iokit_joystick.h
deleted file mode 100644
--- a/glfw/src/iokit_joystick.h
+++ /dev/null
@@ -1,61 +0,0 @@
-//========================================================================
-// GLFW 3.1 IOKit - www.glfw.org
-//------------------------------------------------------------------------
-// Copyright (c) 2006-2014 Camilla Berglund <elmindreda@elmindreda.org>
-//
-// 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.
-//
-//========================================================================
-
-#ifndef _iokit_joystick_h_
-#define _iokit_joystick_h_
-
-#include <IOKit/IOKitLib.h>
-#include <IOKit/IOCFPlugIn.h>
-#include <IOKit/hid/IOHIDLib.h>
-#include <IOKit/hid/IOHIDKeys.h>
-
-#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE \
-    _GLFWjoystickIOKit iokit_js[GLFW_JOYSTICK_LAST + 1]
-
-
-// IOKit-specific per-joystick data
-//
-typedef struct _GLFWjoystickIOKit
-{
-    int             present;
-    char            name[256];
-
-    IOHIDDeviceInterface** interface;
-
-    CFMutableArrayRef axisElements;
-    CFMutableArrayRef buttonElements;
-    CFMutableArrayRef hatElements;
-
-    float*          axes;
-    unsigned char*  buttons;
-
-} _GLFWjoystickIOKit;
-
-
-void _glfwInitJoysticks(void);
-void _glfwTerminateJoysticks(void);
-
-#endif // _iokit_joystick_h_
diff --git a/glfw/src/iokit_joystick.m b/glfw/src/iokit_joystick.m
deleted file mode 100644
--- a/glfw/src/iokit_joystick.m
+++ /dev/null
@@ -1,506 +0,0 @@
-//========================================================================
-// GLFW 3.1 IOKit - www.glfw.org
-//------------------------------------------------------------------------
-// Copyright (c) 2009-2010 Camilla Berglund <elmindreda@elmindreda.org>
-// Copyright (c) 2012 Torsten Walluhn <tw@mad-cad.net>
-//
-// 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 <unistd.h>
-#include <ctype.h>
-
-#include <mach/mach.h>
-#include <mach/mach_error.h>
-
-#include <CoreFoundation/CoreFoundation.h>
-#include <Kernel/IOKit/hidsystem/IOHIDUsageTables.h>
-
-
-//------------------------------------------------------------------------
-// Joystick element information
-//------------------------------------------------------------------------
-typedef struct
-{
-    IOHIDElementCookie cookie;
-
-    long min;
-    long max;
-
-    long minReport;
-    long maxReport;
-
-} _GLFWjoyelement;
-
-
-static void getElementsCFArrayHandler(const void* value, void* parameter);
-
-
-// Adds an element to the specified joystick
-//
-static void addJoystickElement(_GLFWjoystickIOKit* joystick, CFTypeRef elementRef)
-{
-    long elementType, usagePage, usage;
-    CFMutableArrayRef elementsArray = NULL;
-
-    CFNumberGetValue(CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementTypeKey)),
-                     kCFNumberLongType, &elementType);
-    CFNumberGetValue(CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementUsagePageKey)),
-                     kCFNumberLongType, &usagePage);
-    CFNumberGetValue(CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementUsageKey)),
-                     kCFNumberLongType, &usage);
-
-    if ((elementType == kIOHIDElementTypeInput_Axis) ||
-        (elementType == kIOHIDElementTypeInput_Button) ||
-        (elementType == kIOHIDElementTypeInput_Misc))
-    {
-        switch (usagePage)
-        {
-            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:
-                        elementsArray = joystick->axisElements;
-                        break;
-                    case kHIDUsage_GD_Hatswitch:
-                        elementsArray = joystick->hatElements;
-                        break;
-                }
-
-                break;
-            }
-
-            case kHIDPage_Button:
-                elementsArray = joystick->buttonElements;
-                break;
-            default:
-                break;
-        }
-
-        if (elementsArray)
-        {
-            long number;
-            CFTypeRef numberRef;
-            _GLFWjoyelement* element = calloc(1, sizeof(_GLFWjoyelement));
-
-            CFArrayAppendValue(elementsArray, element);
-
-            numberRef = CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementCookieKey));
-            if (numberRef && CFNumberGetValue(numberRef, kCFNumberLongType, &number))
-                element->cookie = (IOHIDElementCookie) number;
-
-            numberRef = CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementMinKey));
-            if (numberRef && CFNumberGetValue(numberRef, kCFNumberLongType, &number))
-                element->minReport = element->min = number;
-
-            numberRef = CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementMaxKey));
-            if (numberRef && CFNumberGetValue(numberRef, kCFNumberLongType, &number))
-                element->maxReport = element->max = number;
-        }
-    }
-    else
-    {
-        CFTypeRef array = CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementKey));
-        if (array)
-        {
-            if (CFGetTypeID(array) == CFArrayGetTypeID())
-            {
-                CFRange range = { 0, CFArrayGetCount(array) };
-                CFArrayApplyFunction(array, range, getElementsCFArrayHandler, joystick);
-            }
-        }
-    }
-}
-
-// Adds an element to the specified joystick
-//
-static void getElementsCFArrayHandler(const void* value, void* parameter)
-{
-    if (CFGetTypeID(value) == CFDictionaryGetTypeID())
-        addJoystickElement((_GLFWjoystickIOKit*) parameter, (CFTypeRef) value);
-}
-
-// Returns the value of the specified element of the specified joystick
-//
-static long getElementValue(_GLFWjoystickIOKit* joystick, _GLFWjoyelement* 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(_GLFWjoystickIOKit* joystick)
-{
-    int i;
-
-    if (!joystick->present)
-        return;
-
-    for (i = 0;  i < CFArrayGetCount(joystick->axisElements);  i++)
-        free((void*) CFArrayGetValueAtIndex(joystick->axisElements, i));
-    CFArrayRemoveAllValues(joystick->axisElements);
-
-    for (i = 0;  i < CFArrayGetCount(joystick->buttonElements);  i++)
-        free((void*) CFArrayGetValueAtIndex(joystick->buttonElements, i));
-    CFArrayRemoveAllValues(joystick->buttonElements);
-
-    for (i = 0;  i < CFArrayGetCount(joystick->hatElements);  i++)
-        free((void*) CFArrayGetValueAtIndex(joystick->hatElements, i));
-    CFArrayRemoveAllValues(joystick->hatElements);
-
-    free(joystick->axes);
-    free(joystick->buttons);
-
-    (*(joystick->interface))->close(joystick->interface);
-    (*(joystick->interface))->Release(joystick->interface);
-
-    memset(joystick, 0, sizeof(_GLFWjoystickIOKit));
-}
-
-// Callback for user-initiated joystick removal
-//
-static void removalCallback(void* target, IOReturn result, void* refcon, void* sender)
-{
-    removeJoystick((_GLFWjoystickIOKit*) refcon);
-}
-
-// Polls for joystick events and updates GLFW state
-//
-static void pollJoystickEvents(void)
-{
-    int joy;
-
-    for (joy = 0;  joy <= GLFW_JOYSTICK_LAST;  joy++)
-    {
-        CFIndex i;
-        int buttonIndex = 0;
-        _GLFWjoystickIOKit* joystick = _glfw.iokit_js + joy;
-
-        if (!joystick->present)
-            continue;
-
-        for (i = 0;  i < CFArrayGetCount(joystick->buttonElements);  i++)
-        {
-            _GLFWjoyelement* button =
-                (_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick->buttonElements, i);
-
-            if (getElementValue(joystick, button))
-                joystick->buttons[buttonIndex++] = GLFW_PRESS;
-            else
-                joystick->buttons[buttonIndex++] = GLFW_RELEASE;
-        }
-
-        for (i = 0;  i < CFArrayGetCount(joystick->axisElements);  i++)
-        {
-            _GLFWjoyelement* axis =
-                (_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick->axisElements, i);
-
-            long value = getElementValue(joystick, axis);
-            long readScale = axis->maxReport - axis->minReport;
-
-            if (readScale == 0)
-                joystick->axes[i] = value;
-            else
-                joystick->axes[i] = (2.f * (value - axis->minReport) / readScale) - 1.f;
-        }
-
-        for (i = 0;  i < CFArrayGetCount(joystick->hatElements);  i++)
-        {
-            _GLFWjoyelement* hat =
-                (_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick->hatElements, i);
-
-            // Bit fields of button presses for each direction, including nil
-            const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 };
-
-            long j, value = getElementValue(joystick, hat);
-            if (value < 0 || value > 8)
-                value = 8;
-
-            for (j = 0;  j < 4;  j++)
-            {
-                if (directions[value] & (1 << j))
-                    joystick->buttons[buttonIndex++] = GLFW_PRESS;
-                else
-                    joystick->buttons[buttonIndex++] = GLFW_RELEASE;
-            }
-        }
-    }
-}
-
-
-//////////////////////////////////////////////////////////////////////////
-//////                       GLFW internal API                      //////
-//////////////////////////////////////////////////////////////////////////
-
-// Initialize joystick interface
-//
-void _glfwInitJoysticks(void)
-{
-    int joy = 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 propsRef = NULL;
-        CFTypeRef valueRef = NULL;
-        kern_return_t result;
-
-        IOCFPlugInInterface** ppPlugInInterface = NULL;
-        HRESULT plugInResult = S_OK;
-        SInt32 score = 0;
-
-        long usagePage = 0;
-        long usage = 0;
-
-        valueRef = IORegistryEntryCreateCFProperty(ioHIDDeviceObject,
-                                                   CFSTR(kIOHIDPrimaryUsagePageKey),
-                                                   kCFAllocatorDefault, kNilOptions);
-        if (valueRef)
-        {
-            CFNumberGetValue(valueRef, kCFNumberLongType, &usagePage);
-            CFRelease(valueRef);
-        }
-
-        valueRef = IORegistryEntryCreateCFProperty(ioHIDDeviceObject,
-                                                   CFSTR(kIOHIDPrimaryUsageKey),
-                                                   kCFAllocatorDefault, kNilOptions);
-        if (valueRef)
-        {
-            CFNumberGetValue(valueRef, kCFNumberLongType, &usage);
-            CFRelease(valueRef);
-        }
-
-        if (usagePage != kHIDPage_GenericDesktop)
-        {
-            // This device is not relevant to GLFW
-            continue;
-        }
-
-        if ((usage != kHIDUsage_GD_Joystick &&
-             usage != kHIDUsage_GD_GamePad &&
-             usage != kHIDUsage_GD_MultiAxisController))
-        {
-            // This device is not relevant to GLFW
-            continue;
-        }
-        
-        result = IORegistryEntryCreateCFProperties(ioHIDDeviceObject,
-                                                   &propsRef,
-                                                   kCFAllocatorDefault,
-                                                   kNilOptions);
-        
-        if (result != kIOReturnSuccess)
-            continue;
-
-        _GLFWjoystickIOKit* joystick = _glfw.iokit_js + joy;
-        joystick->present = GL_TRUE;
-
-        result = IOCreatePlugInInterfaceForService(ioHIDDeviceObject,
-                                                   kIOHIDDeviceUserClientTypeID,
-                                                   kIOCFPlugInInterfaceID,
-                                                   &ppPlugInInterface,
-                                                   &score);
-
-        if (kIOReturnSuccess != result)
-        {
-            CFRelease(propsRef);
-            return;
-        }
-
-        plugInResult = (*ppPlugInInterface)->QueryInterface(
-                            ppPlugInInterface,
-                            CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),
-                            (void *) &(joystick->interface));
-
-        if (plugInResult != S_OK)
-        {
-            CFRelease(propsRef);
-            return;
-        }
-
-        (*ppPlugInInterface)->Release(ppPlugInInterface);
-
-        (*(joystick->interface))->open(joystick->interface, 0);
-        (*(joystick->interface))->setRemovalCallback(joystick->interface,
-                                                     removalCallback,
-                                                     joystick,
-                                                     joystick);
-
-        // Get product string
-        valueRef = CFDictionaryGetValue(propsRef, CFSTR(kIOHIDProductKey));
-        if (valueRef)
-        {
-            CFStringGetCString(valueRef,
-                               joystick->name,
-                               sizeof(joystick->name),
-                               kCFStringEncodingUTF8);
-        }
-
-        joystick->axisElements = CFArrayCreateMutable(NULL, 0, NULL);
-        joystick->buttonElements = CFArrayCreateMutable(NULL, 0, NULL);
-        joystick->hatElements = CFArrayCreateMutable(NULL, 0, NULL);
-
-        valueRef = CFDictionaryGetValue(propsRef, CFSTR(kIOHIDElementKey));
-        if (CFGetTypeID(valueRef) == CFArrayGetTypeID())
-        {
-            CFRange range = { 0, CFArrayGetCount(valueRef) };
-            CFArrayApplyFunction(valueRef,
-                                 range,
-                                 getElementsCFArrayHandler,
-                                 (void*) joystick);
-        }
-
-        CFRelease(propsRef);
-
-        joystick->axes = calloc(CFArrayGetCount(joystick->axisElements),
-                                         sizeof(float));
-        joystick->buttons = calloc(CFArrayGetCount(joystick->buttonElements) +
-                                   CFArrayGetCount(joystick->hatElements) * 4, 1);
-
-        joy++;
-        if (joy > GLFW_JOYSTICK_LAST)
-            break;
-    }
-}
-
-// Close all opened joystick handles
-//
-void _glfwTerminateJoysticks(void)
-{
-    int i;
-
-    for (i = 0;  i < GLFW_JOYSTICK_LAST + 1;  i++)
-    {
-        _GLFWjoystickIOKit* joystick = &_glfw.iokit_js[i];
-        removeJoystick(joystick);
-
-        if (joystick->axisElements)
-            CFRelease(joystick->axisElements);
-        if (joystick->buttonElements)
-            CFRelease(joystick->buttonElements);
-        if (joystick->hatElements)
-            CFRelease(joystick->hatElements);
-    }
-}
-
-
-//////////////////////////////////////////////////////////////////////////
-//////                       GLFW platform API                      //////
-//////////////////////////////////////////////////////////////////////////
-
-int _glfwPlatformJoystickPresent(int joy)
-{
-    pollJoystickEvents();
-
-    return _glfw.iokit_js[joy].present;
-}
-
-const float* _glfwPlatformGetJoystickAxes(int joy, int* count)
-{
-    _GLFWjoystickIOKit* joystick = _glfw.iokit_js + joy;
-
-    pollJoystickEvents();
-
-    if (!joystick->present)
-        return NULL;
-
-    *count = (int) CFArrayGetCount(joystick->axisElements);
-    return joystick->axes;
-}
-
-const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
-{
-    _GLFWjoystickIOKit* joystick = _glfw.iokit_js + joy;
-
-    pollJoystickEvents();
-
-    if (!joystick->present)
-        return NULL;
-
-    *count = (int) CFArrayGetCount(joystick->buttonElements) +
-             (int) CFArrayGetCount(joystick->hatElements) * 4;
-    return joystick->buttons;
-}
-
-const char* _glfwPlatformGetJoystickName(int joy)
-{
-    pollJoystickEvents();
-
-    return _glfw.iokit_js[joy].name;
-}
-
diff --git a/glfw/src/linux_joystick.c b/glfw/src/linux_joystick.c
--- a/glfw/src/linux_joystick.c
+++ b/glfw/src/linux_joystick.c
@@ -1,8 +1,8 @@
 //========================================================================
-// GLFW 3.1 Linux - www.glfw.org
+// GLFW 3.2 Linux - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -45,12 +45,13 @@
 
 // Attempt to open the specified joystick device
 //
-static void openJoystickDevice(const char* path)
-{
 #if defined(__linux__)
+static GLFWbool openJoystickDevice(const char* path)
+{
     char axisCount, buttonCount;
-    char name[256];
+    char name[256] = "";
     int joy, fd, version;
+    _GLFWjoystickLinux* js;
 
     for (joy = GLFW_JOYSTICK_1;  joy <= GLFW_JOYSTICK_LAST;  joy++)
     {
@@ -58,7 +59,7 @@
             continue;
 
         if (strcmp(_glfw.linux_js.js[joy].path, path) == 0)
-            return;
+            return GLFW_FALSE;
     }
 
     for (joy = GLFW_JOYSTICK_1;  joy <= GLFW_JOYSTICK_LAST;  joy++)
@@ -68,13 +69,11 @@
     }
 
     if (joy > GLFW_JOYSTICK_LAST)
-        return;
+        return GLFW_FALSE;
 
     fd = open(path, O_RDONLY | O_NONBLOCK);
     if (fd == -1)
-        return;
-
-    _glfw.linux_js.js[joy].fd = fd;
+        return GLFW_FALSE;
 
     // Verify that the joystick driver version is at least 1.0
     ioctl(fd, JSIOCGVERSION, &version);
@@ -82,116 +81,102 @@
     {
         // It's an old 0.x interface (we don't support it)
         close(fd);
-        return;
+        return GLFW_FALSE;
     }
 
     if (ioctl(fd, JSIOCGNAME(sizeof(name)), name) < 0)
         strncpy(name, "Unknown", sizeof(name));
 
-    _glfw.linux_js.js[joy].name = strdup(name);
-    _glfw.linux_js.js[joy].path = strdup(path);
+    js = _glfw.linux_js.js + joy;
+    js->present = GLFW_TRUE;
+    js->name = strdup(name);
+    js->path = strdup(path);
+    js->fd = fd;
 
     ioctl(fd, JSIOCGAXES, &axisCount);
-    _glfw.linux_js.js[joy].axisCount = (int) axisCount;
+    js->axisCount = (int) axisCount;
+    js->axes = calloc(axisCount, sizeof(float));
 
     ioctl(fd, JSIOCGBUTTONS, &buttonCount);
-    _glfw.linux_js.js[joy].buttonCount = (int) buttonCount;
-
-    _glfw.linux_js.js[joy].axes = calloc(axisCount, sizeof(float));
-    _glfw.linux_js.js[joy].buttons = calloc(buttonCount, 1);
+    js->buttonCount = (int) buttonCount;
+    js->buttons = calloc(buttonCount, 1);
 
-    _glfw.linux_js.js[joy].present = GL_TRUE;
-#endif // __linux__
+    _glfwInputJoystickChange(joy, GLFW_CONNECTED);
+    return GLFW_TRUE;
 }
+#endif // __linux__
 
-// Polls for and processes events for all present joysticks
+// Polls for and processes events the specified joystick
 //
-static void pollJoystickEvents(void)
+static GLFWbool pollJoystickEvents(_GLFWjoystickLinux* js)
 {
 #if defined(__linux__)
-    int i;
-    struct js_event e;
-    ssize_t offset = 0;
-    char buffer[16384];
-
-    const ssize_t size = read(_glfw.linux_js.inotify, buffer, sizeof(buffer));
-
-    while (size > offset)
-    {
-        regmatch_t match;
-        const struct inotify_event* e = (struct inotify_event*) (buffer + offset);
-
-        if (regexec(&_glfw.linux_js.regex, e->name, 1, &match, 0) == 0)
-        {
-            char path[20];
-            snprintf(path, sizeof(path), "/dev/input/%s", e->name);
-            openJoystickDevice(path);
-        }
+    _glfwPollJoystickEvents();
 
-        offset += sizeof(struct inotify_event) + e->len;
-    }
+    if (!js->present)
+        return GLFW_FALSE;
 
-    for (i = 0;  i <= GLFW_JOYSTICK_LAST;  i++)
+    // Read all queued events (non-blocking)
+    for (;;)
     {
-        if (!_glfw.linux_js.js[i].present)
-            continue;
+        struct js_event e;
 
-        // Read all queued events (non-blocking)
-        for (;;)
+        errno = 0;
+        if (read(js->fd, &e, sizeof(e)) < 0)
         {
-            errno = 0;
-            if (read(_glfw.linux_js.js[i].fd, &e, sizeof(e)) < 0)
+            // Reset the joystick slot if the device was disconnected
+            if (errno == ENODEV)
             {
-                if (errno == ENODEV)
-                {
-                    // The joystick was disconnected
-
-                    free(_glfw.linux_js.js[i].axes);
-                    free(_glfw.linux_js.js[i].buttons);
-                    free(_glfw.linux_js.js[i].name);
-                    free(_glfw.linux_js.js[i].path);
+                free(js->axes);
+                free(js->buttons);
+                free(js->name);
+                free(js->path);
 
-                    memset(&_glfw.linux_js.js[i], 0, sizeof(_glfw.linux_js.js[i]));
-                }
+                memset(js, 0, sizeof(_GLFWjoystickLinux));
 
-                break;
+                _glfwInputJoystickChange(js - _glfw.linux_js.js,
+                                         GLFW_DISCONNECTED);
             }
 
-            // We don't care if it's an init event or not
-            e.type &= ~JS_EVENT_INIT;
-
-            switch (e.type)
-            {
-                case JS_EVENT_AXIS:
-                    _glfw.linux_js.js[i].axes[e.number] =
-                        (float) e.value / 32767.0f;
-                    break;
+            break;
+        }
 
-                case JS_EVENT_BUTTON:
-                    _glfw.linux_js.js[i].buttons[e.number] =
-                        e.value ? GLFW_PRESS : GLFW_RELEASE;
-                    break;
+        // Clear the initial-state bit
+        e.type &= ~JS_EVENT_INIT;
 
-                default:
-                    break;
-            }
-        }
+        if (e.type == JS_EVENT_AXIS)
+            js->axes[e.number] = (float) e.value / 32767.0f;
+        else if (e.type == JS_EVENT_BUTTON)
+            js->buttons[e.number] = e.value ? GLFW_PRESS : GLFW_RELEASE;
     }
 #endif // __linux__
+    return js->present;
 }
 
+// Lexically compare joysticks by name; used by qsort
+//
+#if defined(__linux__)
+static int compareJoysticks(const void* fp, const void* sp)
+{
+    const _GLFWjoystickLinux* fj = fp;
+    const _GLFWjoystickLinux* sj = sp;
+    return strcmp(fj->path, sj->path);
+}
+#endif // __linux__
 
+
 //////////////////////////////////////////////////////////////////////////
 //////                       GLFW internal API                      //////
 //////////////////////////////////////////////////////////////////////////
 
 // Initialize joystick interface
 //
-int _glfwInitJoysticks(void)
+GLFWbool _glfwInitJoysticksLinux(void)
 {
 #if defined(__linux__)
-    const char* dirname = "/dev/input";
     DIR* dir;
+    int count = 0;
+    const char* dirname = "/dev/input";
 
     _glfw.linux_js.inotify = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
     if (_glfw.linux_js.inotify == -1)
@@ -199,7 +184,7 @@
         _glfwInputError(GLFW_PLATFORM_ERROR,
                         "Linux: Failed to initialize inotify: %s",
                         strerror(errno));
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
 
     // HACK: Register for IN_ATTRIB as well to get notified when udev is done
@@ -220,7 +205,7 @@
     if (regcomp(&_glfw.linux_js.regex, "^js[0-9]\\+$", 0) != 0)
     {
         _glfwInputError(GLFW_PLATFORM_ERROR, "Linux: Failed to compile regex");
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
 
     dir = opendir(dirname);
@@ -237,7 +222,8 @@
                 continue;
 
             snprintf(path, sizeof(path), "%s/%s", dirname, entry->d_name);
-            openJoystickDevice(path);
+            if (openJoystickDevice(path))
+                count++;
         }
 
         closedir(dir);
@@ -251,14 +237,15 @@
         // Continue with no joysticks detected
     }
 
+    qsort(_glfw.linux_js.js, count, sizeof(_GLFWjoystickLinux), compareJoysticks);
 #endif // __linux__
 
-    return GL_TRUE;
+    return GLFW_TRUE;
 }
 
 // Close all opened joystick handles
 //
-void _glfwTerminateJoysticks(void)
+void _glfwTerminateJoysticksLinux(void)
 {
 #if defined(__linux__)
     int i;
@@ -287,38 +274,68 @@
 #endif // __linux__
 }
 
+void _glfwPollJoystickEvents(void)
+{
+#if defined(__linux__)
+    ssize_t offset = 0;
+    char buffer[16384];
 
+    const ssize_t size = read(_glfw.linux_js.inotify, buffer, sizeof(buffer));
+
+    while (size > offset)
+    {
+        regmatch_t match;
+        const struct inotify_event* e = (struct inotify_event*) (buffer + offset);
+
+        if (regexec(&_glfw.linux_js.regex, e->name, 1, &match, 0) == 0)
+        {
+            char path[20];
+            snprintf(path, sizeof(path), "/dev/input/%s", e->name);
+            openJoystickDevice(path);
+        }
+
+        offset += sizeof(struct inotify_event) + e->len;
+    }
+#endif
+}
+
+
 //////////////////////////////////////////////////////////////////////////
 //////                       GLFW platform API                      //////
 //////////////////////////////////////////////////////////////////////////
 
 int _glfwPlatformJoystickPresent(int joy)
 {
-    pollJoystickEvents();
-
-    return _glfw.linux_js.js[joy].present;
+    _GLFWjoystickLinux* js = _glfw.linux_js.js + joy;
+    return pollJoystickEvents(js);
 }
 
 const float* _glfwPlatformGetJoystickAxes(int joy, int* count)
 {
-    pollJoystickEvents();
+    _GLFWjoystickLinux* js = _glfw.linux_js.js + joy;
+    if (!pollJoystickEvents(js))
+        return NULL;
 
-    *count = _glfw.linux_js.js[joy].axisCount;
-    return _glfw.linux_js.js[joy].axes;
+    *count = js->axisCount;
+    return js->axes;
 }
 
 const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
 {
-    pollJoystickEvents();
+    _GLFWjoystickLinux* js = _glfw.linux_js.js + joy;
+    if (!pollJoystickEvents(js))
+        return NULL;
 
-    *count = _glfw.linux_js.js[joy].buttonCount;
-    return _glfw.linux_js.js[joy].buttons;
+    *count = js->buttonCount;
+    return js->buttons;
 }
 
 const char* _glfwPlatformGetJoystickName(int joy)
 {
-    pollJoystickEvents();
+    _GLFWjoystickLinux* js = _glfw.linux_js.js + joy;
+    if (!pollJoystickEvents(js))
+        return NULL;
 
-    return _glfw.linux_js.js[joy].name;
+    return js->name;
 }
 
diff --git a/glfw/src/linux_joystick.h b/glfw/src/linux_joystick.h
--- a/glfw/src/linux_joystick.h
+++ b/glfw/src/linux_joystick.h
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.1 Linux - www.glfw.org
+// GLFW 3.2 Linux - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
 //
@@ -24,40 +24,45 @@
 //
 //========================================================================
 
-#ifndef _linux_joystick_h_
-#define _linux_joystick_h_
+#ifndef _glfw3_linux_joystick_h_
+#define _glfw3_linux_joystick_h_
 
 #include <regex.h>
 
-#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE \
-    _GLFWjoystickLinux linux_js
+#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE _GLFWjoylistLinux linux_js
 
 
-// Linux-specific joystick API data
+// Linux-specific joystick data
 //
 typedef struct _GLFWjoystickLinux
 {
-    struct
-    {
-        int             present;
-        int             fd;
-        float*          axes;
-        int             axisCount;
-        unsigned char*  buttons;
-        int             buttonCount;
-        char*           name;
-        char*           path;
-    } js[GLFW_JOYSTICK_LAST + 1];
+    GLFWbool        present;
+    int             fd;
+    float*          axes;
+    int             axisCount;
+    unsigned char*  buttons;
+    int             buttonCount;
+    char*           name;
+    char*           path;
+} _GLFWjoystickLinux;
 
+// Linux-specific joystick API data
+//
+typedef struct _GLFWjoylistLinux
+{
+    _GLFWjoystickLinux js[GLFW_JOYSTICK_LAST + 1];
+
 #if defined(__linux__)
     int             inotify;
     int             watch;
     regex_t         regex;
 #endif /*__linux__*/
-} _GLFWjoystickLinux;
+} _GLFWjoylistLinux;
 
 
-int _glfwInitJoysticks(void);
-void _glfwTerminateJoysticks(void);
+GLFWbool _glfwInitJoysticksLinux(void);
+void _glfwTerminateJoysticksLinux(void);
 
-#endif // _linux_joystick_h_
+void _glfwPollJoystickEvents(void);
+
+#endif // _glfw3_linux_joystick_h_
diff --git a/glfw/src/mach_time.c b/glfw/src/mach_time.c
deleted file mode 100644
--- a/glfw/src/mach_time.c
+++ /dev/null
@@ -1,71 +0,0 @@
-//========================================================================
-// GLFW 3.1 OS X - www.glfw.org
-//------------------------------------------------------------------------
-// Copyright (c) 2009-2010 Camilla Berglund <elmindreda@elmindreda.org>
-//
-// 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 <mach/mach_time.h>
-
-
-// Return raw time
-//
-static uint64_t getRawTime(void)
-{
-    return mach_absolute_time();
-}
-
-
-//////////////////////////////////////////////////////////////////////////
-//////                       GLFW internal API                      //////
-//////////////////////////////////////////////////////////////////////////
-
-// Initialise timer
-//
-void _glfwInitTimer(void)
-{
-    mach_timebase_info_data_t info;
-    mach_timebase_info(&info);
-
-    _glfw.ns_time.resolution = (double) info.numer / (info.denom * 1.0e9);
-    _glfw.ns_time.base = getRawTime();
-}
-
-
-//////////////////////////////////////////////////////////////////////////
-//////                       GLFW platform API                      //////
-//////////////////////////////////////////////////////////////////////////
-
-double _glfwPlatformGetTime(void)
-{
-    return (double) (getRawTime() - _glfw.ns_time.base) *
-        _glfw.ns_time.resolution;
-}
-
-void _glfwPlatformSetTime(double time)
-{
-    _glfw.ns_time.base = getRawTime() -
-        (uint64_t) (time / _glfw.ns_time.resolution);
-}
-
diff --git a/glfw/src/mir_init.c b/glfw/src/mir_init.c
--- a/glfw/src/mir_init.c
+++ b/glfw/src/mir_init.c
@@ -1,7 +1,7 @@
 //========================================================================
-// GLFW 3.1 Mir - www.glfw.org
+// GLFW 3.2 Mir - www.glfw.org
 //------------------------------------------------------------------------
-// Copyright (c) 2014 Brandon Schaefer <brandon.schaefer@canonical.com>
+// Copyright (c) 2014-2015 Brandon Schaefer <brandon.schaefer@canonical.com>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -26,10 +26,136 @@
 
 #include "internal.h"
 
+#include <linux/input.h>
 #include <stdlib.h>
 #include <string.h>
 
 
+// Create key code translation tables
+//
+static void createKeyTables(void)
+{
+    memset(_glfw.mir.publicKeys, -1, sizeof(_glfw.mir.publicKeys));
+
+    _glfw.mir.publicKeys[KEY_GRAVE]      = GLFW_KEY_GRAVE_ACCENT;
+    _glfw.mir.publicKeys[KEY_1]          = GLFW_KEY_1;
+    _glfw.mir.publicKeys[KEY_2]          = GLFW_KEY_2;
+    _glfw.mir.publicKeys[KEY_3]          = GLFW_KEY_3;
+    _glfw.mir.publicKeys[KEY_4]          = GLFW_KEY_4;
+    _glfw.mir.publicKeys[KEY_5]          = GLFW_KEY_5;
+    _glfw.mir.publicKeys[KEY_6]          = GLFW_KEY_6;
+    _glfw.mir.publicKeys[KEY_7]          = GLFW_KEY_7;
+    _glfw.mir.publicKeys[KEY_8]          = GLFW_KEY_8;
+    _glfw.mir.publicKeys[KEY_9]          = GLFW_KEY_9;
+    _glfw.mir.publicKeys[KEY_0]          = GLFW_KEY_0;
+    _glfw.mir.publicKeys[KEY_MINUS]      = GLFW_KEY_MINUS;
+    _glfw.mir.publicKeys[KEY_EQUAL]      = GLFW_KEY_EQUAL;
+    _glfw.mir.publicKeys[KEY_Q]          = GLFW_KEY_Q;
+    _glfw.mir.publicKeys[KEY_W]          = GLFW_KEY_W;
+    _glfw.mir.publicKeys[KEY_E]          = GLFW_KEY_E;
+    _glfw.mir.publicKeys[KEY_R]          = GLFW_KEY_R;
+    _glfw.mir.publicKeys[KEY_T]          = GLFW_KEY_T;
+    _glfw.mir.publicKeys[KEY_Y]          = GLFW_KEY_Y;
+    _glfw.mir.publicKeys[KEY_U]          = GLFW_KEY_U;
+    _glfw.mir.publicKeys[KEY_I]          = GLFW_KEY_I;
+    _glfw.mir.publicKeys[KEY_O]          = GLFW_KEY_O;
+    _glfw.mir.publicKeys[KEY_P]          = GLFW_KEY_P;
+    _glfw.mir.publicKeys[KEY_LEFTBRACE]  = GLFW_KEY_LEFT_BRACKET;
+    _glfw.mir.publicKeys[KEY_RIGHTBRACE] = GLFW_KEY_RIGHT_BRACKET;
+    _glfw.mir.publicKeys[KEY_A]          = GLFW_KEY_A;
+    _glfw.mir.publicKeys[KEY_S]          = GLFW_KEY_S;
+    _glfw.mir.publicKeys[KEY_D]          = GLFW_KEY_D;
+    _glfw.mir.publicKeys[KEY_F]          = GLFW_KEY_F;
+    _glfw.mir.publicKeys[KEY_G]          = GLFW_KEY_G;
+    _glfw.mir.publicKeys[KEY_H]          = GLFW_KEY_H;
+    _glfw.mir.publicKeys[KEY_J]          = GLFW_KEY_J;
+    _glfw.mir.publicKeys[KEY_K]          = GLFW_KEY_K;
+    _glfw.mir.publicKeys[KEY_L]          = GLFW_KEY_L;
+    _glfw.mir.publicKeys[KEY_SEMICOLON]  = GLFW_KEY_SEMICOLON;
+    _glfw.mir.publicKeys[KEY_APOSTROPHE] = GLFW_KEY_APOSTROPHE;
+    _glfw.mir.publicKeys[KEY_Z]          = GLFW_KEY_Z;
+    _glfw.mir.publicKeys[KEY_X]          = GLFW_KEY_X;
+    _glfw.mir.publicKeys[KEY_C]          = GLFW_KEY_C;
+    _glfw.mir.publicKeys[KEY_V]          = GLFW_KEY_V;
+    _glfw.mir.publicKeys[KEY_B]          = GLFW_KEY_B;
+    _glfw.mir.publicKeys[KEY_N]          = GLFW_KEY_N;
+    _glfw.mir.publicKeys[KEY_M]          = GLFW_KEY_M;
+    _glfw.mir.publicKeys[KEY_COMMA]      = GLFW_KEY_COMMA;
+    _glfw.mir.publicKeys[KEY_DOT]        = GLFW_KEY_PERIOD;
+    _glfw.mir.publicKeys[KEY_SLASH]      = GLFW_KEY_SLASH;
+    _glfw.mir.publicKeys[KEY_BACKSLASH]  = GLFW_KEY_BACKSLASH;
+    _glfw.mir.publicKeys[KEY_ESC]        = GLFW_KEY_ESCAPE;
+    _glfw.mir.publicKeys[KEY_TAB]        = GLFW_KEY_TAB;
+    _glfw.mir.publicKeys[KEY_LEFTSHIFT]  = GLFW_KEY_LEFT_SHIFT;
+    _glfw.mir.publicKeys[KEY_RIGHTSHIFT] = GLFW_KEY_RIGHT_SHIFT;
+    _glfw.mir.publicKeys[KEY_LEFTCTRL]   = GLFW_KEY_LEFT_CONTROL;
+    _glfw.mir.publicKeys[KEY_RIGHTCTRL]  = GLFW_KEY_RIGHT_CONTROL;
+    _glfw.mir.publicKeys[KEY_LEFTALT]    = GLFW_KEY_LEFT_ALT;
+    _glfw.mir.publicKeys[KEY_RIGHTALT]   = GLFW_KEY_RIGHT_ALT;
+    _glfw.mir.publicKeys[KEY_LEFTMETA]   = GLFW_KEY_LEFT_SUPER;
+    _glfw.mir.publicKeys[KEY_RIGHTMETA]  = GLFW_KEY_RIGHT_SUPER;
+    _glfw.mir.publicKeys[KEY_MENU]       = GLFW_KEY_MENU;
+    _glfw.mir.publicKeys[KEY_NUMLOCK]    = GLFW_KEY_NUM_LOCK;
+    _glfw.mir.publicKeys[KEY_CAPSLOCK]   = GLFW_KEY_CAPS_LOCK;
+    _glfw.mir.publicKeys[KEY_PRINT]      = GLFW_KEY_PRINT_SCREEN;
+    _glfw.mir.publicKeys[KEY_SCROLLLOCK] = GLFW_KEY_SCROLL_LOCK;
+    _glfw.mir.publicKeys[KEY_PAUSE]      = GLFW_KEY_PAUSE;
+    _glfw.mir.publicKeys[KEY_DELETE]     = GLFW_KEY_DELETE;
+    _glfw.mir.publicKeys[KEY_BACKSPACE]  = GLFW_KEY_BACKSPACE;
+    _glfw.mir.publicKeys[KEY_ENTER]      = GLFW_KEY_ENTER;
+    _glfw.mir.publicKeys[KEY_HOME]       = GLFW_KEY_HOME;
+    _glfw.mir.publicKeys[KEY_END]        = GLFW_KEY_END;
+    _glfw.mir.publicKeys[KEY_PAGEUP]     = GLFW_KEY_PAGE_UP;
+    _glfw.mir.publicKeys[KEY_PAGEDOWN]   = GLFW_KEY_PAGE_DOWN;
+    _glfw.mir.publicKeys[KEY_INSERT]     = GLFW_KEY_INSERT;
+    _glfw.mir.publicKeys[KEY_LEFT]       = GLFW_KEY_LEFT;
+    _glfw.mir.publicKeys[KEY_RIGHT]      = GLFW_KEY_RIGHT;
+    _glfw.mir.publicKeys[KEY_DOWN]       = GLFW_KEY_DOWN;
+    _glfw.mir.publicKeys[KEY_UP]         = GLFW_KEY_UP;
+    _glfw.mir.publicKeys[KEY_F1]         = GLFW_KEY_F1;
+    _glfw.mir.publicKeys[KEY_F2]         = GLFW_KEY_F2;
+    _glfw.mir.publicKeys[KEY_F3]         = GLFW_KEY_F3;
+    _glfw.mir.publicKeys[KEY_F4]         = GLFW_KEY_F4;
+    _glfw.mir.publicKeys[KEY_F5]         = GLFW_KEY_F5;
+    _glfw.mir.publicKeys[KEY_F6]         = GLFW_KEY_F6;
+    _glfw.mir.publicKeys[KEY_F7]         = GLFW_KEY_F7;
+    _glfw.mir.publicKeys[KEY_F8]         = GLFW_KEY_F8;
+    _glfw.mir.publicKeys[KEY_F9]         = GLFW_KEY_F9;
+    _glfw.mir.publicKeys[KEY_F10]        = GLFW_KEY_F10;
+    _glfw.mir.publicKeys[KEY_F11]        = GLFW_KEY_F11;
+    _glfw.mir.publicKeys[KEY_F12]        = GLFW_KEY_F12;
+    _glfw.mir.publicKeys[KEY_F13]        = GLFW_KEY_F13;
+    _glfw.mir.publicKeys[KEY_F14]        = GLFW_KEY_F14;
+    _glfw.mir.publicKeys[KEY_F15]        = GLFW_KEY_F15;
+    _glfw.mir.publicKeys[KEY_F16]        = GLFW_KEY_F16;
+    _glfw.mir.publicKeys[KEY_F17]        = GLFW_KEY_F17;
+    _glfw.mir.publicKeys[KEY_F18]        = GLFW_KEY_F18;
+    _glfw.mir.publicKeys[KEY_F19]        = GLFW_KEY_F19;
+    _glfw.mir.publicKeys[KEY_F20]        = GLFW_KEY_F20;
+    _glfw.mir.publicKeys[KEY_F21]        = GLFW_KEY_F21;
+    _glfw.mir.publicKeys[KEY_F22]        = GLFW_KEY_F22;
+    _glfw.mir.publicKeys[KEY_F23]        = GLFW_KEY_F23;
+    _glfw.mir.publicKeys[KEY_F24]        = GLFW_KEY_F24;
+    _glfw.mir.publicKeys[KEY_KPSLASH]    = GLFW_KEY_KP_DIVIDE;
+    _glfw.mir.publicKeys[KEY_KPDOT]      = GLFW_KEY_KP_MULTIPLY;
+    _glfw.mir.publicKeys[KEY_KPMINUS]    = GLFW_KEY_KP_SUBTRACT;
+    _glfw.mir.publicKeys[KEY_KPPLUS]     = GLFW_KEY_KP_ADD;
+    _glfw.mir.publicKeys[KEY_KP0]        = GLFW_KEY_KP_0;
+    _glfw.mir.publicKeys[KEY_KP1]        = GLFW_KEY_KP_1;
+    _glfw.mir.publicKeys[KEY_KP2]        = GLFW_KEY_KP_2;
+    _glfw.mir.publicKeys[KEY_KP3]        = GLFW_KEY_KP_3;
+    _glfw.mir.publicKeys[KEY_KP4]        = GLFW_KEY_KP_4;
+    _glfw.mir.publicKeys[KEY_KP5]        = GLFW_KEY_KP_5;
+    _glfw.mir.publicKeys[KEY_KP6]        = GLFW_KEY_KP_6;
+    _glfw.mir.publicKeys[KEY_KP7]        = GLFW_KEY_KP_7;
+    _glfw.mir.publicKeys[KEY_KP8]        = GLFW_KEY_KP_8;
+    _glfw.mir.publicKeys[KEY_KP9]        = GLFW_KEY_KP_9;
+    _glfw.mir.publicKeys[KEY_KPCOMMA]    = GLFW_KEY_KP_DECIMAL;
+    _glfw.mir.publicKeys[KEY_KPEQUAL]    = GLFW_KEY_KP_EQUAL;
+    _glfw.mir.publicKeys[KEY_KPENTER]    = GLFW_KEY_KP_ENTER;
+}
+
+
 //////////////////////////////////////////////////////////////////////////
 //////                       GLFW internal API                      //////
 //////////////////////////////////////////////////////////////////////////
@@ -46,39 +172,47 @@
                         "Mir: Unable to connect to server: %s",
                         mir_connection_get_error_message(_glfw.mir.connection));
 
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
 
     _glfw.mir.display =
         mir_connection_get_egl_native_display(_glfw.mir.connection);
 
-    if (!_glfwInitContextAPI())
-        return GL_FALSE;
+    createKeyTables();
 
-    _glfwInitTimer();
-    _glfwInitJoysticks();
+    if (!_glfwInitThreadLocalStoragePOSIX())
+        return GLFW_FALSE;
 
+    if (!_glfwInitJoysticksLinux())
+        return GLFW_FALSE;
+
+    _glfwInitTimerPOSIX();
+
+    // Need the default conf for when we set a NULL cursor
+    _glfw.mir.default_conf = mir_cursor_configuration_from_name(mir_arrow_cursor_name);
+
     _glfw.mir.event_queue = calloc(1, sizeof(EventQueue));
-    _glfwInitEventQueue(_glfw.mir.event_queue);
+    _glfwInitEventQueueMir(_glfw.mir.event_queue);
 
     error = pthread_mutex_init(&_glfw.mir.event_mutex, NULL);
     if (error)
     {
         _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "Mir: Failed to create event mutex: %s\n",
+                        "Mir: Failed to create event mutex: %s",
                         strerror(error));
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
 
-    return GL_TRUE;
+    return GLFW_TRUE;
 }
 
 void _glfwPlatformTerminate(void)
 {
-    _glfwTerminateContextAPI();
-    _glfwTerminateJoysticks();
+    _glfwTerminateEGL();
+    _glfwTerminateJoysticksLinux();
+    _glfwTerminateThreadLocalStoragePOSIX();
 
-    _glfwDeleteEventQueue(_glfw.mir.event_queue);
+    _glfwDeleteEventQueueMir(_glfw.mir.event_queue);
 
     pthread_mutex_destroy(&_glfw.mir.event_mutex);
 
@@ -87,15 +221,18 @@
 
 const char* _glfwPlatformGetVersionString(void)
 {
-    const char* version = _GLFW_VERSION_NUMBER " Mir EGL"
+    return _GLFW_VERSION_NUMBER " Mir EGL"
 #if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK)
         " clock_gettime"
+#else
+        " gettimeofday"
 #endif
+#if defined(__linux__)
+        " /dev/js"
+#endif
 #if defined(_GLFW_BUILD_DLL)
         " shared"
 #endif
         ;
-
-    return version;
 }
 
diff --git a/glfw/src/mir_monitor.c b/glfw/src/mir_monitor.c
--- a/glfw/src/mir_monitor.c
+++ b/glfw/src/mir_monitor.c
@@ -1,7 +1,7 @@
 //========================================================================
-// GLFW 3.1 Mir - www.glfw.org
+// GLFW 3.2 Mir - www.glfw.org
 //------------------------------------------------------------------------
-// Copyright (c) 2014 Brandon Schaefer <brandon.schaefer@canonical.com>
+// Copyright (c) 2014-2015 Brandon Schaefer <brandon.schaefer@canonical.com>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -73,7 +73,7 @@
     return monitors;
 }
 
-GLboolean _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
+GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
 {
     return first->mir.output_id == second->mir.output_id;
 }
@@ -86,6 +86,39 @@
         *ypos = monitor->mir.y;
 }
 
+void FillInRGBBitsFromPixelFormat(GLFWvidmode* mode, const MirPixelFormat pf)
+{
+    switch (pf)
+    {
+      case mir_pixel_format_rgb_565:
+          mode->redBits   = 5;
+          mode->greenBits = 6;
+          mode->blueBits  = 5;
+          break;
+      case mir_pixel_format_rgba_5551:
+          mode->redBits   = 5;
+          mode->greenBits = 5;
+          mode->blueBits  = 5;
+          break;
+      case mir_pixel_format_rgba_4444:
+          mode->redBits   = 4;
+          mode->greenBits = 4;
+          mode->blueBits  = 4;
+          break;
+      case mir_pixel_format_abgr_8888:
+      case mir_pixel_format_xbgr_8888:
+      case mir_pixel_format_argb_8888:
+      case mir_pixel_format_xrgb_8888:
+      case mir_pixel_format_bgr_888:
+      case mir_pixel_format_rgb_888:
+      default:
+          mode->redBits   = 8;
+          mode->greenBits = 8;
+          mode->blueBits  = 8;
+          break;
+    }
+}
+
 GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
 {
     int i;
@@ -106,9 +139,8 @@
             modes[*found].width  = out->modes[*found].horizontal_resolution;
             modes[*found].height = out->modes[*found].vertical_resolution;
             modes[*found].refreshRate = out->modes[*found].refresh_rate;
-            modes[*found].redBits     = 8;
-            modes[*found].greenBits   = 8;
-            modes[*found].blueBits    = 8;
+
+            FillInRGBBitsFromPixelFormat(&modes[*found], out->output_formats[*found]);
         }
 
         break;
@@ -127,12 +159,24 @@
 void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
 {
     _glfwInputError(GLFW_PLATFORM_ERROR,
-                    "Mir: Unsupported function %s!", __PRETTY_FUNCTION__);
+                    "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
 }
 
 void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
 {
     _glfwInputError(GLFW_PLATFORM_ERROR,
-                    "Mir: Unsupported function %s!", __PRETTY_FUNCTION__);
+                    "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                        GLFW native API                       //////
+//////////////////////////////////////////////////////////////////////////
+
+GLFWAPI int glfwGetMirMonitor(GLFWmonitor* handle)
+{
+    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
+    _GLFW_REQUIRE_INIT_OR_RETURN(0);
+    return monitor->mir.output_id;
 }
 
diff --git a/glfw/src/mir_platform.h b/glfw/src/mir_platform.h
--- a/glfw/src/mir_platform.h
+++ b/glfw/src/mir_platform.h
@@ -1,7 +1,7 @@
 //========================================================================
-// GLFW 3.1 Mir - www.glfw.org
+// GLFW 3.2 Mir - www.glfw.org
 //------------------------------------------------------------------------
-// Copyright (c) 2014 Brandon Schaefer <brandon.schaefer@canonical.com>
+// Copyright (c) 2014-2015 Brandon Schaefer <brandon.schaefer@canonical.com>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -24,33 +24,51 @@
 //
 //========================================================================
 
-#ifndef _mir_platform_h_
-#define _mir_platform_h_
+#ifndef _glfw3_mir_platform_h_
+#define _glfw3_mir_platform_h_
 
+#include <sys/queue.h>
+#include <pthread.h>
+#include <dlfcn.h>
+
 #include <mir_toolkit/mir_client_library.h>
 
+typedef VkFlags VkMirSurfaceCreateFlagsKHR;
+
+typedef struct VkMirSurfaceCreateInfoKHR
+{
+    VkStructureType             sType;
+    const void*                 pNext;
+    VkMirSurfaceCreateFlagsKHR  flags;
+    MirConnection*              connection;
+    MirSurface*                 mirSurface;
+} VkMirSurfaceCreateInfoKHR;
+
+typedef VkResult (APIENTRY *PFN_vkCreateMirSurfaceKHR)(VkInstance,const VkMirSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*);
+typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)(VkPhysicalDevice,uint32_t,MirConnection*);
+
 #include "posix_tls.h"
 #include "posix_time.h"
 #include "linux_joystick.h"
-
-#include <sys/queue.h>
-
-#include <pthread.h>
+#include "xkb_unicode.h"
+#include "egl_context.h"
 
-#if defined(_GLFW_EGL)
- #include "egl_context.h"
-#else
- #error "The Mir backend depends on EGL platform support"
-#endif
+#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
+#define _glfw_dlclose(handle) dlclose(handle)
+#define _glfw_dlsym(handle, name) dlsym(handle, name)
 
-#define _GLFW_EGL_NATIVE_WINDOW  window->mir.window
-#define _GLFW_EGL_NATIVE_DISPLAY _glfw.mir.display
+#define _GLFW_EGL_NATIVE_WINDOW  ((EGLNativeWindowType) window->mir.window)
+#define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.mir.display)
 
 #define _GLFW_PLATFORM_WINDOW_STATE         _GLFWwindowMir  mir
 #define _GLFW_PLATFORM_MONITOR_STATE        _GLFWmonitorMir mir
 #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryMir mir
 #define _GLFW_PLATFORM_CURSOR_STATE         _GLFWcursorMir  mir
 
+#define _GLFW_PLATFORM_CONTEXT_STATE
+#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE
+
+
 // Mir-specific Event Queue
 //
 typedef struct EventQueue
@@ -69,7 +87,6 @@
 
 } _GLFWwindowMir;
 
-
 // Mir-specific per-monitor data
 //
 typedef struct _GLFWmonitorMir
@@ -81,30 +98,33 @@
 
 } _GLFWmonitorMir;
 
-
 // Mir-specific global data
 //
 typedef struct _GLFWlibraryMir
 {
     MirConnection*          connection;
     MirEGLNativeDisplayType display;
+    MirCursorConfiguration* default_conf;
     EventQueue* event_queue;
 
+    short int       publicKeys[256];
+
     pthread_mutex_t event_mutex;
     pthread_cond_t  event_cond;
 
 } _GLFWlibraryMir;
 
-
 // Mir-specific per-cursor data
 // TODO: Only system cursors are implemented in Mir atm. Need to wait for support.
 //
 typedef struct _GLFWcursorMir
 {
+    MirCursorConfiguration* conf;
+    MirBufferStream*        custom_cursor;
 } _GLFWcursorMir;
 
 
-extern void _glfwInitEventQueue(EventQueue* queue);
-extern void _glfwDeleteEventQueue(EventQueue* queue);
+extern void _glfwInitEventQueueMir(EventQueue* queue);
+extern void _glfwDeleteEventQueueMir(EventQueue* queue);
 
-#endif // _mir_platform_h_
+#endif // _glfw3_mir_platform_h_
diff --git a/glfw/src/mir_window.c b/glfw/src/mir_window.c
--- a/glfw/src/mir_window.c
+++ b/glfw/src/mir_window.c
@@ -1,7 +1,7 @@
 //========================================================================
-// GLFW 3.1 Mir - www.glfw.org
+// GLFW 3.2 Mir - www.glfw.org
 //------------------------------------------------------------------------
-// Copyright (c) 2014 Brandon Schaefer <brandon.schaefer@canonical.com>
+// Copyright (c) 2014-2015 Brandon Schaefer <brandon.schaefer@canonical.com>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -25,7 +25,6 @@
 //========================================================================
 
 #include "internal.h"
-#include "xkb_unicode.h"
 
 #include <linux/input.h>
 #include <stdlib.h>
@@ -35,32 +34,34 @@
 typedef struct EventNode
 {
     TAILQ_ENTRY(EventNode) entries;
-    MirEvent*              event;
+    const MirEvent*        event;
     _GLFWwindow*           window;
 } EventNode;
 
 static void deleteNode(EventQueue* queue, EventNode* node)
 {
-    free(node->event);
+    mir_event_unref(node->event);
     free(node);
 }
 
-static int emptyEventQueue(EventQueue* queue)
+static GLFWbool emptyEventQueue(EventQueue* queue)
 {
-    return queue->head.tqh_first == NULL ? GL_TRUE : GL_FALSE;
+    return queue->head.tqh_first == NULL;
 }
 
-static EventNode* newEventNode(MirEvent const* event, _GLFWwindow* context)
+// TODO The mir_event_ref is not supposed to be used but ... its needed
+//      in this case. Need to wait until we can read from an FD set up by mir
+//      for single threaded event handling.
+static EventNode* newEventNode(const MirEvent* event, _GLFWwindow* context)
 {
     EventNode* new_node = calloc(1, sizeof(EventNode));
-    new_node->event     = calloc(1, sizeof(MirEvent));
+    new_node->event     = mir_event_ref(event);
     new_node->window    = context;
 
-    memcpy(new_node->event, event, sizeof(MirEvent));
     return new_node;
 }
 
-static void enqueueEvent(MirEvent const* event, _GLFWwindow* context)
+static void enqueueEvent(const MirEvent* event, _GLFWwindow* context)
 {
     pthread_mutex_lock(&_glfw.mir.event_mutex);
 
@@ -88,6 +89,9 @@
     return node;
 }
 
+/* FIXME Soon to be changed upstream mir! So we can use an egl config to figure out
+         the best pixel format!
+*/
 static MirPixelFormat findValidPixelFormat(void)
 {
     unsigned int i, validFormats, mirPixelFormats = 32;
@@ -114,234 +118,119 @@
 {
     int publicMods = 0x0;
 
-    if (mods & mir_key_modifier_alt)
+    if (mods & mir_input_event_modifier_alt)
         publicMods |= GLFW_MOD_ALT;
-    else if (mods & mir_key_modifier_shift)
+    else if (mods & mir_input_event_modifier_shift)
         publicMods |= GLFW_MOD_SHIFT;
-    else if (mods & mir_key_modifier_ctrl)
+    else if (mods & mir_input_event_modifier_ctrl)
         publicMods |= GLFW_MOD_CONTROL;
-    else if (mods & mir_key_modifier_meta)
+    else if (mods & mir_input_event_modifier_meta)
         publicMods |= GLFW_MOD_SUPER;
 
     return publicMods;
 }
 
-// Taken from wl_init.c
 static int toGLFWKeyCode(uint32_t key)
 {
-    switch (key)
-    {
-        case KEY_GRAVE:         return GLFW_KEY_GRAVE_ACCENT;
-        case KEY_1:             return GLFW_KEY_1;
-        case KEY_2:             return GLFW_KEY_2;
-        case KEY_3:             return GLFW_KEY_3;
-        case KEY_4:             return GLFW_KEY_4;
-        case KEY_5:             return GLFW_KEY_5;
-        case KEY_6:             return GLFW_KEY_6;
-        case KEY_7:             return GLFW_KEY_7;
-        case KEY_8:             return GLFW_KEY_8;
-        case KEY_9:             return GLFW_KEY_9;
-        case KEY_0:             return GLFW_KEY_0;
-        case KEY_MINUS:         return GLFW_KEY_MINUS;
-        case KEY_EQUAL:         return GLFW_KEY_EQUAL;
-        case KEY_Q:             return GLFW_KEY_Q;
-        case KEY_W:             return GLFW_KEY_W;
-        case KEY_E:             return GLFW_KEY_E;
-        case KEY_R:             return GLFW_KEY_R;
-        case KEY_T:             return GLFW_KEY_T;
-        case KEY_Y:             return GLFW_KEY_Y;
-        case KEY_U:             return GLFW_KEY_U;
-        case KEY_I:             return GLFW_KEY_I;
-        case KEY_O:             return GLFW_KEY_O;
-        case KEY_P:             return GLFW_KEY_P;
-        case KEY_LEFTBRACE:     return GLFW_KEY_LEFT_BRACKET;
-        case KEY_RIGHTBRACE:    return GLFW_KEY_RIGHT_BRACKET;
-        case KEY_A:             return GLFW_KEY_A;
-        case KEY_S:             return GLFW_KEY_S;
-        case KEY_D:             return GLFW_KEY_D;
-        case KEY_F:             return GLFW_KEY_F;
-        case KEY_G:             return GLFW_KEY_G;
-        case KEY_H:             return GLFW_KEY_H;
-        case KEY_J:             return GLFW_KEY_J;
-        case KEY_K:             return GLFW_KEY_K;
-        case KEY_L:             return GLFW_KEY_L;
-        case KEY_SEMICOLON:     return GLFW_KEY_SEMICOLON;
-        case KEY_APOSTROPHE:    return GLFW_KEY_APOSTROPHE;
-        case KEY_Z:             return GLFW_KEY_Z;
-        case KEY_X:             return GLFW_KEY_X;
-        case KEY_C:             return GLFW_KEY_C;
-        case KEY_V:             return GLFW_KEY_V;
-        case KEY_B:             return GLFW_KEY_B;
-        case KEY_N:             return GLFW_KEY_N;
-        case KEY_M:             return GLFW_KEY_M;
-        case KEY_COMMA:         return GLFW_KEY_COMMA;
-        case KEY_DOT:           return GLFW_KEY_PERIOD;
-        case KEY_SLASH:         return GLFW_KEY_SLASH;
-        case KEY_BACKSLASH:     return GLFW_KEY_BACKSLASH;
-        case KEY_ESC:           return GLFW_KEY_ESCAPE;
-        case KEY_TAB:           return GLFW_KEY_TAB;
-        case KEY_LEFTSHIFT:     return GLFW_KEY_LEFT_SHIFT;
-        case KEY_RIGHTSHIFT:    return GLFW_KEY_RIGHT_SHIFT;
-        case KEY_LEFTCTRL:      return GLFW_KEY_LEFT_CONTROL;
-        case KEY_RIGHTCTRL:     return GLFW_KEY_RIGHT_CONTROL;
-        case KEY_LEFTALT:       return GLFW_KEY_LEFT_ALT;
-        case KEY_RIGHTALT:      return GLFW_KEY_RIGHT_ALT;
-        case KEY_LEFTMETA:      return GLFW_KEY_LEFT_SUPER;
-        case KEY_RIGHTMETA:     return GLFW_KEY_RIGHT_SUPER;
-        case KEY_MENU:          return GLFW_KEY_MENU;
-        case KEY_NUMLOCK:       return GLFW_KEY_NUM_LOCK;
-        case KEY_CAPSLOCK:      return GLFW_KEY_CAPS_LOCK;
-        case KEY_PRINT:         return GLFW_KEY_PRINT_SCREEN;
-        case KEY_SCROLLLOCK:    return GLFW_KEY_SCROLL_LOCK;
-        case KEY_PAUSE:         return GLFW_KEY_PAUSE;
-        case KEY_DELETE:        return GLFW_KEY_DELETE;
-        case KEY_BACKSPACE:     return GLFW_KEY_BACKSPACE;
-        case KEY_ENTER:         return GLFW_KEY_ENTER;
-        case KEY_HOME:          return GLFW_KEY_HOME;
-        case KEY_END:           return GLFW_KEY_END;
-        case KEY_PAGEUP:        return GLFW_KEY_PAGE_UP;
-        case KEY_PAGEDOWN:      return GLFW_KEY_PAGE_DOWN;
-        case KEY_INSERT:        return GLFW_KEY_INSERT;
-        case KEY_LEFT:          return GLFW_KEY_LEFT;
-        case KEY_RIGHT:         return GLFW_KEY_RIGHT;
-        case KEY_DOWN:          return GLFW_KEY_DOWN;
-        case KEY_UP:            return GLFW_KEY_UP;
-        case KEY_F1:            return GLFW_KEY_F1;
-        case KEY_F2:            return GLFW_KEY_F2;
-        case KEY_F3:            return GLFW_KEY_F3;
-        case KEY_F4:            return GLFW_KEY_F4;
-        case KEY_F5:            return GLFW_KEY_F5;
-        case KEY_F6:            return GLFW_KEY_F6;
-        case KEY_F7:            return GLFW_KEY_F7;
-        case KEY_F8:            return GLFW_KEY_F8;
-        case KEY_F9:            return GLFW_KEY_F9;
-        case KEY_F10:           return GLFW_KEY_F10;
-        case KEY_F11:           return GLFW_KEY_F11;
-        case KEY_F12:           return GLFW_KEY_F12;
-        case KEY_F13:           return GLFW_KEY_F13;
-        case KEY_F14:           return GLFW_KEY_F14;
-        case KEY_F15:           return GLFW_KEY_F15;
-        case KEY_F16:           return GLFW_KEY_F16;
-        case KEY_F17:           return GLFW_KEY_F17;
-        case KEY_F18:           return GLFW_KEY_F18;
-        case KEY_F19:           return GLFW_KEY_F19;
-        case KEY_F20:           return GLFW_KEY_F20;
-        case KEY_F21:           return GLFW_KEY_F21;
-        case KEY_F22:           return GLFW_KEY_F22;
-        case KEY_F23:           return GLFW_KEY_F23;
-        case KEY_F24:           return GLFW_KEY_F24;
-        case KEY_KPSLASH:       return GLFW_KEY_KP_DIVIDE;
-        case KEY_KPDOT:         return GLFW_KEY_KP_MULTIPLY;
-        case KEY_KPMINUS:       return GLFW_KEY_KP_SUBTRACT;
-        case KEY_KPPLUS:        return GLFW_KEY_KP_ADD;
-        case KEY_KP0:           return GLFW_KEY_KP_0;
-        case KEY_KP1:           return GLFW_KEY_KP_1;
-        case KEY_KP2:           return GLFW_KEY_KP_2;
-        case KEY_KP3:           return GLFW_KEY_KP_3;
-        case KEY_KP4:           return GLFW_KEY_KP_4;
-        case KEY_KP5:           return GLFW_KEY_KP_5;
-        case KEY_KP6:           return GLFW_KEY_KP_6;
-        case KEY_KP7:           return GLFW_KEY_KP_7;
-        case KEY_KP8:           return GLFW_KEY_KP_8;
-        case KEY_KP9:           return GLFW_KEY_KP_9;
-        case KEY_KPCOMMA:       return GLFW_KEY_KP_DECIMAL;
-        case KEY_KPEQUAL:       return GLFW_KEY_KP_EQUAL;
-        case KEY_KPENTER:       return GLFW_KEY_KP_ENTER;
-        default:                return GLFW_KEY_UNKNOWN;
-    }
+    if (key < sizeof(_glfw.mir.publicKeys) / sizeof(_glfw.mir.publicKeys[0]))
+        return _glfw.mir.publicKeys[key];
+
+    return GLFW_KEY_UNKNOWN;
 }
 
-static void handleKeyEvent(const MirKeyEvent key, _GLFWwindow* window)
+static void handleKeyEvent(const MirKeyboardEvent* key_event, _GLFWwindow* window)
 {
-    const int pressed = key.action == mir_key_action_up ? GLFW_RELEASE : GLFW_PRESS;
-    const int mods = mirModToGLFWMod(key.modifiers);
-    const long text = _glfwKeySym2Unicode(key.key_code);
-    const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
+    const int action    = mir_keyboard_event_action   (key_event);
+    const int scan_code = mir_keyboard_event_scan_code(key_event);
+    const int key_code  = mir_keyboard_event_key_code (key_event);
+    const int modifiers = mir_keyboard_event_modifiers(key_event);
 
-    _glfwInputKey(window, toGLFWKeyCode(key.scan_code), key.scan_code, pressed, mods);
+    const int  pressed = action == mir_keyboard_action_up ? GLFW_RELEASE : GLFW_PRESS;
+    const int  mods    = mirModToGLFWMod(modifiers);
+    const long text    = _glfwKeySym2Unicode(key_code);
+    const int  plain   = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
 
+    _glfwInputKey(window, toGLFWKeyCode(scan_code), scan_code, pressed, mods);
+
     if (text != -1)
         _glfwInputChar(window, text, mods, plain);
 }
 
-static void handleMouseButton(_GLFWwindow* window,
-                              int pressed, int mods, MirMotionButton button)
+static void handlePointerButton(_GLFWwindow* window,
+                              int pressed,
+                              const MirPointerEvent* pointer_event)
 {
-    static int lastButton;
-    int publicButton;
-    const int publicMods = mirModToGLFWMod(mods);
+    int mods                = mir_pointer_event_modifiers(pointer_event);
+    const int publicMods    = mirModToGLFWMod(mods);
+    MirPointerButton button = mir_pointer_button_primary;
+    static uint32_t oldButtonStates = 0;
+    uint32_t newButtonStates        = mir_pointer_event_buttons(pointer_event);
+    int publicButton                = GLFW_MOUSE_BUTTON_LEFT;
 
+    // XOR our old button states our new states to figure out what was added or removed
+    button = newButtonStates ^ oldButtonStates;
+
     switch (button)
     {
-        case mir_motion_button_primary:
+        case mir_pointer_button_primary:
             publicButton = GLFW_MOUSE_BUTTON_LEFT;
             break;
-        case mir_motion_button_secondary:
+        case mir_pointer_button_secondary:
             publicButton = GLFW_MOUSE_BUTTON_RIGHT;
             break;
-        case mir_motion_button_tertiary:
+        case mir_pointer_button_tertiary:
             publicButton = GLFW_MOUSE_BUTTON_MIDDLE;
             break;
-        case mir_motion_button_forward:
+        case mir_pointer_button_forward:
             // FIXME What is the forward button?
             publicButton = GLFW_MOUSE_BUTTON_4;
             break;
-        case mir_motion_button_back:
+        case mir_pointer_button_back:
             // FIXME What is the back button?
             publicButton = GLFW_MOUSE_BUTTON_5;
             break;
         default:
-            publicButton = lastButton;
             break;
     }
 
-    lastButton = publicButton;
+    oldButtonStates = newButtonStates;
 
     _glfwInputMouseClick(window, publicButton, pressed, publicMods);
 }
 
-static void handleMouseMotion(_GLFWwindow* window, int x, int y)
+static void handlePointerMotion(_GLFWwindow* window,
+                                const MirPointerEvent* pointer_event)
 {
-    _glfwInputCursorMotion(window, x, y);
-}
+    int current_x = window->virtualCursorPosX;
+    int current_y = window->virtualCursorPosY;
+    int x  = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_x);
+    int y  = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_y);
+    int dx = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_hscroll);
+    int dy = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_vscroll);
 
-static void handleMouseScroll(_GLFWwindow* window, int dx, int dy)
-{
-    _glfwInputScroll(window, dx, dy);
+    _glfwInputCursorPos(window, x, y);
+    if (dx != 0 || dy != 0)
+      _glfwInputScroll(window, dx, dy);
 }
 
-static void handleMouseEvent(const MirMotionEvent motion,
-                             int cord_index,
+static void handlePointerEvent(const MirPointerEvent* pointer_event,
                              _GLFWwindow* window)
 {
-    switch (motion.action)
+    int action = mir_pointer_event_action(pointer_event);
+
+    switch (action)
     {
-          case mir_motion_action_down:
-          case mir_motion_action_pointer_down:
-              handleMouseButton(window, GLFW_PRESS,
-                                motion.modifiers, motion.button_state);
-              break;
-          case mir_motion_action_up:
-          case mir_motion_action_pointer_up:
-              handleMouseButton(window, GLFW_RELEASE,
-                                motion.modifiers, motion.button_state);
-              break;
-          case mir_motion_action_hover_move:
-          case mir_motion_action_move:
-              handleMouseMotion(window,
-                                motion.pointer_coordinates[cord_index].x,
-                                motion.pointer_coordinates[cord_index].y);
+          case mir_pointer_action_button_down:
+              handlePointerButton(window, GLFW_PRESS, pointer_event);
               break;
-          case mir_motion_action_outside:
+          case mir_pointer_action_button_up:
+              handlePointerButton(window, GLFW_RELEASE, pointer_event);
               break;
-          case mir_motion_action_scroll:
-              handleMouseScroll(window,
-                                motion.pointer_coordinates[cord_index].hscroll,
-                                motion.pointer_coordinates[cord_index].vscroll);
+          case mir_pointer_action_motion:
+              handlePointerMotion(window, pointer_event);
               break;
-          case mir_motion_action_cancel:
-          case mir_motion_action_hover_enter:
-          case mir_motion_action_hover_exit:
+          case mir_pointer_action_enter:
+          case mir_pointer_action_leave:
               break;
           default:
               break;
@@ -349,85 +238,90 @@
     }
 }
 
-static void handleMotionEvent(const MirMotionEvent motion, _GLFWwindow* window)
+static void handleInput(const MirInputEvent* input_event, _GLFWwindow* window)
 {
-    int i;
-    for (i = 0;  i < motion.pointer_count;  i++)
-        handleMouseEvent(motion, i, window);
+    int type = mir_input_event_get_type(input_event);
+
+    switch (type)
+    {
+        case mir_input_event_type_key:
+            handleKeyEvent(mir_input_event_get_keyboard_event(input_event), window);
+            break;
+        case mir_input_event_type_pointer:
+            handlePointerEvent(mir_input_event_get_pointer_event(input_event), window);
+            break;
+        default:
+            break;
+    }
 }
 
-static void handleInput(MirEvent const* event, _GLFWwindow* window)
+static void handleEvent(const MirEvent* event, _GLFWwindow* window)
 {
-    switch (event->type)
+    int type = mir_event_get_type(event);
+
+    switch (type)
     {
-        case mir_event_type_key:
-            handleKeyEvent(event->key, window);
-            break;
-        case mir_event_type_motion:
-            handleMotionEvent(event->motion, window);
+        case mir_event_type_input:
+            handleInput(mir_event_get_input_event(event), window);
             break;
         default:
             break;
     }
 }
 
-static void addNewEvent(MirSurface* surface, MirEvent const* event, void* context)
+static void addNewEvent(MirSurface* surface, const MirEvent* event, void* context)
 {
     enqueueEvent(event, context);
 }
 
-static int createSurface(_GLFWwindow* window)
+static GLFWbool createSurface(_GLFWwindow* window)
 {
-    MirSurfaceParameters params =
-    {
-        .name         = "MirSurface",
-        .width        = window->mir.width,
-        .height       = window->mir.height,
-        .pixel_format = mir_pixel_format_invalid,
-        .buffer_usage = mir_buffer_usage_hardware,
-        .output_id    = mir_display_output_id_invalid
-    };
-
-    MirEventDelegate delegate =
-    {
-        addNewEvent,
-        window
-    };
+    MirSurfaceSpec* spec;
+    MirBufferUsage buffer_usage = mir_buffer_usage_hardware;
+    MirPixelFormat pixel_format = findValidPixelFormat();
 
-    params.pixel_format = findValidPixelFormat();
-    if (params.pixel_format == mir_pixel_format_invalid)
+    if (pixel_format == mir_pixel_format_invalid)
     {
         _glfwInputError(GLFW_PLATFORM_ERROR,
                         "Mir: Unable to find a correct pixel format");
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
+ 
+    spec = mir_connection_create_spec_for_normal_surface(_glfw.mir.connection,
+                                                         window->mir.width,
+                                                         window->mir.height,
+                                                         pixel_format);
 
-    window->mir.surface =
-        mir_connection_create_surface_sync(_glfw.mir.connection, &params);
+    mir_surface_spec_set_buffer_usage(spec, buffer_usage);
+    mir_surface_spec_set_name(spec, "MirSurface");
+
+    window->mir.surface = mir_surface_create_sync(spec);
+    mir_surface_spec_release(spec);
+
     if (!mir_surface_is_valid(window->mir.surface))
     {
         _glfwInputError(GLFW_PLATFORM_ERROR,
                         "Mir: Unable to create surface: %s",
                         mir_surface_get_error_message(window->mir.surface));
 
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
 
-    mir_surface_set_event_handler(window->mir.surface, &delegate);
+    mir_surface_set_event_handler(window->mir.surface, addNewEvent, window);
 
-    return GL_TRUE;
+    return GLFW_TRUE;
 }
 
 //////////////////////////////////////////////////////////////////////////
 //////                       GLFW internal API                      //////
 //////////////////////////////////////////////////////////////////////////
 
-void _glfwInitEventQueue(EventQueue* queue)
+void _glfwInitEventQueueMir(EventQueue* queue)
 {
     TAILQ_INIT(&queue->head);
 }
 
-void _glfwDeleteEventQueue(EventQueue* queue)
+void _glfwDeleteEventQueueMir(EventQueue* queue)
 {
     if (queue)
     {
@@ -457,23 +351,20 @@
                               const _GLFWctxconfig* ctxconfig,
                               const _GLFWfbconfig* fbconfig)
 {
-    if (!_glfwCreateContext(window, ctxconfig, fbconfig))
-        return GL_FALSE;
-
-    if (wndconfig->monitor)
+    if (window->monitor)
     {
         GLFWvidmode mode;
-        _glfwPlatformGetVideoMode(wndconfig->monitor, &mode);
+        _glfwPlatformGetVideoMode(window->monitor, &mode);
 
         mir_surface_set_state(window->mir.surface, mir_surface_state_fullscreen);
 
         if (wndconfig->width > mode.width || wndconfig->height > mode.height)
         {
             _glfwInputError(GLFW_PLATFORM_ERROR,
-                            "Mir: Requested surface size is to large (%i %i)",
-                             wndconfig->width, wndconfig->height);
+                            "Mir: Requested surface size too large: %ix%i",
+                            wndconfig->width, wndconfig->height);
 
-            return GL_FALSE;
+            return GLFW_FALSE;
         }
     }
 
@@ -481,11 +372,20 @@
     window->mir.height = wndconfig->height;
 
     if (!createSurface(window))
-        return GL_FALSE;
+        return GLFW_FALSE;
 
-    window->mir.window = mir_surface_get_egl_native_window(window->mir.surface);
+    window->mir.window = mir_buffer_stream_get_egl_native_window(
+                                   mir_surface_get_buffer_stream(window->mir.surface));
 
-    return GL_TRUE;
+    if (ctxconfig->client != GLFW_NO_API)
+    {
+        if (!_glfwInitEGL())
+            return GLFW_FALSE;
+        if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
+            return GLFW_FALSE;
+    }
+
+    return GLFW_TRUE;
 }
 
 void _glfwPlatformDestroyWindow(_GLFWwindow* window)
@@ -496,19 +396,59 @@
         window->mir.surface = NULL;
     }
 
-    _glfwDestroyContext(window);
+    if (window->context.destroy)
+        window->context.destroy(window);
 }
 
 void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
 {
+    MirSurfaceSpec* spec;
+    const char* e_title = title ? title : "";
+
+    spec = mir_connection_create_spec_for_changes(_glfw.mir.connection);
+    mir_surface_spec_set_name(spec, e_title);
+
+    mir_surface_apply_spec(window->mir.surface, spec);
+    mir_surface_spec_release(spec);
+}
+
+void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
+                                int count, const GLFWimage* images)
+{
     _glfwInputError(GLFW_PLATFORM_ERROR,
-                    "Mir: Unsupported function %s!", __PRETTY_FUNCTION__);
+                    "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
 }
 
+void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
+{
+    MirSurfaceSpec* spec;
+
+    spec = mir_connection_create_spec_for_changes(_glfw.mir.connection);
+    mir_surface_spec_set_width (spec, width);
+    mir_surface_spec_set_height(spec, height);
+
+    mir_surface_apply_spec(window->mir.surface, spec);
+    mir_surface_spec_release(spec);
+}
+
+void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
+                                      int minwidth, int minheight,
+                                      int maxwidth, int maxheight)
+{
+    _glfwInputError(GLFW_PLATFORM_ERROR,
+                    "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
+}
+
+void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom)
+{
+    _glfwInputError(GLFW_PLATFORM_ERROR,
+                    "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
+}
+
 void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
 {
     _glfwInputError(GLFW_PLATFORM_ERROR,
-                    "Mir: Unsupported function %s!", __PRETTY_FUNCTION__);
+                    "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
 }
 
 void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
@@ -516,19 +456,13 @@
                                      int* right, int* bottom)
 {
     _glfwInputError(GLFW_PLATFORM_ERROR,
-                    "Mir: Unsupported function %s!", __PRETTY_FUNCTION__);
+                    "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
 }
 
 void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
 {
     _glfwInputError(GLFW_PLATFORM_ERROR,
-                    "Mir: Unsupported function %s!", __PRETTY_FUNCTION__);
-}
-
-void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
-{
-    _glfwInputError(GLFW_PLATFORM_ERROR,
-                    "Mir: Unsupported function %s!", __PRETTY_FUNCTION__);
+                    "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
 }
 
 void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
@@ -549,43 +483,74 @@
     mir_surface_set_state(window->mir.surface, mir_surface_state_restored);
 }
 
-void _glfwPlatformHideWindow(_GLFWwindow* window)
+void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
 {
     _glfwInputError(GLFW_PLATFORM_ERROR,
-                    "Mir: Unsupported function %s!", __PRETTY_FUNCTION__);
+                    "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
 }
 
+void _glfwPlatformHideWindow(_GLFWwindow* window)
+{
+    MirSurfaceSpec* spec;
+
+    spec = mir_connection_create_spec_for_changes(_glfw.mir.connection);
+    mir_surface_spec_set_state(spec, mir_surface_state_hidden);
+
+    mir_surface_apply_spec(window->mir.surface, spec);
+    mir_surface_spec_release(spec);
+}
+
 void _glfwPlatformShowWindow(_GLFWwindow* window)
 {
+    MirSurfaceSpec* spec;
+
+    spec = mir_connection_create_spec_for_changes(_glfw.mir.connection);
+    mir_surface_spec_set_state(spec, mir_surface_state_restored);
+
+    mir_surface_apply_spec(window->mir.surface, spec);
+    mir_surface_spec_release(spec);
+}
+
+void _glfwPlatformFocusWindow(_GLFWwindow* window)
+{
     _glfwInputError(GLFW_PLATFORM_ERROR,
-                    "Mir: Unsupported function %s!", __PRETTY_FUNCTION__);
+                    "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
 }
 
-void _glfwPlatformUnhideWindow(_GLFWwindow* window)
+void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
+                                   _GLFWmonitor* monitor,
+                                   int xpos, int ypos,
+                                   int width, int height,
+                                   int refreshRate)
 {
     _glfwInputError(GLFW_PLATFORM_ERROR,
-                    "Mir: Unsupported function %s!", __PRETTY_FUNCTION__);
+                    "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
 }
 
 int _glfwPlatformWindowFocused(_GLFWwindow* window)
 {
     _glfwInputError(GLFW_PLATFORM_ERROR,
-                    "Mir: Unsupported function %s!", __PRETTY_FUNCTION__);
-    return GL_FALSE;
+                    "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
+    return GLFW_FALSE;
 }
 
 int _glfwPlatformWindowIconified(_GLFWwindow* window)
 {
     _glfwInputError(GLFW_PLATFORM_ERROR,
-                    "Mir: Unsupported function %s!", __PRETTY_FUNCTION__);
-    return GL_FALSE;
+                    "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
+    return GLFW_FALSE;
 }
 
 int _glfwPlatformWindowVisible(_GLFWwindow* window)
 {
+    return mir_surface_get_visibility(window->mir.surface) == mir_surface_visibility_exposed;
+}
+
+int _glfwPlatformWindowMaximized(_GLFWwindow* window)
+{
     _glfwInputError(GLFW_PLATFORM_ERROR,
-                    "Mir: Unsupported function %s!", __PRETTY_FUNCTION__);
-    return GL_FALSE;
+                    "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
+    return GLFW_FALSE;
 }
 
 void _glfwPlatformPollEvents(void)
@@ -594,7 +559,7 @@
 
     while ((node = dequeueEvent(_glfw.mir.event_queue)))
     {
-        handleInput(node->event, node->window);
+        handleEvent(node->event, node->window);
         deleteNode(_glfw.mir.event_queue, node);
     }
 }
@@ -611,6 +576,24 @@
     _glfwPlatformPollEvents();
 }
 
+void _glfwPlatformWaitEventsTimeout(double timeout)
+{
+    pthread_mutex_lock(&_glfw.mir.event_mutex);
+
+    if (emptyEventQueue(_glfw.mir.event_queue))
+    {
+        struct timespec time;
+        clock_gettime(CLOCK_REALTIME, &time);
+        time.tv_sec += (long) timeout;
+        time.tv_nsec += (long) ((timeout - (long) timeout) * 1e9);
+        pthread_cond_timedwait(&_glfw.mir.event_cond, &_glfw.mir.event_mutex, &time);
+    }
+
+    pthread_mutex_unlock(&_glfw.mir.event_mutex);
+
+    _glfwPlatformPollEvents();
+}
+
 void _glfwPlatformPostEmptyEvent(void)
 {
 }
@@ -623,65 +606,243 @@
         *height = window->mir.height;
 }
 
+// FIXME implement
 int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
                               const GLFWimage* image,
                               int xhot, int yhot)
 {
-    _glfwInputError(GLFW_PLATFORM_ERROR,
-                    "Mir: Unsupported function %s!", __PRETTY_FUNCTION__);
+    MirBufferStream* stream;
+    MirPixelFormat pixel_format = findValidPixelFormat();
 
-    return GL_FALSE;
+    int i_w = image->width;
+    int i_h = image->height;
+
+    if (pixel_format == mir_pixel_format_invalid)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Mir: Unable to find a correct pixel format");
+        return GLFW_FALSE;
+    }
+
+    stream = mir_connection_create_buffer_stream_sync(_glfw.mir.connection,
+                                                      i_w, i_h,
+                                                      pixel_format,
+                                                      mir_buffer_usage_software);
+
+    cursor->mir.conf = mir_cursor_configuration_from_buffer_stream(stream, xhot, yhot);
+
+    char* dest;
+    unsigned char *pixels;
+    int i, r_stride, bytes_per_pixel, bytes_per_row;
+
+    MirGraphicsRegion region;
+    mir_buffer_stream_get_graphics_region(stream, &region);
+
+    // FIXME Figure this out based on the current_pf
+    bytes_per_pixel = 4;
+    bytes_per_row   = bytes_per_pixel * i_w;
+
+    dest   = region.vaddr;
+    pixels = image->pixels;
+
+    r_stride = region.stride;
+
+    for (i = 0; i < i_h; i++)
+    {
+        memcpy(dest, pixels, bytes_per_row);
+        dest   += r_stride;
+        pixels += r_stride;
+    }
+
+    cursor->mir.custom_cursor = stream;
+
+    return GLFW_TRUE;
 }
 
+const char* getSystemCursorName(int shape)
+{
+    switch (shape)
+    {
+        case GLFW_ARROW_CURSOR:
+            return mir_arrow_cursor_name;
+        case GLFW_IBEAM_CURSOR:
+            return mir_caret_cursor_name;
+        case GLFW_CROSSHAIR_CURSOR:
+            return mir_crosshair_cursor_name;
+        case GLFW_HAND_CURSOR:
+            return mir_open_hand_cursor_name;
+        case GLFW_HRESIZE_CURSOR:
+            return mir_horizontal_resize_cursor_name;
+        case GLFW_VRESIZE_CURSOR:
+            return mir_vertical_resize_cursor_name;
+    }
+
+    return NULL;
+}
+
 int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
 {
-    _glfwInputError(GLFW_PLATFORM_ERROR,
-                    "Mir: Unsupported function %s!", __PRETTY_FUNCTION__);
+    const char* cursor_name = getSystemCursorName(shape);
 
-    return GL_FALSE;
+    if (cursor_name)
+    {
+        cursor->mir.conf          = mir_cursor_configuration_from_name(cursor_name);
+        cursor->mir.custom_cursor = NULL;
+
+        return GLFW_TRUE;
+    }
+
+    return GLFW_FALSE;
 }
 
 void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
 {
-    _glfwInputError(GLFW_PLATFORM_ERROR,
-                    "Mir: Unsupported function %s!", __PRETTY_FUNCTION__);
+    if (cursor->mir.conf)
+        mir_cursor_configuration_destroy(cursor->mir.conf);
+    if (cursor->mir.custom_cursor)
+        mir_buffer_stream_release_sync(cursor->mir.custom_cursor);
 }
 
 void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
 {
-    _glfwInputError(GLFW_PLATFORM_ERROR,
-                    "Mir: Unsupported function %s!", __PRETTY_FUNCTION__);
+    if (cursor && cursor->mir.conf)
+    {
+        mir_wait_for(mir_surface_configure_cursor(window->mir.surface, cursor->mir.conf));
+        if (cursor->mir.custom_cursor)
+        {
+            mir_buffer_stream_swap_buffers_sync(cursor->mir.custom_cursor);
+        }
+    }
+    else
+    {
+        mir_wait_for(mir_surface_configure_cursor(window->mir.surface, _glfw.mir.default_conf));
+    }
 }
 
 void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
 {
     _glfwInputError(GLFW_PLATFORM_ERROR,
-                    "Mir: Unsupported function %s!", __PRETTY_FUNCTION__);
+                    "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
 }
 
 void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos)
 {
     _glfwInputError(GLFW_PLATFORM_ERROR,
-                    "Mir: Unsupported function %s!", __PRETTY_FUNCTION__);
+                    "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
 }
 
-void _glfwPlatformApplyCursorMode(_GLFWwindow* window)
+void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
 {
     _glfwInputError(GLFW_PLATFORM_ERROR,
-                    "Mir: Unsupported function %s!", __PRETTY_FUNCTION__);
+                    "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
 }
 
+const char* _glfwPlatformGetKeyName(int key, int scancode)
+{
+    _glfwInputError(GLFW_PLATFORM_ERROR,
+                    "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
+    return NULL;
+}
+
 void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
 {
     _glfwInputError(GLFW_PLATFORM_ERROR,
-                    "Mir: Unsupported function %s!", __PRETTY_FUNCTION__);
+                    "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
 }
 
 const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
 {
     _glfwInputError(GLFW_PLATFORM_ERROR,
-                    "Mir: Unsupported function %s!", __PRETTY_FUNCTION__);
+                    "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
 
     return NULL;
+}
+
+char** _glfwPlatformGetRequiredInstanceExtensions(uint32_t* count)
+{
+    char** extensions;
+
+    *count = 0;
+
+    if (!_glfw.vk.KHR_mir_surface)
+        return NULL;
+
+    extensions = calloc(2, sizeof(char*));
+    extensions[0] = strdup("VK_KHR_surface");
+    extensions[1] = strdup("VK_KHR_mir_surface");
+
+    *count = 2;
+    return extensions;
+}
+
+int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
+                                                      VkPhysicalDevice device,
+                                                      uint32_t queuefamily)
+{
+    PFN_vkGetPhysicalDeviceMirPresentationSupportKHR vkGetPhysicalDeviceMirPresentationSupportKHR =
+        (PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)
+        vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceMirPresentationSupportKHR");
+    if (!vkGetPhysicalDeviceMirPresentationSupportKHR)
+    {
+        _glfwInputError(GLFW_API_UNAVAILABLE,
+                        "Mir: Vulkan instance missing VK_KHR_mir_surface extension");
+        return GLFW_FALSE;
+    }
+
+    return vkGetPhysicalDeviceMirPresentationSupportKHR(device,
+                                                        queuefamily,
+                                                        _glfw.mir.connection);
+}
+
+VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
+                                          _GLFWwindow* window,
+                                          const VkAllocationCallbacks* allocator,
+                                          VkSurfaceKHR* surface)
+{
+    VkResult err;
+    VkMirSurfaceCreateInfoKHR sci;
+    PFN_vkCreateMirSurfaceKHR vkCreateMirSurfaceKHR;
+
+    vkCreateMirSurfaceKHR = (PFN_vkCreateMirSurfaceKHR)
+        vkGetInstanceProcAddr(instance, "vkCreateMirSurfaceKHR");
+    if (!vkCreateMirSurfaceKHR)
+    {
+        _glfwInputError(GLFW_API_UNAVAILABLE,
+                        "Mir: Vulkan instance missing VK_KHR_mir_surface extension");
+        return VK_ERROR_EXTENSION_NOT_PRESENT;
+    }
+
+    memset(&sci, 0, sizeof(sci));
+    sci.sType = VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR;
+    sci.connection = _glfw.mir.connection;
+    sci.mirSurface = window->mir.surface;
+
+    err = vkCreateMirSurfaceKHR(instance, &sci, allocator, surface);
+    if (err)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Mir: Failed to create Vulkan surface: %s",
+                        _glfwGetVulkanResultString(err));
+    }
+
+    return err;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                        GLFW native API                       //////
+//////////////////////////////////////////////////////////////////////////
+
+GLFWAPI MirConnection* glfwGetMirDisplay(void)
+{
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+    return _glfw.mir.connection;
+}
+
+GLFWAPI MirSurface* glfwGetMirWindow(GLFWwindow* handle)
+{
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+    return window->mir.surface;
 }
 
diff --git a/glfw/src/monitor.c b/glfw/src/monitor.c
--- a/glfw/src/monitor.c
+++ b/glfw/src/monitor.c
@@ -1,8 +1,8 @@
 //========================================================================
-// GLFW 3.1 - www.glfw.org
+// GLFW 3.2 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -27,7 +27,9 @@
 
 #include "internal.h"
 
+#include <assert.h>
 #include <math.h>
+#include <float.h>
 #include <string.h>
 #include <stdlib.h>
 #include <limits.h>
@@ -37,43 +39,42 @@
 #define strdup _strdup
 #endif
 
-// Lexical comparison function for GLFW video modes, used by qsort
+// Lexically compare video modes, used by qsort
 //
-static int compareVideoModes(const void* firstPtr, const void* secondPtr)
+static int compareVideoModes(const void* fp, const void* sp)
 {
-    int firstBPP, secondBPP, firstSize, secondSize;
-    const GLFWvidmode* first = firstPtr;
-    const GLFWvidmode* second = secondPtr;
+    const GLFWvidmode* fm = fp;
+    const GLFWvidmode* sm = sp;
+    const int fbpp = fm->redBits + fm->greenBits + fm->blueBits;
+    const int sbpp = sm->redBits + sm->greenBits + sm->blueBits;
+    const int farea = fm->width * fm->height;
+    const int sarea = sm->width * sm->height;
 
     // First sort on color bits per pixel
-    firstBPP = first->redBits + first->greenBits + first->blueBits;
-    secondBPP = second->redBits + second->greenBits + second->blueBits;
-    if (firstBPP != secondBPP)
-        return firstBPP - secondBPP;
+    if (fbpp != sbpp)
+        return fbpp - sbpp;
 
-    // Then sort on screen area, in pixels
-    firstSize = first->width * first->height;
-    secondSize = second->width * second->height;
-    if (firstSize != secondSize)
-        return firstSize - secondSize;
+    // Then sort on screen area
+    if (farea != sarea)
+        return farea - sarea;
 
     // Lastly sort on refresh rate
-    return first->refreshRate - second->refreshRate;
+    return fm->refreshRate - sm->refreshRate;
 }
 
 // Retrieves the available modes for the specified monitor
 //
-static int refreshVideoModes(_GLFWmonitor* monitor)
+static GLFWbool refreshVideoModes(_GLFWmonitor* monitor)
 {
     int modeCount;
     GLFWvidmode* modes;
 
     if (monitor->modes)
-        return GL_TRUE;
+        return GLFW_TRUE;
 
     modes = _glfwPlatformGetVideoModes(monitor, &modeCount);
     if (!modes)
-        return GL_FALSE;
+        return GLFW_FALSE;
 
     qsort(modes, modeCount, sizeof(GLFWvidmode), compareVideoModes);
 
@@ -81,7 +82,7 @@
     monitor->modes = modes;
     monitor->modeCount = modeCount;
 
-    return GL_TRUE;
+    return GLFW_TRUE;
 }
 
 
@@ -129,7 +130,11 @@
         for (window = _glfw.windowListHead;  window;  window = window->next)
         {
             if (window->monitor == monitors[i])
-                window->monitor = NULL;
+            {
+                int width, height;
+                _glfwPlatformGetWindowSize(window, &width, &height);
+                _glfwPlatformSetWindowMonitor(window, NULL, 0, 0, width, height, 0);
+            }
         }
 
         if (_glfw.callbacks.monitor)
@@ -161,7 +166,12 @@
     _glfwFreeMonitors(monitors, monitorCount);
 }
 
+void _glfwInputMonitorWindowChange(_GLFWmonitor* monitor, _GLFWwindow* window)
+{
+    monitor->window = window;
+}
 
+
 //////////////////////////////////////////////////////////////////////////
 //////                       GLFW internal API                      //////
 //////////////////////////////////////////////////////////////////////////
@@ -266,9 +276,9 @@
     return closest;
 }
 
-int _glfwCompareVideoModes(const GLFWvidmode* first, const GLFWvidmode* second)
+int _glfwCompareVideoModes(const GLFWvidmode* fm, const GLFWvidmode* sm)
 {
-    return compareVideoModes(first, second);
+    return compareVideoModes(fm, sm);
 }
 
 void _glfwSplitBPP(int bpp, int* red, int* green, int* blue)
@@ -297,6 +307,7 @@
 
 GLFWAPI GLFWmonitor** glfwGetMonitors(int* count)
 {
+    assert(count != NULL);
     *count = 0;
 
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
@@ -308,12 +319,17 @@
 GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void)
 {
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+
+    if (!_glfw.monitorCount)
+        return NULL;
+
     return (GLFWmonitor*) _glfw.monitors[0];
 }
 
 GLFWAPI void glfwGetMonitorPos(GLFWmonitor* handle, int* xpos, int* ypos)
 {
     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
+    assert(monitor != NULL);
 
     if (xpos)
         *xpos = 0;
@@ -328,6 +344,7 @@
 GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* handle, int* widthMM, int* heightMM)
 {
     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
+    assert(monitor != NULL);
 
     if (widthMM)
         *widthMM = 0;
@@ -345,6 +362,8 @@
 GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* handle)
 {
     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
+    assert(monitor != NULL);
+
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     return monitor->name;
 }
@@ -359,6 +378,8 @@
 GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* handle, int* count)
 {
     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
+    assert(monitor != NULL);
+    assert(count != NULL);
 
     *count = 0;
 
@@ -374,6 +395,7 @@
 GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* handle)
 {
     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
+    assert(monitor != NULL);
 
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
 
@@ -389,10 +411,9 @@
 
     _GLFW_REQUIRE_INIT();
 
-    if (gamma <= 0.f)
+    if (gamma != gamma || gamma <= 0.f || gamma > FLT_MAX)
     {
-        _glfwInputError(GLFW_INVALID_VALUE,
-                        "Gamma value must be greater than zero");
+        _glfwInputError(GLFW_INVALID_VALUE, "Invalid gamma value %f", gamma);
         return;
     }
 
@@ -423,6 +444,7 @@
 GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle)
 {
     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
+    assert(monitor != NULL);
 
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
 
@@ -435,6 +457,19 @@
 GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp)
 {
     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
+    assert(monitor != NULL);
+    assert(ramp != NULL);
+    assert(ramp->red != NULL);
+    assert(ramp->green != NULL);
+    assert(ramp->blue != NULL);
+
+    if (ramp->size <= 0)
+    {
+        _glfwInputError(GLFW_INVALID_VALUE,
+                        "Invalid gamma ramp size %i",
+                        ramp->size);
+        return;
+    }
 
     _GLFW_REQUIRE_INIT();
 
diff --git a/glfw/src/nsgl_context.h b/glfw/src/nsgl_context.h
--- a/glfw/src/nsgl_context.h
+++ b/glfw/src/nsgl_context.h
@@ -1,7 +1,7 @@
 //========================================================================
-// GLFW 3.1 OS X - www.glfw.org
+// GLFW 3.2 OS X - www.glfw.org
 //------------------------------------------------------------------------
-// Copyright (c) 2009-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2009-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -24,10 +24,9 @@
 //
 //========================================================================
 
-#ifndef _nsgl_context_h_
-#define _nsgl_context_h_
+#ifndef _glfw3_nsgl_context_h_
+#define _glfw3_nsgl_context_h_
 
-#define _GLFW_PLATFORM_FBCONFIG
 #define _GLFW_PLATFORM_CONTEXT_STATE            _GLFWcontextNSGL nsgl
 #define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE    _GLFWlibraryNSGL nsgl
 
@@ -37,26 +36,25 @@
 typedef struct _GLFWcontextNSGL
 {
     id           pixelFormat;
-    id	         context;
+    id	         object;
 
 } _GLFWcontextNSGL;
 
-
 // NSGL-specific global data
 //
 typedef struct _GLFWlibraryNSGL
 {
     // dlopen handle for OpenGL.framework (for glfwGetProcAddress)
-    void*           framework;
+    CFBundleRef     framework;
 
 } _GLFWlibraryNSGL;
 
 
-int _glfwInitContextAPI(void);
-void _glfwTerminateContextAPI(void);
-int _glfwCreateContext(_GLFWwindow* window,
-                       const _GLFWctxconfig* ctxconfig,
-                       const _GLFWfbconfig* fbconfig);
-void _glfwDestroyContext(_GLFWwindow* window);
+GLFWbool _glfwInitNSGL(void);
+void _glfwTerminateNSGL(void);
+GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
+                                const _GLFWctxconfig* ctxconfig,
+                                const _GLFWfbconfig* fbconfig);
+void _glfwDestroyContextNSGL(_GLFWwindow* window);
 
-#endif // _nsgl_context_h_
+#endif // _glfw3_nsgl_context_h_
diff --git a/glfw/src/nsgl_context.m b/glfw/src/nsgl_context.m
--- a/glfw/src/nsgl_context.m
+++ b/glfw/src/nsgl_context.m
@@ -1,7 +1,7 @@
 //========================================================================
-// GLFW 3.1 OS X - www.glfw.org
+// GLFW 3.2 OS X - www.glfw.org
 //------------------------------------------------------------------------
-// Copyright (c) 2009-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2009-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -27,58 +27,112 @@
 #include "internal.h"
 
 
+static void makeContextCurrentNSGL(_GLFWwindow* window)
+{
+    if (window)
+        [window->context.nsgl.object makeCurrentContext];
+    else
+        [NSOpenGLContext clearCurrentContext];
+
+    _glfwPlatformSetCurrentContext(window);
+}
+
+static void swapBuffersNSGL(_GLFWwindow* window)
+{
+    // ARP appears to be unnecessary, but this is future-proof
+    [window->context.nsgl.object flushBuffer];
+}
+
+static void swapIntervalNSGL(int interval)
+{
+    _GLFWwindow* window = _glfwPlatformGetCurrentContext();
+
+    GLint sync = interval;
+    [window->context.nsgl.object setValues:&sync
+                              forParameter:NSOpenGLCPSwapInterval];
+}
+
+static int extensionSupportedNSGL(const char* extension)
+{
+    // There are no NSGL extensions
+    return GLFW_FALSE;
+}
+
+static GLFWglproc getProcAddressNSGL(const char* procname)
+{
+    CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault,
+                                                       procname,
+                                                       kCFStringEncodingASCII);
+
+    GLFWglproc symbol = CFBundleGetFunctionPointerForName(_glfw.nsgl.framework,
+                                                          symbolName);
+
+    CFRelease(symbolName);
+
+    return symbol;
+}
+
+// Destroy the OpenGL context
+//
+static void destroyContextNSGL(_GLFWwindow* window)
+{
+    [window->context.nsgl.pixelFormat release];
+    window->context.nsgl.pixelFormat = nil;
+
+    [window->context.nsgl.object release];
+    window->context.nsgl.object = nil;
+}
+
+
 //////////////////////////////////////////////////////////////////////////
 //////                       GLFW internal API                      //////
 //////////////////////////////////////////////////////////////////////////
 
 // Initialize OpenGL support
 //
-int _glfwInitContextAPI(void)
+GLFWbool _glfwInitNSGL(void)
 {
-    if (!_glfwInitTLS())
-        return GL_FALSE;
+    if (_glfw.nsgl.framework)
+        return GLFW_TRUE;
 
     _glfw.nsgl.framework =
         CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
     if (_glfw.nsgl.framework == NULL)
     {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
+        _glfwInputError(GLFW_API_UNAVAILABLE,
                         "NSGL: Failed to locate OpenGL framework");
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
 
-    return GL_TRUE;
+    return GLFW_TRUE;
 }
 
 // Terminate OpenGL support
 //
-void _glfwTerminateContextAPI(void)
+void _glfwTerminateNSGL(void)
 {
-    _glfwTerminateTLS();
 }
 
 // Create the OpenGL context
 //
-int _glfwCreateContext(_GLFWwindow* window,
-                       const _GLFWctxconfig* ctxconfig,
-                       const _GLFWfbconfig* fbconfig)
+GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
+                                const _GLFWctxconfig* ctxconfig,
+                                const _GLFWfbconfig* fbconfig)
 {
     unsigned int attributeCount = 0;
 
-    if (ctxconfig->api == GLFW_OPENGL_ES_API)
+    if (ctxconfig->client == GLFW_OPENGL_ES_API)
     {
-        _glfwInputError(GLFW_VERSION_UNAVAILABLE,
-                        "NSGL: This API does not support OpenGL ES");
-        return GL_FALSE;
+        _glfwInputError(GLFW_API_UNAVAILABLE,
+                        "NSGL: OpenGL ES is not available on OS X");
+        return GLFW_FALSE;
     }
 
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
     if (ctxconfig->major == 3 && ctxconfig->minor < 2)
     {
         _glfwInputError(GLFW_VERSION_UNAVAILABLE,
-                        "NSGL: The targeted version of OS X does not "
-                        "support OpenGL 3.0 or 3.1");
-        return GL_FALSE;
+                        "NSGL: The targeted version of OS X does not support OpenGL 3.0 or 3.1");
+        return GLFW_FALSE;
     }
 
     if (ctxconfig->major > 2)
@@ -86,31 +140,17 @@
         if (!ctxconfig->forward)
         {
             _glfwInputError(GLFW_VERSION_UNAVAILABLE,
-                            "NSGL: The targeted version of OS X only "
-                            "supports OpenGL 3.2 and later versions if they "
-                            "are forward-compatible");
-            return GL_FALSE;
+                            "NSGL: The targeted version of OS X only supports forward-compatible contexts for OpenGL 3.2 and above");
+            return GLFW_FALSE;
         }
 
         if (ctxconfig->profile != GLFW_OPENGL_CORE_PROFILE)
         {
             _glfwInputError(GLFW_VERSION_UNAVAILABLE,
-                            "NSGL: The targeted version of OS X only "
-                            "supports OpenGL 3.2 and later versions if they "
-                            "use the core profile");
-            return GL_FALSE;
+                            "NSGL: The targeted version of OS X only supports core profile contexts for OpenGL 3.2 and above");
+            return GLFW_FALSE;
         }
     }
-#else
-    // Fail if OpenGL 3.0 or above was requested
-    if (ctxconfig->major > 2)
-    {
-        _glfwInputError(GLFW_VERSION_UNAVAILABLE,
-                        "NSGL: The targeted version of OS X does not "
-                        "support OpenGL version 3.0 or above");
-        return GL_FALSE;
-    }
-#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
 
     // Context robustness modes (GL_KHR_robustness) are not yet supported on
     // OS X but are not a hard constraint, so ignore and continue
@@ -127,7 +167,6 @@
     ADD_ATTR(NSOpenGLPFAAccelerated);
     ADD_ATTR(NSOpenGLPFAClosestPolicy);
 
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
     if (ctxconfig->major >= 4)
     {
@@ -139,7 +178,6 @@
     {
         ADD_ATTR2(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core);
     }
-#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
 
     if (ctxconfig->major <= 2)
     {
@@ -213,91 +251,40 @@
 #undef ADD_ATTR
 #undef ADD_ATTR2
 
-    window->nsgl.pixelFormat =
+    window->context.nsgl.pixelFormat =
         [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
-    if (window->nsgl.pixelFormat == nil)
+    if (window->context.nsgl.pixelFormat == nil)
     {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "NSGL: Failed to create OpenGL pixel format");
-        return GL_FALSE;
+        _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
+                        "NSGL: Failed to find a suitable pixel format");
+        return GLFW_FALSE;
     }
 
     NSOpenGLContext* share = NULL;
 
     if (ctxconfig->share)
-        share = ctxconfig->share->nsgl.context;
+        share = ctxconfig->share->context.nsgl.object;
 
-    window->nsgl.context =
-        [[NSOpenGLContext alloc] initWithFormat:window->nsgl.pixelFormat
+    window->context.nsgl.object =
+        [[NSOpenGLContext alloc] initWithFormat:window->context.nsgl.pixelFormat
                                    shareContext:share];
-    if (window->nsgl.context == nil)
+    if (window->context.nsgl.object == nil)
     {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
+        _glfwInputError(GLFW_VERSION_UNAVAILABLE,
                         "NSGL: Failed to create OpenGL context");
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
 
-    return GL_TRUE;
-}
-
-// Destroy the OpenGL context
-//
-void _glfwDestroyContext(_GLFWwindow* window)
-{
-    [window->nsgl.pixelFormat release];
-    window->nsgl.pixelFormat = nil;
-
-    [window->nsgl.context release];
-    window->nsgl.context = nil;
-}
-
-
-//////////////////////////////////////////////////////////////////////////
-//////                       GLFW platform API                      //////
-//////////////////////////////////////////////////////////////////////////
-
-void _glfwPlatformMakeContextCurrent(_GLFWwindow* window)
-{
-    if (window)
-        [window->nsgl.context makeCurrentContext];
-    else
-        [NSOpenGLContext clearCurrentContext];
-
-    _glfwSetCurrentContext(window);
-}
-
-void _glfwPlatformSwapBuffers(_GLFWwindow* window)
-{
-    // ARP appears to be unnecessary, but this is future-proof
-    [window->nsgl.context flushBuffer];
-}
-
-void _glfwPlatformSwapInterval(int interval)
-{
-    _GLFWwindow* window = _glfwPlatformGetCurrentContext();
-
-    GLint sync = interval;
-    [window->nsgl.context setValues:&sync forParameter:NSOpenGLCPSwapInterval];
-}
-
-int _glfwPlatformExtensionSupported(const char* extension)
-{
-    // There are no NSGL extensions
-    return GL_FALSE;
-}
-
-GLFWglproc _glfwPlatformGetProcAddress(const char* procname)
-{
-    CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault,
-                                                       procname,
-                                                       kCFStringEncodingASCII);
-
-    GLFWglproc symbol = CFBundleGetFunctionPointerForName(_glfw.nsgl.framework,
-                                                          symbolName);
+    [window->context.nsgl.object setView:window->ns.view];
 
-    CFRelease(symbolName);
+    window->context.makeCurrent = makeContextCurrentNSGL;
+    window->context.swapBuffers = swapBuffersNSGL;
+    window->context.swapInterval = swapIntervalNSGL;
+    window->context.extensionSupported = extensionSupportedNSGL;
+    window->context.getProcAddress = getProcAddressNSGL;
+    window->context.destroy = destroyContextNSGL;
 
-    return symbol;
+    return GLFW_TRUE;
 }
 
 
@@ -309,6 +296,13 @@
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(nil);
-    return window->nsgl.context;
+
+    if (window->context.client == GLFW_NO_API)
+    {
+        _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
+        return NULL;
+    }
+
+    return window->context.nsgl.object;
 }
 
diff --git a/glfw/src/posix_time.c b/glfw/src/posix_time.c
--- a/glfw/src/posix_time.c
+++ b/glfw/src/posix_time.c
@@ -1,8 +1,8 @@
 //========================================================================
-// GLFW 3.1 POSIX - www.glfw.org
+// GLFW 3.2 POSIX - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -30,52 +30,29 @@
 #include <sys/time.h>
 #include <time.h>
 
-// Return raw time
-//
-static uint64_t getRawTime(void)
-{
-#if defined(CLOCK_MONOTONIC)
-    if (_glfw.posix_time.monotonic)
-    {
-        struct timespec ts;
 
-        clock_gettime(CLOCK_MONOTONIC, &ts);
-        return (uint64_t) ts.tv_sec * (uint64_t) 1000000000 + (uint64_t) ts.tv_nsec;
-    }
-    else
-#endif
-    {
-        struct timeval tv;
-
-        gettimeofday(&tv, NULL);
-        return (uint64_t) tv.tv_sec * (uint64_t) 1000000 + (uint64_t) tv.tv_usec;
-    }
-}
-
-
 //////////////////////////////////////////////////////////////////////////
 //////                       GLFW internal API                      //////
 //////////////////////////////////////////////////////////////////////////
 
 // Initialise timer
 //
-void _glfwInitTimer(void)
+void _glfwInitTimerPOSIX(void)
 {
 #if defined(CLOCK_MONOTONIC)
     struct timespec ts;
 
     if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
     {
-        _glfw.posix_time.monotonic = GL_TRUE;
-        _glfw.posix_time.resolution = 1e-9;
+        _glfw.posix_time.monotonic = GLFW_TRUE;
+        _glfw.posix_time.frequency = 1000000000;
     }
     else
 #endif
     {
-        _glfw.posix_time.resolution = 1e-6;
+        _glfw.posix_time.monotonic = GLFW_FALSE;
+        _glfw.posix_time.frequency = 1000000;
     }
-
-    _glfw.posix_time.base = getRawTime();
 }
 
 
@@ -83,15 +60,26 @@
 //////                       GLFW platform API                      //////
 //////////////////////////////////////////////////////////////////////////
 
-double _glfwPlatformGetTime(void)
+uint64_t _glfwPlatformGetTimerValue(void)
 {
-    return (double) (getRawTime() - _glfw.posix_time.base) *
-        _glfw.posix_time.resolution;
+#if defined(CLOCK_MONOTONIC)
+    if (_glfw.posix_time.monotonic)
+    {
+        struct timespec ts;
+        clock_gettime(CLOCK_MONOTONIC, &ts);
+        return (uint64_t) ts.tv_sec * (uint64_t) 1000000000 + (uint64_t) ts.tv_nsec;
+    }
+    else
+#endif
+    {
+        struct timeval tv;
+        gettimeofday(&tv, NULL);
+        return (uint64_t) tv.tv_sec * (uint64_t) 1000000 + (uint64_t) tv.tv_usec;
+    }
 }
 
-void _glfwPlatformSetTime(double time)
+uint64_t _glfwPlatformGetTimerFrequency(void)
 {
-    _glfw.posix_time.base = getRawTime() -
-        (uint64_t) (time / _glfw.posix_time.resolution);
+    return _glfw.posix_time.frequency;
 }
 
diff --git a/glfw/src/posix_time.h b/glfw/src/posix_time.h
--- a/glfw/src/posix_time.h
+++ b/glfw/src/posix_time.h
@@ -1,8 +1,8 @@
 //========================================================================
-// GLFW 3.1 POSIX - www.glfw.org
+// GLFW 3.2 POSIX - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -25,8 +25,8 @@
 //
 //========================================================================
 
-#ifndef _posix_time_h_
-#define _posix_time_h_
+#ifndef _glfw3_posix_time_h_
+#define _glfw3_posix_time_h_
 
 #define _GLFW_PLATFORM_LIBRARY_TIME_STATE _GLFWtimePOSIX posix_time
 
@@ -37,13 +37,12 @@
 //
 typedef struct _GLFWtimePOSIX
 {
-    GLboolean   monotonic;
-    double      resolution;
-    uint64_t    base;
+    GLFWbool    monotonic;
+    uint64_t    frequency;
 
 } _GLFWtimePOSIX;
 
 
-void _glfwInitTimer(void);
+void _glfwInitTimerPOSIX(void);
 
-#endif // _posix_time_h_
+#endif // _glfw3_posix_time_h_
diff --git a/glfw/src/posix_tls.c b/glfw/src/posix_tls.c
--- a/glfw/src/posix_tls.c
+++ b/glfw/src/posix_tls.c
@@ -1,8 +1,8 @@
 //========================================================================
-// GLFW 3.1 POSIX - www.glfw.org
+// GLFW 3.2 POSIX - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -32,32 +32,34 @@
 //////                       GLFW internal API                      //////
 //////////////////////////////////////////////////////////////////////////
 
-int _glfwInitTLS(void)
+GLFWbool _glfwInitThreadLocalStoragePOSIX(void)
 {
     if (pthread_key_create(&_glfw.posix_tls.context, NULL) != 0)
     {
         _glfwInputError(GLFW_PLATFORM_ERROR,
                         "POSIX: Failed to create context TLS");
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
 
-    return GL_TRUE;
-}
-
-void _glfwTerminateTLS(void)
-{
-    pthread_key_delete(_glfw.posix_tls.context);
+    _glfw.posix_tls.allocated = GLFW_TRUE;
+    return GLFW_TRUE;
 }
 
-void _glfwSetCurrentContext(_GLFWwindow* context)
+void _glfwTerminateThreadLocalStoragePOSIX(void)
 {
-    pthread_setspecific(_glfw.posix_tls.context, context);
+    if (_glfw.posix_tls.allocated)
+        pthread_key_delete(_glfw.posix_tls.context);
 }
 
 
 //////////////////////////////////////////////////////////////////////////
 //////                       GLFW platform API                      //////
 //////////////////////////////////////////////////////////////////////////
+
+void _glfwPlatformSetCurrentContext(_GLFWwindow* context)
+{
+    pthread_setspecific(_glfw.posix_tls.context, context);
+}
 
 _GLFWwindow* _glfwPlatformGetCurrentContext(void)
 {
diff --git a/glfw/src/posix_tls.h b/glfw/src/posix_tls.h
--- a/glfw/src/posix_tls.h
+++ b/glfw/src/posix_tls.h
@@ -1,8 +1,8 @@
 //========================================================================
-// GLFW 3.1 POSIX - www.glfw.org
+// GLFW 3.2 POSIX - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -25,8 +25,8 @@
 //
 //========================================================================
 
-#ifndef _posix_tls_h_
-#define _posix_tls_h_
+#ifndef _glfw3_posix_tls_h_
+#define _glfw3_posix_tls_h_
 
 #include <pthread.h>
 
@@ -37,13 +37,13 @@
 //
 typedef struct _GLFWtlsPOSIX
 {
+    GLFWbool        allocated;
     pthread_key_t   context;
 
 } _GLFWtlsPOSIX;
 
 
-int _glfwInitTLS(void);
-void _glfwTerminateTLS(void);
-void _glfwSetCurrentContext(_GLFWwindow* context);
+GLFWbool _glfwInitThreadLocalStoragePOSIX(void);
+void _glfwTerminateThreadLocalStoragePOSIX(void);
 
-#endif // _posix_tls_h_
+#endif // _glfw3_posix_tls_h_
diff --git a/glfw/src/vulkan.c b/glfw/src/vulkan.c
new file mode 100644
--- /dev/null
+++ b/glfw/src/vulkan.c
@@ -0,0 +1,302 @@
+//========================================================================
+// GLFW 3.2 - www.glfw.org
+//------------------------------------------------------------------------
+// Copyright (c) 2002-2006 Marcus Geelnard
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
+//
+// 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 <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                       GLFW internal API                      //////
+//////////////////////////////////////////////////////////////////////////
+
+GLFWbool _glfwInitVulkan(void)
+{
+    VkResult err;
+    VkExtensionProperties* ep;
+    uint32_t i, count;
+
+#if !defined(_GLFW_VULKAN_STATIC)
+#if defined(_GLFW_WIN32)
+    const char* name = "vulkan-1.dll";
+#else
+    const char* name = "libvulkan.so.1";
+#endif
+
+    if (_glfw.vk.available)
+        return GLFW_TRUE;
+
+    _glfw.vk.handle = _glfw_dlopen(name);
+    if (!_glfw.vk.handle)
+        return GLFW_FALSE;
+
+    _glfw.vk.GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)
+        _glfw_dlsym(_glfw.vk.handle, "vkGetInstanceProcAddr");
+    if (!_glfw.vk.GetInstanceProcAddr)
+    {
+        _glfwInputError(GLFW_API_UNAVAILABLE,
+                        "Vulkan: Loader does not export vkGetInstanceProcAddr");
+
+        _glfwTerminateVulkan();
+        return GLFW_FALSE;
+    }
+
+    _glfw.vk.EnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)
+        vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceExtensionProperties");
+    if (!_glfw.vk.EnumerateInstanceExtensionProperties)
+    {
+        _glfwInputError(GLFW_API_UNAVAILABLE,
+                        "Vulkan: Failed to retrieve vkEnumerateInstanceExtensionProperties");
+
+        _glfwTerminateVulkan();
+        return GLFW_FALSE;
+    }
+#endif // _GLFW_VULKAN_STATIC
+
+    err = vkEnumerateInstanceExtensionProperties(NULL, &count, NULL);
+    if (err)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Vulkan: Failed to query instance extension count: %s",
+                        _glfwGetVulkanResultString(err));
+
+        _glfwTerminateVulkan();
+        return GLFW_FALSE;
+    }
+
+    ep = calloc(count, sizeof(VkExtensionProperties));
+
+    err = vkEnumerateInstanceExtensionProperties(NULL, &count, ep);
+    if (err)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Vulkan: Failed to query instance extensions: %s",
+                        _glfwGetVulkanResultString(err));
+
+        free(ep);
+        _glfwTerminateVulkan();
+        return GLFW_FALSE;
+    }
+
+    for (i = 0;  i < count;  i++)
+    {
+        if (strcmp(ep[i].extensionName, "VK_KHR_surface") == 0)
+            _glfw.vk.KHR_surface = GLFW_TRUE;
+        if (strcmp(ep[i].extensionName, "VK_KHR_win32_surface") == 0)
+            _glfw.vk.KHR_win32_surface = GLFW_TRUE;
+        if (strcmp(ep[i].extensionName, "VK_KHR_xlib_surface") == 0)
+            _glfw.vk.KHR_xlib_surface = GLFW_TRUE;
+        if (strcmp(ep[i].extensionName, "VK_KHR_xcb_surface") == 0)
+            _glfw.vk.KHR_xcb_surface = GLFW_TRUE;
+        if (strcmp(ep[i].extensionName, "VK_KHR_wayland_surface") == 0)
+            _glfw.vk.KHR_wayland_surface = GLFW_TRUE;
+        if (strcmp(ep[i].extensionName, "VK_KHR_mir_surface") == 0)
+            _glfw.vk.KHR_mir_surface = GLFW_TRUE;
+    }
+
+    free(ep);
+
+    _glfw.vk.available = GLFW_TRUE;
+
+    if (_glfw.vk.KHR_surface)
+    {
+        _glfw.vk.extensions =
+            _glfwPlatformGetRequiredInstanceExtensions(&_glfw.vk.extensionCount);
+    }
+
+    return GLFW_TRUE;
+}
+
+void _glfwTerminateVulkan(void)
+{
+    uint32_t i;
+
+    for (i = 0;  i < _glfw.vk.extensionCount;  i++)
+        free(_glfw.vk.extensions[i]);
+    free(_glfw.vk.extensions);
+
+    if (_glfw.vk.handle)
+        _glfw_dlclose(_glfw.vk.handle);
+}
+
+const char* _glfwGetVulkanResultString(VkResult result)
+{
+    switch (result)
+    {
+        case VK_SUCCESS:
+            return "Success";
+        case VK_NOT_READY:
+            return "A fence or query has not yet completed";
+        case VK_TIMEOUT:
+            return "A wait operation has not completed in the specified time";
+        case VK_EVENT_SET:
+            return "An event is signaled";
+        case VK_EVENT_RESET:
+            return "An event is unsignaled";
+        case VK_INCOMPLETE:
+            return "A return array was too small for the result";
+        case VK_ERROR_OUT_OF_HOST_MEMORY:
+            return "A host memory allocation has failed";
+        case VK_ERROR_OUT_OF_DEVICE_MEMORY:
+            return "A device memory allocation has failed";
+        case VK_ERROR_INITIALIZATION_FAILED:
+            return "Initialization of an object could not be completed for implementation-specific reasons";
+        case VK_ERROR_DEVICE_LOST:
+            return "The logical or physical device has been lost";
+        case VK_ERROR_MEMORY_MAP_FAILED:
+            return "Mapping of a memory object has failed";
+        case VK_ERROR_LAYER_NOT_PRESENT:
+            return "A requested layer is not present or could not be loaded";
+        case VK_ERROR_EXTENSION_NOT_PRESENT:
+            return "A requested extension is not supported";
+        case VK_ERROR_FEATURE_NOT_PRESENT:
+            return "A requested feature is not supported";
+        case VK_ERROR_INCOMPATIBLE_DRIVER:
+            return "The requested version of Vulkan is not supported by the driver or is otherwise incompatible";
+        case VK_ERROR_TOO_MANY_OBJECTS:
+            return "Too many objects of the type have already been created";
+        case VK_ERROR_FORMAT_NOT_SUPPORTED:
+            return "A requested format is not supported on this device";
+        case VK_ERROR_SURFACE_LOST_KHR:
+            return "A surface is no longer available";
+        case VK_SUBOPTIMAL_KHR:
+            return "A swapchain no longer matches the surface properties exactly, but can still be used";
+        case VK_ERROR_OUT_OF_DATE_KHR:
+            return "A surface has changed in such a way that it is no longer compatible with the swapchain";
+        case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR:
+            return "The display used by a swapchain does not use the same presentable image layout";
+        case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
+            return "The requested window is already connected to a VkSurfaceKHR, or to some other non-Vulkan API";
+        case VK_ERROR_VALIDATION_FAILED_EXT:
+            return "A validation layer found an error";
+        default:
+            return "ERROR: UNKNOWN VULKAN ERROR";
+    }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                        GLFW public API                       //////
+//////////////////////////////////////////////////////////////////////////
+
+GLFWAPI int glfwVulkanSupported(void)
+{
+    _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
+    return _glfwInitVulkan();
+}
+
+GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count)
+{
+    *count = 0;
+
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+
+    if (!_glfwInitVulkan())
+    {
+        _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: API not available");
+        return NULL;
+    }
+
+    *count = _glfw.vk.extensionCount;
+    return (const char**) _glfw.vk.extensions;
+}
+
+GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance,
+                                              const char* procname)
+{
+    GLFWvkproc proc;
+
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+
+    if (!_glfwInitVulkan())
+    {
+        _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: API not available");
+        return NULL;
+    }
+
+    proc = (GLFWvkproc) vkGetInstanceProcAddr(instance, procname);
+    if (!proc)
+        proc = (GLFWvkproc) _glfw_dlsym(_glfw.vk.handle, procname);
+
+    return proc;
+}
+
+GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance,
+                                                     VkPhysicalDevice device,
+                                                     uint32_t queuefamily)
+{
+    _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
+
+    if (!_glfwInitVulkan())
+    {
+        _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: API not available");
+        return GLFW_FALSE;
+    }
+
+    if (!_glfw.vk.extensions)
+    {
+        _glfwInputError(GLFW_API_UNAVAILABLE,
+                        "Vulkan: Window surface creation extensions not found");
+        return GLFW_FALSE;
+    }
+
+    return _glfwPlatformGetPhysicalDevicePresentationSupport(instance,
+                                                             device,
+                                                             queuefamily);
+}
+
+GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance,
+                                         GLFWwindow* handle,
+                                         const VkAllocationCallbacks* allocator,
+                                         VkSurfaceKHR* surface)
+{
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+    assert(surface != NULL);
+
+    *surface = VK_NULL_HANDLE;
+
+    _GLFW_REQUIRE_INIT_OR_RETURN(VK_ERROR_INITIALIZATION_FAILED);
+
+    if (!_glfwInitVulkan())
+    {
+        _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: API not available");
+        return VK_ERROR_INITIALIZATION_FAILED;
+    }
+
+    if (!_glfw.vk.extensions)
+    {
+        _glfwInputError(GLFW_API_UNAVAILABLE,
+                        "Vulkan: Window surface creation extensions not found");
+        return VK_ERROR_EXTENSION_NOT_PRESENT;
+    }
+
+    return _glfwPlatformCreateWindowSurface(instance, window, allocator, surface);
+}
+
diff --git a/glfw/src/wgl_context.c b/glfw/src/wgl_context.c
--- a/glfw/src/wgl_context.c
+++ b/glfw/src/wgl_context.c
@@ -1,8 +1,8 @@
 //========================================================================
-// GLFW 3.1 WGL - www.glfw.org
+// GLFW 3.2 WGL - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -32,111 +32,21 @@
 #include <assert.h>
 
 
-// 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(_GLFWwindow* window)
-{
-    // This needs to include every function pointer loaded below
-    window->wgl.SwapIntervalEXT = NULL;
-    window->wgl.GetPixelFormatAttribivARB = NULL;
-    window->wgl.GetExtensionsStringARB = NULL;
-    window->wgl.GetExtensionsStringEXT = NULL;
-    window->wgl.CreateContextAttribsARB = NULL;
-
-    // This needs to include every extension used below except for
-    // WGL_ARB_extensions_string and WGL_EXT_extensions_string
-    window->wgl.ARB_multisample = GL_FALSE;
-    window->wgl.ARB_framebuffer_sRGB = GL_FALSE;
-    window->wgl.ARB_create_context = GL_FALSE;
-    window->wgl.ARB_create_context_profile = GL_FALSE;
-    window->wgl.EXT_create_context_es2_profile = GL_FALSE;
-    window->wgl.ARB_create_context_robustness = GL_FALSE;
-    window->wgl.EXT_swap_control = GL_FALSE;
-    window->wgl.ARB_pixel_format = GL_FALSE;
-    window->wgl.ARB_context_flush_control = GL_FALSE;
-
-    window->wgl.GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)
-        wglGetProcAddress("wglGetExtensionsStringEXT");
-    if (!window->wgl.GetExtensionsStringEXT)
-    {
-        window->wgl.GetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)
-            wglGetProcAddress("wglGetExtensionsStringARB");
-        if (!window->wgl.GetExtensionsStringARB)
-            return;
-    }
-
-    if (_glfwPlatformExtensionSupported("WGL_ARB_multisample"))
-        window->wgl.ARB_multisample = GL_TRUE;
-
-    if (_glfwPlatformExtensionSupported("WGL_ARB_framebuffer_sRGB"))
-        window->wgl.ARB_framebuffer_sRGB = GL_TRUE;
-
-    if (_glfwPlatformExtensionSupported("WGL_ARB_create_context"))
-    {
-        window->wgl.CreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)
-            wglGetProcAddress("wglCreateContextAttribsARB");
-
-        if (window->wgl.CreateContextAttribsARB)
-            window->wgl.ARB_create_context = GL_TRUE;
-    }
-
-    if (window->wgl.ARB_create_context)
-    {
-        if (_glfwPlatformExtensionSupported("WGL_ARB_create_context_profile"))
-            window->wgl.ARB_create_context_profile = GL_TRUE;
-    }
-
-    if (window->wgl.ARB_create_context &&
-        window->wgl.ARB_create_context_profile)
-    {
-        if (_glfwPlatformExtensionSupported("WGL_EXT_create_context_es2_profile"))
-            window->wgl.EXT_create_context_es2_profile = GL_TRUE;
-    }
-
-    if (window->wgl.ARB_create_context)
-    {
-        if (_glfwPlatformExtensionSupported("WGL_ARB_create_context_robustness"))
-            window->wgl.ARB_create_context_robustness = GL_TRUE;
-    }
-
-    if (_glfwPlatformExtensionSupported("WGL_EXT_swap_control"))
-    {
-        window->wgl.SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)
-            wglGetProcAddress("wglSwapIntervalEXT");
-
-        if (window->wgl.SwapIntervalEXT)
-            window->wgl.EXT_swap_control = GL_TRUE;
-    }
-
-    if (_glfwPlatformExtensionSupported("WGL_ARB_pixel_format"))
-    {
-        window->wgl.GetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)
-            wglGetProcAddress("wglGetPixelFormatAttribivARB");
-
-        if (window->wgl.GetPixelFormatAttribivARB)
-            window->wgl.ARB_pixel_format = GL_TRUE;
-    }
-
-    if (_glfwPlatformExtensionSupported("WGL_ARB_context_flush_control"))
-        window->wgl.ARB_context_flush_control = GL_TRUE;
-}
-
 // Returns the specified attribute of the specified pixel format
-// NOTE: Do not call this unless we have found WGL_ARB_pixel_format
 //
 static int getPixelFormatAttrib(_GLFWwindow* window, int pixelFormat, int attrib)
 {
     int value = 0;
 
-    if (!window->wgl.GetPixelFormatAttribivARB(window->wgl.dc,
-                                               pixelFormat,
-                                               0, 1, &attrib, &value))
+    assert(_glfw.wgl.ARB_pixel_format);
+
+    if (!_glfw.wgl.GetPixelFormatAttribivARB(window->context.wgl.dc,
+                                             pixelFormat,
+                                             0, 1, &attrib, &value))
     {
-        // NOTE: We should probably handle this error somehow
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "WGL: Failed to retrieve pixel format attribute %i",
+                        attrib);
         return 0;
     }
 
@@ -145,34 +55,26 @@
 
 // Return a list of available and usable framebuffer configs
 //
-static GLboolean choosePixelFormat(_GLFWwindow* window,
-                                   const _GLFWfbconfig* desired,
-                                   int* result)
+static int choosePixelFormat(_GLFWwindow* window, const _GLFWfbconfig* desired)
 {
     _GLFWfbconfig* usableConfigs;
     const _GLFWfbconfig* closest;
-    int i, nativeCount, usableCount;
+    int i, pixelFormat, nativeCount, usableCount;
 
-    if (window->wgl.ARB_pixel_format)
+    if (_glfw.wgl.ARB_pixel_format)
     {
         nativeCount = getPixelFormatAttrib(window,
-                                         1,
-                                         WGL_NUMBER_PIXEL_FORMATS_ARB);
+                                           1,
+                                           WGL_NUMBER_PIXEL_FORMATS_ARB);
     }
     else
     {
-        nativeCount = DescribePixelFormat(window->wgl.dc,
+        nativeCount = DescribePixelFormat(window->context.wgl.dc,
                                           1,
                                           sizeof(PIXELFORMATDESCRIPTOR),
                                           NULL);
     }
 
-    if (!nativeCount)
-    {
-        _glfwInputError(GLFW_API_UNAVAILABLE, "WGL: No pixel formats found");
-        return GL_FALSE;
-    }
-
     usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig));
     usableCount = 0;
 
@@ -181,9 +83,10 @@
         const int n = i + 1;
         _GLFWfbconfig* u = usableConfigs + usableCount;
 
-        if (window->wgl.ARB_pixel_format)
+        if (_glfw.wgl.ARB_pixel_format)
         {
-            // Get pixel format attributes through WGL_ARB_pixel_format
+            // Get pixel format attributes through "modern" extension
+
             if (!getPixelFormatAttrib(window, n, WGL_SUPPORT_OPENGL_ARB) ||
                 !getPixelFormatAttrib(window, n, WGL_DRAW_TO_WINDOW_ARB))
             {
@@ -218,26 +121,27 @@
             u->auxBuffers = getPixelFormatAttrib(window, n, WGL_AUX_BUFFERS_ARB);
 
             if (getPixelFormatAttrib(window, n, WGL_STEREO_ARB))
-                u->stereo = GL_TRUE;
+                u->stereo = GLFW_TRUE;
             if (getPixelFormatAttrib(window, n, WGL_DOUBLE_BUFFER_ARB))
-                u->doublebuffer = GL_TRUE;
+                u->doublebuffer = GLFW_TRUE;
 
-            if (window->wgl.ARB_multisample)
+            if (_glfw.wgl.ARB_multisample)
                 u->samples = getPixelFormatAttrib(window, n, WGL_SAMPLES_ARB);
 
-            if (window->wgl.ARB_framebuffer_sRGB)
+            if (_glfw.wgl.ARB_framebuffer_sRGB ||
+                _glfw.wgl.EXT_framebuffer_sRGB)
             {
                 if (getPixelFormatAttrib(window, n, WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB))
-                    u->sRGB = GL_TRUE;
+                    u->sRGB = GLFW_TRUE;
             }
         }
         else
         {
             PIXELFORMATDESCRIPTOR pfd;
 
-            // Get pixel format attributes through old-fashioned PFDs
+            // Get pixel format attributes through legacy PFDs
 
-            if (!DescribePixelFormat(window->wgl.dc,
+            if (!DescribePixelFormat(window->context.wgl.dc,
                                      n,
                                      sizeof(PIXELFORMATDESCRIPTOR),
                                      &pfd))
@@ -276,12 +180,12 @@
             u->auxBuffers = pfd.cAuxBuffers;
 
             if (pfd.dwFlags & PFD_STEREO)
-                u->stereo = GL_TRUE;
+                u->stereo = GLFW_TRUE;
             if (pfd.dwFlags & PFD_DOUBLEBUFFER)
-                u->doublebuffer = GL_TRUE;
+                u->doublebuffer = GLFW_TRUE;
         }
 
-        u->wgl = n;
+        u->handle = n;
         usableCount++;
     }
 
@@ -291,55 +195,267 @@
                         "WGL: The driver does not appear to support OpenGL");
 
         free(usableConfigs);
-        return GL_FALSE;
+        return 0;
     }
 
     closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount);
     if (!closest)
     {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
+        _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
                         "WGL: Failed to find a suitable pixel format");
 
         free(usableConfigs);
-        return GL_FALSE;
+        return 0;
     }
 
-    *result = closest->wgl;
+    pixelFormat = (int) closest->handle;
     free(usableConfigs);
 
-    return GL_TRUE;
+    return pixelFormat;
 }
 
+// Returns whether desktop compositing is enabled
+//
+static GLFWbool isCompositionEnabled(void)
+{
+    BOOL enabled;
 
+    if (!_glfw_DwmIsCompositionEnabled)
+        return FALSE;
+
+    if (_glfw_DwmIsCompositionEnabled(&enabled) != S_OK)
+        return FALSE;
+
+    return enabled;
+}
+
+static void makeContextCurrentWGL(_GLFWwindow* window)
+{
+    if (window)
+    {
+        if (wglMakeCurrent(window->context.wgl.dc, window->context.wgl.handle))
+            _glfwPlatformSetCurrentContext(window);
+        else
+        {
+            _glfwInputError(GLFW_PLATFORM_ERROR,
+                            "WGL: Failed to make context current");
+            _glfwPlatformSetCurrentContext(NULL);
+        }
+    }
+    else
+    {
+        if (!wglMakeCurrent(NULL, NULL))
+        {
+            _glfwInputError(GLFW_PLATFORM_ERROR,
+                            "WGL: Failed to clear current context");
+        }
+
+        _glfwPlatformSetCurrentContext(NULL);
+    }
+}
+
+static void swapBuffersWGL(_GLFWwindow* window)
+{
+    // HACK: Use DwmFlush when desktop composition is enabled
+    if (isCompositionEnabled() && !window->monitor)
+    {
+        int count = abs(window->context.wgl.interval);
+        while (count--)
+            _glfw_DwmFlush();
+    }
+
+    SwapBuffers(window->context.wgl.dc);
+}
+
+static void swapIntervalWGL(int interval)
+{
+    _GLFWwindow* window = _glfwPlatformGetCurrentContext();
+
+    window->context.wgl.interval = interval;
+
+    // HACK: Disable WGL swap interval when desktop composition is enabled to
+    //       avoid interfering with DWM vsync
+    if (isCompositionEnabled() && !window->monitor)
+        interval = 0;
+
+    if (_glfw.wgl.EXT_swap_control)
+        _glfw.wgl.SwapIntervalEXT(interval);
+}
+
+static int extensionSupportedWGL(const char* extension)
+{
+    const char* extensions;
+
+    if (_glfw.wgl.GetExtensionsStringEXT)
+    {
+        extensions = _glfw.wgl.GetExtensionsStringEXT();
+        if (extensions)
+        {
+            if (_glfwStringInExtensionString(extension, extensions))
+                return GLFW_TRUE;
+        }
+    }
+
+    if (_glfw.wgl.GetExtensionsStringARB)
+    {
+        extensions = _glfw.wgl.GetExtensionsStringARB(wglGetCurrentDC());
+        if (extensions)
+        {
+            if (_glfwStringInExtensionString(extension, extensions))
+                return GLFW_TRUE;
+        }
+    }
+
+    return GLFW_FALSE;
+}
+
+static GLFWglproc getProcAddressWGL(const char* procname)
+{
+    const GLFWglproc proc = (GLFWglproc) wglGetProcAddress(procname);
+    if (proc)
+        return proc;
+
+    return (GLFWglproc) GetProcAddress(_glfw.wgl.instance, procname);
+}
+
+// Destroy the OpenGL context
+//
+static void destroyContextWGL(_GLFWwindow* window)
+{
+    if (window->context.wgl.handle)
+    {
+        wglDeleteContext(window->context.wgl.handle);
+        window->context.wgl.handle = NULL;
+    }
+}
+
+// Initialize WGL-specific extensions
+//
+static void loadWGLExtensions(void)
+{
+    PIXELFORMATDESCRIPTOR pfd;
+    HGLRC rc;
+    HDC dc = GetDC(_glfw.win32.helperWindowHandle);;
+
+    _glfw.wgl.extensionsLoaded = GLFW_TRUE;
+
+    // NOTE: A dummy context has to be created for opengl32.dll to load the
+    //       OpenGL ICD, from which we can then query WGL extensions
+    // NOTE: This code will accept the Microsoft GDI ICD; accelerated context
+    //       creation failure occurs during manual pixel format enumeration
+
+    ZeroMemory(&pfd, sizeof(pfd));
+    pfd.nSize = sizeof(pfd);
+    pfd.nVersion = 1;
+    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
+    pfd.iPixelType = PFD_TYPE_RGBA;
+    pfd.cColorBits = 24;
+
+    if (!SetPixelFormat(dc, ChoosePixelFormat(dc, &pfd), &pfd))
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "WGL: Failed to set pixel format for dummy context");
+        return;
+    }
+
+    rc = wglCreateContext(dc);
+    if (!rc)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "WGL: Failed to create dummy context");
+        return;
+    }
+
+    if (!wglMakeCurrent(dc, rc))
+    {
+        wglDeleteContext(rc);
+
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "WGL: Failed to make dummy context current");
+        return;
+    }
+
+    // NOTE: Functions must be loaded first as they're needed to retrieve the
+    //       extension string that tells us whether the functions are supported
+    _glfw.wgl.GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)
+        wglGetProcAddress("wglGetExtensionsStringEXT");
+    _glfw.wgl.GetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)
+        wglGetProcAddress("wglGetExtensionsStringARB");
+    _glfw.wgl.CreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)
+        wglGetProcAddress("wglCreateContextAttribsARB");
+    _glfw.wgl.SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)
+        wglGetProcAddress("wglSwapIntervalEXT");
+    _glfw.wgl.GetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)
+        wglGetProcAddress("wglGetPixelFormatAttribivARB");
+
+    // NOTE: WGL_ARB_extensions_string and WGL_EXT_extensions_string are not
+    //       checked below as we are already using them
+    _glfw.wgl.ARB_multisample =
+        extensionSupportedWGL("WGL_ARB_multisample");
+    _glfw.wgl.ARB_framebuffer_sRGB =
+        extensionSupportedWGL("WGL_ARB_framebuffer_sRGB");
+    _glfw.wgl.EXT_framebuffer_sRGB =
+        extensionSupportedWGL("WGL_EXT_framebuffer_sRGB");
+    _glfw.wgl.ARB_create_context =
+        extensionSupportedWGL("WGL_ARB_create_context");
+    _glfw.wgl.ARB_create_context_profile =
+        extensionSupportedWGL("WGL_ARB_create_context_profile");
+    _glfw.wgl.EXT_create_context_es2_profile =
+        extensionSupportedWGL("WGL_EXT_create_context_es2_profile");
+    _glfw.wgl.ARB_create_context_robustness =
+        extensionSupportedWGL("WGL_ARB_create_context_robustness");
+    _glfw.wgl.EXT_swap_control =
+        extensionSupportedWGL("WGL_EXT_swap_control");
+    _glfw.wgl.ARB_pixel_format =
+        extensionSupportedWGL("WGL_ARB_pixel_format");
+    _glfw.wgl.ARB_context_flush_control =
+        extensionSupportedWGL("WGL_ARB_context_flush_control");
+
+    wglMakeCurrent(dc, NULL);
+    wglDeleteContext(rc);
+}
+
+
 //////////////////////////////////////////////////////////////////////////
 //////                       GLFW internal API                      //////
 //////////////////////////////////////////////////////////////////////////
 
 // Initialize WGL
 //
-int _glfwInitContextAPI(void)
+GLFWbool _glfwInitWGL(void)
 {
-    if (!_glfwInitTLS())
-        return GL_FALSE;
+    if (_glfw.wgl.instance)
+        return GLFW_TRUE;
 
-    _glfw.wgl.opengl32.instance = LoadLibraryW(L"opengl32.dll");
-    if (!_glfw.wgl.opengl32.instance)
+    _glfw.wgl.instance = LoadLibraryA("opengl32.dll");
+    if (!_glfw.wgl.instance)
     {
-        _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to load opengl32.dll");
-        return GL_FALSE;
+        _glfwInputError(GLFW_PLATFORM_ERROR, "WGL: Failed to load opengl32.dll");
+        return GLFW_FALSE;
     }
 
-    return GL_TRUE;
+    _glfw.wgl.CreateContext = (WGLCREATECONTEXT_T)
+        GetProcAddress(_glfw.wgl.instance, "wglCreateContext");
+    _glfw.wgl.DeleteContext = (WGLDELETECONTEXT_T)
+        GetProcAddress(_glfw.wgl.instance, "wglDeleteContext");
+    _glfw.wgl.GetProcAddress = (WGLGETPROCADDRESS_T)
+        GetProcAddress(_glfw.wgl.instance, "wglGetProcAddress");
+    _glfw.wgl.GetCurrentDC = (WGLGETCURRENTDC_T)
+        GetProcAddress(_glfw.wgl.instance, "wglGetCurrentDC");
+    _glfw.wgl.MakeCurrent = (WGLMAKECURRENT_T)
+        GetProcAddress(_glfw.wgl.instance, "wglMakeCurrent");
+    _glfw.wgl.ShareLists = (WGLSHARELISTS_T)
+        GetProcAddress(_glfw.wgl.instance, "wglShareLists");
+
+    return GLFW_TRUE;
 }
 
 // Terminate WGL
 //
-void _glfwTerminateContextAPI(void)
+void _glfwTerminateWGL(void)
 {
-    if (_glfw.wgl.opengl32.instance)
-        FreeLibrary(_glfw.wgl.opengl32.instance);
-
-    _glfwTerminateTLS();
+    if (_glfw.wgl.instance)
+        FreeLibrary(_glfw.wgl.instance);
 }
 
 #define setWGLattrib(attribName, attribValue) \
@@ -351,75 +467,118 @@
 
 // Create the OpenGL or OpenGL ES context
 //
-int _glfwCreateContext(_GLFWwindow* window,
-                       const _GLFWctxconfig* ctxconfig,
-                       const _GLFWfbconfig* fbconfig)
+GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
+                               const _GLFWctxconfig* ctxconfig,
+                               const _GLFWfbconfig* fbconfig)
 {
     int attribs[40];
-    int pixelFormat = 0;
+    int pixelFormat;
     PIXELFORMATDESCRIPTOR pfd;
     HGLRC share = NULL;
 
+    if (!_glfw.wgl.extensionsLoaded)
+        loadWGLExtensions();
+
     if (ctxconfig->share)
-        share = ctxconfig->share->wgl.context;
+        share = ctxconfig->share->context.wgl.handle;
 
-    window->wgl.dc = GetDC(window->win32.handle);
-    if (!window->wgl.dc)
+    window->context.wgl.dc = GetDC(window->win32.handle);
+    if (!window->context.wgl.dc)
     {
         _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "Win32: Failed to retrieve DC for window");
-        return GL_FALSE;
+                        "WGL: Failed to retrieve DC for window");
+        return GLFW_FALSE;
     }
 
-    if (!choosePixelFormat(window, fbconfig, &pixelFormat))
-        return GL_FALSE;
+    pixelFormat = choosePixelFormat(window, fbconfig);
+    if (!pixelFormat)
+        return GLFW_FALSE;
 
-    if (!DescribePixelFormat(window->wgl.dc, pixelFormat, sizeof(pfd), &pfd))
+    if (!DescribePixelFormat(window->context.wgl.dc,
+                             pixelFormat, sizeof(pfd), &pfd))
     {
         _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "Win32: Failed to retrieve PFD for selected pixel "
-                        "format");
-        return GL_FALSE;
+                        "WGL: Failed to retrieve PFD for selected pixel format");
+        return GLFW_FALSE;
     }
 
-    if (!SetPixelFormat(window->wgl.dc, pixelFormat, &pfd))
+    if (!SetPixelFormat(window->context.wgl.dc, pixelFormat, &pfd))
     {
         _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "Win32: Failed to set selected pixel format");
-        return GL_FALSE;
+                        "WGL: Failed to set selected pixel format");
+        return GLFW_FALSE;
     }
 
-    if (window->wgl.ARB_create_context)
+    if (ctxconfig->client == GLFW_OPENGL_API)
     {
-        int index = 0, mask = 0, flags = 0, strategy = 0;
+        if (ctxconfig->forward)
+        {
+            if (!_glfw.wgl.ARB_create_context)
+            {
+                _glfwInputError(GLFW_VERSION_UNAVAILABLE,
+                                "WGL: A forward compatible OpenGL context requested but WGL_ARB_create_context is unavailable");
+                return GLFW_FALSE;
+            }
+        }
 
-        if (ctxconfig->api == GLFW_OPENGL_API)
+        if (ctxconfig->profile)
         {
+            if (!_glfw.wgl.ARB_create_context_profile)
+            {
+                _glfwInputError(GLFW_VERSION_UNAVAILABLE,
+                                "WGL: OpenGL profile requested but WGL_ARB_create_context_profile is unavailable");
+                return GLFW_FALSE;
+            }
+        }
+    }
+    else
+    {
+        if (!_glfw.wgl.ARB_create_context ||
+            !_glfw.wgl.ARB_create_context_profile ||
+            !_glfw.wgl.EXT_create_context_es2_profile)
+        {
+            _glfwInputError(GLFW_API_UNAVAILABLE,
+                            "WGL: OpenGL ES requested but WGL_ARB_create_context_es2_profile is unavailable");
+            return GLFW_FALSE;
+        }
+    }
+
+    if (_glfw.wgl.ARB_create_context)
+    {
+        int index = 0, mask = 0, flags = 0;
+
+        if (ctxconfig->client == GLFW_OPENGL_API)
+        {
             if (ctxconfig->forward)
                 flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
 
-            if (ctxconfig->debug)
-                flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
-
-            if (ctxconfig->profile)
-            {
-                if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
-                    mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
-                else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
-                    mask |= WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
-            }
+            if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
+                mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
+            else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
+                mask |= WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
         }
         else
             mask |= WGL_CONTEXT_ES2_PROFILE_BIT_EXT;
 
+        if (ctxconfig->debug)
+            flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
+        if (ctxconfig->noerror)
+            flags |= GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR;
+
         if (ctxconfig->robustness)
         {
-            if (window->wgl.ARB_create_context_robustness)
+            if (_glfw.wgl.ARB_create_context_robustness)
             {
                 if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
-                    strategy = WGL_NO_RESET_NOTIFICATION_ARB;
+                {
+                    setWGLattrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
+                                 WGL_NO_RESET_NOTIFICATION_ARB);
+                }
                 else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
-                    strategy = WGL_LOSE_CONTEXT_ON_RESET_ARB;
+                {
+                    setWGLattrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
+                                 WGL_LOSE_CONTEXT_ON_RESET_ARB);
+                }
 
                 flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB;
             }
@@ -427,7 +586,7 @@
 
         if (ctxconfig->release)
         {
-            if (window->wgl.ARB_context_flush_control)
+            if (_glfw.wgl.ARB_context_flush_control)
             {
                 if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE)
                 {
@@ -442,12 +601,11 @@
             }
         }
 
+        // NOTE: Only request an explicitly versioned context when necessary, as
+        //       explicitly requesting version 1.0 does not always return the
+        //       highest version supported by the driver
         if (ctxconfig->major != 1 || ctxconfig->minor != 0)
         {
-            // NOTE: Only request an explicitly versioned context when
-            //       necessary, as explicitly requesting version 1.0 does not
-            //       always return the highest available version
-
             setWGLattrib(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major);
             setWGLattrib(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor);
         }
@@ -458,242 +616,86 @@
         if (mask)
             setWGLattrib(WGL_CONTEXT_PROFILE_MASK_ARB, mask);
 
-        if (strategy)
-            setWGLattrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, strategy);
-
         setWGLattrib(0, 0);
 
-        window->wgl.context = window->wgl.CreateContextAttribsARB(window->wgl.dc,
-                                                                  share,
-                                                                  attribs);
-        if (!window->wgl.context)
-        {
-            _glfwInputError(GLFW_VERSION_UNAVAILABLE,
-                            "WGL: Failed to create OpenGL context");
-            return GL_FALSE;
-        }
-    }
-    else
-    {
-        window->wgl.context = wglCreateContext(window->wgl.dc);
-        if (!window->wgl.context)
+        window->context.wgl.handle =
+            _glfw.wgl.CreateContextAttribsARB(window->context.wgl.dc,
+                                              share, attribs);
+        if (!window->context.wgl.handle)
         {
-            _glfwInputError(GLFW_PLATFORM_ERROR,
-                            "WGL: Failed to create OpenGL context");
-            return GL_FALSE;
-        }
+            const DWORD error = GetLastError();
 
-        if (share)
-        {
-            if (!wglShareLists(share, window->wgl.context))
+            if (error == (0xc0070000 | ERROR_INVALID_VERSION_ARB))
             {
-                _glfwInputError(GLFW_PLATFORM_ERROR,
-                                "WGL: Failed to enable sharing with specified "
-                                "OpenGL context");
-                return GL_FALSE;
+                if (ctxconfig->client == GLFW_OPENGL_API)
+                {
+                    _glfwInputError(GLFW_VERSION_UNAVAILABLE,
+                                    "WGL: Driver does not support OpenGL version %i.%i",
+                                    ctxconfig->major,
+                                    ctxconfig->minor);
+                }
+                else
+                {
+                    _glfwInputError(GLFW_VERSION_UNAVAILABLE,
+                                    "WGL: Driver does not support OpenGL ES version %i.%i",
+                                    ctxconfig->major,
+                                    ctxconfig->minor);
+                }
             }
-        }
-    }
-
-    _glfwPlatformMakeContextCurrent(window);
-    initWGLExtensions(window);
-
-    return GL_TRUE;
-}
-
-#undef setWGLattrib
-
-// Destroy the OpenGL context
-//
-void _glfwDestroyContext(_GLFWwindow* window)
-{
-    if (window->wgl.context)
-    {
-        wglDeleteContext(window->wgl.context);
-        window->wgl.context = NULL;
-    }
-
-    if (window->wgl.dc)
-    {
-        ReleaseDC(window->win32.handle, window->wgl.dc);
-        window->wgl.dc = NULL;
-    }
-}
-
-// Analyzes the specified context for possible recreation
-//
-int _glfwAnalyzeContext(const _GLFWwindow* window,
-                        const _GLFWctxconfig* ctxconfig,
-                        const _GLFWfbconfig* fbconfig)
-{
-    GLboolean required = GL_FALSE;
-
-    if (ctxconfig->api == GLFW_OPENGL_API)
-    {
-        if (ctxconfig->forward)
-        {
-            if (!window->wgl.ARB_create_context)
+            else if (error == (0xc0070000 | ERROR_INVALID_PROFILE_ARB))
             {
                 _glfwInputError(GLFW_VERSION_UNAVAILABLE,
-                                "WGL: A forward compatible OpenGL context "
-                                "requested but WGL_ARB_create_context is "
-                                "unavailable");
-                return _GLFW_RECREATION_IMPOSSIBLE;
+                                "WGL: Driver does not support the requested OpenGL profile");
             }
-
-            required = GL_TRUE;
-        }
-
-        if (ctxconfig->profile)
-        {
-            if (!window->wgl.ARB_create_context_profile)
+            else
             {
-                _glfwInputError(GLFW_VERSION_UNAVAILABLE,
-                                "WGL: OpenGL profile requested but "
-                                "WGL_ARB_create_context_profile is unavailable");
-                return _GLFW_RECREATION_IMPOSSIBLE;
+                if (ctxconfig->client == GLFW_OPENGL_API)
+                {
+                    _glfwInputError(GLFW_VERSION_UNAVAILABLE,
+                                    "WGL: Failed to create OpenGL context");
+                }
+                else
+                {
+                    _glfwInputError(GLFW_VERSION_UNAVAILABLE,
+                                    "WGL: Failed to create OpenGL ES context");
+                }
             }
 
-            required = GL_TRUE;
-        }
-
-        if (ctxconfig->release)
-        {
-            if (window->wgl.ARB_context_flush_control)
-                required = GL_TRUE;
+            return GLFW_FALSE;
         }
     }
     else
     {
-        if (!window->wgl.ARB_create_context ||
-            !window->wgl.ARB_create_context_profile ||
-            !window->wgl.EXT_create_context_es2_profile)
+        window->context.wgl.handle = wglCreateContext(window->context.wgl.dc);
+        if (!window->context.wgl.handle)
         {
-            _glfwInputError(GLFW_API_UNAVAILABLE,
-                            "WGL: OpenGL ES requested but "
-                            "WGL_ARB_create_context_es2_profile is unavailable");
-            return _GLFW_RECREATION_IMPOSSIBLE;
+            _glfwInputError(GLFW_VERSION_UNAVAILABLE,
+                            "WGL: Failed to create OpenGL context");
+            return GLFW_FALSE;
         }
 
-        required = GL_TRUE;
-    }
-
-    if (ctxconfig->major != 1 || ctxconfig->minor != 0)
-    {
-        if (window->wgl.ARB_create_context)
-            required = GL_TRUE;
-    }
-
-    if (ctxconfig->debug)
-    {
-        if (window->wgl.ARB_create_context)
-            required = GL_TRUE;
-    }
-
-    if (fbconfig->samples > 0)
-    {
-        // We want FSAA, but can we get it?
-        // FSAA is not a hard constraint, so otherwise we just don't care
-
-        if (window->wgl.ARB_multisample && window->wgl.ARB_pixel_format)
-        {
-            // We appear to have both the extension and the means to ask for it
-            required = GL_TRUE;
-        }
-    }
-
-    if (fbconfig->sRGB)
-    {
-        // We want sRGB, but can we get it?
-        // sRGB is not a hard constraint, so otherwise we just don't care
-
-        if (window->wgl.ARB_framebuffer_sRGB && window->wgl.ARB_pixel_format)
-        {
-            // We appear to have both the extension and the means to ask for it
-            required = GL_TRUE;
-        }
-    }
-
-    if (required)
-        return _GLFW_RECREATION_REQUIRED;
-
-    return _GLFW_RECREATION_NOT_NEEDED;
-}
-
-
-//////////////////////////////////////////////////////////////////////////
-//////                       GLFW platform API                      //////
-//////////////////////////////////////////////////////////////////////////
-
-void _glfwPlatformMakeContextCurrent(_GLFWwindow* window)
-{
-    if (window)
-        wglMakeCurrent(window->wgl.dc, window->wgl.context);
-    else
-        wglMakeCurrent(NULL, NULL);
-
-    _glfwSetCurrentContext(window);
-}
-
-void _glfwPlatformSwapBuffers(_GLFWwindow* window)
-{
-    SwapBuffers(window->wgl.dc);
-}
-
-void _glfwPlatformSwapInterval(int interval)
-{
-    _GLFWwindow* window = _glfwPlatformGetCurrentContext();
-
-#if !defined(_GLFW_USE_DWM_SWAP_INTERVAL)
-    if (_glfwIsCompositionEnabled() && interval)
-    {
-        // Don't enabled vsync when desktop compositing is enabled, as it leads
-        // to frame jitter
-        return;
-    }
-#endif
-
-    if (window->wgl.EXT_swap_control)
-        window->wgl.SwapIntervalEXT(interval);
-}
-
-int _glfwPlatformExtensionSupported(const char* extension)
-{
-    const GLubyte* extensions;
-
-    _GLFWwindow* window = _glfwPlatformGetCurrentContext();
-
-    if (window->wgl.GetExtensionsStringEXT != NULL)
-    {
-        extensions = (GLubyte*) window->wgl.GetExtensionsStringEXT();
-        if (extensions != NULL)
+        if (share)
         {
-            if (_glfwStringInExtensionString(extension, extensions))
-                return GL_TRUE;
+            if (!wglShareLists(share, window->context.wgl.handle))
+            {
+                _glfwInputError(GLFW_PLATFORM_ERROR,
+                                "WGL: Failed to enable sharing with specified OpenGL context");
+                return GLFW_FALSE;
+            }
         }
     }
 
-    if (window->wgl.GetExtensionsStringARB != NULL)
-    {
-        extensions = (GLubyte*) window->wgl.GetExtensionsStringARB(window->wgl.dc);
-        if (extensions != NULL)
-        {
-            if (_glfwStringInExtensionString(extension, extensions))
-                return GL_TRUE;
-        }
-    }
+    window->context.makeCurrent = makeContextCurrentWGL;
+    window->context.swapBuffers = swapBuffersWGL;
+    window->context.swapInterval = swapIntervalWGL;
+    window->context.extensionSupported = extensionSupportedWGL;
+    window->context.getProcAddress = getProcAddressWGL;
+    window->context.destroy = destroyContextWGL;
 
-    return GL_FALSE;
+    return GLFW_TRUE;
 }
 
-GLFWglproc _glfwPlatformGetProcAddress(const char* procname)
-{
-    const GLFWglproc proc = (GLFWglproc) wglGetProcAddress(procname);
-    if (proc)
-        return proc;
-
-    return (GLFWglproc) GetProcAddress(_glfw.wgl.opengl32.instance, procname);
-}
+#undef setWGLattrib
 
 
 //////////////////////////////////////////////////////////////////////////
@@ -704,6 +706,13 @@
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
-    return window->wgl.context;
+
+    if (window->context.client == GLFW_NO_API)
+    {
+        _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
+        return NULL;
+    }
+
+    return window->context.wgl.handle;
 }
 
diff --git a/glfw/src/wgl_context.h b/glfw/src/wgl_context.h
--- a/glfw/src/wgl_context.h
+++ b/glfw/src/wgl_context.h
@@ -1,8 +1,8 @@
 //========================================================================
-// GLFW 3.1 WGL - www.glfw.org
+// GLFW 3.2 WGL - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -25,15 +25,82 @@
 //
 //========================================================================
 
-#ifndef _wgl_context_h_
-#define _wgl_context_h_
+#ifndef _glfw3_wgl_context_h_
+#define _glfw3_wgl_context_h_
 
-// This path may need to be changed if you build GLFW using your own setup
-// We ship and use our own copy of wglext.h since GLFW uses fairly new
-// extensions and not all operating systems come with an up-to-date version
-#include "../deps/GL/wglext.h"
 
-#define _GLFW_PLATFORM_FBCONFIG                 int             wgl
+#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
+#define WGL_SUPPORT_OPENGL_ARB 0x2010
+#define WGL_DRAW_TO_WINDOW_ARB 0x2001
+#define WGL_PIXEL_TYPE_ARB 0x2013
+#define WGL_TYPE_RGBA_ARB 0x202b
+#define WGL_ACCELERATION_ARB 0x2003
+#define WGL_NO_ACCELERATION_ARB 0x2025
+#define WGL_RED_BITS_ARB 0x2015
+#define WGL_RED_SHIFT_ARB 0x2016
+#define WGL_GREEN_BITS_ARB 0x2017
+#define WGL_GREEN_SHIFT_ARB 0x2018
+#define WGL_BLUE_BITS_ARB 0x2019
+#define WGL_BLUE_SHIFT_ARB 0x201a
+#define WGL_ALPHA_BITS_ARB 0x201b
+#define WGL_ALPHA_SHIFT_ARB 0x201c
+#define WGL_ACCUM_BITS_ARB 0x201d
+#define WGL_ACCUM_RED_BITS_ARB 0x201e
+#define WGL_ACCUM_GREEN_BITS_ARB 0x201f
+#define WGL_ACCUM_BLUE_BITS_ARB 0x2020
+#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021
+#define WGL_DEPTH_BITS_ARB 0x2022
+#define WGL_STENCIL_BITS_ARB 0x2023
+#define WGL_AUX_BUFFERS_ARB 0x2024
+#define WGL_STEREO_ARB 0x2012
+#define WGL_DOUBLE_BUFFER_ARB 0x2011
+#define WGL_SAMPLES_ARB 0x2042
+#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9
+#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001
+#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
+#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
+#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
+#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
+#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
+#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
+#define WGL_CONTEXT_FLAGS_ARB 0x2094
+#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
+#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
+#define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252
+#define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
+#define WGL_NO_RESET_NOTIFICATION_ARB 0x8261
+#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
+#define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0
+#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
+
+#define ERROR_INVALID_VERSION_ARB 0x2095
+#define ERROR_INVALID_PROFILE_ARB 0x2096
+
+typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC)(int);
+typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC)(HDC,int,int,UINT,const int*,int*);
+typedef const char* (WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC)(void);
+typedef const char* (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC);
+typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC,HGLRC,const int*);
+
+typedef HGLRC (WINAPI * WGLCREATECONTEXT_T)(HDC);
+typedef BOOL (WINAPI * WGLDELETECONTEXT_T)(HGLRC);
+typedef PROC (WINAPI * WGLGETPROCADDRESS_T)(LPCSTR);
+typedef HDC (WINAPI * WGLGETCURRENTDC_T)(void);
+typedef BOOL (WINAPI * WGLMAKECURRENT_T)(HDC,HGLRC);
+typedef BOOL (WINAPI * WGLSHARELISTS_T)(HGLRC,HGLRC);
+
+// opengl32.dll function pointer typedefs
+#define wglCreateContext _glfw.wgl.CreateContext
+#define wglDeleteContext _glfw.wgl.DeleteContext
+#define wglGetProcAddress _glfw.wgl.GetProcAddress
+#define wglGetCurrentDC _glfw.wgl.GetCurrentDC
+#define wglMakeCurrent _glfw.wgl.MakeCurrent
+#define wglShareLists _glfw.wgl.ShareLists
+
+#define _GLFW_RECREATION_NOT_NEEDED 0
+#define _GLFW_RECREATION_REQUIRED   1
+#define _GLFW_RECREATION_IMPOSSIBLE 2
+
 #define _GLFW_PLATFORM_CONTEXT_STATE            _GLFWcontextWGL wgl
 #define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE    _GLFWlibraryWGL wgl
 
@@ -42,48 +109,49 @@
 //
 typedef struct _GLFWcontextWGL
 {
-    HDC       dc;              // Private GDI device context
-    HGLRC     context;         // Permanent rendering context
-
-    // WGL extensions (context specific)
-    PFNWGLSWAPINTERVALEXTPROC           SwapIntervalEXT;
-    PFNWGLGETPIXELFORMATATTRIBIVARBPROC GetPixelFormatAttribivARB;
-    PFNWGLGETEXTENSIONSSTRINGEXTPROC    GetExtensionsStringEXT;
-    PFNWGLGETEXTENSIONSSTRINGARBPROC    GetExtensionsStringARB;
-    PFNWGLCREATECONTEXTATTRIBSARBPROC   CreateContextAttribsARB;
-    GLboolean                           EXT_swap_control;
-    GLboolean                           ARB_multisample;
-    GLboolean                           ARB_framebuffer_sRGB;
-    GLboolean                           ARB_pixel_format;
-    GLboolean                           ARB_create_context;
-    GLboolean                           ARB_create_context_profile;
-    GLboolean                           EXT_create_context_es2_profile;
-    GLboolean                           ARB_create_context_robustness;
-    GLboolean                           ARB_context_flush_control;
+    HDC       dc;
+    HGLRC     handle;
+    int       interval;
 
 } _GLFWcontextWGL;
 
-
 // WGL-specific global data
 //
 typedef struct _GLFWlibraryWGL
 {
-    // opengl32.dll (for glfwGetProcAddress)
-    struct {
-        HINSTANCE   instance;
-    } opengl32;
+    HINSTANCE                           instance;
+    WGLCREATECONTEXT_T                  CreateContext;
+    WGLDELETECONTEXT_T                  DeleteContext;
+    WGLGETPROCADDRESS_T                 GetProcAddress;
+    WGLGETCURRENTDC_T                   GetCurrentDC;
+    WGLMAKECURRENT_T                    MakeCurrent;
+    WGLSHARELISTS_T                     ShareLists;
 
+    GLFWbool                            extensionsLoaded;
+
+    PFNWGLSWAPINTERVALEXTPROC           SwapIntervalEXT;
+    PFNWGLGETPIXELFORMATATTRIBIVARBPROC GetPixelFormatAttribivARB;
+    PFNWGLGETEXTENSIONSSTRINGEXTPROC    GetExtensionsStringEXT;
+    PFNWGLGETEXTENSIONSSTRINGARBPROC    GetExtensionsStringARB;
+    PFNWGLCREATECONTEXTATTRIBSARBPROC   CreateContextAttribsARB;
+    GLFWbool                            EXT_swap_control;
+    GLFWbool                            ARB_multisample;
+    GLFWbool                            ARB_framebuffer_sRGB;
+    GLFWbool                            EXT_framebuffer_sRGB;
+    GLFWbool                            ARB_pixel_format;
+    GLFWbool                            ARB_create_context;
+    GLFWbool                            ARB_create_context_profile;
+    GLFWbool                            EXT_create_context_es2_profile;
+    GLFWbool                            ARB_create_context_robustness;
+    GLFWbool                            ARB_context_flush_control;
+
 } _GLFWlibraryWGL;
 
 
-int _glfwInitContextAPI(void);
-void _glfwTerminateContextAPI(void);
-int _glfwCreateContext(_GLFWwindow* window,
-                       const _GLFWctxconfig* ctxconfig,
-                       const _GLFWfbconfig* fbconfig);
-void _glfwDestroyContext(_GLFWwindow* window);
-int _glfwAnalyzeContext(const _GLFWwindow* window,
-                        const _GLFWctxconfig* ctxconfig,
-                        const _GLFWfbconfig* fbconfig);
+GLFWbool _glfwInitWGL(void);
+void _glfwTerminateWGL(void);
+GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
+                               const _GLFWctxconfig* ctxconfig,
+                               const _GLFWfbconfig* fbconfig);
 
-#endif // _wgl_context_h_
+#endif // _glfw3_wgl_context_h_
diff --git a/glfw/src/win32_init.c b/glfw/src/win32_init.c
--- a/glfw/src/win32_init.c
+++ b/glfw/src/win32_init.c
@@ -1,8 +1,8 @@
 //========================================================================
-// GLFW 3.1 Win32 - www.glfw.org
+// GLFW 3.2 Win32 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -30,20 +30,24 @@
 #include <stdlib.h>
 #include <malloc.h>
 
-#ifdef __BORLANDC__
-// With the Borland C++ compiler, we want to disable FPU exceptions
-#include <float.h>
-#endif // __BORLANDC__
+#include <initguid.h>
+DEFINE_GUID(GUID_DEVINTERFACE_HID,0x4d1e55b2,0xf16f,0x11cf,0x88,0xcb,0x00,0x11,0x11,0x00,0x00,0x30);
 
+#if defined(_GLFW_USE_HYBRID_HPG) || defined(_GLFW_USE_OPTIMUS_HPG)
 
-#if defined(_GLFW_USE_OPTIMUS_HPG)
+// Applications exporting this symbol with this value will be automatically
+// directed to the high-performance GPU on Nvidia Optimus systems with
+// up-to-date drivers
+//
+__declspec(dllexport) DWORD NvOptimusEnablement = 1;
 
 // Applications exporting this symbol with this value will be automatically
-// directed to the high-performance GPU on Nvidia Optimus systems
+// directed to the high-performance GPU on AMD PowerXpress systems with
+// up-to-date drivers
 //
-__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
+__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
 
-#endif // _GLFW_USE_OPTIMUS_HPG
+#endif // _GLFW_USE_HYBRID_HPG
 
 #if defined(_GLFW_BUILD_DLL)
 
@@ -58,58 +62,93 @@
 
 // Load necessary libraries (DLLs)
 //
-static GLboolean initLibraries(void)
+static GLFWbool loadLibraries(void)
 {
-    _glfw.win32.winmm.instance = LoadLibraryW(L"winmm.dll");
+    _glfw.win32.winmm.instance = LoadLibraryA("winmm.dll");
     if (!_glfw.win32.winmm.instance)
     {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "Win32: Failed to load winmm.dll");
-        return GL_FALSE;
+        _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to load winmm.dll");
+        return GLFW_FALSE;
     }
 
-    _glfw.win32.winmm.joyGetDevCaps = (JOYGETDEVCAPS_T)
-        GetProcAddress(_glfw.win32.winmm.instance, "joyGetDevCapsW");
-    _glfw.win32.winmm.joyGetPos = (JOYGETPOS_T)
-        GetProcAddress(_glfw.win32.winmm.instance, "joyGetPos");
-    _glfw.win32.winmm.joyGetPosEx = (JOYGETPOSEX_T)
-        GetProcAddress(_glfw.win32.winmm.instance, "joyGetPosEx");
     _glfw.win32.winmm.timeGetTime = (TIMEGETTIME_T)
         GetProcAddress(_glfw.win32.winmm.instance, "timeGetTime");
 
-    if (!_glfw.win32.winmm.joyGetDevCaps ||
-        !_glfw.win32.winmm.joyGetPos ||
-        !_glfw.win32.winmm.joyGetPosEx ||
-        !_glfw.win32.winmm.timeGetTime)
+    _glfw.win32.user32.instance = LoadLibraryA("user32.dll");
+    if (!_glfw.win32.user32.instance)
     {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "Win32: Failed to load winmm functions");
-        return GL_FALSE;
+        _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to load user32.dll");
+        return GLFW_FALSE;
     }
 
-    _glfw.win32.user32.instance = LoadLibraryW(L"user32.dll");
-    if (_glfw.win32.user32.instance)
+    _glfw.win32.user32.SetProcessDPIAware = (SETPROCESSDPIAWARE_T)
+        GetProcAddress(_glfw.win32.user32.instance, "SetProcessDPIAware");
+    _glfw.win32.user32.ChangeWindowMessageFilterEx = (CHANGEWINDOWMESSAGEFILTEREX_T)
+        GetProcAddress(_glfw.win32.user32.instance, "ChangeWindowMessageFilterEx");
+
+    _glfw.win32.dinput8.instance = LoadLibraryA("dinput8.dll");
+    if (_glfw.win32.dinput8.instance)
     {
-        _glfw.win32.user32.SetProcessDPIAware = (SETPROCESSDPIAWARE_T)
-            GetProcAddress(_glfw.win32.user32.instance, "SetProcessDPIAware");
-        _glfw.win32.user32.ChangeWindowMessageFilterEx = (CHANGEWINDOWMESSAGEFILTEREX_T)
-            GetProcAddress(_glfw.win32.user32.instance, "ChangeWindowMessageFilterEx");
+        _glfw.win32.dinput8.DirectInput8Create = (DIRECTINPUT8CREATE_T)
+            GetProcAddress(_glfw.win32.dinput8.instance, "DirectInput8Create");
     }
 
-    _glfw.win32.dwmapi.instance = LoadLibraryW(L"dwmapi.dll");
+    {
+        int i;
+        const char* names[] =
+        {
+            "xinput1_4.dll",
+            "xinput1_3.dll",
+            "xinput9_1_0.dll",
+            "xinput1_2.dll",
+            "xinput1_1.dll",
+            NULL
+        };
+
+        for (i = 0;  names[i];  i++)
+        {
+            _glfw.win32.xinput.instance = LoadLibraryA(names[i]);
+            if (_glfw.win32.xinput.instance)
+            {
+                _glfw.win32.xinput.XInputGetCapabilities = (XINPUTGETCAPABILITIES_T)
+                    GetProcAddress(_glfw.win32.xinput.instance, "XInputGetCapabilities");
+                _glfw.win32.xinput.XInputGetState = (XINPUTGETSTATE_T)
+                    GetProcAddress(_glfw.win32.xinput.instance, "XInputGetState");
+
+                break;
+            }
+        }
+    }
+
+    _glfw.win32.dwmapi.instance = LoadLibraryA("dwmapi.dll");
     if (_glfw.win32.dwmapi.instance)
     {
         _glfw.win32.dwmapi.DwmIsCompositionEnabled = (DWMISCOMPOSITIONENABLED_T)
             GetProcAddress(_glfw.win32.dwmapi.instance, "DwmIsCompositionEnabled");
+        _glfw.win32.dwmapi.DwmFlush = (DWMFLUSH_T)
+            GetProcAddress(_glfw.win32.dwmapi.instance, "DwmFlush");
     }
 
-    return GL_TRUE;
+    _glfw.win32.shcore.instance = LoadLibraryA("shcore.dll");
+    if (_glfw.win32.shcore.instance)
+    {
+        _glfw.win32.shcore.SetProcessDpiAwareness = (SETPROCESSDPIAWARENESS_T)
+            GetProcAddress(_glfw.win32.shcore.instance, "SetProcessDpiAwareness");
+    }
+
+    return GLFW_TRUE;
 }
 
 // Unload used libraries (DLLs)
 //
-static void terminateLibraries(void)
+static void freeLibraries(void)
 {
+    if (_glfw.win32.xinput.instance)
+        FreeLibrary(_glfw.win32.xinput.instance);
+
+    if (_glfw.win32.dinput8.instance)
+        FreeLibrary(_glfw.win32.dinput8.instance);
+
     if (_glfw.win32.winmm.instance)
         FreeLibrary(_glfw.win32.winmm.instance);
 
@@ -118,13 +157,19 @@
 
     if (_glfw.win32.dwmapi.instance)
         FreeLibrary(_glfw.win32.dwmapi.instance);
+
+    if (_glfw.win32.shcore.instance)
+        FreeLibrary(_glfw.win32.shcore.instance);
 }
 
 // Create key code translation tables
 //
 static void createKeyTables(void)
 {
+    int scancode;
+
     memset(_glfw.win32.publicKeys, -1, sizeof(_glfw.win32.publicKeys));
+    memset(_glfw.win32.nativeKeys, -1, sizeof(_glfw.win32.nativeKeys));
 
     _glfw.win32.publicKeys[0x00B] = GLFW_KEY_0;
     _glfw.win32.publicKeys[0x002] = GLFW_KEY_1;
@@ -187,6 +232,7 @@
     _glfw.win32.publicKeys[0x151] = GLFW_KEY_PAGE_DOWN;
     _glfw.win32.publicKeys[0x149] = GLFW_KEY_PAGE_UP;
     _glfw.win32.publicKeys[0x045] = GLFW_KEY_PAUSE;
+    _glfw.win32.publicKeys[0x146] = GLFW_KEY_PAUSE;
     _glfw.win32.publicKeys[0x039] = GLFW_KEY_SPACE;
     _glfw.win32.publicKeys[0x00F] = GLFW_KEY_TAB;
     _glfw.win32.publicKeys[0x03A] = GLFW_KEY_CAPS_LOCK;
@@ -246,31 +292,61 @@
     _glfw.win32.publicKeys[0x11C] = GLFW_KEY_KP_ENTER;
     _glfw.win32.publicKeys[0x037] = GLFW_KEY_KP_MULTIPLY;
     _glfw.win32.publicKeys[0x04A] = GLFW_KEY_KP_SUBTRACT;
-}
 
-
-//////////////////////////////////////////////////////////////////////////
-//////                       GLFW internal API                      //////
-//////////////////////////////////////////////////////////////////////////
+    for (scancode = 0;  scancode < 512;  scancode++)
+    {
+        if (_glfw.win32.publicKeys[scancode] > 0)
+            _glfw.win32.nativeKeys[_glfw.win32.publicKeys[scancode]] = scancode;
+    }
+}
 
-// Returns whether desktop compositing is enabled
+// Creates a dummy window for behind-the-scenes work
 //
-BOOL _glfwIsCompositionEnabled(void)
+static HWND createHelperWindow(void)
 {
-    BOOL enabled;
+    HWND window = CreateWindowExW(WS_EX_OVERLAPPEDWINDOW,
+                                  _GLFW_WNDCLASSNAME,
+                                  L"GLFW helper window",
+                                  WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
+                                  0, 0, 1, 1,
+                                  HWND_MESSAGE, NULL,
+                                  GetModuleHandleW(NULL),
+                                  NULL);
+    if (!window)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Win32: Failed to create helper window");
+        return NULL;
+    }
 
-    if (!_glfw_DwmIsCompositionEnabled)
-        return FALSE;
+    // HACK: The first call to ShowWindow is ignored if the parent process
+    //       passed along a STARTUPINFO, so clear that flag with a no-op call
+    ShowWindow(window, SW_HIDE);
 
-    if (_glfw_DwmIsCompositionEnabled(&enabled) != S_OK)
-        return FALSE;
+    // Register for HID device notifications
+    {
+        DEV_BROADCAST_DEVICEINTERFACE_W dbi;
+        ZeroMemory(&dbi, sizeof(dbi));
+        dbi.dbcc_size = sizeof(dbi);
+        dbi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
+        dbi.dbcc_classguid = GUID_DEVINTERFACE_HID;
 
-    return enabled;
+        RegisterDeviceNotificationW(window,
+                                    (DEV_BROADCAST_HDR*) &dbi,
+                                    DEVICE_NOTIFY_WINDOW_HANDLE);
+    }
+
+   return window;
 }
 
+
+//////////////////////////////////////////////////////////////////////////
+//////                       GLFW internal API                      //////
+//////////////////////////////////////////////////////////////////////////
+
 // Returns a wide string version of the specified UTF-8 string
 //
-WCHAR* _glfwCreateWideStringFromUTF8(const char* source)
+WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source)
 {
     WCHAR* target;
     int length;
@@ -292,7 +368,7 @@
 
 // Returns a UTF-8 string version of the specified wide string
 //
-char* _glfwCreateUTF8FromWideString(const WCHAR* source)
+char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source)
 {
     char* target;
     int length;
@@ -301,7 +377,7 @@
     if (!length)
         return NULL;
 
-    target = calloc(length, sizeof(char));
+    target = calloc(length, 1);
 
     if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, length, NULL, NULL))
     {
@@ -319,6 +395,9 @@
 
 int _glfwPlatformInit(void)
 {
+    if (!_glfwInitThreadLocalStorageWin32())
+        return GLFW_FALSE;
+
     // To make SetForegroundWindow work as we want, we need to fiddle
     // with the FOREGROUNDLOCKTIMEOUT system setting (we do this as early
     // as possible in the hope of still being the foreground process)
@@ -327,36 +406,38 @@
     SystemParametersInfoW(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, UIntToPtr(0),
                           SPIF_SENDCHANGE);
 
-    if (!initLibraries())
-        return GL_FALSE;
+    if (!loadLibraries())
+        return GLFW_FALSE;
 
     createKeyTables();
 
-    if (_glfw_SetProcessDPIAware)
+    if (_glfw_SetProcessDpiAwareness)
+        _glfw_SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
+    else if (_glfw_SetProcessDPIAware)
         _glfw_SetProcessDPIAware();
 
-#ifdef __BORLANDC__
-    // With the Borland C++ compiler, we want to disable FPU exceptions
-    // (this is recommended for OpenGL applications under Windows)
-    _control87(MCW_EM, MCW_EM);
-#endif
+    if (!_glfwRegisterWindowClassWin32())
+        return GLFW_FALSE;
 
-    if (!_glfwRegisterWindowClass())
-        return GL_FALSE;
+    _glfw.win32.helperWindowHandle = createHelperWindow();
+    if (!_glfw.win32.helperWindowHandle)
+        return GLFW_FALSE;
 
-    if (!_glfwInitContextAPI())
-        return GL_FALSE;
+    _glfwPlatformPollEvents();
 
-    _glfwInitTimer();
-    _glfwInitJoysticks();
+    _glfwInitTimerWin32();
+    _glfwInitJoysticksWin32();
 
-    return GL_TRUE;
+    return GLFW_TRUE;
 }
 
 void _glfwPlatformTerminate(void)
 {
-    _glfwUnregisterWindowClass();
+    if (_glfw.win32.helperWindowHandle)
+        DestroyWindow(_glfw.win32.helperWindowHandle);
 
+    _glfwUnregisterWindowClassWin32();
+
     // Restore previous foreground lock timeout system setting
     SystemParametersInfoW(SPI_SETFOREGROUNDLOCKTIMEOUT, 0,
                           UIntToPtr(_glfw.win32.foregroundLockTimeout),
@@ -364,31 +445,29 @@
 
     free(_glfw.win32.clipboardString);
 
-    _glfwTerminateJoysticks();
-    _glfwTerminateContextAPI();
-    terminateLibraries();
+    _glfwTerminateWGL();
+    _glfwTerminateEGL();
+
+    _glfwTerminateJoysticksWin32();
+    _glfwTerminateThreadLocalStorageWin32();
+
+    freeLibraries();
 }
 
 const char* _glfwPlatformGetVersionString(void)
 {
-    const char* version = _GLFW_VERSION_NUMBER " Win32"
-#if defined(_GLFW_WGL)
-        " WGL"
-#elif defined(_GLFW_EGL)
-        " EGL"
-#endif
+    return _GLFW_VERSION_NUMBER " Win32 WGL EGL"
 #if defined(__MINGW32__)
         " MinGW"
 #elif defined(_MSC_VER)
         " VisualC"
-#elif defined(__BORLANDC__)
-        " BorlandC"
 #endif
+#if defined(_GLFW_USE_HYBRID_HPG) || defined(_GLFW_USE_OPTIMUS_HPG)
+        " hybrid-GPU"
+#endif
 #if defined(_GLFW_BUILD_DLL)
         " DLL"
 #endif
         ;
-
-    return version;
 }
 
diff --git a/glfw/src/win32_joystick.c b/glfw/src/win32_joystick.c
new file mode 100644
--- /dev/null
+++ b/glfw/src/win32_joystick.c
@@ -0,0 +1,763 @@
+//========================================================================
+// GLFW 3.1 Win32 - www.glfw.org
+//------------------------------------------------------------------------
+// Copyright (c) 2002-2006 Marcus Geelnard
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
+//
+// 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 <math.h>
+
+#include <initguid.h>
+
+#define _GLFW_PRESENCE_ONLY 1
+#define _GLFW_UPDATE_STATE  2
+
+#define _GLFW_TYPE_AXIS     0
+#define _GLFW_TYPE_SLIDER   1
+#define _GLFW_TYPE_BUTTON   2
+#define _GLFW_TYPE_POV      3
+
+// Data produced with DirectInput device object enumeration
+//
+typedef struct _GLFWobjenumWin32
+{
+    IDirectInputDevice8W*   device;
+    _GLFWjoyobjectWin32*    objects;
+    int                     objectCount;
+    int                     axisCount;
+    int                     sliderCount;
+    int                     buttonCount;
+    int                     povCount;
+} _GLFWobjenumWin32;
+
+// Define only the necessary GUIDs (it's bad enough that we're exporting these)
+//
+DEFINE_GUID(IID_IDirectInput8W,0xbf798031,0x483a,0x4da2,0xaa,0x99,0x5d,0x64,0xed,0x36,0x97,0x00);
+DEFINE_GUID(GUID_XAxis,0xa36d02e0,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00);
+DEFINE_GUID(GUID_YAxis,0xa36d02e1,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00);
+DEFINE_GUID(GUID_ZAxis,0xa36d02e2,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00);
+DEFINE_GUID(GUID_RxAxis,0xa36d02f4,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00);
+DEFINE_GUID(GUID_RyAxis,0xa36d02f5,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00);
+DEFINE_GUID(GUID_RzAxis,0xa36d02e3,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00);
+DEFINE_GUID(GUID_Slider,0xa36d02e4,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00);
+DEFINE_GUID(GUID_Button,0xa36d02f0,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00);
+DEFINE_GUID(GUID_POV,0xa36d02f2,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00);
+
+// Object data array for our clone of c_dfDIJoystick
+// Generated with https://github.com/elmindreda/c_dfDIJoystick2
+//
+static DIOBJECTDATAFORMAT _glfwObjectDataFormats[] =
+{
+    { &GUID_XAxis,DIJOFS_X,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
+    { &GUID_YAxis,DIJOFS_Y,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
+    { &GUID_ZAxis,DIJOFS_Z,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
+    { &GUID_RxAxis,DIJOFS_RX,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
+    { &GUID_RyAxis,DIJOFS_RY,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
+    { &GUID_RzAxis,DIJOFS_RZ,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
+    { &GUID_Slider,DIJOFS_SLIDER(0),DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
+    { &GUID_Slider,DIJOFS_SLIDER(1),DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
+    { &GUID_POV,DIJOFS_POV(0),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { &GUID_POV,DIJOFS_POV(1),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { &GUID_POV,DIJOFS_POV(2),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { &GUID_POV,DIJOFS_POV(3),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(0),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(1),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(2),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(3),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(4),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(5),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(6),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(7),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(8),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(9),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(10),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(11),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(12),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(13),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(14),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(15),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(16),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(17),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(18),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(19),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(20),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(21),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(22),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(23),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(24),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(25),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(26),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(27),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(28),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(29),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(30),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(31),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+};
+
+// Our clone of c_dfDIJoystick
+//
+static const DIDATAFORMAT _glfwDataFormat =
+{
+    sizeof(DIDATAFORMAT),
+    sizeof(DIOBJECTDATAFORMAT),
+    DIDFT_ABSAXIS,
+    sizeof(DIJOYSTATE),
+    sizeof(_glfwObjectDataFormats) / sizeof(DIOBJECTDATAFORMAT),
+    _glfwObjectDataFormats
+};
+
+// Returns a description fitting the specified XInput capabilities
+//
+static const char* getDeviceDescription(const XINPUT_CAPABILITIES* xic)
+{
+    switch (xic->SubType)
+    {
+        case XINPUT_DEVSUBTYPE_WHEEL:
+            return "XInput Wheel";
+        case XINPUT_DEVSUBTYPE_ARCADE_STICK:
+            return "XInput Arcade Stick";
+        case XINPUT_DEVSUBTYPE_FLIGHT_STICK:
+            return "XInput Flight Stick";
+        case XINPUT_DEVSUBTYPE_DANCE_PAD:
+            return "XInput Dance Pad";
+        case XINPUT_DEVSUBTYPE_GUITAR:
+            return "XInput Guitar";
+        case XINPUT_DEVSUBTYPE_DRUM_KIT:
+            return "XInput Drum Kit";
+        case XINPUT_DEVSUBTYPE_GAMEPAD:
+        {
+            if (xic->Flags & XINPUT_CAPS_WIRELESS)
+                return "Wireless Xbox 360 Controller";
+            else
+                return "Xbox 360 Controller";
+        }
+    }
+
+    return "Unknown XInput Device";
+}
+
+// Lexically compare device objects
+//
+static int compareJoystickObjects(const void* first, const void* second)
+{
+    const _GLFWjoyobjectWin32* fo = first;
+    const _GLFWjoyobjectWin32* so = second;
+
+    if (fo->type != so->type)
+        return fo->type - so->type;
+
+    return fo->offset - so->offset;
+}
+
+// Checks whether the specified device supports XInput
+// Technique from FDInputJoystickManager::IsXInputDeviceFast in ZDoom
+//
+static GLFWbool supportsXInput(const GUID* guid)
+{
+    UINT i, count = 0;
+    RAWINPUTDEVICELIST* ridl;
+    GLFWbool result = GLFW_FALSE;
+
+    if (GetRawInputDeviceList(NULL, &count, sizeof(RAWINPUTDEVICELIST)) != 0)
+        return GLFW_FALSE;
+
+    ridl = calloc(count, sizeof(RAWINPUTDEVICELIST));
+
+    if (GetRawInputDeviceList(ridl, &count, sizeof(RAWINPUTDEVICELIST)) == (UINT) -1)
+    {
+        free(ridl);
+        return GLFW_FALSE;
+    }
+
+    for (i = 0;  i < count;  i++)
+    {
+        RID_DEVICE_INFO rdi;
+        char name[256];
+        UINT size;
+
+        if (ridl[i].dwType != RIM_TYPEHID)
+            continue;
+
+        ZeroMemory(&rdi, sizeof(rdi));
+        rdi.cbSize = sizeof(rdi);
+        size = sizeof(rdi);
+
+        if ((INT) GetRawInputDeviceInfoA(ridl[i].hDevice,
+                                         RIDI_DEVICEINFO,
+                                         &rdi, &size) == -1)
+        {
+            continue;
+        }
+
+        if (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) != (LONG) guid->Data1)
+            continue;
+
+        memset(name, 0, sizeof(name));
+        size = sizeof(name);
+
+        if ((INT) GetRawInputDeviceInfoA(ridl[i].hDevice,
+                                         RIDI_DEVICENAME,
+                                         name, &size) == -1)
+        {
+            break;
+        }
+
+        name[sizeof(name) - 1] = '\0';
+        if (strstr(name, "IG_"))
+        {
+            result = GLFW_TRUE;
+            break;
+        }
+    }
+
+    free(ridl);
+    return result;
+}
+
+// Frees all resources associated with the specified joystick
+//
+static void closeJoystick(_GLFWjoystickWin32* js)
+{
+    if (js->device)
+    {
+        IDirectInputDevice8_Unacquire(js->device);
+        IDirectInputDevice8_Release(js->device);
+    }
+
+    free(js->name);
+    free(js->axes);
+    free(js->buttons);
+    free(js->objects);
+    memset(js, 0, sizeof(_GLFWjoystickWin32));
+
+    _glfwInputJoystickChange((int) (js - _glfw.win32_js), GLFW_DISCONNECTED);
+}
+
+// DirectInput device object enumeration callback
+// Insights gleaned from SDL2
+//
+static BOOL CALLBACK deviceObjectCallback(const DIDEVICEOBJECTINSTANCEW* doi,
+                                          void* user)
+{
+    _GLFWobjenumWin32* data = user;
+    _GLFWjoyobjectWin32* object = data->objects + data->objectCount;
+
+    if (DIDFT_GETTYPE(doi->dwType) & DIDFT_AXIS)
+    {
+        DIPROPRANGE dipr;
+
+        if (memcmp(&doi->guidType, &GUID_Slider, sizeof(GUID)) == 0)
+            object->offset = DIJOFS_SLIDER(data->sliderCount);
+        else if (memcmp(&doi->guidType, &GUID_XAxis, sizeof(GUID)) == 0)
+            object->offset = DIJOFS_X;
+        else if (memcmp(&doi->guidType, &GUID_YAxis, sizeof(GUID)) == 0)
+            object->offset = DIJOFS_Y;
+        else if (memcmp(&doi->guidType, &GUID_ZAxis, sizeof(GUID)) == 0)
+            object->offset = DIJOFS_Z;
+        else if (memcmp(&doi->guidType, &GUID_RxAxis, sizeof(GUID)) == 0)
+            object->offset = DIJOFS_RX;
+        else if (memcmp(&doi->guidType, &GUID_RyAxis, sizeof(GUID)) == 0)
+            object->offset = DIJOFS_RY;
+        else if (memcmp(&doi->guidType, &GUID_RzAxis, sizeof(GUID)) == 0)
+            object->offset = DIJOFS_RZ;
+        else
+            return DIENUM_CONTINUE;
+
+        ZeroMemory(&dipr, sizeof(dipr));
+        dipr.diph.dwSize = sizeof(dipr);
+        dipr.diph.dwHeaderSize = sizeof(dipr.diph);
+        dipr.diph.dwObj = doi->dwType;
+        dipr.diph.dwHow = DIPH_BYID;
+        dipr.lMin = -32768;
+        dipr.lMax =  32767;
+
+        if (FAILED(IDirectInputDevice8_SetProperty(data->device,
+                                                   DIPROP_RANGE,
+                                                   &dipr.diph)))
+        {
+            return DIENUM_CONTINUE;
+        }
+
+        if (memcmp(&doi->guidType, &GUID_Slider, sizeof(GUID)) == 0)
+        {
+            object->type = _GLFW_TYPE_SLIDER;
+            data->sliderCount++;
+        }
+        else
+        {
+            object->type = _GLFW_TYPE_AXIS;
+            data->axisCount++;
+        }
+    }
+    else if (DIDFT_GETTYPE(doi->dwType) & DIDFT_BUTTON)
+    {
+        object->offset = DIJOFS_BUTTON(data->buttonCount);
+        object->type = _GLFW_TYPE_BUTTON;
+        data->buttonCount++;
+    }
+    else if (DIDFT_GETTYPE(doi->dwType) & DIDFT_POV)
+    {
+        object->offset = DIJOFS_POV(data->povCount);
+        object->type = _GLFW_TYPE_POV;
+        data->povCount++;
+    }
+
+    data->objectCount++;
+    return DIENUM_CONTINUE;
+}
+
+// DirectInput device enumeration callback
+//
+static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user)
+{
+    int joy = 0;
+    DIDEVCAPS dc;
+    DIPROPDWORD dipd;
+    IDirectInputDevice8* device;
+    _GLFWobjenumWin32 data;
+    _GLFWjoystickWin32* js;
+
+    for (joy = GLFW_JOYSTICK_1;  joy <= GLFW_JOYSTICK_LAST;  joy++)
+    {
+        if (memcmp(&_glfw.win32_js[joy].guid, &di->guidInstance, sizeof(GUID)) == 0)
+            return DIENUM_CONTINUE;
+    }
+
+    for (joy = GLFW_JOYSTICK_1;  joy <= GLFW_JOYSTICK_LAST;  joy++)
+    {
+        if (!_glfw.win32_js[joy].present)
+            break;
+    }
+
+    if (joy > GLFW_JOYSTICK_LAST)
+        return DIENUM_STOP;
+
+    if (supportsXInput(&di->guidProduct))
+        return DIENUM_CONTINUE;
+
+    if (FAILED(IDirectInput8_CreateDevice(_glfw.win32.dinput8.api,
+                                          &di->guidInstance,
+                                          &device,
+                                          NULL)))
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR, "DI: Failed to create device");
+        return DIENUM_CONTINUE;
+    }
+
+    if (FAILED(IDirectInputDevice8_SetDataFormat(device, &_glfwDataFormat)))
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "DI: Failed to set device data format");
+
+        IDirectInputDevice8_Release(device);
+        return DIENUM_CONTINUE;
+    }
+
+    ZeroMemory(&dc, sizeof(dc));
+    dc.dwSize = sizeof(dc);
+
+    if (FAILED(IDirectInputDevice8_GetCapabilities(device, &dc)))
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "DI: Failed to query device capabilities");
+
+        IDirectInputDevice8_Release(device);
+        return DIENUM_CONTINUE;
+    }
+
+    ZeroMemory(&dipd, sizeof(dipd));
+    dipd.diph.dwSize = sizeof(dipd);
+    dipd.diph.dwHeaderSize = sizeof(dipd.diph);
+    dipd.diph.dwHow = DIPH_DEVICE;
+    dipd.dwData = DIPROPAXISMODE_ABS;
+
+    if (FAILED(IDirectInputDevice8_SetProperty(device,
+                                               DIPROP_AXISMODE,
+                                               &dipd.diph)))
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "DI: Failed to set device axis mode");
+
+        IDirectInputDevice8_Release(device);
+        return DIENUM_CONTINUE;
+    }
+
+    memset(&data, 0, sizeof(data));
+    data.device = device;
+    data.objects = calloc(dc.dwAxes + dc.dwButtons + dc.dwPOVs,
+                          sizeof(_GLFWjoyobjectWin32));
+
+    if (FAILED(IDirectInputDevice8_EnumObjects(device,
+                                               deviceObjectCallback,
+                                               &data,
+                                               DIDFT_AXIS | DIDFT_BUTTON | DIDFT_POV)))
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "DI: Failed to enumerate device objects");
+
+        IDirectInputDevice8_Release(device);
+        free(data.objects);
+        return DIENUM_CONTINUE;
+    }
+
+    qsort(data.objects, data.objectCount,
+          sizeof(_GLFWjoyobjectWin32),
+          compareJoystickObjects);
+
+    js = _glfw.win32_js + joy;
+    js->device = device;
+    js->guid = di->guidInstance;
+    js->axisCount = data.axisCount + data.sliderCount;
+    js->axes = calloc(js->axisCount, sizeof(float));
+    js->buttonCount += data.buttonCount + data.povCount * 4;
+    js->buttons = calloc(js->buttonCount, 1);
+    js->objects = data.objects;
+    js->objectCount = data.objectCount;
+    js->name = _glfwCreateUTF8FromWideStringWin32(di->tszInstanceName);
+    js->present = GLFW_TRUE;
+
+    _glfwInputJoystickChange(joy, GLFW_CONNECTED);
+    return DIENUM_CONTINUE;
+}
+
+// Attempt to open the specified joystick device
+// TODO: Pack state arrays for non-gamepad devices
+//
+static GLFWbool openXinputDevice(DWORD index)
+{
+    int joy;
+    XINPUT_CAPABILITIES xic;
+    _GLFWjoystickWin32* js;
+
+    for (joy = GLFW_JOYSTICK_1;  joy <= GLFW_JOYSTICK_LAST;  joy++)
+    {
+        if (_glfw.win32_js[joy].present &&
+            _glfw.win32_js[joy].device == NULL &&
+            _glfw.win32_js[joy].index == index)
+        {
+            return GLFW_FALSE;
+        }
+    }
+
+    for (joy = GLFW_JOYSTICK_1;  joy <= GLFW_JOYSTICK_LAST;  joy++)
+    {
+        if (!_glfw.win32_js[joy].present)
+            break;
+    }
+
+    if (joy > GLFW_JOYSTICK_LAST)
+        return GLFW_FALSE;
+
+    if (_glfw_XInputGetCapabilities(index, 0, &xic) != ERROR_SUCCESS)
+        return GLFW_FALSE;
+
+    js = _glfw.win32_js + joy;
+    js->axisCount = 6;
+    js->axes = calloc(js->axisCount, sizeof(float));
+    js->buttonCount = 14;
+    js->buttons = calloc(js->buttonCount, 1);
+    js->present = GLFW_TRUE;
+    js->name = strdup(getDeviceDescription(&xic));
+    js->index = index;
+
+    _glfwInputJoystickChange(joy, GLFW_CONNECTED);
+
+    return GLFW_TRUE;
+}
+
+// Polls for and processes events the specified joystick
+//
+static GLFWbool pollJoystickState(_GLFWjoystickWin32* js, int mode)
+{
+    if (!js->present)
+        return GLFW_FALSE;
+
+    if (js->device)
+    {
+        int i, j, ai = 0, bi = 0;
+        HRESULT result;
+        DIJOYSTATE state;
+
+        IDirectInputDevice8_Poll(js->device);
+        result = IDirectInputDevice8_GetDeviceState(js->device,
+                                                    sizeof(state),
+                                                    &state);
+        if (result == DIERR_NOTACQUIRED || result == DIERR_INPUTLOST)
+        {
+            IDirectInputDevice8_Acquire(js->device);
+            IDirectInputDevice8_Poll(js->device);
+            result = IDirectInputDevice8_GetDeviceState(js->device,
+                                                        sizeof(state),
+                                                        &state);
+        }
+
+        if (FAILED(result))
+        {
+            closeJoystick(js);
+            return GLFW_FALSE;
+        }
+
+        if (mode == _GLFW_PRESENCE_ONLY)
+            return GLFW_TRUE;
+
+        for (i = 0;  i < js->objectCount;  i++)
+        {
+            const void* data = (char*) &state + js->objects[i].offset;
+
+            switch (js->objects[i].type)
+            {
+                case _GLFW_TYPE_AXIS:
+                case _GLFW_TYPE_SLIDER:
+                {
+                    js->axes[ai++] = (*((LONG*) data) + 0.5f) / 32767.5f;
+                    break;
+                }
+
+                case _GLFW_TYPE_BUTTON:
+                {
+                    if (*((BYTE*) data) & 0x80)
+                        js->buttons[bi++] = GLFW_PRESS;
+                    else
+                        js->buttons[bi++] = GLFW_RELEASE;
+
+                    break;
+                }
+
+                case _GLFW_TYPE_POV:
+                {
+                    const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 };
+                    // Screams of horror are appropriate at this point
+                    int value = LOWORD(*(DWORD*) data) / (45 * DI_DEGREES);
+                    if (value < 0 || value > 8)
+                        value = 8;
+
+                    for (j = 0;  j < 4;  j++)
+                    {
+                        if (directions[value] & (1 << j))
+                            js->buttons[bi++] = GLFW_PRESS;
+                        else
+                            js->buttons[bi++] = GLFW_RELEASE;
+                    }
+
+                    break;
+                }
+            }
+        }
+
+        return GLFW_TRUE;
+    }
+    else
+    {
+        int i;
+        DWORD result;
+        XINPUT_STATE xis;
+        const WORD buttons[14] =
+        {
+            XINPUT_GAMEPAD_A,
+            XINPUT_GAMEPAD_B,
+            XINPUT_GAMEPAD_X,
+            XINPUT_GAMEPAD_Y,
+            XINPUT_GAMEPAD_LEFT_SHOULDER,
+            XINPUT_GAMEPAD_RIGHT_SHOULDER,
+            XINPUT_GAMEPAD_BACK,
+            XINPUT_GAMEPAD_START,
+            XINPUT_GAMEPAD_LEFT_THUMB,
+            XINPUT_GAMEPAD_RIGHT_THUMB,
+            XINPUT_GAMEPAD_DPAD_UP,
+            XINPUT_GAMEPAD_DPAD_RIGHT,
+            XINPUT_GAMEPAD_DPAD_DOWN,
+            XINPUT_GAMEPAD_DPAD_LEFT
+        };
+
+        result = _glfw_XInputGetState(js->index, &xis);
+        if (result != ERROR_SUCCESS)
+        {
+            if (result == ERROR_DEVICE_NOT_CONNECTED)
+                closeJoystick(js);
+
+            return GLFW_FALSE;
+        }
+
+        if (mode == _GLFW_PRESENCE_ONLY)
+            return GLFW_TRUE;
+
+        if (sqrt((double) (xis.Gamepad.sThumbLX * xis.Gamepad.sThumbLX +
+                           xis.Gamepad.sThumbLY * xis.Gamepad.sThumbLY)) >
+            (double) XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE)
+        {
+            js->axes[0] = (xis.Gamepad.sThumbLX + 0.5f) / 32767.f;
+            js->axes[1] = (xis.Gamepad.sThumbLY + 0.5f) / 32767.f;
+        }
+        else
+        {
+            js->axes[0] = 0.f;
+            js->axes[1] = 0.f;
+        }
+
+        if (sqrt((double) (xis.Gamepad.sThumbRX * xis.Gamepad.sThumbRX +
+                           xis.Gamepad.sThumbRY * xis.Gamepad.sThumbRY)) >
+            (double) XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE)
+        {
+            js->axes[2] = (xis.Gamepad.sThumbRX + 0.5f) / 32767.f;
+            js->axes[3] = (xis.Gamepad.sThumbRY + 0.5f) / 32767.f;
+        }
+        else
+        {
+            js->axes[2] = 0.f;
+            js->axes[3] = 0.f;
+        }
+
+        if (xis.Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD)
+            js->axes[4] = xis.Gamepad.bLeftTrigger / 127.5f - 1.f;
+        else
+            js->axes[4] = -1.f;
+
+        if (xis.Gamepad.bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD)
+            js->axes[5] = xis.Gamepad.bRightTrigger / 127.5f - 1.f;
+        else
+            js->axes[5] = -1.f;
+
+        for (i = 0;  i < 14;  i++)
+            js->buttons[i] = (xis.Gamepad.wButtons & buttons[i]) ? 1 : 0;
+
+        return GLFW_TRUE;
+    }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                       GLFW internal API                      //////
+//////////////////////////////////////////////////////////////////////////
+
+// Initialize joystick interface
+//
+void _glfwInitJoysticksWin32(void)
+{
+    if (_glfw.win32.dinput8.instance)
+    {
+        if (FAILED(_glfw_DirectInput8Create(GetModuleHandle(NULL),
+                                            DIRECTINPUT_VERSION,
+                                            &IID_IDirectInput8W,
+                                            (void**) &_glfw.win32.dinput8.api,
+                                            NULL)))
+        {
+            _glfwInputError(GLFW_PLATFORM_ERROR,
+                            "DI: Failed to create interface");
+        }
+    }
+
+    _glfwDetectJoystickConnectionWin32();
+}
+
+// Close all opened joystick handles
+//
+void _glfwTerminateJoysticksWin32(void)
+{
+    int joy;
+
+    for (joy = GLFW_JOYSTICK_1;  joy <= GLFW_JOYSTICK_LAST;  joy++)
+        closeJoystick(_glfw.win32_js + joy);
+
+    if (_glfw.win32.dinput8.api)
+        IDirectInput8_Release(_glfw.win32.dinput8.api);
+}
+
+// Checks for new joysticks after DBT_DEVICEARRIVAL
+//
+void _glfwDetectJoystickConnectionWin32(void)
+{
+    if (_glfw.win32.xinput.instance)
+    {
+        DWORD i;
+
+        for (i = 0;  i < XUSER_MAX_COUNT;  i++)
+            openXinputDevice(i);
+    }
+
+    if (_glfw.win32.dinput8.api)
+    {
+        if (FAILED(IDirectInput8_EnumDevices(_glfw.win32.dinput8.api,
+                                             DI8DEVCLASS_GAMECTRL,
+                                             deviceCallback,
+                                             NULL,
+                                             DIEDFL_ALLDEVICES)))
+        {
+            _glfwInputError(GLFW_PLATFORM_ERROR,
+                            "Failed to enumerate DirectInput8 devices");
+            return;
+        }
+    }
+}
+
+// Checks for joystick disconnection after DBT_DEVICEREMOVECOMPLETE
+//
+void _glfwDetectJoystickDisconnectionWin32(void)
+{
+    int joy;
+
+    for (joy = GLFW_JOYSTICK_1;  joy <= GLFW_JOYSTICK_LAST;  joy++)
+        pollJoystickState(_glfw.win32_js + joy, _GLFW_PRESENCE_ONLY);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                       GLFW platform API                      //////
+//////////////////////////////////////////////////////////////////////////
+
+int _glfwPlatformJoystickPresent(int joy)
+{
+    _GLFWjoystickWin32* js = _glfw.win32_js + joy;
+    return pollJoystickState(js, _GLFW_PRESENCE_ONLY);
+}
+
+const float* _glfwPlatformGetJoystickAxes(int joy, int* count)
+{
+    _GLFWjoystickWin32* js = _glfw.win32_js + joy;
+    if (!pollJoystickState(js, _GLFW_UPDATE_STATE))
+        return NULL;
+
+    *count = js->axisCount;
+    return js->axes;
+}
+
+const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
+{
+    _GLFWjoystickWin32* js = _glfw.win32_js + joy;
+    if (!pollJoystickState(js, _GLFW_UPDATE_STATE))
+        return NULL;
+
+    *count = js->buttonCount;
+    return js->buttons;
+}
+
+const char* _glfwPlatformGetJoystickName(int joy)
+{
+    _GLFWjoystickWin32* js = _glfw.win32_js + joy;
+    if (!pollJoystickState(js, _GLFW_PRESENCE_ONLY))
+        return NULL;
+
+    return js->name;
+}
+
diff --git a/glfw/src/win32_joystick.h b/glfw/src/win32_joystick.h
new file mode 100644
--- /dev/null
+++ b/glfw/src/win32_joystick.h
@@ -0,0 +1,64 @@
+//========================================================================
+// GLFW 3.2 Win32 - www.glfw.org
+//------------------------------------------------------------------------
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
+//
+// 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.
+//
+//========================================================================
+
+#ifndef _glfw3_win32_joystick_h_
+#define _glfw3_win32_joystick_h_
+
+#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE \
+    _GLFWjoystickWin32 win32_js[GLFW_JOYSTICK_LAST + 1]
+
+// Joystick element (axis, button or slider)
+//
+typedef struct _GLFWjoyobjectWin32
+{
+    int                     offset;
+    int                     type;
+} _GLFWjoyobjectWin32;
+
+// Win32-specific per-joystick data
+//
+typedef struct _GLFWjoystickWin32
+{
+    GLFWbool                present;
+    float*                  axes;
+    int                     axisCount;
+    unsigned char*          buttons;
+    int                     buttonCount;
+    _GLFWjoyobjectWin32*    objects;
+    int                     objectCount;
+    char*                   name;
+    IDirectInputDevice8W*   device;
+    DWORD                   index;
+    GUID                    guid;
+} _GLFWjoystickWin32;
+
+
+void _glfwInitJoysticksWin32(void);
+void _glfwTerminateJoysticksWin32(void);
+void _glfwDetectJoystickConnectionWin32(void);
+void _glfwDetectJoystickDisconnectionWin32(void);
+
+#endif // _glfw3_win32_joystick_h_
diff --git a/glfw/src/win32_monitor.c b/glfw/src/win32_monitor.c
--- a/glfw/src/win32_monitor.c
+++ b/glfw/src/win32_monitor.c
@@ -1,8 +1,8 @@
 //========================================================================
-// GLFW 3.1 Win32 - www.glfw.org
+// GLFW 3.2 Win32 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -32,22 +32,67 @@
 #include <limits.h>
 #include <malloc.h>
 
-// These constants are missing on MinGW
-#ifndef EDS_ROTATEDMODE
- #define EDS_ROTATEDMODE 0x00000004
-#endif
-#ifndef DISPLAY_DEVICE_ACTIVE
- #define DISPLAY_DEVICE_ACTIVE 0x00000001
-#endif
 
+// Create monitor from an adapter and (optionally) a display
+//
+static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter,
+                                   DISPLAY_DEVICEW* display)
+{
+    _GLFWmonitor* monitor;
+    char* name;
+    HDC dc;
 
+    if (display)
+        name = _glfwCreateUTF8FromWideStringWin32(display->DeviceString);
+    else
+        name = _glfwCreateUTF8FromWideStringWin32(adapter->DeviceString);
+    if (!name)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Win32: Failed to convert string to UTF-8");
+        return NULL;
+    }
+
+    dc = CreateDCW(L"DISPLAY", adapter->DeviceName, NULL, NULL);
+
+    monitor = _glfwAllocMonitor(name,
+                                GetDeviceCaps(dc, HORZSIZE),
+                                GetDeviceCaps(dc, VERTSIZE));
+
+    DeleteDC(dc);
+    free(name);
+
+    if (adapter->StateFlags & DISPLAY_DEVICE_MODESPRUNED)
+        monitor->win32.modesPruned = GLFW_TRUE;
+
+    wcscpy(monitor->win32.adapterName, adapter->DeviceName);
+    WideCharToMultiByte(CP_UTF8, 0,
+                        adapter->DeviceName, -1,
+                        monitor->win32.publicAdapterName,
+                        sizeof(monitor->win32.publicAdapterName),
+                        NULL, NULL);
+
+    if (display)
+    {
+        wcscpy(monitor->win32.displayName, display->DeviceName);
+        WideCharToMultiByte(CP_UTF8, 0,
+                            display->DeviceName, -1,
+                            monitor->win32.publicDisplayName,
+                            sizeof(monitor->win32.publicDisplayName),
+                            NULL, NULL);
+    }
+
+    return monitor;
+}
+
+
 //////////////////////////////////////////////////////////////////////////
 //////                       GLFW internal API                      //////
 //////////////////////////////////////////////////////////////////////////
 
 // Change the current video mode
 //
-GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired)
+GLFWbool _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired)
 {
     GLFWvidmode current;
     const GLFWvidmode* best;
@@ -56,7 +101,7 @@
     best = _glfwChooseVideoMode(monitor, desired);
     _glfwPlatformGetVideoMode(monitor, &current);
     if (_glfwCompareVideoModes(&current, best) == 0)
-        return GL_TRUE;
+        return GLFW_TRUE;
 
     ZeroMemory(&dm, sizeof(dm));
     dm.dmSize = sizeof(DEVMODEW);
@@ -77,22 +122,22 @@
                                  NULL) != DISP_CHANGE_SUCCESSFUL)
     {
         _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to set video mode");
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
 
-    monitor->win32.modeChanged = GL_TRUE;
-    return GL_TRUE;
+    monitor->win32.modeChanged = GLFW_TRUE;
+    return GLFW_TRUE;
 }
 
 // Restore the previously saved (original) video mode
 //
-void _glfwRestoreVideoMode(_GLFWmonitor* monitor)
+void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor)
 {
     if (monitor->win32.modeChanged)
     {
         ChangeDisplaySettingsExW(monitor->win32.adapterName,
                                  NULL, NULL, CDS_FULLSCREEN, NULL);
-        monitor->win32.modeChanged = GL_FALSE;
+        monitor->win32.modeChanged = GLFW_FALSE;
     }
 }
 
@@ -103,16 +148,19 @@
 
 _GLFWmonitor** _glfwPlatformGetMonitors(int* count)
 {
-    int size = 0, found = 0;
+    int found = 0;
+    DWORD adapterIndex, displayIndex, primaryIndex = 0;
+    DISPLAY_DEVICEW adapter, display;
+    GLFWbool hasDisplays = GLFW_FALSE;
     _GLFWmonitor** monitors = NULL;
-    DWORD adapterIndex, displayIndex;
 
     *count = 0;
 
+    // HACK: Check if any active adapters have connected displays
+    //       If not, this is a headless system or a VMware guest
+
     for (adapterIndex = 0;  ;  adapterIndex++)
     {
-        DISPLAY_DEVICEW adapter;
-
         ZeroMemory(&adapter, sizeof(DISPLAY_DEVICEW));
         adapter.cb = sizeof(DISPLAY_DEVICEW);
 
@@ -122,73 +170,65 @@
         if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE))
             continue;
 
-        for (displayIndex = 0;  ;  displayIndex++)
-        {
-            DISPLAY_DEVICEW display;
-            char* name;
-            HDC dc;
-
-            ZeroMemory(&display, sizeof(DISPLAY_DEVICEW));
-            display.cb = sizeof(DISPLAY_DEVICEW);
-
-            if (!EnumDisplayDevicesW(adapter.DeviceName, displayIndex, &display, 0))
-                break;
-
-            if (found == size)
-            {
-                size += 4;
-                monitors = realloc(monitors, sizeof(_GLFWmonitor*) * size);
-            }
+        ZeroMemory(&display, sizeof(DISPLAY_DEVICEW));
+        display.cb = sizeof(DISPLAY_DEVICEW);
 
-            name = _glfwCreateUTF8FromWideString(display.DeviceString);
-            if (!name)
-            {
-                _glfwInputError(GLFW_PLATFORM_ERROR,
-                                "Failed to convert string to UTF-8");
-                continue;
-            }
+        if (EnumDisplayDevicesW(adapter.DeviceName, 0, &display, 0))
+        {
+            hasDisplays = GLFW_TRUE;
+            break;
+        }
+    }
 
-            dc = CreateDCW(L"DISPLAY", adapter.DeviceName, NULL, NULL);
+    for (adapterIndex = 0;  ;  adapterIndex++)
+    {
+        ZeroMemory(&adapter, sizeof(DISPLAY_DEVICEW));
+        adapter.cb = sizeof(DISPLAY_DEVICEW);
 
-            monitors[found] = _glfwAllocMonitor(name,
-                                                GetDeviceCaps(dc, HORZSIZE),
-                                                GetDeviceCaps(dc, VERTSIZE));
+        if (!EnumDisplayDevicesW(NULL, adapterIndex, &adapter, 0))
+            break;
 
-            DeleteDC(dc);
-            free(name);
+        if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE))
+            continue;
 
-            wcscpy(monitors[found]->win32.adapterName, adapter.DeviceName);
-            wcscpy(monitors[found]->win32.displayName, display.DeviceName);
+        if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
+            primaryIndex = found;
 
-            WideCharToMultiByte(CP_UTF8, 0,
-                                adapter.DeviceName, -1,
-                                monitors[found]->win32.publicAdapterName,
-                                sizeof(monitors[found]->win32.publicAdapterName),
-                                NULL, NULL);
+        if (hasDisplays)
+        {
+            for (displayIndex = 0;  ;  displayIndex++)
+            {
+                ZeroMemory(&display, sizeof(DISPLAY_DEVICEW));
+                display.cb = sizeof(DISPLAY_DEVICEW);
 
-            WideCharToMultiByte(CP_UTF8, 0,
-                                display.DeviceName, -1,
-                                monitors[found]->win32.publicDisplayName,
-                                sizeof(monitors[found]->win32.publicDisplayName),
-                                NULL, NULL);
+                if (!EnumDisplayDevicesW(adapter.DeviceName, displayIndex, &display, 0))
+                    break;
 
-            if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE &&
-                displayIndex == 0)
-            {
-                _GLFW_SWAP_POINTERS(monitors[0], monitors[found]);
+                found++;
+                monitors = realloc(monitors, sizeof(_GLFWmonitor*) * found);
+                monitors[found - 1] = createMonitor(&adapter, &display);
             }
-
+        }
+        else
+        {
             found++;
+            monitors = realloc(monitors, sizeof(_GLFWmonitor*) * found);
+            monitors[found - 1] = createMonitor(&adapter, NULL);
         }
     }
 
+    _GLFW_SWAP_POINTERS(monitors[0], monitors[primaryIndex]);
+
     *count = found;
     return monitors;
 }
 
-GLboolean _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
+GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
 {
-    return wcscmp(first->win32.displayName, second->win32.displayName) == 0;
+    if (wcslen(first->win32.displayName))
+        return wcscmp(first->win32.displayName, second->win32.displayName) == 0;
+    else
+        return wcscmp(first->win32.adapterName, second->win32.adapterName) == 0;
 }
 
 void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
@@ -208,12 +248,12 @@
         *ypos = settings.dmPosition.y;
 }
 
-GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
+GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
 {
-    int modeIndex = 0, count = 0;
+    int modeIndex = 0, size = 0;
     GLFWvidmode* result = NULL;
 
-    *found = 0;
+    *count = 0;
 
     for (;;)
     {
@@ -229,11 +269,9 @@
 
         modeIndex++;
 
+        // Skip modes with less than 15 BPP
         if (dm.dmBitsPerPel < 15)
-        {
-            // Skip modes with less than 15 BPP
             continue;
-        }
 
         mode.width  = dm.dmPelsWidth;
         mode.height = dm.dmPelsHeight;
@@ -243,30 +281,45 @@
                       &mode.greenBits,
                       &mode.blueBits);
 
-        for (i = 0;  i < *found;  i++)
+        for (i = 0;  i < *count;  i++)
         {
             if (_glfwCompareVideoModes(result + i, &mode) == 0)
                 break;
         }
 
-        if (i < *found)
-        {
-            // This is a duplicate, so skip it
+        // Skip duplicate modes
+        if (i < *count)
             continue;
-        }
 
-        if (*found == count)
+        if (monitor->win32.modesPruned)
         {
-            if (count)
-                count *= 2;
-            else
-                count = 128;
+            // Skip modes not supported by the connected displays
+            if (ChangeDisplaySettingsExW(monitor->win32.adapterName,
+                                         &dm,
+                                         NULL,
+                                         CDS_TEST,
+                                         NULL) != DISP_CHANGE_SUCCESSFUL)
+            {
+                continue;
+            }
+        }
 
-            result = (GLFWvidmode*) realloc(result, count * sizeof(GLFWvidmode));
+        if (*count == size)
+        {
+            size += 128;
+            result = (GLFWvidmode*) realloc(result, size * sizeof(GLFWvidmode));
         }
 
-        result[*found] = mode;
-        (*found)++;
+        (*count)++;
+        result[*count - 1] = mode;
+    }
+
+    if (!*count)
+    {
+        // HACK: Report the current mode if no valid modes were found
+        result = calloc(1, sizeof(GLFWvidmode));
+        _glfwPlatformGetVideoMode(monitor, result);
+        *count = 1;
     }
 
     return result;
diff --git a/glfw/src/win32_platform.h b/glfw/src/win32_platform.h
--- a/glfw/src/win32_platform.h
+++ b/glfw/src/win32_platform.h
@@ -1,8 +1,8 @@
 //========================================================================
-// GLFW 3.1 Win32 - www.glfw.org
+// GLFW 3.2 Win32 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -25,9 +25,8 @@
 //
 //========================================================================
 
-#ifndef _win32_platform_h_
-#define _win32_platform_h_
-
+#ifndef _glfw3_win32_platform_h_
+#define _glfw3_win32_platform_h_
 
 // We don't need all the fancy stuff
 #ifndef NOMINMAX
@@ -62,8 +61,14 @@
  #define _WIN32_WINNT 0x0501
 #endif
 
+// GLFW uses DirectInput8 interfaces
+#define DIRECTINPUT_VERSION 0x0800
+
+#include <wctype.h>
 #include <windows.h>
 #include <mmsystem.h>
+#include <dinput.h>
+#include <xinput.h>
 #include <dbt.h>
 
 #if defined(_MSC_VER)
@@ -71,9 +76,7 @@
  #define strdup _strdup
 #endif
 
-
-// HACK: Define macros that some older windows.h variants don't
-
+// HACK: Define macros that some windows.h variants don't
 #ifndef WM_MOUSEHWHEEL
  #define WM_MOUSEHWHEEL 0x020E
 #endif
@@ -89,6 +92,18 @@
 #ifndef UNICODE_NOCHAR
  #define UNICODE_NOCHAR 0xFFFF
 #endif
+#ifndef WM_DPICHANGED
+ #define WM_DPICHANGED 0x02E0
+#endif
+#ifndef GET_XBUTTON_WPARAM
+ #define GET_XBUTTON_WPARAM(w) (HIWORD(w))
+#endif
+#ifndef EDS_ROTATEDMODE
+ #define EDS_ROTATEDMODE 0x00000004
+#endif
+#ifndef DISPLAY_DEVICE_ACTIVE
+ #define DISPLAY_DEVICE_ACTIVE 0x00000001
+#endif
 
 #if WINVER < 0x0601
 typedef struct tagCHANGEFILTERSTRUCT
@@ -102,17 +117,63 @@
 #endif
 #endif /*Windows 7*/
 
+#ifndef DPI_ENUMS_DECLARED
+typedef enum PROCESS_DPI_AWARENESS
+{
+    PROCESS_DPI_UNAWARE = 0,
+    PROCESS_SYSTEM_DPI_AWARE = 1,
+    PROCESS_PER_MONITOR_DPI_AWARE = 2
+} PROCESS_DPI_AWARENESS;
+#endif /*DPI_ENUMS_DECLARED*/
 
+// HACK: Define macros that some xinput.h variants don't
+#ifndef XINPUT_CAPS_WIRELESS
+ #define XINPUT_CAPS_WIRELESS 0x0002
+#endif
+#ifndef XINPUT_DEVSUBTYPE_WHEEL
+ #define XINPUT_DEVSUBTYPE_WHEEL 0x02
+#endif
+#ifndef XINPUT_DEVSUBTYPE_ARCADE_STICK
+ #define XINPUT_DEVSUBTYPE_ARCADE_STICK 0x03
+#endif
+#ifndef XINPUT_DEVSUBTYPE_FLIGHT_STICK
+ #define XINPUT_DEVSUBTYPE_FLIGHT_STICK 0x04
+#endif
+#ifndef XINPUT_DEVSUBTYPE_DANCE_PAD
+ #define XINPUT_DEVSUBTYPE_DANCE_PAD 0x05
+#endif
+#ifndef XINPUT_DEVSUBTYPE_GUITAR
+ #define XINPUT_DEVSUBTYPE_GUITAR 0x06
+#endif
+#ifndef XINPUT_DEVSUBTYPE_DRUM_KIT
+ #define XINPUT_DEVSUBTYPE_DRUM_KIT 0x08
+#endif
+#ifndef XINPUT_DEVSUBTYPE_ARCADE_PAD
+ #define XINPUT_DEVSUBTYPE_ARCADE_PAD 0x13
+#endif
+#ifndef XUSER_MAX_COUNT
+ #define XUSER_MAX_COUNT 4
+#endif
+
+// HACK: Define macros that some dinput.h variants don't
+#ifndef DIDFT_OPTIONAL
+ #define DIDFT_OPTIONAL	0x80000000
+#endif
+
 // winmm.dll function pointer typedefs
-typedef MMRESULT (WINAPI * JOYGETDEVCAPS_T)(UINT,LPJOYCAPS,UINT);
-typedef MMRESULT (WINAPI * JOYGETPOS_T)(UINT,LPJOYINFO);
-typedef MMRESULT (WINAPI * JOYGETPOSEX_T)(UINT,LPJOYINFOEX);
 typedef DWORD (WINAPI * TIMEGETTIME_T)(void);
-#define _glfw_joyGetDevCaps _glfw.win32.winmm.joyGetDevCaps
-#define _glfw_joyGetPos _glfw.win32.winmm.joyGetPos
-#define _glfw_joyGetPosEx _glfw.win32.winmm.joyGetPosEx
 #define _glfw_timeGetTime _glfw.win32.winmm.timeGetTime
 
+// xinput.dll function pointer typedefs
+typedef DWORD (WINAPI * XINPUTGETCAPABILITIES_T)(DWORD,DWORD,XINPUT_CAPABILITIES*);
+typedef DWORD (WINAPI * XINPUTGETSTATE_T)(DWORD,XINPUT_STATE*);
+#define _glfw_XInputGetCapabilities _glfw.win32.xinput.XInputGetCapabilities
+#define _glfw_XInputGetState _glfw.win32.xinput.XInputGetState
+
+// dinput8.dll function pointer typedefs
+typedef HRESULT (WINAPI * DIRECTINPUT8CREATE_T)(HINSTANCE,DWORD,REFIID,LPVOID*,LPUNKNOWN);
+#define _glfw_DirectInput8Create _glfw.win32.dinput8.DirectInput8Create
+
 // user32.dll function pointer typedefs
 typedef BOOL (WINAPI * SETPROCESSDPIAWARE_T)(void);
 typedef BOOL (WINAPI * CHANGEWINDOWMESSAGEFILTEREX_T)(HWND,UINT,DWORD,PCHANGEFILTERSTRUCT);
@@ -121,31 +182,45 @@
 
 // dwmapi.dll function pointer typedefs
 typedef HRESULT (WINAPI * DWMISCOMPOSITIONENABLED_T)(BOOL*);
+typedef HRESULT (WINAPI * DWMFLUSH_T)(VOID);
 #define _glfw_DwmIsCompositionEnabled _glfw.win32.dwmapi.DwmIsCompositionEnabled
+#define _glfw_DwmFlush _glfw.win32.dwmapi.DwmFlush
 
+// shcore.dll function pointer typedefs
+typedef HRESULT (WINAPI * SETPROCESSDPIAWARENESS_T)(PROCESS_DPI_AWARENESS);
+#define _glfw_SetProcessDpiAwareness _glfw.win32.shcore.SetProcessDpiAwareness
 
-#define _GLFW_RECREATION_NOT_NEEDED 0
-#define _GLFW_RECREATION_REQUIRED   1
-#define _GLFW_RECREATION_IMPOSSIBLE 2
+typedef VkFlags VkWin32SurfaceCreateFlagsKHR;
 
+typedef struct VkWin32SurfaceCreateInfoKHR
+{
+    VkStructureType                 sType;
+    const void*                     pNext;
+    VkWin32SurfaceCreateFlagsKHR    flags;
+    HINSTANCE                       hinstance;
+    HWND                            hwnd;
+} VkWin32SurfaceCreateInfoKHR;
 
-#include "win32_tls.h"
+typedef VkResult (APIENTRY *PFN_vkCreateWin32SurfaceKHR)(VkInstance,const VkWin32SurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*);
+typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice,uint32_t);
 
-#if defined(_GLFW_WGL)
- #include "wgl_context.h"
-#elif defined(_GLFW_EGL)
- #define _GLFW_EGL_NATIVE_WINDOW  window->win32.handle
- #define _GLFW_EGL_NATIVE_DISPLAY EGL_DEFAULT_DISPLAY
- #include "egl_context.h"
-#else
- #error "No supported context creation API selected"
-#endif
+#include "win32_joystick.h"
+#include "wgl_context.h"
+#include "egl_context.h"
 
-#include "winmm_joystick.h"
+#define _GLFW_WNDCLASSNAME L"GLFW30"
 
+#define _glfw_dlopen(name) LoadLibraryA(name)
+#define _glfw_dlclose(handle) FreeLibrary((HMODULE) handle)
+#define _glfw_dlsym(handle, name) GetProcAddress((HMODULE) handle, name)
+
+#define _GLFW_EGL_NATIVE_WINDOW  ((EGLNativeWindowType) window->win32.handle)
+#define _GLFW_EGL_NATIVE_DISPLAY EGL_DEFAULT_DISPLAY
+
 #define _GLFW_PLATFORM_WINDOW_STATE         _GLFWwindowWin32  win32
 #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWin32 win32
 #define _GLFW_PLATFORM_LIBRARY_TIME_STATE   _GLFWtimeWin32    win32_time
+#define _GLFW_PLATFORM_LIBRARY_TLS_STATE    _GLFWtlsWin32     win32_tls
 #define _GLFW_PLATFORM_MONITOR_STATE        _GLFWmonitorWin32 win32
 #define _GLFW_PLATFORM_CURSOR_STATE         _GLFWcursorWin32  win32
 
@@ -155,50 +230,67 @@
 typedef struct _GLFWwindowWin32
 {
     HWND                handle;
-    DWORD               dwStyle;
-    DWORD               dwExStyle;
+    HICON               bigIcon;
+    HICON               smallIcon;
 
-    GLboolean           cursorInside;
-    GLboolean           iconified;
+    GLFWbool            cursorTracked;
+    GLFWbool            iconified;
 
     // The last received cursor position, regardless of source
-    int                 cursorPosX, cursorPosY;
+    int                 lastCursorPosX, lastCursorPosY;
 
 } _GLFWwindowWin32;
 
-
 // Win32-specific global data
 //
 typedef struct _GLFWlibraryWin32
 {
+    HWND                helperWindowHandle;
     DWORD               foregroundLockTimeout;
     char*               clipboardString;
+    char                keyName[64];
     short int           publicKeys[512];
+    short int           nativeKeys[GLFW_KEY_LAST + 1];
+    // Where to place the cursor when re-enabled
+    double              restoreCursorPosX, restoreCursorPosY;
+    // The window whose disabled cursor mode is active
+    _GLFWwindow*        disabledCursorWindow;
 
-    // winmm.dll
     struct {
         HINSTANCE       instance;
-        JOYGETDEVCAPS_T joyGetDevCaps;
-        JOYGETPOS_T     joyGetPos;
-        JOYGETPOSEX_T   joyGetPosEx;
         TIMEGETTIME_T   timeGetTime;
     } winmm;
 
-    // user32.dll
     struct {
-        HINSTANCE       instance;
-        SETPROCESSDPIAWARE_T SetProcessDPIAware;
+        HINSTANCE            instance;
+        DIRECTINPUT8CREATE_T DirectInput8Create;
+        IDirectInput8W*      api;
+    } dinput8;
+
+    struct {
+        HINSTANCE               instance;
+        XINPUTGETCAPABILITIES_T XInputGetCapabilities;
+        XINPUTGETSTATE_T        XInputGetState;
+    } xinput;
+
+    struct {
+        HINSTANCE                     instance;
+        SETPROCESSDPIAWARE_T          SetProcessDPIAware;
         CHANGEWINDOWMESSAGEFILTEREX_T ChangeWindowMessageFilterEx;
     } user32;
 
-    // dwmapi.dll
     struct {
         HINSTANCE       instance;
         DWMISCOMPOSITIONENABLED_T DwmIsCompositionEnabled;
+        DWMFLUSH_T      DwmFlush;
     } dwmapi;
 
-} _GLFWlibraryWin32;
+    struct {
+        HINSTANCE       instance;
+        SETPROCESSDPIAWARENESS_T SetProcessDpiAwareness;
+    } shcore;
 
+} _GLFWlibraryWin32;
 
 // Win32-specific per-monitor data
 //
@@ -209,11 +301,11 @@
     WCHAR               displayName[32];
     char                publicAdapterName[64];
     char                publicDisplayName[64];
-    GLboolean           modeChanged;
+    GLFWbool            modesPruned;
+    GLFWbool            modeChanged;
 
 } _GLFWmonitorWin32;
 
-
 // Win32-specific per-cursor data
 //
 typedef struct _GLFWcursorWin32
@@ -222,29 +314,37 @@
 
 } _GLFWcursorWin32;
 
-
 // Win32-specific global timer data
 //
 typedef struct _GLFWtimeWin32
 {
-    GLboolean           hasPC;
-    double              resolution;
-    unsigned __int64    base;
+    GLFWbool            hasPC;
+    uint64_t            frequency;
 
 } _GLFWtimeWin32;
 
+// Win32-specific global TLS data
+//
+typedef struct _GLFWtlsWin32
+{
+    GLFWbool        allocated;
+    DWORD           context;
 
-GLboolean _glfwRegisterWindowClass(void);
-void _glfwUnregisterWindowClass(void);
+} _GLFWtlsWin32;
 
-BOOL _glfwIsCompositionEnabled(void);
 
-WCHAR* _glfwCreateWideStringFromUTF8(const char* source);
-char* _glfwCreateUTF8FromWideString(const WCHAR* source);
+GLFWbool _glfwRegisterWindowClassWin32(void);
+void _glfwUnregisterWindowClassWin32(void);
 
-void _glfwInitTimer(void);
+GLFWbool _glfwInitThreadLocalStorageWin32(void);
+void _glfwTerminateThreadLocalStorageWin32(void);
 
-GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired);
-void _glfwRestoreVideoMode(_GLFWmonitor* monitor);
+WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source);
+char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source);
 
-#endif // _win32_platform_h_
+void _glfwInitTimerWin32(void);
+
+GLFWbool _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired);
+void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor);
+
+#endif // _glfw3_win32_platform_h_
diff --git a/glfw/src/win32_time.c b/glfw/src/win32_time.c
--- a/glfw/src/win32_time.c
+++ b/glfw/src/win32_time.c
@@ -1,8 +1,8 @@
 //========================================================================
-// GLFW 3.1 Win32 - www.glfw.org
+// GLFW 3.2 Win32 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -28,43 +28,26 @@
 #include "internal.h"
 
 
-// Return raw time
-//
-static unsigned __int64 getRawTime(void)
-{
-    if (_glfw.win32_time.hasPC)
-    {
-        unsigned __int64 time;
-        QueryPerformanceCounter((LARGE_INTEGER*) &time);
-        return time;
-    }
-    else
-        return (unsigned __int64) _glfw_timeGetTime();
-}
-
-
 //////////////////////////////////////////////////////////////////////////
 //////                       GLFW internal API                      //////
 //////////////////////////////////////////////////////////////////////////
 
 // Initialise timer
 //
-void _glfwInitTimer(void)
+void _glfwInitTimerWin32(void)
 {
-    unsigned __int64 frequency;
+    uint64_t frequency;
 
     if (QueryPerformanceFrequency((LARGE_INTEGER*) &frequency))
     {
-        _glfw.win32_time.hasPC = GL_TRUE;
-        _glfw.win32_time.resolution = 1.0 / (double) frequency;
+        _glfw.win32_time.hasPC = GLFW_TRUE;
+        _glfw.win32_time.frequency = frequency;
     }
     else
     {
-        _glfw.win32_time.hasPC = GL_FALSE;
-        _glfw.win32_time.resolution = 0.001; // winmm resolution is 1 ms
+        _glfw.win32_time.hasPC = GLFW_FALSE;
+        _glfw.win32_time.frequency = 1000;
     }
-
-    _glfw.win32_time.base = getRawTime();
 }
 
 
@@ -72,15 +55,20 @@
 //////                       GLFW platform API                      //////
 //////////////////////////////////////////////////////////////////////////
 
-double _glfwPlatformGetTime(void)
+uint64_t _glfwPlatformGetTimerValue(void)
 {
-    return (double) (getRawTime() - _glfw.win32_time.base) *
-        _glfw.win32_time.resolution;
+    if (_glfw.win32_time.hasPC)
+    {
+        uint64_t value;
+        QueryPerformanceCounter((LARGE_INTEGER*) &value);
+        return value;
+    }
+    else
+        return (uint64_t) _glfw_timeGetTime();
 }
 
-void _glfwPlatformSetTime(double time)
+uint64_t _glfwPlatformGetTimerFrequency(void)
 {
-    _glfw.win32_time.base = getRawTime() -
-        (unsigned __int64) (time / _glfw.win32_time.resolution);
+    return _glfw.win32_time.frequency;
 }
 
diff --git a/glfw/src/win32_tls.c b/glfw/src/win32_tls.c
--- a/glfw/src/win32_tls.c
+++ b/glfw/src/win32_tls.c
@@ -1,8 +1,8 @@
 //========================================================================
-// GLFW 3.1 Win32 - www.glfw.org
+// GLFW 3.2 Win32 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -32,35 +32,35 @@
 //////                       GLFW internal API                      //////
 //////////////////////////////////////////////////////////////////////////
 
-int _glfwInitTLS(void)
+GLFWbool _glfwInitThreadLocalStorageWin32(void)
 {
     _glfw.win32_tls.context = TlsAlloc();
     if (_glfw.win32_tls.context == TLS_OUT_OF_INDEXES)
     {
         _glfwInputError(GLFW_PLATFORM_ERROR,
                         "Win32: Failed to allocate TLS index");
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
 
-    _glfw.win32_tls.allocated = GL_TRUE;
-    return GL_TRUE;
+    _glfw.win32_tls.allocated = GLFW_TRUE;
+    return GLFW_TRUE;
 }
 
-void _glfwTerminateTLS(void)
+void _glfwTerminateThreadLocalStorageWin32(void)
 {
     if (_glfw.win32_tls.allocated)
         TlsFree(_glfw.win32_tls.context);
 }
 
-void _glfwSetCurrentContext(_GLFWwindow* context)
-{
-    TlsSetValue(_glfw.win32_tls.context, context);
-}
 
-
 //////////////////////////////////////////////////////////////////////////
 //////                       GLFW platform API                      //////
 //////////////////////////////////////////////////////////////////////////
+
+void _glfwPlatformSetCurrentContext(_GLFWwindow* context)
+{
+    TlsSetValue(_glfw.win32_tls.context, context);
+}
 
 _GLFWwindow* _glfwPlatformGetCurrentContext(void)
 {
diff --git a/glfw/src/win32_tls.h b/glfw/src/win32_tls.h
deleted file mode 100644
--- a/glfw/src/win32_tls.h
+++ /dev/null
@@ -1,48 +0,0 @@
-//========================================================================
-// GLFW 3.1 Win32 - www.glfw.org
-//------------------------------------------------------------------------
-// Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
-//
-// 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.
-//
-//========================================================================
-
-#ifndef _win32_tls_h_
-#define _win32_tls_h_
-
-#define _GLFW_PLATFORM_LIBRARY_TLS_STATE _GLFWtlsWin32 win32_tls
-
-
-// Win32-specific global TLS data
-//
-typedef struct _GLFWtlsWin32
-{
-    GLboolean       allocated;
-    DWORD           context;
-
-} _GLFWtlsWin32;
-
-
-int _glfwInitTLS(void);
-void _glfwTerminateTLS(void);
-void _glfwSetCurrentContext(_GLFWwindow* context);
-
-#endif // _win32_tls_h_
diff --git a/glfw/src/win32_window.c b/glfw/src/win32_window.c
--- a/glfw/src/win32_window.c
+++ b/glfw/src/win32_window.c
@@ -1,1301 +1,1713 @@
 //========================================================================
-// GLFW 3.1 Win32 - www.glfw.org
-//------------------------------------------------------------------------
-// Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
-//
-// 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 <stdlib.h>
-#include <malloc.h>
-#include <string.h>
-#include <windowsx.h>
-#include <shellapi.h>
-
-#define _GLFW_KEY_INVALID -2
-
-#define _GLFW_WNDCLASSNAME L"GLFW30"
-
-
-// Updates the cursor clip rect
-//
-static void updateClipRect(_GLFWwindow* window)
-{
-    RECT clipRect;
-    GetClientRect(window->win32.handle, &clipRect);
-    ClientToScreen(window->win32.handle, (POINT*) &clipRect.left);
-    ClientToScreen(window->win32.handle, (POINT*) &clipRect.right);
-    ClipCursor(&clipRect);
-}
-
-// Hide the mouse cursor
-//
-static void hideCursor(_GLFWwindow* window)
-{
-    POINT pos;
-
-    ClipCursor(NULL);
-
-    if (GetCursorPos(&pos))
-    {
-        if (WindowFromPoint(pos) == window->win32.handle)
-            SetCursor(NULL);
-    }
-}
-
-// Disable the mouse cursor
-//
-static void disableCursor(_GLFWwindow* window)
-{
-    POINT pos;
-
-    updateClipRect(window);
-
-    if (GetCursorPos(&pos))
-    {
-        if (WindowFromPoint(pos) == window->win32.handle)
-            SetCursor(NULL);
-    }
-}
-
-// Restores the mouse cursor
-//
-static void restoreCursor(_GLFWwindow* window)
-{
-    POINT pos;
-
-    ClipCursor(NULL);
-
-    if (GetCursorPos(&pos))
-    {
-        if (WindowFromPoint(pos) == window->win32.handle)
-        {
-            if (window->cursor)
-                SetCursor(window->cursor->win32.handle);
-            else
-                SetCursor(LoadCursorW(NULL, IDC_ARROW));
-        }
-    }
-}
-
-// Translates a GLFW standard cursor to a resource ID
-//
-static LPWSTR translateCursorShape(int shape)
-{
-    switch (shape)
-    {
-        case GLFW_ARROW_CURSOR:
-            return IDC_ARROW;
-        case GLFW_IBEAM_CURSOR:
-            return IDC_IBEAM;
-        case GLFW_CROSSHAIR_CURSOR:
-            return IDC_CROSS;
-        case GLFW_HAND_CURSOR:
-            return IDC_HAND;
-        case GLFW_HRESIZE_CURSOR:
-            return IDC_SIZEWE;
-        case GLFW_VRESIZE_CURSOR:
-            return IDC_SIZENS;
-    }
-
-    return NULL;
-}
-
-// Retrieves and translates modifier keys
-//
-static int getKeyMods(void)
-{
-    int mods = 0;
-
-    if (GetKeyState(VK_SHIFT) & (1 << 31))
-        mods |= GLFW_MOD_SHIFT;
-    if (GetKeyState(VK_CONTROL) & (1 << 31))
-        mods |= GLFW_MOD_CONTROL;
-    if (GetKeyState(VK_MENU) & (1 << 31))
-        mods |= GLFW_MOD_ALT;
-    if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & (1 << 31))
-        mods |= GLFW_MOD_SUPER;
-
-    return mods;
-}
-
-// Retrieves and translates modifier keys
-//
-static int getAsyncKeyMods(void)
-{
-    int mods = 0;
-
-    if (GetAsyncKeyState(VK_SHIFT) & (1 << 31))
-        mods |= GLFW_MOD_SHIFT;
-    if (GetAsyncKeyState(VK_CONTROL) & (1 << 31))
-        mods |= GLFW_MOD_CONTROL;
-    if (GetAsyncKeyState(VK_MENU) & (1 << 31))
-        mods |= GLFW_MOD_ALT;
-    if ((GetAsyncKeyState(VK_LWIN) | GetAsyncKeyState(VK_RWIN)) & (1 << 31))
-        mods |= GLFW_MOD_SUPER;
-
-    return mods;
-}
-
-// Translates a Windows key to the corresponding GLFW key
-//
-static int translateKey(WPARAM wParam, LPARAM lParam)
-{
-    if (wParam == VK_CONTROL)
-    {
-        // The CTRL keys require special handling
-
-        MSG next;
-        DWORD time;
-
-        // Is this an extended key (i.e. right key)?
-        if (lParam & 0x01000000)
-            return GLFW_KEY_RIGHT_CONTROL;
-
-        // Here is a trick: "Alt Gr" sends LCTRL, then RALT. We only
-        // want the RALT message, so we try to see if the next message
-        // is a RALT message. In that case, this is a false LCTRL!
-        time = GetMessageTime();
-
-        if (PeekMessageW(&next, NULL, 0, 0, PM_NOREMOVE))
-        {
-            if (next.message == WM_KEYDOWN ||
-                next.message == WM_SYSKEYDOWN ||
-                next.message == WM_KEYUP ||
-                next.message == WM_SYSKEYUP)
-            {
-                if (next.wParam == VK_MENU &&
-                    (next.lParam & 0x01000000) &&
-                    next.time == time)
-                {
-                    // Next message is a RALT down message, which
-                    // means that this is not a proper LCTRL message
-                    return _GLFW_KEY_INVALID;
-                }
-            }
-        }
-
-        return GLFW_KEY_LEFT_CONTROL;
-    }
-
-    return _glfw.win32.publicKeys[HIWORD(lParam) & 0x1FF];
-}
-
-// Enter full screen mode
-//
-static GLboolean enterFullscreenMode(_GLFWwindow* window)
-{
-    GLFWvidmode mode;
-    GLboolean status;
-    int xpos, ypos;
-
-    status = _glfwSetVideoMode(window->monitor, &window->videoMode);
-
-    _glfwPlatformGetVideoMode(window->monitor, &mode);
-    _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos);
-
-    SetWindowPos(window->win32.handle, HWND_TOPMOST,
-                 xpos, ypos, mode.width, mode.height, SWP_NOCOPYBITS);
-
-    return status;
-}
-
-// Leave full screen mode
-//
-static void leaveFullscreenMode(_GLFWwindow* window)
-{
-    _glfwRestoreVideoMode(window->monitor);
-}
-
-// Window callback function (handles window events)
-//
-static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
-                                   WPARAM wParam, LPARAM lParam)
-{
-    _GLFWwindow* window = (_GLFWwindow*) GetWindowLongPtrW(hWnd, 0);
-
-    switch (uMsg)
-    {
-        case WM_NCCREATE:
-        {
-            CREATESTRUCTW* cs = (CREATESTRUCTW*) lParam;
-            SetWindowLongPtrW(hWnd, 0, (LONG_PTR) cs->lpCreateParams);
-            break;
-        }
-
-        case WM_SETFOCUS:
-        {
-            if (window->cursorMode != GLFW_CURSOR_NORMAL)
-                _glfwPlatformApplyCursorMode(window);
-
-            if (window->monitor && window->autoIconify)
-                enterFullscreenMode(window);
-
-            _glfwInputWindowFocus(window, GL_TRUE);
-            return 0;
-        }
-
-        case WM_KILLFOCUS:
-        {
-            if (window->cursorMode != GLFW_CURSOR_NORMAL)
-                restoreCursor(window);
-
-            if (window->monitor && window->autoIconify)
-            {
-                _glfwPlatformIconifyWindow(window);
-                leaveFullscreenMode(window);
-            }
-
-            _glfwInputWindowFocus(window, GL_FALSE);
-            return 0;
-        }
-
-        case WM_SYSCOMMAND:
-        {
-            switch (wParam & 0xfff0)
-            {
-                case SC_SCREENSAVE:
-                case SC_MONITORPOWER:
-                {
-                    if (window->monitor)
-                    {
-                        // We are running in full screen mode, so disallow
-                        // screen saver and screen blanking
-                        return 0;
-                    }
-                    else
-                        break;
-                }
-
-                // User trying to access application menu using ALT?
-                case SC_KEYMENU:
-                    return 0;
-            }
-            break;
-        }
-
-        case WM_CLOSE:
-        {
-            _glfwInputWindowCloseRequest(window);
-            return 0;
-        }
-
-        case WM_KEYDOWN:
-        case WM_SYSKEYDOWN:
-        {
-            const int scancode = (lParam >> 16) & 0x1ff;
-            const int key = translateKey(wParam, lParam);
-            if (key == _GLFW_KEY_INVALID)
-                break;
-
-            _glfwInputKey(window, key, scancode, GLFW_PRESS, getKeyMods());
-            break;
-        }
-
-        case WM_CHAR:
-        {
-            _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), GL_TRUE);
-            return 0;
-        }
-
-        case WM_SYSCHAR:
-        {
-            _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), GL_FALSE);
-            return 0;
-        }
-
-        case WM_UNICHAR:
-        {
-            // This message is not sent by Windows, but is sent by some
-            // third-party input method engines
-
-            if (wParam == UNICODE_NOCHAR)
-            {
-                // Returning TRUE here announces support for this message
-                return TRUE;
-            }
-
-            _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), GL_TRUE);
-            return FALSE;
-        }
-
-        case WM_KEYUP:
-        case WM_SYSKEYUP:
-        {
-            const int mods = getKeyMods();
-            const int scancode = (lParam >> 16) & 0x1ff;
-            const int key = translateKey(wParam, lParam);
-            if (key == _GLFW_KEY_INVALID)
-                break;
-
-            if (wParam == VK_SHIFT)
-            {
-                // Release both Shift keys on Shift up event, as only one event
-                // is sent even if both keys are released
-                _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, scancode, GLFW_RELEASE, mods);
-                _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, scancode, GLFW_RELEASE, mods);
-            }
-            else if (wParam == VK_SNAPSHOT)
-            {
-                // Key down is not reported for the print screen key
-                _glfwInputKey(window, key, scancode, GLFW_PRESS, mods);
-                _glfwInputKey(window, key, scancode, GLFW_RELEASE, mods);
-            }
-            else
-                _glfwInputKey(window, key, scancode, GLFW_RELEASE, mods);
-
-            break;
-        }
-
-        case WM_LBUTTONDOWN:
-        case WM_RBUTTONDOWN:
-        case WM_MBUTTONDOWN:
-        case WM_XBUTTONDOWN:
-        {
-            const int mods = getKeyMods();
-
-            SetCapture(hWnd);
-
-            if (uMsg == WM_LBUTTONDOWN)
-                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS, mods);
-            else if (uMsg == WM_RBUTTONDOWN)
-                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS, mods);
-            else if (uMsg == WM_MBUTTONDOWN)
-                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS, mods);
-            else
-            {
-                if (HIWORD(wParam) == XBUTTON1)
-                    _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_4, GLFW_PRESS, mods);
-                else if (HIWORD(wParam) == XBUTTON2)
-                    _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_5, GLFW_PRESS, mods);
-
-                return TRUE;
-            }
-
-            return 0;
-        }
-
-        case WM_LBUTTONUP:
-        case WM_RBUTTONUP:
-        case WM_MBUTTONUP:
-        case WM_XBUTTONUP:
-        {
-            const int mods = getKeyMods();
-
-            ReleaseCapture();
-
-            if (uMsg == WM_LBUTTONUP)
-                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_RELEASE, mods);
-            else if (uMsg == WM_RBUTTONUP)
-                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_RELEASE, mods);
-            else if (uMsg == WM_MBUTTONUP)
-                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_RELEASE, mods);
-            else
-            {
-                if (HIWORD(wParam) == XBUTTON1)
-                    _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_4, GLFW_RELEASE, mods);
-                else if (HIWORD(wParam) == XBUTTON2)
-                    _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_5, GLFW_RELEASE, mods);
-
-                return TRUE;
-            }
-
-            return 0;
-        }
-
-        case WM_MOUSEMOVE:
-        {
-            const int x = GET_X_LPARAM(lParam);
-            const int y = GET_Y_LPARAM(lParam);
-
-            if (window->cursorMode == GLFW_CURSOR_DISABLED)
-            {
-                if (_glfw.focusedWindow != window)
-                    break;
-
-                _glfwInputCursorMotion(window,
-                                        x - window->win32.cursorPosX,
-                                        y - window->win32.cursorPosY);
-            }
-            else
-                _glfwInputCursorMotion(window, x, y);
-
-            window->win32.cursorPosX = x;
-            window->win32.cursorPosY = y;
-
-            if (!window->win32.cursorInside)
-            {
-                TRACKMOUSEEVENT tme;
-                ZeroMemory(&tme, sizeof(tme));
-                tme.cbSize = sizeof(tme);
-                tme.dwFlags = TME_LEAVE;
-                tme.hwndTrack = window->win32.handle;
-                TrackMouseEvent(&tme);
-
-                window->win32.cursorInside = GL_TRUE;
-                _glfwInputCursorEnter(window, GL_TRUE);
-            }
-
-            return 0;
-        }
-
-        case WM_MOUSELEAVE:
-        {
-            window->win32.cursorInside = GL_FALSE;
-            _glfwInputCursorEnter(window, GL_FALSE);
-            return 0;
-        }
-
-        case WM_MOUSEWHEEL:
-        {
-            _glfwInputScroll(window, 0.0, (SHORT) HIWORD(wParam) / (double) WHEEL_DELTA);
-            return 0;
-        }
-
-        case WM_MOUSEHWHEEL:
-        {
-            // This message is only sent on Windows Vista and later
-            // NOTE: The X-axis is inverted for consistency with OS X and X11.
-            _glfwInputScroll(window, -((SHORT) HIWORD(wParam) / (double) WHEEL_DELTA), 0.0);
-            return 0;
-        }
-
-        case WM_SIZE:
-        {
-            if (_glfw.focusedWindow == window)
-            {
-                if (window->cursorMode == GLFW_CURSOR_DISABLED)
-                    updateClipRect(window);
-            }
-
-            if (!window->win32.iconified && wParam == SIZE_MINIMIZED)
-            {
-                window->win32.iconified = GL_TRUE;
-                _glfwInputWindowIconify(window, GL_TRUE);
-            }
-            else if (window->win32.iconified &&
-                     (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED))
-            {
-                window->win32.iconified = GL_FALSE;
-                _glfwInputWindowIconify(window, GL_FALSE);
-            }
-
-            _glfwInputFramebufferSize(window, LOWORD(lParam), HIWORD(lParam));
-            _glfwInputWindowSize(window, LOWORD(lParam), HIWORD(lParam));
-            return 0;
-        }
-
-        case WM_MOVE:
-        {
-            if (_glfw.focusedWindow == window)
-            {
-                if (window->cursorMode == GLFW_CURSOR_DISABLED)
-                    updateClipRect(window);
-            }
-
-            // NOTE: This cannot use LOWORD/HIWORD recommended by MSDN, as
-            // those macros do not handle negative window positions correctly
-            _glfwInputWindowPos(window,
-                                GET_X_LPARAM(lParam),
-                                GET_Y_LPARAM(lParam));
-            return 0;
-        }
-
-        case WM_PAINT:
-        {
-            _glfwInputWindowDamage(window);
-            break;
-        }
-
-        case WM_ERASEBKGND:
-        {
-            return TRUE;
-        }
-
-        case WM_SETCURSOR:
-        {
-            if (_glfw.focusedWindow == window && LOWORD(lParam) == HTCLIENT)
-            {
-                if (window->cursorMode == GLFW_CURSOR_HIDDEN ||
-                    window->cursorMode == GLFW_CURSOR_DISABLED)
-                {
-                    SetCursor(NULL);
-                    return TRUE;
-                }
-                else if (window->cursor)
-                {
-                    SetCursor(window->cursor->win32.handle);
-                    return TRUE;
-                }
-            }
-
-            break;
-        }
-
-        case WM_DEVICECHANGE:
-        {
-            if (DBT_DEVNODES_CHANGED == wParam)
-            {
-                _glfwInputMonitorChange();
-                return TRUE;
-            }
-            break;
-        }
-
-        case WM_DWMCOMPOSITIONCHANGED:
-        {
-            if (_glfwIsCompositionEnabled())
-            {
-                _GLFWwindow* previous = _glfwPlatformGetCurrentContext();
-                _glfwPlatformMakeContextCurrent(window);
-                _glfwPlatformSwapInterval(0);
-                _glfwPlatformMakeContextCurrent(previous);
-            }
-
-            // TODO: Restore vsync if compositing was disabled
-            break;
-        }
-
-        case WM_DROPFILES:
-        {
-            HDROP hDrop = (HDROP) wParam;
-            POINT pt;
-            int i;
-
-            const int count = DragQueryFileW(hDrop, 0xffffffff, NULL, 0);
-            char** paths = calloc(count, sizeof(char*));
-
-            // Move the mouse to the position of the drop
-            DragQueryPoint(hDrop, &pt);
-            _glfwInputCursorMotion(window, pt.x, pt.y);
-
-            for (i = 0;  i < count;  i++)
-            {
-                const UINT length = DragQueryFileW(hDrop, i, NULL, 0);
-                WCHAR* buffer = calloc(length + 1, sizeof(WCHAR));
-
-                DragQueryFileW(hDrop, i, buffer, length + 1);
-                paths[i] = _glfwCreateUTF8FromWideString(buffer);
-
-                free(buffer);
-            }
-
-            _glfwInputDrop(window, count, (const char**) paths);
-
-            for (i = 0;  i < count;  i++)
-                free(paths[i]);
-            free(paths);
-
-            DragFinish(hDrop);
-            return 0;
-        }
-    }
-
-    return DefWindowProc(hWnd, uMsg, wParam, lParam);
-}
-
-// Translate client window size to full window size (including window borders)
-//
-static void getFullWindowSize(_GLFWwindow* window,
-                              int clientWidth, int clientHeight,
-                              int* fullWidth, int* fullHeight)
-{
-    RECT rect = { 0, 0, clientWidth, clientHeight };
-    AdjustWindowRectEx(&rect, window->win32.dwStyle,
-                       FALSE, window->win32.dwExStyle);
-    *fullWidth = rect.right - rect.left;
-    *fullHeight = rect.bottom - rect.top;
-}
-
-// Creates the GLFW window and rendering context
-//
-static int createWindow(_GLFWwindow* window,
-                        const _GLFWwndconfig* wndconfig,
-                        const _GLFWctxconfig* ctxconfig,
-                        const _GLFWfbconfig* fbconfig)
-{
-    int xpos, ypos, fullWidth, fullHeight;
-    WCHAR* wideTitle;
-
-    window->win32.dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
-    window->win32.dwExStyle = WS_EX_APPWINDOW;
-
-    if (window->monitor)
-    {
-        window->win32.dwStyle |= WS_POPUP;
-
-        // NOTE: This window placement is temporary and approximate, as the
-        //       correct position and size cannot be known until the monitor
-        //       video mode has been set
-        _glfwPlatformGetMonitorPos(wndconfig->monitor, &xpos, &ypos);
-        fullWidth  = wndconfig->width;
-        fullHeight = wndconfig->height;
-    }
-    else
-    {
-        if (wndconfig->decorated)
-        {
-            window->win32.dwStyle |= WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
-
-            if (wndconfig->resizable)
-            {
-                window->win32.dwStyle |= WS_MAXIMIZEBOX | WS_SIZEBOX;
-                window->win32.dwExStyle |= WS_EX_WINDOWEDGE;
-            }
-        }
-        else
-            window->win32.dwStyle |= WS_POPUP;
-
-        xpos = CW_USEDEFAULT;
-        ypos = CW_USEDEFAULT;
-
-        getFullWindowSize(window,
-                          wndconfig->width, wndconfig->height,
-                          &fullWidth, &fullHeight);
-    }
-
-    wideTitle = _glfwCreateWideStringFromUTF8(wndconfig->title);
-    if (!wideTitle)
-    {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "Win32: Failed to convert title to wide string");
-        return GL_FALSE;
-    }
-
-    window->win32.handle = CreateWindowExW(window->win32.dwExStyle,
-                                           _GLFW_WNDCLASSNAME,
-                                           wideTitle,
-                                           window->win32.dwStyle,
-                                           xpos, ypos,
-                                           fullWidth, fullHeight,
-                                           NULL, // No parent window
-                                           NULL, // No window menu
-                                           GetModuleHandleW(NULL),
-                                           window); // Pass object to WM_CREATE
-
-    free(wideTitle);
-
-    if (!window->win32.handle)
-    {
-        _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create window");
-        return GL_FALSE;
-    }
-
-    if (_glfw_ChangeWindowMessageFilterEx)
-    {
-        _glfw_ChangeWindowMessageFilterEx(window->win32.handle,
-                                          WM_DROPFILES, MSGFLT_ALLOW, NULL);
-        _glfw_ChangeWindowMessageFilterEx(window->win32.handle,
-                                          WM_COPYDATA, MSGFLT_ALLOW, NULL);
-        _glfw_ChangeWindowMessageFilterEx(window->win32.handle,
-                                          WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL);
-    }
-
-    if (wndconfig->floating && !wndconfig->monitor)
-    {
-        SetWindowPos(window->win32.handle,
-                        HWND_TOPMOST,
-                        0, 0, 0, 0,
-                        SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
-    }
-
-    DragAcceptFiles(window->win32.handle, TRUE);
-
-    if (!_glfwCreateContext(window, ctxconfig, fbconfig))
-        return GL_FALSE;
-
-    return GL_TRUE;
-}
-
-// Destroys the GLFW window and rendering context
-//
-static void destroyWindow(_GLFWwindow* window)
-{
-    _glfwDestroyContext(window);
-
-    if (window->win32.handle)
-    {
-        DestroyWindow(window->win32.handle);
-        window->win32.handle = NULL;
-    }
-}
-
-
-//////////////////////////////////////////////////////////////////////////
-//////                       GLFW internal API                      //////
-//////////////////////////////////////////////////////////////////////////
-
-// Registers the GLFW window class
-//
-GLboolean _glfwRegisterWindowClass(void)
-{
-    WNDCLASSW wc;
-
-    wc.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
-    wc.lpfnWndProc   = (WNDPROC) windowProc;
-    wc.cbClsExtra    = 0;                           // No extra class data
-    wc.cbWndExtra    = sizeof(void*) + sizeof(int); // Make room for one pointer
-    wc.hInstance     = GetModuleHandleW(NULL);
-    wc.hCursor       = LoadCursorW(NULL, IDC_ARROW);
-    wc.hbrBackground = NULL;                        // No background
-    wc.lpszMenuName  = NULL;                        // No menu
-    wc.lpszClassName = _GLFW_WNDCLASSNAME;
-
-    // Load user-provided icon if available
-    wc.hIcon = LoadIconW(GetModuleHandleW(NULL), L"GLFW_ICON");
-    if (!wc.hIcon)
-    {
-        // No user-provided icon found, load default icon
-        wc.hIcon = LoadIconW(NULL, IDI_WINLOGO);
-    }
-
-    if (!RegisterClassW(&wc))
-    {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "Win32: Failed to register window class");
-        return GL_FALSE;
-    }
-
-    return GL_TRUE;
-}
-
-// Unregisters the GLFW window class
-//
-void _glfwUnregisterWindowClass(void)
-{
-    UnregisterClassW(_GLFW_WNDCLASSNAME, GetModuleHandleW(NULL));
-}
-
-
-//////////////////////////////////////////////////////////////////////////
-//////                       GLFW platform API                      //////
-//////////////////////////////////////////////////////////////////////////
-
-int _glfwPlatformCreateWindow(_GLFWwindow* window,
-                              const _GLFWwndconfig* wndconfig,
-                              const _GLFWctxconfig* ctxconfig,
-                              const _GLFWfbconfig* fbconfig)
-{
-    int status;
-
-    if (!createWindow(window, wndconfig, ctxconfig, fbconfig))
-        return GL_FALSE;
-
-    status = _glfwAnalyzeContext(window, ctxconfig, fbconfig);
-
-    if (status == _GLFW_RECREATION_IMPOSSIBLE)
-        return GL_FALSE;
-
-    if (status == _GLFW_RECREATION_REQUIRED)
-    {
-        // Some window hints require us to re-create the context using WGL
-        // extensions retrieved through the current context, as we cannot check
-        // for WGL extensions or retrieve WGL entry points before we have a
-        // current context (actually until we have implicitly loaded the ICD)
-
-        // Yes, this is strange, and yes, this is the proper way on Win32
-
-        // As Windows only allows you to set the pixel format once for a
-        // window, we need to destroy the current window and create a new one
-        // to be able to use the new pixel format
-
-        // Technically, it may be possible to keep the old window around if
-        // we're just creating an OpenGL 3.0+ context with the same pixel
-        // format, but it's not worth the added code complexity
-
-        // First we clear the current context (the one we just created)
-        // This is usually done by glfwDestroyWindow, but as we're not doing
-        // full GLFW window destruction, it's duplicated here
-        _glfwPlatformMakeContextCurrent(NULL);
-
-        // Next destroy the Win32 window and WGL context (without resetting or
-        // destroying the GLFW window object)
-        destroyWindow(window);
-
-        // ...and then create them again, this time with better APIs
-        if (!createWindow(window, wndconfig, ctxconfig, fbconfig))
-            return GL_FALSE;
-    }
-
-    if (window->monitor)
-    {
-        _glfwPlatformShowWindow(window);
-        if (!enterFullscreenMode(window))
-            return GL_FALSE;
-    }
-
-    return GL_TRUE;
-}
-
-void _glfwPlatformDestroyWindow(_GLFWwindow* window)
-{
-    if (window->monitor)
-        leaveFullscreenMode(window);
-
-    destroyWindow(window);
-}
-
-void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
-{
-    WCHAR* wideTitle = _glfwCreateWideStringFromUTF8(title);
-    if (!wideTitle)
-    {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "Win32: Failed to convert title to wide string");
-        return;
-    }
-
-    SetWindowTextW(window->win32.handle, wideTitle);
-    free(wideTitle);
-}
-
-void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
-{
-    POINT pos = { 0, 0 };
-    ClientToScreen(window->win32.handle, &pos);
-
-    if (xpos)
-        *xpos = pos.x;
-    if (ypos)
-        *ypos = pos.y;
-}
-
-void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
-{
-    RECT rect = { xpos, ypos, xpos, ypos };
-    AdjustWindowRectEx(&rect, window->win32.dwStyle,
-                       FALSE, window->win32.dwExStyle);
-    SetWindowPos(window->win32.handle, NULL, rect.left, rect.top, 0, 0,
-                 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
-}
-
-void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
-{
-    RECT area;
-    GetClientRect(window->win32.handle, &area);
-
-    if (width)
-        *width = area.right;
-    if (height)
-        *height = area.bottom;
-}
-
-void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
-{
-    if (window->monitor)
-        enterFullscreenMode(window);
-    else
-    {
-        int fullWidth, fullHeight;
-        getFullWindowSize(window, width, height, &fullWidth, &fullHeight);
-
-        SetWindowPos(window->win32.handle, HWND_TOP,
-                     0, 0, fullWidth, fullHeight,
-                     SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER);
-    }
-}
-
-void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height)
-{
-    _glfwPlatformGetWindowSize(window, width, height);
-}
-
-void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
-                                     int* left, int* top,
-                                     int* right, int* bottom)
-{
-    RECT rect;
-    int width, height;
-
-    _glfwPlatformGetWindowSize(window, &width, &height);
-    SetRect(&rect, 0, 0, width, height);
-    AdjustWindowRectEx(&rect, window->win32.dwStyle,
-                       FALSE, window->win32.dwExStyle);
-
-    if (left)
-        *left = -rect.left;
-    if (top)
-        *top = -rect.top;
-    if (right)
-        *right = rect.right - width;
-    if (bottom)
-        *bottom = rect.bottom - height;
-}
-
-void _glfwPlatformIconifyWindow(_GLFWwindow* window)
-{
-    ShowWindow(window->win32.handle, SW_MINIMIZE);
-}
-
-void _glfwPlatformRestoreWindow(_GLFWwindow* window)
-{
-    ShowWindow(window->win32.handle, SW_RESTORE);
-}
-
-void _glfwPlatformShowWindow(_GLFWwindow* window)
-{
-    ShowWindow(window->win32.handle, SW_SHOW);
-    BringWindowToTop(window->win32.handle);
-    SetForegroundWindow(window->win32.handle);
-    SetFocus(window->win32.handle);
-}
-
-void _glfwPlatformUnhideWindow(_GLFWwindow* window)
-{
-    ShowWindow(window->win32.handle, SW_SHOW);
-}
-
-void _glfwPlatformHideWindow(_GLFWwindow* window)
-{
-    ShowWindow(window->win32.handle, SW_HIDE);
-}
-
-int _glfwPlatformWindowFocused(_GLFWwindow* window)
-{
-    return window->win32.handle == GetActiveWindow();
-}
-
-int _glfwPlatformWindowIconified(_GLFWwindow* window)
-{
-    return IsIconic(window->win32.handle);
-}
-
-int _glfwPlatformWindowVisible(_GLFWwindow* window)
-{
-    return IsWindowVisible(window->win32.handle);
-}
-
-void _glfwPlatformPollEvents(void)
-{
-    MSG msg;
-    _GLFWwindow* window;
-
-    while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
-    {
-        if (msg.message == WM_QUIT)
-        {
-            // Treat WM_QUIT as a close on all windows
-            // While GLFW does not itself post WM_QUIT, other processes may post
-            // it to this one, for example Task Manager
-
-            window = _glfw.windowListHead;
-            while (window)
-            {
-                _glfwInputWindowCloseRequest(window);
-                window = window->next;
-            }
-        }
-        else
-        {
-            TranslateMessage(&msg);
-            DispatchMessageW(&msg);
-        }
-    }
-
-    window = _glfw.focusedWindow;
-    if (window)
-    {
-        // LSHIFT/RSHIFT fixup (keys tend to "stick" without this fix)
-        // This is the only async event handling in GLFW, but it solves some
-        // nasty problems
-        {
-            const int mods = getAsyncKeyMods();
-
-            // Get current state of left and right shift keys
-            const int lshiftDown = (GetAsyncKeyState(VK_LSHIFT) >> 15) & 1;
-            const int rshiftDown = (GetAsyncKeyState(VK_RSHIFT) >> 15) & 1;
-
-            // See if this differs from our belief of what has happened
-            // (we only have to check for lost key up events)
-            if (!lshiftDown && window->keys[GLFW_KEY_LEFT_SHIFT] == 1)
-                _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, 0, GLFW_RELEASE, mods);
-
-            if (!rshiftDown && window->keys[GLFW_KEY_RIGHT_SHIFT] == 1)
-                _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, 0, GLFW_RELEASE, mods);
-        }
-
-        // Did the cursor move in an focused window that has disabled the cursor
-        if (window->cursorMode == GLFW_CURSOR_DISABLED)
-        {
-            int width, height;
-            _glfwPlatformGetWindowSize(window, &width, &height);
-            _glfwPlatformSetCursorPos(window, width / 2, height / 2);
-        }
-    }
-}
-
-void _glfwPlatformWaitEvents(void)
-{
-    WaitMessage();
-
-    _glfwPlatformPollEvents();
-}
-
-void _glfwPlatformPostEmptyEvent(void)
-{
-    _GLFWwindow* window = _glfw.windowListHead;
-    PostMessage(window->win32.handle, WM_NULL, 0, 0);
-}
-
-void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
-{
-    POINT pos;
-
-    if (GetCursorPos(&pos))
-    {
-        ScreenToClient(window->win32.handle, &pos);
-
-        if (xpos)
-            *xpos = pos.x;
-        if (ypos)
-            *ypos = pos.y;
-    }
-}
-
-void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos)
-{
-    POINT pos = { (int) xpos, (int) ypos };
-
-    // Store the new position so it can be recognized later
-    window->win32.cursorPosX = pos.x;
-    window->win32.cursorPosY = pos.y;
-
-    ClientToScreen(window->win32.handle, &pos);
-    SetCursorPos(pos.x, pos.y);
-}
-
-void _glfwPlatformApplyCursorMode(_GLFWwindow* window)
-{
-    switch (window->cursorMode)
-    {
-        case GLFW_CURSOR_NORMAL:
-            restoreCursor(window);
-            break;
-        case GLFW_CURSOR_HIDDEN:
-            hideCursor(window);
-            break;
-        case GLFW_CURSOR_DISABLED:
-            disableCursor(window);
-            break;
-    }
-}
-
-int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
-                              const GLFWimage* image,
-                              int xhot, int yhot)
-{
-    HDC dc;
-    HBITMAP bitmap, mask;
-    BITMAPV5HEADER bi;
-    ICONINFO ii;
-    DWORD* target = 0;
-    BYTE* source = (BYTE*) image->pixels;
-    int i;
-
-    ZeroMemory(&bi, sizeof(bi));
-    bi.bV5Size        = sizeof(BITMAPV5HEADER);
-    bi.bV5Width       = image->width;
-    bi.bV5Height      = -image->height;
-    bi.bV5Planes      = 1;
-    bi.bV5BitCount    = 32;
-    bi.bV5Compression = BI_BITFIELDS;
-    bi.bV5RedMask     = 0x00ff0000;
-    bi.bV5GreenMask   = 0x0000ff00;
-    bi.bV5BlueMask    = 0x000000ff;
-    bi.bV5AlphaMask   = 0xff000000;
-
-    dc = GetDC(NULL);
-    bitmap = CreateDIBSection(dc, (BITMAPINFO*) &bi, DIB_RGB_COLORS,
-                              (void**) &target, NULL, (DWORD) 0);
-    ReleaseDC(NULL, dc);
-
-    if (!bitmap)
-        return GL_FALSE;
-
-    mask = CreateBitmap(image->width, image->height, 1, 1, NULL);
-    if (!mask)
-    {
-        DeleteObject(bitmap);
-        return GL_FALSE;
-    }
-
-    for (i = 0;  i < image->width * image->height;  i++, target++, source += 4)
-    {
-        *target = (source[3] << 24) |
-                  (source[0] << 16) |
-                  (source[1] <<  8) |
-                   source[2];
-    }
-
-    ZeroMemory(&ii, sizeof(ii));
-    ii.fIcon    = FALSE;
-    ii.xHotspot = xhot;
-    ii.yHotspot = yhot;
-    ii.hbmMask  = mask;
-    ii.hbmColor = bitmap;
-
-    cursor->win32.handle = (HCURSOR) CreateIconIndirect(&ii);
-
-    DeleteObject(bitmap);
-    DeleteObject(mask);
-
-    if (!cursor->win32.handle)
-        return GL_FALSE;
-
-    return GL_TRUE;
-}
-
-int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
-{
-    LPCWSTR native = translateCursorShape(shape);
-    if (!native)
-    {
-        _glfwInputError(GLFW_INVALID_ENUM, "Win32: Invalid standard cursor");
-        return GL_FALSE;
-    }
-
-    cursor->win32.handle = CopyCursor(LoadCursorW(NULL, native));
-    if (!cursor->win32.handle)
-    {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "Win32: Failed to retrieve shared cursor");
-        return GL_FALSE;
-    }
-
-    return GL_TRUE;
-}
-
-void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
-{
-    if (cursor->win32.handle)
-        DestroyIcon((HICON) cursor->win32.handle);
-}
-
-void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
-{
-    // It should be guaranteed that the cursor is not being used by this window if
-    // the following condition is not met. That way it should be safe to destroy the
-    // cursor after calling glfwSetCursor(window, NULL) on all windows using the cursor.
-
-    if (_glfw.focusedWindow == window &&
-        window->cursorMode == GLFW_CURSOR_NORMAL &&
-        window->win32.cursorInside)
-    {
-        if (cursor)
-            SetCursor(cursor->win32.handle);
-        else
-            SetCursor(LoadCursorW(NULL, IDC_ARROW));
-    }
-}
-
-void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
-{
-    WCHAR* wideString;
-    HANDLE stringHandle;
-    size_t wideSize;
-
-    wideString = _glfwCreateWideStringFromUTF8(string);
-    if (!wideString)
-    {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "Win32: Failed to convert clipboard string to "
-                        "wide string");
-        return;
-    }
-
-    wideSize = (wcslen(wideString) + 1) * sizeof(WCHAR);
-
-    stringHandle = GlobalAlloc(GMEM_MOVEABLE, wideSize);
-    if (!stringHandle)
-    {
-        free(wideString);
-
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "Win32: Failed to allocate global handle for clipboard");
-        return;
-    }
-
-    memcpy(GlobalLock(stringHandle), wideString, wideSize);
-    GlobalUnlock(stringHandle);
-
-    if (!OpenClipboard(window->win32.handle))
-    {
-        GlobalFree(stringHandle);
-        free(wideString);
-
-        _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to open clipboard");
-        return;
-    }
-
-    EmptyClipboard();
-    SetClipboardData(CF_UNICODETEXT, stringHandle);
-    CloseClipboard();
-
-    free(wideString);
-}
-
-const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
-{
-    HANDLE stringHandle;
-
-    if (!IsClipboardFormatAvailable(CF_UNICODETEXT))
-    {
-        _glfwInputError(GLFW_FORMAT_UNAVAILABLE, NULL);
-        return NULL;
-    }
-
-    if (!OpenClipboard(window->win32.handle))
-    {
-        _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to open clipboard");
-        return NULL;
-    }
-
-    stringHandle = GetClipboardData(CF_UNICODETEXT);
-    if (!stringHandle)
-    {
-        CloseClipboard();
-
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "Win32: Failed to retrieve clipboard data");
-        return NULL;
-    }
-
-    free(_glfw.win32.clipboardString);
-    _glfw.win32.clipboardString =
-        _glfwCreateUTF8FromWideString(GlobalLock(stringHandle));
-
-    GlobalUnlock(stringHandle);
-    CloseClipboard();
-
-    if (!_glfw.win32.clipboardString)
-    {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "Win32: Failed to convert wide string to UTF-8");
-        return NULL;
-    }
-
-    return _glfw.win32.clipboardString;
+// GLFW 3.2 Win32 - www.glfw.org
+//------------------------------------------------------------------------
+// Copyright (c) 2002-2006 Marcus Geelnard
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
+//
+// 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 <limits.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <string.h>
+#include <windowsx.h>
+#include <shellapi.h>
+
+#define _GLFW_KEY_INVALID -2
+
+// Returns the window style for the specified window
+//
+static DWORD getWindowStyle(const _GLFWwindow* window)
+{
+    DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
+
+    if (window->monitor)
+        style |= WS_POPUP;
+    else
+    {
+        if (window->decorated)
+        {
+            style |= WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
+
+            if (window->resizable)
+                style |= WS_MAXIMIZEBOX | WS_THICKFRAME;
+        }
+        else
+            style |= WS_POPUP;
+    }
+
+    return style;
+}
+
+// Returns the extended window style for the specified window
+//
+static DWORD getWindowExStyle(const _GLFWwindow* window)
+{
+    DWORD style = WS_EX_APPWINDOW;
+
+    if (window->monitor || window->floating)
+        style |= WS_EX_TOPMOST;
+
+    return style;
+}
+
+// Returns the image whose area most closely matches the desired one
+//
+static const GLFWimage* chooseImage(int count, const GLFWimage* images,
+                                    int width, int height)
+{
+    int i, leastDiff = INT_MAX;
+    const GLFWimage* closest = NULL;
+
+    for (i = 0;  i < count;  i++)
+    {
+        const int currDiff = abs(images[i].width * images[i].height -
+                                 width * height);
+        if (currDiff < leastDiff)
+        {
+            closest = images + i;
+            leastDiff = currDiff;
+        }
+    }
+
+    return closest;
+}
+
+// Creates an RGBA icon or cursor
+//
+static HICON createIcon(const GLFWimage* image,
+                        int xhot, int yhot, GLFWbool icon)
+{
+    int i;
+    HDC dc;
+    HICON handle;
+    HBITMAP color, mask;
+    BITMAPV5HEADER bi;
+    ICONINFO ii;
+    unsigned char* target = NULL;
+    unsigned char* source = image->pixels;
+
+    ZeroMemory(&bi, sizeof(bi));
+    bi.bV5Size        = sizeof(BITMAPV5HEADER);
+    bi.bV5Width       = image->width;
+    bi.bV5Height      = -image->height;
+    bi.bV5Planes      = 1;
+    bi.bV5BitCount    = 32;
+    bi.bV5Compression = BI_BITFIELDS;
+    bi.bV5RedMask     = 0x00ff0000;
+    bi.bV5GreenMask   = 0x0000ff00;
+    bi.bV5BlueMask    = 0x000000ff;
+    bi.bV5AlphaMask   = 0xff000000;
+
+    dc = GetDC(NULL);
+    color = CreateDIBSection(dc,
+                             (BITMAPINFO*) &bi,
+                             DIB_RGB_COLORS,
+                             (void**) &target,
+                             NULL,
+                             (DWORD) 0);
+    ReleaseDC(NULL, dc);
+
+    if (!color)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Win32: Failed to create RGBA bitmap");
+        return NULL;
+    }
+
+    mask = CreateBitmap(image->width, image->height, 1, 1, NULL);
+    if (!mask)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Win32: Failed to create mask bitmap");
+        DeleteObject(color);
+        return NULL;
+    }
+
+    for (i = 0;  i < image->width * image->height;  i++)
+    {
+        target[0] = source[2];
+        target[1] = source[1];
+        target[2] = source[0];
+        target[3] = source[3];
+        target += 4;
+        source += 4;
+    }
+
+    ZeroMemory(&ii, sizeof(ii));
+    ii.fIcon    = icon;
+    ii.xHotspot = xhot;
+    ii.yHotspot = yhot;
+    ii.hbmMask  = mask;
+    ii.hbmColor = color;
+
+    handle = CreateIconIndirect(&ii);
+
+    DeleteObject(color);
+    DeleteObject(mask);
+
+    if (!handle)
+    {
+        if (icon)
+            _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create icon");
+        else
+            _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create cursor");
+    }
+
+    return handle;
+}
+
+// Translate client window size to full window size according to styles
+//
+static void getFullWindowSize(DWORD style, DWORD exStyle,
+                              int clientWidth, int clientHeight,
+                              int* fullWidth, int* fullHeight)
+{
+    RECT rect = { 0, 0, clientWidth, clientHeight };
+    AdjustWindowRectEx(&rect, style, FALSE, exStyle);
+    *fullWidth = rect.right - rect.left;
+    *fullHeight = rect.bottom - rect.top;
+}
+
+// Enforce the client rect aspect ratio based on which edge is being dragged
+//
+static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area)
+{
+    int xoff, yoff;
+    const float ratio = (float) window->numer / (float) window->denom;
+
+    getFullWindowSize(getWindowStyle(window), getWindowExStyle(window),
+                      0, 0, &xoff, &yoff);
+
+    if (edge == WMSZ_LEFT  || edge == WMSZ_BOTTOMLEFT ||
+        edge == WMSZ_RIGHT || edge == WMSZ_BOTTOMRIGHT)
+    {
+        area->bottom = area->top + yoff +
+            (int) ((area->right - area->left - xoff) / ratio);
+    }
+    else if (edge == WMSZ_TOPLEFT || edge == WMSZ_TOPRIGHT)
+    {
+        area->top = area->bottom - yoff -
+            (int) ((area->right - area->left - xoff) / ratio);
+    }
+    else if (edge == WMSZ_TOP || edge == WMSZ_BOTTOM)
+    {
+        area->right = area->left + xoff +
+            (int) ((area->bottom - area->top - yoff) * ratio);
+    }
+}
+
+// Centers the cursor over the window client area
+//
+static void centerCursor(_GLFWwindow* window)
+{
+    int width, height;
+    _glfwPlatformGetWindowSize(window, &width, &height);
+    _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0);
+}
+
+// Returns whether the cursor is in the client area of the specified window
+//
+static GLFWbool cursorInClientArea(_GLFWwindow* window)
+{
+    RECT area;
+    POINT pos;
+
+    if (!GetCursorPos(&pos))
+        return GLFW_FALSE;
+
+    if (WindowFromPoint(pos) != window->win32.handle)
+        return GLFW_FALSE;
+
+    GetClientRect(window->win32.handle, &area);
+    ClientToScreen(window->win32.handle, (POINT*) &area.left);
+    ClientToScreen(window->win32.handle, (POINT*) &area.right);
+
+    return PtInRect(&area, pos);
+}
+
+// Updates the cursor image according to its cursor mode
+//
+static void updateCursorImage(_GLFWwindow* window)
+{
+    if (window->cursorMode == GLFW_CURSOR_NORMAL)
+    {
+        if (window->cursor)
+            SetCursor(window->cursor->win32.handle);
+        else
+            SetCursor(LoadCursorW(NULL, IDC_ARROW));
+    }
+    else
+        SetCursor(NULL);
+}
+
+// Updates the cursor clip rect
+//
+static void updateClipRect(_GLFWwindow* window)
+{
+    if (window)
+    {
+        RECT clipRect;
+        GetClientRect(window->win32.handle, &clipRect);
+        ClientToScreen(window->win32.handle, (POINT*) &clipRect.left);
+        ClientToScreen(window->win32.handle, (POINT*) &clipRect.right);
+        ClipCursor(&clipRect);
+    }
+    else
+        ClipCursor(NULL);
+}
+
+// Translates a GLFW standard cursor to a resource ID
+//
+static LPWSTR translateCursorShape(int shape)
+{
+    switch (shape)
+    {
+        case GLFW_ARROW_CURSOR:
+            return IDC_ARROW;
+        case GLFW_IBEAM_CURSOR:
+            return IDC_IBEAM;
+        case GLFW_CROSSHAIR_CURSOR:
+            return IDC_CROSS;
+        case GLFW_HAND_CURSOR:
+            return IDC_HAND;
+        case GLFW_HRESIZE_CURSOR:
+            return IDC_SIZEWE;
+        case GLFW_VRESIZE_CURSOR:
+            return IDC_SIZENS;
+    }
+
+    return NULL;
+}
+
+// Retrieves and translates modifier keys
+//
+static int getKeyMods(void)
+{
+    int mods = 0;
+
+    if (GetKeyState(VK_SHIFT) & (1 << 31))
+        mods |= GLFW_MOD_SHIFT;
+    if (GetKeyState(VK_CONTROL) & (1 << 31))
+        mods |= GLFW_MOD_CONTROL;
+    if (GetKeyState(VK_MENU) & (1 << 31))
+        mods |= GLFW_MOD_ALT;
+    if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & (1 << 31))
+        mods |= GLFW_MOD_SUPER;
+
+    return mods;
+}
+
+// Retrieves and translates modifier keys
+//
+static int getAsyncKeyMods(void)
+{
+    int mods = 0;
+
+    if (GetAsyncKeyState(VK_SHIFT) & (1 << 31))
+        mods |= GLFW_MOD_SHIFT;
+    if (GetAsyncKeyState(VK_CONTROL) & (1 << 31))
+        mods |= GLFW_MOD_CONTROL;
+    if (GetAsyncKeyState(VK_MENU) & (1 << 31))
+        mods |= GLFW_MOD_ALT;
+    if ((GetAsyncKeyState(VK_LWIN) | GetAsyncKeyState(VK_RWIN)) & (1 << 31))
+        mods |= GLFW_MOD_SUPER;
+
+    return mods;
+}
+
+// Translates a Windows key to the corresponding GLFW key
+//
+static int translateKey(WPARAM wParam, LPARAM lParam)
+{
+    if (wParam == VK_CONTROL)
+    {
+        // The CTRL keys require special handling
+
+        MSG next;
+        DWORD time;
+
+        // Is this an extended key (i.e. right key)?
+        if (lParam & 0x01000000)
+            return GLFW_KEY_RIGHT_CONTROL;
+
+        // Here is a trick: "Alt Gr" sends LCTRL, then RALT. We only
+        // want the RALT message, so we try to see if the next message
+        // is a RALT message. In that case, this is a false LCTRL!
+        time = GetMessageTime();
+
+        if (PeekMessageW(&next, NULL, 0, 0, PM_NOREMOVE))
+        {
+            if (next.message == WM_KEYDOWN ||
+                next.message == WM_SYSKEYDOWN ||
+                next.message == WM_KEYUP ||
+                next.message == WM_SYSKEYUP)
+            {
+                if (next.wParam == VK_MENU &&
+                    (next.lParam & 0x01000000) &&
+                    next.time == time)
+                {
+                    // Next message is a RALT down message, which
+                    // means that this is not a proper LCTRL message
+                    return _GLFW_KEY_INVALID;
+                }
+            }
+        }
+
+        return GLFW_KEY_LEFT_CONTROL;
+    }
+
+    if (wParam == VK_PROCESSKEY)
+    {
+        // IME notifies that keys have been filtered by setting the virtual
+        // key-code to VK_PROCESSKEY
+        return _GLFW_KEY_INVALID;
+    }
+
+    return _glfw.win32.publicKeys[HIWORD(lParam) & 0x1FF];
+}
+
+// Make the specified window and its video mode active on its monitor
+//
+static GLFWbool acquireMonitor(_GLFWwindow* window)
+{
+    GLFWvidmode mode;
+    GLFWbool status;
+    int xpos, ypos;
+
+    status = _glfwSetVideoModeWin32(window->monitor, &window->videoMode);
+
+    _glfwPlatformGetVideoMode(window->monitor, &mode);
+    _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos);
+
+    SetWindowPos(window->win32.handle, HWND_TOPMOST,
+                 xpos, ypos, mode.width, mode.height,
+                 SWP_NOACTIVATE | SWP_NOCOPYBITS);
+
+    _glfwInputMonitorWindowChange(window->monitor, window);
+    return status;
+}
+
+// Remove the window and restore the original video mode
+//
+static void releaseMonitor(_GLFWwindow* window)
+{
+    if (window->monitor->window != window)
+        return;
+
+    _glfwInputMonitorWindowChange(window->monitor, NULL);
+    _glfwRestoreVideoModeWin32(window->monitor);
+}
+
+// Window callback function (handles window messages)
+//
+static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
+                                   WPARAM wParam, LPARAM lParam)
+{
+    _GLFWwindow* window = GetPropW(hWnd, L"GLFW");
+    if (!window)
+    {
+        // This is the message handling for the hidden helper window
+
+        switch (uMsg)
+        {
+            case WM_DEVICECHANGE:
+            {
+                if (wParam == DBT_DEVNODES_CHANGED)
+                {
+                    _glfwInputMonitorChange();
+                    return TRUE;
+                }
+                else if (wParam == DBT_DEVICEARRIVAL)
+                {
+                    DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*) lParam;
+                    if (dbh)
+                    {
+                        if (dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
+                            _glfwDetectJoystickConnectionWin32();
+                    }
+                }
+                else if (wParam == DBT_DEVICEREMOVECOMPLETE)
+                {
+                    DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*) lParam;
+                    if (dbh)
+                    {
+                        if (dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
+                            _glfwDetectJoystickDisconnectionWin32();
+                    }
+                }
+
+                break;
+            }
+        }
+
+        return DefWindowProcW(hWnd, uMsg, wParam, lParam);
+    }
+
+    switch (uMsg)
+    {
+        case WM_SETFOCUS:
+        {
+            _glfwInputWindowFocus(window, GLFW_TRUE);
+
+            if (window->cursorMode == GLFW_CURSOR_DISABLED)
+                _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED);
+
+            return 0;
+        }
+
+        case WM_KILLFOCUS:
+        {
+            if (window->cursorMode == GLFW_CURSOR_DISABLED)
+                _glfwPlatformSetCursorMode(window, GLFW_CURSOR_NORMAL);
+
+            if (window->monitor && window->autoIconify)
+                _glfwPlatformIconifyWindow(window);
+
+            _glfwInputWindowFocus(window, GLFW_FALSE);
+            return 0;
+        }
+
+        case WM_SYSCOMMAND:
+        {
+            switch (wParam & 0xfff0)
+            {
+                case SC_SCREENSAVE:
+                case SC_MONITORPOWER:
+                {
+                    if (window->monitor)
+                    {
+                        // We are running in full screen mode, so disallow
+                        // screen saver and screen blanking
+                        return 0;
+                    }
+                    else
+                        break;
+                }
+
+                // User trying to access application menu using ALT?
+                case SC_KEYMENU:
+                    return 0;
+            }
+            break;
+        }
+
+        case WM_CLOSE:
+        {
+            _glfwInputWindowCloseRequest(window);
+            return 0;
+        }
+
+        case WM_CHAR:
+        case WM_SYSCHAR:
+        case WM_UNICHAR:
+        {
+            const GLFWbool plain = (uMsg != WM_SYSCHAR);
+
+            if (uMsg == WM_UNICHAR && wParam == UNICODE_NOCHAR)
+            {
+                // WM_UNICHAR is not sent by Windows, but is sent by some
+                // third-party input method engine
+                // Returning TRUE here announces support for this message
+                return TRUE;
+            }
+
+            _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), plain);
+            return 0;
+        }
+
+        case WM_KEYDOWN:
+        case WM_SYSKEYDOWN:
+        case WM_KEYUP:
+        case WM_SYSKEYUP:
+        {
+            const int key = translateKey(wParam, lParam);
+            const int scancode = (lParam >> 16) & 0x1ff;
+            const int action = ((lParam >> 31) & 1) ? GLFW_RELEASE : GLFW_PRESS;
+            const int mods = getKeyMods();
+
+            if (key == _GLFW_KEY_INVALID)
+                break;
+
+            if (action == GLFW_RELEASE && wParam == VK_SHIFT)
+            {
+                // Release both Shift keys on Shift up event, as only one event
+                // is sent even if both keys are released
+                _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, scancode, action, mods);
+                _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, scancode, action, mods);
+            }
+            else if (wParam == VK_SNAPSHOT)
+            {
+                // Key down is not reported for the Print Screen key
+                _glfwInputKey(window, key, scancode, GLFW_PRESS, mods);
+                _glfwInputKey(window, key, scancode, GLFW_RELEASE, mods);
+            }
+            else
+                _glfwInputKey(window, key, scancode, action, mods);
+
+            break;
+        }
+
+        case WM_LBUTTONDOWN:
+        case WM_RBUTTONDOWN:
+        case WM_MBUTTONDOWN:
+        case WM_XBUTTONDOWN:
+        case WM_LBUTTONUP:
+        case WM_RBUTTONUP:
+        case WM_MBUTTONUP:
+        case WM_XBUTTONUP:
+        {
+            int button, action;
+
+            if (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONUP)
+                button = GLFW_MOUSE_BUTTON_LEFT;
+            else if (uMsg == WM_RBUTTONDOWN || uMsg == WM_RBUTTONUP)
+                button = GLFW_MOUSE_BUTTON_RIGHT;
+            else if (uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONUP)
+                button = GLFW_MOUSE_BUTTON_MIDDLE;
+            else if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1)
+                button = GLFW_MOUSE_BUTTON_4;
+            else
+                button = GLFW_MOUSE_BUTTON_5;
+
+            if (uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN ||
+                uMsg == WM_MBUTTONDOWN || uMsg == WM_XBUTTONDOWN)
+            {
+                action = GLFW_PRESS;
+                SetCapture(hWnd);
+            }
+            else
+            {
+                action = GLFW_RELEASE;
+                ReleaseCapture();
+            }
+
+            _glfwInputMouseClick(window, button, action, getKeyMods());
+
+            if (uMsg == WM_XBUTTONDOWN || uMsg == WM_XBUTTONUP)
+                return TRUE;
+
+            return 0;
+        }
+
+        case WM_MOUSEMOVE:
+        {
+            const int x = GET_X_LPARAM(lParam);
+            const int y = GET_Y_LPARAM(lParam);
+
+            if (window->cursorMode == GLFW_CURSOR_DISABLED)
+            {
+                const int dx = x - window->win32.lastCursorPosX;
+                const int dy = y - window->win32.lastCursorPosY;
+
+                if (_glfw.win32.disabledCursorWindow != window)
+                    break;
+
+                _glfwInputCursorPos(window,
+                                    window->virtualCursorPosX + dx,
+                                    window->virtualCursorPosY + dy);
+            }
+            else
+                _glfwInputCursorPos(window, x, y);
+
+            window->win32.lastCursorPosX = x;
+            window->win32.lastCursorPosY = y;
+
+            if (!window->win32.cursorTracked)
+            {
+                TRACKMOUSEEVENT tme;
+                ZeroMemory(&tme, sizeof(tme));
+                tme.cbSize = sizeof(tme);
+                tme.dwFlags = TME_LEAVE;
+                tme.hwndTrack = window->win32.handle;
+                TrackMouseEvent(&tme);
+
+                window->win32.cursorTracked = GLFW_TRUE;
+                _glfwInputCursorEnter(window, GLFW_TRUE);
+            }
+
+            return 0;
+        }
+
+        case WM_MOUSELEAVE:
+        {
+            window->win32.cursorTracked = GLFW_FALSE;
+            _glfwInputCursorEnter(window, GLFW_FALSE);
+            return 0;
+        }
+
+        case WM_MOUSEWHEEL:
+        {
+            _glfwInputScroll(window, 0.0, (SHORT) HIWORD(wParam) / (double) WHEEL_DELTA);
+            return 0;
+        }
+
+        case WM_MOUSEHWHEEL:
+        {
+            // This message is only sent on Windows Vista and later
+            // NOTE: The X-axis is inverted for consistency with OS X and X11.
+            _glfwInputScroll(window, -((SHORT) HIWORD(wParam) / (double) WHEEL_DELTA), 0.0);
+            return 0;
+        }
+
+        case WM_ENTERSIZEMOVE:
+        case WM_ENTERMENULOOP:
+        {
+            if (window->cursorMode == GLFW_CURSOR_DISABLED)
+                _glfwPlatformSetCursorMode(window, GLFW_CURSOR_NORMAL);
+
+            break;
+        }
+
+        case WM_EXITSIZEMOVE:
+        case WM_EXITMENULOOP:
+        {
+            if (window->cursorMode == GLFW_CURSOR_DISABLED)
+                _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED);
+
+            break;
+        }
+
+        case WM_SIZE:
+        {
+            const GLFWbool iconified =
+                !window->win32.iconified && wParam == SIZE_MINIMIZED;
+            const GLFWbool restored =
+                window->win32.iconified &&
+                (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED);
+
+            if (_glfw.win32.disabledCursorWindow == window)
+                updateClipRect(window);
+
+            if (iconified)
+                _glfwInputWindowIconify(window, GLFW_TRUE);
+            else if (restored)
+                _glfwInputWindowIconify(window, GLFW_FALSE);
+
+            _glfwInputFramebufferSize(window, LOWORD(lParam), HIWORD(lParam));
+            _glfwInputWindowSize(window, LOWORD(lParam), HIWORD(lParam));
+
+            if (iconified)
+            {
+                window->win32.iconified = GLFW_TRUE;
+                if (window->monitor)
+                    releaseMonitor(window);
+            }
+            else if (restored)
+            {
+                window->win32.iconified = GLFW_FALSE;
+                if (window->monitor)
+                    acquireMonitor(window);
+            }
+
+            return 0;
+        }
+
+        case WM_MOVE:
+        {
+            if (_glfw.win32.disabledCursorWindow == window)
+                updateClipRect(window);
+
+            // NOTE: This cannot use LOWORD/HIWORD recommended by MSDN, as
+            // those macros do not handle negative window positions correctly
+            _glfwInputWindowPos(window,
+                                GET_X_LPARAM(lParam),
+                                GET_Y_LPARAM(lParam));
+            return 0;
+        }
+
+        case WM_SIZING:
+        {
+            if (window->numer == GLFW_DONT_CARE ||
+                window->denom == GLFW_DONT_CARE)
+            {
+                break;
+            }
+
+            applyAspectRatio(window, (int) wParam, (RECT*) lParam);
+            return TRUE;
+        }
+
+        case WM_GETMINMAXINFO:
+        {
+            int xoff, yoff;
+            MINMAXINFO* mmi = (MINMAXINFO*) lParam;
+
+            if (window->monitor)
+                break;
+
+            getFullWindowSize(getWindowStyle(window), getWindowExStyle(window),
+                              0, 0, &xoff, &yoff);
+
+            if (window->minwidth != GLFW_DONT_CARE &&
+                window->minheight != GLFW_DONT_CARE)
+            {
+                mmi->ptMinTrackSize.x = window->minwidth + xoff;
+                mmi->ptMinTrackSize.y = window->minheight + yoff;
+            }
+
+            if (window->maxwidth != GLFW_DONT_CARE &&
+                window->maxheight != GLFW_DONT_CARE)
+            {
+                mmi->ptMaxTrackSize.x = window->maxwidth + xoff;
+                mmi->ptMaxTrackSize.y = window->maxheight + yoff;
+            }
+
+            return 0;
+        }
+
+        case WM_PAINT:
+        {
+            _glfwInputWindowDamage(window);
+            break;
+        }
+
+        case WM_ERASEBKGND:
+        {
+            return TRUE;
+        }
+
+        case WM_SETCURSOR:
+        {
+            if (LOWORD(lParam) == HTCLIENT)
+            {
+                updateCursorImage(window);
+                return TRUE;
+            }
+
+            break;
+        }
+
+        case WM_DPICHANGED:
+        {
+            RECT* rect = (RECT*) lParam;
+            SetWindowPos(window->win32.handle,
+                         HWND_TOP,
+                         rect->left,
+                         rect->top,
+                         rect->right - rect->left,
+                         rect->bottom - rect->top,
+                         SWP_NOACTIVATE | SWP_NOZORDER);
+            break;
+        }
+
+        case WM_DROPFILES:
+        {
+            HDROP drop = (HDROP) wParam;
+            POINT pt;
+            int i;
+
+            const int count = DragQueryFileW(drop, 0xffffffff, NULL, 0);
+            char** paths = calloc(count, sizeof(char*));
+
+            // Move the mouse to the position of the drop
+            DragQueryPoint(drop, &pt);
+            _glfwInputCursorPos(window, pt.x, pt.y);
+
+            for (i = 0;  i < count;  i++)
+            {
+                const UINT length = DragQueryFileW(drop, i, NULL, 0);
+                WCHAR* buffer = calloc(length + 1, sizeof(WCHAR));
+
+                DragQueryFileW(drop, i, buffer, length + 1);
+                paths[i] = _glfwCreateUTF8FromWideStringWin32(buffer);
+
+                free(buffer);
+            }
+
+            _glfwInputDrop(window, count, (const char**) paths);
+
+            for (i = 0;  i < count;  i++)
+                free(paths[i]);
+            free(paths);
+
+            DragFinish(drop);
+            return 0;
+        }
+    }
+
+    return DefWindowProcW(hWnd, uMsg, wParam, lParam);
+}
+
+// Creates the GLFW window
+//
+static int createNativeWindow(_GLFWwindow* window,
+                              const _GLFWwndconfig* wndconfig)
+{
+    int xpos, ypos, fullWidth, fullHeight;
+    WCHAR* wideTitle;
+    DWORD style = getWindowStyle(window);
+    DWORD exStyle = getWindowExStyle(window);
+
+    if (window->monitor)
+    {
+        GLFWvidmode mode;
+
+        // NOTE: This window placement is temporary and approximate, as the
+        //       correct position and size cannot be known until the monitor
+        //       video mode has been set
+        _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos);
+        _glfwPlatformGetVideoMode(window->monitor, &mode);
+        fullWidth  = mode.width;
+        fullHeight = mode.height;
+    }
+    else
+    {
+        xpos = CW_USEDEFAULT;
+        ypos = CW_USEDEFAULT;
+
+        if (wndconfig->maximized)
+            style |= WS_MAXIMIZE;
+
+        getFullWindowSize(style, exStyle,
+                          wndconfig->width, wndconfig->height,
+                          &fullWidth, &fullHeight);
+    }
+
+    wideTitle = _glfwCreateWideStringFromUTF8Win32(wndconfig->title);
+    if (!wideTitle)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Win32: Failed to convert window title to UTF-16");
+        return GLFW_FALSE;
+    }
+
+    window->win32.handle = CreateWindowExW(exStyle,
+                                           _GLFW_WNDCLASSNAME,
+                                           wideTitle,
+                                           style,
+                                           xpos, ypos,
+                                           fullWidth, fullHeight,
+                                           NULL, // No parent window
+                                           NULL, // No window menu
+                                           GetModuleHandleW(NULL),
+                                           NULL);
+
+    free(wideTitle);
+
+    if (!window->win32.handle)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create window");
+        return GLFW_FALSE;
+    }
+
+    SetPropW(window->win32.handle, L"GLFW", window);
+
+    if (_glfw_ChangeWindowMessageFilterEx)
+    {
+        _glfw_ChangeWindowMessageFilterEx(window->win32.handle,
+                                          WM_DROPFILES, MSGFLT_ALLOW, NULL);
+        _glfw_ChangeWindowMessageFilterEx(window->win32.handle,
+                                          WM_COPYDATA, MSGFLT_ALLOW, NULL);
+        _glfw_ChangeWindowMessageFilterEx(window->win32.handle,
+                                          WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL);
+    }
+
+    DragAcceptFiles(window->win32.handle, TRUE);
+
+    return GLFW_TRUE;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                       GLFW internal API                      //////
+//////////////////////////////////////////////////////////////////////////
+
+// Registers the GLFW window class
+//
+GLFWbool _glfwRegisterWindowClassWin32(void)
+{
+    WNDCLASSEXW wc;
+
+    ZeroMemory(&wc, sizeof(wc));
+    wc.cbSize        = sizeof(wc);
+    wc.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
+    wc.lpfnWndProc   = (WNDPROC) windowProc;
+    wc.hInstance     = GetModuleHandleW(NULL);
+    wc.hCursor       = LoadCursorW(NULL, IDC_ARROW);
+    wc.lpszClassName = _GLFW_WNDCLASSNAME;
+
+    // Load user-provided icon if available
+    wc.hIcon = LoadImageW(GetModuleHandleW(NULL),
+                          L"GLFW_ICON", IMAGE_ICON,
+                          0, 0, LR_DEFAULTSIZE | LR_SHARED);
+    if (!wc.hIcon)
+    {
+        // No user-provided icon found, load default icon
+        wc.hIcon = LoadImageW(NULL,
+                              IDI_APPLICATION, IMAGE_ICON,
+                              0, 0, LR_DEFAULTSIZE | LR_SHARED);
+    }
+
+    if (!RegisterClassExW(&wc))
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Win32: Failed to register window class");
+        return GLFW_FALSE;
+    }
+
+    return GLFW_TRUE;
+}
+
+// Unregisters the GLFW window class
+//
+void _glfwUnregisterWindowClassWin32(void)
+{
+    UnregisterClassW(_GLFW_WNDCLASSNAME, GetModuleHandleW(NULL));
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                       GLFW platform API                      //////
+//////////////////////////////////////////////////////////////////////////
+
+int _glfwPlatformCreateWindow(_GLFWwindow* window,
+                              const _GLFWwndconfig* wndconfig,
+                              const _GLFWctxconfig* ctxconfig,
+                              const _GLFWfbconfig* fbconfig)
+{
+    if (!createNativeWindow(window, wndconfig))
+        return GLFW_FALSE;
+
+    if (ctxconfig->client != GLFW_NO_API)
+    {
+        if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API)
+        {
+            if (!_glfwInitWGL())
+                return GLFW_FALSE;
+            if (!_glfwCreateContextWGL(window, ctxconfig, fbconfig))
+                return GLFW_FALSE;
+        }
+        else
+        {
+            if (!_glfwInitEGL())
+                return GLFW_FALSE;
+            if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
+                return GLFW_FALSE;
+        }
+    }
+
+    if (window->monitor)
+    {
+        _glfwPlatformShowWindow(window);
+        _glfwPlatformFocusWindow(window);
+        if (!acquireMonitor(window))
+            return GLFW_FALSE;
+
+        centerCursor(window);
+    }
+
+    return GLFW_TRUE;
+}
+
+void _glfwPlatformDestroyWindow(_GLFWwindow* window)
+{
+    if (window->monitor)
+        releaseMonitor(window);
+
+    if (window->context.destroy)
+        window->context.destroy(window);
+
+    if (_glfw.win32.disabledCursorWindow == window)
+        _glfw.win32.disabledCursorWindow = NULL;
+
+    if (window->win32.handle)
+    {
+        RemovePropW(window->win32.handle, L"GLFW");
+        DestroyWindow(window->win32.handle);
+        window->win32.handle = NULL;
+    }
+
+    if (window->win32.bigIcon)
+        DestroyIcon(window->win32.bigIcon);
+
+    if (window->win32.smallIcon)
+        DestroyIcon(window->win32.smallIcon);
+}
+
+void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
+{
+    WCHAR* wideTitle = _glfwCreateWideStringFromUTF8Win32(title);
+    if (!wideTitle)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Win32: Failed to convert window title to UTF-16");
+        return;
+    }
+
+    SetWindowTextW(window->win32.handle, wideTitle);
+    free(wideTitle);
+}
+
+void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
+                                int count, const GLFWimage* images)
+{
+    HICON bigIcon = NULL, smallIcon = NULL;
+
+    if (count)
+    {
+        const GLFWimage* bigImage = chooseImage(count, images,
+                                                GetSystemMetrics(SM_CXICON),
+                                                GetSystemMetrics(SM_CYICON));
+        const GLFWimage* smallImage = chooseImage(count, images,
+                                                  GetSystemMetrics(SM_CXSMICON),
+                                                  GetSystemMetrics(SM_CYSMICON));
+
+        bigIcon = createIcon(bigImage, 0, 0, GLFW_TRUE);
+        smallIcon = createIcon(smallImage, 0, 0, GLFW_TRUE);
+    }
+    else
+    {
+        bigIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICON);
+        smallIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICONSM);
+    }
+
+    SendMessage(window->win32.handle, WM_SETICON, ICON_BIG, (LPARAM) bigIcon);
+    SendMessage(window->win32.handle, WM_SETICON, ICON_SMALL, (LPARAM) smallIcon);
+
+    if (window->win32.bigIcon)
+        DestroyIcon(window->win32.bigIcon);
+
+    if (window->win32.smallIcon)
+        DestroyIcon(window->win32.smallIcon);
+
+    if (count)
+    {
+        window->win32.bigIcon = bigIcon;
+        window->win32.smallIcon = smallIcon;
+    }
+}
+
+void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
+{
+    POINT pos = { 0, 0 };
+    ClientToScreen(window->win32.handle, &pos);
+
+    if (xpos)
+        *xpos = pos.x;
+    if (ypos)
+        *ypos = pos.y;
+}
+
+void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
+{
+    RECT rect = { xpos, ypos, xpos, ypos };
+    AdjustWindowRectEx(&rect, getWindowStyle(window),
+                       FALSE, getWindowExStyle(window));
+    SetWindowPos(window->win32.handle, NULL, rect.left, rect.top, 0, 0,
+                 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
+}
+
+void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
+{
+    RECT area;
+    GetClientRect(window->win32.handle, &area);
+
+    if (width)
+        *width = area.right;
+    if (height)
+        *height = area.bottom;
+}
+
+void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
+{
+    if (window->monitor)
+    {
+        if (window->monitor->window == window)
+            acquireMonitor(window);
+    }
+    else
+    {
+        RECT rect = { 0, 0, width, height };
+        AdjustWindowRectEx(&rect, getWindowStyle(window),
+                           FALSE, getWindowExStyle(window));
+        SetWindowPos(window->win32.handle, HWND_TOP,
+                     0, 0, rect.right - rect.left, rect.bottom - rect.top,
+                     SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER);
+    }
+}
+
+void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
+                                      int minwidth, int minheight,
+                                      int maxwidth, int maxheight)
+{
+    RECT area;
+
+    if ((minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE) &&
+        (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE))
+    {
+        return;
+    }
+
+    GetWindowRect(window->win32.handle, &area);
+    MoveWindow(window->win32.handle,
+               area.left, area.top,
+               area.right - area.left,
+               area.bottom - area.top, TRUE);
+}
+
+void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom)
+{
+    RECT area;
+
+    if (numer == GLFW_DONT_CARE || denom == GLFW_DONT_CARE)
+        return;
+
+    GetWindowRect(window->win32.handle, &area);
+    applyAspectRatio(window, WMSZ_BOTTOMRIGHT, &area);
+    MoveWindow(window->win32.handle,
+               area.left, area.top,
+               area.right - area.left,
+               area.bottom - area.top, TRUE);
+}
+
+void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height)
+{
+    _glfwPlatformGetWindowSize(window, width, height);
+}
+
+void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
+                                     int* left, int* top,
+                                     int* right, int* bottom)
+{
+    RECT rect;
+    int width, height;
+
+    _glfwPlatformGetWindowSize(window, &width, &height);
+    SetRect(&rect, 0, 0, width, height);
+    AdjustWindowRectEx(&rect, getWindowStyle(window),
+                       FALSE, getWindowExStyle(window));
+
+    if (left)
+        *left = -rect.left;
+    if (top)
+        *top = -rect.top;
+    if (right)
+        *right = rect.right - width;
+    if (bottom)
+        *bottom = rect.bottom - height;
+}
+
+void _glfwPlatformIconifyWindow(_GLFWwindow* window)
+{
+    ShowWindow(window->win32.handle, SW_MINIMIZE);
+}
+
+void _glfwPlatformRestoreWindow(_GLFWwindow* window)
+{
+    ShowWindow(window->win32.handle, SW_RESTORE);
+}
+
+void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
+{
+    ShowWindow(window->win32.handle, SW_MAXIMIZE);
+}
+
+void _glfwPlatformShowWindow(_GLFWwindow* window)
+{
+    ShowWindow(window->win32.handle, SW_SHOW);
+}
+
+void _glfwPlatformHideWindow(_GLFWwindow* window)
+{
+    ShowWindow(window->win32.handle, SW_HIDE);
+}
+
+void _glfwPlatformFocusWindow(_GLFWwindow* window)
+{
+    BringWindowToTop(window->win32.handle);
+    SetForegroundWindow(window->win32.handle);
+    SetFocus(window->win32.handle);
+}
+
+void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
+                                   _GLFWmonitor* monitor,
+                                   int xpos, int ypos,
+                                   int width, int height,
+                                   int refreshRate)
+{
+    if (window->monitor == monitor)
+    {
+        if (monitor)
+        {
+            if (monitor->window == window)
+                acquireMonitor(window);
+        }
+        else
+        {
+            RECT rect = { xpos, ypos, xpos + width, ypos + height };
+            AdjustWindowRectEx(&rect, getWindowStyle(window),
+                               FALSE, getWindowExStyle(window));
+            SetWindowPos(window->win32.handle, HWND_TOP,
+                         rect.left, rect.top,
+                         rect.right - rect.left, rect.bottom - rect.top,
+                         SWP_NOCOPYBITS | SWP_NOACTIVATE | SWP_NOZORDER);
+        }
+
+        return;
+    }
+
+    if (window->monitor)
+        releaseMonitor(window);
+
+    _glfwInputWindowMonitorChange(window, monitor);
+
+    if (monitor)
+    {
+        GLFWvidmode mode;
+        DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE);
+        UINT flags = SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOCOPYBITS;
+
+        if (window->decorated)
+        {
+            style &= ~WS_OVERLAPPEDWINDOW;
+            style |= getWindowStyle(window);
+            SetWindowLongW(window->win32.handle, GWL_STYLE, style);
+
+            flags |= SWP_FRAMECHANGED;
+        }
+
+        _glfwPlatformGetVideoMode(monitor, &mode);
+        _glfwPlatformGetMonitorPos(monitor, &xpos, &ypos);
+
+        SetWindowPos(window->win32.handle, HWND_TOPMOST,
+                     xpos, ypos, mode.width, mode.height,
+                     flags);
+
+        acquireMonitor(window);
+    }
+    else
+    {
+        HWND after;
+        RECT rect = { xpos, ypos, xpos + width, ypos + height };
+        DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE);
+        UINT flags = SWP_NOACTIVATE | SWP_NOCOPYBITS;
+
+        if (window->decorated)
+        {
+            style &= ~WS_POPUP;
+            style |= getWindowStyle(window);
+            SetWindowLongW(window->win32.handle, GWL_STYLE, style);
+
+            flags |= SWP_FRAMECHANGED;
+        }
+
+        if (window->floating)
+            after = HWND_TOPMOST;
+        else
+            after = HWND_NOTOPMOST;
+
+        AdjustWindowRectEx(&rect, getWindowStyle(window),
+                           FALSE, getWindowExStyle(window));
+        SetWindowPos(window->win32.handle, after,
+                     rect.left, rect.top,
+                     rect.right - rect.left, rect.bottom - rect.top,
+                     flags);
+    }
+}
+
+int _glfwPlatformWindowFocused(_GLFWwindow* window)
+{
+    return window->win32.handle == GetActiveWindow();
+}
+
+int _glfwPlatformWindowIconified(_GLFWwindow* window)
+{
+    return IsIconic(window->win32.handle);
+}
+
+int _glfwPlatformWindowVisible(_GLFWwindow* window)
+{
+    return IsWindowVisible(window->win32.handle);
+}
+
+int _glfwPlatformWindowMaximized(_GLFWwindow* window)
+{
+    return IsZoomed(window->win32.handle);
+}
+
+void _glfwPlatformPollEvents(void)
+{
+    MSG msg;
+    HWND handle;
+    _GLFWwindow* window;
+
+    while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
+    {
+        if (msg.message == WM_QUIT)
+        {
+            // Treat WM_QUIT as a close on all windows
+            // While GLFW does not itself post WM_QUIT, other processes may post
+            // it to this one, for example Task Manager
+
+            window = _glfw.windowListHead;
+            while (window)
+            {
+                _glfwInputWindowCloseRequest(window);
+                window = window->next;
+            }
+        }
+        else
+        {
+            TranslateMessage(&msg);
+            DispatchMessageW(&msg);
+        }
+    }
+
+    handle = GetActiveWindow();
+    if (handle)
+    {
+        // LSHIFT/RSHIFT fixup (keys tend to "stick" without this fix)
+        // This is the only async event handling in GLFW, but it solves some
+        // nasty problems
+        window = GetPropW(handle, L"GLFW");
+        if (window)
+        {
+            const int mods = getAsyncKeyMods();
+
+            // Get current state of left and right shift keys
+            const int lshiftDown = (GetAsyncKeyState(VK_LSHIFT) >> 15) & 1;
+            const int rshiftDown = (GetAsyncKeyState(VK_RSHIFT) >> 15) & 1;
+
+            // See if this differs from our belief of what has happened
+            // (we only have to check for lost key up events)
+            if (!lshiftDown && window->keys[GLFW_KEY_LEFT_SHIFT] == 1)
+                _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, 0, GLFW_RELEASE, mods);
+
+            if (!rshiftDown && window->keys[GLFW_KEY_RIGHT_SHIFT] == 1)
+                _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, 0, GLFW_RELEASE, mods);
+        }
+    }
+
+    window = _glfw.win32.disabledCursorWindow;
+    if (window)
+    {
+        int width, height;
+        _glfwPlatformGetWindowSize(window, &width, &height);
+
+        // NOTE: Re-center the cursor only if it has moved since the last call,
+        //       to avoid breaking glfwWaitEvents with WM_MOUSEMOVE
+        if (window->win32.lastCursorPosX != width / 2 ||
+            window->win32.lastCursorPosY != height / 2)
+        {
+            _glfwPlatformSetCursorPos(window, width / 2, height / 2);
+        }
+    }
+}
+
+void _glfwPlatformWaitEvents(void)
+{
+    WaitMessage();
+
+    _glfwPlatformPollEvents();
+}
+
+void _glfwPlatformWaitEventsTimeout(double timeout)
+{
+    MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD) (timeout * 1e3), QS_ALLEVENTS);
+
+    _glfwPlatformPollEvents();
+}
+
+void _glfwPlatformPostEmptyEvent(void)
+{
+    _GLFWwindow* window = _glfw.windowListHead;
+    PostMessage(window->win32.handle, WM_NULL, 0, 0);
+}
+
+void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
+{
+    POINT pos;
+
+    if (GetCursorPos(&pos))
+    {
+        ScreenToClient(window->win32.handle, &pos);
+
+        if (xpos)
+            *xpos = pos.x;
+        if (ypos)
+            *ypos = pos.y;
+    }
+}
+
+void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos)
+{
+    POINT pos = { (int) xpos, (int) ypos };
+
+    // Store the new position so it can be recognized later
+    window->win32.lastCursorPosX = pos.x;
+    window->win32.lastCursorPosY = pos.y;
+
+    ClientToScreen(window->win32.handle, &pos);
+    SetCursorPos(pos.x, pos.y);
+}
+
+void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
+{
+    if (mode == GLFW_CURSOR_DISABLED)
+    {
+        _glfw.win32.disabledCursorWindow = window;
+        _glfwPlatformGetCursorPos(window,
+                                  &_glfw.win32.restoreCursorPosX,
+                                  &_glfw.win32.restoreCursorPosY);
+        centerCursor(window);
+        updateClipRect(window);
+    }
+    else if (_glfw.win32.disabledCursorWindow == window)
+    {
+        _glfw.win32.disabledCursorWindow = NULL;
+        updateClipRect(NULL);
+        _glfwPlatformSetCursorPos(window,
+                                  _glfw.win32.restoreCursorPosX,
+                                  _glfw.win32.restoreCursorPosY);
+    }
+
+    if (cursorInClientArea(window))
+        updateCursorImage(window);
+}
+
+const char* _glfwPlatformGetKeyName(int key, int scancode)
+{
+    WCHAR name[16];
+
+    if (key != GLFW_KEY_UNKNOWN)
+        scancode = _glfw.win32.nativeKeys[key];
+
+    if (!_glfwIsPrintable(_glfw.win32.publicKeys[scancode]))
+        return NULL;
+
+    if (!GetKeyNameTextW(scancode << 16, name, sizeof(name) / sizeof(WCHAR)))
+        return NULL;
+
+    if (!WideCharToMultiByte(CP_UTF8, 0, name, -1,
+                             _glfw.win32.keyName,
+                             sizeof(_glfw.win32.keyName),
+                             NULL, NULL))
+    {
+        return NULL;
+    }
+
+    return _glfw.win32.keyName;
+}
+
+int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
+                              const GLFWimage* image,
+                              int xhot, int yhot)
+{
+    cursor->win32.handle = (HCURSOR) createIcon(image, xhot, yhot, GLFW_FALSE);
+    if (!cursor->win32.handle)
+        return GLFW_FALSE;
+
+    return GLFW_TRUE;
+}
+
+int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
+{
+    cursor->win32.handle =
+        CopyCursor(LoadCursorW(NULL, translateCursorShape(shape)));
+    if (!cursor->win32.handle)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Win32: Failed to create standard cursor");
+        return GLFW_FALSE;
+    }
+
+    return GLFW_TRUE;
+}
+
+void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
+{
+    if (cursor->win32.handle)
+        DestroyIcon((HICON) cursor->win32.handle);
+}
+
+void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
+{
+    if (cursorInClientArea(window))
+        updateCursorImage(window);
+}
+
+void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
+{
+    int characterCount;
+    HANDLE object;
+    WCHAR* buffer;
+
+    characterCount = MultiByteToWideChar(CP_UTF8, 0, string, -1, NULL, 0);
+    if (!characterCount)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Win32: Failed to convert clipboard string to UTF-16");
+        return;
+    }
+
+    object = GlobalAlloc(GMEM_MOVEABLE, characterCount * sizeof(WCHAR));
+    if (!object)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Win32: Failed to allocate global handle for clipboard");
+        return;
+    }
+
+    buffer = GlobalLock(object);
+    if (!buffer)
+    {
+        GlobalFree(object);
+
+        _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to lock global handle");
+        return;
+    }
+
+    MultiByteToWideChar(CP_UTF8, 0, string, -1, buffer, characterCount);
+    GlobalUnlock(object);
+
+    if (!OpenClipboard(_glfw.win32.helperWindowHandle))
+    {
+        GlobalFree(object);
+
+        _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to open clipboard");
+        return;
+    }
+
+    EmptyClipboard();
+    SetClipboardData(CF_UNICODETEXT, object);
+    CloseClipboard();
+}
+
+const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
+{
+    HANDLE object;
+    WCHAR* buffer;
+
+    if (!OpenClipboard(_glfw.win32.helperWindowHandle))
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to open clipboard");
+        return NULL;
+    }
+
+    object = GetClipboardData(CF_UNICODETEXT);
+    if (!object)
+    {
+        CloseClipboard();
+
+        _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
+                        "Win32: Failed to convert clipboard to string");
+        return NULL;
+    }
+
+    buffer = GlobalLock(object);
+    if (!buffer)
+    {
+        CloseClipboard();
+
+        _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to lock global handle");
+        return NULL;
+    }
+
+    free(_glfw.win32.clipboardString);
+    _glfw.win32.clipboardString =
+        _glfwCreateUTF8FromWideStringWin32(buffer);
+
+    GlobalUnlock(object);
+    CloseClipboard();
+
+    if (!_glfw.win32.clipboardString)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Win32: Failed to convert wide string to UTF-8");
+        return NULL;
+    }
+
+    return _glfw.win32.clipboardString;
+}
+
+char** _glfwPlatformGetRequiredInstanceExtensions(uint32_t* count)
+{
+    char** extensions;
+
+    *count = 0;
+
+    if (!_glfw.vk.KHR_win32_surface)
+        return NULL;
+
+    extensions = calloc(2, sizeof(char*));
+    extensions[0] = strdup("VK_KHR_surface");
+    extensions[1] = strdup("VK_KHR_win32_surface");
+
+    *count = 2;
+    return extensions;
+}
+
+int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
+                                                      VkPhysicalDevice device,
+                                                      uint32_t queuefamily)
+{
+    PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR =
+        (PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)
+        vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR");
+    if (!vkGetPhysicalDeviceWin32PresentationSupportKHR)
+    {
+        _glfwInputError(GLFW_API_UNAVAILABLE,
+                        "Win32: Vulkan instance missing VK_KHR_win32_surface extension");
+        return GLFW_FALSE;
+    }
+
+    return vkGetPhysicalDeviceWin32PresentationSupportKHR(device, queuefamily);
+}
+
+VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
+                                          _GLFWwindow* window,
+                                          const VkAllocationCallbacks* allocator,
+                                          VkSurfaceKHR* surface)
+{
+    VkResult err;
+    VkWin32SurfaceCreateInfoKHR sci;
+    PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR;
+
+    vkCreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR)
+        vkGetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR");
+    if (!vkCreateWin32SurfaceKHR)
+    {
+        _glfwInputError(GLFW_API_UNAVAILABLE,
+                        "Win32: Vulkan instance missing VK_KHR_win32_surface extension");
+        return VK_ERROR_EXTENSION_NOT_PRESENT;
+    }
+
+    memset(&sci, 0, sizeof(sci));
+    sci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
+    sci.hinstance = GetModuleHandle(NULL);
+    sci.hwnd = window->win32.handle;
+
+    err = vkCreateWin32SurfaceKHR(instance, &sci, allocator, surface);
+    if (err)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Win32: Failed to create Vulkan surface: %s",
+                        _glfwGetVulkanResultString(err));
+    }
+
+    return err;
 }
 
 
diff --git a/glfw/src/window.c b/glfw/src/window.c
--- a/glfw/src/window.c
+++ b/glfw/src/window.c
@@ -1,8 +1,8 @@
 //========================================================================
-// GLFW 3.1 - www.glfw.org
+// GLFW 3.2 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
 // Copyright (c) 2012 Torsten Walluhn <tw@mad-cad.net>
 //
 // This software is provided 'as-is', without any express or implied
@@ -28,20 +28,20 @@
 
 #include "internal.h"
 
+#include <assert.h>
 #include <string.h>
 #include <stdlib.h>
+#include <float.h>
 
 
 //////////////////////////////////////////////////////////////////////////
 //////                         GLFW event API                       //////
 //////////////////////////////////////////////////////////////////////////
 
-void _glfwInputWindowFocus(_GLFWwindow* window, GLboolean focused)
+void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused)
 {
     if (focused)
     {
-        _glfw.focusedWindow = window;
-
         if (window->callbacks.focus)
             window->callbacks.focus((GLFWwindow*) window, focused);
     }
@@ -49,8 +49,6 @@
     {
         int i;
 
-        _glfw.focusedWindow = NULL;
-
         if (window->callbacks.focus)
             window->callbacks.focus((GLFWwindow*) window, focused);
 
@@ -82,7 +80,7 @@
         window->callbacks.size((GLFWwindow*) window, width, height);
 }
 
-void _glfwInputWindowIconify(_GLFWwindow* window, int iconified)
+void _glfwInputWindowIconify(_GLFWwindow* window, GLFWbool iconified)
 {
     if (window->callbacks.iconify)
         window->callbacks.iconify((GLFWwindow*) window, iconified);
@@ -102,13 +100,18 @@
 
 void _glfwInputWindowCloseRequest(_GLFWwindow* window)
 {
-    window->closed = GL_TRUE;
+    window->closed = GLFW_TRUE;
 
     if (window->callbacks.close)
         window->callbacks.close((GLFWwindow*) window);
 }
 
+void _glfwInputWindowMonitorChange(_GLFWwindow* window, _GLFWmonitor* monitor)
+{
+    window->monitor = monitor;
+}
 
+
 //////////////////////////////////////////////////////////////////////////
 //////                        GLFW public API                       //////
 //////////////////////////////////////////////////////////////////////////
@@ -124,55 +127,38 @@
     _GLFWwindow* window;
     _GLFWwindow* previous;
 
+    assert(title != NULL);
+
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
 
     if (width <= 0 || height <= 0)
     {
-        _glfwInputError(GLFW_INVALID_VALUE, "Invalid window size");
+        _glfwInputError(GLFW_INVALID_VALUE,
+                        "Invalid window size %ix%i",
+                        width, height);
+
         return NULL;
     }
 
-    // Set up desired framebuffer config
-    fbconfig.redBits        = _glfw.hints.redBits;
-    fbconfig.greenBits      = _glfw.hints.greenBits;
-    fbconfig.blueBits       = _glfw.hints.blueBits;
-    fbconfig.alphaBits      = _glfw.hints.alphaBits;
-    fbconfig.depthBits      = _glfw.hints.depthBits;
-    fbconfig.stencilBits    = _glfw.hints.stencilBits;
-    fbconfig.accumRedBits   = _glfw.hints.accumRedBits;
-    fbconfig.accumGreenBits = _glfw.hints.accumGreenBits;
-    fbconfig.accumBlueBits  = _glfw.hints.accumBlueBits;
-    fbconfig.accumAlphaBits = _glfw.hints.accumAlphaBits;
-    fbconfig.auxBuffers     = _glfw.hints.auxBuffers;
-    fbconfig.stereo         = _glfw.hints.stereo ? GL_TRUE : GL_FALSE;
-    fbconfig.samples        = _glfw.hints.samples;
-    fbconfig.sRGB           = _glfw.hints.sRGB;
-    fbconfig.doublebuffer   = _glfw.hints.doublebuffer ? GL_TRUE : GL_FALSE;
+    fbconfig  = _glfw.hints.framebuffer;
+    ctxconfig = _glfw.hints.context;
+    wndconfig = _glfw.hints.window;
 
-    // Set up desired window config
-    wndconfig.width         = width;
-    wndconfig.height        = height;
-    wndconfig.title         = title;
-    wndconfig.resizable     = _glfw.hints.resizable ? GL_TRUE : GL_FALSE;
-    wndconfig.visible       = _glfw.hints.visible ? GL_TRUE : GL_FALSE;
-    wndconfig.decorated     = _glfw.hints.decorated ? GL_TRUE : GL_FALSE;
-    wndconfig.focused       = _glfw.hints.focused ? GL_TRUE : GL_FALSE;
-    wndconfig.autoIconify   = _glfw.hints.autoIconify ? GL_TRUE : GL_FALSE;
-    wndconfig.floating      = _glfw.hints.floating ? GL_TRUE : GL_FALSE;
-    wndconfig.monitor       = (_GLFWmonitor*) monitor;
+    wndconfig.width   = width;
+    wndconfig.height  = height;
+    wndconfig.title   = title;
+    ctxconfig.share   = (_GLFWwindow*) share;
 
-    // Set up desired context config
-    ctxconfig.api           = _glfw.hints.api;
-    ctxconfig.major         = _glfw.hints.major;
-    ctxconfig.minor         = _glfw.hints.minor;
-    ctxconfig.forward       = _glfw.hints.forward ? GL_TRUE : GL_FALSE;
-    ctxconfig.debug         = _glfw.hints.debug ? GL_TRUE : GL_FALSE;
-    ctxconfig.profile       = _glfw.hints.profile;
-    ctxconfig.robustness    = _glfw.hints.robustness;
-    ctxconfig.release       = _glfw.hints.release;
-    ctxconfig.share         = (_GLFWwindow*) share;
+    if (ctxconfig.share)
+    {
+        if (ctxconfig.client == GLFW_NO_API ||
+            ctxconfig.share->context.client == GLFW_NO_API)
+        {
+            _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
+            return NULL;
+        }
+    }
 
-    // Check the OpenGL bits of the window config
     if (!_glfwIsValidContextConfig(&ctxconfig))
         return NULL;
 
@@ -180,85 +166,63 @@
     window->next = _glfw.windowListHead;
     _glfw.windowListHead = window;
 
-    if (wndconfig.monitor)
-    {
-        wndconfig.resizable = GL_TRUE;
-        wndconfig.visible   = GL_TRUE;
-        wndconfig.focused   = GL_TRUE;
-
-        // Set up desired video mode
-        window->videoMode.width       = width;
-        window->videoMode.height      = height;
-        window->videoMode.redBits     = _glfw.hints.redBits;
-        window->videoMode.greenBits   = _glfw.hints.greenBits;
-        window->videoMode.blueBits    = _glfw.hints.blueBits;
-        window->videoMode.refreshRate = _glfw.hints.refreshRate;
-    }
+    window->videoMode.width       = width;
+    window->videoMode.height      = height;
+    window->videoMode.redBits     = fbconfig.redBits;
+    window->videoMode.greenBits   = fbconfig.greenBits;
+    window->videoMode.blueBits    = fbconfig.blueBits;
+    window->videoMode.refreshRate = _glfw.hints.refreshRate;
 
-    // Transfer window hints that are persistent settings and not
-    // just initial states
-    window->monitor     = wndconfig.monitor;
+    window->monitor     = (_GLFWmonitor*) monitor;
     window->resizable   = wndconfig.resizable;
     window->decorated   = wndconfig.decorated;
     window->autoIconify = wndconfig.autoIconify;
     window->floating    = wndconfig.floating;
     window->cursorMode  = GLFW_CURSOR_NORMAL;
 
+    window->minwidth    = GLFW_DONT_CARE;
+    window->minheight   = GLFW_DONT_CARE;
+    window->maxwidth    = GLFW_DONT_CARE;
+    window->maxheight   = GLFW_DONT_CARE;
+    window->numer       = GLFW_DONT_CARE;
+    window->denom       = GLFW_DONT_CARE;
+
     // Save the currently current context so it can be restored later
     previous = _glfwPlatformGetCurrentContext();
+    if (ctxconfig.client != GLFW_NO_API)
+        glfwMakeContextCurrent(NULL);
 
     // Open the actual window and create its context
     if (!_glfwPlatformCreateWindow(window, &wndconfig, &ctxconfig, &fbconfig))
     {
+        glfwMakeContextCurrent((GLFWwindow*) previous);
         glfwDestroyWindow((GLFWwindow*) window);
-        _glfwPlatformMakeContextCurrent(previous);
         return NULL;
     }
 
-    _glfwPlatformMakeContextCurrent(window);
-
-    // Retrieve the actual (as opposed to requested) context attributes
-    if (!_glfwRefreshContextAttribs(&ctxconfig))
-    {
-        glfwDestroyWindow((GLFWwindow*) window);
-        _glfwPlatformMakeContextCurrent(previous);
-        return NULL;
-    }
-
-    // Verify the context against the requested parameters
-    if (!_glfwIsValidContext(&ctxconfig))
-    {
-        glfwDestroyWindow((GLFWwindow*) window);
-        _glfwPlatformMakeContextCurrent(previous);
-        return NULL;
-    }
-
-    // Clearing the front buffer to black to avoid garbage pixels left over
-    // from previous uses of our bit of VRAM
-    glClear(GL_COLOR_BUFFER_BIT);
-    _glfwPlatformSwapBuffers(window);
-
-    // Restore the previously current context (or NULL)
-    _glfwPlatformMakeContextCurrent(previous);
-
-    if (wndconfig.monitor)
+    if (ctxconfig.client != GLFW_NO_API)
     {
-        int width, height;
-        _glfwPlatformGetWindowSize(window, &width, &height);
+        window->context.makeCurrent(window);
 
-        window->cursorPosX = width / 2;
-        window->cursorPosY = height / 2;
+        // Retrieve the actual (as opposed to requested) context attributes
+        if (!_glfwRefreshContextAttribs(&ctxconfig))
+        {
+            glfwMakeContextCurrent((GLFWwindow*) previous);
+            glfwDestroyWindow((GLFWwindow*) window);
+            return NULL;
+        }
 
-        _glfwPlatformSetCursorPos(window, window->cursorPosX, window->cursorPosY);
+        // Restore the previously current context (or NULL)
+        glfwMakeContextCurrent((GLFWwindow*) previous);
     }
-    else
+
+    if (!window->monitor)
     {
         if (wndconfig.visible)
         {
+            _glfwPlatformShowWindow(window);
             if (wndconfig.focused)
-                _glfwPlatformShowWindow(window);
-            else
-                _glfwPlatformUnhideWindow(window);
+                _glfwPlatformFocusWindow(window);
         }
     }
 
@@ -272,129 +236,139 @@
     memset(&_glfw.hints, 0, sizeof(_glfw.hints));
 
     // The default is OpenGL with minimum version 1.0
-    _glfw.hints.api   = GLFW_OPENGL_API;
-    _glfw.hints.major = 1;
-    _glfw.hints.minor = 0;
+    _glfw.hints.context.client = GLFW_OPENGL_API;
+    _glfw.hints.context.source = GLFW_NATIVE_CONTEXT_API;
+    _glfw.hints.context.major  = 1;
+    _glfw.hints.context.minor  = 0;
 
     // The default is a focused, visible, resizable window with decorations
-    _glfw.hints.resizable   = GL_TRUE;
-    _glfw.hints.visible     = GL_TRUE;
-    _glfw.hints.decorated   = GL_TRUE;
-    _glfw.hints.focused     = GL_TRUE;
-    _glfw.hints.autoIconify = GL_TRUE;
-
-    // The default is to select the highest available refresh rate
-    _glfw.hints.refreshRate = GLFW_DONT_CARE;
+    _glfw.hints.window.resizable   = GLFW_TRUE;
+    _glfw.hints.window.visible     = GLFW_TRUE;
+    _glfw.hints.window.decorated   = GLFW_TRUE;
+    _glfw.hints.window.focused     = GLFW_TRUE;
+    _glfw.hints.window.autoIconify = GLFW_TRUE;
 
     // The default is 24 bits of color, 24 bits of depth and 8 bits of stencil,
     // double buffered
-    _glfw.hints.redBits      = 8;
-    _glfw.hints.greenBits    = 8;
-    _glfw.hints.blueBits     = 8;
-    _glfw.hints.alphaBits    = 8;
-    _glfw.hints.depthBits    = 24;
-    _glfw.hints.stencilBits  = 8;
-    _glfw.hints.doublebuffer = GL_TRUE;
+    _glfw.hints.framebuffer.redBits      = 8;
+    _glfw.hints.framebuffer.greenBits    = 8;
+    _glfw.hints.framebuffer.blueBits     = 8;
+    _glfw.hints.framebuffer.alphaBits    = 8;
+    _glfw.hints.framebuffer.depthBits    = 24;
+    _glfw.hints.framebuffer.stencilBits  = 8;
+    _glfw.hints.framebuffer.doublebuffer = GLFW_TRUE;
+
+    // The default is to select the highest available refresh rate
+    _glfw.hints.refreshRate = GLFW_DONT_CARE;
 }
 
-GLFWAPI void glfwWindowHint(int target, int hint)
+GLFWAPI void glfwWindowHint(int hint, int value)
 {
     _GLFW_REQUIRE_INIT();
 
-    switch (target)
+    switch (hint)
     {
         case GLFW_RED_BITS:
-            _glfw.hints.redBits = hint;
+            _glfw.hints.framebuffer.redBits = value;
             break;
         case GLFW_GREEN_BITS:
-            _glfw.hints.greenBits = hint;
+            _glfw.hints.framebuffer.greenBits = value;
             break;
         case GLFW_BLUE_BITS:
-            _glfw.hints.blueBits = hint;
+            _glfw.hints.framebuffer.blueBits = value;
             break;
         case GLFW_ALPHA_BITS:
-            _glfw.hints.alphaBits = hint;
+            _glfw.hints.framebuffer.alphaBits = value;
             break;
         case GLFW_DEPTH_BITS:
-            _glfw.hints.depthBits = hint;
+            _glfw.hints.framebuffer.depthBits = value;
             break;
         case GLFW_STENCIL_BITS:
-            _glfw.hints.stencilBits = hint;
+            _glfw.hints.framebuffer.stencilBits = value;
             break;
         case GLFW_ACCUM_RED_BITS:
-            _glfw.hints.accumRedBits = hint;
+            _glfw.hints.framebuffer.accumRedBits = value;
             break;
         case GLFW_ACCUM_GREEN_BITS:
-            _glfw.hints.accumGreenBits = hint;
+            _glfw.hints.framebuffer.accumGreenBits = value;
             break;
         case GLFW_ACCUM_BLUE_BITS:
-            _glfw.hints.accumBlueBits = hint;
+            _glfw.hints.framebuffer.accumBlueBits = value;
             break;
         case GLFW_ACCUM_ALPHA_BITS:
-            _glfw.hints.accumAlphaBits = hint;
+            _glfw.hints.framebuffer.accumAlphaBits = value;
             break;
         case GLFW_AUX_BUFFERS:
-            _glfw.hints.auxBuffers = hint;
+            _glfw.hints.framebuffer.auxBuffers = value;
             break;
         case GLFW_STEREO:
-            _glfw.hints.stereo = hint;
-            break;
-        case GLFW_REFRESH_RATE:
-            _glfw.hints.refreshRate = hint;
+            _glfw.hints.framebuffer.stereo = value ? GLFW_TRUE : GLFW_FALSE;
             break;
         case GLFW_DOUBLEBUFFER:
-            _glfw.hints.doublebuffer = hint;
+            _glfw.hints.framebuffer.doublebuffer = value ? GLFW_TRUE : GLFW_FALSE;
             break;
+        case GLFW_SAMPLES:
+            _glfw.hints.framebuffer.samples = value;
+            break;
+        case GLFW_SRGB_CAPABLE:
+            _glfw.hints.framebuffer.sRGB = value ? GLFW_TRUE : GLFW_FALSE;
+            break;
         case GLFW_RESIZABLE:
-            _glfw.hints.resizable = hint;
+            _glfw.hints.window.resizable = value ? GLFW_TRUE : GLFW_FALSE;
             break;
         case GLFW_DECORATED:
-            _glfw.hints.decorated = hint;
+            _glfw.hints.window.decorated = value ? GLFW_TRUE : GLFW_FALSE;
             break;
         case GLFW_FOCUSED:
-            _glfw.hints.focused = hint;
+            _glfw.hints.window.focused = value ? GLFW_TRUE : GLFW_FALSE;
             break;
         case GLFW_AUTO_ICONIFY:
-            _glfw.hints.autoIconify = hint;
+            _glfw.hints.window.autoIconify = value ? GLFW_TRUE : GLFW_FALSE;
             break;
         case GLFW_FLOATING:
-            _glfw.hints.floating = hint;
-            break;
-        case GLFW_VISIBLE:
-            _glfw.hints.visible = hint;
+            _glfw.hints.window.floating = value ? GLFW_TRUE : GLFW_FALSE;
             break;
-        case GLFW_SAMPLES:
-            _glfw.hints.samples = hint;
+        case GLFW_MAXIMIZED:
+            _glfw.hints.window.maximized = value ? GLFW_TRUE : GLFW_FALSE;
             break;
-        case GLFW_SRGB_CAPABLE:
-            _glfw.hints.sRGB = hint;
+        case GLFW_VISIBLE:
+            _glfw.hints.window.visible = value ? GLFW_TRUE : GLFW_FALSE;
             break;
         case GLFW_CLIENT_API:
-            _glfw.hints.api = hint;
+            _glfw.hints.context.client = value;
             break;
+        case GLFW_CONTEXT_CREATION_API:
+            _glfw.hints.context.source = value;
+            break;
         case GLFW_CONTEXT_VERSION_MAJOR:
-            _glfw.hints.major = hint;
+            _glfw.hints.context.major = value;
             break;
         case GLFW_CONTEXT_VERSION_MINOR:
-            _glfw.hints.minor = hint;
+            _glfw.hints.context.minor = value;
             break;
         case GLFW_CONTEXT_ROBUSTNESS:
-            _glfw.hints.robustness = hint;
+            _glfw.hints.context.robustness = value;
             break;
         case GLFW_OPENGL_FORWARD_COMPAT:
-            _glfw.hints.forward = hint;
+            _glfw.hints.context.forward = value ? GLFW_TRUE : GLFW_FALSE;
             break;
         case GLFW_OPENGL_DEBUG_CONTEXT:
-            _glfw.hints.debug = hint;
+            _glfw.hints.context.debug = value ? GLFW_TRUE : GLFW_FALSE;
             break;
+        case GLFW_CONTEXT_NO_ERROR:
+            _glfw.hints.context.noerror = value ? GLFW_TRUE : GLFW_FALSE;
+            break;
         case GLFW_OPENGL_PROFILE:
-            _glfw.hints.profile = hint;
+            _glfw.hints.context.profile = value;
             break;
         case GLFW_CONTEXT_RELEASE_BEHAVIOR:
-            _glfw.hints.release = hint;
+            _glfw.hints.context.release = value;
             break;
+        case GLFW_REFRESH_RATE:
+            _glfw.hints.refreshRate = value;
+            break;
         default:
-            _glfwInputError(GLFW_INVALID_ENUM, NULL);
+            _glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint %i", hint);
             break;
     }
 }
@@ -415,11 +389,7 @@
     // The window's context must not be current on another thread when the
     // window is destroyed
     if (window == _glfwPlatformGetCurrentContext())
-        _glfwPlatformMakeContextCurrent(NULL);
-
-    // Clear the focused window pointer if this is the focused window
-    if (_glfw.focusedWindow == window)
-        _glfw.focusedWindow = NULL;
+        glfwMakeContextCurrent(NULL);
 
     _glfwPlatformDestroyWindow(window);
 
@@ -439,6 +409,8 @@
 GLFWAPI int glfwWindowShouldClose(GLFWwindow* handle)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _GLFW_REQUIRE_INIT_OR_RETURN(0);
     return window->closed;
 }
@@ -446,6 +418,8 @@
 GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* handle, int value)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _GLFW_REQUIRE_INIT();
     window->closed = value;
 }
@@ -453,13 +427,30 @@
 GLFWAPI void glfwSetWindowTitle(GLFWwindow* handle, const char* title)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
+    assert(title != NULL);
+
     _GLFW_REQUIRE_INIT();
     _glfwPlatformSetWindowTitle(window, title);
 }
 
+GLFWAPI void glfwSetWindowIcon(GLFWwindow* handle,
+                               int count, const GLFWimage* images)
+{
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+    assert(count >= 0);
+    assert(count == 0 || images != NULL);
+
+    _GLFW_REQUIRE_INIT();
+    _glfwPlatformSetWindowIcon(window, count, images);
+}
+
 GLFWAPI void glfwGetWindowPos(GLFWwindow* handle, int* xpos, int* ypos)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
 
     if (xpos)
         *xpos = 0;
@@ -473,15 +464,12 @@
 GLFWAPI void glfwSetWindowPos(GLFWwindow* handle, int xpos, int ypos)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
 
     _GLFW_REQUIRE_INIT();
 
     if (window->monitor)
-    {
-        _glfwInputError(GLFW_INVALID_VALUE,
-                        "Full screen windows cannot be positioned");
         return;
-    }
 
     _glfwPlatformSetWindowPos(window, xpos, ypos);
 }
@@ -489,6 +477,7 @@
 GLFWAPI void glfwGetWindowSize(GLFWwindow* handle, int* width, int* height)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
 
     if (width)
         *width = 0;
@@ -502,21 +491,92 @@
 GLFWAPI void glfwSetWindowSize(GLFWwindow* handle, int width, int height)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
 
     _GLFW_REQUIRE_INIT();
 
-    if (window->monitor)
+    window->videoMode.width  = width;
+    window->videoMode.height = height;
+
+    _glfwPlatformSetWindowSize(window, width, height);
+}
+
+GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* handle,
+                                     int minwidth, int minheight,
+                                     int maxwidth, int maxheight)
+{
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
+    _GLFW_REQUIRE_INIT();
+
+    if (minwidth != GLFW_DONT_CARE && minheight != GLFW_DONT_CARE)
     {
-        window->videoMode.width  = width;
-        window->videoMode.height = height;
+        if (minwidth < 0 || minheight < 0)
+        {
+            _glfwInputError(GLFW_INVALID_VALUE,
+                            "Invalid window minimum size %ix%i",
+                            minwidth, minheight);
+            return;
+        }
     }
 
-    _glfwPlatformSetWindowSize(window, width, height);
+    if (maxwidth != GLFW_DONT_CARE && maxheight != GLFW_DONT_CARE)
+    {
+        if (maxwidth < 0 || maxheight < 0 ||
+            maxwidth < minwidth || maxheight < minheight)
+        {
+            _glfwInputError(GLFW_INVALID_VALUE,
+                            "Invalid window maximum size %ix%i",
+                            maxwidth, maxheight);
+            return;
+        }
+    }
+
+    window->minwidth  = minwidth;
+    window->minheight = minheight;
+    window->maxwidth  = maxwidth;
+    window->maxheight = maxheight;
+
+    if (window->monitor || !window->resizable)
+        return;
+
+    _glfwPlatformSetWindowSizeLimits(window,
+                                     minwidth, minheight,
+                                     maxwidth, maxheight);
 }
 
+GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* handle, int numer, int denom)
+{
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
+    _GLFW_REQUIRE_INIT();
+
+    if (numer != GLFW_DONT_CARE && denom != GLFW_DONT_CARE)
+    {
+        if (numer <= 0 || denom <= 0)
+        {
+            _glfwInputError(GLFW_INVALID_VALUE,
+                            "Invalid window aspect ratio %i:%i",
+                            numer, denom);
+            return;
+        }
+    }
+
+    window->numer = numer;
+    window->denom = denom;
+
+    if (window->monitor || !window->resizable)
+        return;
+
+    _glfwPlatformSetWindowAspectRatio(window, numer, denom);
+}
+
 GLFWAPI void glfwGetFramebufferSize(GLFWwindow* handle, int* width, int* height)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
 
     if (width)
         *width = 0;
@@ -532,6 +592,7 @@
                                     int* right, int* bottom)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
 
     if (left)
         *left = 0;
@@ -549,6 +610,8 @@
 GLFWAPI void glfwIconifyWindow(GLFWwindow* handle)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _GLFW_REQUIRE_INIT();
     _glfwPlatformIconifyWindow(window);
 }
@@ -556,13 +619,25 @@
 GLFWAPI void glfwRestoreWindow(GLFWwindow* handle)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _GLFW_REQUIRE_INIT();
     _glfwPlatformRestoreWindow(window);
 }
 
+GLFWAPI void glfwMaximizeWindow(GLFWwindow* handle)
+{
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
+    _GLFW_REQUIRE_INIT();
+    _glfwPlatformMaximizeWindow(window);
+}
+
 GLFWAPI void glfwShowWindow(GLFWwindow* handle)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
 
     _GLFW_REQUIRE_INIT();
 
@@ -570,11 +645,13 @@
         return;
 
     _glfwPlatformShowWindow(window);
+    _glfwPlatformFocusWindow(window);
 }
 
 GLFWAPI void glfwHideWindow(GLFWwindow* handle)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
 
     _GLFW_REQUIRE_INIT();
 
@@ -584,9 +661,20 @@
     _glfwPlatformHideWindow(window);
 }
 
+GLFWAPI void glfwFocusWindow(GLFWwindow* handle)
+{
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
+    _GLFW_REQUIRE_INIT();
+
+    _glfwPlatformFocusWindow(window);
+}
+
 GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
 
     _GLFW_REQUIRE_INIT_OR_RETURN(0);
 
@@ -598,6 +686,8 @@
             return _glfwPlatformWindowIconified(window);
         case GLFW_VISIBLE:
             return _glfwPlatformWindowVisible(window);
+        case GLFW_MAXIMIZED:
+            return _glfwPlatformWindowMaximized(window);
         case GLFW_RESIZABLE:
             return window->resizable;
         case GLFW_DECORATED:
@@ -605,7 +695,9 @@
         case GLFW_FLOATING:
             return window->floating;
         case GLFW_CLIENT_API:
-            return window->context.api;
+            return window->context.client;
+        case GLFW_CONTEXT_CREATION_API:
+            return window->context.source;
         case GLFW_CONTEXT_VERSION_MAJOR:
             return window->context.major;
         case GLFW_CONTEXT_VERSION_MINOR:
@@ -622,22 +714,65 @@
             return window->context.profile;
         case GLFW_CONTEXT_RELEASE_BEHAVIOR:
             return window->context.release;
+        case GLFW_CONTEXT_NO_ERROR:
+            return window->context.noerror;
     }
 
-    _glfwInputError(GLFW_INVALID_ENUM, NULL);
+    _glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute %i", attrib);
     return 0;
 }
 
 GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* handle)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     return (GLFWmonitor*) window->monitor;
 }
 
+GLFWAPI void glfwSetWindowMonitor(GLFWwindow* wh,
+                                  GLFWmonitor* mh,
+                                  int xpos, int ypos,
+                                  int width, int height,
+                                  int refreshRate)
+{
+    _GLFWwindow* window = (_GLFWwindow*) wh;
+    _GLFWmonitor* monitor = (_GLFWmonitor*) mh;
+    assert(window != NULL);
+
+    _GLFW_REQUIRE_INIT();
+
+    if (width <= 0 || height <= 0)
+    {
+        _glfwInputError(GLFW_INVALID_VALUE,
+                        "Invalid window size %ix%i",
+                        width, height);
+        return;
+    }
+
+    if (refreshRate < 0 && refreshRate != GLFW_DONT_CARE)
+    {
+        _glfwInputError(GLFW_INVALID_VALUE,
+                        "Invalid refresh rate %i",
+                        refreshRate);
+        return;
+    }
+
+    window->videoMode.width       = width;
+    window->videoMode.height      = height;
+    window->videoMode.refreshRate = refreshRate;
+
+    _glfwPlatformSetWindowMonitor(window, monitor,
+                                  xpos, ypos, width, height,
+                                  refreshRate);
+}
+
 GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* handle, void* pointer)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _GLFW_REQUIRE_INIT();
     window->userPointer = pointer;
 }
@@ -645,6 +780,8 @@
 GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* handle)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     return window->userPointer;
 }
@@ -653,6 +790,8 @@
                                                   GLFWwindowposfun cbfun)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP_POINTERS(window->callbacks.pos, cbfun);
     return cbfun;
@@ -662,6 +801,8 @@
                                                     GLFWwindowsizefun cbfun)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP_POINTERS(window->callbacks.size, cbfun);
     return cbfun;
@@ -671,6 +812,8 @@
                                                       GLFWwindowclosefun cbfun)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP_POINTERS(window->callbacks.close, cbfun);
     return cbfun;
@@ -680,6 +823,8 @@
                                                           GLFWwindowrefreshfun cbfun)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP_POINTERS(window->callbacks.refresh, cbfun);
     return cbfun;
@@ -689,6 +834,8 @@
                                                       GLFWwindowfocusfun cbfun)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP_POINTERS(window->callbacks.focus, cbfun);
     return cbfun;
@@ -698,6 +845,8 @@
                                                           GLFWwindowiconifyfun cbfun)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP_POINTERS(window->callbacks.iconify, cbfun);
     return cbfun;
@@ -707,6 +856,8 @@
                                                               GLFWframebuffersizefun cbfun)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP_POINTERS(window->callbacks.fbsize, cbfun);
     return cbfun;
@@ -726,6 +877,19 @@
         return;
 
     _glfwPlatformWaitEvents();
+}
+
+GLFWAPI void glfwWaitEventsTimeout(double timeout)
+{
+    _GLFW_REQUIRE_INIT();
+
+    if (timeout != timeout || timeout < 0.0 || timeout > DBL_MAX)
+    {
+        _glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", timeout);
+        return;
+    }
+
+    _glfwPlatformWaitEventsTimeout(timeout);
 }
 
 GLFWAPI void glfwPostEmptyEvent(void)
diff --git a/glfw/src/winmm_joystick.c b/glfw/src/winmm_joystick.c
deleted file mode 100644
--- a/glfw/src/winmm_joystick.c
+++ /dev/null
@@ -1,177 +0,0 @@
-//========================================================================
-// GLFW 3.1 WinMM - www.glfw.org
-//------------------------------------------------------------------------
-// Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
-//
-// 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 <stdlib.h>
-
-
-//////////////////////////////////////////////////////////////////////////
-//////                       GLFW internal API                      //////
-//////////////////////////////////////////////////////////////////////////
-
-// Convert axis value to the [-1,1] range
-//
-static float normalizeAxis(DWORD pos, DWORD min, DWORD max)
-{
-    float fpos = (float) pos;
-    float fmin = (float) min;
-    float fmax = (float) max;
-
-    return (2.f * (fpos - fmin) / (fmax - fmin)) - 1.f;
-}
-
-
-//////////////////////////////////////////////////////////////////////////
-//////                       GLFW internal API                      //////
-//////////////////////////////////////////////////////////////////////////
-
-// Initialize joystick interface
-//
-void _glfwInitJoysticks(void)
-{
-}
-
-// Close all opened joystick handles
-//
-void _glfwTerminateJoysticks(void)
-{
-    int i;
-
-    for (i = 0;  i < GLFW_JOYSTICK_LAST;  i++)
-        free(_glfw.winmm_js[i].name);
-}
-
-
-//////////////////////////////////////////////////////////////////////////
-//////                       GLFW platform API                      //////
-//////////////////////////////////////////////////////////////////////////
-
-int _glfwPlatformJoystickPresent(int joy)
-{
-    JOYINFO ji;
-
-    if (_glfw_joyGetPos(joy, &ji) != JOYERR_NOERROR)
-        return GL_FALSE;
-
-    return GL_TRUE;
-}
-
-const float* _glfwPlatformGetJoystickAxes(int joy, int* count)
-{
-    JOYCAPS jc;
-    JOYINFOEX ji;
-    float* axes = _glfw.winmm_js[joy].axes;
-
-    if (_glfw_joyGetDevCaps(joy, &jc, sizeof(JOYCAPS)) != JOYERR_NOERROR)
-        return NULL;
-
-    ji.dwSize = sizeof(JOYINFOEX);
-    ji.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ |
-                 JOY_RETURNR | JOY_RETURNU | JOY_RETURNV;
-    if (_glfw_joyGetPosEx(joy, &ji) != JOYERR_NOERROR)
-        return NULL;
-
-    axes[(*count)++] = normalizeAxis(ji.dwXpos, jc.wXmin, jc.wXmax);
-    axes[(*count)++] = normalizeAxis(ji.dwYpos, jc.wYmin, jc.wYmax);
-
-    if (jc.wCaps & JOYCAPS_HASZ)
-        axes[(*count)++] = normalizeAxis(ji.dwZpos, jc.wZmin, jc.wZmax);
-
-    if (jc.wCaps & JOYCAPS_HASR)
-        axes[(*count)++] = normalizeAxis(ji.dwRpos, jc.wRmin, jc.wRmax);
-
-    if (jc.wCaps & JOYCAPS_HASU)
-        axes[(*count)++] = normalizeAxis(ji.dwUpos, jc.wUmin, jc.wUmax);
-
-    if (jc.wCaps & JOYCAPS_HASV)
-        axes[(*count)++] = normalizeAxis(ji.dwVpos, jc.wVmin, jc.wVmax);
-
-    return axes;
-}
-
-const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
-{
-    JOYCAPS jc;
-    JOYINFOEX ji;
-    unsigned char* buttons = _glfw.winmm_js[joy].buttons;
-
-    if (_glfw_joyGetDevCaps(joy, &jc, sizeof(JOYCAPS)) != JOYERR_NOERROR)
-        return NULL;
-
-    ji.dwSize = sizeof(JOYINFOEX);
-    ji.dwFlags = JOY_RETURNBUTTONS | JOY_RETURNPOV;
-    if (_glfw_joyGetPosEx(joy, &ji) != JOYERR_NOERROR)
-        return NULL;
-
-    while (*count < (int) jc.wNumButtons)
-    {
-        buttons[*count] = (unsigned char)
-            (ji.dwButtons & (1UL << *count) ? GLFW_PRESS : GLFW_RELEASE);
-        (*count)++;
-    }
-
-    // Virtual buttons - Inject data from hats
-    // Each hat is exposed as 4 buttons which exposes 8 directions with
-    // concurrent button presses
-    // NOTE: this API exposes only one hat
-
-    if ((jc.wCaps & JOYCAPS_HASPOV) && (jc.wCaps & JOYCAPS_POV4DIR))
-    {
-        int i, value = ji.dwPOV / 100 / 45;
-
-        // Bit fields of button presses for each direction, including nil
-        const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 };
-
-        if (value < 0 || value > 8)
-            value = 8;
-
-        for (i = 0;  i < 4;  i++)
-        {
-            if (directions[value] & (1 << i))
-                buttons[(*count)++] = GLFW_PRESS;
-            else
-                buttons[(*count)++] = GLFW_RELEASE;
-        }
-    }
-
-    return buttons;
-}
-
-const char* _glfwPlatformGetJoystickName(int joy)
-{
-    JOYCAPS jc;
-
-    if (_glfw_joyGetDevCaps(joy, &jc, sizeof(JOYCAPS)) != JOYERR_NOERROR)
-        return NULL;
-
-    free(_glfw.winmm_js[joy].name);
-    _glfw.winmm_js[joy].name = _glfwCreateUTF8FromWideString(jc.szPname);
-
-    return _glfw.winmm_js[joy].name;
-}
-
diff --git a/glfw/src/winmm_joystick.h b/glfw/src/winmm_joystick.h
deleted file mode 100644
--- a/glfw/src/winmm_joystick.h
+++ /dev/null
@@ -1,47 +0,0 @@
-//========================================================================
-// GLFW 3.1 WinMM - www.glfw.org
-//------------------------------------------------------------------------
-// Copyright (c) 2006-2014 Camilla Berglund <elmindreda@elmindreda.org>
-//
-// 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.
-//
-//========================================================================
-
-#ifndef _winmm_joystick_h_
-#define _winmm_joystick_h_
-
-#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE \
-    _GLFWjoystickWinMM winmm_js[GLFW_JOYSTICK_LAST + 1]
-
-
-// WinMM-specific per-joystick data
-//
-typedef struct _GLFWjoystickWinMM
-{
-    float           axes[6];
-    unsigned char   buttons[36]; // 32 buttons plus one hat
-    char*           name;
-} _GLFWjoystickWinMM;
-
-
-void _glfwInitJoysticks(void);
-void _glfwTerminateJoysticks(void);
-
-#endif // _winmm_joystick_h_
diff --git a/glfw/src/wl_init.c b/glfw/src/wl_init.c
--- a/glfw/src/wl_init.c
+++ b/glfw/src/wl_init.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.1 Wayland - www.glfw.org
+// GLFW 3.2 Wayland - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
 //
@@ -35,8 +35,12 @@
 #include <wayland-client.h>
 #include <wayland-cursor.h>
 
-#include "xkb_unicode.h"
 
+static inline int min(int n1, int n2)
+{
+    return n1 < n2 ? n1 : n2;
+}
+
 static void pointerHandleEnter(void* data,
                                struct wl_pointer* pointer,
                                uint32_t serial,
@@ -50,7 +54,7 @@
     _glfw.wl.pointerFocus = window;
 
     _glfwPlatformSetCursor(window, window->wl.currentCursor);
-    _glfwInputCursorEnter(window, GL_TRUE);
+    _glfwInputCursorEnter(window, GLFW_TRUE);
 }
 
 static void pointerHandleLeave(void* data,
@@ -65,7 +69,7 @@
 
     _glfw.wl.pointerSerial = serial;
     _glfw.wl.pointerFocus = NULL;
-    _glfwInputCursorEnter(window, GL_FALSE);
+    _glfwInputCursorEnter(window, GLFW_FALSE);
 }
 
 static void pointerHandleMotion(void* data,
@@ -80,16 +84,16 @@
         return;
 
     if (window->cursorMode == GLFW_CURSOR_DISABLED)
-    {
-        /* TODO */
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "Wayland: GLFW_CURSOR_DISABLED not supported");
         return;
+    else
+    {
+        window->wl.cursorPosX = wl_fixed_to_double(sx);
+        window->wl.cursorPosY = wl_fixed_to_double(sy);
     }
 
-    _glfwInputCursorMotion(window,
-                           wl_fixed_to_double(sx),
-                           wl_fixed_to_double(sy));
+    _glfwInputCursorPos(window,
+                        wl_fixed_to_double(sx),
+                        wl_fixed_to_double(sy));
 }
 
 static void pointerHandleButton(void* data,
@@ -229,7 +233,7 @@
     _GLFWwindow* window = wl_surface_get_user_data(surface);
 
     _glfw.wl.keyboardFocus = window;
-    _glfwInputWindowFocus(window, GL_TRUE);
+    _glfwInputWindowFocus(window, GLFW_TRUE);
 }
 
 static void keyboardHandleLeave(void* data,
@@ -243,131 +247,15 @@
         return;
 
     _glfw.wl.keyboardFocus = NULL;
-    _glfwInputWindowFocus(window, GL_FALSE);
+    _glfwInputWindowFocus(window, GLFW_FALSE);
 }
 
 static int toGLFWKeyCode(uint32_t key)
 {
-    switch (key)
-    {
-        case KEY_GRAVE:         return GLFW_KEY_GRAVE_ACCENT;
-        case KEY_1:             return GLFW_KEY_1;
-        case KEY_2:             return GLFW_KEY_2;
-        case KEY_3:             return GLFW_KEY_3;
-        case KEY_4:             return GLFW_KEY_4;
-        case KEY_5:             return GLFW_KEY_5;
-        case KEY_6:             return GLFW_KEY_6;
-        case KEY_7:             return GLFW_KEY_7;
-        case KEY_8:             return GLFW_KEY_8;
-        case KEY_9:             return GLFW_KEY_9;
-        case KEY_0:             return GLFW_KEY_0;
-        case KEY_MINUS:         return GLFW_KEY_MINUS;
-        case KEY_EQUAL:         return GLFW_KEY_EQUAL;
-        case KEY_Q:             return GLFW_KEY_Q;
-        case KEY_W:             return GLFW_KEY_W;
-        case KEY_E:             return GLFW_KEY_E;
-        case KEY_R:             return GLFW_KEY_R;
-        case KEY_T:             return GLFW_KEY_T;
-        case KEY_Y:             return GLFW_KEY_Y;
-        case KEY_U:             return GLFW_KEY_U;
-        case KEY_I:             return GLFW_KEY_I;
-        case KEY_O:             return GLFW_KEY_O;
-        case KEY_P:             return GLFW_KEY_P;
-        case KEY_LEFTBRACE:     return GLFW_KEY_LEFT_BRACKET;
-        case KEY_RIGHTBRACE:    return GLFW_KEY_RIGHT_BRACKET;
-        case KEY_A:             return GLFW_KEY_A;
-        case KEY_S:             return GLFW_KEY_S;
-        case KEY_D:             return GLFW_KEY_D;
-        case KEY_F:             return GLFW_KEY_F;
-        case KEY_G:             return GLFW_KEY_G;
-        case KEY_H:             return GLFW_KEY_H;
-        case KEY_J:             return GLFW_KEY_J;
-        case KEY_K:             return GLFW_KEY_K;
-        case KEY_L:             return GLFW_KEY_L;
-        case KEY_SEMICOLON:     return GLFW_KEY_SEMICOLON;
-        case KEY_APOSTROPHE:    return GLFW_KEY_APOSTROPHE;
-        case KEY_Z:             return GLFW_KEY_Z;
-        case KEY_X:             return GLFW_KEY_X;
-        case KEY_C:             return GLFW_KEY_C;
-        case KEY_V:             return GLFW_KEY_V;
-        case KEY_B:             return GLFW_KEY_B;
-        case KEY_N:             return GLFW_KEY_N;
-        case KEY_M:             return GLFW_KEY_M;
-        case KEY_COMMA:         return GLFW_KEY_COMMA;
-        case KEY_DOT:           return GLFW_KEY_PERIOD;
-        case KEY_SLASH:         return GLFW_KEY_SLASH;
-        case KEY_BACKSLASH:     return GLFW_KEY_BACKSLASH;
-        case KEY_ESC:           return GLFW_KEY_ESCAPE;
-        case KEY_TAB:           return GLFW_KEY_TAB;
-        case KEY_LEFTSHIFT:     return GLFW_KEY_LEFT_SHIFT;
-        case KEY_RIGHTSHIFT:    return GLFW_KEY_RIGHT_SHIFT;
-        case KEY_LEFTCTRL:      return GLFW_KEY_LEFT_CONTROL;
-        case KEY_RIGHTCTRL:     return GLFW_KEY_RIGHT_CONTROL;
-        case KEY_LEFTALT:       return GLFW_KEY_LEFT_ALT;
-        case KEY_RIGHTALT:      return GLFW_KEY_RIGHT_ALT;
-        case KEY_LEFTMETA:      return GLFW_KEY_LEFT_SUPER;
-        case KEY_RIGHTMETA:     return GLFW_KEY_RIGHT_SUPER;
-        case KEY_MENU:          return GLFW_KEY_MENU;
-        case KEY_NUMLOCK:       return GLFW_KEY_NUM_LOCK;
-        case KEY_CAPSLOCK:      return GLFW_KEY_CAPS_LOCK;
-        case KEY_PRINT:         return GLFW_KEY_PRINT_SCREEN;
-        case KEY_SCROLLLOCK:    return GLFW_KEY_SCROLL_LOCK;
-        case KEY_PAUSE:         return GLFW_KEY_PAUSE;
-        case KEY_DELETE:        return GLFW_KEY_DELETE;
-        case KEY_BACKSPACE:     return GLFW_KEY_BACKSPACE;
-        case KEY_ENTER:         return GLFW_KEY_ENTER;
-        case KEY_HOME:          return GLFW_KEY_HOME;
-        case KEY_END:           return GLFW_KEY_END;
-        case KEY_PAGEUP:        return GLFW_KEY_PAGE_UP;
-        case KEY_PAGEDOWN:      return GLFW_KEY_PAGE_DOWN;
-        case KEY_INSERT:        return GLFW_KEY_INSERT;
-        case KEY_LEFT:          return GLFW_KEY_LEFT;
-        case KEY_RIGHT:         return GLFW_KEY_RIGHT;
-        case KEY_DOWN:          return GLFW_KEY_DOWN;
-        case KEY_UP:            return GLFW_KEY_UP;
-        case KEY_F1:            return GLFW_KEY_F1;
-        case KEY_F2:            return GLFW_KEY_F2;
-        case KEY_F3:            return GLFW_KEY_F3;
-        case KEY_F4:            return GLFW_KEY_F4;
-        case KEY_F5:            return GLFW_KEY_F5;
-        case KEY_F6:            return GLFW_KEY_F6;
-        case KEY_F7:            return GLFW_KEY_F7;
-        case KEY_F8:            return GLFW_KEY_F8;
-        case KEY_F9:            return GLFW_KEY_F9;
-        case KEY_F10:           return GLFW_KEY_F10;
-        case KEY_F11:           return GLFW_KEY_F11;
-        case KEY_F12:           return GLFW_KEY_F12;
-        case KEY_F13:           return GLFW_KEY_F13;
-        case KEY_F14:           return GLFW_KEY_F14;
-        case KEY_F15:           return GLFW_KEY_F15;
-        case KEY_F16:           return GLFW_KEY_F16;
-        case KEY_F17:           return GLFW_KEY_F17;
-        case KEY_F18:           return GLFW_KEY_F18;
-        case KEY_F19:           return GLFW_KEY_F19;
-        case KEY_F20:           return GLFW_KEY_F20;
-        case KEY_F21:           return GLFW_KEY_F21;
-        case KEY_F22:           return GLFW_KEY_F22;
-        case KEY_F23:           return GLFW_KEY_F23;
-        case KEY_F24:           return GLFW_KEY_F24;
-        case KEY_KPSLASH:       return GLFW_KEY_KP_DIVIDE;
-        case KEY_KPDOT:         return GLFW_KEY_KP_MULTIPLY;
-        case KEY_KPMINUS:       return GLFW_KEY_KP_SUBTRACT;
-        case KEY_KPPLUS:        return GLFW_KEY_KP_ADD;
-        case KEY_KP0:           return GLFW_KEY_KP_0;
-        case KEY_KP1:           return GLFW_KEY_KP_1;
-        case KEY_KP2:           return GLFW_KEY_KP_2;
-        case KEY_KP3:           return GLFW_KEY_KP_3;
-        case KEY_KP4:           return GLFW_KEY_KP_4;
-        case KEY_KP5:           return GLFW_KEY_KP_5;
-        case KEY_KP6:           return GLFW_KEY_KP_6;
-        case KEY_KP7:           return GLFW_KEY_KP_7;
-        case KEY_KP8:           return GLFW_KEY_KP_8;
-        case KEY_KP9:           return GLFW_KEY_KP_9;
-        case KEY_KPCOMMA:       return GLFW_KEY_KP_DECIMAL;
-        case KEY_KPEQUAL:       return GLFW_KEY_KP_EQUAL;
-        case KEY_KPENTER:       return GLFW_KEY_KP_ENTER;
-        default:                return GLFW_KEY_UNKNOWN;
-    }
+    if (key < sizeof(_glfw.wl.publicKeys) / sizeof(_glfw.wl.publicKeys[0]))
+        return _glfw.wl.publicKeys[key];
+
+    return GLFW_KEY_UNKNOWN;
 }
 
 static void keyboardHandleKey(void* data,
@@ -492,8 +380,10 @@
 {
     if (strcmp(interface, "wl_compositor") == 0)
     {
+        _glfw.wl.wl_compositor_version = min(3, version);
         _glfw.wl.compositor =
-            wl_registry_bind(registry, name, &wl_compositor_interface, 1);
+            wl_registry_bind(registry, name, &wl_compositor_interface,
+                             _glfw.wl.wl_compositor_version);
     }
     else if (strcmp(interface, "wl_shm") == 0)
     {
@@ -507,7 +397,7 @@
     }
     else if (strcmp(interface, "wl_output") == 0)
     {
-        _glfwAddOutput(name, version);
+        _glfwAddOutputWayland(name, version);
     }
     else if (strcmp(interface, "wl_seat") == 0)
     {
@@ -518,6 +408,20 @@
             wl_seat_add_listener(_glfw.wl.seat, &seatListener, NULL);
         }
     }
+    else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0)
+    {
+        _glfw.wl.relativePointerManager =
+            wl_registry_bind(registry, name,
+                             &zwp_relative_pointer_manager_v1_interface,
+                             1);
+    }
+    else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0)
+    {
+        _glfw.wl.pointerConstraints =
+            wl_registry_bind(registry, name,
+                             &zwp_pointer_constraints_v1_interface,
+                             1);
+    }
 }
 
 static void registryHandleGlobalRemove(void *data,
@@ -532,7 +436,131 @@
     registryHandleGlobalRemove
 };
 
+// Create key code translation tables
+//
+static void createKeyTables(void)
+{
+    memset(_glfw.wl.publicKeys, -1, sizeof(_glfw.wl.publicKeys));
 
+    _glfw.wl.publicKeys[KEY_GRAVE]      = GLFW_KEY_GRAVE_ACCENT;
+    _glfw.wl.publicKeys[KEY_1]          = GLFW_KEY_1;
+    _glfw.wl.publicKeys[KEY_2]          = GLFW_KEY_2;
+    _glfw.wl.publicKeys[KEY_3]          = GLFW_KEY_3;
+    _glfw.wl.publicKeys[KEY_4]          = GLFW_KEY_4;
+    _glfw.wl.publicKeys[KEY_5]          = GLFW_KEY_5;
+    _glfw.wl.publicKeys[KEY_6]          = GLFW_KEY_6;
+    _glfw.wl.publicKeys[KEY_7]          = GLFW_KEY_7;
+    _glfw.wl.publicKeys[KEY_8]          = GLFW_KEY_8;
+    _glfw.wl.publicKeys[KEY_9]          = GLFW_KEY_9;
+    _glfw.wl.publicKeys[KEY_0]          = GLFW_KEY_0;
+    _glfw.wl.publicKeys[KEY_MINUS]      = GLFW_KEY_MINUS;
+    _glfw.wl.publicKeys[KEY_EQUAL]      = GLFW_KEY_EQUAL;
+    _glfw.wl.publicKeys[KEY_Q]          = GLFW_KEY_Q;
+    _glfw.wl.publicKeys[KEY_W]          = GLFW_KEY_W;
+    _glfw.wl.publicKeys[KEY_E]          = GLFW_KEY_E;
+    _glfw.wl.publicKeys[KEY_R]          = GLFW_KEY_R;
+    _glfw.wl.publicKeys[KEY_T]          = GLFW_KEY_T;
+    _glfw.wl.publicKeys[KEY_Y]          = GLFW_KEY_Y;
+    _glfw.wl.publicKeys[KEY_U]          = GLFW_KEY_U;
+    _glfw.wl.publicKeys[KEY_I]          = GLFW_KEY_I;
+    _glfw.wl.publicKeys[KEY_O]          = GLFW_KEY_O;
+    _glfw.wl.publicKeys[KEY_P]          = GLFW_KEY_P;
+    _glfw.wl.publicKeys[KEY_LEFTBRACE]  = GLFW_KEY_LEFT_BRACKET;
+    _glfw.wl.publicKeys[KEY_RIGHTBRACE] = GLFW_KEY_RIGHT_BRACKET;
+    _glfw.wl.publicKeys[KEY_A]          = GLFW_KEY_A;
+    _glfw.wl.publicKeys[KEY_S]          = GLFW_KEY_S;
+    _glfw.wl.publicKeys[KEY_D]          = GLFW_KEY_D;
+    _glfw.wl.publicKeys[KEY_F]          = GLFW_KEY_F;
+    _glfw.wl.publicKeys[KEY_G]          = GLFW_KEY_G;
+    _glfw.wl.publicKeys[KEY_H]          = GLFW_KEY_H;
+    _glfw.wl.publicKeys[KEY_J]          = GLFW_KEY_J;
+    _glfw.wl.publicKeys[KEY_K]          = GLFW_KEY_K;
+    _glfw.wl.publicKeys[KEY_L]          = GLFW_KEY_L;
+    _glfw.wl.publicKeys[KEY_SEMICOLON]  = GLFW_KEY_SEMICOLON;
+    _glfw.wl.publicKeys[KEY_APOSTROPHE] = GLFW_KEY_APOSTROPHE;
+    _glfw.wl.publicKeys[KEY_Z]          = GLFW_KEY_Z;
+    _glfw.wl.publicKeys[KEY_X]          = GLFW_KEY_X;
+    _glfw.wl.publicKeys[KEY_C]          = GLFW_KEY_C;
+    _glfw.wl.publicKeys[KEY_V]          = GLFW_KEY_V;
+    _glfw.wl.publicKeys[KEY_B]          = GLFW_KEY_B;
+    _glfw.wl.publicKeys[KEY_N]          = GLFW_KEY_N;
+    _glfw.wl.publicKeys[KEY_M]          = GLFW_KEY_M;
+    _glfw.wl.publicKeys[KEY_COMMA]      = GLFW_KEY_COMMA;
+    _glfw.wl.publicKeys[KEY_DOT]        = GLFW_KEY_PERIOD;
+    _glfw.wl.publicKeys[KEY_SLASH]      = GLFW_KEY_SLASH;
+    _glfw.wl.publicKeys[KEY_BACKSLASH]  = GLFW_KEY_BACKSLASH;
+    _glfw.wl.publicKeys[KEY_ESC]        = GLFW_KEY_ESCAPE;
+    _glfw.wl.publicKeys[KEY_TAB]        = GLFW_KEY_TAB;
+    _glfw.wl.publicKeys[KEY_LEFTSHIFT]  = GLFW_KEY_LEFT_SHIFT;
+    _glfw.wl.publicKeys[KEY_RIGHTSHIFT] = GLFW_KEY_RIGHT_SHIFT;
+    _glfw.wl.publicKeys[KEY_LEFTCTRL]   = GLFW_KEY_LEFT_CONTROL;
+    _glfw.wl.publicKeys[KEY_RIGHTCTRL]  = GLFW_KEY_RIGHT_CONTROL;
+    _glfw.wl.publicKeys[KEY_LEFTALT]    = GLFW_KEY_LEFT_ALT;
+    _glfw.wl.publicKeys[KEY_RIGHTALT]   = GLFW_KEY_RIGHT_ALT;
+    _glfw.wl.publicKeys[KEY_LEFTMETA]   = GLFW_KEY_LEFT_SUPER;
+    _glfw.wl.publicKeys[KEY_RIGHTMETA]  = GLFW_KEY_RIGHT_SUPER;
+    _glfw.wl.publicKeys[KEY_MENU]       = GLFW_KEY_MENU;
+    _glfw.wl.publicKeys[KEY_NUMLOCK]    = GLFW_KEY_NUM_LOCK;
+    _glfw.wl.publicKeys[KEY_CAPSLOCK]   = GLFW_KEY_CAPS_LOCK;
+    _glfw.wl.publicKeys[KEY_PRINT]      = GLFW_KEY_PRINT_SCREEN;
+    _glfw.wl.publicKeys[KEY_SCROLLLOCK] = GLFW_KEY_SCROLL_LOCK;
+    _glfw.wl.publicKeys[KEY_PAUSE]      = GLFW_KEY_PAUSE;
+    _glfw.wl.publicKeys[KEY_DELETE]     = GLFW_KEY_DELETE;
+    _glfw.wl.publicKeys[KEY_BACKSPACE]  = GLFW_KEY_BACKSPACE;
+    _glfw.wl.publicKeys[KEY_ENTER]      = GLFW_KEY_ENTER;
+    _glfw.wl.publicKeys[KEY_HOME]       = GLFW_KEY_HOME;
+    _glfw.wl.publicKeys[KEY_END]        = GLFW_KEY_END;
+    _glfw.wl.publicKeys[KEY_PAGEUP]     = GLFW_KEY_PAGE_UP;
+    _glfw.wl.publicKeys[KEY_PAGEDOWN]   = GLFW_KEY_PAGE_DOWN;
+    _glfw.wl.publicKeys[KEY_INSERT]     = GLFW_KEY_INSERT;
+    _glfw.wl.publicKeys[KEY_LEFT]       = GLFW_KEY_LEFT;
+    _glfw.wl.publicKeys[KEY_RIGHT]      = GLFW_KEY_RIGHT;
+    _glfw.wl.publicKeys[KEY_DOWN]       = GLFW_KEY_DOWN;
+    _glfw.wl.publicKeys[KEY_UP]         = GLFW_KEY_UP;
+    _glfw.wl.publicKeys[KEY_F1]         = GLFW_KEY_F1;
+    _glfw.wl.publicKeys[KEY_F2]         = GLFW_KEY_F2;
+    _glfw.wl.publicKeys[KEY_F3]         = GLFW_KEY_F3;
+    _glfw.wl.publicKeys[KEY_F4]         = GLFW_KEY_F4;
+    _glfw.wl.publicKeys[KEY_F5]         = GLFW_KEY_F5;
+    _glfw.wl.publicKeys[KEY_F6]         = GLFW_KEY_F6;
+    _glfw.wl.publicKeys[KEY_F7]         = GLFW_KEY_F7;
+    _glfw.wl.publicKeys[KEY_F8]         = GLFW_KEY_F8;
+    _glfw.wl.publicKeys[KEY_F9]         = GLFW_KEY_F9;
+    _glfw.wl.publicKeys[KEY_F10]        = GLFW_KEY_F10;
+    _glfw.wl.publicKeys[KEY_F11]        = GLFW_KEY_F11;
+    _glfw.wl.publicKeys[KEY_F12]        = GLFW_KEY_F12;
+    _glfw.wl.publicKeys[KEY_F13]        = GLFW_KEY_F13;
+    _glfw.wl.publicKeys[KEY_F14]        = GLFW_KEY_F14;
+    _glfw.wl.publicKeys[KEY_F15]        = GLFW_KEY_F15;
+    _glfw.wl.publicKeys[KEY_F16]        = GLFW_KEY_F16;
+    _glfw.wl.publicKeys[KEY_F17]        = GLFW_KEY_F17;
+    _glfw.wl.publicKeys[KEY_F18]        = GLFW_KEY_F18;
+    _glfw.wl.publicKeys[KEY_F19]        = GLFW_KEY_F19;
+    _glfw.wl.publicKeys[KEY_F20]        = GLFW_KEY_F20;
+    _glfw.wl.publicKeys[KEY_F21]        = GLFW_KEY_F21;
+    _glfw.wl.publicKeys[KEY_F22]        = GLFW_KEY_F22;
+    _glfw.wl.publicKeys[KEY_F23]        = GLFW_KEY_F23;
+    _glfw.wl.publicKeys[KEY_F24]        = GLFW_KEY_F24;
+    _glfw.wl.publicKeys[KEY_KPSLASH]    = GLFW_KEY_KP_DIVIDE;
+    _glfw.wl.publicKeys[KEY_KPDOT]      = GLFW_KEY_KP_MULTIPLY;
+    _glfw.wl.publicKeys[KEY_KPMINUS]    = GLFW_KEY_KP_SUBTRACT;
+    _glfw.wl.publicKeys[KEY_KPPLUS]     = GLFW_KEY_KP_ADD;
+    _glfw.wl.publicKeys[KEY_KP0]        = GLFW_KEY_KP_0;
+    _glfw.wl.publicKeys[KEY_KP1]        = GLFW_KEY_KP_1;
+    _glfw.wl.publicKeys[KEY_KP2]        = GLFW_KEY_KP_2;
+    _glfw.wl.publicKeys[KEY_KP3]        = GLFW_KEY_KP_3;
+    _glfw.wl.publicKeys[KEY_KP4]        = GLFW_KEY_KP_4;
+    _glfw.wl.publicKeys[KEY_KP5]        = GLFW_KEY_KP_5;
+    _glfw.wl.publicKeys[KEY_KP6]        = GLFW_KEY_KP_6;
+    _glfw.wl.publicKeys[KEY_KP7]        = GLFW_KEY_KP_7;
+    _glfw.wl.publicKeys[KEY_KP8]        = GLFW_KEY_KP_8;
+    _glfw.wl.publicKeys[KEY_KP9]        = GLFW_KEY_KP_9;
+    _glfw.wl.publicKeys[KEY_KPCOMMA]    = GLFW_KEY_KP_DECIMAL;
+    _glfw.wl.publicKeys[KEY_KPEQUAL]    = GLFW_KEY_KP_EQUAL;
+    _glfw.wl.publicKeys[KEY_KPENTER]    = GLFW_KEY_KP_ENTER;
+}
+
+
 //////////////////////////////////////////////////////////////////////////
 //////                       GLFW platform API                      //////
 //////////////////////////////////////////////////////////////////////////
@@ -544,7 +572,7 @@
     {
         _glfwInputError(GLFW_PLATFORM_ERROR,
                         "Wayland: Failed to connect to display");
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
 
     _glfw.wl.registry = wl_display_get_registry(_glfw.wl.display);
@@ -553,12 +581,14 @@
     _glfw.wl.monitors = calloc(4, sizeof(_GLFWmonitor*));
     _glfw.wl.monitorsSize = 4;
 
+    createKeyTables();
+
     _glfw.wl.xkb.context = xkb_context_new(0);
     if (!_glfw.wl.xkb.context)
     {
         _glfwInputError(GLFW_PLATFORM_ERROR,
                         "Wayland: Failed to initialize xkb context");
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
 
     // Sync so we got all registry objects
@@ -567,12 +597,14 @@
     // Sync so we got all initial output events
     wl_display_roundtrip(_glfw.wl.display);
 
-    if (!_glfwInitContextAPI())
-        return GL_FALSE;
+    if (!_glfwInitThreadLocalStoragePOSIX())
+        return GLFW_FALSE;
 
-    _glfwInitTimer();
-    _glfwInitJoysticks();
+    if (!_glfwInitJoysticksLinux())
+        return GLFW_FALSE;
 
+    _glfwInitTimerPOSIX();
+
     if (_glfw.wl.pointer && _glfw.wl.shm)
     {
         _glfw.wl.cursorTheme = wl_cursor_theme_load(NULL, 32, _glfw.wl.shm);
@@ -580,27 +612,20 @@
         {
             _glfwInputError(GLFW_PLATFORM_ERROR,
                             "Wayland: Unable to load default cursor theme\n");
-            return GL_FALSE;
-        }
-        _glfw.wl.defaultCursor =
-            wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, "left_ptr");
-        if (!_glfw.wl.defaultCursor)
-        {
-            _glfwInputError(GLFW_PLATFORM_ERROR,
-                            "Wayland: Unable to load default left pointer\n");
-            return GL_FALSE;
+            return GLFW_FALSE;
         }
         _glfw.wl.cursorSurface =
             wl_compositor_create_surface(_glfw.wl.compositor);
     }
 
-    return GL_TRUE;
+    return GLFW_TRUE;
 }
 
 void _glfwPlatformTerminate(void)
 {
-    _glfwTerminateContextAPI();
-    _glfwTerminateJoysticks();
+    _glfwTerminateEGL();
+    _glfwTerminateJoysticksLinux();
+    _glfwTerminateThreadLocalStoragePOSIX();
 
     if (_glfw.wl.cursorTheme)
         wl_cursor_theme_destroy(_glfw.wl.cursorTheme);
@@ -616,15 +641,18 @@
 
 const char* _glfwPlatformGetVersionString(void)
 {
-    const char* version = _GLFW_VERSION_NUMBER " Wayland EGL "
+    return _GLFW_VERSION_NUMBER " Wayland EGL"
 #if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK)
         " clock_gettime"
+#else
+        " gettimeofday"
 #endif
+#if defined(__linux__)
+        " /dev/js"
+#endif
 #if defined(_GLFW_BUILD_DLL)
         " shared"
 #endif
         ;
-
-    return version;
 }
 
diff --git a/glfw/src/wl_monitor.c b/glfw/src/wl_monitor.c
--- a/glfw/src/wl_monitor.c
+++ b/glfw/src/wl_monitor.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.1 Wayland - www.glfw.org
+// GLFW 3.2 Wayland - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
 //
@@ -69,7 +69,7 @@
 
     mode.base.width = width;
     mode.base.height = height;
-    mode.base.refreshRate = refresh;
+    mode.base.refreshRate = refresh / 1000;
     mode.flags = flags;
 
     if (monitor->wl.modesCount + 1 >= monitor->wl.modesSize)
@@ -90,13 +90,16 @@
 {
     struct _GLFWmonitor *monitor = data;
 
-    monitor->wl.done = GL_TRUE;
+    monitor->wl.done = GLFW_TRUE;
 }
 
 static void scale(void* data,
                   struct wl_output* output,
                   int32_t factor)
 {
+    struct _GLFWmonitor *monitor = data;
+
+    monitor->wl.scale = factor;
 }
 
 static const struct wl_output_listener output_listener = {
@@ -111,13 +114,13 @@
 //////                       GLFW internal API                      //////
 //////////////////////////////////////////////////////////////////////////
 
-void _glfwAddOutput(uint32_t name, uint32_t version)
+void _glfwAddOutputWayland(uint32_t name, uint32_t version)
 {
     _GLFWmonitor *monitor;
     struct wl_output *output;
     char name_str[80];
 
-    memset(name_str, 0, 80 * sizeof(char));
+    memset(name_str, 0, sizeof(name_str));
     snprintf(name_str, 79, "wl_output@%u", name);
 
     if (version < 2)
@@ -142,6 +145,8 @@
     monitor->wl.modes = calloc(4, sizeof(_GLFWvidmodeWayland));
     monitor->wl.modesSize = 4;
 
+    monitor->wl.scale = 1;
+
     monitor->wl.output = output;
     wl_output_add_listener(output, &output_listener, monitor);
 
@@ -195,7 +200,7 @@
     return NULL;
 }
 
-GLboolean _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
+GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
 {
     return first->wl.output == second->wl.output;
 }
@@ -239,12 +244,26 @@
 void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
 {
     // TODO
-    fprintf(stderr, "_glfwPlatformGetGammaRamp not implemented yet\n");
+    _glfwInputError(GLFW_PLATFORM_ERROR,
+                    "Wayland: Gamma ramp getting not supported yet");
 }
 
 void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
 {
     // TODO
-    fprintf(stderr, "_glfwPlatformSetGammaRamp not implemented yet\n");
+    _glfwInputError(GLFW_PLATFORM_ERROR,
+                    "Wayland: Gamma ramp setting not supported yet");
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                        GLFW native API                       //////
+//////////////////////////////////////////////////////////////////////////
+
+GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* handle)
+{
+    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+    return monitor->wl.output;
 }
 
diff --git a/glfw/src/wl_platform.h b/glfw/src/wl_platform.h
--- a/glfw/src/wl_platform.h
+++ b/glfw/src/wl_platform.h
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.1 Wayland - www.glfw.org
+// GLFW 3.2 Wayland - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
 //
@@ -24,51 +24,86 @@
 //
 //========================================================================
 
-#ifndef _wayland_platform_h_
-#define _wayland_platform_h_
-
+#ifndef _glfw3_wayland_platform_h_
+#define _glfw3_wayland_platform_h_
 
 #include <wayland-client.h>
 #include <xkbcommon/xkbcommon.h>
+#include <dlfcn.h>
 
-#if defined(_GLFW_EGL)
- #include "egl_context.h"
-#else
- #error "The Wayland backend depends on EGL platform support"
-#endif
+typedef VkFlags VkWaylandSurfaceCreateFlagsKHR;
 
+typedef struct VkWaylandSurfaceCreateInfoKHR
+{
+    VkStructureType                 sType;
+    const void*                     pNext;
+    VkWaylandSurfaceCreateFlagsKHR  flags;
+    struct wl_display*              display;
+    struct wl_surface*              surface;
+} VkWaylandSurfaceCreateInfoKHR;
+
+typedef VkResult (APIENTRY *PFN_vkCreateWaylandSurfaceKHR)(VkInstance,const VkWaylandSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*);
+typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice,uint32_t,struct wl_display*);
+
 #include "posix_tls.h"
 #include "posix_time.h"
 #include "linux_joystick.h"
+#include "xkb_unicode.h"
+#include "egl_context.h"
 
-#define _GLFW_EGL_NATIVE_WINDOW         window->wl.native
-#define _GLFW_EGL_NATIVE_DISPLAY        _glfw.wl.display
+#include "wayland-relative-pointer-unstable-v1-client-protocol.h"
+#include "wayland-pointer-constraints-unstable-v1-client-protocol.h"
 
+#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
+#define _glfw_dlclose(handle) dlclose(handle)
+#define _glfw_dlsym(handle, name) dlsym(handle, name)
+
+#define _GLFW_EGL_NATIVE_WINDOW         ((EGLNativeWindowType) window->wl.native)
+#define _GLFW_EGL_NATIVE_DISPLAY        ((EGLNativeDisplayType) _glfw.wl.display)
+
 #define _GLFW_PLATFORM_WINDOW_STATE         _GLFWwindowWayland  wl
 #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWayland wl
 #define _GLFW_PLATFORM_MONITOR_STATE        _GLFWmonitorWayland wl
 #define _GLFW_PLATFORM_CURSOR_STATE         _GLFWcursorWayland  wl
 
+#define _GLFW_PLATFORM_CONTEXT_STATE
+#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE
 
+
 // Wayland-specific video mode data
 //
 typedef struct _GLFWvidmodeWayland _GLFWvidmodeWayland;
 
-
 // Wayland-specific per-window data
 //
 typedef struct _GLFWwindowWayland
 {
     int                         width, height;
-    GLboolean                   visible;
+    GLFWbool                    visible;
+    GLFWbool                    maximized;
     struct wl_surface*          surface;
     struct wl_egl_window*       native;
     struct wl_shell_surface*    shell_surface;
     struct wl_callback*         callback;
+
     _GLFWcursor*                currentCursor;
-} _GLFWwindowWayland;
+    double                      cursorPosX, cursorPosY;
 
+    char*                       title;
 
+    // We need to track the monitors the window spans on to calculate the
+    // optimal scaling factor.
+    int                         scale;
+    _GLFWmonitor**              monitors;
+    int                         monitorsCount;
+    int                         monitorsSize;
+
+    struct {
+        struct zwp_relative_pointer_v1*    relativePointer;
+        struct zwp_locked_pointer_v1*      lockedPointer;
+    } pointerLock;
+} _GLFWwindowWayland;
+
 // Wayland-specific global data
 //
 typedef struct _GLFWlibraryWayland
@@ -81,9 +116,12 @@
     struct wl_seat*             seat;
     struct wl_pointer*          pointer;
     struct wl_keyboard*         keyboard;
+    struct zwp_relative_pointer_manager_v1* relativePointerManager;
+    struct zwp_pointer_constraints_v1*      pointerConstraints;
 
+    int                         wl_compositor_version;
+
     struct wl_cursor_theme*     cursorTheme;
-    struct wl_cursor*           defaultCursor;
     struct wl_surface*          cursorSurface;
     uint32_t                    pointerSerial;
 
@@ -91,6 +129,8 @@
     int                         monitorsCount;
     int                         monitorsSize;
 
+    short int                   publicKeys[256];
+
     struct {
         struct xkb_context*     context;
         struct xkb_keymap*      keymap;
@@ -107,7 +147,6 @@
 
 } _GLFWlibraryWayland;
 
-
 // Wayland-specific per-monitor data
 //
 typedef struct _GLFWmonitorWayland
@@ -117,24 +156,24 @@
     _GLFWvidmodeWayland*        modes;
     int                         modesCount;
     int                         modesSize;
-    GLboolean                   done;
+    GLFWbool                    done;
 
     int                         x;
     int                         y;
-
+    int                         scale;
 } _GLFWmonitorWayland;
 
-
 // Wayland-specific per-cursor data
 //
 typedef struct _GLFWcursorWayland
 {
+    struct wl_cursor_image*     image;
     struct wl_buffer*           buffer;
     int                         width, height;
     int                         xhot, yhot;
 } _GLFWcursorWayland;
 
 
-void _glfwAddOutput(uint32_t name, uint32_t version);
+void _glfwAddOutputWayland(uint32_t name, uint32_t version);
 
-#endif // _wayland_platform_h_
+#endif // _glfw3_wayland_platform_h_
diff --git a/glfw/src/wl_window.c b/glfw/src/wl_window.c
--- a/glfw/src/wl_window.c
+++ b/glfw/src/wl_window.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.1 Wayland - www.glfw.org
+// GLFW 3.2 Wayland - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
 //
@@ -55,7 +55,32 @@
                             int32_t height)
 {
     _GLFWwindow* window = data;
-    _glfwInputFramebufferSize(window, width, height);
+    float aspectRatio;
+    float targetRatio;
+
+    if (!window->monitor)
+    {
+        if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE)
+        {
+            aspectRatio = (float)width / (float)height;
+            targetRatio = (float)window->numer / (float)window->denom;
+            if (aspectRatio < targetRatio)
+                height = width / targetRatio;
+            else if (aspectRatio > targetRatio)
+                width = height * targetRatio;
+        }
+
+        if (window->minwidth != GLFW_DONT_CARE && width < window->minwidth)
+            width = window->minwidth;
+        else if (window->maxwidth != GLFW_DONT_CARE && width > window->maxwidth)
+            width = window->maxwidth;
+
+        if (window->minheight != GLFW_DONT_CARE && height < window->minheight)
+            height = window->minheight;
+        else if (window->maxheight != GLFW_DONT_CARE && height > window->maxheight)
+            height = window->maxheight;
+    }
+
     _glfwInputWindowSize(window, width, height);
     _glfwPlatformSetWindowSize(window, width, height);
     _glfwInputWindowDamage(window);
@@ -72,34 +97,159 @@
     handlePopupDone
 };
 
-static GLboolean createSurface(_GLFWwindow* window,
-                               const _GLFWwndconfig* wndconfig)
+static void checkScaleChange(_GLFWwindow* window)
 {
+    int scaledWidth, scaledHeight;
+    int scale = 1;
+    int i;
+    int monitorScale;
+
+    // Check if we will be able to set the buffer scale or not.
+    if (_glfw.wl.wl_compositor_version < 3)
+        return;
+
+    // Get the scale factor from the highest scale monitor.
+    for (i = 0; i < window->wl.monitorsCount; ++i)
+    {
+        monitorScale = window->wl.monitors[i]->wl.scale;
+        if (scale < monitorScale)
+            scale = monitorScale;
+    }
+
+    // Only change the framebuffer size if the scale changed.
+    if (scale != window->wl.scale)
+    {
+        window->wl.scale = scale;
+        scaledWidth = window->wl.width * scale;
+        scaledHeight = window->wl.height * scale;
+        wl_surface_set_buffer_scale(window->wl.surface, scale);
+        wl_egl_window_resize(window->wl.native, scaledWidth, scaledHeight, 0, 0);
+        _glfwInputFramebufferSize(window, scaledWidth, scaledHeight);
+    }
+}
+
+static void handleEnter(void *data,
+                        struct wl_surface *surface,
+                        struct wl_output *output)
+{
+    _GLFWwindow* window = data;
+    _GLFWmonitor* monitor = wl_output_get_user_data(output);
+
+    if (window->wl.monitorsCount + 1 > window->wl.monitorsSize)
+    {
+        ++window->wl.monitorsSize;
+        window->wl.monitors =
+            realloc(window->wl.monitors,
+                    window->wl.monitorsSize * sizeof(_GLFWmonitor*));
+    }
+
+    window->wl.monitors[window->wl.monitorsCount++] = monitor;
+
+    checkScaleChange(window);
+}
+
+static void handleLeave(void *data,
+                        struct wl_surface *surface,
+                        struct wl_output *output)
+{
+    _GLFWwindow* window = data;
+    _GLFWmonitor* monitor = wl_output_get_user_data(output);
+    GLFWbool found;
+    int i;
+
+    for (i = 0, found = GLFW_FALSE; i < window->wl.monitorsCount - 1; ++i)
+    {
+        if (monitor == window->wl.monitors[i])
+            found = GLFW_TRUE;
+        if (found)
+            window->wl.monitors[i] = window->wl.monitors[i + 1];
+    }
+    window->wl.monitors[--window->wl.monitorsCount] = NULL;
+
+    checkScaleChange(window);
+}
+
+static const struct wl_surface_listener surfaceListener = {
+    handleEnter,
+    handleLeave
+};
+
+// Makes the surface considered as XRGB instead of ARGB.
+static void setOpaqueRegion(_GLFWwindow* window)
+{
+    struct wl_region* region;
+
+    region = wl_compositor_create_region(_glfw.wl.compositor);
+    if (!region)
+        return;
+
+    wl_region_add(region, 0, 0, window->wl.width, window->wl.height);
+    wl_surface_set_opaque_region(window->wl.surface, region);
+    wl_surface_commit(window->wl.surface);
+    wl_region_destroy(region);
+}
+
+static GLFWbool createSurface(_GLFWwindow* window,
+                              const _GLFWwndconfig* wndconfig)
+{
     window->wl.surface = wl_compositor_create_surface(_glfw.wl.compositor);
     if (!window->wl.surface)
-        return GL_FALSE;
+        return GLFW_FALSE;
 
+    wl_surface_add_listener(window->wl.surface,
+                            &surfaceListener,
+                            window);
+
     wl_surface_set_user_data(window->wl.surface, window);
 
     window->wl.native = wl_egl_window_create(window->wl.surface,
                                              wndconfig->width,
                                              wndconfig->height);
     if (!window->wl.native)
-        return GL_FALSE;
+        return GLFW_FALSE;
 
+    window->wl.width = wndconfig->width;
+    window->wl.height = wndconfig->height;
+    window->wl.scale = 1;
+
+    // TODO: make this optional once issue #197 is fixed.
+    setOpaqueRegion(window);
+
+    return GLFW_TRUE;
+}
+
+static GLFWbool createShellSurface(_GLFWwindow* window)
+{
     window->wl.shell_surface = wl_shell_get_shell_surface(_glfw.wl.shell,
                                                           window->wl.surface);
     if (!window->wl.shell_surface)
-        return GL_FALSE;
+        return GLFW_FALSE;
 
     wl_shell_surface_add_listener(window->wl.shell_surface,
                                   &shellSurfaceListener,
                                   window);
 
-    window->wl.width = wndconfig->width;
-    window->wl.height = wndconfig->height;
+    if (window->wl.title)
+        wl_shell_surface_set_title(window->wl.shell_surface, window->wl.title);
 
-    return GL_TRUE;
+    if (window->monitor)
+    {
+        wl_shell_surface_set_fullscreen(
+            window->wl.shell_surface,
+            WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
+            0,
+            window->monitor->wl.output);
+    }
+    else if (window->wl.maximized)
+    {
+        wl_shell_surface_set_maximized(window->wl.shell_surface, NULL);
+    }
+    else
+    {
+        wl_shell_surface_set_toplevel(window->wl.shell_surface);
+    }
+
+    return GLFW_TRUE;
 }
 
 static int
@@ -114,6 +264,43 @@
     return fd;
 }
 
+static void
+handleEvents(int timeout)
+{
+    struct wl_display* display = _glfw.wl.display;
+    struct pollfd fds[] = {
+        { wl_display_get_fd(display), POLLIN },
+    };
+
+    while (wl_display_prepare_read(display) != 0)
+        wl_display_dispatch_pending(display);
+
+    // If an error different from EAGAIN happens, we have likely been
+    // disconnected from the Wayland session, try to handle that the best we
+    // can.
+    if (wl_display_flush(display) < 0 && errno != EAGAIN)
+    {
+        _GLFWwindow* window = _glfw.windowListHead;
+        while (window)
+        {
+            _glfwInputWindowCloseRequest(window);
+            window = window->next;
+        }
+        wl_display_cancel_read(display);
+        return;
+    }
+
+    if (poll(fds, 1, timeout) > 0)
+    {
+        wl_display_read_events(display);
+        wl_display_dispatch_pending(display);
+    }
+    else
+    {
+        wl_display_cancel_read(display);
+    }
+}
+
 /*
  * Create a new, unique, anonymous file of the given size, and
  * return the file descriptor for it. The file descriptor is set
@@ -150,7 +337,7 @@
         return -1;
     }
 
-    name = malloc(strlen(path) + sizeof(template));
+    name = calloc(strlen(path) + sizeof(template), 1);
     strcpy(name, path);
     strcat(name, template);
 
@@ -170,6 +357,28 @@
     return fd;
 }
 
+// Translates a GLFW standard cursor to a theme cursor name
+//
+static char *translateCursorShape(int shape)
+{
+    switch (shape)
+    {
+        case GLFW_ARROW_CURSOR:
+            return "left_ptr";
+        case GLFW_IBEAM_CURSOR:
+            return "xterm";
+        case GLFW_CROSSHAIR_CURSOR:
+            return "crosshair";
+        case GLFW_HAND_CURSOR:
+            return "grabbing";
+        case GLFW_HRESIZE_CURSOR:
+            return "sb_h_double_arrow";
+        case GLFW_VRESIZE_CURSOR:
+            return "sb_v_double_arrow";
+    }
+    return NULL;
+}
+
 //////////////////////////////////////////////////////////////////////////
 //////                       GLFW platform API                      //////
 //////////////////////////////////////////////////////////////////////////
@@ -179,28 +388,40 @@
                               const _GLFWctxconfig* ctxconfig,
                               const _GLFWfbconfig* fbconfig)
 {
-    if (!_glfwCreateContext(window, ctxconfig, fbconfig))
-        return GL_FALSE;
-
     if (!createSurface(window, wndconfig))
-        return GL_FALSE;
+        return GLFW_FALSE;
 
-    if (wndconfig->monitor)
+    if (ctxconfig->client != GLFW_NO_API)
     {
-        wl_shell_surface_set_fullscreen(
-            window->wl.shell_surface,
-            WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
-            0,
-            wndconfig->monitor->wl.output);
+        if (!_glfwInitEGL())
+            return GLFW_FALSE;
+        if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
+            return GLFW_FALSE;
     }
+
+    if (wndconfig->title)
+        window->wl.title = strdup(wndconfig->title);
+
+    if (wndconfig->visible)
+    {
+        if (!createShellSurface(window))
+            return GLFW_FALSE;
+
+        window->wl.visible = GLFW_TRUE;
+    }
     else
     {
-        wl_shell_surface_set_toplevel(window->wl.shell_surface);
+        window->wl.shell_surface = NULL;
+        window->wl.visible = GLFW_FALSE;
     }
 
     window->wl.currentCursor = NULL;
 
-    return GL_TRUE;
+    window->wl.monitors = calloc(1, sizeof(_GLFWmonitor*));
+    window->wl.monitorsCount = 0;
+    window->wl.monitorsSize = 1;
+
+    return GLFW_TRUE;
 }
 
 void _glfwPlatformDestroyWindow(_GLFWwindow* window)
@@ -208,15 +429,16 @@
     if (window == _glfw.wl.pointerFocus)
     {
         _glfw.wl.pointerFocus = NULL;
-        _glfwInputCursorEnter(window, GL_FALSE);
+        _glfwInputCursorEnter(window, GLFW_FALSE);
     }
     if (window == _glfw.wl.keyboardFocus)
     {
         _glfw.wl.keyboardFocus = NULL;
-        _glfwInputWindowFocus(window, GL_FALSE);
+        _glfwInputWindowFocus(window, GLFW_FALSE);
     }
 
-    _glfwDestroyContext(window);
+    if (window->context.destroy)
+        window->context.destroy(window);
 
     if (window->wl.native)
         wl_egl_window_destroy(window->wl.native);
@@ -226,13 +448,27 @@
 
     if (window->wl.surface)
         wl_surface_destroy(window->wl.surface);
+
+    free(window->wl.title);
+    free(window->wl.monitors);
 }
 
 void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
 {
-    wl_shell_surface_set_title(window->wl.shell_surface, title);
+    if (window->wl.title)
+        free(window->wl.title);
+    window->wl.title = strdup(title);
+    if (window->wl.shell_surface)
+        wl_shell_surface_set_title(window->wl.shell_surface, title);
 }
 
+void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
+                                int count, const GLFWimage* images)
+{
+    _glfwInputError(GLFW_PLATFORM_ERROR,
+                    "Wayland: Setting window icon not supported");
+}
+
 void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
 {
     // A Wayland client is not aware of its position, so just warn and leave it
@@ -260,111 +496,157 @@
 
 void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
 {
-    wl_egl_window_resize(window->wl.native, width, height, 0, 0);
+    int scaledWidth = width * window->wl.scale;
+    int scaledHeight = height * window->wl.scale;
     window->wl.width = width;
     window->wl.height = height;
+    wl_egl_window_resize(window->wl.native, scaledWidth, scaledHeight, 0, 0);
+    setOpaqueRegion(window);
+    _glfwInputFramebufferSize(window, scaledWidth, scaledHeight);
 }
 
+void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
+                                      int minwidth, int minheight,
+                                      int maxwidth, int maxheight)
+{
+    // TODO: find out how to trigger a resize.
+    // The actual limits are checked in the wl_shell_surface::configure handler.
+}
+
+void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom)
+{
+    // TODO: find out how to trigger a resize.
+    // The actual limits are checked in the wl_shell_surface::configure handler.
+}
+
 void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height)
 {
     _glfwPlatformGetWindowSize(window, width, height);
+    *width *= window->wl.scale;
+    *height *= window->wl.scale;
 }
 
 void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
                                      int* left, int* top,
                                      int* right, int* bottom)
 {
-    // TODO
-    fprintf(stderr, "_glfwPlatformGetWindowFrameSize not implemented yet\n");
+    // TODO: will need a proper implementation once decorations are
+    // implemented, but for now just leave everything as 0.
 }
 
 void _glfwPlatformIconifyWindow(_GLFWwindow* window)
 {
-    // TODO
-    fprintf(stderr, "_glfwPlatformIconifyWindow not implemented yet\n");
+    // TODO: move to xdg_shell instead of wl_shell.
+    _glfwInputError(GLFW_PLATFORM_ERROR,
+                    "Wayland: Iconify window not supported");
 }
 
 void _glfwPlatformRestoreWindow(_GLFWwindow* window)
 {
-    // TODO
-    fprintf(stderr, "_glfwPlatformRestoreWindow not implemented yet\n");
+    // TODO: also do the same for iconified.
+    if (window->monitor || window->wl.maximized)
+    {
+        if (window->wl.shell_surface)
+            wl_shell_surface_set_toplevel(window->wl.shell_surface);
+
+        window->wl.maximized = GLFW_FALSE;
+    }
 }
 
-void _glfwPlatformShowWindow(_GLFWwindow* window)
+void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
 {
-    wl_shell_surface_set_toplevel(window->wl.shell_surface);
+    if (!window->monitor && !window->wl.maximized)
+    {
+        if (window->wl.shell_surface)
+        {
+            // Let the compositor select the best output.
+            wl_shell_surface_set_maximized(window->wl.shell_surface, NULL);
+        }
+        window->wl.maximized = GLFW_TRUE;
+    }
 }
 
-void _glfwPlatformUnhideWindow(_GLFWwindow* window)
+void _glfwPlatformShowWindow(_GLFWwindow* window)
 {
-    // TODO
-    fprintf(stderr, "_glfwPlatformUnhideWindow not implemented yet\n");
+    if (!window->monitor)
+    {
+        if (!window->wl.shell_surface)
+            createShellSurface(window);
+        window->wl.visible = GLFW_TRUE;
+    }
 }
 
 void _glfwPlatformHideWindow(_GLFWwindow* window)
 {
-    wl_surface_attach(window->wl.surface, NULL, 0, 0);
-    wl_surface_commit(window->wl.surface);
+    if (!window->monitor)
+    {
+        if (window->wl.shell_surface)
+            wl_shell_surface_destroy(window->wl.shell_surface);
+        window->wl.visible = GLFW_FALSE;
+    }
 }
 
+void _glfwPlatformFocusWindow(_GLFWwindow* window)
+{
+    _glfwInputError(GLFW_PLATFORM_ERROR,
+                    "Wayland: Focusing a window requires user interaction");
+}
+
+void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
+                                   _GLFWmonitor* monitor,
+                                   int xpos, int ypos,
+                                   int width, int height,
+                                   int refreshRate)
+{
+    if (monitor)
+    {
+        wl_shell_surface_set_fullscreen(
+            window->wl.shell_surface,
+            WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
+            refreshRate * 1000, // Convert Hz to mHz.
+            monitor->wl.output);
+    }
+    else
+    {
+        wl_shell_surface_set_toplevel(window->wl.shell_surface);
+    }
+    _glfwInputWindowMonitorChange(window, monitor);
+}
+
 int _glfwPlatformWindowFocused(_GLFWwindow* window)
 {
-    // TODO
-    return GL_FALSE;
+    return _glfw.wl.keyboardFocus == window;
 }
 
 int _glfwPlatformWindowIconified(_GLFWwindow* window)
 {
-    // TODO
-    return GL_FALSE;
+    // TODO: move to xdg_shell, wl_shell doesn't have any iconified concept.
+    return GLFW_FALSE;
 }
 
 int _glfwPlatformWindowVisible(_GLFWwindow* window)
 {
-    // TODO
-    return GL_FALSE;
+    return window->wl.visible;
 }
 
-void _glfwPlatformPollEvents(void)
+int _glfwPlatformWindowMaximized(_GLFWwindow* window)
 {
-    struct wl_display* display = _glfw.wl.display;
-    struct pollfd fds[] = {
-        { wl_display_get_fd(display), POLLIN },
-    };
+    return window->wl.maximized;
+}
 
-    while (wl_display_prepare_read(display) != 0)
-        wl_display_dispatch_pending(display);
-    wl_display_flush(display);
-    if (poll(fds, 1, 0) > 0)
-    {
-        wl_display_read_events(display);
-        wl_display_dispatch_pending(display);
-    }
-    else
-    {
-        wl_display_cancel_read(display);
-    }
+void _glfwPlatformPollEvents(void)
+{
+    handleEvents(0);
 }
 
 void _glfwPlatformWaitEvents(void)
 {
-    struct wl_display* display = _glfw.wl.display;
-    struct pollfd fds[] = {
-        { wl_display_get_fd(display), POLLIN },
-    };
+    handleEvents(-1);
+}
 
-    while (wl_display_prepare_read(display) != 0)
-        wl_display_dispatch_pending(display);
-    wl_display_flush(display);
-    if (poll(fds, 1, -1) > 0)
-    {
-        wl_display_read_events(display);
-        wl_display_dispatch_pending(display);
-    }
-    else
-    {
-        wl_display_cancel_read(display);
-    }
+void _glfwPlatformWaitEventsTimeout(double timeout)
+{
+    handleEvents((int) (timeout * 1e3));
 }
 
 void _glfwPlatformPostEmptyEvent(void)
@@ -374,22 +656,36 @@
 
 void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
 {
-    // TODO
-    fprintf(stderr, "_glfwPlatformGetCursorPos not implemented yet\n");
+    if (xpos)
+        *xpos = window->wl.cursorPosX;
+    if (ypos)
+        *ypos = window->wl.cursorPosY;
 }
 
+static GLFWbool isPointerLocked(_GLFWwindow* window);
+
 void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
 {
-    // A Wayland client can not set the cursor position
-    _glfwInputError(GLFW_PLATFORM_ERROR,
-                    "Wayland: Cursor position setting not supported");
+    if (isPointerLocked(window))
+    {
+        zwp_locked_pointer_v1_set_cursor_position_hint(
+            window->wl.pointerLock.lockedPointer,
+            wl_fixed_from_double(x), wl_fixed_from_double(y));
+        wl_surface_commit(window->wl.surface);
+    }
 }
 
-void _glfwPlatformApplyCursorMode(_GLFWwindow* window)
+void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
 {
     _glfwPlatformSetCursor(window, window->wl.currentCursor);
 }
 
+const char* _glfwPlatformGetKeyName(int key, int scancode)
+{
+    // TODO
+    return NULL;
+}
+
 int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
                               const GLFWimage* image,
                               int xhot, int yhot)
@@ -404,18 +700,18 @@
     if (fd < 0)
     {
         _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "Wayland: Creating a buffer file for %d B failed: %m\n",
+                        "Wayland: Creating a buffer file for %d B failed: %m",
                         length);
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
 
     data = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
     if (data == MAP_FAILED)
     {
         _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "Wayland: Cursor mmap failed: %m\n");
+                        "Wayland: Cursor mmap failed: %m");
         close(fd);
-        return GL_FALSE;
+        return GLFW_FALSE;
     }
 
     pool = wl_shm_create_pool(_glfw.wl.shm, fd, length);
@@ -425,10 +721,12 @@
     unsigned char* target = data;
     for (i = 0;  i < image->width * image->height;  i++, source += 4)
     {
-        *target++ = source[2];
-        *target++ = source[1];
-        *target++ = source[0];
-        *target++ = source[3];
+        unsigned int alpha = source[3];
+
+        *target++ = (unsigned char) ((source[2] * alpha) / 255);
+        *target++ = (unsigned char) ((source[1] * alpha) / 255);
+        *target++ = (unsigned char) ((source[0] * alpha) / 255);
+        *target++ = (unsigned char) alpha;
     }
 
     cursor->wl.buffer =
@@ -443,24 +741,138 @@
     cursor->wl.height = image->height;
     cursor->wl.xhot = xhot;
     cursor->wl.yhot = yhot;
-    return GL_TRUE;
+    return GLFW_TRUE;
 }
 
 int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
 {
-    // TODO
-    fprintf(stderr, "_glfwPlatformCreateStandardCursor not implemented yet\n");
-    return GL_FALSE;
+    struct wl_cursor* standardCursor;
+
+    standardCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme,
+                                                translateCursorShape(shape));
+    if (!standardCursor)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Wayland: Standard cursor \"%s\" not found",
+                        translateCursorShape(shape));
+        return GLFW_FALSE;
+    }
+
+    cursor->wl.image = standardCursor->images[0];
+    return GLFW_TRUE;
 }
 
 void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
 {
-    wl_buffer_destroy(cursor->wl.buffer);
+    // If it's a standard cursor we don't need to do anything here
+    if (cursor->wl.image)
+        return;
+
+    if (cursor->wl.buffer)
+        wl_buffer_destroy(cursor->wl.buffer);
 }
 
+static void handleRelativeMotion(void* data,
+                                 struct zwp_relative_pointer_v1* pointer,
+                                 uint32_t timeHi,
+                                 uint32_t timeLo,
+                                 wl_fixed_t dx,
+                                 wl_fixed_t dy,
+                                 wl_fixed_t dxUnaccel,
+                                 wl_fixed_t dyUnaccel)
+{
+    _GLFWwindow* window = data;
+
+    if (window->cursorMode != GLFW_CURSOR_DISABLED)
+        return;
+
+    _glfwInputCursorPos(window,
+                        window->virtualCursorPosX + wl_fixed_to_double(dxUnaccel),
+                        window->virtualCursorPosY + wl_fixed_to_double(dyUnaccel));
+}
+
+static const struct zwp_relative_pointer_v1_listener relativePointerListener = {
+    handleRelativeMotion
+};
+
+static void handleLocked(void* data,
+                         struct zwp_locked_pointer_v1* lockedPointer)
+{
+}
+
+static void unlockPointer(_GLFWwindow* window)
+{
+    struct zwp_relative_pointer_v1* relativePointer =
+        window->wl.pointerLock.relativePointer;
+    struct zwp_locked_pointer_v1* lockedPointer =
+        window->wl.pointerLock.lockedPointer;
+
+    zwp_relative_pointer_v1_destroy(relativePointer);
+    zwp_locked_pointer_v1_destroy(lockedPointer);
+
+    window->wl.pointerLock.relativePointer = NULL;
+    window->wl.pointerLock.lockedPointer = NULL;
+}
+
+static void lockPointer(_GLFWwindow* window);
+
+static void handleUnlocked(void* data,
+                           struct zwp_locked_pointer_v1* lockedPointer)
+{
+}
+
+static const struct zwp_locked_pointer_v1_listener lockedPointerListener = {
+    handleLocked,
+    handleUnlocked
+};
+
+static void lockPointer(_GLFWwindow* window)
+{
+    struct zwp_relative_pointer_v1* relativePointer;
+    struct zwp_locked_pointer_v1* lockedPointer;
+
+    if (!_glfw.wl.relativePointerManager)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Wayland: no relative pointer manager");
+        return;
+    }
+
+    relativePointer =
+        zwp_relative_pointer_manager_v1_get_relative_pointer(
+            _glfw.wl.relativePointerManager,
+            _glfw.wl.pointer);
+    zwp_relative_pointer_v1_add_listener(relativePointer,
+                                         &relativePointerListener,
+                                         window);
+
+    lockedPointer =
+        zwp_pointer_constraints_v1_lock_pointer(
+            _glfw.wl.pointerConstraints,
+            window->wl.surface,
+            _glfw.wl.pointer,
+            NULL,
+            ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
+    zwp_locked_pointer_v1_add_listener(lockedPointer,
+                                       &lockedPointerListener,
+                                       window);
+
+    window->wl.pointerLock.relativePointer = relativePointer;
+    window->wl.pointerLock.lockedPointer = lockedPointer;
+
+    wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial,
+                          NULL, 0, 0);
+}
+
+static GLFWbool isPointerLocked(_GLFWwindow* window)
+{
+    return window->wl.pointerLock.lockedPointer != NULL;
+}
+
 void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
 {
     struct wl_buffer* buffer;
+    struct wl_cursor* defaultCursor;
     struct wl_cursor_image* image;
     struct wl_surface* surface = _glfw.wl.cursorSurface;
 
@@ -474,11 +886,29 @@
     if (window != _glfw.wl.pointerFocus)
         return;
 
+    // Unlock possible pointer lock if no longer disabled.
+    if (window->cursorMode != GLFW_CURSOR_DISABLED && isPointerLocked(window))
+        unlockPointer(window);
+
     if (window->cursorMode == GLFW_CURSOR_NORMAL)
     {
-        if (cursor == NULL)
+        if (cursor)
+            image = cursor->wl.image;
+        else
         {
-            image = _glfw.wl.defaultCursor->images[0];
+            defaultCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme,
+                                                       "left_ptr");
+            if (!defaultCursor)
+            {
+                _glfwInputError(GLFW_PLATFORM_ERROR,
+                                "Wayland: Standard cursor not found");
+                return;
+            }
+            image = defaultCursor->images[0];
+        }
+
+        if (image)
+        {
             buffer = wl_cursor_image_get_buffer(image);
             if (!buffer)
                 return;
@@ -503,22 +933,118 @@
             wl_surface_commit(surface);
         }
     }
-    else /* Cursor is hidden set cursor surface to NULL */
+    else if (window->cursorMode == GLFW_CURSOR_DISABLED)
     {
-        wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial, NULL, 0, 0);
+        if (!isPointerLocked(window))
+            lockPointer(window);
     }
+    else if (window->cursorMode == GLFW_CURSOR_HIDDEN)
+    {
+        wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial,
+                              NULL, 0, 0);
+    }
 }
 
 void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
 {
     // TODO
-    fprintf(stderr, "_glfwPlatformSetClipboardString not implemented yet\n");
+    _glfwInputError(GLFW_PLATFORM_ERROR,
+                    "Wayland: Clipboard setting not implemented yet");
 }
 
 const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
 {
     // TODO
-    fprintf(stderr, "_glfwPlatformGetClipboardString not implemented yet\n");
+    _glfwInputError(GLFW_PLATFORM_ERROR,
+                    "Wayland: Clipboard getting not implemented yet");
     return NULL;
+}
+
+char** _glfwPlatformGetRequiredInstanceExtensions(uint32_t* count)
+{
+    char** extensions;
+
+    *count = 0;
+
+    if (!_glfw.vk.KHR_wayland_surface)
+        return NULL;
+
+    extensions = calloc(2, sizeof(char*));
+    extensions[0] = strdup("VK_KHR_surface");
+    extensions[1] = strdup("VK_KHR_wayland_surface");
+
+    *count = 2;
+    return extensions;
+}
+
+int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
+                                                      VkPhysicalDevice device,
+                                                      uint32_t queuefamily)
+{
+    PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR =
+        (PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)
+        vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceWaylandPresentationSupportKHR");
+    if (!vkGetPhysicalDeviceWaylandPresentationSupportKHR)
+    {
+        _glfwInputError(GLFW_API_UNAVAILABLE,
+                        "Wayland: Vulkan instance missing VK_KHR_wayland_surface extension");
+        return VK_NULL_HANDLE;
+    }
+
+    return vkGetPhysicalDeviceWaylandPresentationSupportKHR(device,
+                                                            queuefamily,
+                                                            _glfw.wl.display);
+}
+
+VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
+                                          _GLFWwindow* window,
+                                          const VkAllocationCallbacks* allocator,
+                                          VkSurfaceKHR* surface)
+{
+    VkResult err;
+    VkWaylandSurfaceCreateInfoKHR sci;
+    PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR;
+
+    vkCreateWaylandSurfaceKHR = (PFN_vkCreateWaylandSurfaceKHR)
+        vkGetInstanceProcAddr(instance, "vkCreateWaylandSurfaceKHR");
+    if (!vkCreateWaylandSurfaceKHR)
+    {
+        _glfwInputError(GLFW_API_UNAVAILABLE,
+                        "Wayland: Vulkan instance missing VK_KHR_wayland_surface extension");
+        return VK_ERROR_EXTENSION_NOT_PRESENT;
+    }
+
+    memset(&sci, 0, sizeof(sci));
+    sci.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
+    sci.display = _glfw.wl.display;
+    sci.surface = window->wl.surface;
+
+    err = vkCreateWaylandSurfaceKHR(instance, &sci, allocator, surface);
+    if (err)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Wayland: Failed to create Vulkan surface: %s",
+                        _glfwGetVulkanResultString(err));
+    }
+
+    return err;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                        GLFW native API                       //////
+//////////////////////////////////////////////////////////////////////////
+
+GLFWAPI struct wl_display* glfwGetWaylandDisplay(void)
+{
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+    return _glfw.wl.display;
+}
+
+GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* handle)
+{
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+    return window->wl.surface;
 }
 
diff --git a/glfw/src/x11_init.c b/glfw/src/x11_init.c
--- a/glfw/src/x11_init.c
+++ b/glfw/src/x11_init.c
@@ -1,8 +1,8 @@
 //========================================================================
-// GLFW 3.1 X11 - www.glfw.org
+// GLFW 3.2 X11 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -38,7 +38,7 @@
 
 // Translate an X11 key code to a GLFW key code.
 //
-static int translateKey(int scancode)
+static int translateKeyCode(int scancode)
 {
     int keySym;
 
@@ -72,9 +72,8 @@
             default:                break;
         }
 
-        // Now try primary keysym for function keys (non-printable keys). These
-        // should not be layout dependent (i.e. US layout and international
-        // layouts should give the same result).
+        // Now try primary keysym for function keys (non-printable keys)
+        // These should not depend on the current keyboard layout
         keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, 0, 0);
     }
     else
@@ -234,6 +233,7 @@
     int scancode, key;
 
     memset(_glfw.x11.publicKeys, -1, sizeof(_glfw.x11.publicKeys));
+    memset(_glfw.x11.nativeKeys, -1, sizeof(_glfw.x11.nativeKeys));
 
     if (_glfw.x11.xkb.available)
     {
@@ -241,15 +241,14 @@
         // keyboard layout
 
         char name[XkbKeyNameLength + 1];
-        XkbDescPtr descr = XkbGetKeyboard(_glfw.x11.display,
-                                          XkbAllComponentsMask,
-                                          XkbUseCoreKbd);
+        XkbDescPtr desc = XkbGetMap(_glfw.x11.display, 0, XkbUseCoreKbd);
+        XkbGetNames(_glfw.x11.display, XkbKeyNamesMask, desc);
 
         // Find the X11 key code -> GLFW key code mapping
-        for (scancode = descr->min_key_code;  scancode <= descr->max_key_code;  scancode++)
+        for (scancode = desc->min_key_code;  scancode <= desc->max_key_code;  scancode++)
         {
-            memcpy(name, descr->names->keys[scancode].name, XkbKeyNameLength);
-            name[XkbKeyNameLength] = 0;
+            memcpy(name, desc->names->keys[scancode].name, XkbKeyNameLength);
+            name[XkbKeyNameLength] = '\0';
 
             // Map the key name to a GLFW key code. Note: We only map printable
             // keys here, and we use the US keyboard layout. The rest of the
@@ -309,34 +308,39 @@
                 _glfw.x11.publicKeys[scancode] = key;
         }
 
-        XkbFreeKeyboard(descr, 0, True);
+        XkbFreeNames(desc, XkbKeyNamesMask, True);
+        XkbFreeKeyboard(desc, 0, True);
     }
 
-    // Translate the un-translated key codes using traditional X11 KeySym
-    // lookups
     for (scancode = 0;  scancode < 256;  scancode++)
     {
+        // Translate the un-translated key codes using traditional X11 KeySym
+        // lookups
         if (_glfw.x11.publicKeys[scancode] < 0)
-            _glfw.x11.publicKeys[scancode] = translateKey(scancode);
+            _glfw.x11.publicKeys[scancode] = translateKeyCode(scancode);
+
+        // Store the reverse translation for faster key name lookup
+        if (_glfw.x11.publicKeys[scancode] > 0)
+            _glfw.x11.nativeKeys[_glfw.x11.publicKeys[scancode]] = scancode;
     }
 }
 
 // Check whether the IM has a usable style
 //
-static GLboolean hasUsableInputMethodStyle(void)
+static GLFWbool hasUsableInputMethodStyle(void)
 {
     unsigned int i;
-    GLboolean found = GL_FALSE;
+    GLFWbool found = GLFW_FALSE;
     XIMStyles* styles = NULL;
 
     if (XGetIMValues(_glfw.x11.im, XNQueryInputStyle, &styles, NULL) != NULL)
-        return GL_FALSE;
+        return GLFW_FALSE;
 
     for (i = 0;  i < styles->count_styles;  i++)
     {
         if (styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing))
         {
-            found = GL_TRUE;
+            found = GLFW_TRUE;
             break;
         }
     }
@@ -351,16 +355,13 @@
                              unsigned long atomCount,
                              const char* atomName)
 {
-    Atom atom = XInternAtom(_glfw.x11.display, atomName, True);
-    if (atom != None)
-    {
-        unsigned long i;
+    unsigned long i;
+    const Atom atom = XInternAtom(_glfw.x11.display, atomName, False);
 
-        for (i = 0;  i < atomCount;  i++)
-        {
-            if (supportedAtoms[i] == atom)
-                return atom;
-        }
+    for (i = 0;  i < atomCount;  i++)
+    {
+        if (supportedAtoms[i] == atom)
+            return atom;
     }
 
     return None;
@@ -373,33 +374,31 @@
     Window* windowFromRoot = NULL;
     Window* windowFromChild = NULL;
 
-    // First we need a couple of atoms, which should already be there
-    Atom supportingWmCheck =
-        XInternAtom(_glfw.x11.display, "_NET_SUPPORTING_WM_CHECK", True);
-    Atom wmSupported =
-        XInternAtom(_glfw.x11.display, "_NET_SUPPORTED", True);
-    if (supportingWmCheck == None || wmSupported == None)
-        return;
+    // First we need a couple of atoms
+    const Atom supportingWmCheck =
+        XInternAtom(_glfw.x11.display, "_NET_SUPPORTING_WM_CHECK", False);
+    const Atom wmSupported =
+        XInternAtom(_glfw.x11.display, "_NET_SUPPORTED", False);
 
     // Then we look for the _NET_SUPPORTING_WM_CHECK property of the root window
-    if (_glfwGetWindowProperty(_glfw.x11.root,
-                               supportingWmCheck,
-                               XA_WINDOW,
-                               (unsigned char**) &windowFromRoot) != 1)
+    if (_glfwGetWindowPropertyX11(_glfw.x11.root,
+                                  supportingWmCheck,
+                                  XA_WINDOW,
+                                  (unsigned char**) &windowFromRoot) != 1)
     {
         if (windowFromRoot)
             XFree(windowFromRoot);
         return;
     }
 
-    _glfwGrabXErrorHandler();
+    _glfwGrabErrorHandlerX11();
 
     // It should be the ID of a child window (of the root)
     // Then we look for the same property on the child window
-    if (_glfwGetWindowProperty(*windowFromRoot,
-                               supportingWmCheck,
-                               XA_WINDOW,
-                               (unsigned char**) &windowFromChild) != 1)
+    if (_glfwGetWindowPropertyX11(*windowFromRoot,
+                                  supportingWmCheck,
+                                  XA_WINDOW,
+                                  (unsigned char**) &windowFromChild) != 1)
     {
         XFree(windowFromRoot);
         if (windowFromChild)
@@ -407,7 +406,7 @@
         return;
     }
 
-    _glfwReleaseXErrorHandler();
+    _glfwReleaseErrorHandlerX11();
 
     // It should be the ID of that same child window
     if (*windowFromRoot != *windowFromChild)
@@ -427,10 +426,10 @@
 
     // Now we need to check the _NET_SUPPORTED property of the root window
     // It should be a list of supported WM protocol and state atoms
-    atomCount = _glfwGetWindowProperty(_glfw.x11.root,
-                                       wmSupported,
-                                       XA_ATOM,
-                                       (unsigned char**) &supportedAtoms);
+    atomCount = _glfwGetWindowPropertyX11(_glfw.x11.root,
+                                          wmSupported,
+                                          XA_ATOM,
+                                          (unsigned char**) &supportedAtoms);
 
     // See which of the atoms we support that are supported by the WM
     _glfw.x11.NET_WM_STATE =
@@ -439,46 +438,30 @@
         getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_ABOVE");
     _glfw.x11.NET_WM_STATE_FULLSCREEN =
         getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN");
+    _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT =
+        getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_VERT");
+    _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ =
+        getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_HORZ");
     _glfw.x11.NET_WM_FULLSCREEN_MONITORS =
         getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_FULLSCREEN_MONITORS");
-    _glfw.x11.NET_WM_NAME =
-        getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_NAME");
-    _glfw.x11.NET_WM_ICON_NAME =
-        getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_ICON_NAME");
-    _glfw.x11.NET_WM_PID =
-        getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_PID");
-    _glfw.x11.NET_WM_PING =
-        getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_PING");
+    _glfw.x11.NET_WM_WINDOW_TYPE =
+        getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE");
+    _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL =
+        getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE_NORMAL");
     _glfw.x11.NET_ACTIVE_WINDOW =
         getSupportedAtom(supportedAtoms, atomCount, "_NET_ACTIVE_WINDOW");
     _glfw.x11.NET_FRAME_EXTENTS =
         getSupportedAtom(supportedAtoms, atomCount, "_NET_FRAME_EXTENTS");
     _glfw.x11.NET_REQUEST_FRAME_EXTENTS =
         getSupportedAtom(supportedAtoms, atomCount, "_NET_REQUEST_FRAME_EXTENTS");
-    _glfw.x11.NET_WM_BYPASS_COMPOSITOR =
-        getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_BYPASS_COMPOSITOR");
 
     XFree(supportedAtoms);
-
-    _glfw.x11.hasEWMH = GL_TRUE;
 }
 
 // Initialize X11 display and look for supported X11 extensions
 //
-static GLboolean initExtensions(void)
+static GLFWbool initExtensions(void)
 {
-    // Find or create window manager atoms
-    _glfw.x11.WM_PROTOCOLS = XInternAtom(_glfw.x11.display,
-                                         "WM_PROTOCOLS",
-                                         False);
-    _glfw.x11.WM_STATE = XInternAtom(_glfw.x11.display, "WM_STATE", False);
-    _glfw.x11.WM_DELETE_WINDOW = XInternAtom(_glfw.x11.display,
-                                             "WM_DELETE_WINDOW",
-                                             False);
-    _glfw.x11.MOTIF_WM_HINTS = XInternAtom(_glfw.x11.display,
-                                           "_MOTIF_WM_HINTS",
-                                           False);
-
 #if defined(_GLFW_HAS_XF86VM)
     // Check for XF86VidMode extension
     _glfw.x11.vidmode.available =
@@ -488,32 +471,29 @@
 #endif /*_GLFW_HAS_XF86VM*/
 
     // Check for RandR extension
-    _glfw.x11.randr.available =
-        XRRQueryExtension(_glfw.x11.display,
+    if (XRRQueryExtension(_glfw.x11.display,
                           &_glfw.x11.randr.eventBase,
-                          &_glfw.x11.randr.errorBase);
-
-    if (_glfw.x11.randr.available)
+                          &_glfw.x11.randr.errorBase))
     {
-        XRRScreenResources* sr;
-
-        if (!XRRQueryVersion(_glfw.x11.display,
-                             &_glfw.x11.randr.versionMajor,
-                             &_glfw.x11.randr.versionMinor))
+        if (XRRQueryVersion(_glfw.x11.display,
+                            &_glfw.x11.randr.major,
+                            &_glfw.x11.randr.minor))
         {
-            _glfwInputError(GLFW_PLATFORM_ERROR,
-                            "X11: Failed to query RandR version");
-            return GL_FALSE;
+            // The GLFW RandR path requires at least version 1.3
+            if (_glfw.x11.randr.major > 1 || _glfw.x11.randr.minor >= 3)
+                _glfw.x11.randr.available = GLFW_TRUE;
         }
-
-        // The GLFW RandR path requires at least version 1.3
-        if (_glfw.x11.randr.versionMajor == 1 &&
-            _glfw.x11.randr.versionMinor < 3)
+        else
         {
-            _glfw.x11.randr.available = GL_FALSE;
+            _glfwInputError(GLFW_PLATFORM_ERROR,
+                            "X11: Failed to query RandR version");
         }
+    }
 
-        sr = XRRGetScreenResources(_glfw.x11.display, _glfw.x11.root);
+    if (_glfw.x11.randr.available)
+    {
+        XRRScreenResources* sr = XRRGetScreenResources(_glfw.x11.display,
+                                                       _glfw.x11.root);
 
         if (!sr->ncrtc || !XRRGetCrtcGammaSize(_glfw.x11.display, sr->crtcs[0]))
         {
@@ -523,49 +503,33 @@
             // available
             _glfwInputError(GLFW_PLATFORM_ERROR,
                             "X11: RandR gamma ramp support seems broken");
-            _glfw.x11.randr.gammaBroken = GL_TRUE;
+            _glfw.x11.randr.gammaBroken = GLFW_TRUE;
         }
 
         XRRFreeScreenResources(sr);
+
+        XRRSelectInput(_glfw.x11.display, _glfw.x11.root,
+                       RROutputChangeNotifyMask);
     }
 
     if (XineramaQueryExtension(_glfw.x11.display,
-                               &_glfw.x11.xinerama.versionMajor,
-                               &_glfw.x11.xinerama.versionMinor))
+                               &_glfw.x11.xinerama.major,
+                               &_glfw.x11.xinerama.minor))
     {
         if (XineramaIsActive(_glfw.x11.display))
-            _glfw.x11.xinerama.available = GL_TRUE;
+            _glfw.x11.xinerama.available = GLFW_TRUE;
     }
 
-#if defined(_GLFW_HAS_XINPUT)
-    if (XQueryExtension(_glfw.x11.display,
-                        "XInputExtension",
-                        &_glfw.x11.xi.majorOpcode,
-                        &_glfw.x11.xi.eventBase,
-                        &_glfw.x11.xi.errorBase))
-    {
-        _glfw.x11.xi.versionMajor = 2;
-        _glfw.x11.xi.versionMinor = 0;
-
-        if (XIQueryVersion(_glfw.x11.display,
-                           &_glfw.x11.xi.versionMajor,
-                           &_glfw.x11.xi.versionMinor) != BadRequest)
-        {
-            _glfw.x11.xi.available = GL_TRUE;
-        }
-    }
-#endif /*_GLFW_HAS_XINPUT*/
-
     // Check if Xkb is supported on this display
-    _glfw.x11.xkb.versionMajor = 1;
-    _glfw.x11.xkb.versionMinor = 0;
+    _glfw.x11.xkb.major = 1;
+    _glfw.x11.xkb.minor = 0;
     _glfw.x11.xkb.available =
         XkbQueryExtension(_glfw.x11.display,
                           &_glfw.x11.xkb.majorOpcode,
                           &_glfw.x11.xkb.eventBase,
                           &_glfw.x11.xkb.errorBase,
-                          &_glfw.x11.xkb.versionMajor,
-                          &_glfw.x11.xkb.versionMinor);
+                          &_glfw.x11.xkb.major,
+                          &_glfw.x11.xkb.minor);
 
     if (_glfw.x11.xkb.available)
     {
@@ -574,10 +538,17 @@
         if (XkbSetDetectableAutoRepeat(_glfw.x11.display, True, &supported))
         {
             if (supported)
-                _glfw.x11.xkb.detectable = GL_TRUE;
+                _glfw.x11.xkb.detectable = GLFW_TRUE;
         }
     }
 
+    _glfw.x11.x11xcb.handle = dlopen("libX11-xcb.so", RTLD_LAZY | RTLD_GLOBAL);
+    if (_glfw.x11.x11xcb.handle)
+    {
+        _glfw.x11.x11xcb.XGetXCBConnection = (XGETXCBCONNECTION_T)
+            dlsym(_glfw.x11.x11xcb.handle, "XGetXCBConnection");
+    }
+
     // Update the key code LUT
     // FIXME: We should listen to XkbMapNotify events to track changes to
     // the keyboard mapping.
@@ -586,7 +557,7 @@
     // Detect whether an EWMH-conformant window manager is running
     detectEWMH();
 
-    // Find or create string format atoms
+    // String format atoms
     _glfw.x11.NULL_ = XInternAtom(_glfw.x11.display, "NULL", False);
     _glfw.x11.UTF8_STRING =
         XInternAtom(_glfw.x11.display, "UTF8_STRING", False);
@@ -594,45 +565,69 @@
         XInternAtom(_glfw.x11.display, "COMPOUND_STRING", False);
     _glfw.x11.ATOM_PAIR = XInternAtom(_glfw.x11.display, "ATOM_PAIR", False);
 
-    // Find or create selection property atom
+    // Custom selection property atom
     _glfw.x11.GLFW_SELECTION =
         XInternAtom(_glfw.x11.display, "GLFW_SELECTION", False);
 
-    // Find or create standard clipboard atoms
+    // ICCCM standard clipboard atoms
     _glfw.x11.TARGETS = XInternAtom(_glfw.x11.display, "TARGETS", False);
     _glfw.x11.MULTIPLE = XInternAtom(_glfw.x11.display, "MULTIPLE", False);
     _glfw.x11.CLIPBOARD = XInternAtom(_glfw.x11.display, "CLIPBOARD", False);
 
-    // Find or create clipboard manager atoms
+    // Clipboard manager atoms
     _glfw.x11.CLIPBOARD_MANAGER =
         XInternAtom(_glfw.x11.display, "CLIPBOARD_MANAGER", False);
     _glfw.x11.SAVE_TARGETS =
         XInternAtom(_glfw.x11.display, "SAVE_TARGETS", False);
 
-    // Find Xdnd (drag and drop) atoms, if available
-    _glfw.x11.XdndAware = XInternAtom(_glfw.x11.display, "XdndAware", True);
-    _glfw.x11.XdndEnter = XInternAtom(_glfw.x11.display, "XdndEnter", True);
-    _glfw.x11.XdndPosition = XInternAtom(_glfw.x11.display, "XdndPosition", True);
-    _glfw.x11.XdndStatus = XInternAtom(_glfw.x11.display, "XdndStatus", True);
-    _glfw.x11.XdndActionCopy = XInternAtom(_glfw.x11.display, "XdndActionCopy", True);
-    _glfw.x11.XdndDrop = XInternAtom(_glfw.x11.display, "XdndDrop", True);
-    _glfw.x11.XdndLeave = XInternAtom(_glfw.x11.display, "XdndLeave", True);
-    _glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", True);
-    _glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", True);
+    // Xdnd (drag and drop) atoms
+    _glfw.x11.XdndAware = XInternAtom(_glfw.x11.display, "XdndAware", False);
+    _glfw.x11.XdndEnter = XInternAtom(_glfw.x11.display, "XdndEnter", False);
+    _glfw.x11.XdndPosition = XInternAtom(_glfw.x11.display, "XdndPosition", False);
+    _glfw.x11.XdndStatus = XInternAtom(_glfw.x11.display, "XdndStatus", False);
+    _glfw.x11.XdndActionCopy = XInternAtom(_glfw.x11.display, "XdndActionCopy", False);
+    _glfw.x11.XdndDrop = XInternAtom(_glfw.x11.display, "XdndDrop", False);
+    _glfw.x11.XdndLeave = XInternAtom(_glfw.x11.display, "XdndLeave", False);
+    _glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", False);
+    _glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", False);
 
-    return GL_TRUE;
+    // ICCCM, EWMH and Motif window property atoms
+    // These can be set safely even without WM support
+    // The EWMH atoms that require WM support are handled in detectEWMH
+    _glfw.x11.WM_PROTOCOLS =
+        XInternAtom(_glfw.x11.display, "WM_PROTOCOLS", False);
+    _glfw.x11.WM_STATE =
+        XInternAtom(_glfw.x11.display, "WM_STATE", False);
+    _glfw.x11.WM_DELETE_WINDOW =
+        XInternAtom(_glfw.x11.display, "WM_DELETE_WINDOW", False);
+    _glfw.x11.NET_WM_ICON =
+        XInternAtom(_glfw.x11.display, "_NET_WM_ICON", False);
+    _glfw.x11.NET_WM_PING =
+        XInternAtom(_glfw.x11.display, "_NET_WM_PING", False);
+    _glfw.x11.NET_WM_PID =
+        XInternAtom(_glfw.x11.display, "_NET_WM_PID", False);
+    _glfw.x11.NET_WM_NAME =
+        XInternAtom(_glfw.x11.display, "_NET_WM_NAME", False);
+    _glfw.x11.NET_WM_ICON_NAME =
+        XInternAtom(_glfw.x11.display, "_NET_WM_ICON_NAME", False);
+    _glfw.x11.NET_WM_BYPASS_COMPOSITOR =
+        XInternAtom(_glfw.x11.display, "_NET_WM_BYPASS_COMPOSITOR", False);
+    _glfw.x11.MOTIF_WM_HINTS =
+        XInternAtom(_glfw.x11.display, "_MOTIF_WM_HINTS", False);
+
+    return GLFW_TRUE;
 }
 
 // Create a blank cursor for hidden and disabled cursor modes
 //
-static Cursor createNULLCursor(void)
+static Cursor createHiddenCursor(void)
 {
     unsigned char pixels[16 * 16 * 4];
     GLFWimage image = { 16, 16, pixels };
 
     memset(pixels, 0, sizeof(pixels));
 
-    return _glfwCreateCursor(&image, 0, 0);
+    return _glfwCreateCursorX11(&image, 0, 0);
 }
 
 // X error handler
@@ -650,7 +645,7 @@
 
 // Sets the X error handler callback
 //
-void _glfwGrabXErrorHandler(void)
+void _glfwGrabErrorHandlerX11(void)
 {
     _glfw.x11.errorCode = Success;
     XSetErrorHandler(errorHandler);
@@ -658,7 +653,7 @@
 
 // Clears the X error handler callback
 //
-void _glfwReleaseXErrorHandler(void)
+void _glfwReleaseErrorHandlerX11(void)
 {
     // Synchronize to make sure all commands are processed
     XSync(_glfw.x11.display, False);
@@ -667,7 +662,7 @@
 
 // Reports the specified error, appending information about the last X error
 //
-void _glfwInputXError(int error, const char* message)
+void _glfwInputErrorX11(int error, const char* message)
 {
     char buffer[8192];
     XGetErrorText(_glfw.x11.display, _glfw.x11.errorCode,
@@ -678,7 +673,7 @@
 
 // Creates a native cursor object from the specified image and hotspot
 //
-Cursor _glfwCreateCursor(const GLFWimage* image, int xhot, int yhot)
+Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot)
 {
     int i;
     Cursor cursor;
@@ -695,10 +690,12 @@
 
     for (i = 0;  i < image->width * image->height;  i++, target++, source += 4)
     {
-        *target = (source[3] << 24) |
-                  (source[0] << 16) |
-                  (source[1] <<  8) |
-                   source[2];
+        unsigned int alpha = source[3];
+
+        *target = (alpha << 24) |
+                  ((unsigned char) ((source[0] * alpha) / 255) << 16) |
+                  ((unsigned char) ((source[1] * alpha) / 255) <<  8) |
+                  ((unsigned char) ((source[2] * alpha) / 255) <<  0);
     }
 
     cursor = XcursorImageLoadCursor(_glfw.x11.display, native);
@@ -714,16 +711,31 @@
 
 int _glfwPlatformInit(void)
 {
+#if !defined(X_HAVE_UTF8_STRING)
+    // HACK: If the current locale is C, apply the environment's locale
+    //       This is done because the C locale breaks wide character input
     if (strcmp(setlocale(LC_CTYPE, NULL), "C") == 0)
         setlocale(LC_CTYPE, "");
+#endif
 
     XInitThreads();
 
     _glfw.x11.display = XOpenDisplay(NULL);
     if (!_glfw.x11.display)
     {
-        _glfwInputError(GLFW_API_UNAVAILABLE, "X11: Failed to open X display");
-        return GL_FALSE;
+        const char* display = getenv("DISPLAY");
+        if (display)
+        {
+            _glfwInputError(GLFW_PLATFORM_ERROR,
+                            "X11: Failed to open display %s", display);
+        }
+        else
+        {
+            _glfwInputError(GLFW_PLATFORM_ERROR,
+                            "X11: The DISPLAY environment variable is missing");
+        }
+
+        return GLFW_FALSE;
     }
 
     _glfw.x11.screen = DefaultScreen(_glfw.x11.display);
@@ -731,15 +743,15 @@
     _glfw.x11.context = XUniqueContext();
 
     if (!initExtensions())
-        return GL_FALSE;
+        return GLFW_FALSE;
 
-    _glfw.x11.cursor = createNULLCursor();
+    _glfw.x11.cursor = createHiddenCursor();
 
     if (XSupportsLocale())
     {
         XSetLocaleModifiers("");
 
-        _glfw.x11.im = XOpenIM(_glfw.x11.display, 0, 0, 0);
+        _glfw.x11.im = XOpenIM(_glfw.x11.display, 0, NULL, NULL);
         if (_glfw.x11.im)
         {
             if (!hasUsableInputMethodStyle())
@@ -750,19 +762,25 @@
         }
     }
 
-    if (!_glfwInitContextAPI())
-        return GL_FALSE;
+    if (!_glfwInitThreadLocalStoragePOSIX())
+        return GLFW_FALSE;
 
-    if (!_glfwInitJoysticks())
-        return GL_FALSE;
+    if (!_glfwInitJoysticksLinux())
+        return GLFW_FALSE;
 
-    _glfwInitTimer();
+    _glfwInitTimerPOSIX();
 
-    return GL_TRUE;
+    return GLFW_TRUE;
 }
 
 void _glfwPlatformTerminate(void)
 {
+    if (_glfw.x11.x11xcb.handle)
+    {
+        dlclose(_glfw.x11.x11xcb.handle);
+        _glfw.x11.x11xcb.handle = NULL;
+    }
+
     if (_glfw.x11.cursor)
     {
         XFreeCursor(_glfw.x11.display, _glfw.x11.cursor);
@@ -777,44 +795,39 @@
         _glfw.x11.im = NULL;
     }
 
-    _glfwTerminateJoysticks();
-    _glfwTerminateContextAPI();
+    _glfwTerminateEGL();
 
     if (_glfw.x11.display)
     {
         XCloseDisplay(_glfw.x11.display);
         _glfw.x11.display = NULL;
     }
+
+    // NOTE: This needs to be done after XCloseDisplay, as libGL registers
+    //       cleanup callbacks that get called by it
+    _glfwTerminateGLX();
+
+    _glfwTerminateJoysticksLinux();
+    _glfwTerminateThreadLocalStoragePOSIX();
 }
 
 const char* _glfwPlatformGetVersionString(void)
 {
-    const char* version = _GLFW_VERSION_NUMBER " X11"
-#if defined(_GLFW_GLX)
-        " GLX"
-#elif defined(_GLFW_EGL)
-        " EGL"
-#endif
-#if defined(_GLFW_HAS_GLXGETPROCADDRESS)
-        " glXGetProcAddress"
-#elif defined(_GLFW_HAS_GLXGETPROCADDRESSARB)
-        " glXGetProcAddressARB"
-#elif defined(_GLFW_HAS_GLXGETPROCADDRESSEXT)
-        " glXGetProcAddressEXT"
-#elif defined(_GLFW_DLOPEN_LIBGL)
-        " dlsym(libGL)"
-#endif
+    return _GLFW_VERSION_NUMBER " X11 GLX EGL"
 #if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK)
         " clock_gettime"
+#else
+        " gettimeofday"
 #endif
 #if defined(__linux__)
         " /dev/js"
 #endif
+#if defined(_GLFW_HAS_XF86VM)
+        " Xf86vm"
+#endif
 #if defined(_GLFW_BUILD_DLL)
         " shared"
 #endif
         ;
-
-    return version;
 }
 
diff --git a/glfw/src/x11_monitor.c b/glfw/src/x11_monitor.c
--- a/glfw/src/x11_monitor.c
+++ b/glfw/src/x11_monitor.c
@@ -1,8 +1,8 @@
 //========================================================================
-// GLFW 3.1 X11 - www.glfw.org
+// GLFW 3.2 X11 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -34,7 +34,7 @@
 
 // Check whether the display mode should be included in enumeration
 //
-static GLboolean modeIsGood(const XRRModeInfo* mi)
+static GLFWbool modeIsGood(const XRRModeInfo* mi)
 {
     return (mi->modeFlags & RR_Interlace) == 0;
 }
@@ -97,7 +97,7 @@
 
 // Set the current video mode for the specified monitor
 //
-GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired)
+GLFWbool _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired)
 {
     if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
     {
@@ -112,7 +112,7 @@
         best = _glfwChooseVideoMode(monitor, desired);
         _glfwPlatformGetVideoMode(monitor, &current);
         if (_glfwCompareVideoModes(&current, best) == 0)
-            return GL_TRUE;
+            return GLFW_TRUE;
 
         sr = XRRGetScreenResources(_glfw.x11.display, _glfw.x11.root);
         ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
@@ -155,16 +155,16 @@
         {
             _glfwInputError(GLFW_PLATFORM_ERROR,
                             "X11: Monitor mode list changed");
-            return GL_FALSE;
+            return GLFW_FALSE;
         }
     }
 
-    return GL_TRUE;
+    return GLFW_TRUE;
 }
 
 // Restore the saved (original) video mode for the specified monitor
 //
-void _glfwRestoreVideoMode(_GLFWmonitor* monitor)
+void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor)
 {
     if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
     {
@@ -200,7 +200,7 @@
 
 _GLFWmonitor** _glfwPlatformGetMonitors(int* count)
 {
-    int i, j, k, size = 0, found = 0;
+    int i, j, k, found = 0;
     _GLFWmonitor** monitors = NULL;
 
     *count = 0;
@@ -214,6 +214,8 @@
         RROutput primary = XRRGetOutputPrimary(_glfw.x11.display,
                                                _glfw.x11.root);
 
+        monitors = calloc(sr->noutput, sizeof(_GLFWmonitor*));
+
         if (_glfw.x11.xinerama.available)
             screens = XineramaQueryScreens(_glfw.x11.display, &screenCount);
 
@@ -225,6 +227,7 @@
             for (j = 0;  j < ci->noutput;  j++)
             {
                 int widthMM, heightMM;
+                _GLFWmonitor* monitor;
                 XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display,
                                                      sr, ci->outputs[j]);
                 if (oi->connection != RR_Connected)
@@ -233,12 +236,6 @@
                     continue;
                 }
 
-                if (found == size)
-                {
-                    size += 4;
-                    monitors = realloc(monitors, sizeof(_GLFWmonitor*) * size);
-                }
-
                 if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270)
                 {
                     widthMM  = oi->mm_height;
@@ -250,9 +247,9 @@
                     heightMM = oi->mm_height;
                 }
 
-                monitors[found] = _glfwAllocMonitor(oi->name, widthMM, heightMM);
-                monitors[found]->x11.output = ci->outputs[j];
-                monitors[found]->x11.crtc   = oi->crtc;
+                monitor = _glfwAllocMonitor(oi->name, widthMM, heightMM);
+                monitor->x11.output = ci->outputs[j];
+                monitor->x11.crtc   = oi->crtc;
 
                 for (k = 0;  k < screenCount;  k++)
                 {
@@ -261,17 +258,18 @@
                         screens[k].width == ci->width &&
                         screens[k].height == ci->height)
                     {
-                        monitors[found]->x11.index = k;
+                        monitor->x11.index = k;
                         break;
                     }
                 }
 
                 XRRFreeOutputInfo(oi);
 
-                if (ci->outputs[j] == primary)
-                    _GLFW_SWAP_POINTERS(monitors[0], monitors[found]);
-
                 found++;
+                monitors[found - 1] = monitor;
+
+                if (ci->outputs[j] == primary)
+                    _GLFW_SWAP_POINTERS(monitors[0], monitors[found - 1]);
             }
 
             XRRFreeCrtcInfo(ci);
@@ -286,7 +284,10 @@
         {
             _glfwInputError(GLFW_PLATFORM_ERROR,
                             "X11: RandR monitor support seems broken");
-            _glfw.x11.randr.monitorBroken = GL_TRUE;
+
+            _glfw.x11.randr.monitorBroken = GLFW_TRUE;
+            free(monitors);
+            monitors = NULL;
         }
     }
 
@@ -305,7 +306,7 @@
     return monitors;
 }
 
-GLboolean _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
+GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
 {
     return first->x11.crtc == second->x11.crtc;
 }
@@ -330,13 +331,11 @@
     }
 }
 
-GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
+GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
 {
     GLFWvidmode* result;
 
-    *found = 0;
-
-    // Build array of available resolutions
+    *count = 0;
 
     if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
     {
@@ -359,20 +358,18 @@
 
             const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci);
 
-            for (j = 0;  j < *found;  j++)
+            for (j = 0;  j < *count;  j++)
             {
                 if (_glfwCompareVideoModes(result + j, &mode) == 0)
                     break;
             }
 
-            if (j < *found)
-            {
-                // This is a duplicate, so skip it
+            // Skip duplicate modes
+            if (j < *count)
                 continue;
-            }
 
-            result[*found] = mode;
-            (*found)++;
+            (*count)++;
+            result[*count - 1] = mode;
         }
 
         XRRFreeOutputInfo(oi);
@@ -381,7 +378,7 @@
     }
     else
     {
-        *found = 1;
+        *count = 1;
         result = calloc(1, sizeof(GLFWvidmode));
         _glfwPlatformGetVideoMode(monitor, result);
     }
diff --git a/glfw/src/x11_platform.h b/glfw/src/x11_platform.h
--- a/glfw/src/x11_platform.h
+++ b/glfw/src/x11_platform.h
@@ -1,8 +1,8 @@
 //========================================================================
-// GLFW 3.1 X11 - www.glfw.org
+// GLFW 3.2 X11 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -25,12 +25,13 @@
 //
 //========================================================================
 
-#ifndef _x11_platform_h_
-#define _x11_platform_h_
+#ifndef _glfw3_x11_platform_h_
+#define _glfw3_x11_platform_h_
 
 #include <unistd.h>
 #include <signal.h>
 #include <stdint.h>
+#include <dlfcn.h>
 
 #include <X11/Xlib.h>
 #include <X11/keysym.h>
@@ -46,34 +47,56 @@
 // The Xinerama extension provides legacy monitor indices
 #include <X11/extensions/Xinerama.h>
 
-#if defined(_GLFW_HAS_XINPUT)
- // The XInput2 extension provides improved input events
- #include <X11/extensions/XInput2.h>
-#endif
-
 #if defined(_GLFW_HAS_XF86VM)
  // The Xf86VidMode extension provides fallback gamma control
  #include <X11/extensions/xf86vmode.h>
 #endif
 
-#include "posix_tls.h"
+typedef XID xcb_window_t;
+typedef XID xcb_visualid_t;
+typedef struct xcb_connection_t xcb_connection_t;
+typedef xcb_connection_t* (* XGETXCBCONNECTION_T)(Display*);
 
-#if defined(_GLFW_GLX)
- #define _GLFW_X11_CONTEXT_VISUAL window->glx.visual
- #include "glx_context.h"
-#elif defined(_GLFW_EGL)
- #define _GLFW_X11_CONTEXT_VISUAL window->egl.visual
- #define _GLFW_EGL_NATIVE_WINDOW  window->x11.handle
- #define _GLFW_EGL_NATIVE_DISPLAY _glfw.x11.display
- #include "egl_context.h"
-#else
- #error "No supported context creation API selected"
-#endif
+typedef VkFlags VkXlibSurfaceCreateFlagsKHR;
+typedef VkFlags VkXcbSurfaceCreateFlagsKHR;
 
+typedef struct VkXlibSurfaceCreateInfoKHR
+{
+    VkStructureType             sType;
+    const void*                 pNext;
+    VkXlibSurfaceCreateFlagsKHR flags;
+    Display*                    dpy;
+    Window                      window;
+} VkXlibSurfaceCreateInfoKHR;
+
+typedef struct VkXcbSurfaceCreateInfoKHR
+{
+    VkStructureType             sType;
+    const void*                 pNext;
+    VkXcbSurfaceCreateFlagsKHR  flags;
+    xcb_connection_t*           connection;
+    xcb_window_t                window;
+} VkXcbSurfaceCreateInfoKHR;
+
+typedef VkResult (APIENTRY *PFN_vkCreateXlibSurfaceKHR)(VkInstance,const VkXlibSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*);
+typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice,uint32_t,Display*,VisualID);
+typedef VkResult (APIENTRY *PFN_vkCreateXcbSurfaceKHR)(VkInstance,const VkXcbSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*);
+typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice,uint32_t,xcb_connection_t*,xcb_visualid_t);
+
+#include "posix_tls.h"
 #include "posix_time.h"
 #include "linux_joystick.h"
 #include "xkb_unicode.h"
+#include "glx_context.h"
+#include "egl_context.h"
 
+#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
+#define _glfw_dlclose(handle) dlclose(handle)
+#define _glfw_dlsym(handle, name) dlsym(handle, name)
+
+#define _GLFW_EGL_NATIVE_WINDOW  ((EGLNativeWindowType) window->x11.handle)
+#define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.x11.display)
+
 #define _GLFW_PLATFORM_WINDOW_STATE         _GLFWwindowX11  x11
 #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11
 #define _GLFW_PLATFORM_MONITOR_STATE        _GLFWmonitorX11 x11
@@ -88,19 +111,22 @@
     Window          handle;
     XIC             ic;
 
-    GLboolean       overrideRedirect;
+    GLFWbool        overrideRedirect;
 
     // Cached position and size used to filter out duplicate events
     int             width, height;
     int             xpos, ypos;
 
     // The last received cursor position, regardless of source
-    double          cursorPosX, cursorPosY;
+    int             lastCursorPosX, lastCursorPosY;
     // The last position the cursor was warped to by GLFW
-    int             warpPosX, warpPosY;
+    int             warpCursorPosX, warpCursorPosY;
 
-} _GLFWwindowX11;
+    // The information from the last KeyPress event
+    unsigned int    lastKeyCode;
+    Time            lastKeyTime;
 
+} _GLFWwindowX11;
 
 // X11-specific global data
 //
@@ -116,14 +142,20 @@
     XContext        context;
     // XIM input method
     XIM             im;
-    // True if window manager supports EWMH
-    GLboolean       hasEWMH;
     // Most recent error code received by X error handler
     int             errorCode;
     // Clipboard string (while the selection is owned)
     char*           clipboardString;
+    // Key name string
+    char            keyName[64];
     // X11 keycode to GLFW key LUT
     short int       publicKeys[256];
+    // GLFW key to X11 keycode LUT
+    short int       nativeKeys[GLFW_KEY_LAST + 1];
+    // Where to place the cursor when re-enabled
+    double          restoreCursorPosX, restoreCursorPosY;
+    // The window whose disabled cursor mode is active
+    _GLFWwindow*    disabledCursorWindow;
 
     // Window manager atoms
     Atom            WM_PROTOCOLS;
@@ -131,11 +163,16 @@
     Atom            WM_DELETE_WINDOW;
     Atom            NET_WM_NAME;
     Atom            NET_WM_ICON_NAME;
+    Atom            NET_WM_ICON;
     Atom            NET_WM_PID;
     Atom            NET_WM_PING;
+    Atom            NET_WM_WINDOW_TYPE;
+    Atom            NET_WM_WINDOW_TYPE_NORMAL;
     Atom            NET_WM_STATE;
     Atom            NET_WM_STATE_ABOVE;
     Atom            NET_WM_STATE_FULLSCREEN;
+    Atom            NET_WM_STATE_MAXIMIZED_VERT;
+    Atom            NET_WM_STATE_MAXIMIZED_HORZ;
     Atom            NET_WM_BYPASS_COMPOSITOR;
     Atom            NET_WM_FULLSCREEN_MONITORS;
     Atom            NET_ACTIVE_WINDOW;
@@ -167,23 +204,23 @@
     Atom            GLFW_SELECTION;
 
     struct {
-        GLboolean   available;
+        GLFWbool    available;
         int         eventBase;
         int         errorBase;
-        int         versionMajor;
-        int         versionMinor;
-        GLboolean   gammaBroken;
-        GLboolean   monitorBroken;
+        int         major;
+        int         minor;
+        GLFWbool    gammaBroken;
+        GLFWbool    monitorBroken;
     } randr;
 
     struct {
-        GLboolean   available;
-        GLboolean   detectable;
+        GLFWbool    available;
+        GLFWbool    detectable;
         int         majorOpcode;
         int         eventBase;
         int         errorBase;
-        int         versionMajor;
-        int         versionMinor;
+        int         major;
+        int         minor;
     } xkb;
 
     struct {
@@ -199,25 +236,19 @@
     } xdnd;
 
     struct {
-        GLboolean   available;
-        int         versionMajor;
-        int         versionMinor;
+        GLFWbool    available;
+        int         major;
+        int         minor;
     } xinerama;
 
-#if defined(_GLFW_HAS_XINPUT)
     struct {
-        GLboolean   available;
-        int         majorOpcode;
-        int         eventBase;
-        int         errorBase;
-        int         versionMajor;
-        int         versionMinor;
-    } xi;
-#endif /*_GLFW_HAS_XINPUT*/
+        void*       handle;
+        XGETXCBCONNECTION_T XGetXCBConnection;
+    } x11xcb;
 
 #if defined(_GLFW_HAS_XF86VM)
     struct {
-        GLboolean   available;
+        GLFWbool    available;
         int         eventBase;
         int         errorBase;
     } vidmode;
@@ -225,7 +256,6 @@
 
 } _GLFWlibraryX11;
 
-
 // X11-specific per-monitor data
 //
 typedef struct _GLFWmonitorX11
@@ -240,7 +270,6 @@
 
 } _GLFWmonitorX11;
 
-
 // X11-specific per-cursor data
 //
 typedef struct _GLFWcursorX11
@@ -250,18 +279,18 @@
 } _GLFWcursorX11;
 
 
-GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired);
-void _glfwRestoreVideoMode(_GLFWmonitor* monitor);
+GLFWbool _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired);
+void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor);
 
-Cursor _glfwCreateCursor(const GLFWimage* image, int xhot, int yhot);
+Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot);
 
-unsigned long _glfwGetWindowProperty(Window window,
-                                     Atom property,
-                                     Atom type,
-                                     unsigned char** value);
+unsigned long _glfwGetWindowPropertyX11(Window window,
+                                        Atom property,
+                                        Atom type,
+                                        unsigned char** value);
 
-void _glfwGrabXErrorHandler(void);
-void _glfwReleaseXErrorHandler(void);
-void _glfwInputXError(int error, const char* message);
+void _glfwGrabErrorHandlerX11(void);
+void _glfwReleaseErrorHandlerX11(void);
+void _glfwInputErrorX11(int error, const char* message);
 
-#endif // _x11_platform_h_
+#endif // _glfw3_x11_platform_h_
diff --git a/glfw/src/x11_window.c b/glfw/src/x11_window.c
--- a/glfw/src/x11_window.c
+++ b/glfw/src/x11_window.c
@@ -1,1924 +1,2458 @@
 //========================================================================
-// GLFW 3.1 X11 - www.glfw.org
-//------------------------------------------------------------------------
-// Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
-//
-// 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 <X11/cursorfont.h>
-#include <X11/Xmd.h>
-
-#include <sys/select.h>
-
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-
-// Action for EWMH client messages
-#define _NET_WM_STATE_REMOVE        0
-#define _NET_WM_STATE_ADD           1
-#define _NET_WM_STATE_TOGGLE        2
-
-// Additional mouse button names for XButtonEvent
-#define Button6            6
-#define Button7            7
-
-typedef struct
-{
-    unsigned long flags;
-    unsigned long functions;
-    unsigned long decorations;
-    long input_mode;
-    unsigned long status;
-} MotifWmHints;
-
-#define MWM_HINTS_DECORATIONS (1L << 1)
-
-
-// Returns whether the window is iconified
-//
-static int getWindowState(_GLFWwindow* window)
-{
-    int result = WithdrawnState;
-    struct {
-        CARD32 state;
-        Window icon;
-    } *state = NULL;
-
-    if (_glfwGetWindowProperty(window->x11.handle,
-                               _glfw.x11.WM_STATE,
-                               _glfw.x11.WM_STATE,
-                               (unsigned char**) &state) >= 2)
-    {
-        result = state->state;
-    }
-
-    XFree(state);
-    return result;
-}
-
-// Returns whether the event is a selection event
-//
-static Bool isFrameExtentsEvent(Display* display, XEvent* event, XPointer pointer)
-{
-    _GLFWwindow* window = (_GLFWwindow*) pointer;
-    return event->type == PropertyNotify &&
-           event->xproperty.state == PropertyNewValue &&
-           event->xproperty.window == window->x11.handle &&
-           event->xproperty.atom == _glfw.x11.NET_FRAME_EXTENTS;
-}
-
-// Translates a GLFW standard cursor to a font cursor shape
-//
-static int translateCursorShape(int shape)
-{
-    switch (shape)
-    {
-        case GLFW_ARROW_CURSOR:
-            return XC_arrow;
-        case GLFW_IBEAM_CURSOR:
-            return XC_xterm;
-        case GLFW_CROSSHAIR_CURSOR:
-            return XC_crosshair;
-        case GLFW_HAND_CURSOR:
-            return XC_hand1;
-        case GLFW_HRESIZE_CURSOR:
-            return XC_sb_h_double_arrow;
-        case GLFW_VRESIZE_CURSOR:
-            return XC_sb_v_double_arrow;
-    }
-
-    return 0;
-}
-
-// Translates an X event modifier state mask
-//
-static int translateState(int state)
-{
-    int mods = 0;
-
-    if (state & ShiftMask)
-        mods |= GLFW_MOD_SHIFT;
-    if (state & ControlMask)
-        mods |= GLFW_MOD_CONTROL;
-    if (state & Mod1Mask)
-        mods |= GLFW_MOD_ALT;
-    if (state & Mod4Mask)
-        mods |= GLFW_MOD_SUPER;
-
-    return mods;
-}
-
-// Translates an X Window key to internal coding
-//
-static int translateKey(int scancode)
-{
-    // Use the pre-filled LUT (see createKeyTables() in x11_init.c)
-    if (scancode < 0 || scancode > 255)
-        return GLFW_KEY_UNKNOWN;
-
-    return _glfw.x11.publicKeys[scancode];
-}
-
-// Return the GLFW window corresponding to the specified X11 window
-//
-static _GLFWwindow* findWindowByHandle(Window handle)
-{
-    _GLFWwindow* window;
-
-    if (XFindContext(_glfw.x11.display,
-                     handle,
-                     _glfw.x11.context,
-                     (XPointer*) &window) != 0)
-    {
-        return NULL;
-    }
-
-    return window;
-}
-
-// Adds or removes an EWMH state to a window
-//
-static void changeWindowState(_GLFWwindow* window, Atom state, int action)
-{
-    XEvent event;
-    memset(&event, 0, sizeof(event));
-
-    event.type = ClientMessage;
-    event.xclient.window = window->x11.handle;
-    event.xclient.format = 32; // Data is 32-bit longs
-    event.xclient.message_type = _glfw.x11.NET_WM_STATE;
-    event.xclient.data.l[0] = action;
-    event.xclient.data.l[1] = state;
-    event.xclient.data.l[2] = 0; // No secondary property
-    event.xclient.data.l[3] = 1; // Sender is a normal application
-
-    XSendEvent(_glfw.x11.display,
-               _glfw.x11.root,
-               False,
-               SubstructureNotifyMask | SubstructureRedirectMask,
-               &event);
-}
-
-// Splits and translates a text/uri-list into separate file paths
-// NOTE: This function destroys the provided string
-//
-static char** parseUriList(char* text, int* count)
-{
-    const char* prefix = "file://";
-    char** paths = NULL;
-    char* line;
-
-    *count = 0;
-
-    while ((line = strtok(text, "\r\n")))
-    {
-        text = NULL;
-
-        if (line[0] == '#')
-            continue;
-
-        if (strncmp(line, prefix, strlen(prefix)) == 0)
-            line += strlen(prefix);
-
-        (*count)++;
-
-        char* path = calloc(strlen(line) + 1, 1);
-        paths = realloc(paths, *count * sizeof(char*));
-        paths[*count - 1] = path;
-
-        while (*line)
-        {
-            if (line[0] == '%' && line[1] && line[2])
-            {
-                const char digits[3] = { line[1], line[2], '\0' };
-                *path = strtol(digits, NULL, 16);
-                line += 2;
-            }
-            else
-                *path = *line;
-
-            path++;
-            line++;
-        }
-    }
-
-    return paths;
-}
-
-// Create the X11 window (and its colormap)
-//
-static GLboolean createWindow(_GLFWwindow* window,
-                              const _GLFWwndconfig* wndconfig)
-{
-    unsigned long wamask;
-    XSetWindowAttributes wa;
-    XVisualInfo* visual = _GLFW_X11_CONTEXT_VISUAL;
-
-    // Every window needs a colormap
-    // Create one based on the visual used by the current context
-    // TODO: Decouple this from context creation
-
-    window->x11.colormap = XCreateColormap(_glfw.x11.display,
-                                           _glfw.x11.root,
-                                           visual->visual,
-                                           AllocNone);
-
-    // Create the actual window
-    {
-        wamask = CWBorderPixel | CWColormap | CWEventMask;
-
-        wa.colormap = window->x11.colormap;
-        wa.border_pixel = 0;
-        wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask |
-                        PointerMotionMask | ButtonPressMask | ButtonReleaseMask |
-                        ExposureMask | FocusChangeMask | VisibilityChangeMask |
-                        EnterWindowMask | LeaveWindowMask | PropertyChangeMask;
-
-        _glfwGrabXErrorHandler();
-
-        window->x11.handle = XCreateWindow(_glfw.x11.display,
-                                           _glfw.x11.root,
-                                           0, 0,
-                                           wndconfig->width, wndconfig->height,
-                                           0,              // Border width
-                                           visual->depth,  // Color depth
-                                           InputOutput,
-                                           visual->visual,
-                                           wamask,
-                                           &wa);
-
-        _glfwReleaseXErrorHandler();
-
-        if (!window->x11.handle)
-        {
-            _glfwInputXError(GLFW_PLATFORM_ERROR,
-                             "X11: Failed to create window");
-            return GL_FALSE;
-        }
-
-        if (!wndconfig->decorated)
-        {
-            MotifWmHints hints;
-            hints.flags = MWM_HINTS_DECORATIONS;
-            hints.decorations = 0;
-
-            XChangeProperty(_glfw.x11.display, window->x11.handle,
-                            _glfw.x11.MOTIF_WM_HINTS,
-                            _glfw.x11.MOTIF_WM_HINTS, 32,
-                            PropModeReplace,
-                            (unsigned char*) &hints,
-                            sizeof(MotifWmHints) / sizeof(long));
-        }
-
-        XSaveContext(_glfw.x11.display,
-                     window->x11.handle,
-                     _glfw.x11.context,
-                     (XPointer) window);
-    }
-
-    if (window->monitor && !_glfw.x11.hasEWMH)
-    {
-        // This is the butcher's way of removing window decorations
-        // Setting the override-redirect attribute on a window makes the window
-        // manager ignore the window completely (ICCCM, section 4)
-        // The good thing is that this makes undecorated full screen windows
-        // easy to do; the bad thing is that we have to do everything manually
-        // and some things (like iconify/restore) won't work at all, as those
-        // are tasks usually performed by the window manager
-
-        XSetWindowAttributes attributes;
-        attributes.override_redirect = True;
-        XChangeWindowAttributes(_glfw.x11.display,
-                                window->x11.handle,
-                                CWOverrideRedirect,
-                                &attributes);
-
-        window->x11.overrideRedirect = GL_TRUE;
-    }
-
-    // Declare the WM protocols supported by GLFW
-    {
-        int count = 0;
-        Atom protocols[2];
-
-        // The WM_DELETE_WINDOW ICCCM protocol
-        // Basic window close notification protocol
-        if (_glfw.x11.WM_DELETE_WINDOW)
-            protocols[count++] = _glfw.x11.WM_DELETE_WINDOW;
-
-        // The _NET_WM_PING EWMH protocol
-        // Tells the WM to ping the GLFW window and flag the application as
-        // unresponsive if the WM doesn't get a reply within a few seconds
-        if (_glfw.x11.NET_WM_PING)
-            protocols[count++] = _glfw.x11.NET_WM_PING;
-
-        if (count > 0)
-        {
-            XSetWMProtocols(_glfw.x11.display, window->x11.handle,
-                            protocols, count);
-        }
-    }
-
-    if (_glfw.x11.NET_WM_PID)
-    {
-        const pid_t pid = getpid();
-
-        XChangeProperty(_glfw.x11.display,  window->x11.handle,
-                        _glfw.x11.NET_WM_PID, XA_CARDINAL, 32,
-                        PropModeReplace,
-                        (unsigned char*) &pid, 1);
-    }
-
-    // Set ICCCM WM_HINTS property
-    {
-        XWMHints* hints = XAllocWMHints();
-        if (!hints)
-        {
-            _glfwInputError(GLFW_OUT_OF_MEMORY,
-                            "X11: Failed to allocate WM hints");
-            return GL_FALSE;
-        }
-
-        hints->flags = StateHint;
-        hints->initial_state = NormalState;
-
-        XSetWMHints(_glfw.x11.display, window->x11.handle, hints);
-        XFree(hints);
-    }
-
-    // Set ICCCM WM_NORMAL_HINTS property (even if no parts are set)
-    {
-        XSizeHints* hints = XAllocSizeHints();
-        hints->flags = 0;
-
-        if (wndconfig->monitor)
-        {
-            hints->flags |= PPosition;
-            _glfwPlatformGetMonitorPos(wndconfig->monitor, &hints->x, &hints->y);
-        }
-        else
-        {
-            // HACK: Explicitly setting PPosition to any value causes some WMs,
-            //       notably Compiz and Metacity, to honor the position of
-            //       unmapped windows set by XMoveWindow
-            hints->flags |= PPosition;
-            hints->x = hints->y = 0;
-        }
-
-        if (!wndconfig->resizable)
-        {
-            hints->flags |= (PMinSize | PMaxSize);
-            hints->min_width  = hints->max_width  = wndconfig->width;
-            hints->min_height = hints->max_height = wndconfig->height;
-        }
-
-        XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints);
-        XFree(hints);
-    }
-
-    // Set ICCCM WM_CLASS property
-    // HACK: Until a mechanism for specifying the application name is added, the
-    //       initial window title is used as the window class name
-    if (strlen(wndconfig->title))
-    {
-        XClassHint* hint = XAllocClassHint();
-        hint->res_name = (char*) wndconfig->title;
-        hint->res_class = (char*) wndconfig->title;
-
-        XSetClassHint(_glfw.x11.display, window->x11.handle, hint);
-        XFree(hint);
-    }
-
-#if defined(_GLFW_HAS_XINPUT)
-    if (_glfw.x11.xi.available)
-    {
-        // Select for XInput2 events
-
-        XIEventMask eventmask;
-        unsigned char mask[] = { 0 };
-
-        eventmask.deviceid = 2;
-        eventmask.mask_len = sizeof(mask);
-        eventmask.mask = mask;
-        XISetMask(mask, XI_Motion);
-
-        XISelectEvents(_glfw.x11.display, window->x11.handle, &eventmask, 1);
-    }
-#endif /*_GLFW_HAS_XINPUT*/
-
-    if (_glfw.x11.XdndAware)
-    {
-        // Announce support for Xdnd (drag and drop)
-        const Atom version = 5;
-        XChangeProperty(_glfw.x11.display, window->x11.handle,
-                        _glfw.x11.XdndAware, XA_ATOM, 32,
-                        PropModeReplace, (unsigned char*) &version, 1);
-    }
-
-    if (_glfw.x11.NET_REQUEST_FRAME_EXTENTS)
-    {
-        // Ensure _NET_FRAME_EXTENTS is set, allowing glfwGetWindowFrameSize to
-        // function before the window is mapped
-
-        XEvent event;
-        memset(&event, 0, sizeof(event));
-
-        event.type = ClientMessage;
-        event.xclient.window = window->x11.handle;
-        event.xclient.format = 32; // Data is 32-bit longs
-        event.xclient.message_type = _glfw.x11.NET_REQUEST_FRAME_EXTENTS;
-
-        XSendEvent(_glfw.x11.display,
-                   _glfw.x11.root,
-                   False,
-                   SubstructureNotifyMask | SubstructureRedirectMask,
-                   &event);
-        XIfEvent(_glfw.x11.display, &event, isFrameExtentsEvent, (XPointer) window);
-    }
-
-    if (wndconfig->floating && !wndconfig->monitor)
-    {
-        if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_ABOVE)
-        {
-            changeWindowState(window,
-                              _glfw.x11.NET_WM_STATE_ABOVE,
-                              _NET_WM_STATE_ADD);
-        }
-    }
-
-    _glfwPlatformSetWindowTitle(window, wndconfig->title);
-
-    XRRSelectInput(_glfw.x11.display, window->x11.handle,
-                   RRScreenChangeNotifyMask);
-
-    if (_glfw.x11.im)
-    {
-        window->x11.ic = XCreateIC(_glfw.x11.im,
-                                   XNInputStyle,
-                                   XIMPreeditNothing | XIMStatusNothing,
-                                   XNClientWindow,
-                                   window->x11.handle,
-                                   XNFocusWindow,
-                                   window->x11.handle,
-                                   NULL);
-    }
-
-    _glfwPlatformGetWindowPos(window, &window->x11.xpos, &window->x11.ypos);
-    _glfwPlatformGetWindowSize(window, &window->x11.width, &window->x11.height);
-
-    return GL_TRUE;
-}
-
-// Hide the mouse cursor
-//
-static void hideCursor(_GLFWwindow* window)
-{
-    XUngrabPointer(_glfw.x11.display, CurrentTime);
-    XDefineCursor(_glfw.x11.display, window->x11.handle, _glfw.x11.cursor);
-}
-
-// Disable the mouse cursor
-//
-static void disableCursor(_GLFWwindow* window)
-{
-    XGrabPointer(_glfw.x11.display, window->x11.handle, True,
-                 ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
-                 GrabModeAsync, GrabModeAsync,
-                 window->x11.handle, _glfw.x11.cursor, CurrentTime);
-}
-
-// Restores the mouse cursor
-//
-static void restoreCursor(_GLFWwindow* window)
-{
-    XUngrabPointer(_glfw.x11.display, CurrentTime);
-
-    if (window->cursor)
-    {
-        XDefineCursor(_glfw.x11.display, window->x11.handle,
-                      window->cursor->x11.handle);
-    }
-    else
-        XUndefineCursor(_glfw.x11.display, window->x11.handle);
-}
-
-// Returns whether the event is a selection event
-//
-static Bool isSelectionEvent(Display* display, XEvent* event, XPointer pointer)
-{
-    return event->type == SelectionRequest ||
-           event->type == SelectionNotify ||
-           event->type == SelectionClear;
-}
-
-// Set the specified property to the selection converted to the requested target
-//
-static Atom writeTargetToProperty(const XSelectionRequestEvent* request)
-{
-    int i;
-    const Atom formats[] = { _glfw.x11.UTF8_STRING,
-                             _glfw.x11.COMPOUND_STRING,
-                             XA_STRING };
-    const int formatCount = sizeof(formats) / sizeof(formats[0]);
-
-    if (request->property == None)
-    {
-        // The requester is a legacy client (ICCCM section 2.2)
-        // We don't support legacy clients, so fail here
-        return None;
-    }
-
-    if (request->target == _glfw.x11.TARGETS)
-    {
-        // The list of supported targets was requested
-
-        const Atom targets[] = { _glfw.x11.TARGETS,
-                                 _glfw.x11.MULTIPLE,
-                                 _glfw.x11.UTF8_STRING,
-                                 _glfw.x11.COMPOUND_STRING,
-                                 XA_STRING };
-
-        XChangeProperty(_glfw.x11.display,
-                        request->requestor,
-                        request->property,
-                        XA_ATOM,
-                        32,
-                        PropModeReplace,
-                        (unsigned char*) targets,
-                        sizeof(targets) / sizeof(targets[0]));
-
-        return request->property;
-    }
-
-    if (request->target == _glfw.x11.MULTIPLE)
-    {
-        // Multiple conversions were requested
-
-        Atom* targets;
-        unsigned long i, count;
-
-        count = _glfwGetWindowProperty(request->requestor,
-                                       request->property,
-                                       _glfw.x11.ATOM_PAIR,
-                                       (unsigned char**) &targets);
-
-        for (i = 0;  i < count;  i += 2)
-        {
-            int j;
-
-            for (j = 0;  j < formatCount;  j++)
-            {
-                if (targets[i] == formats[j])
-                    break;
-            }
-
-            if (j < formatCount)
-            {
-                XChangeProperty(_glfw.x11.display,
-                                request->requestor,
-                                targets[i + 1],
-                                targets[i],
-                                8,
-                                PropModeReplace,
-                                (unsigned char*) _glfw.x11.clipboardString,
-                                strlen(_glfw.x11.clipboardString));
-            }
-            else
-                targets[i + 1] = None;
-        }
-
-        XChangeProperty(_glfw.x11.display,
-                        request->requestor,
-                        request->property,
-                        _glfw.x11.ATOM_PAIR,
-                        32,
-                        PropModeReplace,
-                        (unsigned char*) targets,
-                        count);
-
-        XFree(targets);
-
-        return request->property;
-    }
-
-    if (request->target == _glfw.x11.SAVE_TARGETS)
-    {
-        // The request is a check whether we support SAVE_TARGETS
-        // It should be handled as a no-op side effect target
-
-        XChangeProperty(_glfw.x11.display,
-                        request->requestor,
-                        request->property,
-                        _glfw.x11.NULL_,
-                        32,
-                        PropModeReplace,
-                        NULL,
-                        0);
-
-        return request->property;
-    }
-
-    // Conversion to a data target was requested
-
-    for (i = 0;  i < formatCount;  i++)
-    {
-        if (request->target == formats[i])
-        {
-            // The requested target is one we support
-
-            XChangeProperty(_glfw.x11.display,
-                            request->requestor,
-                            request->property,
-                            request->target,
-                            8,
-                            PropModeReplace,
-                            (unsigned char*) _glfw.x11.clipboardString,
-                            strlen(_glfw.x11.clipboardString));
-
-            return request->property;
-        }
-    }
-
-    // The requested target is not supported
-
-    return None;
-}
-
-static void handleSelectionClear(XEvent* event)
-{
-    free(_glfw.x11.clipboardString);
-    _glfw.x11.clipboardString = NULL;
-}
-
-static void handleSelectionRequest(XEvent* event)
-{
-    const XSelectionRequestEvent* request = &event->xselectionrequest;
-
-    XEvent response;
-    memset(&response, 0, sizeof(response));
-
-    response.xselection.property = writeTargetToProperty(request);
-    response.xselection.type = SelectionNotify;
-    response.xselection.display = request->display;
-    response.xselection.requestor = request->requestor;
-    response.xselection.selection = request->selection;
-    response.xselection.target = request->target;
-    response.xselection.time = request->time;
-
-    XSendEvent(_glfw.x11.display, request->requestor, False, 0, &response);
-}
-
-static void pushSelectionToManager(_GLFWwindow* window)
-{
-    XConvertSelection(_glfw.x11.display,
-                      _glfw.x11.CLIPBOARD_MANAGER,
-                      _glfw.x11.SAVE_TARGETS,
-                      None,
-                      window->x11.handle,
-                      CurrentTime);
-
-    for (;;)
-    {
-        XEvent event;
-
-        if (!XCheckIfEvent(_glfw.x11.display, &event, isSelectionEvent, NULL))
-            continue;
-
-        switch (event.type)
-        {
-            case SelectionRequest:
-                handleSelectionRequest(&event);
-                break;
-
-            case SelectionClear:
-                handleSelectionClear(&event);
-                break;
-
-            case SelectionNotify:
-            {
-                if (event.xselection.target == _glfw.x11.SAVE_TARGETS)
-                {
-                    // This means one of two things; either the selection was
-                    // not owned, which means there is no clipboard manager, or
-                    // the transfer to the clipboard manager has completed
-                    // In either case, it means we are done here
-                    return;
-                }
-
-                break;
-            }
-        }
-    }
-}
-
-// Enter full screen mode
-//
-static void enterFullscreenMode(_GLFWwindow* window)
-{
-    if (_glfw.x11.saver.count == 0)
-    {
-        // Remember old screen saver settings
-        XGetScreenSaver(_glfw.x11.display,
-                        &_glfw.x11.saver.timeout,
-                        &_glfw.x11.saver.interval,
-                        &_glfw.x11.saver.blanking,
-                        &_glfw.x11.saver.exposure);
-
-        // Disable screen saver
-        XSetScreenSaver(_glfw.x11.display, 0, 0, DontPreferBlanking,
-                        DefaultExposures);
-    }
-
-    _glfw.x11.saver.count++;
-
-    _glfwSetVideoMode(window->monitor, &window->videoMode);
-
-    if (_glfw.x11.NET_WM_BYPASS_COMPOSITOR)
-    {
-        const unsigned long value = 1;
-
-        XChangeProperty(_glfw.x11.display,  window->x11.handle,
-                        _glfw.x11.NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32,
-                        PropModeReplace, (unsigned char*) &value, 1);
-    }
-
-    if (_glfw.x11.xinerama.available && _glfw.x11.NET_WM_FULLSCREEN_MONITORS)
-    {
-        XEvent event;
-        memset(&event, 0, sizeof(event));
-
-        event.type = ClientMessage;
-        event.xclient.window = window->x11.handle;
-        event.xclient.format = 32; // Data is 32-bit longs
-        event.xclient.message_type = _glfw.x11.NET_WM_FULLSCREEN_MONITORS;
-        event.xclient.data.l[0] = window->monitor->x11.index;
-        event.xclient.data.l[1] = window->monitor->x11.index;
-        event.xclient.data.l[2] = window->monitor->x11.index;
-        event.xclient.data.l[3] = window->monitor->x11.index;
-
-        XSendEvent(_glfw.x11.display,
-                   _glfw.x11.root,
-                   False,
-                   SubstructureNotifyMask | SubstructureRedirectMask,
-                   &event);
-    }
-
-    if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN)
-    {
-        int x, y;
-        _glfwPlatformGetMonitorPos(window->monitor, &x, &y);
-        _glfwPlatformSetWindowPos(window, x, y);
-
-        if (_glfw.x11.NET_ACTIVE_WINDOW)
-        {
-            // Ask the window manager to raise and focus the GLFW window
-            // Only focused windows with the _NET_WM_STATE_FULLSCREEN state end
-            // up on top of all other windows ("Stacking order" in EWMH spec)
-
-            XEvent event;
-            memset(&event, 0, sizeof(event));
-
-            event.type = ClientMessage;
-            event.xclient.window = window->x11.handle;
-            event.xclient.format = 32; // Data is 32-bit longs
-            event.xclient.message_type = _glfw.x11.NET_ACTIVE_WINDOW;
-            event.xclient.data.l[0] = 1; // Sender is a normal application
-            event.xclient.data.l[1] = 0; // We don't really know the timestamp
-
-            XSendEvent(_glfw.x11.display,
-                       _glfw.x11.root,
-                       False,
-                       SubstructureNotifyMask | SubstructureRedirectMask,
-                       &event);
-        }
-
-        // Ask the window manager to make the GLFW window a full screen window
-        // Full screen windows are undecorated and, when focused, are kept
-        // on top of all other windows
-
-        changeWindowState(window,
-                          _glfw.x11.NET_WM_STATE_FULLSCREEN,
-                          _NET_WM_STATE_ADD);
-    }
-    else if (window->x11.overrideRedirect)
-    {
-        // In override-redirect mode we have divorced ourselves from the
-        // window manager, so we need to do everything manually
-        int xpos, ypos;
-        GLFWvidmode mode;
-
-        _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos);
-        _glfwPlatformGetVideoMode(window->monitor, &mode);
-
-        XRaiseWindow(_glfw.x11.display, window->x11.handle);
-        XSetInputFocus(_glfw.x11.display, window->x11.handle,
-                       RevertToParent, CurrentTime);
-        XMoveWindow(_glfw.x11.display, window->x11.handle, xpos, ypos);
-        XResizeWindow(_glfw.x11.display, window->x11.handle,
-                      mode.width, mode.height);
-    }
-}
-
-// Leave full screen mode
-//
-static void leaveFullscreenMode(_GLFWwindow* window)
-{
-    _glfwRestoreVideoMode(window->monitor);
-
-    _glfw.x11.saver.count--;
-
-    if (_glfw.x11.saver.count == 0)
-    {
-        // Restore old screen saver settings
-        XSetScreenSaver(_glfw.x11.display,
-                        _glfw.x11.saver.timeout,
-                        _glfw.x11.saver.interval,
-                        _glfw.x11.saver.blanking,
-                        _glfw.x11.saver.exposure);
-    }
-
-    if (_glfw.x11.NET_WM_BYPASS_COMPOSITOR)
-    {
-        const unsigned long value = 0;
-
-        XChangeProperty(_glfw.x11.display,  window->x11.handle,
-                        _glfw.x11.NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32,
-                        PropModeReplace, (unsigned char*) &value, 1);
-    }
-
-    if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN)
-    {
-        // Ask the window manager to make the GLFW window a normal window
-        // Normal windows usually have frames and other decorations
-
-        changeWindowState(window,
-                          _glfw.x11.NET_WM_STATE_FULLSCREEN,
-                          _NET_WM_STATE_REMOVE);
-    }
-}
-
-// Process the specified X event
-//
-static void processEvent(XEvent *event)
-{
-    _GLFWwindow* window = NULL;
-
-    if (event->type != GenericEvent)
-    {
-        window = findWindowByHandle(event->xany.window);
-        if (window == NULL)
-        {
-            // This is an event for a window that has already been destroyed
-            return;
-        }
-    }
-
-    switch (event->type)
-    {
-        case KeyPress:
-        {
-            const int key = translateKey(event->xkey.keycode);
-            const int mods = translateState(event->xkey.state);
-            const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
-
-            if (event->xkey.keycode)
-                _glfwInputKey(window, key, event->xkey.keycode, GLFW_PRESS, mods);
-
-            if (window->x11.ic)
-            {
-                // Translate keys to characters with XIM input context
-
-                int i;
-                Status status;
-                wchar_t buffer[16];
-
-                if (XFilterEvent(event, None))
-                {
-                    // Discard intermediary (dead key) events for character input
-                    break;
-                }
-
-                const int count = XwcLookupString(window->x11.ic,
-                                                  &event->xkey,
-                                                  buffer, sizeof(buffer),
-                                                  NULL, &status);
-
-                for (i = 0;  i < count;  i++)
-                    _glfwInputChar(window, buffer[i], mods, plain);
-            }
-            else
-            {
-                // Translate keys to characters with fallback lookup table
-
-                KeySym keysym;
-                XLookupString(&event->xkey, NULL, 0, &keysym, NULL);
-
-                const long character = _glfwKeySym2Unicode(keysym);
-                if (character != -1)
-                    _glfwInputChar(window, character, mods, plain);
-            }
-
-            break;
-        }
-
-        case KeyRelease:
-        {
-            const int key = translateKey(event->xkey.keycode);
-            const int mods = translateState(event->xkey.state);
-
-            if (!_glfw.x11.xkb.detectable)
-            {
-                // HACK: Key repeat events will arrive as KeyRelease/KeyPress
-                //       pairs with similar or identical time stamps
-                //       The key repeat logic in _glfwInputKey expects only key
-                //       presses to repeat, so detect and discard release events
-                if (XEventsQueued(_glfw.x11.display, QueuedAfterReading))
-                {
-                    XEvent nextEvent;
-                    XPeekEvent(_glfw.x11.display, &nextEvent);
-
-                    if (nextEvent.type == KeyPress &&
-                        nextEvent.xkey.window == event->xkey.window &&
-                        nextEvent.xkey.keycode == event->xkey.keycode)
-                    {
-                        // HACK: Repeat events sometimes leak through due to
-                        //       some sort of time drift, so add an epsilon
-                        //       Toshiyuki Takahashi can press a button 16 times
-                        //       per second so it's fairly safe to assume that
-                        //       no human is pressing the key 50 times per
-                        //       second (value is ms)
-                        if ((nextEvent.xkey.time - event->xkey.time) < 20)
-                        {
-                            // This is very likely a server-generated key repeat
-                            // event, so ignore it
-                            break;
-                        }
-                    }
-                }
-            }
-
-            _glfwInputKey(window, key, event->xkey.keycode, GLFW_RELEASE, mods);
-            break;
-        }
-
-        case ButtonPress:
-        {
-            const int mods = translateState(event->xbutton.state);
-
-            if (event->xbutton.button == Button1)
-                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS, mods);
-            else if (event->xbutton.button == Button2)
-                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS, mods);
-            else if (event->xbutton.button == Button3)
-                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS, mods);
-
-            // Modern X provides scroll events as mouse button presses
-            else if (event->xbutton.button == Button4)
-                _glfwInputScroll(window, 0.0, 1.0);
-            else if (event->xbutton.button == Button5)
-                _glfwInputScroll(window, 0.0, -1.0);
-            else if (event->xbutton.button == Button6)
-                _glfwInputScroll(window, 1.0, 0.0);
-            else if (event->xbutton.button == Button7)
-                _glfwInputScroll(window, -1.0, 0.0);
-
-            else
-            {
-                // Additional buttons after 7 are treated as regular buttons
-                // We subtract 4 to fill the gap left by scroll input above
-                _glfwInputMouseClick(window,
-                                     event->xbutton.button - 4,
-                                     GLFW_PRESS,
-                                     mods);
-            }
-
-            break;
-        }
-
-        case ButtonRelease:
-        {
-            const int mods = translateState(event->xbutton.state);
-
-            if (event->xbutton.button == Button1)
-            {
-                _glfwInputMouseClick(window,
-                                     GLFW_MOUSE_BUTTON_LEFT,
-                                     GLFW_RELEASE,
-                                     mods);
-            }
-            else if (event->xbutton.button == Button2)
-            {
-                _glfwInputMouseClick(window,
-                                     GLFW_MOUSE_BUTTON_MIDDLE,
-                                     GLFW_RELEASE,
-                                     mods);
-            }
-            else if (event->xbutton.button == Button3)
-            {
-                _glfwInputMouseClick(window,
-                                     GLFW_MOUSE_BUTTON_RIGHT,
-                                     GLFW_RELEASE,
-                                     mods);
-            }
-            else if (event->xbutton.button > Button7)
-            {
-                // Additional buttons after 7 are treated as regular buttons
-                // We subtract 4 to fill the gap left by scroll input above
-                _glfwInputMouseClick(window,
-                                     event->xbutton.button - 4,
-                                     GLFW_RELEASE,
-                                     mods);
-            }
-            break;
-        }
-
-        case EnterNotify:
-        {
-            _glfwInputCursorEnter(window, GL_TRUE);
-            break;
-        }
-
-        case LeaveNotify:
-        {
-            _glfwInputCursorEnter(window, GL_FALSE);
-            break;
-        }
-
-        case MotionNotify:
-        {
-            const int x = event->xmotion.x;
-            const int y = event->xmotion.y;
-
-            if (x != window->x11.warpPosX || y != window->x11.warpPosY)
-            {
-                // The cursor was moved by something other than GLFW
-
-                if (window->cursorMode == GLFW_CURSOR_DISABLED)
-                {
-                    if (_glfw.focusedWindow != window)
-                        break;
-
-                    _glfwInputCursorMotion(window,
-                                           x - window->x11.cursorPosX,
-                                           y - window->x11.cursorPosY);
-                }
-                else
-                    _glfwInputCursorMotion(window, x, y);
-            }
-
-            window->x11.cursorPosX = x;
-            window->x11.cursorPosY = y;
-            break;
-        }
-
-        case ConfigureNotify:
-        {
-            if (event->xconfigure.width != window->x11.width ||
-                event->xconfigure.height != window->x11.height)
-            {
-                _glfwInputFramebufferSize(window,
-                                          event->xconfigure.width,
-                                          event->xconfigure.height);
-
-                _glfwInputWindowSize(window,
-                                     event->xconfigure.width,
-                                     event->xconfigure.height);
-
-                window->x11.width = event->xconfigure.width;
-                window->x11.height = event->xconfigure.height;
-            }
-
-            if (event->xconfigure.x != window->x11.xpos ||
-                event->xconfigure.y != window->x11.ypos)
-            {
-                _glfwInputWindowPos(window,
-                                    event->xconfigure.x,
-                                    event->xconfigure.y);
-
-                window->x11.xpos = event->xconfigure.x;
-                window->x11.ypos = event->xconfigure.y;
-            }
-
-            break;
-        }
-
-        case ClientMessage:
-        {
-            // Custom client message, probably from the window manager
-
-            if (event->xclient.message_type == None)
-                break;
-
-            if (event->xclient.message_type == _glfw.x11.WM_PROTOCOLS)
-            {
-                if (_glfw.x11.WM_DELETE_WINDOW &&
-                    (Atom) event->xclient.data.l[0] == _glfw.x11.WM_DELETE_WINDOW)
-                {
-                    // The window manager was asked to close the window, for example by
-                    // the user pressing a 'close' window decoration button
-
-                    _glfwInputWindowCloseRequest(window);
-                }
-                else if (_glfw.x11.NET_WM_PING &&
-                        (Atom) event->xclient.data.l[0] == _glfw.x11.NET_WM_PING)
-                {
-                    // The window manager is pinging the application to ensure it's
-                    // still responding to events
-
-                    event->xclient.window = _glfw.x11.root;
-                    XSendEvent(_glfw.x11.display,
-                            event->xclient.window,
-                            False,
-                            SubstructureNotifyMask | SubstructureRedirectMask,
-                            event);
-                }
-            }
-            else if (event->xclient.message_type == _glfw.x11.XdndEnter)
-            {
-                // A drag operation has entered the window
-                // TODO: Check if UTF-8 string is supported by the source
-            }
-            else if (event->xclient.message_type == _glfw.x11.XdndDrop)
-            {
-                // The drag operation has finished dropping on
-                // the window, ask to convert it to a UTF-8 string
-                _glfw.x11.xdnd.source = event->xclient.data.l[0];
-                XConvertSelection(_glfw.x11.display,
-                                  _glfw.x11.XdndSelection,
-                                  _glfw.x11.UTF8_STRING,
-                                  _glfw.x11.XdndSelection,
-                                  window->x11.handle, CurrentTime);
-            }
-            else if (event->xclient.message_type == _glfw.x11.XdndPosition)
-            {
-                // The drag operation has moved over the window
-                const int absX = (event->xclient.data.l[2] >> 16) & 0xFFFF;
-                const int absY = (event->xclient.data.l[2]) & 0xFFFF;
-                int x, y;
-
-                _glfwPlatformGetWindowPos(window, &x, &y);
-                _glfwInputCursorMotion(window, absX - x, absY - y);
-
-                // Reply that we are ready to copy the dragged data
-                XEvent reply;
-                memset(&reply, 0, sizeof(reply));
-
-                reply.type = ClientMessage;
-                reply.xclient.window = event->xclient.data.l[0];
-                reply.xclient.message_type = _glfw.x11.XdndStatus;
-                reply.xclient.format = 32;
-                reply.xclient.data.l[0] = window->x11.handle;
-                reply.xclient.data.l[1] = 1; // Always accept the dnd with no rectangle
-                reply.xclient.data.l[2] = 0; // Specify an empty rectangle
-                reply.xclient.data.l[3] = 0;
-                reply.xclient.data.l[4] = _glfw.x11.XdndActionCopy;
-
-                XSendEvent(_glfw.x11.display, event->xclient.data.l[0],
-                           False, NoEventMask, &reply);
-                XFlush(_glfw.x11.display);
-            }
-
-            break;
-        }
-
-        case SelectionNotify:
-        {
-            if (event->xselection.property)
-            {
-                // The converted data from the drag operation has arrived
-                char* data;
-                const int result =
-                    _glfwGetWindowProperty(event->xselection.requestor,
-                                           event->xselection.property,
-                                           event->xselection.target,
-                                           (unsigned char**) &data);
-
-                if (result)
-                {
-                    int i, count;
-                    char** paths = parseUriList(data, &count);
-
-                    _glfwInputDrop(window, count, (const char**) paths);
-
-                    for (i = 0;  i < count;  i++)
-                        free(paths[i]);
-                    free(paths);
-                }
-
-                XFree(data);
-
-                XEvent reply;
-                memset(&reply, 0, sizeof(reply));
-
-                reply.type = ClientMessage;
-                reply.xclient.window = _glfw.x11.xdnd.source;
-                reply.xclient.message_type = _glfw.x11.XdndFinished;
-                reply.xclient.format = 32;
-                reply.xclient.data.l[0] = window->x11.handle;
-                reply.xclient.data.l[1] = result;
-                reply.xclient.data.l[2] = _glfw.x11.XdndActionCopy;
-
-                // Reply that all is well
-                XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source,
-                           False, NoEventMask, &reply);
-                XFlush(_glfw.x11.display);
-            }
-
-            break;
-        }
-
-        case FocusIn:
-        {
-            if (event->xfocus.mode == NotifyNormal)
-            {
-                _glfwInputWindowFocus(window, GL_TRUE);
-
-                if (window->cursorMode == GLFW_CURSOR_DISABLED)
-                    disableCursor(window);
-            }
-
-            break;
-        }
-
-        case FocusOut:
-        {
-            if (event->xfocus.mode == NotifyNormal)
-            {
-                _glfwInputWindowFocus(window, GL_FALSE);
-
-                if (window->cursorMode == GLFW_CURSOR_DISABLED)
-                    restoreCursor(window);
-            }
-
-            break;
-        }
-
-        case Expose:
-        {
-            _glfwInputWindowDamage(window);
-            break;
-        }
-
-        case PropertyNotify:
-        {
-            if (event->xproperty.atom == _glfw.x11.WM_STATE &&
-                event->xproperty.state == PropertyNewValue)
-            {
-                const int state = getWindowState(window);
-                if (state == IconicState)
-                    _glfwInputWindowIconify(window, GL_TRUE);
-                else if (state == NormalState)
-                    _glfwInputWindowIconify(window, GL_FALSE);
-            }
-
-            break;
-        }
-
-        case SelectionClear:
-        {
-            handleSelectionClear(event);
-            break;
-        }
-
-        case SelectionRequest:
-        {
-            handleSelectionRequest(event);
-            break;
-        }
-
-        case DestroyNotify:
-            return;
-
-#if defined(_GLFW_HAS_XINPUT)
-        case GenericEvent:
-        {
-            if (event->xcookie.extension == _glfw.x11.xi.majorOpcode &&
-                XGetEventData(_glfw.x11.display, &event->xcookie))
-            {
-                if (event->xcookie.evtype == XI_Motion)
-                {
-                    XIDeviceEvent* data = (XIDeviceEvent*) event->xcookie.data;
-
-                    window = findWindowByHandle(data->event);
-                    if (window)
-                    {
-                        if (data->event_x != window->x11.warpPosX ||
-                            data->event_y != window->x11.warpPosY)
-                        {
-                            // The cursor was moved by something other than GLFW
-
-                            double x, y;
-
-                            if (window->cursorMode == GLFW_CURSOR_DISABLED)
-                            {
-                                if (_glfw.focusedWindow != window)
-                                    break;
-
-                                x = data->event_x - window->x11.cursorPosX;
-                                y = data->event_y - window->x11.cursorPosY;
-                            }
-                            else
-                            {
-                                x = data->event_x;
-                                y = data->event_y;
-                            }
-
-                            _glfwInputCursorMotion(window, x, y);
-                        }
-
-                        window->x11.cursorPosX = data->event_x;
-                        window->x11.cursorPosY = data->event_y;
-                    }
-                }
-            }
-
-            XFreeEventData(_glfw.x11.display, &event->xcookie);
-            break;
-        }
-#endif /*_GLFW_HAS_XINPUT*/
-
-        default:
-        {
-            switch (event->type - _glfw.x11.randr.eventBase)
-            {
-                case RRScreenChangeNotify:
-                {
-                    XRRUpdateConfiguration(event);
-                    break;
-                }
-            }
-
-            break;
-        }
-    }
-}
-
-
-//////////////////////////////////////////////////////////////////////////
-//////                       GLFW internal API                      //////
-//////////////////////////////////////////////////////////////////////////
-
-// Retrieve a single window property of the specified type
-// Inspired by fghGetWindowProperty from freeglut
-//
-unsigned long _glfwGetWindowProperty(Window window,
-                                     Atom property,
-                                     Atom type,
-                                     unsigned char** value)
-{
-    Atom actualType;
-    int actualFormat;
-    unsigned long itemCount, bytesAfter;
-
-    XGetWindowProperty(_glfw.x11.display,
-                       window,
-                       property,
-                       0,
-                       LONG_MAX,
-                       False,
-                       type,
-                       &actualType,
-                       &actualFormat,
-                       &itemCount,
-                       &bytesAfter,
-                       value);
-
-    if (type != AnyPropertyType && actualType != type)
-        return 0;
-
-    return itemCount;
-}
-
-
-//////////////////////////////////////////////////////////////////////////
-//////                       GLFW platform API                      //////
-//////////////////////////////////////////////////////////////////////////
-
-int _glfwPlatformCreateWindow(_GLFWwindow* window,
-                              const _GLFWwndconfig* wndconfig,
-                              const _GLFWctxconfig* ctxconfig,
-                              const _GLFWfbconfig* fbconfig)
-{
-    if (!_glfwCreateContext(window, ctxconfig, fbconfig))
-        return GL_FALSE;
-
-    if (!createWindow(window, wndconfig))
-        return GL_FALSE;
-
-    if (wndconfig->monitor)
-    {
-        _glfwPlatformShowWindow(window);
-        enterFullscreenMode(window);
-    }
-
-    return GL_TRUE;
-}
-
-void _glfwPlatformDestroyWindow(_GLFWwindow* window)
-{
-    if (window->monitor)
-        leaveFullscreenMode(window);
-
-    if (window->x11.ic)
-    {
-        XDestroyIC(window->x11.ic);
-        window->x11.ic = NULL;
-    }
-
-    _glfwDestroyContext(window);
-
-    if (window->x11.handle)
-    {
-        if (window->x11.handle ==
-            XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD))
-        {
-            pushSelectionToManager(window);
-        }
-
-        XDeleteContext(_glfw.x11.display, window->x11.handle, _glfw.x11.context);
-        XUnmapWindow(_glfw.x11.display, window->x11.handle);
-        XDestroyWindow(_glfw.x11.display, window->x11.handle);
-        window->x11.handle = (Window) 0;
-    }
-
-    if (window->x11.colormap)
-    {
-        XFreeColormap(_glfw.x11.display, window->x11.colormap);
-        window->x11.colormap = (Colormap) 0;
-    }
-
-    XFlush(_glfw.x11.display);
-}
-
-void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
-{
-#if defined(X_HAVE_UTF8_STRING)
-    Xutf8SetWMProperties(_glfw.x11.display,
-                         window->x11.handle,
-                         title, title,
-                         NULL, 0,
-                         NULL, NULL, NULL);
-#else
-    // This may be a slightly better fallback than using XStoreName and
-    // XSetIconName, which always store their arguments using STRING
-    XmbSetWMProperties(_glfw.x11.display,
-                       window->x11.handle,
-                       title, title,
-                       NULL, 0,
-                       NULL, NULL, NULL);
-#endif
-
-    if (_glfw.x11.NET_WM_NAME)
-    {
-        XChangeProperty(_glfw.x11.display,  window->x11.handle,
-                        _glfw.x11.NET_WM_NAME, _glfw.x11.UTF8_STRING, 8,
-                        PropModeReplace,
-                        (unsigned char*) title, strlen(title));
-    }
-
-    if (_glfw.x11.NET_WM_ICON_NAME)
-    {
-        XChangeProperty(_glfw.x11.display,  window->x11.handle,
-                        _glfw.x11.NET_WM_ICON_NAME, _glfw.x11.UTF8_STRING, 8,
-                        PropModeReplace,
-                        (unsigned char*) title, strlen(title));
-    }
-
-    XFlush(_glfw.x11.display);
-}
-
-void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
-{
-    Window child;
-    int x, y;
-
-    XTranslateCoordinates(_glfw.x11.display, window->x11.handle, _glfw.x11.root,
-                          0, 0, &x, &y, &child);
-
-    if (child)
-    {
-        int left, top;
-        XTranslateCoordinates(_glfw.x11.display, window->x11.handle, child,
-                              0, 0, &left, &top, &child);
-
-        x -= left;
-        y -= top;
-    }
-
-    if (xpos)
-        *xpos = x;
-    if (ypos)
-        *ypos = y;
-}
-
-void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
-{
-    XMoveWindow(_glfw.x11.display, window->x11.handle, xpos, ypos);
-    XFlush(_glfw.x11.display);
-}
-
-void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
-{
-    XWindowAttributes attribs;
-    XGetWindowAttributes(_glfw.x11.display, window->x11.handle, &attribs);
-
-    if (width)
-        *width = attribs.width;
-    if (height)
-        *height = attribs.height;
-}
-
-void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
-{
-    if (window->monitor)
-    {
-        _glfwSetVideoMode(window->monitor, &window->videoMode);
-
-        if (window->x11.overrideRedirect)
-        {
-            GLFWvidmode mode;
-            _glfwPlatformGetVideoMode(window->monitor, &mode);
-            XResizeWindow(_glfw.x11.display, window->x11.handle,
-                          mode.width, mode.height);
-        }
-    }
-    else
-    {
-        if (!window->resizable)
-        {
-            // Update window size restrictions to match new window size
-
-            XSizeHints* hints = XAllocSizeHints();
-
-            hints->flags |= (PMinSize | PMaxSize);
-            hints->min_width  = hints->max_width  = width;
-            hints->min_height = hints->max_height = height;
-
-            XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints);
-            XFree(hints);
-        }
-
-        XResizeWindow(_glfw.x11.display, window->x11.handle, width, height);
-    }
-
-    XFlush(_glfw.x11.display);
-}
-
-void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height)
-{
-    _glfwPlatformGetWindowSize(window, width, height);
-}
-
-void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
-                                     int* left, int* top,
-                                     int* right, int* bottom)
-{
-    long* extents = NULL;
-
-    if (_glfw.x11.NET_FRAME_EXTENTS == None)
-        return;
-
-    if (_glfwGetWindowProperty(window->x11.handle,
-                               _glfw.x11.NET_FRAME_EXTENTS,
-                               XA_CARDINAL,
-                               (unsigned char**) &extents) == 4)
-    {
-        if (left)
-            *left = extents[0];
-        if (top)
-            *top = extents[2];
-        if (right)
-            *right = extents[1];
-        if (bottom)
-            *bottom = extents[3];
-    }
-
-    if (extents)
-        XFree(extents);
-}
-
-void _glfwPlatformIconifyWindow(_GLFWwindow* window)
-{
-    if (window->x11.overrideRedirect)
-    {
-        // Override-redirect windows cannot be iconified or restored, as those
-        // tasks are performed by the window manager
-        _glfwInputError(GLFW_API_UNAVAILABLE,
-                        "X11: Iconification of full screen windows requires "
-                        "a WM that supports EWMH");
-        return;
-    }
-
-    XIconifyWindow(_glfw.x11.display, window->x11.handle, _glfw.x11.screen);
-    XFlush(_glfw.x11.display);
-}
-
-void _glfwPlatformRestoreWindow(_GLFWwindow* window)
-{
-    if (window->x11.overrideRedirect)
-    {
-        // Override-redirect windows cannot be iconified or restored, as those
-        // tasks are performed by the window manager
-        _glfwInputError(GLFW_API_UNAVAILABLE,
-                        "X11: Iconification of full screen windows requires "
-                        "a WM that supports EWMH");
-        return;
-    }
-
-    XMapWindow(_glfw.x11.display, window->x11.handle);
-    XFlush(_glfw.x11.display);
-}
-
-void _glfwPlatformShowWindow(_GLFWwindow* window)
-{
-    XMapRaised(_glfw.x11.display, window->x11.handle);
-    XFlush(_glfw.x11.display);
-}
-
-void _glfwPlatformUnhideWindow(_GLFWwindow* window)
-{
-    XMapWindow(_glfw.x11.display, window->x11.handle);
-    XFlush(_glfw.x11.display);
-}
-
-void _glfwPlatformHideWindow(_GLFWwindow* window)
-{
-    XUnmapWindow(_glfw.x11.display, window->x11.handle);
-    XFlush(_glfw.x11.display);
-}
-
-int _glfwPlatformWindowFocused(_GLFWwindow* window)
-{
-    Window focused;
-    int state;
-
-    XGetInputFocus(_glfw.x11.display, &focused, &state);
-    return window->x11.handle == focused;
-}
-
-int _glfwPlatformWindowIconified(_GLFWwindow* window)
-{
-    return getWindowState(window) == IconicState;
-}
-
-int _glfwPlatformWindowVisible(_GLFWwindow* window)
-{
-    XWindowAttributes wa;
-    XGetWindowAttributes(_glfw.x11.display, window->x11.handle, &wa);
-    return wa.map_state == IsViewable;
-}
-
-void _glfwPlatformPollEvents(void)
-{
-    int count = XPending(_glfw.x11.display);
-    while (count--)
-    {
-        XEvent event;
-        XNextEvent(_glfw.x11.display, &event);
-        processEvent(&event);
-    }
-
-    _GLFWwindow* window = _glfw.focusedWindow;
-    if (window && window->cursorMode == GLFW_CURSOR_DISABLED)
-    {
-        int width, height;
-        _glfwPlatformGetWindowSize(window, &width, &height);
-        _glfwPlatformSetCursorPos(window, width / 2, height / 2);
-    }
-}
-
-void _glfwPlatformWaitEvents(void)
-{
-    if (!XPending(_glfw.x11.display))
-    {
-        fd_set fds;
-        const int fd = ConnectionNumber(_glfw.x11.display);
-
-        FD_ZERO(&fds);
-        FD_SET(fd, &fds);
-
-        // select(1) is used instead of an X function like XNextEvent, as the
-        // wait inside those are guarded by the mutex protecting the display
-        // struct, locking out other threads from using X (including GLX)
-        if (select(fd + 1, &fds, NULL, NULL, NULL) < 0)
-            return;
-    }
-
-    _glfwPlatformPollEvents();
-}
-
-void _glfwPlatformPostEmptyEvent(void)
-{
-    XEvent event;
-    _GLFWwindow* window = _glfw.windowListHead;
-
-    memset(&event, 0, sizeof(event));
-    event.type = ClientMessage;
-    event.xclient.window = window->x11.handle;
-    event.xclient.format = 32; // Data is 32-bit longs
-    event.xclient.message_type = _glfw.x11.NULL_;
-
-    XSendEvent(_glfw.x11.display, window->x11.handle, False, 0, &event);
-    XFlush(_glfw.x11.display);
-}
-
-void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
-{
-    Window root, child;
-    int rootX, rootY, childX, childY;
-    unsigned int mask;
-
-    XQueryPointer(_glfw.x11.display, window->x11.handle,
-                  &root, &child,
-                  &rootX, &rootY, &childX, &childY,
-                  &mask);
-
-    if (xpos)
-        *xpos = childX;
-    if (ypos)
-        *ypos = childY;
-}
-
-void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
-{
-    // Store the new position so it can be recognized later
-    window->x11.warpPosX = (int) x;
-    window->x11.warpPosY = (int) y;
-
-    XWarpPointer(_glfw.x11.display, None, window->x11.handle,
-                 0,0,0,0, (int) x, (int) y);
-}
-
-void _glfwPlatformApplyCursorMode(_GLFWwindow* window)
-{
-    switch (window->cursorMode)
-    {
-        case GLFW_CURSOR_NORMAL:
-            restoreCursor(window);
-            break;
-        case GLFW_CURSOR_HIDDEN:
-            hideCursor(window);
-            break;
-        case GLFW_CURSOR_DISABLED:
-            disableCursor(window);
-            break;
-    }
-}
-
-int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
-                              const GLFWimage* image,
-                              int xhot, int yhot)
-{
-    cursor->x11.handle = _glfwCreateCursor(image, xhot, yhot);
-    if (!cursor->x11.handle)
-        return GL_FALSE;
-
-    return GL_TRUE;
-}
-
-int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
-{
-    const unsigned int native = translateCursorShape(shape);
-    if (!native)
-    {
-        _glfwInputError(GLFW_INVALID_ENUM, "X11: Invalid standard cursor");
-        return GL_FALSE;
-    }
-
-    cursor->x11.handle = XCreateFontCursor(_glfw.x11.display, native);
-    if (!cursor->x11.handle)
-    {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "X11: Failed to create standard cursor");
-        return GL_FALSE;
-    }
-
-    return GL_TRUE;
-}
-
-void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
-{
-    if (cursor->x11.handle)
-        XFreeCursor(_glfw.x11.display, cursor->x11.handle);
-}
-
-void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
-{
-    if (window->cursorMode == GLFW_CURSOR_NORMAL)
-    {
-        if (cursor)
-            XDefineCursor(_glfw.x11.display, window->x11.handle, cursor->x11.handle);
-        else
-            XUndefineCursor(_glfw.x11.display, window->x11.handle);
-
-        XFlush(_glfw.x11.display);
-    }
-}
-
-void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
-{
-    free(_glfw.x11.clipboardString);
-    _glfw.x11.clipboardString = strdup(string);
-
-    XSetSelectionOwner(_glfw.x11.display,
-                       _glfw.x11.CLIPBOARD,
-                       window->x11.handle, CurrentTime);
-
-    if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) !=
-        window->x11.handle)
-    {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "X11: Failed to become owner of the clipboard selection");
-    }
-}
-
-const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
-{
-    size_t i;
-    const Atom formats[] = { _glfw.x11.UTF8_STRING,
-                             _glfw.x11.COMPOUND_STRING,
-                             XA_STRING };
-    const size_t formatCount = sizeof(formats) / sizeof(formats[0]);
-
-    if (findWindowByHandle(XGetSelectionOwner(_glfw.x11.display,
-                                              _glfw.x11.CLIPBOARD)))
-    {
-        // Instead of doing a large number of X round-trips just to put this
-        // string into a window property and then read it back, just return it
-        return _glfw.x11.clipboardString;
-    }
-
-    free(_glfw.x11.clipboardString);
-    _glfw.x11.clipboardString = NULL;
-
-    for (i = 0;  i < formatCount;  i++)
-    {
-        char* data;
-        XEvent event;
-
-        XConvertSelection(_glfw.x11.display,
-                          _glfw.x11.CLIPBOARD,
-                          formats[i],
-                          _glfw.x11.GLFW_SELECTION,
-                          window->x11.handle, CurrentTime);
-
-        // XCheckTypedEvent is used instead of XIfEvent in order not to lock
-        // other threads out from the display during the entire wait period
-        while (!XCheckTypedEvent(_glfw.x11.display, SelectionNotify, &event))
-            ;
-
-        if (event.xselection.property == None)
-            continue;
-
-        if (_glfwGetWindowProperty(event.xselection.requestor,
-                                   event.xselection.property,
-                                   event.xselection.target,
-                                   (unsigned char**) &data))
-        {
-            _glfw.x11.clipboardString = strdup(data);
-        }
-
-        XFree(data);
-
-        XDeleteProperty(_glfw.x11.display,
-                        event.xselection.requestor,
-                        event.xselection.property);
-
-        if (_glfw.x11.clipboardString)
-            break;
-    }
-
-    if (_glfw.x11.clipboardString == NULL)
-    {
-        _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
-                        "X11: Failed to convert selection to string");
-    }
-
-    return _glfw.x11.clipboardString;
+// GLFW 3.2 X11 - www.glfw.org
+//------------------------------------------------------------------------
+// Copyright (c) 2002-2006 Marcus Geelnard
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
+//
+// 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 <X11/cursorfont.h>
+#include <X11/Xmd.h>
+
+#include <sys/select.h>
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <errno.h>
+#include <assert.h>
+
+// Action for EWMH client messages
+#define _NET_WM_STATE_REMOVE        0
+#define _NET_WM_STATE_ADD           1
+#define _NET_WM_STATE_TOGGLE        2
+
+// Additional mouse button names for XButtonEvent
+#define Button6            6
+#define Button7            7
+
+
+// Wait for data to arrive using select
+// This avoids blocking other threads via the per-display Xlib lock that also
+// covers GLX functions
+//
+static GLFWbool waitForEvent(double* timeout)
+{
+    fd_set fds;
+    const int fd = ConnectionNumber(_glfw.x11.display);
+    int count = fd + 1;
+
+    FD_ZERO(&fds);
+    FD_SET(fd, &fds);
+#if defined(__linux__)
+    FD_SET(_glfw.linux_js.inotify, &fds);
+
+    if (fd < _glfw.linux_js.inotify)
+        count = _glfw.linux_js.inotify + 1;
+#endif
+    for (;;)
+    {
+        if (timeout)
+        {
+            const long seconds = (long) *timeout;
+            const long microseconds = (long) ((*timeout - seconds) * 1e6);
+            struct timeval tv = { seconds, microseconds };
+            const uint64_t base = _glfwPlatformGetTimerValue();
+
+            const int result = select(count, &fds, NULL, NULL, &tv);
+            const int error = errno;
+
+            *timeout -= (_glfwPlatformGetTimerValue() - base) /
+                (double) _glfwPlatformGetTimerFrequency();
+
+            if (result > 0)
+                return GLFW_TRUE;
+            if ((result == -1 && error == EINTR) || *timeout <= 0.0)
+                return GLFW_FALSE;
+        }
+        else if (select(count, &fds, NULL, NULL, NULL) != -1 || errno != EINTR)
+            return GLFW_TRUE;
+    }
+}
+
+// Waits until a VisibilityNotify event arrives for the specified window or the
+// timeout period elapses (ICCCM section 4.2.2)
+//
+static GLFWbool waitForVisibilityNotify(_GLFWwindow* window)
+{
+    XEvent dummy;
+    double timeout = 0.1;
+
+    while (!XCheckTypedWindowEvent(_glfw.x11.display,
+                                   window->x11.handle,
+                                   VisibilityNotify,
+                                   &dummy))
+    {
+        if (!waitForEvent(&timeout))
+            return GLFW_FALSE;
+    }
+
+    return GLFW_TRUE;
+}
+
+// Returns whether the window is iconified
+//
+static int getWindowState(_GLFWwindow* window)
+{
+    int result = WithdrawnState;
+    struct {
+        CARD32 state;
+        Window icon;
+    } *state = NULL;
+
+    if (_glfwGetWindowPropertyX11(window->x11.handle,
+                                  _glfw.x11.WM_STATE,
+                                  _glfw.x11.WM_STATE,
+                                  (unsigned char**) &state) >= 2)
+    {
+        result = state->state;
+    }
+
+    XFree(state);
+    return result;
+}
+
+// Returns whether the event is a selection event
+//
+static Bool isSelectionEvent(Display* display, XEvent* event, XPointer pointer)
+{
+    return event->type == SelectionRequest ||
+           event->type == SelectionNotify ||
+           event->type == SelectionClear;
+}
+
+// Returns whether it is a _NET_FRAME_EXTENTS event for the specified window
+//
+static Bool isFrameExtentsEvent(Display* display, XEvent* event, XPointer pointer)
+{
+    _GLFWwindow* window = (_GLFWwindow*) pointer;
+    return event->type == PropertyNotify &&
+           event->xproperty.state == PropertyNewValue &&
+           event->xproperty.window == window->x11.handle &&
+           event->xproperty.atom == _glfw.x11.NET_FRAME_EXTENTS;
+}
+
+// Translates a GLFW standard cursor to a font cursor shape
+//
+static int translateCursorShape(int shape)
+{
+    switch (shape)
+    {
+        case GLFW_ARROW_CURSOR:
+            return XC_left_ptr;
+        case GLFW_IBEAM_CURSOR:
+            return XC_xterm;
+        case GLFW_CROSSHAIR_CURSOR:
+            return XC_crosshair;
+        case GLFW_HAND_CURSOR:
+            return XC_hand1;
+        case GLFW_HRESIZE_CURSOR:
+            return XC_sb_h_double_arrow;
+        case GLFW_VRESIZE_CURSOR:
+            return XC_sb_v_double_arrow;
+    }
+
+    return 0;
+}
+
+// Translates an X event modifier state mask
+//
+static int translateState(int state)
+{
+    int mods = 0;
+
+    if (state & ShiftMask)
+        mods |= GLFW_MOD_SHIFT;
+    if (state & ControlMask)
+        mods |= GLFW_MOD_CONTROL;
+    if (state & Mod1Mask)
+        mods |= GLFW_MOD_ALT;
+    if (state & Mod4Mask)
+        mods |= GLFW_MOD_SUPER;
+
+    return mods;
+}
+
+// Translates an X11 key code to a GLFW key token
+//
+static int translateKey(int scancode)
+{
+    // Use the pre-filled LUT (see createKeyTables() in x11_init.c)
+    if (scancode < 0 || scancode > 255)
+        return GLFW_KEY_UNKNOWN;
+
+    return _glfw.x11.publicKeys[scancode];
+}
+
+// Return the GLFW window corresponding to the specified X11 window
+//
+static _GLFWwindow* findWindowByHandle(Window handle)
+{
+    _GLFWwindow* window;
+
+    if (XFindContext(_glfw.x11.display,
+                     handle,
+                     _glfw.x11.context,
+                     (XPointer*) &window) != 0)
+    {
+        return NULL;
+    }
+
+    return window;
+}
+
+// Sends an EWMH or ICCCM event to the window manager
+//
+static void sendEventToWM(_GLFWwindow* window, Atom type,
+                          long a, long b, long c, long d, long e)
+{
+    XEvent event;
+    memset(&event, 0, sizeof(event));
+
+    event.type = ClientMessage;
+    event.xclient.window = window->x11.handle;
+    event.xclient.format = 32; // Data is 32-bit longs
+    event.xclient.message_type = type;
+    event.xclient.data.l[0] = a;
+    event.xclient.data.l[1] = b;
+    event.xclient.data.l[2] = c;
+    event.xclient.data.l[3] = d;
+    event.xclient.data.l[4] = e;
+
+    XSendEvent(_glfw.x11.display, _glfw.x11.root,
+               False,
+               SubstructureNotifyMask | SubstructureRedirectMask,
+               &event);
+}
+
+// Updates the normal hints according to the window settings
+//
+static void updateNormalHints(_GLFWwindow* window, int width, int height)
+{
+    XSizeHints* hints = XAllocSizeHints();
+
+    if (!window->monitor)
+    {
+        if (window->resizable)
+        {
+            if (window->minwidth != GLFW_DONT_CARE &&
+                window->minheight != GLFW_DONT_CARE)
+            {
+                hints->flags |= PMinSize;
+                hints->min_width = window->minwidth;
+                hints->min_height = window->minheight;
+            }
+
+            if (window->maxwidth != GLFW_DONT_CARE &&
+                window->maxheight != GLFW_DONT_CARE)
+            {
+                hints->flags |= PMaxSize;
+                hints->max_width = window->maxwidth;
+                hints->max_height = window->maxheight;
+            }
+
+            if (window->numer != GLFW_DONT_CARE &&
+                window->denom != GLFW_DONT_CARE)
+            {
+                hints->flags |= PAspect;
+                hints->min_aspect.x = hints->max_aspect.x = window->numer;
+                hints->min_aspect.y = hints->max_aspect.y = window->denom;
+            }
+        }
+        else
+        {
+            hints->flags |= (PMinSize | PMaxSize);
+            hints->min_width  = hints->max_width  = width;
+            hints->min_height = hints->max_height = height;
+        }
+    }
+
+    hints->flags |= PWinGravity;
+    hints->win_gravity = StaticGravity;
+
+    XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints);
+    XFree(hints);
+}
+
+// Updates the full screen status of the window
+//
+static void updateWindowMode(_GLFWwindow* window)
+{
+    if (window->monitor)
+    {
+        if (_glfw.x11.xinerama.available &&
+            _glfw.x11.NET_WM_FULLSCREEN_MONITORS)
+        {
+            sendEventToWM(window,
+                          _glfw.x11.NET_WM_FULLSCREEN_MONITORS,
+                          window->monitor->x11.index,
+                          window->monitor->x11.index,
+                          window->monitor->x11.index,
+                          window->monitor->x11.index,
+                          0);
+        }
+
+        if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN)
+        {
+            sendEventToWM(window,
+                          _glfw.x11.NET_WM_STATE,
+                          _NET_WM_STATE_ADD,
+                          _glfw.x11.NET_WM_STATE_FULLSCREEN,
+                          0, 1, 0);
+        }
+        else
+        {
+            // This is the butcher's way of removing window decorations
+            // Setting the override-redirect attribute on a window makes the
+            // window manager ignore the window completely (ICCCM, section 4)
+            // The good thing is that this makes undecorated full screen windows
+            // easy to do; the bad thing is that we have to do everything
+            // manually and some things (like iconify/restore) won't work at
+            // all, as those are tasks usually performed by the window manager
+
+            XSetWindowAttributes attributes;
+            attributes.override_redirect = True;
+            XChangeWindowAttributes(_glfw.x11.display,
+                                    window->x11.handle,
+                                    CWOverrideRedirect,
+                                    &attributes);
+
+            window->x11.overrideRedirect = GLFW_TRUE;
+        }
+
+        // Enable compositor bypass
+        {
+            const unsigned long value = 1;
+
+            XChangeProperty(_glfw.x11.display,  window->x11.handle,
+                            _glfw.x11.NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32,
+                            PropModeReplace, (unsigned char*) &value, 1);
+        }
+    }
+    else
+    {
+        if (_glfw.x11.xinerama.available &&
+            _glfw.x11.NET_WM_FULLSCREEN_MONITORS)
+        {
+            XDeleteProperty(_glfw.x11.display, window->x11.handle,
+                            _glfw.x11.NET_WM_FULLSCREEN_MONITORS);
+        }
+
+        if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN)
+        {
+            sendEventToWM(window,
+                          _glfw.x11.NET_WM_STATE,
+                          _NET_WM_STATE_REMOVE,
+                          _glfw.x11.NET_WM_STATE_FULLSCREEN,
+                          0, 1, 0);
+        }
+        else
+        {
+            XSetWindowAttributes attributes;
+            attributes.override_redirect = False;
+            XChangeWindowAttributes(_glfw.x11.display,
+                                    window->x11.handle,
+                                    CWOverrideRedirect,
+                                    &attributes);
+
+            window->x11.overrideRedirect = GLFW_FALSE;
+        }
+
+        // Disable compositor bypass
+        {
+            XDeleteProperty(_glfw.x11.display, window->x11.handle,
+                            _glfw.x11.NET_WM_BYPASS_COMPOSITOR);
+        }
+    }
+}
+
+// Splits and translates a text/uri-list into separate file paths
+// NOTE: This function destroys the provided string
+//
+static char** parseUriList(char* text, int* count)
+{
+    const char* prefix = "file://";
+    char** paths = NULL;
+    char* line;
+
+    *count = 0;
+
+    while ((line = strtok(text, "\r\n")))
+    {
+        text = NULL;
+
+        if (line[0] == '#')
+            continue;
+
+        if (strncmp(line, prefix, strlen(prefix)) == 0)
+            line += strlen(prefix);
+
+        (*count)++;
+
+        char* path = calloc(strlen(line) + 1, 1);
+        paths = realloc(paths, *count * sizeof(char*));
+        paths[*count - 1] = path;
+
+        while (*line)
+        {
+            if (line[0] == '%' && line[1] && line[2])
+            {
+                const char digits[3] = { line[1], line[2], '\0' };
+                *path = strtol(digits, NULL, 16);
+                line += 2;
+            }
+            else
+                *path = *line;
+
+            path++;
+            line++;
+        }
+    }
+
+    return paths;
+}
+
+// Centers the cursor over the window client area
+//
+static void centerCursor(_GLFWwindow* window)
+{
+    int width, height;
+    _glfwPlatformGetWindowSize(window, &width, &height);
+    _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0);
+}
+
+// Updates the cursor image according to its cursor mode
+//
+static void updateCursorImage(_GLFWwindow* window)
+{
+    if (window->cursorMode == GLFW_CURSOR_NORMAL)
+    {
+        if (window->cursor)
+        {
+            XDefineCursor(_glfw.x11.display, window->x11.handle,
+                          window->cursor->x11.handle);
+        }
+        else
+            XUndefineCursor(_glfw.x11.display, window->x11.handle);
+    }
+    else
+        XDefineCursor(_glfw.x11.display, window->x11.handle, _glfw.x11.cursor);
+}
+
+// Create the X11 window (and its colormap)
+//
+static GLFWbool createNativeWindow(_GLFWwindow* window,
+                                   const _GLFWwndconfig* wndconfig,
+                                   Visual* visual, int depth)
+{
+    // Create a colormap based on the visual used by the current context
+    window->x11.colormap = XCreateColormap(_glfw.x11.display,
+                                           _glfw.x11.root,
+                                           visual,
+                                           AllocNone);
+
+    // Create the actual window
+    {
+        XSetWindowAttributes wa;
+        const unsigned long wamask = CWBorderPixel | CWColormap | CWEventMask;
+
+        wa.colormap = window->x11.colormap;
+        wa.border_pixel = 0;
+        wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask |
+                        PointerMotionMask | ButtonPressMask | ButtonReleaseMask |
+                        ExposureMask | FocusChangeMask | VisibilityChangeMask |
+                        EnterWindowMask | LeaveWindowMask | PropertyChangeMask;
+
+        _glfwGrabErrorHandlerX11();
+
+        window->x11.handle = XCreateWindow(_glfw.x11.display,
+                                           _glfw.x11.root,
+                                           0, 0,
+                                           wndconfig->width, wndconfig->height,
+                                           0,      // Border width
+                                           depth,  // Color depth
+                                           InputOutput,
+                                           visual,
+                                           wamask,
+                                           &wa);
+
+        _glfwReleaseErrorHandlerX11();
+
+        if (!window->x11.handle)
+        {
+            _glfwInputErrorX11(GLFW_PLATFORM_ERROR,
+                               "X11: Failed to create window");
+            return GLFW_FALSE;
+        }
+
+        XSaveContext(_glfw.x11.display,
+                     window->x11.handle,
+                     _glfw.x11.context,
+                     (XPointer) window);
+    }
+
+    if (!wndconfig->decorated)
+    {
+        struct
+        {
+            unsigned long flags;
+            unsigned long functions;
+            unsigned long decorations;
+            long input_mode;
+            unsigned long status;
+        } hints;
+
+        hints.flags = 2;       // Set decorations
+        hints.decorations = 0; // No decorations
+
+        XChangeProperty(_glfw.x11.display, window->x11.handle,
+                        _glfw.x11.MOTIF_WM_HINTS,
+                        _glfw.x11.MOTIF_WM_HINTS, 32,
+                        PropModeReplace,
+                        (unsigned char*) &hints,
+                        sizeof(hints) / sizeof(long));
+    }
+
+    if (_glfw.x11.NET_WM_STATE && !window->monitor)
+    {
+        Atom states[3];
+        int count = 0;
+
+        if (wndconfig->floating)
+        {
+            if (_glfw.x11.NET_WM_STATE_ABOVE)
+                states[count++] = _glfw.x11.NET_WM_STATE_ABOVE;
+        }
+
+        if (wndconfig->maximized)
+        {
+            if (_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT &&
+                _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ)
+            {
+                states[count++] = _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT;
+                states[count++] = _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ;
+            }
+        }
+
+        if (count)
+        {
+            XChangeProperty(_glfw.x11.display, window->x11.handle,
+                            _glfw.x11.NET_WM_STATE, XA_ATOM, 32,
+                            PropModeReplace, (unsigned char*) &states, count);
+        }
+    }
+
+    // Declare the WM protocols supported by GLFW
+    {
+        Atom protocols[] =
+        {
+            _glfw.x11.WM_DELETE_WINDOW,
+            _glfw.x11.NET_WM_PING
+        };
+
+        XSetWMProtocols(_glfw.x11.display, window->x11.handle,
+                        protocols, sizeof(protocols) / sizeof(Atom));
+    }
+
+    // Declare our PID
+    {
+        const pid_t pid = getpid();
+
+        XChangeProperty(_glfw.x11.display,  window->x11.handle,
+                        _glfw.x11.NET_WM_PID, XA_CARDINAL, 32,
+                        PropModeReplace,
+                        (unsigned char*) &pid, 1);
+    }
+
+    if (_glfw.x11.NET_WM_WINDOW_TYPE && _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL)
+    {
+        Atom type = _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL;
+        XChangeProperty(_glfw.x11.display,  window->x11.handle,
+                        _glfw.x11.NET_WM_WINDOW_TYPE, XA_ATOM, 32,
+                        PropModeReplace, (unsigned char*) &type, 1);
+    }
+
+    // Set ICCCM WM_HINTS property
+    {
+        XWMHints* hints = XAllocWMHints();
+        if (!hints)
+        {
+            _glfwInputError(GLFW_OUT_OF_MEMORY,
+                            "X11: Failed to allocate WM hints");
+            return GLFW_FALSE;
+        }
+
+        hints->flags = StateHint;
+        hints->initial_state = NormalState;
+
+        XSetWMHints(_glfw.x11.display, window->x11.handle, hints);
+        XFree(hints);
+    }
+
+    updateNormalHints(window, wndconfig->width, wndconfig->height);
+
+    // Set ICCCM WM_CLASS property
+    // HACK: Until a mechanism for specifying the application name is added, the
+    //       initial window title is used as the window class name
+    if (strlen(wndconfig->title))
+    {
+        XClassHint* hint = XAllocClassHint();
+        hint->res_name = (char*) wndconfig->title;
+        hint->res_class = (char*) wndconfig->title;
+
+        XSetClassHint(_glfw.x11.display, window->x11.handle, hint);
+        XFree(hint);
+    }
+
+    if (_glfw.x11.XdndAware)
+    {
+        // Announce support for Xdnd (drag and drop)
+        const Atom version = 5;
+        XChangeProperty(_glfw.x11.display, window->x11.handle,
+                        _glfw.x11.XdndAware, XA_ATOM, 32,
+                        PropModeReplace, (unsigned char*) &version, 1);
+    }
+
+    _glfwPlatformSetWindowTitle(window, wndconfig->title);
+
+    if (_glfw.x11.im)
+    {
+        window->x11.ic = XCreateIC(_glfw.x11.im,
+                                   XNInputStyle,
+                                   XIMPreeditNothing | XIMStatusNothing,
+                                   XNClientWindow,
+                                   window->x11.handle,
+                                   XNFocusWindow,
+                                   window->x11.handle,
+                                   NULL);
+    }
+
+    _glfwPlatformGetWindowPos(window, &window->x11.xpos, &window->x11.ypos);
+    _glfwPlatformGetWindowSize(window, &window->x11.width, &window->x11.height);
+
+    return GLFW_TRUE;
+}
+
+// Set the specified property to the selection converted to the requested target
+//
+static Atom writeTargetToProperty(const XSelectionRequestEvent* request)
+{
+    int i;
+    const Atom formats[] = { _glfw.x11.UTF8_STRING,
+                             _glfw.x11.COMPOUND_STRING,
+                             XA_STRING };
+    const int formatCount = sizeof(formats) / sizeof(formats[0]);
+
+    if (request->property == None)
+    {
+        // The requester is a legacy client (ICCCM section 2.2)
+        // We don't support legacy clients, so fail here
+        return None;
+    }
+
+    if (request->target == _glfw.x11.TARGETS)
+    {
+        // The list of supported targets was requested
+
+        const Atom targets[] = { _glfw.x11.TARGETS,
+                                 _glfw.x11.MULTIPLE,
+                                 _glfw.x11.UTF8_STRING,
+                                 _glfw.x11.COMPOUND_STRING,
+                                 XA_STRING };
+
+        XChangeProperty(_glfw.x11.display,
+                        request->requestor,
+                        request->property,
+                        XA_ATOM,
+                        32,
+                        PropModeReplace,
+                        (unsigned char*) targets,
+                        sizeof(targets) / sizeof(targets[0]));
+
+        return request->property;
+    }
+
+    if (request->target == _glfw.x11.MULTIPLE)
+    {
+        // Multiple conversions were requested
+
+        Atom* targets;
+        unsigned long i, count;
+
+        count = _glfwGetWindowPropertyX11(request->requestor,
+                                          request->property,
+                                          _glfw.x11.ATOM_PAIR,
+                                          (unsigned char**) &targets);
+
+        for (i = 0;  i < count;  i += 2)
+        {
+            int j;
+
+            for (j = 0;  j < formatCount;  j++)
+            {
+                if (targets[i] == formats[j])
+                    break;
+            }
+
+            if (j < formatCount)
+            {
+                XChangeProperty(_glfw.x11.display,
+                                request->requestor,
+                                targets[i + 1],
+                                targets[i],
+                                8,
+                                PropModeReplace,
+                                (unsigned char*) _glfw.x11.clipboardString,
+                                strlen(_glfw.x11.clipboardString));
+            }
+            else
+                targets[i + 1] = None;
+        }
+
+        XChangeProperty(_glfw.x11.display,
+                        request->requestor,
+                        request->property,
+                        _glfw.x11.ATOM_PAIR,
+                        32,
+                        PropModeReplace,
+                        (unsigned char*) targets,
+                        count);
+
+        XFree(targets);
+
+        return request->property;
+    }
+
+    if (request->target == _glfw.x11.SAVE_TARGETS)
+    {
+        // The request is a check whether we support SAVE_TARGETS
+        // It should be handled as a no-op side effect target
+
+        XChangeProperty(_glfw.x11.display,
+                        request->requestor,
+                        request->property,
+                        _glfw.x11.NULL_,
+                        32,
+                        PropModeReplace,
+                        NULL,
+                        0);
+
+        return request->property;
+    }
+
+    // Conversion to a data target was requested
+
+    for (i = 0;  i < formatCount;  i++)
+    {
+        if (request->target == formats[i])
+        {
+            // The requested target is one we support
+
+            XChangeProperty(_glfw.x11.display,
+                            request->requestor,
+                            request->property,
+                            request->target,
+                            8,
+                            PropModeReplace,
+                            (unsigned char*) _glfw.x11.clipboardString,
+                            strlen(_glfw.x11.clipboardString));
+
+            return request->property;
+        }
+    }
+
+    // The requested target is not supported
+
+    return None;
+}
+
+static void handleSelectionClear(XEvent* event)
+{
+    free(_glfw.x11.clipboardString);
+    _glfw.x11.clipboardString = NULL;
+}
+
+static void handleSelectionRequest(XEvent* event)
+{
+    const XSelectionRequestEvent* request = &event->xselectionrequest;
+
+    XEvent reply;
+    memset(&reply, 0, sizeof(reply));
+
+    reply.xselection.property = writeTargetToProperty(request);
+    reply.xselection.type = SelectionNotify;
+    reply.xselection.display = request->display;
+    reply.xselection.requestor = request->requestor;
+    reply.xselection.selection = request->selection;
+    reply.xselection.target = request->target;
+    reply.xselection.time = request->time;
+
+    XSendEvent(_glfw.x11.display, request->requestor, False, 0, &reply);
+}
+
+static void pushSelectionToManager(_GLFWwindow* window)
+{
+    XConvertSelection(_glfw.x11.display,
+                      _glfw.x11.CLIPBOARD_MANAGER,
+                      _glfw.x11.SAVE_TARGETS,
+                      None,
+                      window->x11.handle,
+                      CurrentTime);
+
+    for (;;)
+    {
+        XEvent event;
+
+        while (XCheckIfEvent(_glfw.x11.display, &event, isSelectionEvent, NULL))
+        {
+            switch (event.type)
+            {
+                case SelectionRequest:
+                    handleSelectionRequest(&event);
+                    break;
+
+                case SelectionClear:
+                    handleSelectionClear(&event);
+                    break;
+
+                case SelectionNotify:
+                {
+                    if (event.xselection.target == _glfw.x11.SAVE_TARGETS)
+                    {
+                        // This means one of two things; either the selection was
+                        // not owned, which means there is no clipboard manager, or
+                        // the transfer to the clipboard manager has completed
+                        // In either case, it means we are done here
+                        return;
+                    }
+
+                    break;
+                }
+            }
+        }
+
+        waitForEvent(NULL);
+    }
+}
+
+// Make the specified window and its video mode active on its monitor
+//
+static GLFWbool acquireMonitor(_GLFWwindow* window)
+{
+    GLFWbool status;
+
+    if (_glfw.x11.saver.count == 0)
+    {
+        // Remember old screen saver settings
+        XGetScreenSaver(_glfw.x11.display,
+                        &_glfw.x11.saver.timeout,
+                        &_glfw.x11.saver.interval,
+                        &_glfw.x11.saver.blanking,
+                        &_glfw.x11.saver.exposure);
+
+        // Disable screen saver
+        XSetScreenSaver(_glfw.x11.display, 0, 0, DontPreferBlanking,
+                        DefaultExposures);
+    }
+
+    if (!window->monitor->window)
+        _glfw.x11.saver.count++;
+
+    status = _glfwSetVideoModeX11(window->monitor, &window->videoMode);
+
+    if (window->x11.overrideRedirect)
+    {
+        int xpos, ypos;
+        GLFWvidmode mode;
+
+        // Manually position the window over its monitor
+        _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos);
+        _glfwPlatformGetVideoMode(window->monitor, &mode);
+
+        XMoveResizeWindow(_glfw.x11.display, window->x11.handle,
+                          xpos, ypos, mode.width, mode.height);
+    }
+
+    _glfwInputMonitorWindowChange(window->monitor, window);
+    return status;
+}
+
+// Remove the window and restore the original video mode
+//
+static void releaseMonitor(_GLFWwindow* window)
+{
+    if (window->monitor->window != window)
+        return;
+
+    _glfwInputMonitorWindowChange(window->monitor, NULL);
+    _glfwRestoreVideoModeX11(window->monitor);
+
+    _glfw.x11.saver.count--;
+
+    if (_glfw.x11.saver.count == 0)
+    {
+        // Restore old screen saver settings
+        XSetScreenSaver(_glfw.x11.display,
+                        _glfw.x11.saver.timeout,
+                        _glfw.x11.saver.interval,
+                        _glfw.x11.saver.blanking,
+                        _glfw.x11.saver.exposure);
+    }
+}
+
+// Decode a Unicode code point from a UTF-8 stream
+// Based on cutef8 by Jeff Bezanson (Public Domain)
+//
+#if defined(X_HAVE_UTF8_STRING)
+static unsigned int decodeUTF8(const char** s)
+{
+    unsigned int ch = 0, count = 0;
+    static const unsigned int offsets[] =
+    {
+        0x00000000u, 0x00003080u, 0x000e2080u,
+        0x03c82080u, 0xfa082080u, 0x82082080u
+    };
+
+    do
+    {
+        ch = (ch << 6) + (unsigned char) **s;
+        (*s)++;
+        count++;
+    } while ((**s & 0xc0) == 0x80);
+
+    assert(count <= 6);
+    return ch - offsets[count - 1];
+}
+#endif /*X_HAVE_UTF8_STRING*/
+
+// Process the specified X event
+//
+static void processEvent(XEvent *event)
+{
+    _GLFWwindow* window = NULL;
+    int keycode = 0;
+    Bool filtered = False;
+
+    // HACK: Save scancode as some IMs clear the field in XFilterEvent
+    if (event->type == KeyPress || event->type == KeyRelease)
+        keycode = event->xkey.keycode;
+
+    if (_glfw.x11.im)
+        filtered = XFilterEvent(event, None);
+
+    if (_glfw.x11.randr.available)
+    {
+        if (event->type == _glfw.x11.randr.eventBase + RRNotify)
+        {
+            XRRUpdateConfiguration(event);
+            _glfwInputMonitorChange();
+            return;
+        }
+    }
+
+    if (event->type != GenericEvent)
+    {
+        window = findWindowByHandle(event->xany.window);
+        if (window == NULL)
+        {
+            // This is an event for a window that has already been destroyed
+            return;
+        }
+    }
+
+    switch (event->type)
+    {
+        case KeyPress:
+        {
+            const int key = translateKey(keycode);
+            const int mods = translateState(event->xkey.state);
+            const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
+
+            if (window->x11.ic)
+            {
+                // HACK: Ignore duplicate key press events generated by ibus
+                //       Corresponding release events are filtered out by the
+                //       GLFW key repeat logic
+                if (window->x11.lastKeyCode != keycode ||
+                    window->x11.lastKeyTime != event->xkey.time)
+                {
+                    if (keycode)
+                        _glfwInputKey(window, key, keycode, GLFW_PRESS, mods);
+                }
+
+                window->x11.lastKeyCode = keycode;
+                window->x11.lastKeyTime = event->xkey.time;
+
+                if (!filtered)
+                {
+                    int count;
+                    Status status;
+#if defined(X_HAVE_UTF8_STRING)
+                    char buffer[100];
+                    char* chars = buffer;
+
+                    count = Xutf8LookupString(window->x11.ic,
+                                              &event->xkey,
+                                              buffer, sizeof(buffer) - 1,
+                                              NULL, &status);
+
+                    if (status == XBufferOverflow)
+                    {
+                        chars = calloc(count + 1, 1);
+                        count = Xutf8LookupString(window->x11.ic,
+                                                  &event->xkey,
+                                                  chars, count,
+                                                  NULL, &status);
+                    }
+
+                    if (status == XLookupChars || status == XLookupBoth)
+                    {
+                        const char* c = chars;
+                        chars[count] = '\0';
+                        while (c - chars < count)
+                            _glfwInputChar(window, decodeUTF8(&c), mods, plain);
+                    }
+#else /*X_HAVE_UTF8_STRING*/
+                    wchar_t buffer[16];
+                    wchar_t* chars = buffer;
+
+                    count = XwcLookupString(window->x11.ic,
+                                            &event->xkey,
+                                            buffer, sizeof(buffer) / sizeof(wchar_t),
+                                            NULL, &status);
+
+                    if (status == XBufferOverflow)
+                    {
+                        chars = calloc(count, sizeof(wchar_t));
+                        count = XwcLookupString(window->x11.ic,
+                                                &event->xkey,
+                                                chars, count,
+                                                NULL, &status);
+                    }
+
+                    if (status == XLookupChars || status == XLookupBoth)
+                    {
+                        int i;
+                        for (i = 0;  i < count;  i++)
+                            _glfwInputChar(window, chars[i], mods, plain);
+                    }
+#endif /*X_HAVE_UTF8_STRING*/
+
+                    if (chars != buffer)
+                        free(chars);
+                }
+            }
+            else
+            {
+                KeySym keysym;
+                XLookupString(&event->xkey, NULL, 0, &keysym, NULL);
+
+                _glfwInputKey(window, key, keycode, GLFW_PRESS, mods);
+
+                const long character = _glfwKeySym2Unicode(keysym);
+                if (character != -1)
+                    _glfwInputChar(window, character, mods, plain);
+            }
+
+            return;
+        }
+
+        case KeyRelease:
+        {
+            const int key = translateKey(keycode);
+            const int mods = translateState(event->xkey.state);
+
+            if (!_glfw.x11.xkb.detectable)
+            {
+                // HACK: Key repeat events will arrive as KeyRelease/KeyPress
+                //       pairs with similar or identical time stamps
+                //       The key repeat logic in _glfwInputKey expects only key
+                //       presses to repeat, so detect and discard release events
+                if (XEventsQueued(_glfw.x11.display, QueuedAfterReading))
+                {
+                    XEvent next;
+                    XPeekEvent(_glfw.x11.display, &next);
+
+                    if (next.type == KeyPress &&
+                        next.xkey.window == event->xkey.window &&
+                        next.xkey.keycode == keycode)
+                    {
+                        // HACK: The time of repeat events sometimes doesn't
+                        //       match that of the press event, so add an
+                        //       epsilon
+                        //       Toshiyuki Takahashi can press a button
+                        //       16 times per second so it's fairly safe to
+                        //       assume that no human is pressing the key 50
+                        //       times per second (value is ms)
+                        if ((next.xkey.time - event->xkey.time) < 20)
+                        {
+                            // This is very likely a server-generated key repeat
+                            // event, so ignore it
+                            return;
+                        }
+                    }
+                }
+            }
+
+            _glfwInputKey(window, key, keycode, GLFW_RELEASE, mods);
+            return;
+        }
+
+        case ButtonPress:
+        {
+            const int mods = translateState(event->xbutton.state);
+
+            if (event->xbutton.button == Button1)
+                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS, mods);
+            else if (event->xbutton.button == Button2)
+                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS, mods);
+            else if (event->xbutton.button == Button3)
+                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS, mods);
+
+            // Modern X provides scroll events as mouse button presses
+            else if (event->xbutton.button == Button4)
+                _glfwInputScroll(window, 0.0, 1.0);
+            else if (event->xbutton.button == Button5)
+                _glfwInputScroll(window, 0.0, -1.0);
+            else if (event->xbutton.button == Button6)
+                _glfwInputScroll(window, 1.0, 0.0);
+            else if (event->xbutton.button == Button7)
+                _glfwInputScroll(window, -1.0, 0.0);
+
+            else
+            {
+                // Additional buttons after 7 are treated as regular buttons
+                // We subtract 4 to fill the gap left by scroll input above
+                _glfwInputMouseClick(window,
+                                     event->xbutton.button - Button1 - 4,
+                                     GLFW_PRESS,
+                                     mods);
+            }
+
+            return;
+        }
+
+        case ButtonRelease:
+        {
+            const int mods = translateState(event->xbutton.state);
+
+            if (event->xbutton.button == Button1)
+            {
+                _glfwInputMouseClick(window,
+                                     GLFW_MOUSE_BUTTON_LEFT,
+                                     GLFW_RELEASE,
+                                     mods);
+            }
+            else if (event->xbutton.button == Button2)
+            {
+                _glfwInputMouseClick(window,
+                                     GLFW_MOUSE_BUTTON_MIDDLE,
+                                     GLFW_RELEASE,
+                                     mods);
+            }
+            else if (event->xbutton.button == Button3)
+            {
+                _glfwInputMouseClick(window,
+                                     GLFW_MOUSE_BUTTON_RIGHT,
+                                     GLFW_RELEASE,
+                                     mods);
+            }
+            else if (event->xbutton.button > Button7)
+            {
+                // Additional buttons after 7 are treated as regular buttons
+                // We subtract 4 to fill the gap left by scroll input above
+                _glfwInputMouseClick(window,
+                                     event->xbutton.button - Button1 - 4,
+                                     GLFW_RELEASE,
+                                     mods);
+            }
+
+            return;
+        }
+
+        case EnterNotify:
+        {
+            // HACK: This is a workaround for WMs (KWM, Fluxbox) that otherwise
+            //       ignore the defined cursor for hidden cursor mode
+            if (window->cursorMode == GLFW_CURSOR_HIDDEN)
+                _glfwPlatformSetCursorMode(window, GLFW_CURSOR_HIDDEN);
+
+            _glfwInputCursorEnter(window, GLFW_TRUE);
+            return;
+        }
+
+        case LeaveNotify:
+        {
+            _glfwInputCursorEnter(window, GLFW_FALSE);
+            return;
+        }
+
+        case MotionNotify:
+        {
+            const int x = event->xmotion.x;
+            const int y = event->xmotion.y;
+
+            if (x != window->x11.warpCursorPosX || y != window->x11.warpCursorPosY)
+            {
+                // The cursor was moved by something other than GLFW
+
+                if (window->cursorMode == GLFW_CURSOR_DISABLED)
+                {
+                    if (_glfw.x11.disabledCursorWindow != window)
+                        return;
+
+                    const int dx = x - window->x11.lastCursorPosX;
+                    const int dy = y - window->x11.lastCursorPosY;
+
+                    _glfwInputCursorPos(window,
+                                        window->virtualCursorPosX + dx,
+                                        window->virtualCursorPosY + dy);
+                }
+                else
+                    _glfwInputCursorPos(window, x, y);
+            }
+
+            window->x11.lastCursorPosX = x;
+            window->x11.lastCursorPosY = y;
+            return;
+        }
+
+        case ConfigureNotify:
+        {
+            if (event->xconfigure.width != window->x11.width ||
+                event->xconfigure.height != window->x11.height)
+            {
+                _glfwInputFramebufferSize(window,
+                                          event->xconfigure.width,
+                                          event->xconfigure.height);
+
+                _glfwInputWindowSize(window,
+                                     event->xconfigure.width,
+                                     event->xconfigure.height);
+
+                window->x11.width = event->xconfigure.width;
+                window->x11.height = event->xconfigure.height;
+            }
+
+            if (event->xconfigure.x != window->x11.xpos ||
+                event->xconfigure.y != window->x11.ypos)
+            {
+                if (window->x11.overrideRedirect || event->xany.send_event)
+                {
+                    _glfwInputWindowPos(window,
+                                        event->xconfigure.x,
+                                        event->xconfigure.y);
+
+                    window->x11.xpos = event->xconfigure.x;
+                    window->x11.ypos = event->xconfigure.y;
+                }
+            }
+
+            return;
+        }
+
+        case ClientMessage:
+        {
+            // Custom client message, probably from the window manager
+
+            if (filtered)
+                return;
+
+            if (event->xclient.message_type == None)
+                return;
+
+            if (event->xclient.message_type == _glfw.x11.WM_PROTOCOLS)
+            {
+                const Atom protocol = event->xclient.data.l[0];
+                if (protocol == None)
+                    return;
+
+                if (protocol == _glfw.x11.WM_DELETE_WINDOW)
+                {
+                    // The window manager was asked to close the window, for example by
+                    // the user pressing a 'close' window decoration button
+                    _glfwInputWindowCloseRequest(window);
+                }
+                else if (protocol == _glfw.x11.NET_WM_PING)
+                {
+                    // The window manager is pinging the application to ensure it's
+                    // still responding to events
+
+                    XEvent reply = *event;
+                    reply.xclient.window = _glfw.x11.root;
+
+                    XSendEvent(_glfw.x11.display, _glfw.x11.root,
+                               False,
+                               SubstructureNotifyMask | SubstructureRedirectMask,
+                               &reply);
+                }
+            }
+            else if (event->xclient.message_type == _glfw.x11.XdndEnter)
+            {
+                // A drag operation has entered the window
+                // TODO: Check if UTF-8 string is supported by the source
+            }
+            else if (event->xclient.message_type == _glfw.x11.XdndDrop)
+            {
+                // The drag operation has finished dropping on
+                // the window, ask to convert it to a UTF-8 string
+                _glfw.x11.xdnd.source = event->xclient.data.l[0];
+                XConvertSelection(_glfw.x11.display,
+                                  _glfw.x11.XdndSelection,
+                                  _glfw.x11.UTF8_STRING,
+                                  _glfw.x11.XdndSelection,
+                                  window->x11.handle, CurrentTime);
+            }
+            else if (event->xclient.message_type == _glfw.x11.XdndPosition)
+            {
+                // The drag operation has moved over the window
+                const int absX = (event->xclient.data.l[2] >> 16) & 0xFFFF;
+                const int absY = (event->xclient.data.l[2]) & 0xFFFF;
+                int x, y;
+
+                _glfwPlatformGetWindowPos(window, &x, &y);
+                _glfwInputCursorPos(window, absX - x, absY - y);
+
+                // Reply that we are ready to copy the dragged data
+                XEvent reply;
+                memset(&reply, 0, sizeof(reply));
+
+                reply.type = ClientMessage;
+                reply.xclient.window = event->xclient.data.l[0];
+                reply.xclient.message_type = _glfw.x11.XdndStatus;
+                reply.xclient.format = 32;
+                reply.xclient.data.l[0] = window->x11.handle;
+                reply.xclient.data.l[1] = 1; // Always accept the dnd with no rectangle
+                reply.xclient.data.l[2] = 0; // Specify an empty rectangle
+                reply.xclient.data.l[3] = 0;
+                reply.xclient.data.l[4] = _glfw.x11.XdndActionCopy;
+
+                XSendEvent(_glfw.x11.display, event->xclient.data.l[0],
+                           False, NoEventMask, &reply);
+                XFlush(_glfw.x11.display);
+            }
+
+            return;
+        }
+
+        case SelectionNotify:
+        {
+            if (event->xselection.property)
+            {
+                // The converted data from the drag operation has arrived
+                char* data;
+                const int result =
+                    _glfwGetWindowPropertyX11(event->xselection.requestor,
+                                              event->xselection.property,
+                                              event->xselection.target,
+                                              (unsigned char**) &data);
+
+                if (result)
+                {
+                    int i, count;
+                    char** paths = parseUriList(data, &count);
+
+                    _glfwInputDrop(window, count, (const char**) paths);
+
+                    for (i = 0;  i < count;  i++)
+                        free(paths[i]);
+                    free(paths);
+                }
+
+                XFree(data);
+
+                XEvent reply;
+                memset(&reply, 0, sizeof(reply));
+
+                reply.type = ClientMessage;
+                reply.xclient.window = _glfw.x11.xdnd.source;
+                reply.xclient.message_type = _glfw.x11.XdndFinished;
+                reply.xclient.format = 32;
+                reply.xclient.data.l[0] = window->x11.handle;
+                reply.xclient.data.l[1] = result;
+                reply.xclient.data.l[2] = _glfw.x11.XdndActionCopy;
+
+                // Reply that all is well
+                XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source,
+                           False, NoEventMask, &reply);
+                XFlush(_glfw.x11.display);
+            }
+
+            return;
+        }
+
+        case FocusIn:
+        {
+            if (window->cursorMode == GLFW_CURSOR_DISABLED)
+                _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED);
+
+            if (event->xfocus.mode == NotifyGrab ||
+                event->xfocus.mode == NotifyUngrab)
+            {
+                // Ignore focus events from popup indicator windows, window menu
+                // key chords and window dragging
+                return;
+            }
+
+            if (window->x11.ic)
+                XSetICFocus(window->x11.ic);
+
+            _glfwInputWindowFocus(window, GLFW_TRUE);
+            return;
+        }
+
+        case FocusOut:
+        {
+            if (window->cursorMode == GLFW_CURSOR_DISABLED)
+                _glfwPlatformSetCursorMode(window, GLFW_CURSOR_NORMAL);
+
+            if (event->xfocus.mode == NotifyGrab ||
+                event->xfocus.mode == NotifyUngrab)
+            {
+                // Ignore focus events from popup indicator windows, window menu
+                // key chords and window dragging
+                return;
+            }
+
+            if (window->x11.ic)
+                XUnsetICFocus(window->x11.ic);
+
+            if (window->monitor && window->autoIconify)
+                _glfwPlatformIconifyWindow(window);
+
+            _glfwInputWindowFocus(window, GLFW_FALSE);
+            return;
+        }
+
+        case Expose:
+        {
+            _glfwInputWindowDamage(window);
+            return;
+        }
+
+        case PropertyNotify:
+        {
+            if (event->xproperty.atom == _glfw.x11.WM_STATE &&
+                event->xproperty.state == PropertyNewValue)
+            {
+                const int state = getWindowState(window);
+                if (state == IconicState)
+                {
+                    if (window->monitor)
+                        releaseMonitor(window);
+
+                    _glfwInputWindowIconify(window, GLFW_TRUE);
+                }
+                else if (state == NormalState)
+                {
+                    if (window->monitor)
+                        acquireMonitor(window);
+
+                    _glfwInputWindowIconify(window, GLFW_FALSE);
+                }
+            }
+
+            return;
+        }
+
+        case SelectionClear:
+        {
+            handleSelectionClear(event);
+            return;
+        }
+
+        case SelectionRequest:
+        {
+            handleSelectionRequest(event);
+            return;
+        }
+
+        case DestroyNotify:
+            return;
+    }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                       GLFW internal API                      //////
+//////////////////////////////////////////////////////////////////////////
+
+// Retrieve a single window property of the specified type
+// Inspired by fghGetWindowProperty from freeglut
+//
+unsigned long _glfwGetWindowPropertyX11(Window window,
+                                        Atom property,
+                                        Atom type,
+                                        unsigned char** value)
+{
+    Atom actualType;
+    int actualFormat;
+    unsigned long itemCount, bytesAfter;
+
+    XGetWindowProperty(_glfw.x11.display,
+                       window,
+                       property,
+                       0,
+                       LONG_MAX,
+                       False,
+                       type,
+                       &actualType,
+                       &actualFormat,
+                       &itemCount,
+                       &bytesAfter,
+                       value);
+
+    if (type != AnyPropertyType && actualType != type)
+        return 0;
+
+    return itemCount;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                       GLFW platform API                      //////
+//////////////////////////////////////////////////////////////////////////
+
+int _glfwPlatformCreateWindow(_GLFWwindow* window,
+                              const _GLFWwndconfig* wndconfig,
+                              const _GLFWctxconfig* ctxconfig,
+                              const _GLFWfbconfig* fbconfig)
+{
+    Visual* visual;
+    int depth;
+
+    if (ctxconfig->client == GLFW_NO_API)
+    {
+        visual = DefaultVisual(_glfw.x11.display, _glfw.x11.screen);
+        depth = DefaultDepth(_glfw.x11.display, _glfw.x11.screen);
+    }
+    else
+    {
+        if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API)
+        {
+            if (!_glfwInitGLX())
+                return GLFW_FALSE;
+            if (!_glfwChooseVisualGLX(ctxconfig, fbconfig, &visual, &depth))
+                return GLFW_FALSE;
+        }
+        else
+        {
+            if (!_glfwInitEGL())
+                return GLFW_FALSE;
+            if (!_glfwChooseVisualEGL(ctxconfig, fbconfig, &visual, &depth))
+                return GLFW_FALSE;
+        }
+    }
+
+    if (!createNativeWindow(window, wndconfig, visual, depth))
+        return GLFW_FALSE;
+
+    if (ctxconfig->client != GLFW_NO_API)
+    {
+        if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API)
+        {
+            if (!_glfwCreateContextGLX(window, ctxconfig, fbconfig))
+                return GLFW_FALSE;
+        }
+        else
+        {
+            if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
+                return GLFW_FALSE;
+        }
+    }
+
+    if (window->monitor)
+    {
+        _glfwPlatformShowWindow(window);
+        updateWindowMode(window);
+        if (!acquireMonitor(window))
+            return GLFW_FALSE;
+
+        centerCursor(window);
+    }
+
+    XFlush(_glfw.x11.display);
+    return GLFW_TRUE;
+}
+
+void _glfwPlatformDestroyWindow(_GLFWwindow* window)
+{
+    if (_glfw.x11.disabledCursorWindow == window)
+        _glfw.x11.disabledCursorWindow = NULL;
+
+    if (window->monitor)
+        releaseMonitor(window);
+
+    if (window->x11.ic)
+    {
+        XDestroyIC(window->x11.ic);
+        window->x11.ic = NULL;
+    }
+
+    if (window->context.destroy)
+        window->context.destroy(window);
+
+    if (window->x11.handle)
+    {
+        if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) ==
+            window->x11.handle)
+        {
+            pushSelectionToManager(window);
+        }
+
+        XDeleteContext(_glfw.x11.display, window->x11.handle, _glfw.x11.context);
+        XUnmapWindow(_glfw.x11.display, window->x11.handle);
+        XDestroyWindow(_glfw.x11.display, window->x11.handle);
+        window->x11.handle = (Window) 0;
+    }
+
+    if (window->x11.colormap)
+    {
+        XFreeColormap(_glfw.x11.display, window->x11.colormap);
+        window->x11.colormap = (Colormap) 0;
+    }
+
+    XFlush(_glfw.x11.display);
+}
+
+void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
+{
+#if defined(X_HAVE_UTF8_STRING)
+    Xutf8SetWMProperties(_glfw.x11.display,
+                         window->x11.handle,
+                         title, title,
+                         NULL, 0,
+                         NULL, NULL, NULL);
+#else
+    // This may be a slightly better fallback than using XStoreName and
+    // XSetIconName, which always store their arguments using STRING
+    XmbSetWMProperties(_glfw.x11.display,
+                       window->x11.handle,
+                       title, title,
+                       NULL, 0,
+                       NULL, NULL, NULL);
+#endif
+
+    XChangeProperty(_glfw.x11.display,  window->x11.handle,
+                    _glfw.x11.NET_WM_NAME, _glfw.x11.UTF8_STRING, 8,
+                    PropModeReplace,
+                    (unsigned char*) title, strlen(title));
+
+    XChangeProperty(_glfw.x11.display,  window->x11.handle,
+                    _glfw.x11.NET_WM_ICON_NAME, _glfw.x11.UTF8_STRING, 8,
+                    PropModeReplace,
+                    (unsigned char*) title, strlen(title));
+
+    XFlush(_glfw.x11.display);
+}
+
+void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
+                                int count, const GLFWimage* images)
+{
+    if (count)
+    {
+        int i, j, longCount = 0;
+
+        for (i = 0;  i < count;  i++)
+            longCount += 2 + images[i].width * images[i].height;
+
+        long* icon = calloc(longCount, sizeof(long));
+        long* target = icon;
+
+        for (i = 0;  i < count;  i++)
+        {
+            *target++ = images[i].width;
+            *target++ = images[i].height;
+
+            for (j = 0;  j < images[i].width * images[i].height;  j++)
+            {
+                *target++ = (images[i].pixels[j * 4 + 0] << 16) |
+                            (images[i].pixels[j * 4 + 1] <<  8) |
+                            (images[i].pixels[j * 4 + 2] <<  0) |
+                            (images[i].pixels[j * 4 + 3] << 24);
+            }
+        }
+
+        XChangeProperty(_glfw.x11.display, window->x11.handle,
+                        _glfw.x11.NET_WM_ICON,
+                        XA_CARDINAL, 32,
+                        PropModeReplace,
+                        (unsigned char*) icon,
+                        longCount);
+
+        free(icon);
+    }
+    else
+    {
+        XDeleteProperty(_glfw.x11.display, window->x11.handle,
+                        _glfw.x11.NET_WM_ICON);
+    }
+
+    XFlush(_glfw.x11.display);
+}
+
+void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
+{
+    Window dummy;
+    int x, y;
+
+    XTranslateCoordinates(_glfw.x11.display, window->x11.handle, _glfw.x11.root,
+                          0, 0, &x, &y, &dummy);
+
+    if (xpos)
+        *xpos = x;
+    if (ypos)
+        *ypos = y;
+}
+
+void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
+{
+    // HACK: Explicitly setting PPosition to any value causes some WMs, notably
+    //       Compiz and Metacity, to honor the position of unmapped windows
+    if (!_glfwPlatformWindowVisible(window))
+    {
+        long supplied;
+        XSizeHints* hints = XAllocSizeHints();
+
+        if (XGetWMNormalHints(_glfw.x11.display, window->x11.handle, hints, &supplied))
+        {
+            hints->flags |= PPosition;
+            hints->x = hints->y = 0;
+
+            XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints);
+        }
+
+        XFree(hints);
+    }
+
+    XMoveWindow(_glfw.x11.display, window->x11.handle, xpos, ypos);
+    XFlush(_glfw.x11.display);
+}
+
+void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
+{
+    XWindowAttributes attribs;
+    XGetWindowAttributes(_glfw.x11.display, window->x11.handle, &attribs);
+
+    if (width)
+        *width = attribs.width;
+    if (height)
+        *height = attribs.height;
+}
+
+void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
+{
+    if (window->monitor)
+    {
+        if (window->monitor->window == window)
+            acquireMonitor(window);
+    }
+    else
+    {
+        if (!window->resizable)
+            updateNormalHints(window, width, height);
+
+        XResizeWindow(_glfw.x11.display, window->x11.handle, width, height);
+    }
+
+    XFlush(_glfw.x11.display);
+}
+
+void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
+                                      int minwidth, int minheight,
+                                      int maxwidth, int maxheight)
+{
+    int width, height;
+    _glfwPlatformGetWindowSize(window, &width, &height);
+    updateNormalHints(window, width, height);
+    XFlush(_glfw.x11.display);
+}
+
+void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom)
+{
+    int width, height;
+    _glfwPlatformGetWindowSize(window, &width, &height);
+    updateNormalHints(window, width, height);
+    XFlush(_glfw.x11.display);
+}
+
+void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height)
+{
+    _glfwPlatformGetWindowSize(window, width, height);
+}
+
+void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
+                                     int* left, int* top,
+                                     int* right, int* bottom)
+{
+    long* extents = NULL;
+
+    if (window->monitor || !window->decorated)
+        return;
+
+    if (_glfw.x11.NET_FRAME_EXTENTS == None)
+        return;
+
+    if (!_glfwPlatformWindowVisible(window) &&
+        _glfw.x11.NET_REQUEST_FRAME_EXTENTS)
+    {
+        XEvent event;
+        double timeout = 0.5;
+
+        // Ensure _NET_FRAME_EXTENTS is set, allowing glfwGetWindowFrameSize to
+        // function before the window is mapped
+        sendEventToWM(window, _glfw.x11.NET_REQUEST_FRAME_EXTENTS,
+                      0, 0, 0, 0, 0);
+
+        // HACK: Use a timeout because earlier versions of some window managers
+        //       (at least Unity, Fluxbox and Xfwm) failed to send the reply
+        //       They have been fixed but broken versions are still in the wild
+        //       If you are affected by this and your window manager is NOT
+        //       listed above, PLEASE report it to their and our issue trackers
+        while (!XCheckIfEvent(_glfw.x11.display,
+                              &event,
+                              isFrameExtentsEvent,
+                              (XPointer) window))
+        {
+            if (!waitForEvent(&timeout))
+            {
+                _glfwInputError(GLFW_PLATFORM_ERROR,
+                                "X11: The window manager has a broken _NET_REQUEST_FRAME_EXTENTS implementation; please report this issue");
+                return;
+            }
+        }
+    }
+
+    if (_glfwGetWindowPropertyX11(window->x11.handle,
+                                  _glfw.x11.NET_FRAME_EXTENTS,
+                                  XA_CARDINAL,
+                                  (unsigned char**) &extents) == 4)
+    {
+        if (left)
+            *left = extents[0];
+        if (top)
+            *top = extents[2];
+        if (right)
+            *right = extents[1];
+        if (bottom)
+            *bottom = extents[3];
+    }
+
+    if (extents)
+        XFree(extents);
+}
+
+void _glfwPlatformIconifyWindow(_GLFWwindow* window)
+{
+    if (window->x11.overrideRedirect)
+    {
+        // Override-redirect windows cannot be iconified or restored, as those
+        // tasks are performed by the window manager
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "X11: Iconification of full screen windows requires a WM that supports EWMH full screen");
+        return;
+    }
+
+    XIconifyWindow(_glfw.x11.display, window->x11.handle, _glfw.x11.screen);
+    XFlush(_glfw.x11.display);
+}
+
+void _glfwPlatformRestoreWindow(_GLFWwindow* window)
+{
+    if (window->x11.overrideRedirect)
+    {
+        // Override-redirect windows cannot be iconified or restored, as those
+        // tasks are performed by the window manager
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "X11: Iconification of full screen windows requires a WM that supports EWMH full screen");
+        return;
+    }
+
+    if (_glfwPlatformWindowIconified(window))
+    {
+        XMapWindow(_glfw.x11.display, window->x11.handle);
+        waitForVisibilityNotify(window);
+    }
+    else if (_glfwPlatformWindowVisible(window))
+    {
+        if (_glfw.x11.NET_WM_STATE &&
+            _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT &&
+            _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ)
+        {
+            sendEventToWM(window,
+                          _glfw.x11.NET_WM_STATE,
+                          _NET_WM_STATE_REMOVE,
+                          _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT,
+                          _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ,
+                          1, 0);
+        }
+    }
+
+    XFlush(_glfw.x11.display);
+}
+
+void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
+{
+    if (_glfw.x11.NET_WM_STATE &&
+        _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT &&
+        _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ)
+    {
+        sendEventToWM(window,
+                      _glfw.x11.NET_WM_STATE,
+                      _NET_WM_STATE_ADD,
+                      _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT,
+                      _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ,
+                      1, 0);
+        XFlush(_glfw.x11.display);
+    }
+}
+
+void _glfwPlatformShowWindow(_GLFWwindow* window)
+{
+    if (_glfwPlatformWindowVisible(window))
+        return;
+
+    XMapWindow(_glfw.x11.display, window->x11.handle);
+    waitForVisibilityNotify(window);
+}
+
+void _glfwPlatformHideWindow(_GLFWwindow* window)
+{
+    XUnmapWindow(_glfw.x11.display, window->x11.handle);
+    XFlush(_glfw.x11.display);
+}
+
+void _glfwPlatformFocusWindow(_GLFWwindow* window)
+{
+    if (_glfw.x11.NET_ACTIVE_WINDOW)
+        sendEventToWM(window, _glfw.x11.NET_ACTIVE_WINDOW, 1, 0, 0, 0, 0);
+    else
+    {
+        XRaiseWindow(_glfw.x11.display, window->x11.handle);
+        XSetInputFocus(_glfw.x11.display, window->x11.handle,
+                       RevertToParent, CurrentTime);
+    }
+
+    XFlush(_glfw.x11.display);
+}
+
+void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
+                                   _GLFWmonitor* monitor,
+                                   int xpos, int ypos,
+                                   int width, int height,
+                                   int refreshRate)
+{
+    if (window->monitor == monitor)
+    {
+        if (monitor)
+        {
+            if (monitor->window == window)
+                acquireMonitor(window);
+        }
+        else
+        {
+            XMoveResizeWindow(_glfw.x11.display, window->x11.handle,
+                              xpos, ypos, width, height);
+        }
+
+        return;
+    }
+
+    if (window->monitor)
+        releaseMonitor(window);
+
+    _glfwInputWindowMonitorChange(window, monitor);
+    updateNormalHints(window, width, height);
+    updateWindowMode(window);
+
+    if (window->monitor)
+    {
+        XMapRaised(_glfw.x11.display, window->x11.handle);
+        if (waitForVisibilityNotify(window))
+            acquireMonitor(window);
+    }
+    else
+    {
+        XMoveResizeWindow(_glfw.x11.display, window->x11.handle,
+                          xpos, ypos, width, height);
+    }
+
+    XFlush(_glfw.x11.display);
+}
+
+int _glfwPlatformWindowFocused(_GLFWwindow* window)
+{
+    Window focused;
+    int state;
+
+    XGetInputFocus(_glfw.x11.display, &focused, &state);
+    return window->x11.handle == focused;
+}
+
+int _glfwPlatformWindowIconified(_GLFWwindow* window)
+{
+    return getWindowState(window) == IconicState;
+}
+
+int _glfwPlatformWindowVisible(_GLFWwindow* window)
+{
+    XWindowAttributes wa;
+    XGetWindowAttributes(_glfw.x11.display, window->x11.handle, &wa);
+    return wa.map_state == IsViewable;
+}
+
+int _glfwPlatformWindowMaximized(_GLFWwindow* window)
+{
+    Atom* states;
+    unsigned long i;
+    GLFWbool maximized = GLFW_FALSE;
+    const unsigned long count =
+        _glfwGetWindowPropertyX11(window->x11.handle,
+                                  _glfw.x11.NET_WM_STATE,
+                                  XA_ATOM,
+                                  (unsigned char**) &states);
+
+    for (i = 0;  i < count;  i++)
+    {
+        if (states[i] == _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT ||
+            states[i] == _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ)
+        {
+            maximized = GLFW_TRUE;
+            break;
+        }
+    }
+
+    XFree(states);
+    return maximized;
+}
+
+void _glfwPlatformPollEvents(void)
+{
+    _glfwPollJoystickEvents();
+
+    int count = XPending(_glfw.x11.display);
+    while (count--)
+    {
+        XEvent event;
+        XNextEvent(_glfw.x11.display, &event);
+        processEvent(&event);
+    }
+
+    if (_glfw.x11.disabledCursorWindow)
+        centerCursor(_glfw.x11.disabledCursorWindow);
+
+    XFlush(_glfw.x11.display);
+}
+
+void _glfwPlatformWaitEvents(void)
+{
+    while (!XPending(_glfw.x11.display))
+        waitForEvent(NULL);
+
+    _glfwPlatformPollEvents();
+}
+
+void _glfwPlatformWaitEventsTimeout(double timeout)
+{
+    while (!XPending(_glfw.x11.display))
+    {
+        if (!waitForEvent(&timeout))
+            break;
+    }
+
+    _glfwPlatformPollEvents();
+}
+
+void _glfwPlatformPostEmptyEvent(void)
+{
+    XEvent event;
+    _GLFWwindow* window = _glfw.windowListHead;
+
+    memset(&event, 0, sizeof(event));
+    event.type = ClientMessage;
+    event.xclient.window = window->x11.handle;
+    event.xclient.format = 32; // Data is 32-bit longs
+    event.xclient.message_type = _glfw.x11.NULL_;
+
+    XSendEvent(_glfw.x11.display, window->x11.handle, False, 0, &event);
+    XFlush(_glfw.x11.display);
+}
+
+void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
+{
+    Window root, child;
+    int rootX, rootY, childX, childY;
+    unsigned int mask;
+
+    XQueryPointer(_glfw.x11.display, window->x11.handle,
+                  &root, &child,
+                  &rootX, &rootY, &childX, &childY,
+                  &mask);
+
+    if (xpos)
+        *xpos = childX;
+    if (ypos)
+        *ypos = childY;
+}
+
+void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
+{
+    // Store the new position so it can be recognized later
+    window->x11.warpCursorPosX = (int) x;
+    window->x11.warpCursorPosY = (int) y;
+
+    XWarpPointer(_glfw.x11.display, None, window->x11.handle,
+                 0,0,0,0, (int) x, (int) y);
+    XFlush(_glfw.x11.display);
+}
+
+void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
+{
+    if (mode == GLFW_CURSOR_DISABLED)
+    {
+        _glfw.x11.disabledCursorWindow = window;
+        _glfwPlatformGetCursorPos(window,
+                                  &_glfw.x11.restoreCursorPosX,
+                                  &_glfw.x11.restoreCursorPosY);
+        centerCursor(window);
+        XGrabPointer(_glfw.x11.display, window->x11.handle, True,
+                     ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
+                     GrabModeAsync, GrabModeAsync,
+                     window->x11.handle, _glfw.x11.cursor, CurrentTime);
+    }
+    else if (_glfw.x11.disabledCursorWindow == window)
+    {
+        _glfw.x11.disabledCursorWindow = NULL;
+        XUngrabPointer(_glfw.x11.display, CurrentTime);
+        _glfwPlatformSetCursorPos(window,
+                                  _glfw.x11.restoreCursorPosX,
+                                  _glfw.x11.restoreCursorPosY);
+    }
+
+    updateCursorImage(window);
+    XFlush(_glfw.x11.display);
+}
+
+const char* _glfwPlatformGetKeyName(int key, int scancode)
+{
+    KeySym keysym;
+    int extra;
+
+    if (!_glfw.x11.xkb.available)
+        return NULL;
+
+    if (key != GLFW_KEY_UNKNOWN)
+        scancode = _glfw.x11.nativeKeys[key];
+
+    if (!_glfwIsPrintable(_glfw.x11.publicKeys[scancode]))
+        return NULL;
+
+    keysym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, 0, 0);
+    if (keysym == NoSymbol)
+      return NULL;
+
+    XkbTranslateKeySym(_glfw.x11.display, &keysym, 0,
+                       _glfw.x11.keyName, sizeof(_glfw.x11.keyName),
+                       &extra);
+
+    if (!strlen(_glfw.x11.keyName))
+        return NULL;
+
+    return _glfw.x11.keyName;
+}
+
+int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
+                              const GLFWimage* image,
+                              int xhot, int yhot)
+{
+    cursor->x11.handle = _glfwCreateCursorX11(image, xhot, yhot);
+    if (!cursor->x11.handle)
+        return GLFW_FALSE;
+
+    return GLFW_TRUE;
+}
+
+int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
+{
+    cursor->x11.handle = XCreateFontCursor(_glfw.x11.display,
+                                           translateCursorShape(shape));
+    if (!cursor->x11.handle)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "X11: Failed to create standard cursor");
+        return GLFW_FALSE;
+    }
+
+    return GLFW_TRUE;
+}
+
+void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
+{
+    if (cursor->x11.handle)
+        XFreeCursor(_glfw.x11.display, cursor->x11.handle);
+}
+
+void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
+{
+    if (window->cursorMode == GLFW_CURSOR_NORMAL)
+    {
+        updateCursorImage(window);
+        XFlush(_glfw.x11.display);
+    }
+}
+
+void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
+{
+    free(_glfw.x11.clipboardString);
+    _glfw.x11.clipboardString = strdup(string);
+
+    XSetSelectionOwner(_glfw.x11.display,
+                       _glfw.x11.CLIPBOARD,
+                       window->x11.handle, CurrentTime);
+
+    if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) !=
+        window->x11.handle)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "X11: Failed to become owner of clipboard selection");
+    }
+}
+
+const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
+{
+    size_t i;
+    const Atom formats[] = { _glfw.x11.UTF8_STRING,
+                             _glfw.x11.COMPOUND_STRING,
+                             XA_STRING };
+    const size_t formatCount = sizeof(formats) / sizeof(formats[0]);
+
+    if (findWindowByHandle(XGetSelectionOwner(_glfw.x11.display,
+                                              _glfw.x11.CLIPBOARD)))
+    {
+        // Instead of doing a large number of X round-trips just to put this
+        // string into a window property and then read it back, just return it
+        return _glfw.x11.clipboardString;
+    }
+
+    free(_glfw.x11.clipboardString);
+    _glfw.x11.clipboardString = NULL;
+
+    for (i = 0;  i < formatCount;  i++)
+    {
+        char* data;
+        XEvent event;
+
+        XConvertSelection(_glfw.x11.display,
+                          _glfw.x11.CLIPBOARD,
+                          formats[i],
+                          _glfw.x11.GLFW_SELECTION,
+                          window->x11.handle, CurrentTime);
+
+        while (!XCheckTypedEvent(_glfw.x11.display, SelectionNotify, &event))
+            waitForEvent(NULL);
+
+        if (event.xselection.property == None)
+            continue;
+
+        if (_glfwGetWindowPropertyX11(event.xselection.requestor,
+                                      event.xselection.property,
+                                      event.xselection.target,
+                                      (unsigned char**) &data))
+        {
+            _glfw.x11.clipboardString = strdup(data);
+        }
+
+        XFree(data);
+
+        XDeleteProperty(_glfw.x11.display,
+                        event.xselection.requestor,
+                        event.xselection.property);
+
+        if (_glfw.x11.clipboardString)
+            break;
+    }
+
+    if (_glfw.x11.clipboardString == NULL)
+    {
+        _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
+                        "X11: Failed to convert clipboard to string");
+    }
+
+    return _glfw.x11.clipboardString;
+}
+
+char** _glfwPlatformGetRequiredInstanceExtensions(uint32_t* count)
+{
+    char** extensions;
+
+    *count = 0;
+
+    if (!_glfw.vk.KHR_xcb_surface || !_glfw.x11.x11xcb.handle)
+    {
+        if (!_glfw.vk.KHR_xlib_surface)
+            return NULL;
+    }
+
+    extensions = calloc(2, sizeof(char*));
+    extensions[0] = strdup("VK_KHR_surface");
+
+    if (_glfw.vk.KHR_xcb_surface && _glfw.x11.x11xcb.handle)
+        extensions[1] = strdup("VK_KHR_xcb_surface");
+    else
+        extensions[1] = strdup("VK_KHR_xlib_surface");
+
+    *count = 2;
+    return extensions;
+}
+
+int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
+                                                      VkPhysicalDevice device,
+                                                      uint32_t queuefamily)
+{
+    VisualID visualID = XVisualIDFromVisual(DefaultVisual(_glfw.x11.display,
+                                                          _glfw.x11.screen));
+
+    if (_glfw.vk.KHR_xcb_surface && _glfw.x11.x11xcb.handle)
+    {
+        PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR vkGetPhysicalDeviceXcbPresentationSupportKHR =
+            (PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)
+            vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceXcbPresentationSupportKHR");
+        if (!vkGetPhysicalDeviceXcbPresentationSupportKHR)
+        {
+            _glfwInputError(GLFW_API_UNAVAILABLE,
+                            "X11: Vulkan instance missing VK_KHR_xcb_surface extension");
+            return GLFW_FALSE;
+        }
+
+        xcb_connection_t* connection =
+            _glfw.x11.x11xcb.XGetXCBConnection(_glfw.x11.display);
+        if (!connection)
+        {
+            _glfwInputError(GLFW_PLATFORM_ERROR,
+                            "X11: Failed to retrieve XCB connection");
+            return GLFW_FALSE;
+        }
+
+        return vkGetPhysicalDeviceXcbPresentationSupportKHR(device,
+                                                            queuefamily,
+                                                            connection,
+                                                            visualID);
+    }
+    else
+    {
+        PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR =
+            (PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)
+            vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceXlibPresentationSupportKHR");
+        if (!vkGetPhysicalDeviceXlibPresentationSupportKHR)
+        {
+            _glfwInputError(GLFW_API_UNAVAILABLE,
+                            "X11: Vulkan instance missing VK_KHR_xlib_surface extension");
+            return GLFW_FALSE;
+        }
+
+        return vkGetPhysicalDeviceXlibPresentationSupportKHR(device,
+                                                             queuefamily,
+                                                             _glfw.x11.display,
+                                                             visualID);
+    }
+}
+
+VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
+                                          _GLFWwindow* window,
+                                          const VkAllocationCallbacks* allocator,
+                                          VkSurfaceKHR* surface)
+{
+    if (_glfw.vk.KHR_xcb_surface && _glfw.x11.x11xcb.handle)
+    {
+        VkResult err;
+        VkXcbSurfaceCreateInfoKHR sci;
+        PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR;
+
+        xcb_connection_t* connection =
+            _glfw.x11.x11xcb.XGetXCBConnection(_glfw.x11.display);
+        if (!connection)
+        {
+            _glfwInputError(GLFW_PLATFORM_ERROR,
+                            "X11: Failed to retrieve XCB connection");
+            return VK_ERROR_EXTENSION_NOT_PRESENT;
+        }
+
+        vkCreateXcbSurfaceKHR = (PFN_vkCreateXcbSurfaceKHR)
+            vkGetInstanceProcAddr(instance, "vkCreateXcbSurfaceKHR");
+        if (!vkCreateXcbSurfaceKHR)
+        {
+            _glfwInputError(GLFW_API_UNAVAILABLE,
+                            "X11: Vulkan instance missing VK_KHR_xcb_surface extension");
+            return VK_ERROR_EXTENSION_NOT_PRESENT;
+        }
+
+        memset(&sci, 0, sizeof(sci));
+        sci.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
+        sci.connection = connection;
+        sci.window = window->x11.handle;
+
+        err = vkCreateXcbSurfaceKHR(instance, &sci, allocator, surface);
+        if (err)
+        {
+            _glfwInputError(GLFW_PLATFORM_ERROR,
+                            "X11: Failed to create Vulkan XCB surface: %s",
+                            _glfwGetVulkanResultString(err));
+        }
+
+        return err;
+    }
+    else
+    {
+        VkResult err;
+        VkXlibSurfaceCreateInfoKHR sci;
+        PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR;
+
+        vkCreateXlibSurfaceKHR = (PFN_vkCreateXlibSurfaceKHR)
+            vkGetInstanceProcAddr(instance, "vkCreateXlibSurfaceKHR");
+        if (!vkCreateXlibSurfaceKHR)
+        {
+            _glfwInputError(GLFW_API_UNAVAILABLE,
+                            "X11: Vulkan instance missing VK_KHR_xlib_surface extension");
+            return VK_ERROR_EXTENSION_NOT_PRESENT;
+        }
+
+        memset(&sci, 0, sizeof(sci));
+        sci.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
+        sci.dpy = _glfw.x11.display;
+        sci.window = window->x11.handle;
+
+        err = vkCreateXlibSurfaceKHR(instance, &sci, allocator, surface);
+        if (err)
+        {
+            _glfwInputError(GLFW_PLATFORM_ERROR,
+                            "X11: Failed to create Vulkan X11 surface: %s",
+                            _glfwGetVulkanResultString(err));
+        }
+
+        return err;
+    }
 }
 
 
diff --git a/glfw/src/xkb_unicode.c b/glfw/src/xkb_unicode.c
--- a/glfw/src/xkb_unicode.c
+++ b/glfw/src/xkb_unicode.c
@@ -1,8 +1,8 @@
 //========================================================================
-// GLFW 3.1 X11 - www.glfw.org
+// GLFW 3.2 X11 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
-// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -827,24 +827,24 @@
   { 0x13be, 0x0178 },
   { 0x20ac, 0x20ac },
   // Numeric keypad with numlock on
-  { XK_KP_Space, ' ' },
-  { XK_KP_Equal, '=' },
-  { XK_KP_Multiply, '*' },
-  { XK_KP_Add, '+' },
-  { XK_KP_Separator, ',' },
-  { XK_KP_Subtract, '-' },
-  { XK_KP_Decimal, '.' },
-  { XK_KP_Divide, '/' },
-  { XK_KP_0, 0x0030 },
-  { XK_KP_1, 0x0031 },
-  { XK_KP_2, 0x0032 },
-  { XK_KP_3, 0x0033 },
-  { XK_KP_4, 0x0034 },
-  { XK_KP_5, 0x0035 },
-  { XK_KP_6, 0x0036 },
-  { XK_KP_7, 0x0037 },
-  { XK_KP_8, 0x0038 },
-  { XK_KP_9, 0x0039 }
+  { 0xff80 /*XKB_KEY_KP_Space*/,     ' ' },
+  { 0xffbd /*XKB_KEY_KP_Equal*/,     '=' },
+  { 0xffaa /*XKB_KEY_KP_Multiply*/,  '*' },
+  { 0xffab /*XKB_KEY_KP_Add*/,       '+' },
+  { 0xffac /*XKB_KEY_KP_Separator*/, ',' },
+  { 0xffad /*XKB_KEY_KP_Subtract*/,  '-' },
+  { 0xffae /*XKB_KEY_KP_Decimal*/,   '.' },
+  { 0xffaf /*XKB_KEY_KP_Divide*/,    '/' },
+  { 0xffb0 /*XKB_KEY_KP_0*/, 0x0030 },
+  { 0xffb1 /*XKB_KEY_KP_1*/, 0x0031 },
+  { 0xffb2 /*XKB_KEY_KP_2*/, 0x0032 },
+  { 0xffb3 /*XKB_KEY_KP_3*/, 0x0033 },
+  { 0xffb4 /*XKB_KEY_KP_4*/, 0x0034 },
+  { 0xffb5 /*XKB_KEY_KP_5*/, 0x0035 },
+  { 0xffb6 /*XKB_KEY_KP_6*/, 0x0036 },
+  { 0xffb7 /*XKB_KEY_KP_7*/, 0x0037 },
+  { 0xffb8 /*XKB_KEY_KP_8*/, 0x0038 },
+  { 0xffb9 /*XKB_KEY_KP_9*/, 0x0039 }
 };
 
 
diff --git a/glfw/src/xkb_unicode.h b/glfw/src/xkb_unicode.h
--- a/glfw/src/xkb_unicode.h
+++ b/glfw/src/xkb_unicode.h
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.1 Linux - www.glfw.org
+// GLFW 3.2 Linux - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
 //
@@ -24,10 +24,10 @@
 //
 //========================================================================
 
-#ifndef _xkb_unicode_h_
-#define _xkb_unicode_h_
+#ifndef _glfw3_xkb_unicode_h_
+#define _glfw3_xkb_unicode_h_
 
 
 long _glfwKeySym2Unicode(unsigned int keysym);
 
-#endif // _xkb_unicode_h_
+#endif // _glfw3_xkb_unicode_h_
