init.c (9485B)
1 //======================================================================== 2 // GLFW 3.4 - www.glfw.org 3 //------------------------------------------------------------------------ 4 // Copyright (c) 2002-2006 Marcus Geelnard 5 // Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org> 6 // 7 // This software is provided 'as-is', without any express or implied 8 // warranty. In no event will the authors be held liable for any damages 9 // arising from the use of this software. 10 // 11 // Permission is granted to anyone to use this software for any purpose, 12 // including commercial applications, and to alter it and redistribute it 13 // freely, subject to the following restrictions: 14 // 15 // 1. The origin of this software must not be misrepresented; you must not 16 // claim that you wrote the original software. If you use this software 17 // in a product, an acknowledgment in the product documentation would 18 // be appreciated but is not required. 19 // 20 // 2. Altered source versions must be plainly marked as such, and must not 21 // be misrepresented as being the original software. 22 // 23 // 3. This notice may not be removed or altered from any source 24 // distribution. 25 // 26 //======================================================================== 27 // Please use C89 style variable declarations in this file because VS 2010 28 //======================================================================== 29 30 #include "internal.h" 31 #include "mappings.h" 32 33 #include <string.h> 34 #include <stdlib.h> 35 #include <stdio.h> 36 #include <stdarg.h> 37 #include <assert.h> 38 39 40 // The global variables below comprise all mutable global data in GLFW 41 // 42 // Any other global variable is a bug 43 44 // Global state shared between compilation units of GLFW 45 // 46 _GLFWlibrary _glfw = { GLFW_FALSE }; 47 48 // These are outside of _glfw so they can be used before initialization and 49 // after termination 50 // 51 static _GLFWerror _glfwMainThreadError; 52 static GLFWerrorfun _glfwErrorCallback; 53 static _GLFWinitconfig _glfwInitHints = 54 { 55 GLFW_TRUE, // hat buttons 56 { 57 GLFW_TRUE, // macOS menu bar 58 GLFW_TRUE // macOS bundle chdir 59 } 60 }; 61 62 // Terminate the library 63 // 64 static void _glfw_terminate(void) 65 { 66 int i; 67 68 memset(&_glfw.callbacks, 0, sizeof(_glfw.callbacks)); 69 70 while (_glfw.windowListHead) 71 glfwDestroyWindow((GLFWwindow*) _glfw.windowListHead); 72 73 while (_glfw.cursorListHead) 74 glfwDestroyCursor((GLFWcursor*) _glfw.cursorListHead); 75 76 for (i = 0; i < _glfw.monitorCount; i++) 77 { 78 _GLFWmonitor* monitor = _glfw.monitors[i]; 79 if (monitor->originalRamp.size) 80 _glfwPlatformSetGammaRamp(monitor, &monitor->originalRamp); 81 _glfwFreeMonitor(monitor); 82 } 83 84 free(_glfw.monitors); 85 _glfw.monitors = NULL; 86 _glfw.monitorCount = 0; 87 88 free(_glfw.mappings); 89 _glfw.mappings = NULL; 90 _glfw.mappingCount = 0; 91 92 _glfwTerminateVulkan(); 93 _glfwPlatformTerminate(); 94 95 _glfw.initialized = GLFW_FALSE; 96 97 while (_glfw.errorListHead) 98 { 99 _GLFWerror* error = _glfw.errorListHead; 100 _glfw.errorListHead = error->next; 101 free(error); 102 } 103 104 _glfwPlatformDestroyTls(&_glfw.contextSlot); 105 _glfwPlatformDestroyTls(&_glfw.errorSlot); 106 _glfwPlatformDestroyMutex(&_glfw.errorLock); 107 108 memset(&_glfw, 0, sizeof(_glfw)); 109 } 110 111 112 ////////////////////////////////////////////////////////////////////////// 113 ////// GLFW internal API ////// 114 ////////////////////////////////////////////////////////////////////////// 115 116 char* _glfw_strdup(const char* source) 117 { 118 const size_t length = strlen(source); 119 char* result = (char*)calloc(length + 1, 1); 120 strcpy(result, source); 121 return result; 122 } 123 124 float _glfw_fminf(float a, float b) 125 { 126 if (a != a) 127 return b; 128 else if (b != b) 129 return a; 130 else if (a < b) 131 return a; 132 else 133 return b; 134 } 135 136 float _glfw_fmaxf(float a, float b) 137 { 138 if (a != a) 139 return b; 140 else if (b != b) 141 return a; 142 else if (a > b) 143 return a; 144 else 145 return b; 146 } 147 148 149 ////////////////////////////////////////////////////////////////////////// 150 ////// GLFW event API ////// 151 ////////////////////////////////////////////////////////////////////////// 152 153 // Notifies shared code of an error 154 // 155 void _glfwInputError(int code, const char* format, ...) 156 { 157 _GLFWerror* error; 158 char description[_GLFW_MESSAGE_SIZE]; 159 160 if (format) 161 { 162 va_list vl; 163 164 va_start(vl, format); 165 vsnprintf(description, sizeof(description), format, vl); 166 va_end(vl); 167 168 description[sizeof(description) - 1] = '\0'; 169 } 170 else 171 { 172 if (code == GLFW_NOT_INITIALIZED) 173 strcpy(description, "The GLFW library is not initialized"); 174 else if (code == GLFW_NO_CURRENT_CONTEXT) 175 strcpy(description, "There is no current context"); 176 else if (code == GLFW_INVALID_ENUM) 177 strcpy(description, "Invalid argument for enum parameter"); 178 else if (code == GLFW_INVALID_VALUE) 179 strcpy(description, "Invalid value for parameter"); 180 else if (code == GLFW_OUT_OF_MEMORY) 181 strcpy(description, "Out of memory"); 182 else if (code == GLFW_API_UNAVAILABLE) 183 strcpy(description, "The requested API is unavailable"); 184 else if (code == GLFW_VERSION_UNAVAILABLE) 185 strcpy(description, "The requested API version is unavailable"); 186 else if (code == GLFW_PLATFORM_ERROR) 187 strcpy(description, "A platform-specific error occurred"); 188 else if (code == GLFW_FORMAT_UNAVAILABLE) 189 strcpy(description, "The requested format is unavailable"); 190 else if (code == GLFW_NO_WINDOW_CONTEXT) 191 strcpy(description, "The specified window has no context"); 192 else if (code == GLFW_CURSOR_UNAVAILABLE) 193 strcpy(description, "The specified cursor shape is unavailable"); 194 else 195 strcpy(description, "ERROR: UNKNOWN GLFW ERROR"); 196 } 197 198 if (_glfw.initialized) 199 { 200 error = (_GLFWerror*)_glfwPlatformGetTls(&_glfw.errorSlot); 201 if (!error) 202 { 203 error = (_GLFWerror*)calloc(1, sizeof(_GLFWerror)); 204 _glfwPlatformSetTls(&_glfw.errorSlot, error); 205 _glfwPlatformLockMutex(&_glfw.errorLock); 206 error->next = _glfw.errorListHead; 207 _glfw.errorListHead = error; 208 _glfwPlatformUnlockMutex(&_glfw.errorLock); 209 } 210 } 211 else 212 error = &_glfwMainThreadError; 213 214 error->code = code; 215 strcpy(error->description, description); 216 217 if (_glfwErrorCallback) 218 _glfwErrorCallback(code, description); 219 } 220 221 222 ////////////////////////////////////////////////////////////////////////// 223 ////// GLFW public API ////// 224 ////////////////////////////////////////////////////////////////////////// 225 226 GLFWAPI int glfwInit(void) 227 { 228 if (_glfw.initialized) 229 return GLFW_TRUE; 230 231 memset(&_glfw, 0, sizeof(_glfw)); 232 _glfw.hints.init = _glfwInitHints; 233 234 if (!_glfwPlatformInit()) 235 { 236 _glfw_terminate(); 237 return GLFW_FALSE; 238 } 239 240 if (!_glfwPlatformCreateMutex(&_glfw.errorLock) || 241 !_glfwPlatformCreateTls(&_glfw.errorSlot) || 242 !_glfwPlatformCreateTls(&_glfw.contextSlot)) 243 { 244 _glfw_terminate(); 245 return GLFW_FALSE; 246 } 247 248 _glfwPlatformSetTls(&_glfw.errorSlot, &_glfwMainThreadError); 249 250 _glfw.initialized = GLFW_TRUE; 251 _glfw.timer.offset = _glfwPlatformGetTimerValue(); 252 253 glfwDefaultWindowHints(); 254 255 { 256 int i; 257 258 for (i = 0; _glfwDefaultMappings[i]; i++) 259 { 260 if (!glfwUpdateGamepadMappings(_glfwDefaultMappings[i])) 261 { 262 _glfw_terminate(); 263 return GLFW_FALSE; 264 } 265 } 266 } 267 268 return GLFW_TRUE; 269 } 270 271 GLFWAPI void glfwTerminate(void) 272 { 273 if (!_glfw.initialized) 274 return; 275 276 _glfw_terminate(); 277 } 278 279 GLFWAPI void glfwInitHint(int hint, int value) 280 { 281 switch (hint) 282 { 283 case GLFW_JOYSTICK_HAT_BUTTONS: 284 _glfwInitHints.hatButtons = value; 285 return; 286 case GLFW_COCOA_CHDIR_RESOURCES: 287 _glfwInitHints.ns.chdir = value; 288 return; 289 case GLFW_COCOA_MENUBAR: 290 _glfwInitHints.ns.menubar = value; 291 return; 292 } 293 294 _glfwInputError(GLFW_INVALID_ENUM, 295 "Invalid init hint 0x%08X", hint); 296 } 297 298 GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev) 299 { 300 if (major != NULL) 301 *major = GLFW_VERSION_MAJOR; 302 if (minor != NULL) 303 *minor = GLFW_VERSION_MINOR; 304 if (rev != NULL) 305 *rev = GLFW_VERSION_REVISION; 306 } 307 308 GLFWAPI const char* glfwGetVersionString(void) 309 { 310 return _glfwPlatformGetVersionString(); 311 } 312 313 GLFWAPI int glfwGetError(const char** description) 314 { 315 _GLFWerror* error; 316 int code = GLFW_NO_ERROR; 317 318 if (description) 319 *description = NULL; 320 321 if (_glfw.initialized) 322 error = (_GLFWerror*)_glfwPlatformGetTls(&_glfw.errorSlot); 323 else 324 error = &_glfwMainThreadError; 325 326 if (error) 327 { 328 code = error->code; 329 error->code = GLFW_NO_ERROR; 330 if (description && code) 331 *description = error->description; 332 } 333 334 return code; 335 } 336 337 GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun) 338 { 339 _GLFW_SWAP_POINTERS(GLFWerrorfun, _glfwErrorCallback, cbfun); 340 return cbfun; 341 } 342