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