Add run-time context creation API selection

Fixes #145.
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index dab94ef..5042aba 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -7,23 +7,29 @@
 
 if (_GLFW_COCOA)
     set(glfw_HEADERS ${common_HEADERS} cocoa_platform.h cocoa_joystick.h
-                     posix_tls.h)
+                     posix_tls.h nsgl_context.h)
     set(glfw_SOURCES ${common_SOURCES} cocoa_init.m cocoa_joystick.m
-                     cocoa_monitor.m cocoa_window.m cocoa_time.c posix_tls.c)
+                     cocoa_monitor.m cocoa_window.m cocoa_time.c posix_tls.c
+                     nsgl_context.m)
 elseif (_GLFW_WIN32)
-    set(glfw_HEADERS ${common_HEADERS} win32_platform.h win32_joystick.h)
+    set(glfw_HEADERS ${common_HEADERS} win32_platform.h win32_joystick.h
+                     wgl_context.h egl_context.h)
     set(glfw_SOURCES ${common_SOURCES} win32_init.c win32_joystick.c
-                     win32_monitor.c win32_time.c win32_tls.c win32_window.c)
+                     win32_monitor.c win32_time.c win32_tls.c win32_window.c
+                     wgl_context.c egl_context.c)
 elseif (_GLFW_X11)
     set(glfw_HEADERS ${common_HEADERS} x11_platform.h xkb_unicode.h
-                     linux_joystick.h posix_time.h posix_tls.h)
+                     linux_joystick.h posix_time.h posix_tls.h glx_context.h
+                     egl_context.h)
     set(glfw_SOURCES ${common_SOURCES} x11_init.c x11_monitor.c x11_window.c
-                     xkb_unicode.c linux_joystick.c posix_time.c posix_tls.c)
+                     xkb_unicode.c linux_joystick.c posix_time.c posix_tls.c
+                     glx_context.c egl_context.c)
 elseif (_GLFW_WAYLAND)
     set(glfw_HEADERS ${common_HEADERS} wl_platform.h linux_joystick.h
-                     posix_time.h posix_tls.h xkb_unicode.h)
+                     posix_time.h posix_tls.h xkb_unicode.h egl_context.h)
     set(glfw_SOURCES ${common_SOURCES} wl_init.c wl_monitor.c wl_window.c
-                     linux_joystick.c posix_time.c posix_tls.c xkb_unicode.c)
+                     linux_joystick.c posix_time.c posix_tls.c xkb_unicode.c
+                     egl_context.c)
 
     ecm_add_wayland_client_protocol(glfw_SOURCES
         PROTOCOL
@@ -35,23 +41,10 @@
         BASENAME pointer-constraints-unstable-v1)
 elseif (_GLFW_MIR)
     set(glfw_HEADERS ${common_HEADERS} mir_platform.h linux_joystick.h
-                     posix_time.h posix_tls.h xkb_unicode.h)
+                     posix_time.h posix_tls.h xkb_unicode.h egl_context.h)
     set(glfw_SOURCES ${common_SOURCES} mir_init.c mir_monitor.c mir_window.c
-                     linux_joystick.c posix_time.c posix_tls.c xkb_unicode.c)
-endif()
-
-if (_GLFW_EGL)
-    list(APPEND glfw_HEADERS ${common_HEADERS} egl_context.h)
-    list(APPEND glfw_SOURCES ${common_SOURCES} egl_context.c)
-elseif (_GLFW_NSGL)
-    list(APPEND glfw_HEADERS ${common_HEADERS} nsgl_context.h)
-    list(APPEND glfw_SOURCES ${common_SOURCES} nsgl_context.m)
-elseif (_GLFW_WGL)
-    list(APPEND glfw_HEADERS ${common_HEADERS} wgl_context.h)
-    list(APPEND glfw_SOURCES ${common_SOURCES} wgl_context.c)
-elseif (_GLFW_X11)
-    list(APPEND glfw_HEADERS ${common_HEADERS} glx_context.h)
-    list(APPEND glfw_SOURCES ${common_SOURCES} glx_context.c)
+                     linux_joystick.c posix_time.c posix_tls.c xkb_unicode.c
+                     egl_context.c)
 endif()
 
 if (APPLE)
diff --git a/src/cocoa_init.m b/src/cocoa_init.m
index 16b8c9f..9b6434d 100644
--- a/src/cocoa_init.m
+++ b/src/cocoa_init.m
@@ -280,10 +280,7 @@
 
 const char* _glfwPlatformGetVersionString(void)
 {
-    return _GLFW_VERSION_NUMBER " Cocoa"
-#if defined(_GLFW_NSGL)
-        " NSGL"
-#endif
+    return _GLFW_VERSION_NUMBER " Cocoa NSGL"
 #if defined(_GLFW_USE_CHDIR)
         " chdir"
 #endif
diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h
index eeeb472..95eae62 100644
--- a/src/cocoa_platform.h
+++ b/src/cocoa_platform.h
@@ -41,12 +41,7 @@
 
 #include "posix_tls.h"
 #include "cocoa_joystick.h"
-
-#if defined(_GLFW_NSGL)
- #include "nsgl_context.h"
-#else
- #error "The Cocoa backend depends on NSGL platform support"
-#endif
+#include "nsgl_context.h"
 
 #define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
 #define _glfw_dlclose(handle) dlclose(handle)
@@ -58,6 +53,9 @@
 #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
+
 
 // Cocoa-specific per-window data
 //
diff --git a/src/cocoa_window.m b/src/cocoa_window.m
index 6f51439..f5e9928 100644
--- a/src/cocoa_window.m
+++ b/src/cocoa_window.m
@@ -209,7 +209,7 @@
 
 - (void)windowDidResize:(NSNotification *)notification
 {
-    if (window->context.api != GLFW_NO_API)
+    if (window->context.client != GLFW_NO_API)
         [window->context.nsgl.object update];
 
     if (_glfw.cursorWindow == window &&
@@ -227,7 +227,7 @@
 
 - (void)windowDidMove:(NSNotification *)notification
 {
-    if (window->context.api != GLFW_NO_API)
+    if (window->context.client != GLFW_NO_API)
         [window->context.nsgl.object update];
 
     if (_glfw.cursorWindow == window &&
@@ -1002,10 +1002,18 @@
     if (!createWindow(window, wndconfig))
         return GLFW_FALSE;
 
-    if (ctxconfig->api != GLFW_NO_API)
+    if (ctxconfig->client != GLFW_NO_API)
     {
-        if (!_glfwCreateContextNSGL(window, ctxconfig, fbconfig))
+        if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API)
+        {
+            if (!_glfwCreateContextNSGL(window, ctxconfig, fbconfig))
+                return GLFW_FALSE;
+        }
+        else
+        {
+            _glfwInputError(GLFW_API_UNAVAILABLE, "Cocoa: EGL not available");
             return GLFW_FALSE;
+        }
     }
 
     if (window->monitor)
@@ -1026,8 +1034,8 @@
     if (window->monitor)
         releaseMonitor(window);
 
-    if (window->context.api != GLFW_NO_API)
-        _glfwDestroyContextNSGL(window);
+    if (window->context.client != GLFW_NO_API)
+        window->context.destroyContext(window);
 
     [window->ns.object setDelegate:nil];
     [window->ns.delegate release];
diff --git a/src/context.c b/src/context.c
index eb8a561..5f4a08c 100644
--- a/src/context.c
+++ b/src/context.c
@@ -90,17 +90,26 @@
 
 GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
 {
-    if (ctxconfig->api != GLFW_NO_API &&
-        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 %i",
-                        ctxconfig->api);
+                        "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) ||
@@ -150,7 +159,7 @@
             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) ||
@@ -366,8 +375,13 @@
         glfwGetProcAddress("glGetIntegerv");
     window->context.GetString = (PFNGLGETSTRINGPROC)
         glfwGetProcAddress("glGetString");
+    if (!window->context.GetIntegerv || !window->context.GetString)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR, "Entry point retrieval is broken");
+        return GLFW_FALSE;
+    }
 
-    if (!parseVersionString(&window->context.api,
+    if (!parseVersionString(&window->context.client,
                             &window->context.major,
                             &window->context.minor,
                             &window->context.revision))
@@ -375,6 +389,8 @@
         return GLFW_FALSE;
     }
 
+    window->context.source = ctxconfig->source;
+
     if (window->context.major < ctxconfig->major ||
         (window->context.major == ctxconfig->major &&
          window->context.minor < ctxconfig->minor))
@@ -409,7 +425,7 @@
         }
     }
 
-    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)
@@ -507,7 +523,7 @@
     {
         PFNGLCLEARPROC glClear = (PFNGLCLEARPROC) glfwGetProcAddress("glClear");
         glClear(GL_COLOR_BUFFER_BIT);
-        _glfwPlatformSwapBuffers(window);
+        window->context.swapBuffers(window);
     }
 
     return GLFW_TRUE;
