mirror of
https://github.com/glfw/glfw.git
synced 2024-11-12 17:51:48 +00:00
parent
beaeb0d4af
commit
14a3fe0ac0
@ -122,7 +122,8 @@ information on what to include when reporting a bug.
|
|||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
- Added `glfwGetError` function for querying the last error code (#970)
|
- Added `glfwGetError` function for querying the last error code and its
|
||||||
|
description (#970)
|
||||||
- Added `glfwRequestWindowAttention` function for requesting attention from the
|
- Added `glfwRequestWindowAttention` function for requesting attention from the
|
||||||
user (#732,#988)
|
user (#732,#988)
|
||||||
- Added `glfwGetKeyScancode` function that allows retrieving platform dependent
|
- Added `glfwGetKeyScancode` function that allows retrieving platform dependent
|
||||||
|
@ -128,15 +128,19 @@ immediately.
|
|||||||
@section error_handling Error handling
|
@section error_handling Error handling
|
||||||
|
|
||||||
Some GLFW functions have return values that indicate an error, but this is often
|
Some GLFW functions have return values that indicate an error, but this is often
|
||||||
not very helpful when trying to figure out _why_ the error occurred. Other
|
not very helpful when trying to figure out what happened or why it occurred.
|
||||||
functions have no return value reserved for errors, so error notification needs
|
Other functions have no return value reserved for errors, so error notification
|
||||||
a separate channel. Finally, far from all GLFW functions have return values.
|
needs a separate channel. Finally, far from all GLFW functions have return
|
||||||
|
values.
|
||||||
|
|
||||||
The last error code for the calling thread can be queried at any time with @ref
|
The last [error code](@ref errors) for the calling thread can be queried at any
|
||||||
glfwGetError.
|
time with @ref glfwGetError.
|
||||||
|
|
||||||
@code
|
@code
|
||||||
int error = glfwGetError();
|
int code = glfwGetError(NULL);
|
||||||
|
|
||||||
|
if (code != GLFW_NO_ERROR)
|
||||||
|
handle_error(code);
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
If no error has occurred since the last call, @ref GLFW_NO_ERROR is returned.
|
If no error has occurred since the last call, @ref GLFW_NO_ERROR is returned.
|
||||||
@ -146,42 +150,52 @@ 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
|
such as @ref GLFW_NOT_INITIALIZED has only a single meaning, whereas others like
|
||||||
@ref GLFW_PLATFORM_ERROR are used for many different errors.
|
@ref GLFW_PLATFORM_ERROR are used for many different errors.
|
||||||
|
|
||||||
GLFW usually has much more information about the error than its general category
|
GLFW often has more information about an error than its general category. You
|
||||||
at the point where it occurred. This is where the error callback comes in.
|
can retrieve a UTF-8 encoded human-readable description along with the error
|
||||||
This callback is called whenever an error occurs. It is set with @ref
|
code. If no error has occurred since the last call, the description is set to
|
||||||
glfwSetErrorCallback, a function that may be called regardless of whether GLFW
|
`NULL`.
|
||||||
is initialized.
|
|
||||||
|
@code
|
||||||
|
const char* description;
|
||||||
|
int code = glfwGetError(&description);
|
||||||
|
|
||||||
|
if (description)
|
||||||
|
display_error_message(code, description);
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
The retrieved description string is only valid until the next error occurs.
|
||||||
|
This means you must make a copy of it if you want to keep it.
|
||||||
|
|
||||||
|
You can also set an error callback, which will be called each time an error
|
||||||
|
occurs. It is set with @ref glfwSetErrorCallback.
|
||||||
|
|
||||||
@code
|
@code
|
||||||
glfwSetErrorCallback(error_callback);
|
glfwSetErrorCallback(error_callback);
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
The error callback receives a human-readable description of the error and (when
|
The error callback receives the same error code and human-readable description
|
||||||
possible) its cause. The description encoded as UTF-8. The callback is also
|
returned by @ref glfwGetError.
|
||||||
provided with an [error code](@ref errors).
|
|
||||||
|
|
||||||
@code
|
@code
|
||||||
void error_callback(int error, const char* description)
|
void error_callback(int code, const char* description)
|
||||||
{
|
{
|
||||||
puts(description);
|
display_error_message(code, description);
|
||||||
}
|
}
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
The error callback is called after the error code is set, so calling @ref
|
The error callback is called after the error is stored, so calling @ref
|
||||||
glfwGetError from within the error callback returns the same value as the
|
glfwGetError from within the error callback returns the same values as the
|
||||||
callback argument.
|
callback argument.
|
||||||
|
|
||||||
|
The description string passed to the callback is only valid until the error
|
||||||
|
callback returns. This means you must make a copy of it if you want to keep it.
|
||||||
|
|
||||||
__Reported errors are never fatal.__ As long as GLFW was successfully
|
__Reported errors are never fatal.__ As long as GLFW was successfully
|
||||||
initialized, it will remain initialized and in a safe state until terminated
|
initialized, it will remain initialized and in a safe state until terminated
|
||||||
regardless of how many errors occur. If an error occurs during initialization
|
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
|
that causes @ref glfwInit to fail, any part of the library that was initialized
|
||||||
will be safely terminated.
|
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.
|
|
||||||
|
|
||||||
Do not rely on a currently invalid call to generate a specific error, as in the
|
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.
|
future that same call may generate a different error or become valid.
|
||||||
|
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
|
|
||||||
@subsection news_33_geterror Error query
|
@subsection news_33_geterror Error query
|
||||||
|
|
||||||
GLFW now supports querying the last error code for the calling thread with @ref
|
GLFW now supports querying the last error code for the calling thread and its
|
||||||
glfwGetError.
|
human-readable description with @ref glfwGetError.
|
||||||
|
|
||||||
@see @ref error_handling
|
@see @ref error_handling
|
||||||
|
|
||||||
|
@ -1646,13 +1646,20 @@ GLFWAPI const char* glfwGetVersionString(void);
|
|||||||
/*! @brief Returns and clears the last error for the calling thread.
|
/*! @brief Returns and clears the last error for the calling thread.
|
||||||
*
|
*
|
||||||
* This function returns and clears the [error code](@ref error) of the last
|
* 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
|
* error that occurred on the calling thread, and optionally a UTF-8 encoded
|
||||||
* the last call, it returns @ref GLFW_NO_ERROR.
|
* human-readable description of it. If no error has occurred since the last
|
||||||
|
* call, it returns @ref GLFW_NO_ERROR and the description pointer is set to
|
||||||
|
* `NULL`.
|
||||||
*
|
*
|
||||||
|
* @param[in] description Where to store the error description pointer, or `NULL`.
|
||||||
* @return The last error code for the calling thread, or @ref GLFW_NO_ERROR.
|
* @return The last error code for the calling thread, or @ref GLFW_NO_ERROR.
|
||||||
*
|
*
|
||||||
* @errors None.
|
* @errors None.
|
||||||
*
|
*
|
||||||
|
* @pointer_lifetime The returned string is allocated and freed by GLFW. You
|
||||||
|
* should not free it yourself. It is guaranteed to be valid only until the
|
||||||
|
* next error occurs or the library is terminated.
|
||||||
|
*
|
||||||
* @remark This function may be called before @ref glfwInit.
|
* @remark This function may be called before @ref glfwInit.
|
||||||
*
|
*
|
||||||
* @thread_safety This function may be called from any thread.
|
* @thread_safety This function may be called from any thread.
|
||||||
@ -1664,7 +1671,7 @@ GLFWAPI const char* glfwGetVersionString(void);
|
|||||||
*
|
*
|
||||||
* @ingroup init
|
* @ingroup init
|
||||||
*/
|
*/
|
||||||
GLFWAPI int glfwGetError(void);
|
GLFWAPI int glfwGetError(const char** description);
|
||||||
|
|
||||||
/*! @brief Sets the error callback.
|
/*! @brief Sets the error callback.
|
||||||
*
|
*
|
||||||
|
@ -331,7 +331,7 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig)
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
window = _glfwPlatformGetTls(&_glfw.context);
|
window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||||
|
|
||||||
window->context.source = ctxconfig->source;
|
window->context.source = ctxconfig->source;
|
||||||
window->context.client = GLFW_OPENGL_API;
|
window->context.client = GLFW_OPENGL_API;
|
||||||
@ -578,7 +578,7 @@ GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions
|
|||||||
GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle)
|
GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle)
|
||||||
{
|
{
|
||||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
_GLFWwindow* previous = _glfwPlatformGetTls(&_glfw.context);
|
_GLFWwindow* previous = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||||
|
|
||||||
_GLFW_REQUIRE_INIT();
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
@ -601,7 +601,7 @@ GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle)
|
|||||||
GLFWAPI GLFWwindow* glfwGetCurrentContext(void)
|
GLFWAPI GLFWwindow* glfwGetCurrentContext(void)
|
||||||
{
|
{
|
||||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
return _glfwPlatformGetTls(&_glfw.context);
|
return _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLFWAPI void glfwSwapBuffers(GLFWwindow* handle)
|
GLFWAPI void glfwSwapBuffers(GLFWwindow* handle)
|
||||||
@ -626,7 +626,7 @@ GLFWAPI void glfwSwapInterval(int interval)
|
|||||||
|
|
||||||
_GLFW_REQUIRE_INIT();
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
window = _glfwPlatformGetTls(&_glfw.context);
|
window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||||
if (!window)
|
if (!window)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL);
|
_glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL);
|
||||||
@ -643,7 +643,7 @@ GLFWAPI int glfwExtensionSupported(const char* extension)
|
|||||||
|
|
||||||
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
|
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
|
||||||
|
|
||||||
window = _glfwPlatformGetTls(&_glfw.context);
|
window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||||
if (!window)
|
if (!window)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL);
|
_glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL);
|
||||||
@ -708,7 +708,7 @@ GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname)
|
|||||||
|
|
||||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
|
||||||
window = _glfwPlatformGetTls(&_glfw.context);
|
window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||||
if (!window)
|
if (!window)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL);
|
_glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL);
|
||||||
|
@ -199,12 +199,12 @@ static void makeContextCurrentEGL(_GLFWwindow* window)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_glfwPlatformSetTls(&_glfw.context, window);
|
_glfwPlatformSetTls(&_glfw.contextSlot, window);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void swapBuffersEGL(_GLFWwindow* window)
|
static void swapBuffersEGL(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
if (window != _glfwPlatformGetTls(&_glfw.context))
|
if (window != _glfwPlatformGetTls(&_glfw.contextSlot))
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
"EGL: The context must be current on the calling thread when swapping buffers");
|
"EGL: The context must be current on the calling thread when swapping buffers");
|
||||||
@ -233,7 +233,7 @@ static int extensionSupportedEGL(const char* extension)
|
|||||||
|
|
||||||
static GLFWglproc getProcAddressEGL(const char* procname)
|
static GLFWglproc getProcAddressEGL(const char* procname)
|
||||||
{
|
{
|
||||||
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.context);
|
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||||
|
|
||||||
if (window->context.egl.client)
|
if (window->context.egl.client)
|
||||||
{
|
{
|
||||||
|
@ -165,7 +165,7 @@ static void makeContextCurrentGLX(_GLFWwindow* window)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_glfwPlatformSetTls(&_glfw.context, window);
|
_glfwPlatformSetTls(&_glfw.contextSlot, window);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void swapBuffersGLX(_GLFWwindow* window)
|
static void swapBuffersGLX(_GLFWwindow* window)
|
||||||
@ -175,7 +175,7 @@ static void swapBuffersGLX(_GLFWwindow* window)
|
|||||||
|
|
||||||
static void swapIntervalGLX(int interval)
|
static void swapIntervalGLX(int interval)
|
||||||
{
|
{
|
||||||
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.context);
|
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||||
|
|
||||||
if (_glfw.glx.EXT_swap_control)
|
if (_glfw.glx.EXT_swap_control)
|
||||||
{
|
{
|
||||||
|
117
src/init.c
117
src/init.c
@ -43,7 +43,7 @@ _GLFWlibrary _glfw = { GLFW_FALSE };
|
|||||||
// These are outside of _glfw so they can be used before initialization and
|
// These are outside of _glfw so they can be used before initialization and
|
||||||
// after termination
|
// after termination
|
||||||
//
|
//
|
||||||
static int _glfwErrorCode;
|
static _GLFWerror _glfwMainThreadError;
|
||||||
static GLFWerrorfun _glfwErrorCallback;
|
static GLFWerrorfun _glfwErrorCallback;
|
||||||
static _GLFWinitconfig _glfwInitHints =
|
static _GLFWinitconfig _glfwInitHints =
|
||||||
{
|
{
|
||||||
@ -56,9 +56,9 @@ static _GLFWinitconfig _glfwInitHints =
|
|||||||
|
|
||||||
// Returns a generic string representation of the specified error
|
// Returns a generic string representation of the specified error
|
||||||
//
|
//
|
||||||
static const char* getErrorString(int error)
|
static const char* getErrorString(int code)
|
||||||
{
|
{
|
||||||
switch (error)
|
switch (code)
|
||||||
{
|
{
|
||||||
case GLFW_NOT_INITIALIZED:
|
case GLFW_NOT_INITIALIZED:
|
||||||
return "The GLFW library is not initialized";
|
return "The GLFW library is not initialized";
|
||||||
@ -114,11 +114,18 @@ static void terminate(void)
|
|||||||
_glfwTerminateVulkan();
|
_glfwTerminateVulkan();
|
||||||
_glfwPlatformTerminate();
|
_glfwPlatformTerminate();
|
||||||
|
|
||||||
if (_glfwPlatformIsValidTls(&_glfw.error))
|
_glfw.initialized = GLFW_FALSE;
|
||||||
_glfwErrorCode = (int) (intptr_t) _glfwPlatformGetTls(&_glfw.error);
|
|
||||||
|
|
||||||
_glfwPlatformDestroyTls(&_glfw.context);
|
while (_glfw.errorListHead)
|
||||||
_glfwPlatformDestroyTls(&_glfw.error);
|
{
|
||||||
|
_GLFWerror* error = _glfw.errorListHead;
|
||||||
|
_glfw.errorListHead = error->next;
|
||||||
|
free(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfwPlatformDestroyTls(&_glfw.contextSlot);
|
||||||
|
_glfwPlatformDestroyTls(&_glfw.errorSlot);
|
||||||
|
_glfwPlatformDestroyMutex(&_glfw.errorLock);
|
||||||
|
|
||||||
memset(&_glfw, 0, sizeof(_glfw));
|
memset(&_glfw, 0, sizeof(_glfw));
|
||||||
}
|
}
|
||||||
@ -128,37 +135,47 @@ static void terminate(void)
|
|||||||
////// GLFW event API //////
|
////// GLFW event API //////
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void _glfwInputError(int error, const char* format, ...)
|
void _glfwInputError(int code, const char* format, ...)
|
||||||
{
|
{
|
||||||
if (_glfw.initialized)
|
_GLFWerror* error;
|
||||||
_glfwPlatformSetTls(&_glfw.error, (void*) (intptr_t) error);
|
char description[1024];
|
||||||
|
|
||||||
|
if (format)
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
va_list vl;
|
||||||
|
|
||||||
|
va_start(vl, format);
|
||||||
|
count = vsnprintf(description, sizeof(description), format, vl);
|
||||||
|
va_end(vl);
|
||||||
|
|
||||||
|
if (count < 0)
|
||||||
|
description[sizeof(description) - 1] = '\0';
|
||||||
|
}
|
||||||
else
|
else
|
||||||
_glfwErrorCode = error;
|
strcpy(description, getErrorString(code));
|
||||||
|
|
||||||
|
if (_glfw.initialized)
|
||||||
|
{
|
||||||
|
error = _glfwPlatformGetTls(&_glfw.errorSlot);
|
||||||
|
if (!error)
|
||||||
|
{
|
||||||
|
error = calloc(1, sizeof(_GLFWerror));
|
||||||
|
_glfwPlatformSetTls(&_glfw.errorSlot, error);
|
||||||
|
_glfwPlatformLockMutex(&_glfw.errorLock);
|
||||||
|
error->next = _glfw.errorListHead;
|
||||||
|
_glfw.errorListHead = error;
|
||||||
|
_glfwPlatformUnlockMutex(&_glfw.errorLock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
error = &_glfwMainThreadError;
|
||||||
|
|
||||||
|
error->code = code;
|
||||||
|
strcpy(error->description, description);
|
||||||
|
|
||||||
if (_glfwErrorCallback)
|
if (_glfwErrorCallback)
|
||||||
{
|
_glfwErrorCallback(code, description);
|
||||||
char buffer[8192];
|
|
||||||
const char* description;
|
|
||||||
|
|
||||||
if (format)
|
|
||||||
{
|
|
||||||
int count;
|
|
||||||
va_list vl;
|
|
||||||
|
|
||||||
va_start(vl, format);
|
|
||||||
count = vsnprintf(buffer, sizeof(buffer), format, vl);
|
|
||||||
va_end(vl);
|
|
||||||
|
|
||||||
if (count < 0)
|
|
||||||
buffer[sizeof(buffer) - 1] = '\0';
|
|
||||||
|
|
||||||
description = buffer;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
description = getErrorString(error);
|
|
||||||
|
|
||||||
_glfwErrorCallback(error, description);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -180,12 +197,14 @@ GLFWAPI int glfwInit(void)
|
|||||||
return GLFW_FALSE;
|
return GLFW_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_glfwPlatformCreateTls(&_glfw.error))
|
if (!_glfwPlatformCreateMutex(&_glfw.errorLock))
|
||||||
return GLFW_FALSE;
|
return GLFW_FALSE;
|
||||||
if (!_glfwPlatformCreateTls(&_glfw.context))
|
if (!_glfwPlatformCreateTls(&_glfw.errorSlot))
|
||||||
|
return GLFW_FALSE;
|
||||||
|
if (!_glfwPlatformCreateTls(&_glfw.contextSlot))
|
||||||
return GLFW_FALSE;
|
return GLFW_FALSE;
|
||||||
|
|
||||||
_glfwPlatformSetTls(&_glfw.error, (void*) (intptr_t) _glfwErrorCode);
|
_glfwPlatformSetTls(&_glfw.errorSlot, &_glfwMainThreadError);
|
||||||
|
|
||||||
_glfw.initialized = GLFW_TRUE;
|
_glfw.initialized = GLFW_TRUE;
|
||||||
_glfw.timer.offset = _glfwPlatformGetTimerValue();
|
_glfw.timer.offset = _glfwPlatformGetTimerValue();
|
||||||
@ -237,22 +256,28 @@ GLFWAPI const char* glfwGetVersionString(void)
|
|||||||
return _glfwPlatformGetVersionString();
|
return _glfwPlatformGetVersionString();
|
||||||
}
|
}
|
||||||
|
|
||||||
GLFWAPI int glfwGetError(void)
|
GLFWAPI int glfwGetError(const char** description)
|
||||||
{
|
{
|
||||||
int error;
|
_GLFWerror* error;
|
||||||
|
int code = GLFW_NO_ERROR;
|
||||||
|
|
||||||
|
if (description)
|
||||||
|
*description = NULL;
|
||||||
|
|
||||||
if (_glfw.initialized)
|
if (_glfw.initialized)
|
||||||
{
|
error = _glfwPlatformGetTls(&_glfw.errorSlot);
|
||||||
error = (int) (intptr_t) _glfwPlatformGetTls(&_glfw.error);
|
|
||||||
_glfwPlatformSetTls(&_glfw.error, (void*) (intptr_t) GLFW_NO_ERROR);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
|
error = &_glfwMainThreadError;
|
||||||
|
|
||||||
|
if (error)
|
||||||
{
|
{
|
||||||
error = _glfwErrorCode;
|
code = error->code;
|
||||||
_glfwErrorCode = GLFW_NO_ERROR;
|
error->code = GLFW_NO_ERROR;
|
||||||
|
if (description && code)
|
||||||
|
*description = error->description;
|
||||||
}
|
}
|
||||||
|
|
||||||
return error;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun)
|
GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun)
|
||||||
|
@ -55,6 +55,7 @@
|
|||||||
|
|
||||||
typedef int GLFWbool;
|
typedef int GLFWbool;
|
||||||
|
|
||||||
|
typedef struct _GLFWerror _GLFWerror;
|
||||||
typedef struct _GLFWinitconfig _GLFWinitconfig;
|
typedef struct _GLFWinitconfig _GLFWinitconfig;
|
||||||
typedef struct _GLFWwndconfig _GLFWwndconfig;
|
typedef struct _GLFWwndconfig _GLFWwndconfig;
|
||||||
typedef struct _GLFWctxconfig _GLFWctxconfig;
|
typedef struct _GLFWctxconfig _GLFWctxconfig;
|
||||||
@ -66,6 +67,7 @@ typedef struct _GLFWmonitor _GLFWmonitor;
|
|||||||
typedef struct _GLFWcursor _GLFWcursor;
|
typedef struct _GLFWcursor _GLFWcursor;
|
||||||
typedef struct _GLFWjoystick _GLFWjoystick;
|
typedef struct _GLFWjoystick _GLFWjoystick;
|
||||||
typedef struct _GLFWtls _GLFWtls;
|
typedef struct _GLFWtls _GLFWtls;
|
||||||
|
typedef struct _GLFWmutex _GLFWmutex;
|
||||||
|
|
||||||
typedef void (* _GLFWmakecontextcurrentfun)(_GLFWwindow*);
|
typedef void (* _GLFWmakecontextcurrentfun)(_GLFWwindow*);
|
||||||
typedef void (* _GLFWswapbuffersfun)(_GLFWwindow*);
|
typedef void (* _GLFWswapbuffersfun)(_GLFWwindow*);
|
||||||
@ -257,6 +259,13 @@ typedef void (APIENTRY * PFN_vkVoidFunction)(void);
|
|||||||
// Platform-independent structures
|
// Platform-independent structures
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
|
||||||
|
struct _GLFWerror
|
||||||
|
{
|
||||||
|
_GLFWerror* next;
|
||||||
|
int code;
|
||||||
|
char description[1024];
|
||||||
|
};
|
||||||
|
|
||||||
/*! @brief Initialization configuration.
|
/*! @brief Initialization configuration.
|
||||||
*
|
*
|
||||||
* Parameters relating to the initialization of the library.
|
* Parameters relating to the initialization of the library.
|
||||||
@ -490,6 +499,14 @@ struct _GLFWtls
|
|||||||
_GLFW_PLATFORM_TLS_STATE;
|
_GLFW_PLATFORM_TLS_STATE;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*! @brief Mutex structure.
|
||||||
|
*/
|
||||||
|
struct _GLFWmutex
|
||||||
|
{
|
||||||
|
// This is defined in the platform's tls.h
|
||||||
|
_GLFW_PLATFORM_MUTEX_STATE;
|
||||||
|
};
|
||||||
|
|
||||||
/*! @brief Library global data.
|
/*! @brief Library global data.
|
||||||
*/
|
*/
|
||||||
struct _GLFWlibrary
|
struct _GLFWlibrary
|
||||||
@ -504,8 +521,8 @@ struct _GLFWlibrary
|
|||||||
int refreshRate;
|
int refreshRate;
|
||||||
} hints;
|
} hints;
|
||||||
|
|
||||||
|
_GLFWerror* errorListHead;
|
||||||
_GLFWcursor* cursorListHead;
|
_GLFWcursor* cursorListHead;
|
||||||
|
|
||||||
_GLFWwindow* windowListHead;
|
_GLFWwindow* windowListHead;
|
||||||
|
|
||||||
_GLFWmonitor** monitors;
|
_GLFWmonitor** monitors;
|
||||||
@ -513,8 +530,9 @@ struct _GLFWlibrary
|
|||||||
|
|
||||||
_GLFWjoystick joysticks[GLFW_JOYSTICK_LAST + 1];
|
_GLFWjoystick joysticks[GLFW_JOYSTICK_LAST + 1];
|
||||||
|
|
||||||
_GLFWtls error;
|
_GLFWtls errorSlot;
|
||||||
_GLFWtls context;
|
_GLFWtls contextSlot;
|
||||||
|
_GLFWmutex errorLock;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint64_t offset;
|
uint64_t offset;
|
||||||
@ -651,7 +669,11 @@ GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls);
|
|||||||
void _glfwPlatformDestroyTls(_GLFWtls* tls);
|
void _glfwPlatformDestroyTls(_GLFWtls* tls);
|
||||||
void* _glfwPlatformGetTls(_GLFWtls* tls);
|
void* _glfwPlatformGetTls(_GLFWtls* tls);
|
||||||
void _glfwPlatformSetTls(_GLFWtls* tls, void* value);
|
void _glfwPlatformSetTls(_GLFWtls* tls, void* value);
|
||||||
GLFWbool _glfwPlatformIsValidTls(_GLFWtls* tls);
|
|
||||||
|
GLFWbool _glfwPlatformCreateMutex(_GLFWmutex* mutex);
|
||||||
|
void _glfwPlatformDestroyMutex(_GLFWmutex* mutex);
|
||||||
|
void _glfwPlatformLockMutex(_GLFWmutex* mutex);
|
||||||
|
void _glfwPlatformUnlockMutex(_GLFWmutex* mutex);
|
||||||
|
|
||||||
/*! @} */
|
/*! @} */
|
||||||
|
|
||||||
@ -798,15 +820,15 @@ void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement);
|
|||||||
void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window);
|
void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window);
|
||||||
|
|
||||||
/*! @brief Notifies shared code of an error.
|
/*! @brief Notifies shared code of an error.
|
||||||
* @param[in] error The error code most suitable for the error.
|
* @param[in] code The error code most suitable for the error.
|
||||||
* @param[in] format The `printf` style format string of the error
|
* @param[in] format The `printf` style format string of the error
|
||||||
* description.
|
* description.
|
||||||
* @ingroup event
|
* @ingroup event
|
||||||
*/
|
*/
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
void _glfwInputError(int error, const char* format, ...) __attribute__((format(printf, 2, 3)));
|
void _glfwInputError(int code, const char* format, ...) __attribute__((format(printf, 2, 3)));
|
||||||
#else
|
#else
|
||||||
void _glfwInputError(int error, const char* format, ...);
|
void _glfwInputError(int code, const char* format, ...);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*! @brief Notifies shared code of files or directories dropped on a window.
|
/*! @brief Notifies shared code of files or directories dropped on a window.
|
||||||
|
@ -34,7 +34,7 @@ static void makeContextCurrentNSGL(_GLFWwindow* window)
|
|||||||
else
|
else
|
||||||
[NSOpenGLContext clearCurrentContext];
|
[NSOpenGLContext clearCurrentContext];
|
||||||
|
|
||||||
_glfwPlatformSetTls(&_glfw.context, window);
|
_glfwPlatformSetTls(&_glfw.contextSlot, window);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void swapBuffersNSGL(_GLFWwindow* window)
|
static void swapBuffersNSGL(_GLFWwindow* window)
|
||||||
@ -45,7 +45,7 @@ static void swapBuffersNSGL(_GLFWwindow* window)
|
|||||||
|
|
||||||
static void swapIntervalNSGL(int interval)
|
static void swapIntervalNSGL(int interval)
|
||||||
{
|
{
|
||||||
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.context);
|
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||||
|
|
||||||
GLint sync = interval;
|
GLint sync = interval;
|
||||||
[window->context.nsgl.object setValues:&sync
|
[window->context.nsgl.object setValues:&sync
|
||||||
|
@ -63,7 +63,7 @@ static void makeContextCurrentOSMesa(_GLFWwindow* window)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_glfwPlatformSetTls(&_glfw.context, window);
|
_glfwPlatformSetTls(&_glfw.contextSlot, window);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GLFWglproc getProcAddressOSMesa(const char* procname)
|
static GLFWglproc getProcAddressOSMesa(const char* procname)
|
||||||
|
@ -69,8 +69,35 @@ void _glfwPlatformSetTls(_GLFWtls* tls, void* value)
|
|||||||
pthread_setspecific(tls->posix.key, value);
|
pthread_setspecific(tls->posix.key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLFWbool _glfwPlatformIsValidTls(_GLFWtls* tls)
|
GLFWbool _glfwPlatformCreateMutex(_GLFWmutex* mutex)
|
||||||
{
|
{
|
||||||
return tls->posix.allocated;
|
assert(mutex->posix.allocated == GLFW_FALSE);
|
||||||
|
|
||||||
|
if (pthread_mutex_init(&mutex->posix.handle, NULL) != 0)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR, "POSIX: Failed to create mutex");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mutex->posix.allocated = GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformDestroyMutex(_GLFWmutex* mutex)
|
||||||
|
{
|
||||||
|
if (mutex->posix.allocated)
|
||||||
|
pthread_mutex_destroy(&mutex->posix.handle);
|
||||||
|
memset(mutex, 0, sizeof(_GLFWmutex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformLockMutex(_GLFWmutex* mutex)
|
||||||
|
{
|
||||||
|
assert(mutex->posix.allocated == GLFW_TRUE);
|
||||||
|
pthread_mutex_lock(&mutex->posix.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformUnlockMutex(_GLFWmutex* mutex)
|
||||||
|
{
|
||||||
|
assert(mutex->posix.allocated == GLFW_TRUE);
|
||||||
|
pthread_mutex_unlock(&mutex->posix.handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,8 @@
|
|||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
#define _GLFW_PLATFORM_TLS_STATE _GLFWtlsPOSIX posix
|
#define _GLFW_PLATFORM_TLS_STATE _GLFWtlsPOSIX posix
|
||||||
|
#define _GLFW_PLATFORM_MUTEX_STATE _GLFWmutexPOSIX posix
|
||||||
|
|
||||||
|
|
||||||
// POSIX-specific thread local storage data
|
// POSIX-specific thread local storage data
|
||||||
@ -39,3 +40,12 @@ typedef struct _GLFWtlsPOSIX
|
|||||||
|
|
||||||
} _GLFWtlsPOSIX;
|
} _GLFWtlsPOSIX;
|
||||||
|
|
||||||
|
// POSIX-specific mutex data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWmutexPOSIX
|
||||||
|
{
|
||||||
|
GLFWbool allocated;
|
||||||
|
pthread_mutex_t handle;
|
||||||
|
|
||||||
|
} _GLFWmutexPOSIX;
|
||||||
|
|
||||||
|
@ -249,12 +249,12 @@ static void makeContextCurrentWGL(_GLFWwindow* window)
|
|||||||
if (window)
|
if (window)
|
||||||
{
|
{
|
||||||
if (wglMakeCurrent(window->context.wgl.dc, window->context.wgl.handle))
|
if (wglMakeCurrent(window->context.wgl.dc, window->context.wgl.handle))
|
||||||
_glfwPlatformSetTls(&_glfw.context, window);
|
_glfwPlatformSetTls(&_glfw.contextSlot, window);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||||
"WGL: Failed to make context current");
|
"WGL: Failed to make context current");
|
||||||
_glfwPlatformSetTls(&_glfw.context, NULL);
|
_glfwPlatformSetTls(&_glfw.contextSlot, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -265,7 +265,7 @@ static void makeContextCurrentWGL(_GLFWwindow* window)
|
|||||||
"WGL: Failed to clear current context");
|
"WGL: Failed to clear current context");
|
||||||
}
|
}
|
||||||
|
|
||||||
_glfwPlatformSetTls(&_glfw.context, NULL);
|
_glfwPlatformSetTls(&_glfw.contextSlot, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,7 +284,7 @@ static void swapBuffersWGL(_GLFWwindow* window)
|
|||||||
|
|
||||||
static void swapIntervalWGL(int interval)
|
static void swapIntervalWGL(int interval)
|
||||||
{
|
{
|
||||||
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.context);
|
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||||
|
|
||||||
window->context.wgl.interval = interval;
|
window->context.wgl.interval = interval;
|
||||||
|
|
||||||
|
@ -221,6 +221,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(
|
|||||||
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWin32 win32
|
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWin32 win32
|
||||||
#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorWin32 win32
|
#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorWin32 win32
|
||||||
#define _GLFW_PLATFORM_TLS_STATE _GLFWtlsWin32 win32
|
#define _GLFW_PLATFORM_TLS_STATE _GLFWtlsWin32 win32
|
||||||
|
#define _GLFW_PLATFORM_MUTEX_STATE _GLFWmutexWin32 win32
|
||||||
|
|
||||||
|
|
||||||
// Win32-specific per-window data
|
// Win32-specific per-window data
|
||||||
@ -334,6 +335,15 @@ typedef struct _GLFWtlsWin32
|
|||||||
|
|
||||||
} _GLFWtlsWin32;
|
} _GLFWtlsWin32;
|
||||||
|
|
||||||
|
// Win32-specific mutex data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWmutexWin32
|
||||||
|
{
|
||||||
|
GLFWbool allocated;
|
||||||
|
CRITICAL_SECTION section;
|
||||||
|
|
||||||
|
} _GLFWmutexWin32;
|
||||||
|
|
||||||
|
|
||||||
GLFWbool _glfwRegisterWindowClassWin32(void);
|
GLFWbool _glfwRegisterWindowClassWin32(void);
|
||||||
void _glfwUnregisterWindowClassWin32(void);
|
void _glfwUnregisterWindowClassWin32(void);
|
||||||
|
@ -69,8 +69,29 @@ void _glfwPlatformSetTls(_GLFWtls* tls, void* value)
|
|||||||
TlsSetValue(tls->win32.index, value);
|
TlsSetValue(tls->win32.index, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLFWbool _glfwPlatformIsValidTls(_GLFWtls* tls)
|
GLFWbool _glfwPlatformCreateMutex(_GLFWmutex* mutex)
|
||||||
{
|
{
|
||||||
return tls->win32.allocated;
|
assert(mutex->win32.allocated == GLFW_FALSE);
|
||||||
|
InitializeCriticalSection(&mutex->win32.section);
|
||||||
|
return mutex->win32.allocated = GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformDestroyMutex(_GLFWmutex* mutex)
|
||||||
|
{
|
||||||
|
if (mutex->win32.allocated)
|
||||||
|
DeleteCriticalSection(&mutex->win32.section);
|
||||||
|
memset(mutex, 0, sizeof(_GLFWmutex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformLockMutex(_GLFWmutex* mutex)
|
||||||
|
{
|
||||||
|
assert(mutex->win32.allocated == GLFW_TRUE);
|
||||||
|
EnterCriticalSection(&mutex->win32.section);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformUnlockMutex(_GLFWmutex* mutex)
|
||||||
|
{
|
||||||
|
assert(mutex->win32.allocated == GLFW_TRUE);
|
||||||
|
LeaveCriticalSection(&mutex->win32.section);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,7 +192,7 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
|
|||||||
window->denom = GLFW_DONT_CARE;
|
window->denom = GLFW_DONT_CARE;
|
||||||
|
|
||||||
// Save the currently current context so it can be restored later
|
// Save the currently current context so it can be restored later
|
||||||
previous = _glfwPlatformGetTls(&_glfw.context);
|
previous = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||||
if (ctxconfig.client != GLFW_NO_API)
|
if (ctxconfig.client != GLFW_NO_API)
|
||||||
glfwMakeContextCurrent(NULL);
|
glfwMakeContextCurrent(NULL);
|
||||||
|
|
||||||
@ -408,7 +408,7 @@ GLFWAPI void glfwDestroyWindow(GLFWwindow* handle)
|
|||||||
|
|
||||||
// The window's context must not be current on another thread when the
|
// The window's context must not be current on another thread when the
|
||||||
// window is destroyed
|
// window is destroyed
|
||||||
if (window == _glfwPlatformGetTls(&_glfw.context))
|
if (window == _glfwPlatformGetTls(&_glfw.contextSlot))
|
||||||
glfwMakeContextCurrent(NULL);
|
glfwMakeContextCurrent(NULL);
|
||||||
|
|
||||||
_glfwPlatformDestroyWindow(window);
|
_glfwPlatformDestroyWindow(window);
|
||||||
|
Loading…
Reference in New Issue
Block a user