0//========================================================================
1// GLFW 3.4 - www.glfw.org
2//------------------------------------------------------------------------
3// Copyright (c) 2002-2006 Marcus Geelnard
4// Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>
5//
6// This software is provided 'as-is', without any express or implied
7// warranty. In no event will the authors be held liable for any damages
8// arising from the use of this software.
9//
10// Permission is granted to anyone to use this software for any purpose,
11// including commercial applications, and to alter it and redistribute it
12// freely, subject to the following restrictions:
13//
14// 1. The origin of this software must not be misrepresented; you must not
15// claim that you wrote the original software. If you use this software
16// in a product, an acknowledgment in the product documentation would
17// be appreciated but is not required.
18//
19// 2. Altered source versions must be plainly marked as such, and must not
20// be misrepresented as being the original software.
21//
22// 3. This notice may not be removed or altered from any source
23// distribution.
24//
25//========================================================================
27#include "internal.h"
29#include <string.h>
30#include <stdlib.h>
31#include <stdio.h>
32#include <stdarg.h>
33#include <assert.h>
36// NOTE: The global variables below comprise all mutable global data in GLFW
37// Any other mutable global variable is a bug
39// This contains all mutable state shared between compilation units of GLFW
40//
41_GLFWlibrary _glfw = { GLFW_FALSE };
43// These are outside of _glfw so they can be used before initialization and
44// after termination without special handling when _glfw is cleared to zero
45//
46static _GLFWerror _glfwMainThreadError;
47static GLFWerrorfun _glfwErrorCallback;
48static GLFWallocator _glfwInitAllocator;
49static _GLFWinitconfig _glfwInitHints =
50{
51 .hatButtons = GLFW_TRUE,
52 .angleType = GLFW_ANGLE_PLATFORM_TYPE_NONE,
53 .platformID = GLFW_ANY_PLATFORM,
54 .vulkanLoader = NULL,
55 .ns =
56 {
57 .menubar = GLFW_TRUE,
58 .chdir = GLFW_TRUE
59 },
60 .x11 =
61 {
62 .xcbVulkanSurface = GLFW_TRUE,
63 },
64 .wl =
65 {
66 .libdecorMode = GLFW_WAYLAND_PREFER_LIBDECOR
67 },
68};
70// The allocation function used when no custom allocator is set
71//
72static void* defaultAllocate(size_t size, void* user)
73{
74 return malloc(size);
75}
77// The deallocation function used when no custom allocator is set
78//
79static void defaultDeallocate(void* block, void* user)
80{
81 free(block);
82}
84// The reallocation function used when no custom allocator is set
85//
86static void* defaultReallocate(void* block, size_t size, void* user)
87{
88 return realloc(block, size);
89}
91// Terminate the library
92//
93static void terminate(void)
94{
95 int i;
97 memset(&_glfw.callbacks, 0, sizeof(_glfw.callbacks));
99 while (_glfw.windowListHead)
100 glfwDestroyWindow((GLFWwindow*) _glfw.windowListHead);
102 while (_glfw.cursorListHead)
103 glfwDestroyCursor((GLFWcursor*) _glfw.cursorListHead);
105 for (i = 0; i < _glfw.monitorCount; i++)
106 {
107 _GLFWmonitor* monitor = _glfw.monitors[i];
108 if (monitor->originalRamp.size)
109 _glfw.platform.setGammaRamp(monitor, &monitor->originalRamp);
110 _glfwFreeMonitor(monitor);
111 }
113 _glfw_free(_glfw.monitors);
114 _glfw.monitors = NULL;
115 _glfw.monitorCount = 0;
117 _glfw_free(_glfw.mappings);
118 _glfw.mappings = NULL;
119 _glfw.mappingCount = 0;
121 _glfwTerminateVulkan();
122 _glfw.platform.terminateJoysticks();
123 _glfw.platform.terminate();
125 _glfw.initialized = GLFW_FALSE;
127 while (_glfw.errorListHead)
128 {
129 _GLFWerror* error = _glfw.errorListHead;
130 _glfw.errorListHead = error->next;
131 _glfw_free(error);
132 }
134 _glfwPlatformDestroyTls(&_glfw.contextSlot);
135 _glfwPlatformDestroyTls(&_glfw.errorSlot);
136 _glfwPlatformDestroyMutex(&_glfw.errorLock);
138 memset(&_glfw, 0, sizeof(_glfw));
139}
142//////////////////////////////////////////////////////////////////////////
143////// GLFW internal API //////
144//////////////////////////////////////////////////////////////////////////
146// Encode a Unicode code point to a UTF-8 stream
147// Based on cutef8 by Jeff Bezanson (Public Domain)
148//
149size_t _glfwEncodeUTF8(char* s, uint32_t codepoint)
150{
151 size_t count = 0;
153 if (codepoint < 0x80)
154 s[count++] = (char) codepoint;
155 else if (codepoint < 0x800)
156 {
157 s[count++] = (codepoint >> 6) | 0xc0;
158 s[count++] = (codepoint & 0x3f) | 0x80;
159 }
160 else if (codepoint < 0x10000)
161 {
162 s[count++] = (codepoint >> 12) | 0xe0;
163 s[count++] = ((codepoint >> 6) & 0x3f) | 0x80;
164 s[count++] = (codepoint & 0x3f) | 0x80;
165 }
166 else if (codepoint < 0x110000)
167 {
168 s[count++] = (codepoint >> 18) | 0xf0;
169 s[count++] = ((codepoint >> 12) & 0x3f) | 0x80;
170 s[count++] = ((codepoint >> 6) & 0x3f) | 0x80;
171 s[count++] = (codepoint & 0x3f) | 0x80;
172 }
174 return count;
175}
177// Splits and translates a text/uri-list into separate file paths
178// NOTE: This function destroys the provided string
179//
180char** _glfwParseUriList(char* text, int* count)
181{
182 const char* prefix = "file://";
183 char** paths = NULL;
184 char* line;
186 *count = 0;
188 while ((line = strtok(text, "\r\n")))
189 {
190 char* path;
192 text = NULL;
194 if (line[0] == '#')
195 continue;
197 if (strncmp(line, prefix, strlen(prefix)) == 0)
198 {
199 line += strlen(prefix);
200 // TODO: Validate hostname
201 while (*line != '/')
202 line++;
203 }
205 (*count)++;
207 path = _glfw_calloc(strlen(line) + 1, 1);
208 paths = _glfw_realloc(paths, *count * sizeof(char*));
209 paths[*count - 1] = path;
211 while (*line)
212 {
213 if (line[0] == '%' && line[1] && line[2])
214 {
215 const char digits[3] = { line[1], line[2], '\0' };
216 *path = (char) strtol(digits, NULL, 16);
217 line += 2;
218 }
219 else
220 *path = *line;
222 path++;
223 line++;
224 }
225 }
227 return paths;
228}
230char* _glfw_strdup(const char* source)
231{
232 const size_t length = strlen(source);
233 char* result = _glfw_calloc(length + 1, 1);
234 strcpy(result, source);
235 return result;
236}
238int _glfw_min(int a, int b)
239{
240 return a < b ? a : b;
241}
243int _glfw_max(int a, int b)
244{
245 return a > b ? a : b;
246}
248void* _glfw_calloc(size_t count, size_t size)
249{
250 if (count && size)
251 {
252 void* block;
254 if (count > SIZE_MAX / size)
255 {
256 _glfwInputError(GLFW_INVALID_VALUE, "Allocation size overflow");
257 return NULL;
258 }
260 block = _glfw.allocator.allocate(count * size, _glfw.allocator.user);
261 if (block)
262 return memset(block, 0, count * size);
263 else
264 {
265 _glfwInputError(GLFW_OUT_OF_MEMORY, NULL);
266 return NULL;
267 }
268 }
269 else
270 return NULL;
271}
273void* _glfw_realloc(void* block, size_t size)
274{
275 if (block && size)
276 {
277 void* resized = _glfw.allocator.reallocate(block, size, _glfw.allocator.user);
278 if (resized)
279 return resized;
280 else
281 {
282 _glfwInputError(GLFW_OUT_OF_MEMORY, NULL);
283 return NULL;
284 }
285 }
286 else if (block)
287 {
288 _glfw_free(block);
289 return NULL;
290 }
291 else
292 return _glfw_calloc(1, size);
293}
295void _glfw_free(void* block)
296{
297 if (block)
298 _glfw.allocator.deallocate(block, _glfw.allocator.user);
299}
302//////////////////////////////////////////////////////////////////////////
303////// GLFW event API //////
304//////////////////////////////////////////////////////////////////////////
306// Notifies shared code of an error
307//
308void _glfwInputError(int code, const char* format, ...)
309{
310 _GLFWerror* error;
311 char description[_GLFW_MESSAGE_SIZE];
313 if (format)
314 {
315 va_list vl;
317 va_start(vl, format);
318 vsnprintf(description, sizeof(description), format, vl);
319 va_end(vl);
321 description[sizeof(description) - 1] = '\0';
322 }
323 else
324 {
325 if (code == GLFW_NOT_INITIALIZED)
326 strcpy(description, "The GLFW library is not initialized");
327 else if (code == GLFW_NO_CURRENT_CONTEXT)
328 strcpy(description, "There is no current context");
329 else if (code == GLFW_INVALID_ENUM)
330 strcpy(description, "Invalid argument for enum parameter");
331 else if (code == GLFW_INVALID_VALUE)
332 strcpy(description, "Invalid value for parameter");
333 else if (code == GLFW_OUT_OF_MEMORY)
334 strcpy(description, "Out of memory");
335 else if (code == GLFW_API_UNAVAILABLE)
336 strcpy(description, "The requested API is unavailable");
337 else if (code == GLFW_VERSION_UNAVAILABLE)
338 strcpy(description, "The requested API version is unavailable");
339 else if (code == GLFW_PLATFORM_ERROR)
340 strcpy(description, "A platform-specific error occurred");
341 else if (code == GLFW_FORMAT_UNAVAILABLE)
342 strcpy(description, "The requested format is unavailable");
343 else if (code == GLFW_NO_WINDOW_CONTEXT)
344 strcpy(description, "The specified window has no context");
345 else if (code == GLFW_CURSOR_UNAVAILABLE)
346 strcpy(description, "The specified cursor shape is unavailable");
347 else if (code == GLFW_FEATURE_UNAVAILABLE)
348 strcpy(description, "The requested feature cannot be implemented for this platform");
349 else if (code == GLFW_FEATURE_UNIMPLEMENTED)
350 strcpy(description, "The requested feature has not yet been implemented for this platform");
351 else if (code == GLFW_PLATFORM_UNAVAILABLE)
352 strcpy(description, "The requested platform is unavailable");
353 else
354 strcpy(description, "ERROR: UNKNOWN GLFW ERROR");
355 }
357 if (_glfw.initialized)
358 {
359 error = _glfwPlatformGetTls(&_glfw.errorSlot);
360 if (!error)
361 {
362 error = _glfw_calloc(1, sizeof(_GLFWerror));
363 _glfwPlatformSetTls(&_glfw.errorSlot, error);
364 _glfwPlatformLockMutex(&_glfw.errorLock);
365 error->next = _glfw.errorListHead;
366 _glfw.errorListHead = error;
367 _glfwPlatformUnlockMutex(&_glfw.errorLock);
368 }
369 }
370 else
371 error = &_glfwMainThreadError;
373 error->code = code;
374 strcpy(error->description, description);
376 if (_glfwErrorCallback)
377 _glfwErrorCallback(code, description);
378}
381//////////////////////////////////////////////////////////////////////////
382////// GLFW public API //////
383//////////////////////////////////////////////////////////////////////////
385GLFWAPI int glfwInit(void)
386{
387 if (_glfw.initialized)
388 return GLFW_TRUE;
390 memset(&_glfw, 0, sizeof(_glfw));
391 _glfw.hints.init = _glfwInitHints;
393 _glfw.allocator = _glfwInitAllocator;
394 if (!_glfw.allocator.allocate)
395 {
396 _glfw.allocator.allocate = defaultAllocate;
397 _glfw.allocator.reallocate = defaultReallocate;
398 _glfw.allocator.deallocate = defaultDeallocate;
399 }
401 if (!_glfwSelectPlatform(_glfw.hints.init.platformID, &_glfw.platform))
402 return GLFW_FALSE;
404 if (!_glfw.platform.init())
405 {
406 terminate();
407 return GLFW_FALSE;
408 }
410 if (!_glfwPlatformCreateMutex(&_glfw.errorLock) ||
411 !_glfwPlatformCreateTls(&_glfw.errorSlot) ||
412 !_glfwPlatformCreateTls(&_glfw.contextSlot))
413 {
414 terminate();
415 return GLFW_FALSE;
416 }
418 _glfwPlatformSetTls(&_glfw.errorSlot, &_glfwMainThreadError);
420 _glfwInitGamepadMappings();
422 _glfwPlatformInitTimer();
423 _glfw.timer.offset = _glfwPlatformGetTimerValue();
425 _glfw.initialized = GLFW_TRUE;
427 glfwDefaultWindowHints();
428 return GLFW_TRUE;
429}
431GLFWAPI void glfwTerminate(void)
432{
433 if (!_glfw.initialized)
434 return;
436 terminate();
437}
439GLFWAPI void glfwInitHint(int hint, int value)
440{
441 switch (hint)
442 {
443 case GLFW_JOYSTICK_HAT_BUTTONS:
444 _glfwInitHints.hatButtons = value;
445 return;
446 case GLFW_ANGLE_PLATFORM_TYPE:
447 _glfwInitHints.angleType = value;
448 return;
449 case GLFW_PLATFORM:
450 _glfwInitHints.platformID = value;
451 return;
452 case GLFW_COCOA_CHDIR_RESOURCES:
453 _glfwInitHints.ns.chdir = value;
454 return;
455 case GLFW_COCOA_MENUBAR:
456 _glfwInitHints.ns.menubar = value;
457 return;
458 case GLFW_X11_XCB_VULKAN_SURFACE:
459 _glfwInitHints.x11.xcbVulkanSurface = value;
460 return;
461 case GLFW_WAYLAND_LIBDECOR:
462 _glfwInitHints.wl.libdecorMode = value;
463 return;
464 }
466 _glfwInputError(GLFW_INVALID_ENUM,
467 "Invalid init hint 0x%08X", hint);
468}
470GLFWAPI void glfwInitAllocator(const GLFWallocator* allocator)
471{
472 if (allocator)
473 {
474 if (allocator->allocate && allocator->reallocate && allocator->deallocate)
475 _glfwInitAllocator = *allocator;
476 else
477 _glfwInputError(GLFW_INVALID_VALUE, "Missing function in allocator");
478 }
479 else
480 memset(&_glfwInitAllocator, 0, sizeof(GLFWallocator));
481}
483GLFWAPI void glfwInitVulkanLoader(PFN_vkGetInstanceProcAddr loader)
484{
485 _glfwInitHints.vulkanLoader = loader;
486}
488GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev)
489{
490 if (major != NULL)
491 *major = GLFW_VERSION_MAJOR;
492 if (minor != NULL)
493 *minor = GLFW_VERSION_MINOR;
494 if (rev != NULL)
495 *rev = GLFW_VERSION_REVISION;
496}
498GLFWAPI int glfwGetError(const char** description)
499{
500 _GLFWerror* error;
501 int code = GLFW_NO_ERROR;
503 if (description)
504 *description = NULL;
506 if (_glfw.initialized)
507 error = _glfwPlatformGetTls(&_glfw.errorSlot);
508 else
509 error = &_glfwMainThreadError;
511 if (error)
512 {
513 code = error->code;
514 error->code = GLFW_NO_ERROR;
515 if (description && code)
516 *description = error->description;
517 }
519 return code;
520}
522GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun)
523{
524 _GLFW_SWAP(GLFWerrorfun, _glfwErrorCallback, cbfun);
525 return cbfun;
526}
index : raylib-jai
Bindings from https://solarium.technology