@@ -547,16 +563,24 @@
 GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle)
 {
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    _GLFWwindow* previous = _glfwPlatformGetCurrentContext();
 
     _GLFW_REQUIRE_INIT();
 
-    if (window && window->context.api == GLFW_NO_API)
+    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.makeContextCurrent(NULL);
+    }
+
+    if (window)
+        window->context.makeContextCurrent(window);
 }
 
 GLFWAPI GLFWwindow* glfwGetCurrentContext(void)
@@ -572,26 +596,29 @@
 
     _GLFW_REQUIRE_INIT();
 
-    if (window->context.api == GLFW_NO_API)
+    if (window->context.client == GLFW_NO_API)
     {
         _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
         return;
     }
 
-    _glfwPlatformSwapBuffers(window);
+    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)
@@ -657,21 +684,23 @@
     }
 
     // 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/src/egl_context.c b/src/egl_context.c
index 26df456..0620302 100644
--- a/src/egl_context.c
+++ b/src/egl_context.c
@@ -125,7 +125,7 @@
             continue;
 #endif // _GLFW_X11
 
-        if (ctxconfig->api == GLFW_OPENGL_ES_API)
+        if (ctxconfig->client == GLFW_OPENGL_ES_API)
         {
             if (ctxconfig->major == 1)
             {
@@ -138,7 +138,7 @@
                     continue;
             }
         }
-        else if (ctxconfig->api == GLFW_OPENGL_API)
+        else if (ctxconfig->client == GLFW_OPENGL_API)
         {
             if (!(getConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_BIT))
                 continue;
@@ -169,6 +169,110 @@
     return closest != NULL;
 }
 
+static void makeContextCurrent(_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",
+                            getErrorString(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",
+                            getErrorString(eglGetError()));
+            return;
+        }
+    }
+
+    _glfwPlatformSetCurrentContext(window);
+}
+
+static void swapBuffers(_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 swapInterval(int interval)
+{
+    eglSwapInterval(_glfw.egl.display, interval);
+}
+
+static int extensionSupported(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 getProcAddress(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 destroyContext(_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                      //////
@@ -200,10 +304,7 @@
     }
 
     if (!_glfw.egl.handle)
-    {
-        _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Failed to load EGL");
         return GLFW_FALSE;
-    }
 
     _glfw.egl.GetConfigAttrib = (PFNEGLGETCONFIGATTRIBPROC)
         _glfw_dlsym(_glfw.egl.handle, "eglGetConfigAttrib");
@@ -244,6 +345,8 @@
         _glfwInputError(GLFW_API_UNAVAILABLE,
                         "EGL: Failed to get EGL display: %s",
                         getErrorString(eglGetError()));
+
+        _glfwTerminateEGL();
         return GLFW_FALSE;
     }
 
@@ -252,15 +355,17 @@
         _glfwInputError(GLFW_API_UNAVAILABLE,
                         "EGL: Failed to initialize EGL: %s",
                         getErrorString(eglGetError()));
+
+        _glfwTerminateEGL();
         return GLFW_FALSE;
     }
 
     _glfw.egl.KHR_create_context =
-        _glfwPlatformExtensionSupported("EGL_KHR_create_context");
+        extensionSupported("EGL_KHR_create_context");
     _glfw.egl.KHR_create_context_no_error =
-        _glfwPlatformExtensionSupported("EGL_KHR_create_context_no_error");
+        extensionSupported("EGL_KHR_create_context_no_error");
     _glfw.egl.KHR_gl_colorspace =
-        _glfwPlatformExtensionSupported("EGL_KHR_gl_colorspace");
+        extensionSupported("EGL_KHR_gl_colorspace");
 
     return GLFW_TRUE;
 }
@@ -299,6 +404,12 @@
     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->context.egl.handle;
 
@@ -309,7 +420,7 @@
         return GLFW_FALSE;
     }
 
-    if (ctxconfig->api == GLFW_OPENGL_ES_API)
+    if (ctxconfig->client == GLFW_OPENGL_ES_API)
     {
         if (!eglBindAPI(EGL_OPENGL_ES_API))
         {
@@ -334,7 +445,7 @@
     {
         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;
@@ -388,7 +499,7 @@
     {
         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);
@@ -477,7 +588,7 @@
             NULL
         };
 
-        if (ctxconfig->api == GLFW_OPENGL_ES_API)
+        if (ctxconfig->client == GLFW_OPENGL_ES_API)
         {
             if (ctxconfig->major == 1)
                 sonames = es1sonames;
@@ -502,41 +613,18 @@
         }
     }
 
+    window->context.makeContextCurrent = makeContextCurrent;
+    window->context.swapBuffers = swapBuffers;
+    window->context.swapInterval = swapInterval;
+    window->context.extensionSupported = extensionSupported;
+    window->context.getProcAddress = getProcAddress;
+    window->context.destroyContext = destroyContext;
+
     return GLFW_TRUE;
 }
 
 #undef setEGLattrib
 
-// Destroy the OpenGL context
-//
-void _glfwDestroyContextEGL(_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.api != 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;
-    }
-}
-
 // Returns the Visual and depth of the chosen EGLConfig
 //
 #if defined(_GLFW_X11)
