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