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.
This commit is contained in:
Camilla Löwy 2017-05-01 19:20:57 +02:00
parent 16ddfafeaa
commit 6350641f0a
8 changed files with 122 additions and 19 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.
*

View File

@ -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);

View File

@ -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);
/*! @} */

View File

@ -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;
}

View File

@ -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;
}