@@ -581,87 +669,6 @@
 
 
 //////////////////////////////////////////////////////////////////////////
-//////                       GLFW platform API                      //////
-//////////////////////////////////////////////////////////////////////////
-
-void _glfwPlatformMakeContextCurrent(_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",
-                            getErrorString(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",
-                            getErrorString(eglGetError()));
-            return;
-        }
-    }
-
-    _glfwPlatformSetCurrentContext(window);
-}
-
-void _glfwPlatformSwapBuffers(_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);
-}
-
-void _glfwPlatformSwapInterval(int interval)
-{
-    eglSwapInterval(_glfw.egl.display, interval);
-}
-
-int _glfwPlatformExtensionSupported(const char* extension)
-{
-    const char* extensions = eglQueryString(_glfw.egl.display, EGL_EXTENSIONS);
-    if (extensions)
-    {
-        if (_glfwStringInExtensionString(extension, extensions))
-            return GLFW_TRUE;
-    }
-
-    return GLFW_FALSE;
-}
-
-GLFWglproc _glfwPlatformGetProcAddress(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);
-}
-
-
-//////////////////////////////////////////////////////////////////////////
 //////                        GLFW native API                       //////
 //////////////////////////////////////////////////////////////////////////
 
@@ -676,7 +683,7 @@
     _GLFWwindow* window = (_GLFWwindow*) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_CONTEXT);
 
-    if (window->context.api == GLFW_NO_API)
+    if (window->context.client == GLFW_NO_API)
     {
         _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
         return EGL_NO_CONTEXT;
@@ -690,7 +697,7 @@
     _GLFWwindow* window = (_GLFWwindow*) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_SURFACE);
 
-    if (window->context.api == GLFW_NO_API)
+    if (window->context.client == GLFW_NO_API)
     {
         _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
         return EGL_NO_SURFACE;
diff --git a/src/egl_context.h b/src/egl_context.h
index 0b0b4dc..aed8a25 100644
--- a/src/egl_context.h
+++ b/src/egl_context.h
@@ -149,8 +149,8 @@
 #define eglQueryString _glfw.egl.QueryString
 #define eglGetProcAddress _glfw.egl.GetProcAddress
 
-#define _GLFW_PLATFORM_CONTEXT_STATE            _GLFWcontextEGL egl
-#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE    _GLFWlibraryEGL egl
+#define _GLFW_EGL_CONTEXT_STATE            _GLFWcontextEGL egl
+#define _GLFW_EGL_LIBRARY_CONTEXT_STATE    _GLFWlibraryEGL egl
 
 
 // EGL-specific per-context data
@@ -204,7 +204,6 @@
 GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
                                const _GLFWctxconfig* ctxconfig,
                                const _GLFWfbconfig* fbconfig);
-void _glfwDestroyContextEGL(_GLFWwindow* window);
 #if defined(_GLFW_X11)
 GLFWbool _glfwChooseVisualEGL(const _GLFWctxconfig* ctxconfig,
                               const _GLFWfbconfig* fbconfig,
diff --git a/src/glfw_config.h.in b/src/glfw_config.h.in
index ab57dd5..aed7f7a 100644
--- a/src/glfw_config.h.in
+++ b/src/glfw_config.h.in
@@ -45,15 +45,6 @@
 // Define this to 1 if building GLFW for Mir
 #cmakedefine _GLFW_MIR
 
-// Define this to 1 if building GLFW for EGL
-#cmakedefine _GLFW_EGL
-// Define this to 1 if building GLFW for GLX
-#cmakedefine _GLFW_GLX
-// Define this to 1 if building GLFW for WGL
-#cmakedefine _GLFW_WGL
-// Define this to 1 if building GLFW for NSGL
-#cmakedefine _GLFW_NSGL
-
 // Define this to 1 if building as a shared library / dynamic library / DLL
 #cmakedefine _GLFW_BUILD_DLL
 
diff --git a/src/glx_context.c b/src/glx_context.c
index 0a5b833..1760582 100644
--- a/src/glx_context.c
+++ b/src/glx_context.c
@@ -142,6 +142,96 @@
                                True);
 }
 
+static void makeContextCurrent(_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 swapBuffers(_GLFWwindow* window)
+{
+    glXSwapBuffers(_glfw.x11.display, window->context.glx.window);
+}
+
+static void swapInterval(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 extensionSupported(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 getProcAddress(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 destroyContext(_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                      //////
@@ -229,61 +319,61 @@
         return GLFW_FALSE;
     }
 
-    if (_glfwPlatformExtensionSupported("GLX_EXT_swap_control"))
+    if (extensionSupported("GLX_EXT_swap_control"))
     {
         _glfw.glx.SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)
-            _glfwPlatformGetProcAddress("glXSwapIntervalEXT");
+            getProcAddress("glXSwapIntervalEXT");
 
         if (_glfw.glx.SwapIntervalEXT)
             _glfw.glx.EXT_swap_control = GLFW_TRUE;
     }
 
-    if (_glfwPlatformExtensionSupported("GLX_SGI_swap_control"))
+    if (extensionSupported("GLX_SGI_swap_control"))
     {
         _glfw.glx.SwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)
-            _glfwPlatformGetProcAddress("glXSwapIntervalSGI");
+            getProcAddress("glXSwapIntervalSGI");
 
         if (_glfw.glx.SwapIntervalSGI)
             _glfw.glx.SGI_swap_control = GLFW_TRUE;
     }
 
-    if (_glfwPlatformExtensionSupported("GLX_MESA_swap_control"))
+    if (extensionSupported("GLX_MESA_swap_control"))
     {
         _glfw.glx.SwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC)
-            _glfwPlatformGetProcAddress("glXSwapIntervalMESA");
+            getProcAddress("glXSwapIntervalMESA");
 
         if (_glfw.glx.SwapIntervalMESA)
             _glfw.glx.MESA_swap_control = GLFW_TRUE;
     }
 
-    if (_glfwPlatformExtensionSupported("GLX_ARB_multisample"))
+    if (extensionSupported("GLX_ARB_multisample"))
         _glfw.glx.ARB_multisample = GLFW_TRUE;
 
-    if (_glfwPlatformExtensionSupported("GLX_ARB_framebuffer_sRGB"))
+    if (extensionSupported("GLX_ARB_framebuffer_sRGB"))
         _glfw.glx.ARB_framebuffer_sRGB = GLFW_TRUE;
 
-    if (_glfwPlatformExtensionSupported("GLX_EXT_framebuffer_sRGB"))
+    if (extensionSupported("GLX_EXT_framebuffer_sRGB"))
         _glfw.glx.EXT_framebuffer_sRGB = GLFW_TRUE;
 
-    if (_glfwPlatformExtensionSupported("GLX_ARB_create_context"))
+    if (extensionSupported("GLX_ARB_create_context"))
     {
         _glfw.glx.CreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)
-            _glfwPlatformGetProcAddress("glXCreateContextAttribsARB");
+            getProcAddress("glXCreateContextAttribsARB");
 
         if (_glfw.glx.CreateContextAttribsARB)
             _glfw.glx.ARB_create_context = GLFW_TRUE;
     }
 
