Browse Source

Merge branch 'master' into multi-monitor

Conflicts:
	src/cocoa_window.m
	src/init.c
	tests/iconify.c
	tests/reopen.c
Camilla Berglund 12 years ago
parent
commit
23c6def880

+ 0 - 4
examples/boing.c

@@ -572,17 +572,13 @@ int main( void )
 
    /* Init GLFW */
    if( !glfwInit() )
-   {
-      fprintf( stderr, "Failed to initialize GLFW\n" );
       exit( EXIT_FAILURE );
-   }
 
    glfwWindowHint(GLFW_DEPTH_BITS, 16);
 
    window = glfwCreateWindow( 400, 400, "Boing (classic Amiga demo)", NULL, NULL );
    if (!window)
    {
-       fprintf( stderr, "Failed to open GLFW window\n" );
        glfwTerminate();
        exit( EXIT_FAILURE );
    }

+ 7 - 5
examples/triangle.c

@@ -10,24 +10,26 @@
 #define GLFW_INCLUDE_GLU
 #include <GL/glfw3.h>
 
+static void error_callback(int error, const char* description)
+{
+    fprintf(stderr, "Error: %s\n", description);
+}
+
 int main(void)
 {
     int width, height, x;
     GLFWwindow window;
 
+    glfwSetErrorCallback(error_callback);
+
     // Initialise GLFW
     if (!glfwInit())
-    {
-        fprintf(stderr, "Failed to initialize GLFW\n");
         exit(EXIT_FAILURE);
-    }
 
     // Open a window and create its OpenGL context
     window = glfwCreateWindow(640, 480, "Spinning Triangle", NULL, NULL);
     if (!window)
     {
-        fprintf(stderr, "Failed to open GLFW window\n");
-
         glfwTerminate();
         exit(EXIT_FAILURE);
     }

+ 13 - 4
examples/wave.c

@@ -257,6 +257,16 @@ void calc_grid(void)
 }
 
 
+//========================================================================
+// Print errors
+//========================================================================
+
+static void error_callback(int error, const char* description)
+{
+    fprintf(stderr, "Error: %s\n", description);
+}
+
+
 //========================================================================
 // Handle key strokes
 //========================================================================
@@ -393,16 +403,15 @@ int main(int argc, char* argv[])
     double t, dt_total, t_old;
     int width, height;
 
+    glfwSetErrorCallback(error_callback);
+
     if (!glfwInit())
-    {
-        fprintf(stderr, "GLFW initialization failed\n");
         exit(EXIT_FAILURE);
-    }
 
     window = glfwCreateWindow(640, 480, "Wave Simulation", NULL, NULL);
     if (!window)
     {
-        fprintf(stderr, "Could not open window\n");
+        glfwTerminate();
         exit(EXIT_FAILURE);
     }
 

+ 4 - 19
include/GL/glfw3.h

@@ -985,25 +985,6 @@ GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev);
  */
 GLFWAPI const char* glfwGetVersionString(void);
 
