Pārlūkot izejas kodu

Add glfwGetError

Related to #970.

If you have opinions on the design or implementation of this function,
please come join us in #970 before it is frozen for release.
Camilla Löwy 8 gadi atpakaļ
vecāks
revīzija
6350641f0a
8 mainītis faili ar 122 papildinājumiem un 19 dzēšanām
  1. 1 0
      README.md
  2. 30 14
      docs/intro.dox
  3. 9 0
      docs/news.dox
  4. 35 0
      include/GLFW/glfw3.h
  5. 35 3
      src/init.c
  6. 2 0
      src/internal.h
  7. 5 1
      src/posix_tls.c
  8. 5 1
      src/win32_tls.c

+ 1 - 0
README.md

@@ -122,6 +122,7 @@ information on what to include when reporting a bug.
 
 ## Changelog
 
+- Added `glfwGetError` function for querying the last error code (#970)
 - Added `glfwGetKeyScancode` function that allows retrieving platform dependent
   scancodes for keys (#830)
 - Added `glfwSetWindowMaximizeCallback` and `GLFWwindowmaximizefun` for

+ 30 - 14
docs/intro.dox

@@ -30,6 +30,7 @@ successfully initialized, and only from the main thread.
 
  - @ref glfwGetVersion
  - @ref glfwGetVersionString
+ - @ref glfwGetError
  - @ref glfwSetErrorCallback
  - @ref glfwInitHint
  - @ref glfwInit
@@ -131,9 +132,25 @@ not very helpful when trying to figure out _why_ the error occurred.  Other
 functions have no return value reserved for errors, so error notification needs
 a separate channel.  Finally, far from all GLFW functions have return values.
 
-This is where the error callback comes in.  This callback is called whenever an
-error occurs.  It is set with @ref glfwSetErrorCallback, a function that may be
-called regardless of whether GLFW is initialized.
+The last error code for the calling thread can be queried at any time with @ref
+glfwGetError.
+
+@code
+int error = glfwGetError();
+@endcode
+
+If no error has occurred since the last call, @ref GLFW_NO_ERROR is returned.
+The error is cleared before the function returns.
+
+The error code indicates the general category of the error.  Some error codes,
+such as @ref GLFW_NOT_INITIALIZED has only a single meaning, whereas others like
+@ref GLFW_PLATFORM_ERROR are used for many different errors.
+
+GLFW usually has much more information about the error than its general category
+at the point where it occurred.  This is where the error callback comes in.
+This callback is called whenever an error occurs.  It is set with @ref
+glfwSetErrorCallback, a function that may be called regardless of whether GLFW
+is initialized.
 
 @code
 glfwSetErrorCallback(error_callback);
@@ -150,24 +167,23 @@ void error_callback(int error, const char* description)
 }
 @endcode
 
-The error code indicates the general category of the error.  Some error codes,
-such as @ref GLFW_NOT_INITIALIZED has only a single meaning, whereas others like
-@ref GLFW_PLATFORM_ERROR are used for many different errors.
+The error callback is called after the error code is set, so calling @ref
+glfwGetError from within the error callback returns the same value as the
+callback argument.
 
-Reported errors are never fatal.  As long as GLFW was successfully initialized,
-it will remain initialized and in a safe state until terminated regardless of
-how many errors occur.  If an error occurs during initialization that causes
-@ref glfwInit to fail, any part of the library that was initialized will be
-safely terminated.
+__Reported errors are never fatal.__  As long as GLFW was successfully
+initialized, it will remain initialized and in a safe state until terminated
+regardless of how many errors occur.  If an error occurs during initialization
+that causes @ref glfwInit to fail, any part of the library that was initialized
+will be safely terminated.
 
 The description string is only valid until the error callback returns, as it may
 have been generated specifically for that error.  This lets GLFW provide much
 more specific error descriptions but means you must make a copy if you want to
 keep the description string.
 
-@note Relying on erroneous behavior is not forward compatible.  In other words,
-do not rely on a currently invalid call to generate a specific error, as that
-same call may in future versions generate a different error or become valid.
+Do not rely on a currently invalid call to generate a specific error, as in the
+future that same call may generate a different error or become valid.
 
 
 @section coordinate_systems Coordinate systems

+ 9 - 0
docs/news.dox

@@ -4,6 +4,15 @@
 
 @section news_33 New features in 3.3
 
+
+@subsection news_33_geterror Error query
+
+GLFW now supports querying the last error code for the calling thread with @ref
+glfwGetError.
+
+@see @ref error_handling
+
+
 @subsection news_33_maximize Window maximization callback
 
 GLFW now supports window maximization notifications with @ref

+ 35 - 0
include/GLFW/glfw3.h

@@ -546,6 +546,13 @@ extern "C" {
  *
  *  @ingroup init
  *  @{ */
+/*! @brief No error has occurred.
+ *
+ *  No error has occurred.
+ *
+ *  @analysis Yay.
+ */
+#define GLFW_NO_ERROR               0
 /*! @brief GLFW has not been initialized.
  *
  *  This occurs if a GLFW function was called that must not be called unless the
@@ -1607,11 +1614,38 @@ GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev);
  */
 GLFWAPI const char* glfwGetVersionString(void);
 
+/*! @brief Returns and clears the last error for the calling thread.
+ *
+ *  This function returns and clears the [error code](@ref error) of the last
+ *  error that occurred on the calling thread.  If no error has occurred since
+ *  the last call, it returns @ref GLFW_NO_ERROR.
+ *
+ *  @return The last error code for the calling thread, or @ref GLFW_NO_ERROR.
+ *
+ *  @errors None.
+ *
+ *  @remark This function may be called before @ref glfwInit.
+ *
+ *  @thread_safety This function may be called from any thread.
+ *
+ *  @sa @ref error_handling
+ *  @sa @ref glfwSetErrorCallback
+ *
+ *  @since Added in version 3.3.
+ *
+ *  @ingroup init
+ */
+GLFWAPI int glfwGetError(void);
+
 /*! @brief Sets the error callback.
  *
  *  This function sets the error callback, which is called with an error code
  *  and a human-readable description each time a GLFW error occurs.
  *
+ *  The error code is set before the callback is called.  Calling @ref
+ *  glfwGetError from the error callback will return the same value as the error
+ *  code argument.
+ *
  *  The error callback is called on the thread where the error occurred.  If you
  *  are using GLFW from multiple threads, your error callback needs to be
  *  written accordingly.
@@ -1634,6 +1668,7 @@ GLFWAPI const char* glfwGetVersionString(void);
  *  @thread_safety This function must only be called from the main thread.
  *
  *  @sa @ref error_handling
+ *  @sa @ref glfwGetError
  *
  *  @since Added in version 3.0.
  *

+ 35 - 3
src/init.c

@@ -43,6 +43,7 @@ _GLFWlibrary _glfw = { GLFW_FALSE };
 // These are outside of _glfw so they can be used before initialization and
 // after termination
 //
+static int _glfwErrorCode;
 static GLFWerrorfun _glfwErrorCallback;
 static _GLFWinitconfig _glfwInitHints =
 {
@@ -113,7 +114,11 @@ static void terminate(void)
     _glfwTerminateVulkan();
     _glfwPlatformTerminate();
 
+    if (_glfwPlatformIsValidTls(&_glfw.error))
+        _glfwErrorCode = (int) (intptr_t) _glfwPlatformGetTls(&_glfw.error);
+
     _glfwPlatformDestroyTls(&_glfw.context);
+    _glfwPlatformDestroyTls(&_glfw.error);
 
     memset(&_glfw, 0, sizeof(_glfw));
 }
@@ -125,6 +130,11 @@ static void terminate(void)
 
 void _glfwInputError(int error, const char* format, ...)
 {
+    if (_glfw.initialized)
+        _glfwPlatformSetTls(&_glfw.error, (void*) (intptr_t) error);
+    else
+        _glfwErrorCode = error;
+
     if (_glfwErrorCallback)
     {
         char buffer[8192];
@@ -164,15 +174,19 @@ GLFWAPI int glfwInit(void)
     memset(&_glfw, 0, sizeof(_glfw));
     _glfw.hints.init = _glfwInitHints;
 
-    if (!_glfwPlatformCreateTls(&_glfw.context))
-        return GLFW_FALSE;
-
     if (!_glfwPlatformInit())
     {
         terminate();
         return GLFW_FALSE;
     }
 
+    if (!_glfwPlatformCreateTls(&_glfw.error))
+        return GLFW_FALSE;
+    if (!_glfwPlatformCreateTls(&_glfw.context))
+        return GLFW_FALSE;
+
+    _glfwPlatformSetTls(&_glfw.error, (void*) (intptr_t) _glfwErrorCode);
+
     _glfw.initialized = GLFW_TRUE;
     _glfw.timer.offset = _glfwPlatformGetTimerValue();
 
@@ -223,6 +237,24 @@ GLFWAPI const char* glfwGetVersionString(void)
     return _glfwPlatformGetVersionString();
 }
 
+GLFWAPI int glfwGetError(void)
+{
+    int error;
+
+    if (_glfw.initialized)
+    {
+        error = (int) (intptr_t) _glfwPlatformGetTls(&_glfw.error);
+        _glfwPlatformSetTls(&_glfw.error, (intptr_t) GLFW_NO_ERROR);
+    }
+    else
+    {
+        error = _glfwErrorCode;
+        _glfwErrorCode = GLFW_NO_ERROR;
+    }
+
+    return error;
+}
+
 GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun)
 {
     _GLFW_SWAP_POINTERS(_glfwErrorCallback, cbfun);

+ 2 - 0
src/internal.h

@@ -517,6 +517,7 @@ struct _GLFWlibrary
 
     _GLFWjoystick       joysticks[GLFW_JOYSTICK_LAST + 1];
 
+    _GLFWtls            error;
     _GLFWtls            context;
 
     struct {
@@ -653,6 +654,7 @@ GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls);
 void _glfwPlatformDestroyTls(_GLFWtls* tls);
 void* _glfwPlatformGetTls(_GLFWtls* tls);
 void _glfwPlatformSetTls(_GLFWtls* tls, void* value);
+GLFWbool _glfwPlatformIsValidTls(_GLFWtls* tls);
 
 /*! @} */
 

+ 5 - 1
src/posix_tls.c

@@ -52,7 +52,6 @@ GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls)
 
 void _glfwPlatformDestroyTls(_GLFWtls* tls)
 {
-    assert(tls->posix.allocated == GLFW_TRUE);
     if (tls->posix.allocated)
         pthread_key_delete(tls->posix.key);
     memset(tls, 0, sizeof(_GLFWtls));
@@ -70,3 +69,8 @@ void _glfwPlatformSetTls(_GLFWtls* tls, void* value)
     pthread_setspecific(tls->posix.key, value);
 }
 
+GLFWbool _glfwPlatformIsValidTls(_GLFWtls* tls)
+{
+    return tls->posix.allocated;
+}
+

+ 5 - 1
src/win32_tls.c

@@ -52,7 +52,6 @@ GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls)
 
 void _glfwPlatformDestroyTls(_GLFWtls* tls)
 {
-    assert(tls->win32.allocated == GLFW_TRUE);
     if (tls->win32.allocated)
         TlsFree(tls->win32.index);
     memset(tls, 0, sizeof(_GLFWtls));
@@ -70,3 +69,8 @@ void _glfwPlatformSetTls(_GLFWtls* tls, void* value)
     TlsSetValue(tls->win32.index, value);
 }
 
+GLFWbool _glfwPlatformIsValidTls(_GLFWtls* tls)
+{
+    return tls->win32.allocated;
+}
+