-    if (_glfwPlatformExtensionSupported("GLX_ARB_create_context_robustness"))
+    if (extensionSupported("GLX_ARB_create_context_robustness"))
         _glfw.glx.ARB_create_context_robustness = GLFW_TRUE;
 
-    if (_glfwPlatformExtensionSupported("GLX_ARB_create_context_profile"))
+    if (extensionSupported("GLX_ARB_create_context_profile"))
         _glfw.glx.ARB_create_context_profile = GLFW_TRUE;
 
-    if (_glfwPlatformExtensionSupported("GLX_EXT_create_context_es2_profile"))
+    if (extensionSupported("GLX_EXT_create_context_es2_profile"))
         _glfw.glx.EXT_create_context_es2_profile = GLFW_TRUE;
 
-    if (_glfwPlatformExtensionSupported("GLX_ARB_context_flush_control"))
+    if (extensionSupported("GLX_ARB_context_flush_control"))
         _glfw.glx.ARB_context_flush_control = GLFW_TRUE;
 
     return GLFW_TRUE;
@@ -330,7 +420,7 @@
         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 ||
@@ -369,7 +459,7 @@
     {
         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;
@@ -454,7 +544,7 @@
         if (!window->context.glx.handle)
         {
             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 == GLFW_FALSE)
             {
@@ -482,28 +572,18 @@
         return GLFW_FALSE;
     }
 
+    window->context.makeContextCurrent = makeContextCurrent;
+    window->context.swapBuffers = swapBuffers;
+    window->context.swapInterval = swapInterval;
+    window->context.extensionSupported = extensionSupported;
+    window->context.getProcAddress = getProcAddress;
+    window->context.destroyContext = destroyContext;
+
     return GLFW_TRUE;
 }
 
 #undef setGLXattrib
 
-// Destroy the OpenGL context
-//
-void _glfwDestroyContextGLX(_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;
-    }
-}
-
 // Returns the Visual and depth of the chosen GLXFBConfig
 //
 GLFWbool _glfwChooseVisualGLX(const _GLFWctxconfig* ctxconfig,
@@ -537,84 +617,6 @@
 
 
 //////////////////////////////////////////////////////////////////////////
-//////                       GLFW platform API                      //////
-//////////////////////////////////////////////////////////////////////////
-
-void _glfwPlatformMakeContextCurrent(_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);
-}
-
-void _glfwPlatformSwapBuffers(_GLFWwindow* window)
-{
-    glXSwapBuffers(_glfw.x11.display, window->context.glx.window);
-}
-
-void _glfwPlatformSwapInterval(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);
-    }
-}
-
-int _glfwPlatformExtensionSupported(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;
-}
-
-GLFWglproc _glfwPlatformGetProcAddress(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);
-}
-
-
-//////////////////////////////////////////////////////////////////////////
 //////                        GLFW native API                       //////
 //////////////////////////////////////////////////////////////////////////
 
@@ -623,7 +625,7 @@
     _GLFWwindow* window = (_GLFWwindow*) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
 