-/*! @brief Retrieves the latest error.
- *  @return The latest @link errors error code @endlink.
- *  @ingroup error
- *
- *  @remarks This function may be called before @ref glfwInit.
- */
-GLFWAPI int glfwGetError(void);
-
-/*! @brief Retrieves a generic, human readable description of the specified error.
- *  @param[in] error The @link errors error code @endlink to be described.
- *  @return A UTF-8 encoded string describing the error.
- *  @ingroup error
- *
- *  @remarks This function may be called before @ref glfwInit.
- *
- *  @remarks This function may be called from secondary threads.
- */
-GLFWAPI const char* glfwErrorString(int error);
-
 /*! @brief Sets the error callback.
  *  @param[in] cbfun The new callback, or @c NULL to remove the currently set
  *  callback.
@@ -1298,6 +1279,10 @@ GLFWAPI GLFWwindow glfwCreateWindow(int width, int height, const char* title, GL
  *  @note If the window's context is current on the main thread, it is
  *  detached before being destroyed.
  *
+ *  @note On calling this function, no further callbacks will be called for
+ *  the specified window, even if their associated events occur during window
+ *  destruction.
+ *
  *  @warning The window's context must not be current on any other thread.
  *
  *  @sa glfwCreateWindow

+ 1 - 2
readme.html

@@ -275,8 +275,7 @@ version of GLFW.</p>
   <li>Added <code>GLFWwindow</code> window handle type and updated window-related functions and callbacks to take a window handle</li>
   <li>Added <code>glfwDefaultWindowHints</code> function for resetting all window hints to their default values</li>
   <li>Added <code>glfwMakeContextCurrent</code> function for making the context of the specified window current</li>
-  <li>Added <code>glfwGetError</code> and <code>glfwErrorString</code> error reporting functions and a number of error tokens</li>
-  <li>Added <code>glfwSetErrorCallback</code> function and <code>GLFWerrorfun</code> type for receiving more specific and/or nested errors</li>
+  <li>Added <code>glfwSetErrorCallback</code> function and <code>GLFWerrorfun</code> type for receiving error descriptions</li>
   <li>Added <code>glfwSetWindowUserPointer</code> and <code>glfwGetWindowUserPointer</code> functions for per-window user pointers</li>
   <li>Added <code>glfwGetVersionString</code> function for determining which code paths were enabled at compile time</li>
   <li>Added <code>glfwGetWindowMonitor</code> for querying the monitor, if any, of the specified window</li>

+ 1 - 3
src/cocoa_init.m

@@ -118,7 +118,7 @@ int _glfwPlatformInit(void)
 // Close window, if open, and shut down GLFW
 //========================================================================
 
-int _glfwPlatformTerminate(void)
+void _glfwPlatformTerminate(void)
 {
     // TODO: Probably other cleanup
 
@@ -142,8 +142,6 @@ int _glfwPlatformTerminate(void)
     _glfwTerminateJoysticks();
 
     _glfwTerminateOpenGL();
-
-    return GL_TRUE;
 }
 
 

+ 4 - 0
src/cocoa_platform.h

@@ -120,5 +120,9 @@ void _glfwRestoreVideoMode(void);
 // OpenGL support
 int _glfwInitOpenGL(void);
 void _glfwTerminateOpenGL(void);
+int _glfwCreateContext(_GLFWwindow* window,
+                       const _GLFWwndconfig* wndconfig,
+                       const _GLFWfbconfig* fbconfig);
+void _glfwDestroyContext(_GLFWwindow* window);
 
 #endif // _cocoa_platform_h_

+ 2 - 166
src/cocoa_window.m

@@ -711,166 +711,6 @@ static GLboolean createWindow(_GLFWwindow* window,
 }
 
 
-//========================================================================
-// Create the OpenGL context
-//========================================================================
-
-static GLboolean createContext(_GLFWwindow* window,
-                               const _GLFWwndconfig* wndconfig,
-                               const _GLFWfbconfig* fbconfig)
-{
-    unsigned int attributeCount = 0;
-
-    // Mac OS X needs non-zero color size, so set resonable values
-    int colorBits = fbconfig->redBits + fbconfig->greenBits + fbconfig->blueBits;
-    if (colorBits == 0)
-        colorBits = 24;
-    else if (colorBits < 15)
-        colorBits = 15;
-
-    if (wndconfig->clientAPI == GLFW_OPENGL_ES_API)
-    {
-        _glfwSetError(GLFW_VERSION_UNAVAILABLE,
-                      "NSOpenGL: This API does not support OpenGL ES");
-        return GL_FALSE;
-    }
-
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
-    // Fail if any OpenGL version above 2.1 other than 3.2 was requested
-    if (wndconfig->glMajor > 3 ||
-        (wndconfig->glMajor == 3 && wndconfig->glMinor != 2))
-    {
-        _glfwSetError(GLFW_VERSION_UNAVAILABLE,
-                      "NSOpenGL: The targeted version of Mac OS X does not "
-                      "support any OpenGL version above 2.1 except 3.2");
-        return GL_FALSE;
-    }
-
-    if (wndconfig->glMajor > 2)
-    {
-        if (!wndconfig->glForward)
-        {
-            _glfwSetError(GLFW_VERSION_UNAVAILABLE,
-                          "NSOpenGL: The targeted version of Mac OS X only "
-                          "supports OpenGL 3.2 contexts if they are "
-                          "forward-compatible");
-            return GL_FALSE;
-        }
-
-        if (wndconfig->glProfile != GLFW_OPENGL_CORE_PROFILE)
-        {
-            _glfwSetError(GLFW_VERSION_UNAVAILABLE,
-                          "NSOpenGL: The targeted version of Mac OS X only "
-                          "supports OpenGL 3.2 contexts if they use the "
-                          "core profile");
-            return GL_FALSE;
-        }
-    }
-#else
-    // Fail if OpenGL 3.0 or above was requested
-    if (wndconfig->glMajor > 2)
-    {
-        _glfwSetError(GLFW_VERSION_UNAVAILABLE,
-                      "NSOpenGL: The targeted version of Mac OS X does not "
-                      "support OpenGL version 3.0 or above");
-        return GL_FALSE;
-    }
-#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
-
-    // Fail if a robustness strategy was requested
-    if (wndconfig->glRobustness)
-    {
-        _glfwSetError(GLFW_VERSION_UNAVAILABLE,
-                      "NSOpenGL: Mac OS X does not support OpenGL robustness "
-                      "strategies");
-        return GL_FALSE;
-    }
-
-#define ADD_ATTR(x) { attributes[attributeCount++] = x; }
-#define ADD_ATTR2(x, y) { ADD_ATTR(x); ADD_ATTR(y); }
-
-    // Arbitrary array size here
-    NSOpenGLPixelFormatAttribute attributes[40];
-
-    ADD_ATTR(NSOpenGLPFADoubleBuffer);
-
-    if (wndconfig->monitor)
-    {
-        ADD_ATTR(NSOpenGLPFANoRecovery);
-        ADD_ATTR2(NSOpenGLPFAScreenMask,
-                  CGDisplayIDToOpenGLDisplayMask(CGMainDisplayID()));
-    }
-
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
-    if (wndconfig->glMajor > 2)
-        ADD_ATTR2(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core);
-#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
-
-    ADD_ATTR2(NSOpenGLPFAColorSize, colorBits);
-
-    if (fbconfig->alphaBits > 0)
-        ADD_ATTR2(NSOpenGLPFAAlphaSize, fbconfig->alphaBits);
-
-    if (fbconfig->depthBits > 0)
-        ADD_ATTR2(NSOpenGLPFADepthSize, fbconfig->depthBits);
-
-    if (fbconfig->stencilBits > 0)
-        ADD_ATTR2(NSOpenGLPFAStencilSize, fbconfig->stencilBits);
-
-    int accumBits = fbconfig->accumRedBits + fbconfig->accumGreenBits +
-                    fbconfig->accumBlueBits + fbconfig->accumAlphaBits;
-
-    if (accumBits > 0)
-        ADD_ATTR2(NSOpenGLPFAAccumSize, accumBits);
-
-    if (fbconfig->auxBuffers > 0)
-        ADD_ATTR2(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers);
-
-    if (fbconfig->stereo)
-        ADD_ATTR(NSOpenGLPFAStereo);
-
-    if (fbconfig->samples > 0)
-    {
-        ADD_ATTR2(NSOpenGLPFASampleBuffers, 1);
-        ADD_ATTR2(NSOpenGLPFASamples, fbconfig->samples);
-    }
-
-    // NOTE: All NSOpenGLPixelFormats on the relevant cards support sRGB
-    // frambuffer, so there's no need (and no way) to request it
-
-    ADD_ATTR(0);
-
-#undef ADD_ATTR
-#undef ADD_ATTR2
-
-    window->NSGL.pixelFormat =
-        [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
-    if (window->NSGL.pixelFormat == nil)
-    {
-        _glfwSetError(GLFW_PLATFORM_ERROR,
-                      "NSOpenGL: Failed to create OpenGL pixel format");
-        return GL_FALSE;
-    }
-
-    NSOpenGLContext* share = NULL;
-
-    if (wndconfig->share)
-        share = wndconfig->share->NSGL.context;
-
-    window->NSGL.context =
-        [[NSOpenGLContext alloc] initWithFormat:window->NSGL.pixelFormat
-                                   shareContext:share];
-    if (window->NSGL.context == nil)
-    {
-        _glfwSetError(GLFW_PLATFORM_ERROR,
-                      "NSOpenGL: Failed to create OpenGL context");
-        return GL_FALSE;
-    }
-
-    return GL_TRUE;
-}
-
-
 //////////////////////////////////////////////////////////////////////////
 //////                       GLFW platform API                      //////
 //////////////////////////////////////////////////////////////////////////
@@ -923,7 +763,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
     if (!createWindow(window, wndconfig))
         return GL_FALSE;
 
-    if (!createContext(window, wndconfig, fbconfig))
+    if (!_glfwCreateContext(window, wndconfig, fbconfig))
         return GL_FALSE;
 
     [window->NSGL.context setView:[window->NS.object contentView]];
@@ -968,11 +808,7 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
         _glfwRestoreVideoMode();
     }
 
-    [window->NSGL.pixelFormat release];
-    window->NSGL.pixelFormat = nil;
-
-    [window->NSGL.context release];
-    window->NSGL.context = nil;
+    _glfwDestroyContext(window);
 
     [window->NS.object setDelegate:nil];
     [window->NS.delegate release];

+ 63 - 26
src/glx_context.c

@@ -38,6 +38,11 @@
 void (*glXGetProcAddressEXT(const GLubyte* procName))();
 
 
+#ifndef GLXBadProfileARB
+ #define GLXBadProfileARB 13
+#endif
+
+
 //========================================================================
 // Thread local storage attribute macro
 //========================================================================
@@ -48,6 +53,12 @@ void (*glXGetProcAddressEXT(const GLubyte* procName))();
 #endif
 
 
+//========================================================================
+// The X error code as provided to the X error handler
+//========================================================================
+static unsigned long _glfwErrorCode = Success;
+
+
 //========================================================================
 // The per-thread current context/window pointer
 //========================================================================
@@ -207,18 +218,48 @@ static _GLFWfbconfig* getFBConfigs(_GLFWwindow* window, unsigned int* found)
 
 
 //========================================================================
-// Error handler for BadMatch errors when requesting context with
-// unavailable OpenGL versions using the GLX_ARB_create_context extension
+// Error handler used when creating a context with the GLX_ARB_create_context
+// extension set
 //========================================================================
 
 static int errorHandler(Display *display, XErrorEvent* event)
 {
+    _glfwErrorCode = event->error_code;
     return 0;
 }
 
 
 //========================================================================
-// Create the actual OpenGL context
+// Create the OpenGL context using legacy API
+//========================================================================
+
+static void createLegacyContext(_GLFWwindow* window,
+                                const _GLFWwndconfig* wndconfig,
+                                GLXFBConfig fbconfig,
+                                GLXContext share)
+{
+    if (_glfwLibrary.GLX.SGIX_fbconfig)
+    {
+        window->GLX.context =
+            _glfwLibrary.GLX.CreateContextWithConfigSGIX(_glfwLibrary.X11.display,
+                                                         fbconfig,
+                                                         GLX_RGBA_TYPE,
+                                                         share,
+                                                         True);
+    }
+    else
+    {
+        window->GLX.context = glXCreateNewContext(_glfwLibrary.X11.display,
+                                                  fbconfig,
+                                                  GLX_RGBA_TYPE,
+                                                  share,
+                                                  True);
+    }
+}
+
+
+//========================================================================
+// Create the OpenGL context
 //========================================================================
 
 #define setGLXattrib(attribName, attribValue) \
@@ -386,6 +427,7 @@ static int createContext(_GLFWwindow* window,
         // it because glXCreateContextAttribsARB generates a BadMatch error if
         // the requested OpenGL version is unavailable (instead of a civilized
         // response like returning NULL)
+        _glfwErrorCode = Success;
         XSetErrorHandler(errorHandler);
 
         window->GLX.context =
@@ -397,36 +439,29 @@ static int createContext(_GLFWwindow* window,
 
         // We are done, so unset the error handler again (see above)
         XSetErrorHandler(NULL);
-    }
-    else
-    {
-        if (_glfwLibrary.GLX.SGIX_fbconfig)
-        {
-            window->GLX.context =
-                _glfwLibrary.GLX.CreateContextWithConfigSGIX(_glfwLibrary.X11.display,
-                                                             *fbconfig,
-                                                             GLX_RGBA_TYPE,
-                                                             share,
-                                                             True);
-        }
-        else
+
+        if (window->GLX.context == NULL)
         {
-            window->GLX.context = glXCreateNewContext(_glfwLibrary.X11.display,
-                                                      *fbconfig,
-                                                      GLX_RGBA_TYPE,
-                                                      share,
-                                                      True);
+            // HACK: This is a fallback for the broken Mesa implementation of
+            // GLX_ARB_create_context_profile, which fails default 1.0 context
+            // creation with a GLXBadProfileARB error in violation of the spec
+            if (_glfwErrorCode == _glfwLibrary.GLX.errorBase + GLXBadProfileARB &&
+                wndconfig->clientAPI == GLFW_OPENGL_API &&
+                wndconfig->glProfile == GLFW_OPENGL_NO_PROFILE &&
+                wndconfig->glForward == GL_FALSE)
+            {
+                createLegacyContext(window, wndconfig, *fbconfig, share);
+            }
         }
     }
+    else
+        createLegacyContext(window, wndconfig, *fbconfig, share);
 
     XFree(fbconfig);
 
     if (window->GLX.context == NULL)
     {
-        // TODO: Handle all the various error codes here
-
-        _glfwSetError(GLFW_PLATFORM_ERROR,
-                      "GLX: Failed to create context");
+        _glfwSetError(GLFW_PLATFORM_ERROR, "GLX: Failed to create context");
         return GL_FALSE;
     }
 
@@ -472,7 +507,9 @@ int _glfwInitOpenGL(void)
 #endif
 
     // Check if GLX is supported on this display
-    if (!glXQueryExtension(_glfwLibrary.X11.display, NULL, NULL))
+    if (!glXQueryExtension(_glfwLibrary.X11.display,
+                           &_glfwLibrary.GLX.errorBase,
+                           &_glfwLibrary.GLX.eventBase))
     {
         _glfwSetError(GLFW_API_UNAVAILABLE, "GLX: GLX support not found");
         return GL_FALSE;

+ 2 - 0
src/glx_platform.h

@@ -90,6 +90,8 @@ typedef struct _GLFWlibraryGLX
 {
     // Server-side GLX version
     int             majorVersion, minorVersion;
+    int             eventBase;
+    int             errorBase;
 
     // GLX extensions
     PFNGLXSWAPINTERVALSGIPROC             SwapIntervalSGI;

+ 36 - 62
src/init.c

@@ -50,15 +50,6 @@ GLboolean _glfwInitialized = GL_FALSE;
 _GLFWlibrary _glfwLibrary;
 
 
-//------------------------------------------------------------------------
-// The current GLFW error code
-// This is outside of _glfwLibrary so it can be initialized and usable
-// before glfwInit is called, which lets that function report errors
-// TODO: Make this thread-local
-//------------------------------------------------------------------------
-static int _glfwError = GLFW_NO_ERROR;
-
-
 //------------------------------------------------------------------------
 // The current error callback
 // This is outside of _glfwLibrary so it can be initialized and usable
@@ -67,6 +58,40 @@ static int _glfwError = GLFW_NO_ERROR;
 static GLFWerrorfun _glfwErrorCallback = NULL;
 
 
+//========================================================================
+// Returns a generic string representation of the specified error
+//========================================================================
+
+static const char* getErrorString(int error)
+{
+    switch (error)
+    {
+        case GLFW_NO_ERROR:
+            return "No error";
+        case GLFW_NOT_INITIALIZED:
+            return "The GLFW library is not initialized";
+        case GLFW_NO_CURRENT_CONTEXT:
+            return "There is no current context";
+        case GLFW_INVALID_ENUM:
+            return "Invalid argument for enum parameter";
+        case GLFW_INVALID_VALUE:
+            return "Invalid value for parameter";
+        case GLFW_OUT_OF_MEMORY:
+            return "Out of memory";
+        case GLFW_API_UNAVAILABLE:
+            return "The requested client API is unavailable";
+        case GLFW_VERSION_UNAVAILABLE:
+            return "The requested client API version is unavailable";
+        case GLFW_PLATFORM_ERROR:
+            return "A platform-specific error occurred";
+        case GLFW_FORMAT_UNAVAILABLE:
+            return "The requested format is unavailable";
+    }
+
+    return "ERROR: UNKNOWN ERROR TOKEN PASSED TO glfwErrorString";
+}
+
+
 //////////////////////////////////////////////////////////////////////////
 //////                       GLFW internal API                      //////
 //////////////////////////////////////////////////////////////////////////
@@ -97,12 +122,10 @@ void _glfwSetError(int error, const char* format, ...)
             description = buffer;
         }
         else
-            description = glfwErrorString(error);
+            description = getErrorString(error);
 
         _glfwErrorCallback(error, description);
     }
-    else
-        _glfwError = error;
 }
 
 
@@ -158,8 +181,7 @@ GLFWAPI void glfwTerminate(void)
 
     _glfwDestroyMonitors();
 
-    if (!_glfwPlatformTerminate())
-        return;
+    _glfwPlatformTerminate();
 
     _glfwInitialized = GL_FALSE;
 }
@@ -194,54 +216,6 @@ GLFWAPI const char* glfwGetVersionString(void)
 }
 
 
-//========================================================================
-// Returns the current error value
-// This function may be called without GLFW having been initialized
-//========================================================================
-
-GLFWAPI int glfwGetError(void)
-{
-    int error = _glfwError;
-    _glfwError = GLFW_NO_ERROR;
-    return error;
-}
-
-
-//========================================================================
-// Returns a string representation of the specified error value
-// This function may be called without GLFW having been initialized
-//========================================================================
-
-GLFWAPI const char* glfwErrorString(int error)
-{
-    switch (error)
-    {
-        case GLFW_NO_ERROR:
-            return "No error";
-        case GLFW_NOT_INITIALIZED:
-            return "The GLFW library is not initialized";
-        case GLFW_NO_CURRENT_CONTEXT:
-            return "There is no current context";
-        case GLFW_INVALID_ENUM:
-            return "Invalid argument for enum parameter";
-        case GLFW_INVALID_VALUE:
-            return "Invalid value for parameter";
-        case GLFW_OUT_OF_MEMORY:
-            return "Out of memory";
-        case GLFW_API_UNAVAILABLE:
-            return "The requested client API is unavailable";
-        case GLFW_VERSION_UNAVAILABLE:
-            return "The requested client API version is unavailable";
-        case GLFW_PLATFORM_ERROR:
-            return "A platform-specific error occurred";
-        case GLFW_FORMAT_UNAVAILABLE:
-            return "The requested format is unavailable";
-    }
-
-    return "ERROR: UNKNOWN ERROR TOKEN PASSED TO glfwErrorString";
-}
-
-
 //========================================================================
 // Sets the callback function for GLFW errors
 // This function may be called without GLFW having been initialized

+ 1 - 3
src/internal.h

@@ -289,12 +289,10 @@ extern _GLFWlibrary _glfwLibrary;
 
 // Platform init and version
 int _glfwPlatformInit(void);
-int _glfwPlatformTerminate(void);
+void _glfwPlatformTerminate(void);
 const char* _glfwPlatformGetVersionString(void);
 
 // Input mode support
-void _glfwPlatformEnableSystemKeys(_GLFWwindow* window);
-void _glfwPlatformDisableSystemKeys(_GLFWwindow* window);
 void _glfwPlatformSetCursorPos(_GLFWwindow* window, int x, int y);
 void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode);
 

+ 179 - 1
src/nsgl_context.m

@@ -39,7 +39,7 @@ static pthread_key_t _glfwCurrentTLS;
 
 
 //////////////////////////////////////////////////////////////////////////
-//////                       GLFW platform API                      //////
+//////                       GLFW internal API                      //////
 //////////////////////////////////////////////////////////////////////////
 
 //========================================================================
@@ -69,6 +69,184 @@ void _glfwTerminateOpenGL(void)
 }
 
 
+//========================================================================
+// Create the OpenGL context
+//========================================================================
+
+int _glfwCreateContext(_GLFWwindow* window,
+                       const _GLFWwndconfig* wndconfig,
+                       const _GLFWfbconfig* fbconfig)
+{
+    unsigned int attributeCount = 0;
+
+    // Mac OS X needs non-zero color size, so set resonable values
+    int colorBits = fbconfig->redBits + fbconfig->greenBits + fbconfig->blueBits;
+    if (colorBits == 0)
+        colorBits = 24;
+    else if (colorBits < 15)
+        colorBits = 15;
+
+    if (wndconfig->clientAPI == GLFW_OPENGL_ES_API)
+    {
+        _glfwSetError(GLFW_VERSION_UNAVAILABLE,
+                      "NSOpenGL: This API does not support OpenGL ES");
+        return GL_FALSE;
+    }
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
+    // Fail if any OpenGL version above 2.1 other than 3.2 was requested
+    if (wndconfig->glMajor > 3 ||
+        (wndconfig->glMajor == 3 && wndconfig->glMinor != 2))
+    {
+        _glfwSetError(GLFW_VERSION_UNAVAILABLE,
+                      "NSOpenGL: The targeted version of Mac OS X does not "
+                      "support any OpenGL version above 2.1 except 3.2");
+        return GL_FALSE;
+    }
+
+    if (wndconfig->glMajor > 2)
+    {
+        if (!wndconfig->glForward)
+        {
+            _glfwSetError(GLFW_VERSION_UNAVAILABLE,
+                          "NSOpenGL: The targeted version of Mac OS X only "
+                          "supports OpenGL 3.2 contexts if they are "
+                          "forward-compatible");
+            return GL_FALSE;
+        }
+
+        if (wndconfig->glProfile != GLFW_OPENGL_CORE_PROFILE)
+        {
+            _glfwSetError(GLFW_VERSION_UNAVAILABLE,
+                          "NSOpenGL: The targeted version of Mac OS X only "
+                          "supports OpenGL 3.2 contexts if they use the "
+                          "core profile");
+            return GL_FALSE;
+        }
+    }
+#else
+    // Fail if OpenGL 3.0 or above was requested
+    if (wndconfig->glMajor > 2)
+    {
+        _glfwSetError(GLFW_VERSION_UNAVAILABLE,
+                      "NSOpenGL: The targeted version of Mac OS X does not "
+                      "support OpenGL version 3.0 or above");
+        return GL_FALSE;
+    }
+#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
+
+    // Fail if a robustness strategy was requested
+    if (wndconfig->glRobustness)
+    {
+        _glfwSetError(GLFW_VERSION_UNAVAILABLE,
+                      "NSOpenGL: Mac OS X does not support OpenGL robustness "
+                      "strategies");
+        return GL_FALSE;
+    }
+
+#define ADD_ATTR(x) { attributes[attributeCount++] = x; }
+#define ADD_ATTR2(x, y) { ADD_ATTR(x); ADD_ATTR(y); }
+
+    // Arbitrary array size here
+    NSOpenGLPixelFormatAttribute attributes[40];
+
+    ADD_ATTR(NSOpenGLPFADoubleBuffer);
+
+    if (wndconfig->mode == GLFW_FULLSCREEN)
+    {
+        ADD_ATTR(NSOpenGLPFANoRecovery);
+        ADD_ATTR2(NSOpenGLPFAScreenMask,
+                  CGDisplayIDToOpenGLDisplayMask(CGMainDisplayID()));
+    }
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
+    if (wndconfig->glMajor > 2)
+        ADD_ATTR2(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core);
+#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
+
+    ADD_ATTR2(NSOpenGLPFAColorSize, colorBits);
+
+    if (fbconfig->alphaBits > 0)
+        ADD_ATTR2(NSOpenGLPFAAlphaSize, fbconfig->alphaBits);
+
+    if (fbconfig->depthBits > 0)
+        ADD_ATTR2(NSOpenGLPFADepthSize, fbconfig->depthBits);
+
+    if (fbconfig->stencilBits > 0)
+        ADD_ATTR2(NSOpenGLPFAStencilSize, fbconfig->stencilBits);
+
+    int accumBits = fbconfig->accumRedBits + fbconfig->accumGreenBits +
+                    fbconfig->accumBlueBits + fbconfig->accumAlphaBits;
+
+    if (accumBits > 0)
+        ADD_ATTR2(NSOpenGLPFAAccumSize, accumBits);
+
+    if (fbconfig->auxBuffers > 0)
+        ADD_ATTR2(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers);
+
+    if (fbconfig->stereo)
+        ADD_ATTR(NSOpenGLPFAStereo);
+
+    if (fbconfig->samples > 0)
+    {
+        ADD_ATTR2(NSOpenGLPFASampleBuffers, 1);
+        ADD_ATTR2(NSOpenGLPFASamples, fbconfig->samples);
+    }
+
+    // NOTE: All NSOpenGLPixelFormats on the relevant cards support sRGB
+    // frambuffer, so there's no need (and no way) to request it
+
+    ADD_ATTR(0);
+
+#undef ADD_ATTR
+#undef ADD_ATTR2
+
+    window->NSGL.pixelFormat =
+        [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
+    if (window->NSGL.pixelFormat == nil)
+    {
+        _glfwSetError(GLFW_PLATFORM_ERROR,
+                      "NSOpenGL: Failed to create OpenGL pixel format");
+        return GL_FALSE;
+    }
+
+    NSOpenGLContext* share = NULL;
+
+    if (wndconfig->share)
+        share = wndconfig->share->NSGL.context;
+
+    window->NSGL.context =
+        [[NSOpenGLContext alloc] initWithFormat:window->NSGL.pixelFormat
+                                   shareContext:share];
+    if (window->NSGL.context == nil)
+    {
+        _glfwSetError(GLFW_PLATFORM_ERROR,
+                      "NSOpenGL: Failed to create OpenGL context");
+        return GL_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                      //////
+//////////////////////////////////////////////////////////////////////////
+
 //========================================================================
 // Make the OpenGL context associated with the specified window current
 //========================================================================

+ 1 - 3
src/win32_init.c

@@ -200,7 +200,7 @@ int _glfwPlatformInit(void)
 // Close window and shut down library
 //========================================================================
 
-int _glfwPlatformTerminate(void)
+void _glfwPlatformTerminate(void)
 {
     // Restore the original gamma ramp
     if (_glfwLibrary.rampChanged)
@@ -220,8 +220,6 @@ int _glfwPlatformTerminate(void)
     SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0,
                          UIntToPtr(_glfwLibrary.Win32.foregroundLockTimeout),
                          SPIF_SENDCHANGE);
-
-    return GL_TRUE;
 }
 
 

+ 1 - 3
src/x11_init.c

@@ -662,7 +662,7 @@ int _glfwPlatformInit(void)
 // Close window and shut down library
 //========================================================================
 
-int _glfwPlatformTerminate(void)
+void _glfwPlatformTerminate(void)
 {
     if (_glfwLibrary.X11.cursor)
     {
@@ -681,8 +681,6 @@ int _glfwPlatformTerminate(void)
     // Free clipboard memory
     if (_glfwLibrary.X11.selection.string)
         free(_glfwLibrary.X11.selection.string);
-
-    return GL_TRUE;
 }
 
 

+ 7 - 5
tests/accuracy.c

@@ -51,6 +51,11 @@ static void set_swap_interval(GLFWwindow window, int interval)
     glfwSetWindowTitle(window, title);
 }
 
+static void error_callback(int error, const char* description)
+{
+    fprintf(stderr, "Error: %s\n", description);
+}
+
 static void window_size_callback(GLFWwindow window, int width, int height)
 {
     window_width = width;
@@ -80,18 +85,15 @@ int main(void)
     GLFWwindow window;
     int width, height;
 
+    glfwSetErrorCallback(error_callback);
+
     if (!glfwInit())
-    {
-        fprintf(stderr, "Failed to initialize GLFW: %s\n", glfwErrorString(glfwGetError()));
         exit(EXIT_FAILURE);
-    }
 
     window = glfwCreateWindow(window_width, window_height, "", NULL, NULL);
     if (!window)
     {
         glfwTerminate();
-
-        fprintf(stderr, "Failed to open GLFW window: %s\n", glfwErrorString(glfwGetError()));
         exit(EXIT_FAILURE);
     }
 

+ 5 - 5
tests/clipboard.c

@@ -47,6 +47,11 @@ static GLboolean control_is_down(GLFWwindow window)
            glfwGetKey(window, GLFW_KEY_RIGHT_CONTROL);
 }
 
+static void error_callback(int error, const char* description)
+{
+    fprintf(stderr, "Error: %s\n", description);
+}
+
 static int window_close_callback(GLFWwindow window)
 {
     closed = GL_TRUE;
@@ -93,11 +98,6 @@ static void window_size_callback(GLFWwindow window, int width, int height)
     glViewport(0, 0, width, height);
 }
 
-static void error_callback(int error, const char* description)
-{
-    fprintf(stderr, "Error in %s\n", description);
-}
-
 int main(int argc, char** argv)
 {
     int ch;

+ 7 - 5
tests/defaults.c

@@ -72,16 +72,20 @@ static ParamGLFW glfw_params[] =
     { 0, NULL }
 };
 
+static void error_callback(int error, const char* description)
+{
+    fprintf(stderr, "Error: %s\n", description);
+}
+
 int main(void)
 {
     int i, width, height;
     GLFWwindow window;
 
+    glfwSetErrorCallback(error_callback);
+
     if (!glfwInit())
-    {
-        fprintf(stderr, "Failed to initialize GLFW: %s\n", glfwErrorString(glfwGetError()));
         exit(EXIT_FAILURE);
-    }
 
     glfwWindowHint(GLFW_VISIBLE, GL_FALSE);
 
@@ -89,8 +93,6 @@ int main(void)
     if (!window)
     {
         glfwTerminate();
-
-        fprintf(stderr, "Failed to open GLFW window: %s\n", glfwErrorString(glfwGetError()));
         exit(EXIT_FAILURE);
     }
 

+ 7 - 5
tests/events.c

@@ -218,6 +218,11 @@ static const char* get_character_string(int character)
     return result;
 }
 
+static void error_callback(int error, const char* description)
+{
+    fprintf(stderr, "Error: %s\n", description);
+}
+
 static void window_pos_callback(GLFWwindow window, int x, int y)
 {
     printf("%08x at %0.3f: Window position: %i %i\n",
@@ -370,11 +375,10 @@ int main(void)
 
     setlocale(LC_ALL, "");
 
+    glfwSetErrorCallback(error_callback);
+
     if (!glfwInit())
-    {
-        fprintf(stderr, "Failed to initialize GLFW: %s\n", glfwErrorString(glfwGetError()));
         exit(EXIT_FAILURE);
-    }
 
     printf("Library initialized\n");
 
@@ -382,8 +386,6 @@ int main(void)
     if (!window)
     {
         glfwTerminate();
-
-        fprintf(stderr, "Failed to open GLFW window: %s\n", glfwErrorString(glfwGetError()));
         exit(EXIT_FAILURE);
     }
 

+ 7 - 7
tests/fsaa.c

@@ -38,6 +38,11 @@
 
 #include "getopt.h"
 
+static void error_callback(int error, const char* description)
+{
+    fprintf(stderr, "Error: %s\n", description);
+}
+
 static void window_size_callback(GLFWwindow window, int width, int height)
 {
     glViewport(0, 0, width, height);
@@ -82,11 +87,10 @@ int main(int argc, char** argv)
         }
     }
 
+    glfwSetErrorCallback(error_callback);
+
     if (!glfwInit())
-    {
-        fprintf(stderr, "Failed to initialize GLFW: %s\n", glfwErrorString(glfwGetError()));
         exit(EXIT_FAILURE);
-    }
 
     if (samples)
         printf("Requesting FSAA with %i samples\n", samples);
@@ -99,8 +103,6 @@ int main(int argc, char** argv)
     if (!window)
     {
         glfwTerminate();
-
-        fprintf(stderr, "Failed to open GLFW window: %s\n", glfwErrorString(glfwGetError()));
         exit(EXIT_FAILURE);
     }
 
@@ -113,8 +115,6 @@ int main(int argc, char** argv)
     if (!glfwExtensionSupported("GL_ARB_multisample"))
     {
         glfwTerminate();
-
-        fprintf(stderr, "Context reports GL_ARB_multisample is not supported\n");
         exit(EXIT_FAILURE);
     }
 

+ 7 - 5
tests/fsfocus.c

@@ -35,6 +35,11 @@
 
 static GLboolean running = GL_TRUE;
 
+static void error_callback(int error, const char* description)
+{
+    fprintf(stderr, "Error: %s\n", description);
+}
+
 static void window_focus_callback(GLFWwindow window, int focused)
 {
     printf("%0.3f: Window %s\n",
@@ -76,18 +81,15 @@ int main(void)
 {
     GLFWwindow window;
 
+    glfwSetErrorCallback(error_callback);
+
     if (!glfwInit())
-    {
-        fprintf(stderr, "Failed to initialize GLFW: %s\n", glfwErrorString(glfwGetError()));
         exit(EXIT_FAILURE);
-    }
 
     window = glfwCreateWindow(640, 480, "Fullscreen focus", glfwGetPrimaryMonitor(), NULL);
     if (!window)
     {
         glfwTerminate();
-
-        fprintf(stderr, "Failed to open GLFW window: %s\n", glfwErrorString(glfwGetError()));
         exit(EXIT_FAILURE);
     }
 

+ 7 - 5
tests/gamma.c

@@ -52,6 +52,11 @@ static void set_gamma(float value)
     glfwSetGamma(gamma_value);
 }
 
+static void error_callback(int error, const char* description)
+{
+    fprintf(stderr, "Error: %s\n", description);
+}
+
 static int window_close_callback(GLFWwindow window)
 {
     closed = GL_TRUE;
@@ -118,11 +123,10 @@ int main(int argc, char** argv)
         }
     }
 
+    glfwSetErrorCallback(error_callback);
+
     if (!glfwInit())
-    {
-        fprintf(stderr, "Failed to initialize GLFW: %s\n", glfwErrorString(glfwGetError()));
         exit(EXIT_FAILURE);
-    }
 
     if (monitor)
     {
@@ -141,8 +145,6 @@ int main(int argc, char** argv)
     if (!window)
     {
         glfwTerminate();
-
-        fprintf(stderr, "Failed to open GLFW window: %s\n", glfwErrorString(glfwGetError()));
         exit(EXIT_FAILURE);
     }
 

+ 0 - 3
tests/glfwinfo.c

@@ -257,10 +257,7 @@ int main(int argc, char** argv)
     glfwSetErrorCallback(error_callback);
 
     if (!glfwInit())
-    {
-        fprintf(stderr, "Failed to initialize GLFW: %s\n", glfwErrorString(glfwGetError()));
         exit(EXIT_FAILURE);
-    }
 
     if (major != 1 || minor != 0)
     {

+ 10 - 8
tests/iconify.c

@@ -42,6 +42,11 @@ static void usage(void)
     printf("Usage: iconify [-h] [-f]\n");
 }
 
+static void error_callback(int error, const char* description)
+{
+    fprintf(stderr, "Error: %s\n", description);
+}
+
 static int window_close_callback(GLFWwindow window)
 {
     closed = GL_TRUE;
@@ -95,12 +100,6 @@ int main(int argc, char** argv)
     GLFWmonitor monitor = NULL;
     GLFWwindow window;
 
-    if (!glfwInit())
-    {
-        fprintf(stderr, "Failed to initialize GLFW: %s\n", glfwErrorString(glfwGetError()));
-        exit(EXIT_FAILURE);
-    }
-
     while ((ch = getopt(argc, argv, "fh")) != -1)
     {
         switch (ch)
@@ -119,6 +118,11 @@ int main(int argc, char** argv)
         }
     }
 
+    glfwSetErrorCallback(error_callback);
+
+    if (!glfwInit())
+        exit(EXIT_FAILURE);
+
     if (monitor)
     {
         GLFWvidmode mode;
@@ -136,8 +140,6 @@ int main(int argc, char** argv)
     if (!window)
     {
         glfwTerminate();
-
-        fprintf(stderr, "Failed to open GLFW window: %s\n", glfwErrorString(glfwGetError()));
         exit(EXIT_FAILURE);
     }
 

+ 7 - 5
tests/joysticks.c

@@ -47,6 +47,11 @@ typedef struct Joystick
 static Joystick joysticks[GLFW_JOYSTICK_LAST - GLFW_JOYSTICK_1 + 1];
 static int joystick_count = 0;
 
+static void error_callback(int error, const char* description)
+{
+    fprintf(stderr, "Error: %s\n", description);
+}
+
 static void window_size_callback(GLFWwindow window, int width, int height)
 {
     glViewport(0, 0, width, height);
@@ -185,18 +190,15 @@ int main(void)
 
     memset(joysticks, 0, sizeof(joysticks));
 
+    glfwSetErrorCallback(error_callback);
+
     if (!glfwInit())
-    {
-        fprintf(stderr, "Failed to initialize GLFW: %s\n", glfwErrorString(glfwGetError()));
         exit(EXIT_FAILURE);
-    }
 
     window = glfwCreateWindow(640, 480, "Joystick Test", NULL, NULL);
     if (!window)
     {
         glfwTerminate();
-
-        fprintf(stderr, "Failed to open GLFW window: %s\n", glfwErrorString(glfwGetError()));
         exit(EXIT_FAILURE);
     }
 

+ 7 - 7
tests/peter.c

@@ -56,6 +56,11 @@ static void toggle_cursor(GLFWwindow window)
     }
 }
 
+static void error_callback(int error, const char* description)
+{
+    fprintf(stderr, "Error: %s\n", description);
+}
+
 static void cursor_position_callback(GLFWwindow window, int x, int y)
 {
     printf("Cursor moved to: %i %i (%i %i)\n", x, y, x - cursor_x, y - cursor_y);
@@ -111,16 +116,13 @@ static GLboolean open_window(void)
 
 int main(void)
 {
+    glfwSetErrorCallback(error_callback);
+
     if (!glfwInit())
-    {
-        fprintf(stderr, "Failed to initialize GLFW: %s\n", glfwErrorString(glfwGetError()));
         exit(EXIT_FAILURE);
-    }
 
     if (!open_window())
     {
-        fprintf(stderr, "Failed to open GLFW window: %s\n", glfwErrorString(glfwGetError()));
-
         glfwTerminate();
         exit(EXIT_FAILURE);
     }
@@ -139,8 +141,6 @@ int main(void)
             glfwDestroyWindow(window_handle);
             if (!open_window())
             {
-                fprintf(stderr, "Failed to open GLFW window: %s\n", glfwErrorString(glfwGetError()));
-
                 glfwTerminate();
                 exit(EXIT_FAILURE);
             }

+ 9 - 10
tests/reopen.c

@@ -41,6 +41,11 @@
 static GLFWwindow window_handle = NULL;
 static GLboolean closed = GL_FALSE;
 
+static void error_callback(int error, const char* description)
+{
+    fprintf(stderr, "Error: %s\n", description);
+}
+
 static void window_size_callback(GLFWwindow window, int width, int height)
 {
     glViewport(0, 0, width, height);
@@ -71,16 +76,14 @@ static GLboolean open_window(int width, int height, GLFWmonitor monitor)
 {
     double base;
 
+    if (!glfwInit())
+        return GL_FALSE;
+
     base = glfwGetTime();
 
     window_handle = glfwCreateWindow(width, height, "Window Re-opener", monitor, NULL);
     if (!window_handle)
-    {
-        fprintf(stderr, "Failed to open %s mode GLFW window: %s\n",
-                monitor ? "fullscreen" : "windowed",
-                glfwErrorString(glfwGetError()));
         return GL_FALSE;
-    }
 
     glfwMakeContextCurrent(window_handle);
     glfwSwapInterval(1);
@@ -110,11 +113,7 @@ int main(int argc, char** argv)
 {
     int count = 0;
 
-    if (!glfwInit())
-    {
-        fprintf(stderr, "Failed to initialize GLFW: %s\n", glfwErrorString(glfwGetError()));
-        return GL_FALSE;
-    }
+    glfwSetErrorCallback(error_callback);
 
     for (;;)
     {

+ 7 - 7
tests/sharing.c

@@ -39,6 +39,11 @@
 static GLFWwindow windows[2];
 static GLboolean closed = GL_FALSE;
 
+static void error_callback(int error, const char* description)
+{
+    fprintf(stderr, "Error: %s\n", description);
+}
+
 static void key_callback(GLFWwindow window, int key, int action)
 {
     if (action == GLFW_PRESS && key == GLFW_KEY_ESCAPE)
@@ -128,17 +133,14 @@ int main(int argc, char** argv)
 {
     GLuint texture;
 
+    glfwSetErrorCallback(error_callback);
+
     if (!glfwInit())
-    {
-        fprintf(stderr, "Failed to initialize GLFW: %s\n", glfwErrorString(glfwGetError()));
         exit(EXIT_FAILURE);
-    }
 
     windows[0] = open_window("First", NULL, 0, 0);
     if (!windows[0])
     {
-        fprintf(stderr, "Failed to open first GLFW window: %s\n", glfwErrorString(glfwGetError()));
-
         glfwTerminate();
         exit(EXIT_FAILURE);
     }
@@ -152,8 +154,6 @@ int main(int argc, char** argv)
     windows[1] = open_window("Second", windows[0], WIDTH + 50, 0);
     if (!windows[1])
     {
-        fprintf(stderr, "Failed to open second GLFW window: %s\n", glfwErrorString(glfwGetError()));
-
         glfwTerminate();
         exit(EXIT_FAILURE);
     }

+ 7 - 5
tests/tearing.c

@@ -48,6 +48,11 @@ static void set_swap_interval(GLFWwindow window, int interval)
     glfwSetWindowTitle(window, title);
 }
 
+static void error_callback(int error, const char* description)
+{
+    fprintf(stderr, "Error: %s\n", description);
+}
+
 static void window_size_callback(GLFWwindow window, int width, int height)
 {
     glViewport(0, 0, width, height);
@@ -64,17 +69,14 @@ int main(void)
     float position;
     GLFWwindow window;
 
+    glfwSetErrorCallback(error_callback);
+
     if (!glfwInit())
-    {
-        fprintf(stderr, "Failed to initialize GLFW: %s\n", glfwErrorString(glfwGetError()));
         exit(EXIT_FAILURE);
-    }
 
     window = glfwCreateWindow(640, 480, "", NULL, NULL);
     if (!window)
     {
-        fprintf(stderr, "Failed to open GLFW window: %s\n", glfwErrorString(glfwGetError()));
-
         glfwTerminate();
         exit(EXIT_FAILURE);
     }

+ 10 - 6
tests/threads.c

@@ -47,6 +47,11 @@ typedef struct
 
 static volatile GLboolean running = GL_TRUE;
 
+static void error_callback(int error, const char* description)
+{
+    fprintf(stderr, "Error: %s\n", description);
+}
+
 static int thread_main(void* data)
 {
     const Thread* thread = (const Thread*) data;
@@ -80,12 +85,10 @@ int main(void)
     };
     const int count = sizeof(threads) / sizeof(Thread);
 
+    glfwSetErrorCallback(error_callback);
+
     if (!glfwInit())
-    {
-        fprintf(stderr, "Failed to initialize GLFW: %s\n",
-                glfwErrorString(glfwGetError()));
         exit(EXIT_FAILURE);
-    }
 
     for (i = 0;  i < count;  i++)
     {
@@ -96,8 +99,7 @@ int main(void)
                                              NULL, NULL);
         if (!threads[i].window)
         {
-            fprintf(stderr, "Failed to open GLFW window: %s\n",
-                    glfwErrorString(glfwGetError()));
+            glfwTerminate();
             exit(EXIT_FAILURE);
         }
 
@@ -105,6 +107,8 @@ int main(void)
             thrd_success)
         {
             fprintf(stderr, "Failed to create secondary thread\n");
+
+            glfwTerminate();
             exit(EXIT_FAILURE);
         }
     }

+ 7 - 5
tests/title.c

@@ -32,6 +32,11 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+static void error_callback(int error, const char* description)
+{
+    fprintf(stderr, "Error: %s\n", description);
+}
+
 static void window_size_callback(GLFWwindow window, int width, int height)
 {
     glViewport(0, 0, width, height);
@@ -41,17 +46,14 @@ int main(void)
 {
     GLFWwindow window;
 
+    glfwSetErrorCallback(error_callback);
+
     if (!glfwInit())
-    {
-        fprintf(stderr, "Failed to initialize GLFW: %s\n", glfwErrorString(glfwGetError()));
         exit(EXIT_FAILURE);
-    }
 
     window = glfwCreateWindow(400, 400, "English 日本語 русский язык 官話", NULL, NULL);
     if (!window)
     {
-        fprintf(stderr, "Failed to open GLFW window: %s\n", glfwErrorString(glfwGetError()));
-
         glfwTerminate();
         exit(EXIT_FAILURE);
     }

+ 7 - 7
tests/windows.c

@@ -40,18 +40,21 @@ static const char* titles[] =
     "Quux"
 };
 
+static void error_callback(int error, const char* description)
+{
+    fprintf(stderr, "Error: %s\n", description);
+}
+
 int main(void)
 {
     int i;
     GLboolean running = GL_TRUE;
     GLFWwindow windows[4];
 
+    glfwSetErrorCallback(error_callback);
+
     if (!glfwInit())
-    {
-        fprintf(stderr, "Failed to initialize GLFW: %s\n",
-                glfwErrorString(glfwGetError()));
         exit(EXIT_FAILURE);
-    }
 
     for (i = 0;  i < 4;  i++)
     {
@@ -60,9 +63,6 @@ int main(void)
         windows[i] = glfwCreateWindow(200, 200, titles[i], NULL, NULL);
         if (!windows[i])
         {
-            fprintf(stderr, "Failed to open GLFW window: %s\n",
-                    glfwErrorString(glfwGetError()));
-
             glfwTerminate();
             exit(EXIT_FAILURE);
         }