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