-    if (window->context.api == GLFW_NO_API)
+    if (window->context.client == GLFW_NO_API)
     {
         _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
         return NULL;
@@ -637,7 +639,7 @@
     _GLFWwindow* window = (_GLFWwindow*) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(None);
 
-    if (window->context.api == GLFW_NO_API)
+    if (window->context.client == GLFW_NO_API)
     {
         _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
         return None;
diff --git a/src/internal.h b/src/internal.h
index e830477..6c084f8 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -58,6 +58,13 @@
 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
@@ -258,7 +265,8 @@
  */
 struct _GLFWctxconfig
 {
-    int           api;
+    int           client;
+    int           source;
     int           major;
     int           minor;
     GLFWbool      forward;
@@ -304,7 +312,8 @@
  */
 struct _GLFWcontext
 {
-    int                 api;
+    int                 client;
+    int                 source;
     int                 major, minor, revision;
     GLFWbool            forward, debug, noerror;
     int                 profile;
@@ -315,8 +324,17 @@
     PFNGLGETINTEGERVPROC GetIntegerv;
     PFNGLGETSTRINGPROC  GetString;
 
+    _GLFWmakecontextcurrentfun  makeContextCurrent;
+    _GLFWswapbuffersfun         swapBuffers;
+    _GLFWswapintervalfun        swapInterval;
+    _GLFWextensionsupportedfun  extensionSupported;
+    _GLFWgetprocaddressfun      getProcAddress;
+    _GLFWdestroycontextfun      destroyContext;
+
     // This is defined in the context API's context.h
     _GLFW_PLATFORM_CONTEXT_STATE;
+    // This is defined in egl_context.h
+    _GLFW_EGL_CONTEXT_STATE;
 };
 
 
@@ -461,6 +479,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;
 };
 
 
@@ -742,11 +762,6 @@
  */
 void _glfwPlatformPostEmptyEvent(void);
 
-/*! @copydoc glfwMakeContextCurrent
- *  @ingroup platform
- */
-void _glfwPlatformMakeContextCurrent(_GLFWwindow* window);
-
 /*! @ingroup platform
  */
 void _glfwPlatformSetCurrentContext(_GLFWwindow* context);
@@ -756,26 +771,6 @@
  */
 _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
  */
diff --git a/src/mir_platform.h b/src/mir_platform.h
index 5d328c2..66c6776 100644
--- a/src/mir_platform.h
+++ b/src/mir_platform.h
@@ -51,12 +51,7 @@
 #include "posix_time.h"
 #include "linux_joystick.h"
 #include "xkb_unicode.h"
-
-#if defined(_GLFW_EGL)
- #include "egl_context.h"
-#else
- #error "The Mir backend depends on EGL platform support"
-#endif
+#include "egl_context.h"
 
 #define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
 #define _glfw_dlclose(handle) dlclose(handle)
@@ -70,6 +65,9 @@
 #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
 //
diff --git a/src/mir_window.c b/src/mir_window.c
index 8ab4a4f..26ee526 100644
--- a/src/mir_window.c
+++ b/src/mir_window.c
@@ -378,7 +378,7 @@
     window->mir.window = mir_buffer_stream_get_egl_native_window(
                                    mir_surface_get_buffer_stream(window->mir.surface));
 
-    if (ctxconfig->api != GLFW_NO_API)
+    if (ctxconfig->client != GLFW_NO_API)
     {
         if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
             return GLFW_FALSE;
@@ -395,7 +395,8 @@
         window->mir.surface = NULL;
     }
 
-    _glfwDestroyContextEGL(window);
+    if (window->context.client != GLFW_NO_API)
+        window->context.destroyContext(window);
 }
 
 void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
diff --git a/src/nsgl_context.m b/src/nsgl_context.m
index 714d527..1b515cb 100644
--- a/src/nsgl_context.m
+++ b/src/nsgl_context.m
@@ -27,6 +27,63 @@
 #include "internal.h"
 
 
+static void makeContextCurrent(_GLFWwindow* window)
+{
+    if (window)
+        [window->context.nsgl.object makeCurrentContext];
+    else
+        [NSOpenGLContext clearCurrentContext];
+
+    _glfwPlatformSetCurrentContext(window);
+}
+
+static void swapBuffers(_GLFWwindow* window)
+{
+    // ARP appears to be unnecessary, but this is future-proof
+    [window->context.nsgl.object flushBuffer];
+}
+
+static void swapInterval(int interval)
+{
+    _GLFWwindow* window = _glfwPlatformGetCurrentContext();
+
+    GLint sync = interval;
+    [window->context.nsgl.object setValues:&sync
+                              forParameter:NSOpenGLCPSwapInterval];
+}
+
+static int extensionSupported(const char* extension)
+{
+    // There are no NSGL extensions
+    return GLFW_FALSE;
+}
+
+static GLFWglproc getProcAddress(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 destroyContext(_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                      //////
 //////////////////////////////////////////////////////////////////////////
@@ -61,7 +118,7 @@
 {
     unsigned int attributeCount = 0;
 
-    if (ctxconfig->api == GLFW_OPENGL_ES_API)
+    if (ctxconfig->client == GLFW_OPENGL_ES_API)
     {
         _glfwInputError(GLFW_API_UNAVAILABLE,
                         "NSGL: OpenGL ES is not available on OS X");
@@ -216,70 +273,17 @@
     }
 
     [window->context.nsgl.object setView:window->ns.view];
+
+    window->context.makeContextCurrent = makeContextCurrent;
+    window->context.swapBuffers = swapBuffers;
+    window->context.swapInterval = swapInterval;
+    window->context.extensionSupported = extensionSupported;
+    window->context.getProcAddress = getProcAddress;
+    window->context.destroyContext = destroyContext;
+
     return GLFW_TRUE;
 }
 
-// Destroy the OpenGL context
-//
-void _glfwDestroyContextNSGL(_GLFWwindow* window)
-{
-    [window->context.nsgl.pixelFormat release];
-    window->context.nsgl.pixelFormat = nil;
-
-    [window->context.nsgl.object release];
-    window->context.nsgl.object = nil;
-}
-
-
-//////////////////////////////////////////////////////////////////////////
-//////                       GLFW platform API                      //////
-//////////////////////////////////////////////////////////////////////////
-
-void _glfwPlatformMakeContextCurrent(_GLFWwindow* window)
-{
-    if (window)
-        [window->context.nsgl.object makeCurrentContext];
-    else
-        [NSOpenGLContext clearCurrentContext];
-
-    _glfwPlatformSetCurrentContext(window);
-}
-
-void _glfwPlatformSwapBuffers(_GLFWwindow* window)
-{
-    // ARP appears to be unnecessary, but this is future-proof
-    [window->context.nsgl.object flushBuffer];
-}
-
-void _glfwPlatformSwapInterval(int interval)
-{
-    _GLFWwindow* window = _glfwPlatformGetCurrentContext();
-
-    GLint sync = interval;
-    [window->context.nsgl.object setValues:&sync
-                              forParameter:NSOpenGLCPSwapInterval];
-}
-
-int _glfwPlatformExtensionSupported(const char* extension)
-{
-    // There are no NSGL extensions
-    return GLFW_FALSE;
-}
-
-GLFWglproc _glfwPlatformGetProcAddress(const char* procname)
-{
-    CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault,
-                                                       procname,
-                                                       kCFStringEncodingASCII);
-
-    GLFWglproc symbol = CFBundleGetFunctionPointerForName(_glfw.nsgl.framework,
-                                                          symbolName);
-
-    CFRelease(symbolName);
-
-    return symbol;
-}
-
 
 //////////////////////////////////////////////////////////////////////////
 //////                        GLFW native API                       //////
@@ -290,7 +294,7 @@
     _GLFWwindow* window = (_GLFWwindow*) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(nil);
 
-    if (window->context.api == GLFW_NO_API)
+    if (window->context.client == GLFW_NO_API)
     {
         _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
         return NULL;
diff --git a/src/wgl_context.c b/src/wgl_context.c
index 608587c..55399cb 100644
--- a/src/wgl_context.c
+++ b/src/wgl_context.c
@@ -32,55 +32,6 @@
 #include <assert.h>
 
 
-// Initialize WGL-specific extensions
-//
-static void loadExtensions(void)
-{
-    // Functions for WGL_EXT_extension_string
-    // NOTE: These are needed by _glfwPlatformExtensionSupported
-    _glfw.wgl.GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)
-        wglGetProcAddress("wglGetExtensionsStringEXT");
-    _glfw.wgl.GetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)
-        wglGetProcAddress("wglGetExtensionsStringARB");
-
-    // Functions for WGL_ARB_create_context
-    _glfw.wgl.CreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)
-        wglGetProcAddress("wglCreateContextAttribsARB");
-
-    // Functions for WGL_EXT_swap_control
-    _glfw.wgl.SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)
-        wglGetProcAddress("wglSwapIntervalEXT");
-
-    // Functions for WGL_ARB_pixel_format
-    _glfw.wgl.GetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)
-        wglGetProcAddress("wglGetPixelFormatAttribivARB");
-
-    // This needs to include every extension used below except for
-    // WGL_ARB_extensions_string and WGL_EXT_extensions_string
-    _glfw.wgl.ARB_multisample =
-        _glfwPlatformExtensionSupported("WGL_ARB_multisample");
-    _glfw.wgl.ARB_framebuffer_sRGB =
-        _glfwPlatformExtensionSupported("WGL_ARB_framebuffer_sRGB");
-    _glfw.wgl.EXT_framebuffer_sRGB =
-        _glfwPlatformExtensionSupported("WGL_EXT_framebuffer_sRGB");
-    _glfw.wgl.ARB_create_context =
-        _glfwPlatformExtensionSupported("WGL_ARB_create_context");
-    _glfw.wgl.ARB_create_context_profile =
-        _glfwPlatformExtensionSupported("WGL_ARB_create_context_profile");
-    _glfw.wgl.EXT_create_context_es2_profile =
-        _glfwPlatformExtensionSupported("WGL_EXT_create_context_es2_profile");
-    _glfw.wgl.ARB_create_context_robustness =
-        _glfwPlatformExtensionSupported("WGL_ARB_create_context_robustness");
-    _glfw.wgl.EXT_swap_control =
-        _glfwPlatformExtensionSupported("WGL_EXT_swap_control");
-    _glfw.wgl.ARB_pixel_format =
-        _glfwPlatformExtensionSupported("WGL_ARB_pixel_format");
-    _glfw.wgl.ARB_context_flush_control =
-        _glfwPlatformExtensionSupported("WGL_ARB_context_flush_control");
-
-    _glfw.wgl.extensionsLoaded = GLFW_TRUE;
-}
-
 // Returns the specified attribute of the specified pixel format
 //
 static int getPixelFormatAttrib(_GLFWwindow* window, int pixelFormat, int attrib)
