init.cc (8802B)
1 //======================================================================== 2 // GLFW 3.3 - www.glfw.org 3 //------------------------------------------------------------------------ 4 // Copyright (c) 2002-2006 Marcus Geelnard 5 // Copyright (c) 2006-2016 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 28 #include "internal.h" 29 #include "mappings.h" 30 31 #include <string.h> 32 #include <stdlib.h> 33 #include <stdio.h> 34 #include <stdarg.h> 35 #include <assert.h> 36 37 38 // The global variables below comprise all global data in GLFW. 39 // Any other global variable is a bug. 40 41 // Global state shared between compilation units of GLFW 42 // 43 _GLFWlibrary _glfw = { GLFW_FALSE }; 44 45 // These are outside of _glfw so they can be used before initialization and 46 // after termination 47 // 48 static _GLFWerror _glfwMainThreadError; 49 static GLFWerrorfun _glfwErrorCallback; 50 static _GLFWinitconfig _glfwInitHints = 51 { 52 GLFW_TRUE, // hat buttons 53 { 54 GLFW_TRUE, // macOS menu bar 55 GLFW_TRUE // macOS bundle chdir 56 }, 57 { 58 "", // X11 WM_CLASS name 59 "" // X11 WM_CLASS class 60 } 61 }; 62 63 // Returns a generic string representation of the specified error 64 // 65 static const char* getErrorString(int code) 66 { 67 switch (code) 68 { 69 case GLFW_NOT_INITIALIZED: 70 return "The GLFW library is not initialized"; 71 case GLFW_NO_CURRENT_CONTEXT: 72 return "There is no current context"; 73 case GLFW_INVALID_ENUM: 74 return "Invalid argument for enum parameter"; 75 case GLFW_INVALID_VALUE: 76 return "Invalid value for parameter"; 77 case GLFW_OUT_OF_MEMORY: 78 return "Out of memory"; 79 case GLFW_API_UNAVAILABLE: 80 return "The requested API is unavailable"; 81 case GLFW_VERSION_UNAVAILABLE: 82 return "The requested API version is unavailable"; 83 case GLFW_PLATFORM_ERROR: 84 return "An undocumented platform-specific error occurred"; 85 case GLFW_FORMAT_UNAVAILABLE: 86 return "The requested format is unavailable"; 87 case GLFW_NO_WINDOW_CONTEXT: 88 return "The specified window has no context"; 89 default: 90 return "ERROR: UNKNOWN GLFW ERROR"; 91 } 92 } 93 94 // Terminate the library 95 // 96 static void terminate(void) 97 { 98 int i; 99 100 memset(&_glfw.callbacks, 0, sizeof(_glfw.callbacks)); 101 102 while (_glfw.windowListHead) 103 glfwDestroyWindow((GLFWwindow*) _glfw.windowListHead); 104 105 while (_glfw.cursorListHead) 106 glfwDestroyCursor((GLFWcursor*) _glfw.cursorListHead); 107 108 for (i = 0; i < _glfw.monitorCount; i++) 109 { 110 _GLFWmonitor* monitor = _glfw.monitors[i]; 111 if (monitor->originalRamp.size) 112 _glfwPlatformSetGammaRamp(monitor, &monitor->originalRamp); 113 _glfwFreeMonitor(monitor); 114 } 115 116 free(_glfw.monitors); 117 _glfw.monitors = NULL; 118 _glfw.monitorCount = 0; 119 120 free(_glfw.mappings); 121 _glfw.mappings = NULL; 122 _glfw.mappingCount = 0; 123 124 _glfwTerminateVulkan(); 125 _glfwPlatformTerminate(); 126 127 _glfw.initialized = GLFW_FALSE; 128 129 while (_glfw.errorListHead) 130 { 131 _GLFWerror* error = _glfw.errorListHead; 132 _glfw.errorListHead = error->next; 133 free(error); 134 } 135 136 _glfwPlatformDestroyTls(&_glfw.contextSlot); 137 _glfwPlatformDestroyTls(&_glfw.errorSlot); 138 _glfwPlatformDestroyMutex(&_glfw.errorLock); 139 140 memset(&_glfw, 0, sizeof(_glfw)); 141 } 142 143 144 ////////////////////////////////////////////////////////////////////////// 145 ////// GLFW event API ////// 146 ////////////////////////////////////////////////////////////////////////// 147 148 void _glfwInputError(int code, const char* format, ...) 149 { 150 _GLFWerror* error; 151 char description[_GLFW_MESSAGE_SIZE]; 152 153 if (format) 154 { 155 int count; 156 va_list vl; 157 158 va_start(vl, format); 159 count = vsnprintf(description, sizeof(description), format, vl); 160 va_end(vl); 161 162 if (count < 0) 163 description[sizeof(description) - 1] = '\0'; 164 } 165 else 166 strcpy(description, getErrorString(code)); 167 168 if (_glfw.initialized) 169 { 170 error = _glfwPlatformGetTls(&_glfw.errorSlot); 171 if (!error) 172 { 173 error = calloc(1, sizeof(_GLFWerror)); 174 _glfwPlatformSetTls(&_glfw.errorSlot, error); 175 _glfwPlatformLockMutex(&_glfw.errorLock); 176 error->next = _glfw.errorListHead; 177 _glfw.errorListHead = error; 178 _glfwPlatformUnlockMutex(&_glfw.errorLock); 179 } 180 } 181 else 182 error = &_glfwMainThreadError; 183 184 error->code = code; 185 strcpy(error->description, description); 186 187 if (_glfwErrorCallback) 188 _glfwErrorCallback(code, description); 189 } 190 191 192 ////////////////////////////////////////////////////////////////////////// 193 ////// GLFW public API ////// 194 ////////////////////////////////////////////////////////////////////////// 195 196 GLFWAPI int glfwInit(void) 197 { 198 if (_glfw.initialized) 199 return GLFW_TRUE; 200 201 memset(&_glfw, 0, sizeof(_glfw)); 202 _glfw.hints.init = _glfwInitHints; 203 204 if (!_glfwPlatformInit()) 205 { 206 terminate(); 207 return GLFW_FALSE; 208 } 209 210 if (!_glfwPlatformCreateMutex(&_glfw.errorLock)) 211 return GLFW_FALSE; 212 if (!_glfwPlatformCreateTls(&_glfw.errorSlot)) 213 return GLFW_FALSE; 214 if (!_glfwPlatformCreateTls(&_glfw.contextSlot)) 215 return GLFW_FALSE; 216 217 _glfwPlatformSetTls(&_glfw.errorSlot, &_glfwMainThreadError); 218 219 _glfw.initialized = GLFW_TRUE; 220 _glfw.timer.offset = _glfwPlatformGetTimerValue(); 221 222 glfwDefaultWindowHints(); 223 glfwUpdateGamepadMappings(_glfwDefaultMappings); 224 225 return GLFW_TRUE; 226 } 227 228 GLFWAPI void glfwTerminate(void) 229 { 230 if (!_glfw.initialized) 231 return; 232 233 terminate(); 234 } 235 236 GLFWAPI void glfwInitHint(int hint, int value) 237 { 238 switch (hint) 239 { 240 case GLFW_JOYSTICK_HAT_BUTTONS: 241 _glfwInitHints.hatButtons = value; 242 return; 243 case GLFW_COCOA_CHDIR_RESOURCES: 244 _glfwInitHints.ns.chdir = value; 245 return; 246 case GLFW_COCOA_MENUBAR: 247 _glfwInitHints.ns.menubar = value; 248 return; 249 } 250 251 _glfwInputError(GLFW_INVALID_ENUM, 252 "Invalid integer type init hint 0x%08X", hint); 253 } 254 255 GLFWAPI void glfwInitHintString(int hint, const char* value) 256 { 257 assert(value != NULL); 258 259 switch (hint) 260 { 261 case GLFW_X11_WM_CLASS_NAME: 262 strncpy(_glfwInitHints.x11.className, value, 263 sizeof(_glfwInitHints.x11.className) - 1); 264 break; 265 case GLFW_X11_WM_CLASS_CLASS: 266 strncpy(_glfwInitHints.x11.classClass, value, 267 sizeof(_glfwInitHints.x11.classClass) - 1); 268 break; 269 } 270 271 _glfwInputError(GLFW_INVALID_ENUM, 272 "Invalid string type init hint 0x%08X", hint); 273 } 274 275 GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev) 276 { 277 if (major != NULL) 278 *major = GLFW_VERSION_MAJOR; 279 if (minor != NULL) 280 *minor = GLFW_VERSION_MINOR; 281 if (rev != NULL) 282 *rev = GLFW_VERSION_REVISION; 283 } 284 285 GLFWAPI const char* glfwGetVersionString(void) 286 { 287 return _glfwPlatformGetVersionString(); 288 } 289 290 GLFWAPI int glfwGetError(const char** description) 291 { 292 _GLFWerror* error; 293 int code = GLFW_NO_ERROR; 294 295 if (description) 296 *description = NULL; 297 298 if (_glfw.initialized) 299 error = _glfwPlatformGetTls(&_glfw.errorSlot); 300 else 301 error = &_glfwMainThreadError; 302 303 if (error) 304 { 305 code = error->code; 306 error->code = GLFW_NO_ERROR; 307 if (description && code) 308 *description = error->description; 309 } 310 311 return code; 312 } 313 314 GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun) 315 { 316 _GLFW_SWAP_POINTERS(_glfwErrorCallback, cbfun); 317 return cbfun; 318 } 319