@@ -280,6 +231,157 @@
     return enabled;
 }
 
+static void makeContextCurrent(_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 swapBuffers(_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 swapInterval(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 extensionSupported(const char* extension)
+{
+    const char* extensions;
+
+    _GLFWwindow* window = _glfwPlatformGetCurrentContext();
+
+    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(window->context.wgl.dc);
+        if (extensions)
+        {
+            if (_glfwStringInExtensionString(extension, extensions))
+                return GLFW_TRUE;
+        }
+    }
+
+    return GLFW_FALSE;
+}
+
+static GLFWglproc getProcAddress(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 destroyContext(_GLFWwindow* window)
+{
+    if (window->context.wgl.handle)
+    {
+        wglDeleteContext(window->context.wgl.handle);
+        window->context.wgl.handle = NULL;
+    }
+}
+
+// Initialize WGL-specific extensions
+//
+static void loadExtensions(void)
+{
+    // Functions for WGL_EXT_extension_string
+    // NOTE: These are needed by extensionSupported
+    _glfw.wgl.GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)
+        wglGetProcAddress("wglGetExtensionsStringEXT");
+    _glfw.wgl.GetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)
+        wglGetProcAddress("wglGetExtensionsStringARB");
+
+    // Functions for WGL_ARB_create_context
+    _glfw.wgl.CreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)
+        wglGetProcAddress("wglCreateContextAttribsARB");
+
+    // Functions for WGL_EXT_swap_control
+    _glfw.wgl.SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)
+        wglGetProcAddress("wglSwapIntervalEXT");
+
+    // Functions for WGL_ARB_pixel_format
+    _glfw.wgl.GetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)
+        wglGetProcAddress("wglGetPixelFormatAttribivARB");
+
+    // This needs to include every extension used below except for
+    // WGL_ARB_extensions_string and WGL_EXT_extensions_string
+    _glfw.wgl.ARB_multisample =
+        extensionSupported("WGL_ARB_multisample");
+    _glfw.wgl.ARB_framebuffer_sRGB =
+        extensionSupported("WGL_ARB_framebuffer_sRGB");
+    _glfw.wgl.EXT_framebuffer_sRGB =
+        extensionSupported("WGL_EXT_framebuffer_sRGB");
+    _glfw.wgl.ARB_create_context =
+        extensionSupported("WGL_ARB_create_context");
+    _glfw.wgl.ARB_create_context_profile =
+        extensionSupported("WGL_ARB_create_context_profile");
+    _glfw.wgl.EXT_create_context_es2_profile =
+        extensionSupported("WGL_EXT_create_context_es2_profile");
+    _glfw.wgl.ARB_create_context_robustness =
+        extensionSupported("WGL_ARB_create_context_robustness");
+    _glfw.wgl.EXT_swap_control =
+        extensionSupported("WGL_EXT_swap_control");
+    _glfw.wgl.ARB_pixel_format =
+        extensionSupported("WGL_ARB_pixel_format");
+    _glfw.wgl.ARB_context_flush_control =
+        extensionSupported("WGL_ARB_context_flush_control");
+
+    _glfw.wgl.extensionsLoaded = GLFW_TRUE;
+}
+
 
 //////////////////////////////////////////////////////////////////////////
 //////                       GLFW internal API                      //////
@@ -336,7 +438,7 @@
     PIXELFORMATDESCRIPTOR pfd;
     HGLRC share = NULL;
 
-    if (ctxconfig->api == GLFW_NO_API)
+    if (ctxconfig->client == GLFW_NO_API)
         return GLFW_TRUE;
 
     if (ctxconfig->share)
@@ -372,7 +474,7 @@
     {
         int index = 0, mask = 0, flags = 0;
 
-        if (ctxconfig->api == GLFW_OPENGL_API)
+        if (ctxconfig->client == GLFW_OPENGL_API)
         {
             if (ctxconfig->forward)
                 flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
@@ -474,22 +576,18 @@
         }
     }
 
+    window->context.makeContextCurrent = makeContextCurrent;
+    window->context.swapBuffers = swapBuffers;
+    window->context.swapInterval = swapInterval;
+    window->context.extensionSupported = extensionSupported;
+    window->context.getProcAddress = getProcAddress;
+    window->context.destroyContext = destroyContext;
+
     return GLFW_TRUE;
 }
 
 #undef setWGLattrib
 
-// Destroy the OpenGL context
-//
-void _glfwDestroyContextWGL(_GLFWwindow* window)
-{
-    if (window->context.wgl.handle)
-    {
-        wglDeleteContext(window->context.wgl.handle);
-        window->context.wgl.handle = NULL;
-    }
-}
-
 // Analyzes the specified context for possible recreation
 //
 int _glfwAnalyzeContextWGL(_GLFWwindow* window,
@@ -501,10 +599,10 @@
     if (_glfw.wgl.extensionsLoaded)
         return _GLFW_RECREATION_NOT_NEEDED;
 
-    _glfwPlatformMakeContextCurrent(window);
+    makeContextCurrent(window);
     loadExtensions();
 
-    if (ctxconfig->api == GLFW_OPENGL_API)
+    if (ctxconfig->client == GLFW_OPENGL_API)
     {
         if (ctxconfig->forward)
         {
@@ -588,102 +686,6 @@
 
 
 //////////////////////////////////////////////////////////////////////////
-//////                       GLFW platform API                      //////
-//////////////////////////////////////////////////////////////////////////
-
-void _glfwPlatformMakeContextCurrent(_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);
-    }
-}
-
-void _glfwPlatformSwapBuffers(_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);
-}
-
-void _glfwPlatformSwapInterval(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);
-}
-
-int _glfwPlatformExtensionSupported(const char* extension)
-{
-    const char* extensions;
-
-    _GLFWwindow* window = _glfwPlatformGetCurrentContext();
-
-    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(window->context.wgl.dc);
-        if (extensions)
-        {
-            if (_glfwStringInExtensionString(extension, extensions))
-                return GLFW_TRUE;
-        }
-    }
-
-    return GLFW_FALSE;
-}
-
-GLFWglproc _glfwPlatformGetProcAddress(const char* procname)
-{
-    const GLFWglproc proc = (GLFWglproc) wglGetProcAddress(procname);
-    if (proc)
-        return proc;
-
-    return (GLFWglproc) GetProcAddress(_glfw.wgl.instance, procname);
-}
-
-
-//////////////////////////////////////////////////////////////////////////
 //////                        GLFW native API                       //////
 //////////////////////////////////////////////////////////////////////////
 
@@ -692,7 +694,7 @@
     _GLFWwindow* window = (_GLFWwindow*) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
 
-    if (window->context.api == GLFW_NO_API)
+    if (window->context.client == GLFW_NO_API)
     {
         _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
         return NULL;
diff --git a/src/wgl_context.h b/src/wgl_context.h
index cca55e0..f1e653c 100644
--- a/src/wgl_context.h
+++ b/src/wgl_context.h
@@ -148,7 +148,6 @@
 GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
                                const _GLFWctxconfig* ctxconfig,
                                const _GLFWfbconfig* fbconfig);
-void _glfwDestroyContextWGL(_GLFWwindow* window);
 int _glfwAnalyzeContextWGL(_GLFWwindow* window,
                            const _GLFWctxconfig* ctxconfig,
                            const _GLFWfbconfig* fbconfig);
diff --git a/src/win32_init.c b/src/win32_init.c
index 521f045..0bfe34c 100644
--- a/src/win32_init.c
+++ b/src/win32_init.c
@@ -421,14 +421,10 @@
 
     _glfwPlatformPollEvents();
 
-#if defined(_GLFW_WGL)
     if (!_glfwInitWGL())
         return GLFW_FALSE;
-#elif defined(_GLFW_EGL)
-    if (!_glfwInitEGL())
-        return GLFW_FALSE;
-#endif
 
+    _glfwInitEGL();
     _glfwInitTimerWin32();
     _glfwInitJoysticksWin32();
 
@@ -449,11 +445,8 @@
 
     free(_glfw.win32.clipboardString);
 
-#if defined(_GLFW_WGL)
     _glfwTerminateWGL();
-#elif defined(_GLFW_EGL)
     _glfwTerminateEGL();
-#endif
 
     _glfwTerminateJoysticksWin32();
     _glfwTerminateThreadLocalStorageWin32();
@@ -463,12 +456,7 @@
 
 const char* _glfwPlatformGetVersionString(void)
 {
-    return _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)
diff --git a/src/win32_platform.h b/src/win32_platform.h
index d44ca3b..f3570bc 100644
--- a/src/win32_platform.h
+++ b/src/win32_platform.h
@@ -205,16 +205,8 @@
 typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice,uint32_t);
 
 #include "win32_joystick.h"
-
-#if defined(_GLFW_WGL)
- #include "wgl_context.h"
-#elif defined(_GLFW_EGL)
- #define _GLFW_EGL_NATIVE_WINDOW  ((EGLNativeWindowType) 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 "wgl_context.h"
+#include "egl_context.h"
 
 #define _GLFW_WNDCLASSNAME L"GLFW30"
 
@@ -222,6 +214,9 @@
 #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
diff --git a/src/win32_window.c b/src/win32_window.c
index 944bff6..b5c03ea 100644
--- a/src/win32_window.c
+++ b/src/win32_window.c
@@ -940,55 +940,58 @@
     if (!createWindow(window, wndconfig))
         return GLFW_FALSE;
 
-    if (ctxconfig->api != GLFW_NO_API)
+    if (ctxconfig->client != GLFW_NO_API)
     {
-#if defined(_GLFW_WGL)
-        if (!_glfwCreateContextWGL(window, ctxconfig, fbconfig))
-            return GLFW_FALSE;
-
-        status = _glfwAnalyzeContextWGL(window, ctxconfig, fbconfig);
-
-        if (status == _GLFW_RECREATION_IMPOSSIBLE)
-            return GLFW_FALSE;
-
-        if (status == _GLFW_RECREATION_REQUIRED)
+        if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API)
         {
-            // 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 vendor ICD)
-
-            // Yes, this is strange, and yes, this is the proper way on WGL
-
-            // 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)
-            _glfwDestroyContextWGL(window);
-            destroyWindow(window);
-
-            // ...and then create them again, this time with better APIs
-            if (!createWindow(window, wndconfig))
-                return GLFW_FALSE;
             if (!_glfwCreateContextWGL(window, ctxconfig, fbconfig))
                 return GLFW_FALSE;
+
+            status = _glfwAnalyzeContextWGL(window, ctxconfig, fbconfig);
+
+            if (status == _GLFW_RECREATION_IMPOSSIBLE)
+                return GLFW_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 vendor ICD)
+
+                // Yes, this is strange, and yes, this is the proper way on WGL
+
+                // 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
+                window->context.makeContextCurrent(NULL);
+
+                // Next destroy the Win32 window and WGL context (without resetting
+                // or destroying the GLFW window object)
+                window->context.destroyContext(window);
+                destroyWindow(window);
+
+                // ...and then create them again, this time with better APIs
+                if (!createWindow(window, wndconfig))
+                    return GLFW_FALSE;
+                if (!_glfwCreateContextWGL(window, ctxconfig, fbconfig))
+                    return GLFW_FALSE;
+            }
         }
-#elif defined(_GLFW_EGL)
-        if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
-            return GLFW_FALSE;
-#endif
+        else
+        {
+            if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
+                return GLFW_FALSE;
+        }
     }
 
     if (window->monitor)
@@ -1007,14 +1010,8 @@
     if (window->monitor)
         releaseMonitor(window);
 
-    if (window->context.api != GLFW_NO_API)
-    {
-#if defined(_GLFW_WGL)
-        _glfwDestroyContextWGL(window);
-#elif defined(_GLFW_EGL)
-        _glfwDestroyContextEGL(window);
-#endif
-    }
+    if (window->context.client != GLFW_NO_API)
+        window->context.destroyContext(window);
 
     destroyWindow(window);
 
diff --git a/src/window.c b/src/window.c
index fee08b2..89b0189 100644
--- a/src/window.c
+++ b/src/window.c
@@ -155,7 +155,7 @@
 
     if (ctxconfig.share)
     {
-        if (ctxconfig.share->context.api == GLFW_NO_API)
+        if (ctxconfig.share->context.client == GLFW_NO_API)
         {
             _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
             return NULL;
@@ -192,29 +192,31 @@
 
     // 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;
     }
 
-    if (ctxconfig.api != GLFW_NO_API)
+    if (ctxconfig.client != GLFW_NO_API)
     {
-        _glfwPlatformMakeContextCurrent(window);
+        window->context.makeContextCurrent(window);
 
         // Retrieve the actual (as opposed to requested) context attributes
         if (!_glfwRefreshContextAttribs(&ctxconfig))
         {
+            glfwMakeContextCurrent((GLFWwindow*) previous);
             glfwDestroyWindow((GLFWwindow*) window);
-            _glfwPlatformMakeContextCurrent(previous);
             return NULL;
         }
 
         // Restore the previously current context (or NULL)
-        _glfwPlatformMakeContextCurrent(previous);
+        glfwMakeContextCurrent((GLFWwindow*) previous);
     }
 
     if (window->monitor)
@@ -247,9 +249,10 @@
     memset(&_glfw.hints, 0, sizeof(_glfw.hints));
 
     // The default is OpenGL with minimum version 1.0
-    _glfw.hints.context.api   = GLFW_OPENGL_API;
-    _glfw.hints.context.major = 1;
-    _glfw.hints.context.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.window.resizable   = GLFW_TRUE;
@@ -345,7 +348,10 @@
             _glfw.hints.window.visible = value ? GLFW_TRUE : GLFW_FALSE;
             break;
         case GLFW_CLIENT_API:
-            _glfw.hints.context.api = value;
+            _glfw.hints.context.client = value;
+            break;
+        case GLFW_CONTEXT_CREATION_API:
+            _glfw.hints.context.source = value;
             break;
         case GLFW_CONTEXT_VERSION_MAJOR:
             _glfw.hints.context.major = value;
@@ -396,7 +402,7 @@
     // The window's context must not be current on another thread when the
     // window is destroyed
     if (window == _glfwPlatformGetCurrentContext())
-        _glfwPlatformMakeContextCurrent(NULL);
+        glfwMakeContextCurrent(NULL);
 
     // Clear the focused window pointer if this is the focused window
     if (_glfw.cursorWindow == window)
@@ -683,7 +689,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:
diff --git a/src/wl_platform.h b/src/wl_platform.h
index d75c025..221108e 100644
--- a/src/wl_platform.h
+++ b/src/wl_platform.h
@@ -49,12 +49,7 @@
 #include "posix_time.h"
 #include "linux_joystick.h"
 #include "xkb_unicode.h"
-
-#if defined(_GLFW_EGL)
- #include "egl_context.h"
-#else
- #error "The Wayland backend depends on EGL platform support"
-#endif
+#include "egl_context.h"
 
 #include "wayland-relative-pointer-unstable-v1-client-protocol.h"
 #include "wayland-pointer-constraints-unstable-v1-client-protocol.h"
@@ -71,6 +66,9 @@
 #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
 //
diff --git a/src/wl_window.c b/src/wl_window.c
index 194c0ec..5ff9990 100644
--- a/src/wl_window.c
+++ b/src/wl_window.c
@@ -373,7 +373,7 @@
     if (!createSurface(window, wndconfig))
         return GLFW_FALSE;
 
-    if (ctxconfig->api != GLFW_NO_API)
+    if (ctxconfig->client != GLFW_NO_API)
     {
         if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
             return GLFW_FALSE;
@@ -417,7 +417,8 @@
         _glfwInputWindowFocus(window, GLFW_FALSE);
     }
 
-    _glfwDestroyContextEGL(window);
+    if (window->context.client != GLFW_NO_API)
+        window->context.destroyContext(window);
 
     if (window->wl.native)
         wl_egl_window_destroy(window->wl.native);
diff --git a/src/x11_init.c b/src/x11_init.c
index b81afcc..112e454 100644
--- a/src/x11_init.c
+++ b/src/x11_init.c
@@ -766,17 +766,13 @@
     if (!_glfwInitThreadLocalStoragePOSIX())
         return GLFW_FALSE;
 
-#if defined(_GLFW_GLX)
     if (!_glfwInitGLX())
         return GLFW_FALSE;
-#elif defined(_GLFW_EGL)
-    if (!_glfwInitEGL())
-        return GLFW_FALSE;
-#endif
 
     if (!_glfwInitJoysticksLinux())
         return GLFW_FALSE;
 
+    _glfwInitEGL();
     _glfwInitTimerPOSIX();
 
     return GLFW_TRUE;
@@ -804,9 +800,7 @@
         _glfw.x11.im = NULL;
     }
 
-#if defined(_GLFW_EGL)
     _glfwTerminateEGL();
-#endif
 
     if (_glfw.x11.display)
     {
@@ -816,9 +810,7 @@
 
     // NOTE: This needs to be done after XCloseDisplay, as libGL registers
     //       cleanup callbacks that get called by it
-#if defined(_GLFW_GLX)
     _glfwTerminateGLX();
-#endif
 
     _glfwTerminateJoysticksLinux();
     _glfwTerminateThreadLocalStoragePOSIX();
@@ -826,12 +818,7 @@
 
 const char* _glfwPlatformGetVersionString(void)
 {
-    return _GLFW_VERSION_NUMBER " X11"
-#if defined(_GLFW_GLX)
-        " GLX"
-#elif defined(_GLFW_EGL)
-        " EGL"
-#endif
+    return _GLFW_VERSION_NUMBER " X11 GLX EGL"
 #if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK)
         " clock_gettime"
 #else
diff --git a/src/x11_platform.h b/src/x11_platform.h
index a12374a..9c76d18 100644
--- a/src/x11_platform.h
+++ b/src/x11_platform.h
@@ -87,21 +87,16 @@
 #include "posix_time.h"
 #include "linux_joystick.h"
 #include "xkb_unicode.h"
-
-#if defined(_GLFW_GLX)
- #include "glx_context.h"
-#elif defined(_GLFW_EGL)
- #define _GLFW_EGL_NATIVE_WINDOW  ((EGLNativeWindowType) window->x11.handle)
- #define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.x11.display)
- #include "egl_context.h"
-#else
- #error "No supported context creation API selected"
-#endif
+#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
diff --git a/src/x11_window.c b/src/x11_window.c
index 7cf26ce..19b9d24 100644
--- a/src/x11_window.c
+++ b/src/x11_window.c
@@ -1478,34 +1478,40 @@
     Visual* visual;
     int depth;
 
-    if (ctxconfig->api == GLFW_NO_API)
+    if (ctxconfig->client == GLFW_NO_API)
     {
         visual = DefaultVisual(_glfw.x11.display, _glfw.x11.screen);
         depth = DefaultDepth(_glfw.x11.display, _glfw.x11.screen);
     }
     else
     {
-#if defined(_GLFW_GLX)
-        if (!_glfwChooseVisualGLX(ctxconfig, fbconfig, &visual, &depth))
-            return GLFW_FALSE;
-#elif defined(_GLFW_EGL)
-        if (!_glfwChooseVisualEGL(ctxconfig, fbconfig, &visual, &depth))
-            return GLFW_FALSE;
-#endif
+        if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API)
+        {
+            if (!_glfwChooseVisualGLX(ctxconfig, fbconfig, &visual, &depth))
+                return GLFW_FALSE;
+        }
+        else
+        {
+            if (!_glfwChooseVisualEGL(ctxconfig, fbconfig, &visual, &depth))
+                return GLFW_FALSE;
+        }
     }
 
     if (!createWindow(window, wndconfig, visual, depth))
         return GLFW_FALSE;
 
-    if (ctxconfig->api != GLFW_NO_API)
+    if (ctxconfig->client != GLFW_NO_API)
     {
-#if defined(_GLFW_GLX)
-        if (!_glfwCreateContextGLX(window, ctxconfig, fbconfig))
-            return GLFW_FALSE;
-#elif defined(_GLFW_EGL)
-        if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
-            return GLFW_FALSE;
-#endif
+        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)
@@ -1530,14 +1536,8 @@
         window->x11.ic = NULL;
     }
 
-    if (window->context.api != GLFW_NO_API)
-    {
-#if defined(_GLFW_GLX)
-        _glfwDestroyContextGLX(window);
-#elif defined(_GLFW_EGL)
-        _glfwDestroyContextEGL(window);
-#endif
-    }
+    if (window->context.client != GLFW_NO_API)
+        window->context.destroyContext(window);
 
     if (window->x11.handle)
     {