Logo

index : raylib-jai

Bindings from https://solarium.technology

  • summary
  • about
  • tree
  • log
  • branches
<< path: root/public/raylib-jai.git/html/Raylib/raylib/src/platforms/rcore_desktop_glfw.c blob: 9b360771f89c248a6d9fc6dfeee16c12a2917386 [raw] [clear marker]

        
0/**********************************************************************************************
1*
2* rcore_desktop_glfw - Functions to manage window, graphics device and inputs
3*
4* PLATFORM: DESKTOP: GLFW
5* - Windows (Win32, Win64)
6* - Linux (X11/Wayland desktop mode)
7* - FreeBSD, OpenBSD, NetBSD, DragonFly (X11 desktop)
8* - OSX/macOS (x64, arm64)
9*
10* LIMITATIONS:
11* - Limitation 01
12* - Limitation 02
13*
14* POSSIBLE IMPROVEMENTS:
15* - Improvement 01
16* - Improvement 02
17*
18* ADDITIONAL NOTES:
19* - TRACELOG() function is located in raylib [utils] module
20*
21* CONFIGURATION:
22* #define RCORE_PLATFORM_CUSTOM_FLAG
23* Custom flag for rcore on target platform -not used-
24*
25* DEPENDENCIES:
26* - rglfw: Manage graphic device, OpenGL context and inputs (Windows, Linux, OSX/macOS, FreeBSD...)
27* - gestures: Gestures system for touch-ready devices (or simulated from mouse inputs)
28*
29*
30* LICENSE: zlib/libpng
31*
32* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) and contributors
33*
34* This software is provided "as-is", without any express or implied warranty. In no event
35* will the authors be held liable for any damages arising from the use of this software.
36*
37* Permission is granted to anyone to use this software for any purpose, including commercial
38* applications, and to alter it and redistribute it freely, subject to the following restrictions:
39*
40* 1. The origin of this software must not be misrepresented; you must not claim that you
41* wrote the original software. If you use this software in a product, an acknowledgment
42* in the product documentation would be appreciated but is not required.
43*
44* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
45* as being the original software.
46*
47* 3. This notice may not be removed or altered from any source distribution.
48*
49**********************************************************************************************/
50
51#define GLFW_INCLUDE_NONE // Disable the standard OpenGL header inclusion on GLFW3
52 // NOTE: Already provided by rlgl implementation (on glad.h)
53#include "GLFW/glfw3.h" // GLFW3 library: Windows, OpenGL context and Input management
54 // NOTE: GLFW3 already includes gl.h (OpenGL) headers
55
56// Support retrieving native window handlers
57#if defined(_WIN32)
58 #if !defined(HWND) && !defined(_MSVC_LANG)
59 #define HWND void*
60 #elif !defined(HWND) && defined(_MSVC_LANG)
61 typedef struct HWND__ *HWND;
62 #endif
63
64 #include "../external/win32_clipboard.h" // Clipboard image copy-paste
65
66 #define GLFW_EXPOSE_NATIVE_WIN32
67 #define GLFW_NATIVE_INCLUDE_NONE // To avoid some symbols re-definition in windows.h
68 #include "GLFW/glfw3native.h"
69
70 #if defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP)
71 // NOTE: Those functions require linking with winmm library
72 //#pragma warning(disable: 4273)
73 __declspec(dllimport) unsigned int __stdcall timeEndPeriod(unsigned int uPeriod);
74 //#pragma warning(default: 4273)
75 #endif
76#endif
77#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__)
78 #include <sys/time.h> // Required for: timespec, nanosleep(), select() - POSIX
79
80 #if defined(_GLFW_X11) || defined(_GLFW_WAYLAND)
81 // Set appropriate expose macros based on available backends
82 #if defined(_GLFW_X11)
83 #define GLFW_EXPOSE_NATIVE_X11
84 #define Font X11Font // Hack to fix 'Font' name collision
85 // The definition and references to the X11 Font type will be replaced by 'X11Font'
86 // Works as long as the current file consistently references any X11 Font as X11Font
87 // Since it is never referenced (as of writing), this does not pose an issue
88 #endif
89
90 #if defined(_GLFW_WAYLAND)
91 #define GLFW_EXPOSE_NATIVE_WAYLAND
92 #endif
93
94 #include "GLFW/glfw3native.h" // Include native header only once, regardless of how many backends are defined
95 // Required for: glfwGetX11Window() and glfwGetWaylandWindow()
96 #if defined(_GLFW_X11) // Clean up X11-specific hacks
97 #undef Font // Revert hack and allow normal raylib Font usage
98 #endif
99 #endif
100#endif
101#if defined(__APPLE__)
102 #include <unistd.h> // Required for: usleep()
103
104 //#define GLFW_EXPOSE_NATIVE_COCOA // WARNING: Fails due to type redefinition
105 void *glfwGetCocoaWindow(GLFWwindow* handle);
106 #include "GLFW/glfw3native.h" // Required for: glfwGetCocoaWindow()
107#endif
108
109#include <stddef.h> // Required for: size_t
110
111//----------------------------------------------------------------------------------
112// Types and Structures Definition
113//----------------------------------------------------------------------------------
114typedef struct {
115 GLFWwindow *handle; // GLFW window handle (graphic device)
116} PlatformData;
117
118//----------------------------------------------------------------------------------
119// Global Variables Definition
120//----------------------------------------------------------------------------------
121extern CoreData CORE; // Global CORE state context
122
123static PlatformData platform = { 0 }; // Platform specific data
124
125//----------------------------------------------------------------------------------
126// Module Internal Functions Declaration
127//----------------------------------------------------------------------------------
128int InitPlatform(void); // Initialize platform (graphics, inputs and more)
129void ClosePlatform(void); // Close platform
130
131// Error callback event
132static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error
133
134// Window callbacks events
135static void WindowSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized
136static void FramebufferSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 FramebufferSize Callback, runs when window is resized
137static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley); // GLFW3 Window Content Scale Callback, runs when window changes scale
138static void WindowPosCallback(GLFWwindow *window, int x, int y); // GLFW3 WindowPos Callback, runs when window is moved
139static void WindowIconifyCallback(GLFWwindow *window, int iconified); // GLFW3 WindowIconify Callback, runs when window is minimized/restored
140static void WindowMaximizeCallback(GLFWwindow *window, int maximized); // GLFW3 Window Maximize Callback, runs when window is maximized
141static void WindowFocusCallback(GLFWwindow *window, int focused); // GLFW3 WindowFocus Callback, runs when window get/lose focus
142static void WindowDropCallback(GLFWwindow *window, int count, const char **paths); // GLFW3 Window Drop Callback, runs when drop files into window
143
144// Input callbacks events
145static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods); // GLFW3 Keyboard Callback, runs on key pressed
146static void CharCallback(GLFWwindow *window, unsigned int codepoint); // GLFW3 Char Callback, runs on key pressed (get codepoint value)
147static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods); // GLFW3 Mouse Button Callback, runs on mouse button pressed
148static void MouseCursorPosCallback(GLFWwindow *window, double x, double y); // GLFW3 Cursor Position Callback, runs on mouse move
149static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset); // GLFW3 Scrolling Callback, runs on mouse wheel
150static void CursorEnterCallback(GLFWwindow *window, int enter); // GLFW3 Cursor Enter Callback, cursor enters client area
151static void JoystickCallback(int jid, int event); // GLFW3 Joystick Connected/Disconnected Callback
152
153// Memory allocator wrappers [used by glfwInitAllocator()]
154static void *AllocateWrapper(size_t size, void *user); // GLFW3 GLFWallocatefun, wrapps around RL_CALLOC macro
155static void *ReallocateWrapper(void *block, size_t size, void *user); // GLFW3 GLFWreallocatefun, wrapps around RL_REALLOC macro
156static void DeallocateWrapper(void *block, void *user); // GLFW3 GLFWdeallocatefun, wraps around RL_FREE macro
157
158//----------------------------------------------------------------------------------
159// Module Functions Declaration
160//----------------------------------------------------------------------------------
161// NOTE: Functions declaration is provided by raylib.h
162
163//----------------------------------------------------------------------------------
164// Module Functions Definition: Window and Graphics Device
165//----------------------------------------------------------------------------------
166
167// Check if application should close
168// NOTE: By default, if KEY_ESCAPE pressed or window close icon clicked
169bool WindowShouldClose(void)
170{
171 if (CORE.Window.ready) return CORE.Window.shouldClose;
172 else return true;
173}
174
175// Toggle fullscreen mode
176void ToggleFullscreen(void)
177{
178 if (!FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
179 {
180 // Store previous screen data (in case exiting fullscreen)
181 CORE.Window.previousPosition = CORE.Window.position;
182 CORE.Window.previousScreen = CORE.Window.screen;
183
184 // Use current monitor the window is on to get fullscreen required size
185 int monitorCount = 0;
186 int monitorIndex = GetCurrentMonitor();
187 GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);
188 GLFWmonitor *monitor = (monitorIndex < monitorCount)? monitors[monitorIndex] : NULL;
189
190 if (monitor != NULL)
191 {
192 // Get current monitor video mode
193 const GLFWvidmode *mode = glfwGetVideoMode(monitors[monitorIndex]);
194 CORE.Window.display.width = mode->width;
195 CORE.Window.display.height = mode->height;
196
197 CORE.Window.position = (Point){ 0, 0 };
198 CORE.Window.screen = (Size){ CORE.Window.display.width, CORE.Window.display.height };
199
200 // Set fullscreen flag to be processed on FramebufferSizeCallback() accordingly
201 FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
202
203 // WARNING: This function launches FramebufferSizeCallback()
204 glfwSetWindowMonitor(platform.handle, monitor, 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);
205 }
206 else TRACELOG(LOG_WARNING, "GLFW: Failed to get monitor");
207 }
208 else
209 {
210 // Restore previous window position and size
211 CORE.Window.position = CORE.Window.previousPosition;
212 CORE.Window.screen = CORE.Window.previousScreen;
213
214 // Set fullscreen flag to be processed on FramebufferSizeCallback() accordingly
215 // and considered by GetWindowScaleDPI()
216 FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
217
218#if !defined(__APPLE__)
219 // Make sure to restore render size considering HighDPI scaling
220 if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
221 {
222 Vector2 scaleDpi = GetWindowScaleDPI();
223 CORE.Window.screen.width *= scaleDpi.x;
224 CORE.Window.screen.height *= scaleDpi.y;
225 }
226#endif
227
228 glfwSetWindowMonitor(platform.handle, NULL, CORE.Window.position.x, CORE.Window.position.y,
229 CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);
230 }
231
232 // Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS)
233 // NOTE: V-Sync can be enabled by graphic driver configuration
234 if (FLAG_IS_SET(CORE.Window.flags, FLAG_VSYNC_HINT)) glfwSwapInterval(1);
235}
236
237// Toggle borderless windowed mode
238void ToggleBorderlessWindowed(void)
239{
240 // Leave fullscreen before attempting to set borderless windowed mode
241 // NOTE: Fullscreen already saves the previous position so it does not need to be set again later
242 if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE)) ToggleFullscreen();
243
244 int monitorCount = 0;
245 GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);
246 const int monitor = GetCurrentMonitor();
247
248 if ((monitor >= 0) && (monitor < monitorCount))
249 {
250 const GLFWvidmode *mode = glfwGetVideoMode(monitors[monitor]);
251
252 if (mode != NULL)
253 {
254 if (!FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE))
255 {
256 // Store screen position and size
257 // NOTE: If it was on fullscreen, screen position was already stored, so skip setting it here
258 CORE.Window.previousPosition = CORE.Window.position;
259 CORE.Window.previousScreen = CORE.Window.screen;
260
261 // Set undecorated flag
262 glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_FALSE);
263 FLAG_SET(CORE.Window.flags, FLAG_WINDOW_UNDECORATED);
264
265 // Get monitor position and size
266 int monitorPosX = 0;
267 int monitorPosY = 0;
268 glfwGetMonitorPos(monitors[monitor], &monitorPosX, &monitorPosY);
269 const int monitorWidth = mode->width;
270 const int monitorHeight = mode->height;
271
272 // Set screen position and size
273 glfwSetWindowMonitor(platform.handle, monitors[monitor], monitorPosX, monitorPosY,
274 monitorWidth, monitorHeight, mode->refreshRate);
275
276 // Refocus window
277 glfwFocusWindow(platform.handle);
278
279 FLAG_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
280 }
281 else
282 {
283 // Restore previous screen values
284 CORE.Window.position = CORE.Window.previousPosition;
285 CORE.Window.screen = CORE.Window.previousScreen;
286
287 // Remove undecorated flag
288 glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_TRUE);
289 FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNDECORATED);
290
291 #if !defined(__APPLE__)
292 // Make sure to restore size considering HighDPI scaling
293 if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
294 {
295 Vector2 scaleDpi = GetWindowScaleDPI();
296 CORE.Window.screen.width *= scaleDpi.x;
297 CORE.Window.screen.height *= scaleDpi.y;
298 }
299 #endif
300
301 // Return to previous screen size and position
302 glfwSetWindowMonitor(platform.handle, NULL, CORE.Window.position.x, CORE.Window.position.y,
303 CORE.Window.screen.width, CORE.Window.screen.height, mode->refreshRate);
304
305 // Refocus window
306 glfwFocusWindow(platform.handle);
307
308 FLAG_CLEAR(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
309 }
310 }
311 else TRACELOG(LOG_WARNING, "GLFW: Failed to find video mode for selected monitor");
312 }
313 else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor");
314}
315
316// Set window state: maximized, if resizable
317void MaximizeWindow(void)
318{
319 if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE)
320 {
321 glfwMaximizeWindow(platform.handle);
322 FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
323 }
324}
325
326// Set window state: minimized
327void MinimizeWindow(void)
328{
329 // NOTE: Following function launches callback that sets appropriate flag!
330 glfwIconifyWindow(platform.handle);
331}
332
333// Restore window from being minimized/maximized
334void RestoreWindow(void)
335{
336 if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE)
337 {
338 // Restores the specified window if it was previously iconified (minimized) or maximized
339 glfwRestoreWindow(platform.handle);
340 FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MINIMIZED);
341 FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
342 }
343}
344
345// Set window configuration state using flags
346void SetWindowState(unsigned int flags)
347{
348 if (!CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetWindowState does nothing before window initialization, Use \"SetConfigFlags\" instead");
349
350 // Check previous state and requested state to apply required changes
351 // NOTE: In most cases the functions already change the flags internally
352
353 // State change: FLAG_VSYNC_HINT
354 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_VSYNC_HINT) != FLAG_IS_SET(flags, FLAG_VSYNC_HINT)) && FLAG_IS_SET(flags, FLAG_VSYNC_HINT))
355 {
356 glfwSwapInterval(1);
357 FLAG_SET(CORE.Window.flags, FLAG_VSYNC_HINT);
358 }
359
360 // State change: FLAG_BORDERLESS_WINDOWED_MODE
361 // NOTE: This must be handled before FLAG_FULLSCREEN_MODE because ToggleBorderlessWindowed() needs to get some fullscreen values if fullscreen is running
362 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE) != FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE)) && FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE))
363 {
364 ToggleBorderlessWindowed(); // NOTE: Window state flag updated inside function
365 }
366
367 // State change: FLAG_FULLSCREEN_MODE
368 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE) != FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE)) && FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE))
369 {
370 ToggleFullscreen(); // NOTE: Window state flag updated inside function
371 }
372
373 // State change: FLAG_WINDOW_RESIZABLE
374 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE) != FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE)) && FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE))
375 {
376 glfwSetWindowAttrib(platform.handle, GLFW_RESIZABLE, GLFW_TRUE);
377 FLAG_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE);
378 }
379
380 // State change: FLAG_WINDOW_UNDECORATED
381 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNDECORATED) != FLAG_IS_SET(flags, FLAG_WINDOW_UNDECORATED)) && FLAG_IS_SET(flags, FLAG_WINDOW_UNDECORATED))
382 {
383 glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_FALSE);
384 FLAG_SET(CORE.Window.flags, FLAG_WINDOW_UNDECORATED);
385 }
386
387 // State change: FLAG_WINDOW_HIDDEN
388 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN) != FLAG_IS_SET(flags, FLAG_WINDOW_HIDDEN)) && FLAG_IS_SET(flags, FLAG_WINDOW_HIDDEN))
389 {
390 glfwHideWindow(platform.handle);
391 FLAG_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN);
392 }
393
394 // State change: FLAG_WINDOW_MINIMIZED
395 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED) != FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED)) && FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED))
396 {
397 //GLFW_ICONIFIED
398 MinimizeWindow(); // NOTE: Window state flag updated inside function
399 }
400
401 // State change: FLAG_WINDOW_MAXIMIZED
402 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED) != FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED)) && FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED))
403 {
404 //GLFW_MAXIMIZED
405 MaximizeWindow(); // NOTE: Window state flag updated inside function
406 }
407
408 // State change: FLAG_WINDOW_UNFOCUSED
409 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED) != FLAG_IS_SET(flags, FLAG_WINDOW_UNFOCUSED)) && FLAG_IS_SET(flags, FLAG_WINDOW_UNFOCUSED))
410 {
411 glfwSetWindowAttrib(platform.handle, GLFW_FOCUS_ON_SHOW, GLFW_FALSE);
412 FLAG_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED);
413 }
414
415 // State change: FLAG_WINDOW_TOPMOST
416 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_TOPMOST) != FLAG_IS_SET(flags, FLAG_WINDOW_TOPMOST)) && FLAG_IS_SET(flags, FLAG_WINDOW_TOPMOST))
417 {
418 glfwSetWindowAttrib(platform.handle, GLFW_FLOATING, GLFW_TRUE);
419 FLAG_SET(CORE.Window.flags, FLAG_WINDOW_TOPMOST);
420 }
421
422 // State change: FLAG_WINDOW_ALWAYS_RUN
423 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN) != FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN)) && FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN))
424 {
425 FLAG_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN);
426 }
427
428 // The following states can not be changed after window creation
429
430 // State change: FLAG_WINDOW_TRANSPARENT
431 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_TRANSPARENT) != FLAG_IS_SET(flags, FLAG_WINDOW_TRANSPARENT)) && FLAG_IS_SET(flags, FLAG_WINDOW_TRANSPARENT))
432 {
433 TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only be configured before window initialization");
434 }
435
436 // State change: FLAG_WINDOW_HIGHDPI
437 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI) != FLAG_IS_SET(flags, FLAG_WINDOW_HIGHDPI)) && FLAG_IS_SET(flags, FLAG_WINDOW_HIGHDPI))
438 {
439 TRACELOG(LOG_WARNING, "WINDOW: High DPI can only be configured before window initialization");
440 }
441
442 // State change: FLAG_WINDOW_MOUSE_PASSTHROUGH
443 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MOUSE_PASSTHROUGH) != FLAG_IS_SET(flags, FLAG_WINDOW_MOUSE_PASSTHROUGH)) && FLAG_IS_SET(flags, FLAG_WINDOW_MOUSE_PASSTHROUGH))
444 {
445 glfwSetWindowAttrib(platform.handle, GLFW_MOUSE_PASSTHROUGH, GLFW_TRUE);
446 FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MOUSE_PASSTHROUGH);
447 }
448
449 // State change: FLAG_MSAA_4X_HINT
450 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT) != FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT)) && FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT))
451 {
452 TRACELOG(LOG_WARNING, "WINDOW: MSAA can only be configured before window initialization");
453 }
454
455 // State change: FLAG_INTERLACED_HINT
456 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_INTERLACED_HINT) != FLAG_IS_SET(flags, FLAG_INTERLACED_HINT)) && FLAG_IS_SET(flags, FLAG_INTERLACED_HINT))
457 {
458 TRACELOG(LOG_WARNING, "WINDOW: Interlaced mode can only be configured before window initialization");
459 }
460}
461
462// Clear window configuration state flags
463void ClearWindowState(unsigned int flags)
464{
465 // Check previous state and requested state to apply required changes
466 // NOTE: In most cases the functions already change the flags internally
467
468 // State change: FLAG_VSYNC_HINT
469 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_VSYNC_HINT)) && (FLAG_IS_SET(flags, FLAG_VSYNC_HINT)))
470 {
471 glfwSwapInterval(0);
472 FLAG_CLEAR(CORE.Window.flags, FLAG_VSYNC_HINT);
473 }
474
475 // State change: FLAG_BORDERLESS_WINDOWED_MODE
476 // NOTE: This must be handled before FLAG_FULLSCREEN_MODE because ToggleBorderlessWindowed() needs to get some fullscreen values if fullscreen is running
477 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE)) && (FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE)))
478 {
479 ToggleBorderlessWindowed(); // NOTE: Window state flag updated inside function
480 }
481
482 // State change: FLAG_FULLSCREEN_MODE
483 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE)) && (FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE)))
484 {
485 ToggleFullscreen(); // NOTE: Window state flag updated inside function
486 }
487
488 // State change: FLAG_WINDOW_RESIZABLE
489 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE)) && (FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE)))
490 {
491 glfwSetWindowAttrib(platform.handle, GLFW_RESIZABLE, GLFW_FALSE);
492 FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_RESIZABLE);
493 }
494
495 // State change: FLAG_WINDOW_HIDDEN
496 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN)) && (FLAG_IS_SET(flags, FLAG_WINDOW_HIDDEN)))
497 {
498 glfwShowWindow(platform.handle);
499 FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_HIDDEN);
500 }
501
502 // State change: FLAG_WINDOW_MINIMIZED
503 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) && (FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED)))
504 {
505 RestoreWindow(); // NOTE: Window state flag updated inside function
506 }
507
508 // State change: FLAG_WINDOW_MAXIMIZED
509 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED)) && (FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED)))
510 {
511 RestoreWindow(); // NOTE: Window state flag updated inside function
512 }
513
514 // State change: FLAG_WINDOW_UNDECORATED
515 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNDECORATED)) && (FLAG_IS_SET(flags, FLAG_WINDOW_UNDECORATED)))
516 {
517 glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_TRUE);
518 FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNDECORATED);
519 }
520
521 // State change: FLAG_WINDOW_UNFOCUSED
522 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) && (FLAG_IS_SET(flags, FLAG_WINDOW_UNFOCUSED)))
523 {
524 glfwSetWindowAttrib(platform.handle, GLFW_FOCUS_ON_SHOW, GLFW_TRUE);
525 FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED);
526 }
527
528 // State change: FLAG_WINDOW_TOPMOST
529 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_TOPMOST)) && (FLAG_IS_SET(flags, FLAG_WINDOW_TOPMOST)))
530 {
531 glfwSetWindowAttrib(platform.handle, GLFW_FLOATING, GLFW_FALSE);
532 FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_TOPMOST);
533 }
534
535 // State change: FLAG_WINDOW_ALWAYS_RUN
536 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN)) && (FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN)))
537 {
538 FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN);
539 }
540
541 // The following states can not be changed after window creation
542
543 // State change: FLAG_WINDOW_TRANSPARENT
544 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_TRANSPARENT)) && (FLAG_IS_SET(flags, FLAG_WINDOW_TRANSPARENT)))
545 {
546 TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only be configured before window initialization");
547 }
548
549 // State change: FLAG_WINDOW_HIGHDPI
550 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) && (FLAG_IS_SET(flags, FLAG_WINDOW_HIGHDPI)))
551 {
552 TRACELOG(LOG_WARNING, "WINDOW: High DPI can only be configured before window initialization");
553 }
554
555 // State change: FLAG_WINDOW_MOUSE_PASSTHROUGH
556 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MOUSE_PASSTHROUGH)) && (FLAG_IS_SET(flags, FLAG_WINDOW_MOUSE_PASSTHROUGH)))
557 {
558 glfwSetWindowAttrib(platform.handle, GLFW_MOUSE_PASSTHROUGH, GLFW_FALSE);
559 FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MOUSE_PASSTHROUGH);
560 }
561
562 // State change: FLAG_MSAA_4X_HINT
563 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT)) && (FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT)))
564 {
565 TRACELOG(LOG_WARNING, "WINDOW: MSAA can only be configured before window initialization");
566 }
567
568 // State change: FLAG_INTERLACED_HINT
569 if ((FLAG_IS_SET(CORE.Window.flags, FLAG_INTERLACED_HINT)) && (FLAG_IS_SET(flags, FLAG_INTERLACED_HINT)))
570 {
571 TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only be configured before window initialization");
572 }
573}
574
575// Set icon for window
576// NOTE 1: Image must be in RGBA format, 8bit per channel
577// NOTE 2: Image is scaled by the OS for all required sizes
578void SetWindowIcon(Image image)
579{
580 if (image.data == NULL)
581 {
582 // Revert to the default window icon, pass in an empty image array
583 glfwSetWindowIcon(platform.handle, 0, NULL);
584 }
585 else
586 {
587 if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)
588 {
589 GLFWimage icon[1] = { 0 };
590
591 icon[0].width = image.width;
592 icon[0].height = image.height;
593 icon[0].pixels = (unsigned char *)image.data;
594
595 // NOTE 1: We only support one image icon
596 // NOTE 2: The specified image data is copied before this function returns
597 glfwSetWindowIcon(platform.handle, 1, icon);
598 }
599 else TRACELOG(LOG_WARNING, "GLFW: Window icon image must be in R8G8B8A8 pixel format");
600 }
601}
602
603// Set icon for window, multiple images
604// NOTE 1: Images must be in RGBA format, 8bit per channel
605// NOTE 2: The multiple images are used depending on provided sizes
606// Standard Windows icon sizes: 256, 128, 96, 64, 48, 32, 24, 16
607void SetWindowIcons(Image *images, int count)
608{
609 if ((images == NULL) || (count <= 0))
610 {
611 // Revert to the default window icon, pass in an empty image array
612 glfwSetWindowIcon(platform.handle, 0, NULL);
613 }
614 else
615 {
616 int valid = 0;
617 GLFWimage *icons = (GLFWimage *)RL_CALLOC(count, sizeof(GLFWimage));
618
619 for (int i = 0; i < count; i++)
620 {
621 if (images[i].format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)
622 {
623 icons[valid].width = images[i].width;
624 icons[valid].height = images[i].height;
625 icons[valid].pixels = (unsigned char *)images[i].data;
626
627 valid++;
628 }
629 else TRACELOG(LOG_WARNING, "GLFW: Window icon image must be in R8G8B8A8 pixel format");
630 }
631 // NOTE: Images data is copied internally before this function returns
632 glfwSetWindowIcon(platform.handle, valid, icons);
633
634 RL_FREE(icons);
635 }
636}
637
638// Set title for window
639void SetWindowTitle(const char *title)
640{
641 CORE.Window.title = title;
642 glfwSetWindowTitle(platform.handle, title);
643}
644
645// Set window position on screen (windowed mode)
646void SetWindowPosition(int x, int y)
647{
648 // Update CORE.Window.position as well
649 CORE.Window.position.x = x;
650 CORE.Window.position.y = y;
651 glfwSetWindowPos(platform.handle, x, y);
652}
653
654// Set monitor for the current window
655void SetWindowMonitor(int monitor)
656{
657 int monitorCount = 0;
658 GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);
659
660 if ((monitor >= 0) && (monitor < monitorCount))
661 {
662 if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
663 {
664 TRACELOG(LOG_INFO, "GLFW: Selected fullscreen monitor: [%i] %s", monitor, glfwGetMonitorName(monitors[monitor]));
665
666 const GLFWvidmode *mode = glfwGetVideoMode(monitors[monitor]);
667 glfwSetWindowMonitor(platform.handle, monitors[monitor], 0, 0, mode->width, mode->height, mode->refreshRate);
668 }
669 else
670 {
671 TRACELOG(LOG_INFO, "GLFW: Selected monitor: [%i] %s", monitor, glfwGetMonitorName(monitors[monitor]));
672
673 // Here the render width has to be used again in case high dpi flag is enabled
674 const int screenWidth = CORE.Window.render.width;
675 const int screenHeight = CORE.Window.render.height;
676 int monitorWorkareaX = 0;
677 int monitorWorkareaY = 0;
678 int monitorWorkareaWidth = 0;
679 int monitorWorkareaHeight = 0;
680 glfwGetMonitorWorkarea(monitors[monitor], &monitorWorkareaX, &monitorWorkareaY, &monitorWorkareaWidth, &monitorWorkareaHeight);
681
682 // If the screen size is larger than the monitor workarea, anchor it on the top left corner, otherwise, center it
683 if ((screenWidth >= monitorWorkareaWidth) || (screenHeight >= monitorWorkareaHeight)) glfwSetWindowPos(platform.handle, monitorWorkareaX, monitorWorkareaY);
684 else
685 {
686 const int x = monitorWorkareaX + (monitorWorkareaWidth/2) - (screenWidth/2);
687 const int y = monitorWorkareaY + (monitorWorkareaHeight/2) - (screenHeight/2);
688 glfwSetWindowPos(platform.handle, x, y);
689 }
690 }
691 }
692 else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor");
693}
694
695// Set window minimum dimensions (FLAG_WINDOW_RESIZABLE)
696void SetWindowMinSize(int width, int height)
697{
698 CORE.Window.screenMin.width = width;
699 CORE.Window.screenMin.height = height;
700
701 int minWidth = (CORE.Window.screenMin.width == 0)? GLFW_DONT_CARE : (int)CORE.Window.screenMin.width;
702 int minHeight = (CORE.Window.screenMin.height == 0)? GLFW_DONT_CARE : (int)CORE.Window.screenMin.height;
703 int maxWidth = (CORE.Window.screenMax.width == 0)? GLFW_DONT_CARE : (int)CORE.Window.screenMax.width;
704 int maxHeight = (CORE.Window.screenMax.height == 0)? GLFW_DONT_CARE : (int)CORE.Window.screenMax.height;
705
706 glfwSetWindowSizeLimits(platform.handle, minWidth, minHeight, maxWidth, maxHeight);
707}
708
709// Set window maximum dimensions (FLAG_WINDOW_RESIZABLE)
710void SetWindowMaxSize(int width, int height)
711{
712 CORE.Window.screenMax.width = width;
713 CORE.Window.screenMax.height = height;
714
715 int minWidth = (CORE.Window.screenMin.width == 0)? GLFW_DONT_CARE : (int)CORE.Window.screenMin.width;
716 int minHeight = (CORE.Window.screenMin.height == 0)? GLFW_DONT_CARE : (int)CORE.Window.screenMin.height;
717 int maxWidth = (CORE.Window.screenMax.width == 0)? GLFW_DONT_CARE : (int)CORE.Window.screenMax.width;
718 int maxHeight = (CORE.Window.screenMax.height == 0)? GLFW_DONT_CARE : (int)CORE.Window.screenMax.height;
719
720 glfwSetWindowSizeLimits(platform.handle, minWidth, minHeight, maxWidth, maxHeight);
721}
722
723// Set window dimensions
724void SetWindowSize(int width, int height)
725{
726 CORE.Window.screen.width = width;
727 CORE.Window.screen.height = height;
728
729 glfwSetWindowSize(platform.handle, width, height);
730}
731
732// Set window opacity, value opacity is between 0.0 and 1.0
733void SetWindowOpacity(float opacity)
734{
735 if (opacity >= 1.0f) opacity = 1.0f;
736 else if (opacity <= 0.0f) opacity = 0.0f;
737 glfwSetWindowOpacity(platform.handle, opacity);
738}
739
740// Set window focused
741void SetWindowFocused(void)
742{
743 glfwFocusWindow(platform.handle);
744}
745
746#if defined(__linux__) && defined(_GLFW_X11)
747// Local storage for the window handle returned by glfwGetX11Window
748// This is needed as X11 handles are integers and may not fit inside a pointer depending on platform
749// Storing the handle locally and returning a pointer in GetWindowHandle allows the code to work regardless of pointer width
750static XID X11WindowHandle;
751#endif
752// Get native window handle
753void *GetWindowHandle(void)
754{
755#if defined(_WIN32)
756 // NOTE: Returned handle is: void *HWND (windows.h)
757 return glfwGetWin32Window(platform.handle);
758#endif
759#if defined(__linux__)
760 #if defined(_GLFW_WAYLAND)
761 #if defined(_GLFW_X11)
762 int platformID = glfwGetPlatform();
763 if (platformID == GLFW_PLATFORM_WAYLAND)
764 {
765 return glfwGetWaylandWindow(platform.handle);
766 }
767 else
768 {
769 X11WindowHandle = glfwGetX11Window(platform.handle);
770 return &X11WindowHandle;
771 }
772 #else
773 return glfwGetWaylandWindow(platform.handle);
774 #endif
775 #elif defined(_GLFW_X11)
776 // Store the window handle localy and return a pointer to the variable instead
777 // Reasoning detailed in the declaration of X11WindowHandle
778 X11WindowHandle = glfwGetX11Window(platform.handle);
779 return &X11WindowHandle;
780 #endif
781#endif
782#if defined(__APPLE__)
783 // NOTE: Returned handle is: (objc_object *)
784 return (void *)glfwGetCocoaWindow(platform.handle);
785#endif
786
787 return NULL;
788}
789
790// Get number of monitors
791int GetMonitorCount(void)
792{
793 int monitorCount = 0;
794
795 glfwGetMonitors(&monitorCount);
796
797 return monitorCount;
798}
799
800// Get current monitor where window is placed
801int GetCurrentMonitor(void)
802{
803 int index = 0;
804 int monitorCount = 0;
805 GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);
806 GLFWmonitor *monitor = NULL;
807
808 if (monitorCount >= 1)
809 {
810 if (IsWindowFullscreen())
811 {
812 // Get the handle of the monitor that the specified window is in full screen on
813 monitor = glfwGetWindowMonitor(platform.handle);
814
815 for (int i = 0; i < monitorCount; i++)
816 {
817 if (monitors[i] == monitor)
818 {
819 index = i;
820 break;
821 }
822 }
823 }
824 else
825 {
826 // In case the window is between two monitors, we use below logic
827 // to try to detect the "current monitor" for that window, note that
828 // this is probably an overengineered solution for a very side case
829 // trying to match SDL behaviour
830
831 int closestDist = 0x7FFFFFFF;
832
833 // Window center position
834 int wcx = 0;
835 int wcy = 0;
836
837 glfwGetWindowPos(platform.handle, &wcx, &wcy);
838 wcx += (int)CORE.Window.screen.width/2;
839 wcy += (int)CORE.Window.screen.height/2;
840
841 for (int i = 0; i < monitorCount; i++)
842 {
843 // Monitor top-left position
844 int mx = 0;
845 int my = 0;
846
847 monitor = monitors[i];
848 glfwGetMonitorPos(monitor, &mx, &my);
849 const GLFWvidmode *mode = glfwGetVideoMode(monitor);
850
851 if (mode)
852 {
853 const int right = mx + mode->width - 1;
854 const int bottom = my + mode->height - 1;
855
856 if ((wcx >= mx) &&
857 (wcx <= right) &&
858 (wcy >= my) &&
859 (wcy <= bottom))
860 {
861 index = i;
862 break;
863 }
864
865 int xclosest = wcx;
866 if (wcx < mx) xclosest = mx;
867 else if (wcx > right) xclosest = right;
868
869 int yclosest = wcy;
870 if (wcy < my) yclosest = my;
871 else if (wcy > bottom) yclosest = bottom;
872
873 int dx = wcx - xclosest;
874 int dy = wcy - yclosest;
875 int dist = (dx*dx) + (dy*dy);
876 if (dist < closestDist)
877 {
878 index = i;
879 closestDist = dist;
880 }
881 }
882 else TRACELOG(LOG_WARNING, "GLFW: Failed to find video mode for selected monitor");
883 }
884 }
885 }
886
887 return index;
888}
889
890// Get selected monitor position
891Vector2 GetMonitorPosition(int monitor)
892{
893 int monitorCount = 0;
894 GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);
895
896 if ((monitor >= 0) && (monitor < monitorCount))
897 {
898 int x = 0;
899 int y = 0;
900 glfwGetMonitorPos(monitors[monitor], &x, &y);
901
902 return (Vector2){ (float)x, (float)y };
903 }
904 else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor");
905 return (Vector2){ 0, 0 };
906}
907
908// Get selected monitor width (currently used by monitor)
909int GetMonitorWidth(int monitor)
910{
911 int width = 0;
912 int monitorCount = 0;
913 GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);
914
915 if ((monitor >= 0) && (monitor < monitorCount))
916 {
917 const GLFWvidmode *mode = glfwGetVideoMode(monitors[monitor]);
918
919 if (mode) width = mode->width;
920 else TRACELOG(LOG_WARNING, "GLFW: Failed to find video mode for selected monitor");
921 }
922 else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor");
923
924 return width;
925}
926
927// Get selected monitor height (currently used by monitor)
928int GetMonitorHeight(int monitor)
929{
930 int height = 0;
931 int monitorCount = 0;
932 GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);
933
934 if ((monitor >= 0) && (monitor < monitorCount))
935 {
936 const GLFWvidmode *mode = glfwGetVideoMode(monitors[monitor]);
937
938 if (mode) height = mode->height;
939 else TRACELOG(LOG_WARNING, "GLFW: Failed to find video mode for selected monitor");
940 }
941 else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor");
942
943 return height;
944}
945
946// Get selected monitor physical width in millimetres
947int GetMonitorPhysicalWidth(int monitor)
948{
949 int width = 0;
950 int monitorCount = 0;
951 GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);
952
953 if ((monitor >= 0) && (monitor < monitorCount)) glfwGetMonitorPhysicalSize(monitors[monitor], &width, NULL);
954 else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor");
955
956 return width;
957}
958
959// Get selected monitor physical height in millimetres
960int GetMonitorPhysicalHeight(int monitor)
961{
962 int height = 0;
963 int monitorCount = 0;
964 GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);
965
966 if ((monitor >= 0) && (monitor < monitorCount)) glfwGetMonitorPhysicalSize(monitors[monitor], NULL, &height);
967 else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor");
968
969 return height;
970}
971
972// Get selected monitor refresh rate
973int GetMonitorRefreshRate(int monitor)
974{
975 int refresh = 0;
976 int monitorCount = 0;
977 GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);
978
979 if ((monitor >= 0) && (monitor < monitorCount))
980 {
981 const GLFWvidmode *mode = glfwGetVideoMode(monitors[monitor]);
982
983 if (mode) refresh = mode->refreshRate;
984 else TRACELOG(LOG_WARNING, "GLFW: Failed to find video mode for selected monitor");
985
986 }
987 else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor");
988
989 return refresh;
990}
991
992// Get the human-readable, UTF-8 encoded name of the selected monitor
993const char *GetMonitorName(int monitor)
994{
995 int monitorCount = 0;
996 GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);
997
998 if ((monitor >= 0) && (monitor < monitorCount))
999 {
1000 return glfwGetMonitorName(monitors[monitor]);
1001 }
1002 else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor");
1003 return "";
1004}
1005
1006// Get window position XY on monitor
1007Vector2 GetWindowPosition(void)
1008{
1009 int x = 0;
1010 int y = 0;
1011
1012 glfwGetWindowPos(platform.handle, &x, &y);
1013
1014 return (Vector2){ (float)x, (float)y };
1015}
1016
1017// Get window scale DPI factor for current monitor
1018Vector2 GetWindowScaleDPI(void)
1019{
1020 Vector2 scale = { 1.0f, 1.0f };
1021 if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI) && !FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
1022 glfwGetWindowContentScale(platform.handle, &scale.x, &scale.y);
1023 return scale;
1024}
1025
1026// Set clipboard text content
1027void SetClipboardText(const char *text)
1028{
1029 glfwSetClipboardString(platform.handle, text);
1030}
1031
1032// Get clipboard text content
1033// NOTE: returned string is allocated and freed by GLFW
1034const char *GetClipboardText(void)
1035{
1036 return glfwGetClipboardString(platform.handle);
1037}
1038
1039// Get clipboard image
1040Image GetClipboardImage(void)
1041{
1042 Image image = { 0 };
1043
1044#if defined(SUPPORT_CLIPBOARD_IMAGE)
1045#if defined(_WIN32)
1046 unsigned long long int dataSize = 0;
1047 void *fileData = NULL;
1048 int width = 0;
1049 int height = 0;
1050
1051 fileData = (void *)Win32GetClipboardImageData(&width, &height, &dataSize);
1052
1053 if (fileData == NULL) TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data.");
1054 else image = LoadImageFromMemory(".bmp", (const unsigned char *)fileData, (int)dataSize);
1055#else
1056 TRACELOG(LOG_WARNING, "GetClipboardImage() not implemented on target platform");
1057#endif
1058#endif // SUPPORT_CLIPBOARD_IMAGE
1059
1060 return image;
1061}
1062
1063// Show mouse cursor
1064void ShowCursor(void)
1065{
1066 glfwSetInputMode(platform.handle, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
1067
1068 CORE.Input.Mouse.cursorHidden = false;
1069}
1070
1071// Hides mouse cursor
1072void HideCursor(void)
1073{
1074 glfwSetInputMode(platform.handle, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
1075
1076 CORE.Input.Mouse.cursorHidden = true;
1077}
1078
1079// Enables cursor (unlock cursor)
1080void EnableCursor(void)
1081{
1082 glfwSetInputMode(platform.handle, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
1083
1084 // Set cursor position in the middle
1085 SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2);
1086
1087 if (glfwRawMouseMotionSupported()) glfwSetInputMode(platform.handle, GLFW_RAW_MOUSE_MOTION, GLFW_FALSE);
1088
1089 CORE.Input.Mouse.cursorHidden = false;
1090 CORE.Input.Mouse.cursorLocked = false;
1091}
1092
1093// Disables cursor (lock cursor)
1094void DisableCursor(void)
1095{
1096 // Reset mouse position within the window area before disabling cursor
1097 SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2);
1098
1099 glfwSetInputMode(platform.handle, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
1100
1101 if (glfwRawMouseMotionSupported()) glfwSetInputMode(platform.handle, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE);
1102
1103 CORE.Input.Mouse.cursorHidden = true;
1104 CORE.Input.Mouse.cursorLocked = true;
1105}
1106
1107// Swap back buffer with front buffer (screen drawing)
1108void SwapScreenBuffer(void)
1109{
1110 glfwSwapBuffers(platform.handle);
1111}
1112
1113//----------------------------------------------------------------------------------
1114// Module Functions Definition: Misc
1115//----------------------------------------------------------------------------------
1116
1117// Get elapsed time measure in seconds since InitTimer()
1118double GetTime(void)
1119{
1120 double time = glfwGetTime(); // Elapsed time since glfwInit()
1121 return time;
1122}
1123
1124// Open URL with default system browser (if available)
1125// NOTE: This function is only safe to use if you control the URL given
1126// A user could craft a malicious string performing another action
1127// Only call this function yourself not with user input or make sure to check the string yourself
1128// REF: https://github.com/raysan5/raylib/issues/686
1129void OpenURL(const char *url)
1130{
1131 // Security check to (partially) avoid malicious code
1132 if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character");
1133 else
1134 {
1135 char *cmd = (char *)RL_CALLOC(strlen(url) + 32, sizeof(char));
1136#if defined(_WIN32)
1137 sprintf(cmd, "explorer \"%s\"", url);
1138#endif
1139#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__)
1140 sprintf(cmd, "xdg-open '%s'", url); // Alternatives: firefox, x-www-browser
1141#endif
1142#if defined(__APPLE__)
1143 sprintf(cmd, "open '%s'", url);
1144#endif
1145 int result = system(cmd);
1146 if (result == -1) TRACELOG(LOG_WARNING, "OpenURL() child process could not be created");
1147 RL_FREE(cmd);
1148 }
1149}
1150
1151//----------------------------------------------------------------------------------
1152// Module Functions Definition: Inputs
1153//----------------------------------------------------------------------------------
1154
1155// Set internal gamepad mappings
1156int SetGamepadMappings(const char *mappings)
1157{
1158 return glfwUpdateGamepadMappings(mappings);
1159}
1160
1161// Set gamepad vibration
1162void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration)
1163{
1164 TRACELOG(LOG_WARNING, "SetGamepadVibration() not available on target platform");
1165}
1166
1167// Set mouse position XY
1168void SetMousePosition(int x, int y)
1169{
1170 CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y };
1171 CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
1172
1173 // NOTE: emscripten not implemented
1174 glfwSetCursorPos(platform.handle, CORE.Input.Mouse.currentPosition.x, CORE.Input.Mouse.currentPosition.y);
1175}
1176
1177// Set mouse cursor
1178void SetMouseCursor(int cursor)
1179{
1180 CORE.Input.Mouse.cursor = cursor;
1181 if (cursor == MOUSE_CURSOR_DEFAULT) glfwSetCursor(platform.handle, NULL);
1182 else
1183 {
1184 // NOTE: We are relating internal GLFW enum values to our MouseCursor enum values
1185 glfwSetCursor(platform.handle, glfwCreateStandardCursor(0x00036000 + cursor));
1186 }
1187}
1188
1189// Get physical key name
1190const char *GetKeyName(int key)
1191{
1192 return glfwGetKeyName(key, glfwGetKeyScancode(key));
1193}
1194
1195// Register all input events
1196void PollInputEvents(void)
1197{
1198#if defined(SUPPORT_GESTURES_SYSTEM)
1199 // NOTE: Gestures update must be called every frame to reset gestures correctly
1200 // because ProcessGestureEvent() is just called on an event, not every frame
1201 UpdateGestures();
1202#endif
1203
1204 // Reset keys/chars pressed registered
1205 CORE.Input.Keyboard.keyPressedQueueCount = 0;
1206 CORE.Input.Keyboard.charPressedQueueCount = 0;
1207
1208 // Reset last gamepad button/axis registered state
1209 CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN
1210 //CORE.Input.Gamepad.axisCount = 0;
1211
1212 // Keyboard/Mouse input polling (automatically managed by GLFW3 through callback)
1213
1214 // Register previous keys states
1215 for (int i = 0; i < MAX_KEYBOARD_KEYS; i++)
1216 {
1217 CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i];
1218 CORE.Input.Keyboard.keyRepeatInFrame[i] = 0;
1219 }
1220
1221 // Register previous mouse states
1222 for (int i = 0; i < MAX_MOUSE_BUTTONS; i++) CORE.Input.Mouse.previousButtonState[i] = CORE.Input.Mouse.currentButtonState[i];
1223
1224 // Register previous mouse wheel state
1225 CORE.Input.Mouse.previousWheelMove = CORE.Input.Mouse.currentWheelMove;
1226 CORE.Input.Mouse.currentWheelMove = (Vector2){ 0.0f, 0.0f };
1227
1228 // Register previous mouse position
1229 CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
1230
1231 // Register previous touch states
1232 for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.previousTouchState[i] = CORE.Input.Touch.currentTouchState[i];
1233
1234 // Reset touch positions
1235 //for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.position[i] = (Vector2){ 0, 0 };
1236
1237 // Map touch position to mouse position for convenience
1238 // WARNING: If the target desktop device supports touch screen, this behaviour should be reviewed!
1239 // TODO: GLFW does not support multi-touch input yet
1240 // REF: https://www.codeproject.com/Articles/668404/Programming-for-Multi-Touch
1241 // REF: https://docs.microsoft.com/en-us/windows/win32/wintouch/getting-started-with-multi-touch-messages
1242 CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
1243
1244 // Check if gamepads are ready
1245 // NOTE: We do it here in case of disconnection
1246 for (int i = 0; i < MAX_GAMEPADS; i++)
1247 {
1248 if (glfwJoystickPresent(i)) CORE.Input.Gamepad.ready[i] = true;
1249 else CORE.Input.Gamepad.ready[i] = false;
1250 }
1251
1252 // Register gamepads buttons events
1253 for (int i = 0; i < MAX_GAMEPADS; i++)
1254 {
1255 if (CORE.Input.Gamepad.ready[i]) // Check if gamepad is available
1256 {
1257 // Register previous gamepad states
1258 for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) CORE.Input.Gamepad.previousButtonState[i][k] = CORE.Input.Gamepad.currentButtonState[i][k];
1259
1260 // Get current gamepad state
1261 // NOTE: There is no callback available, so we get it manually
1262 GLFWgamepadstate state = { 0 };
1263 int result = glfwGetGamepadState(i, &state); // This remaps all gamepads so they have their buttons mapped like an xbox controller
1264 if (result == GLFW_FALSE) // No joystick is connected, no gamepad mapping or an error occurred
1265 {
1266 // Setting axes to expected resting value instead of GLFW 0.0f default when gamepad is not connected
1267 state.axes[GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f;
1268 state.axes[GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
1269 }
1270
1271 const unsigned char *buttons = state.buttons;
1272
1273 for (int k = 0; (buttons != NULL) && (k < MAX_GAMEPAD_BUTTONS); k++)
1274 {
1275 int button = -1; // GamepadButton enum values assigned
1276
1277 switch (k)
1278 {
1279 case GLFW_GAMEPAD_BUTTON_Y: button = GAMEPAD_BUTTON_RIGHT_FACE_UP; break;
1280 case GLFW_GAMEPAD_BUTTON_B: button = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT; break;
1281 case GLFW_GAMEPAD_BUTTON_A: button = GAMEPAD_BUTTON_RIGHT_FACE_DOWN; break;
1282 case GLFW_GAMEPAD_BUTTON_X: button = GAMEPAD_BUTTON_RIGHT_FACE_LEFT; break;
1283
1284 case GLFW_GAMEPAD_BUTTON_LEFT_BUMPER: button = GAMEPAD_BUTTON_LEFT_TRIGGER_1; break;
1285 case GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER: button = GAMEPAD_BUTTON_RIGHT_TRIGGER_1; break;
1286
1287 case GLFW_GAMEPAD_BUTTON_BACK: button = GAMEPAD_BUTTON_MIDDLE_LEFT; break;
1288 case GLFW_GAMEPAD_BUTTON_GUIDE: button = GAMEPAD_BUTTON_MIDDLE; break;
1289 case GLFW_GAMEPAD_BUTTON_START: button = GAMEPAD_BUTTON_MIDDLE_RIGHT; break;
1290
1291 case GLFW_GAMEPAD_BUTTON_DPAD_UP: button = GAMEPAD_BUTTON_LEFT_FACE_UP; break;
1292 case GLFW_GAMEPAD_BUTTON_DPAD_RIGHT: button = GAMEPAD_BUTTON_LEFT_FACE_RIGHT; break;
1293 case GLFW_GAMEPAD_BUTTON_DPAD_DOWN: button = GAMEPAD_BUTTON_LEFT_FACE_DOWN; break;
1294 case GLFW_GAMEPAD_BUTTON_DPAD_LEFT: button = GAMEPAD_BUTTON_LEFT_FACE_LEFT; break;
1295
1296 case GLFW_GAMEPAD_BUTTON_LEFT_THUMB: button = GAMEPAD_BUTTON_LEFT_THUMB; break;
1297 case GLFW_GAMEPAD_BUTTON_RIGHT_THUMB: button = GAMEPAD_BUTTON_RIGHT_THUMB; break;
1298 default: break;
1299 }
1300
1301 if (button != -1) // Check for valid button
1302 {
1303 if (buttons[k] == GLFW_PRESS)
1304 {
1305 CORE.Input.Gamepad.currentButtonState[i][button] = 1;
1306 CORE.Input.Gamepad.lastButtonPressed = button;
1307 }
1308 else CORE.Input.Gamepad.currentButtonState[i][button] = 0;
1309 }
1310 }
1311
1312 // Get current state of axes
1313 const float *axes = state.axes;
1314
1315 for (int k = 0; (axes != NULL) && (k < GLFW_GAMEPAD_AXIS_LAST + 1); k++)
1316 {
1317 CORE.Input.Gamepad.axisState[i][k] = axes[k];
1318 }
1319
1320 // Register buttons for 2nd triggers (because GLFW doesn't count these as buttons but rather as axes)
1321 if (CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_LEFT_TRIGGER] > 0.1f)
1322 {
1323 CORE.Input.Gamepad.currentButtonState[i][GAMEPAD_BUTTON_LEFT_TRIGGER_2] = 1;
1324 CORE.Input.Gamepad.lastButtonPressed = GAMEPAD_BUTTON_LEFT_TRIGGER_2;
1325 }
1326 else CORE.Input.Gamepad.currentButtonState[i][GAMEPAD_BUTTON_LEFT_TRIGGER_2] = 0;
1327 if (CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_RIGHT_TRIGGER] > 0.1f)
1328 {
1329 CORE.Input.Gamepad.currentButtonState[i][GAMEPAD_BUTTON_RIGHT_TRIGGER_2] = 1;
1330 CORE.Input.Gamepad.lastButtonPressed = GAMEPAD_BUTTON_RIGHT_TRIGGER_2;
1331 }
1332 else CORE.Input.Gamepad.currentButtonState[i][GAMEPAD_BUTTON_RIGHT_TRIGGER_2] = 0;
1333
1334 CORE.Input.Gamepad.axisCount[i] = GLFW_GAMEPAD_AXIS_LAST + 1;
1335 }
1336 }
1337
1338 CORE.Window.resizedLastFrame = false;
1339
1340 if ((CORE.Window.eventWaiting) ||
1341 (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED) && !FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN)))
1342 {
1343 glfwWaitEvents(); // Wait for in input events before continue (drawing is paused)
1344 CORE.Time.previous = GetTime();
1345 }
1346 else glfwPollEvents(); // Poll input events: keyboard/mouse/window events (callbacks) -> Update keys state
1347
1348 CORE.Window.shouldClose = glfwWindowShouldClose(platform.handle);
1349
1350 // Reset close status for next frame
1351 glfwSetWindowShouldClose(platform.handle, GLFW_FALSE);
1352}
1353
1354//----------------------------------------------------------------------------------
1355// Module Internal Functions Definition
1356//----------------------------------------------------------------------------------
1357// Function wrappers around RL_*alloc macros, used by glfwInitAllocator() inside of InitPlatform()
1358// We need to provide these because GLFWallocator expects function pointers with specific signatures
1359// Similar wrappers exist in utils.c but we cannot reuse them here due to declaration mismatch
1360// REF: https://www.glfw.org/docs/latest/intro_guide.html#init_allocator
1361static void *AllocateWrapper(size_t size, void *user)
1362{
1363 (void)user;
1364 return RL_CALLOC(size, 1);
1365}
1366static void *ReallocateWrapper(void *block, size_t size, void *user)
1367{
1368 (void)user;
1369 return RL_REALLOC(block, size);
1370}
1371static void DeallocateWrapper(void *block, void *user)
1372{
1373 (void)user;
1374 RL_FREE(block);
1375}
1376
1377// Initialize platform: graphics, inputs and more
1378int InitPlatform(void)
1379{
1380 glfwSetErrorCallback(ErrorCallback);
1381
1382 const GLFWallocator allocator = {
1383 .allocate = AllocateWrapper,
1384 .reallocate = ReallocateWrapper,
1385 .deallocate = DeallocateWrapper,
1386 .user = NULL, // RL_*ALLOC macros are not capable of handling user-provided data
1387 };
1388
1389 glfwInitAllocator(&allocator);
1390
1391#if defined(__APPLE__)
1392 glfwInitHint(GLFW_COCOA_CHDIR_RESOURCES, GLFW_FALSE);
1393#endif
1394 // Initialize GLFW internal global state
1395 int result = glfwInit();
1396 if (result == GLFW_FALSE) { TRACELOG(LOG_WARNING, "GLFW: Failed to initialize GLFW"); return -1; }
1397
1398 // Initialize graphic device: display/window and graphic context
1399 //----------------------------------------------------------------------------
1400 glfwDefaultWindowHints(); // Set default windows hints
1401 //glfwWindowHint(GLFW_RED_BITS, 8); // Framebuffer red color component bits
1402 //glfwWindowHint(GLFW_GREEN_BITS, 8); // Framebuffer green color component bits
1403 //glfwWindowHint(GLFW_BLUE_BITS, 8); // Framebuffer blue color component bits
1404 //glfwWindowHint(GLFW_ALPHA_BITS, 8); // Framebuffer alpha color component bits
1405 //glfwWindowHint(GLFW_DEPTH_BITS, 24); // Depthbuffer bits
1406 //glfwWindowHint(GLFW_REFRESH_RATE, 0); // Refresh rate for fullscreen window
1407 //glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); // OpenGL API to use. Alternative: GLFW_OPENGL_ES_API
1408 //glfwWindowHint(GLFW_AUX_BUFFERS, 0); // Number of auxiliar buffers
1409
1410 // Disable GlFW auto iconify behaviour
1411 // Auto Iconify automatically minimizes (iconifies) the window if the window loses focus
1412 // additionally auto iconify restores the hardware resolution of the monitor if the window that loses focus is a fullscreen window
1413 glfwWindowHint(GLFW_AUTO_ICONIFY, 0);
1414
1415 // Window flags requested before initialization to be applied after initialization
1416 unsigned int requestedWindowFlags = CORE.Window.flags;
1417
1418 // Check window creation flags
1419 if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN)) glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // Visible window
1420 else glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE); // Window initially hidden
1421
1422 if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNDECORATED)) glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); // Border and buttons on Window
1423 else glfwWindowHint(GLFW_DECORATED, GLFW_TRUE); // Decorated window
1424
1425 if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE)) glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // Resizable window
1426 else glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); // Avoid window being resizable
1427
1428 // Disable FLAG_WINDOW_MINIMIZED, not supported on initialization
1429 if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MINIMIZED);
1430
1431 // Disable FLAG_WINDOW_MAXIMIZED, not supported on initialization
1432 if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED)) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
1433
1434 if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) glfwWindowHint(GLFW_FOCUSED, GLFW_FALSE);
1435 else glfwWindowHint(GLFW_FOCUSED, GLFW_TRUE);
1436
1437 if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_TOPMOST)) glfwWindowHint(GLFW_FLOATING, GLFW_TRUE);
1438 else glfwWindowHint(GLFW_FLOATING, GLFW_FALSE);
1439
1440 // NOTE: Some GLFW flags are not supported on HTML5
1441 if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_TRANSPARENT)) glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE); // Transparent framebuffer
1442 else glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_FALSE); // Opaque framebuffer
1443
1444 if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
1445 {
1446#if defined(__APPLE__)
1447 glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE);
1448#endif
1449 // Resize window content area based on the monitor content scale
1450 // NOTE: This hint only has an effect on platforms where screen coordinates and
1451 // pixels always map 1:1 such as Windows and X11
1452 // On platforms like macOS the resolution of the framebuffer is changed independently of the window size
1453 glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE);
1454#if defined(__APPLE__)
1455 glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE);
1456#endif
1457 }
1458 else
1459 {
1460 glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_FALSE);
1461#if defined(__APPLE__)
1462 glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE);
1463#endif
1464 }
1465
1466 // Mouse passthrough
1467 if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MOUSE_PASSTHROUGH)) glfwWindowHint(GLFW_MOUSE_PASSTHROUGH, GLFW_TRUE);
1468 else glfwWindowHint(GLFW_MOUSE_PASSTHROUGH, GLFW_FALSE);
1469
1470 if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT))
1471 {
1472 // NOTE: MSAA is only enabled for main framebuffer, not user-created FBOs
1473 TRACELOG(LOG_INFO, "DISPLAY: Trying to enable MSAA x4");
1474 glfwWindowHint(GLFW_SAMPLES, 4); // Tries to enable multisampling x4 (MSAA), default is 0
1475 }
1476
1477 // NOTE: When asking for an OpenGL context version, most drivers provide the highest supported version
1478 // with backward compatibility to older OpenGL versions
1479 // For example, if using OpenGL 1.1, driver can provide a 4.3 backwards compatible context
1480
1481 // Check selection OpenGL version
1482 if (rlGetVersion() == RL_OPENGL_21)
1483 {
1484 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); // Choose OpenGL major version (just hint)
1485 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); // Choose OpenGL minor version (just hint)
1486 }
1487 else if (rlGetVersion() == RL_OPENGL_33)
1488 {
1489 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // Choose OpenGL major version (just hint)
1490 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // Choose OpenGL minor version (just hint)
1491 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Profiles Hint: Only 3.3 and above!
1492 // Values: GLFW_OPENGL_CORE_PROFILE, GLFW_OPENGL_ANY_PROFILE, GLFW_OPENGL_COMPAT_PROFILE
1493#if defined(__APPLE__)
1494 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); // OSX Requires forward compatibility
1495#else
1496 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_FALSE); // Forward Compatibility Hint: Only 3.3 and above!
1497#endif
1498 //glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); // Request OpenGL DEBUG context
1499 }
1500 else if (rlGetVersion() == RL_OPENGL_43)
1501 {
1502 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); // Choose OpenGL major version (just hint)
1503 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // Choose OpenGL minor version (just hint)
1504 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
1505 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_FALSE);
1506#if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT)
1507 glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); // Enable OpenGL Debug Context
1508#endif
1509 }
1510 else if (rlGetVersion() == RL_OPENGL_ES_20) // Request OpenGL ES 2.0 context
1511 {
1512 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
1513 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
1514 glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
1515 glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
1516 }
1517 else if (rlGetVersion() == RL_OPENGL_ES_30) // Request OpenGL ES 3.0 context
1518 {
1519 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
1520 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
1521 glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
1522 glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
1523 }
1524
1525 // NOTE: GLFW 3.4+ defers initialization of the Joystick subsystem on the first call to any Joystick related functions
1526 // Forcing this initialization here avoids doing it on PollInputEvents() called by EndDrawing() after first frame has been just drawn
1527 // The initialization will still happen and possible delays still occur, but before the window is shown, which is a nicer experience
1528 // REF: https://github.com/raysan5/raylib/issues/1554
1529 glfwSetJoystickCallback(NULL);
1530
1531 if ((CORE.Window.screen.width == 0) || (CORE.Window.screen.height == 0)) FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
1532
1533 // Init window in fullscreen mode if requested
1534 // NOTE: Keeping original screen size for toggle
1535 if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
1536 {
1537 // NOTE: Fullscreen applications default to the primary monitor
1538 GLFWmonitor *monitor = glfwGetPrimaryMonitor();
1539 if (!monitor)
1540 {
1541 TRACELOG(LOG_WARNING, "GLFW: Failed to get primary monitor");
1542 return -1;
1543 }
1544
1545 // Set dimensions from monitor
1546 const GLFWvidmode *mode = glfwGetVideoMode(monitor);
1547
1548 // Default display resolution to that of the current mode
1549 CORE.Window.display.width = mode->width;
1550 CORE.Window.display.height = mode->height;
1551
1552 // Check if user requested some screen size
1553 if ((CORE.Window.screen.width == 0) || (CORE.Window.screen.height == 0))
1554 {
1555 // Set some default screen size in case user decides to exit fullscreen mode
1556 CORE.Window.previousScreen.width = 800;
1557 CORE.Window.previousScreen.height = 450;
1558 CORE.Window.previousPosition.x = CORE.Window.display.width/2 - 800/2;
1559 CORE.Window.previousPosition.y = CORE.Window.display.height/2 - 450/2;
1560 }
1561
1562 // Set screen width/height to the display width/height
1563 if (CORE.Window.screen.width == 0) CORE.Window.screen.width = CORE.Window.display.width;
1564 if (CORE.Window.screen.height == 0) CORE.Window.screen.height = CORE.Window.display.height;
1565
1566 platform.handle = glfwCreateWindow(CORE.Window.display.width, CORE.Window.display.height, (CORE.Window.title != 0)? CORE.Window.title : " ", monitor, NULL);
1567 if (!platform.handle)
1568 {
1569 glfwTerminate();
1570 TRACELOG(LOG_WARNING, "GLFW: Failed to initialize Window");
1571 return -1;
1572 }
1573 }
1574 else
1575 {
1576 // Default to at least one pixel in size, as creation with a zero dimension is not allowed
1577 if (CORE.Window.screen.width == 0) CORE.Window.screen.width = 1;
1578 if (CORE.Window.screen.height == 0) CORE.Window.screen.height = 1;
1579
1580 platform.handle = glfwCreateWindow(CORE.Window.screen.width, CORE.Window.screen.height, (CORE.Window.title != 0)? CORE.Window.title : " ", NULL, NULL);
1581 if (!platform.handle)
1582 {
1583 glfwTerminate();
1584 TRACELOG(LOG_WARNING, "GLFW: Failed to initialize Window");
1585 return -1;
1586 }
1587
1588 // After the window was created, determine the monitor that the window manager assigned
1589 // Derive display sizes and, if possible, window size in case it was zero at beginning
1590
1591 int monitorCount = 0;
1592 int monitorIndex = GetCurrentMonitor();
1593 GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);
1594
1595 if (monitorIndex < monitorCount)
1596 {
1597 GLFWmonitor *monitor = monitors[monitorIndex];
1598 const GLFWvidmode *mode = glfwGetVideoMode(monitor);
1599
1600 // Default display resolution to that of the current mode
1601 CORE.Window.display.width = mode->width;
1602 CORE.Window.display.height = mode->height;
1603
1604 // Set screen width/height to the display width/height if they are 0
1605 if (CORE.Window.screen.width == 0) CORE.Window.screen.width = CORE.Window.display.width;
1606 if (CORE.Window.screen.height == 0) CORE.Window.screen.height = CORE.Window.display.height;
1607
1608 glfwSetWindowSize(platform.handle, CORE.Window.screen.width, CORE.Window.screen.height);
1609 }
1610 else
1611 {
1612 // The monitor for the window-manager-created window can not be determined, so it can not be centered
1613 glfwTerminate();
1614 TRACELOG(LOG_WARNING, "GLFW: Failed to determine Monitor to center Window");
1615 return -1;
1616 }
1617
1618 // NOTE: Not considering scale factor now, considered below
1619 CORE.Window.render.width = CORE.Window.screen.width;
1620 CORE.Window.render.height = CORE.Window.screen.height;
1621 }
1622
1623 glfwMakeContextCurrent(platform.handle);
1624 result = glfwGetError(NULL);
1625
1626 // Check context activation
1627 if ((result != GLFW_NO_WINDOW_CONTEXT) && (result != GLFW_PLATFORM_ERROR))
1628 {
1629 CORE.Window.ready = true;
1630
1631 glfwSwapInterval(0); // No V-Sync by default
1632
1633 // Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS)
1634 // NOTE: V-Sync can be enabled by graphic driver configuration, it doesn't need
1635 // to be activated on web platforms since VSync is enforced there
1636 if (FLAG_IS_SET(CORE.Window.flags, FLAG_VSYNC_HINT))
1637 {
1638 // WARNING: It seems to hit a critical render path in Intel HD Graphics
1639 glfwSwapInterval(1);
1640 TRACELOG(LOG_INFO, "DISPLAY: Trying to enable VSYNC");
1641 }
1642
1643 int fbWidth = CORE.Window.screen.width;
1644 int fbHeight = CORE.Window.screen.height;
1645
1646 if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
1647 {
1648 // NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling
1649 // Framebuffer scaling is activated with: glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE);
1650
1651 // Get current framebuffer size, on high-dpi it could be bigger than screen size
1652 glfwGetFramebufferSize(platform.handle, &fbWidth, &fbHeight);
1653
1654 // Screen scaling matrix is required in case desired screen area is different from display area
1655 CORE.Window.screenScale = MatrixScale((float)fbWidth/CORE.Window.screen.width, (float)fbHeight/CORE.Window.screen.height, 1.0f);
1656#if !defined(__APPLE__)
1657 // Mouse input scaling for the new screen size
1658 SetMouseScale((float)CORE.Window.screen.width/fbWidth, (float)CORE.Window.screen.height/fbHeight);
1659#endif
1660 }
1661
1662 CORE.Window.render.width = fbWidth;
1663 CORE.Window.render.height = fbHeight;
1664 CORE.Window.currentFbo.width = fbWidth;
1665 CORE.Window.currentFbo.height = fbHeight;
1666
1667 TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
1668 TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
1669 TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
1670 TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height);
1671 TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
1672 }
1673 else
1674 {
1675 TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphics device");
1676 return -1;
1677 }
1678
1679 if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) MinimizeWindow();
1680
1681 // If graphic device is no properly initialized, we end program
1682 if (!CORE.Window.ready) { TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphic device"); return -1; }
1683 else
1684 {
1685 int monitorCount = 0;
1686 int monitorIndex = GetCurrentMonitor();
1687 GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);
1688 GLFWmonitor *monitor = monitors[monitorIndex];
1689
1690 // Try to center window on screen but avoiding window-bar outside of screen
1691 int monitorX = 0;
1692 int monitorY = 0;
1693 int monitorWidth = 0;
1694 int monitorHeight = 0;
1695 glfwGetMonitorWorkarea(monitor, &monitorX, &monitorY, &monitorWidth, &monitorHeight);
1696
1697 // TODO: Here CORE.Window.render.width/height should be used instead of
1698 // CORE.Window.screen.width/height to center the window correctly when the high dpi flag is enabled
1699 int posX = monitorX + (monitorWidth - (int)CORE.Window.render.width)/2;
1700 int posY = monitorY + (monitorHeight - (int)CORE.Window.render.height)/2;
1701 if (posX < monitorX) posX = monitorX;
1702 if (posY < monitorY) posY = monitorY;
1703 SetWindowPosition(posX, posY);
1704
1705 // Update CORE.Window.position here so it is correct from the start
1706 CORE.Window.position.x = posX;
1707 CORE.Window.position.y = posY;
1708 }
1709
1710 // Apply window flags requested previous to initialization
1711 SetWindowState(requestedWindowFlags);
1712
1713 // Load OpenGL extensions
1714 // NOTE: GL procedures address loader is required to load extensions
1715 rlLoadExtensions(glfwGetProcAddress);
1716 //----------------------------------------------------------------------------
1717
1718 // Initialize input events callbacks
1719 //----------------------------------------------------------------------------
1720 // Set window callback events
1721 glfwSetWindowSizeCallback(platform.handle, WindowSizeCallback); // NOTE: Resizing is not enabled by default
1722 glfwSetFramebufferSizeCallback(platform.handle, FramebufferSizeCallback);
1723 glfwSetWindowPosCallback(platform.handle, WindowPosCallback);
1724 glfwSetWindowMaximizeCallback(platform.handle, WindowMaximizeCallback);
1725 glfwSetWindowIconifyCallback(platform.handle, WindowIconifyCallback);
1726 glfwSetWindowFocusCallback(platform.handle, WindowFocusCallback);
1727 glfwSetDropCallback(platform.handle, WindowDropCallback);
1728 if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) glfwSetWindowContentScaleCallback(platform.handle, WindowContentScaleCallback);
1729
1730 // Set input callback events
1731 glfwSetKeyCallback(platform.handle, KeyCallback);
1732 glfwSetCharCallback(platform.handle, CharCallback);
1733 glfwSetMouseButtonCallback(platform.handle, MouseButtonCallback);
1734 glfwSetCursorPosCallback(platform.handle, MouseCursorPosCallback); // Track mouse position changes
1735 glfwSetScrollCallback(platform.handle, MouseScrollCallback);
1736 glfwSetCursorEnterCallback(platform.handle, CursorEnterCallback);
1737 glfwSetJoystickCallback(JoystickCallback);
1738 glfwSetInputMode(platform.handle, GLFW_LOCK_KEY_MODS, GLFW_TRUE); // Enable lock keys modifiers (CAPS, NUM)
1739
1740 // Retrieve gamepad names
1741 for (int i = 0; i < MAX_GAMEPADS; i++)
1742 {
1743 // WARNING: If glfwGetJoystickName() is longer than MAX_GAMEPAD_NAME_LENGTH,
1744 // we can get a not-NULL terminated string, so, we only copy up to (MAX_GAMEPAD_NAME_LENGTH - 1)
1745 if (glfwJoystickPresent(i))
1746 {
1747 CORE.Input.Gamepad.ready[i] = true;
1748 CORE.Input.Gamepad.axisCount[i] = GLFW_GAMEPAD_AXIS_LAST + 1;
1749 strncpy(CORE.Input.Gamepad.name[i], glfwGetJoystickName(i), MAX_GAMEPAD_NAME_LENGTH - 1);
1750 }
1751 }
1752 //----------------------------------------------------------------------------
1753
1754 // Initialize timming system
1755 //----------------------------------------------------------------------------
1756 InitTimer();
1757 //----------------------------------------------------------------------------
1758
1759 // Initialize storage system
1760 //----------------------------------------------------------------------------
1761 CORE.Storage.basePath = GetWorkingDirectory();
1762 //----------------------------------------------------------------------------
1763
1764#if defined(__NetBSD__)
1765 // Workaround for NetBSD
1766 char *glfwPlatform = "X11 (NetBSD)";
1767#else
1768 char *glfwPlatform = "";
1769 switch (glfwGetPlatform())
1770 {
1771 case GLFW_PLATFORM_WIN32: glfwPlatform = "Win32"; break;
1772 case GLFW_PLATFORM_COCOA: glfwPlatform = "Cocoa"; break;
1773 case GLFW_PLATFORM_WAYLAND: glfwPlatform = "Wayland"; break;
1774 case GLFW_PLATFORM_X11: glfwPlatform = "X11"; break;
1775 case GLFW_PLATFORM_NULL: glfwPlatform = "Null"; break;
1776 default: break;
1777 }
1778#endif
1779
1780 TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (GLFW - %s): Initialized successfully", glfwPlatform);
1781
1782 return 0;
1783}
1784
1785// Close platform
1786void ClosePlatform(void)
1787{
1788 glfwDestroyWindow(platform.handle);
1789 glfwTerminate();
1790
1791#if defined(_WIN32) && defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP)
1792 timeEndPeriod(1); // Restore time period
1793#endif
1794}
1795
1796//----------------------------------------------------------------------------------
1797// Module Internal Functions Definition
1798// NOTE: Those functions are only required for current platform
1799//----------------------------------------------------------------------------------
1800
1801// GLFW3: Error callback, runs on GLFW3 error
1802static void ErrorCallback(int error, const char *description)
1803{
1804 TRACELOG(LOG_WARNING, "GLFW: Error: %i Description: %s", error, description);
1805}
1806
1807// GLFW3: Window size change callback, runs when window is resized
1808// NOTE: Window resizing not enabled by default, use SetConfigFlags()
1809static void WindowSizeCallback(GLFWwindow *window, int width, int height)
1810{
1811 // Nothing to do for now on window resize...
1812 //TRACELOG(LOG_INFO, "GLFW3: Window size callback called [%i,%i]", width, height);
1813}
1814
1815// GLFW3: Framebuffer size change callback, runs when framebuffer is resized
1816// WARNING: If FLAG_WINDOW_HIGHDPI is set, WindowContentScaleCallback() is called before this function
1817static void FramebufferSizeCallback(GLFWwindow *window, int width, int height)
1818{
1819 TRACELOG(LOG_INFO, "GLFW3: Window framebuffer size callback called [%i,%i]", width, height);
1820
1821 // WARNING: On window minimization, callback is called,
1822 // but we don't want to change internal screen values, it breaks things
1823 if ((width == 0) || (height == 0)) return;
1824
1825 // Reset viewport and projection matrix for new size
1826 // NOTE: Stores current render size: CORE.Window.render
1827 SetupViewport(width, height);
1828
1829 // Set render size
1830 CORE.Window.currentFbo.width = width;
1831 CORE.Window.currentFbo.height = height;
1832 CORE.Window.resizedLastFrame = true;
1833
1834 if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
1835 {
1836 // On fullscreen mode, strategy is ignoring high-dpi and
1837 // use the all available display size
1838
1839 // Set screen size to render size (physical pixel size)
1840 CORE.Window.screen.width = width;
1841 CORE.Window.screen.height = height;
1842 CORE.Window.screenScale = MatrixScale(1.0f, 1.0f, 1.0f);
1843 SetMouseScale(1.0f, 1.0f);
1844 }
1845 else // Window mode (including borderless window)
1846 {
1847 // Check if render size was actually scaled for high-dpi
1848 if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
1849 {
1850 // Set screen size to logical pixel size, considering content scaling
1851 Vector2 scaleDpi = GetWindowScaleDPI();
1852 CORE.Window.screen.width = (int)((float)width/scaleDpi.x);
1853 CORE.Window.screen.height = (int)((float)height/scaleDpi.y);
1854 CORE.Window.screenScale = MatrixScale(scaleDpi.x, scaleDpi.y, 1.0f);
1855#if !defined(__APPLE__)
1856 // Mouse input scaling for the new screen size
1857 SetMouseScale(1.0f/scaleDpi.x, 1.0f/scaleDpi.y);
1858#endif
1859 }
1860 else
1861 {
1862 // Set screen size to render size (physical pixel size)
1863 CORE.Window.screen.width = width;
1864 CORE.Window.screen.height = height;
1865 }
1866 }
1867
1868 // WARNING: If using a render texture, it is not scaled to new size
1869}
1870
1871// GLFW3: Window content scale callback, runs on monitor content scale change detected
1872// WARNING: If FLAG_WINDOW_HIGHDPI is not set, this function is not called
1873static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley)
1874{
1875 TRACELOG(LOG_INFO, "GLFW3: Window content scale changed, scale: [%.2f,%.2f]", scalex, scaley);
1876
1877 float fbWidth = (float)CORE.Window.screen.width*scalex;
1878 float fbHeight = (float)CORE.Window.screen.height*scaley;
1879
1880 // NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling
1881 // Framebuffer scaling is activated with: glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE);
1882 CORE.Window.screenScale = MatrixScale(scalex, scaley, 1.0f);
1883
1884#if !defined(__APPLE__)
1885 // Mouse input scaling for the new screen size
1886 SetMouseScale(1.0f/scalex, 1.0f/scaley);
1887#endif
1888
1889 CORE.Window.render.width = (int)fbWidth;
1890 CORE.Window.render.height = (int)fbHeight;
1891 CORE.Window.currentFbo = CORE.Window.render;
1892}
1893
1894// GLFW3: Window position callback, runs when window position changes
1895static void WindowPosCallback(GLFWwindow *window, int x, int y)
1896{
1897 // Set current window position
1898 CORE.Window.position.x = x;
1899 CORE.Window.position.y = y;
1900}
1901
1902// GLFW3: Window iconify callback, runs when window is minimized/restored
1903static void WindowIconifyCallback(GLFWwindow *window, int iconified)
1904{
1905 if (iconified) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED); // The window was iconified
1906 else FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MINIMIZED); // The window was restored
1907}
1908
1909// GLFW3: Window maximize callback, runs when window is maximized/restored
1910static void WindowMaximizeCallback(GLFWwindow *window, int maximized)
1911{
1912 if (maximized) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED); // The window was maximized
1913 else FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED); // The window was restored
1914}
1915
1916// GLFW3: Window focus callback, runs when window get/lose focus
1917static void WindowFocusCallback(GLFWwindow *window, int focused)
1918{
1919 if (focused) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED); // The window was focused
1920 else FLAG_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED); // The window lost focus
1921}
1922
1923// GLFW3: Window drop callback, runs when files are dropped into window
1924static void WindowDropCallback(GLFWwindow *window, int count, const char **paths)
1925{
1926 if (count > 0)
1927 {
1928 // In case previous dropped filepaths have not been freed, we free them
1929 if (CORE.Window.dropFileCount > 0)
1930 {
1931 for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++) RL_FREE(CORE.Window.dropFilepaths[i]);
1932
1933 RL_FREE(CORE.Window.dropFilepaths);
1934
1935 CORE.Window.dropFileCount = 0;
1936 CORE.Window.dropFilepaths = NULL;
1937 }
1938
1939 // WARNING: Paths are freed by GLFW when the callback returns, we must keep an internal copy
1940 CORE.Window.dropFileCount = count;
1941 CORE.Window.dropFilepaths = (char **)RL_CALLOC(CORE.Window.dropFileCount, sizeof(char *));
1942
1943 for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++)
1944 {
1945 CORE.Window.dropFilepaths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
1946 strncpy(CORE.Window.dropFilepaths[i], paths[i], MAX_FILEPATH_LENGTH - 1);
1947 }
1948 }
1949}
1950
1951// GLFW3: Keyboard callback, runs on key pressed
1952static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
1953{
1954 if (key < 0) return; // Security check, macOS fn key generates -1
1955
1956 // WARNING: GLFW could return GLFW_REPEAT, we need to consider it as 1
1957 // to work properly with our implementation (IsKeyDown/IsKeyUp checks)
1958 if (action == GLFW_RELEASE) CORE.Input.Keyboard.currentKeyState[key] = 0;
1959 else if (action == GLFW_PRESS) CORE.Input.Keyboard.currentKeyState[key] = 1;
1960 else if (action == GLFW_REPEAT) CORE.Input.Keyboard.keyRepeatInFrame[key] = 1;
1961
1962 // WARNING: Check if CAPS/NUM key modifiers are enabled and force down state for those keys
1963 if (((key == KEY_CAPS_LOCK) && (FLAG_IS_SET(mods, GLFW_MOD_CAPS_LOCK))) ||
1964 ((key == KEY_NUM_LOCK) && (FLAG_IS_SET(mods, GLFW_MOD_NUM_LOCK)))) CORE.Input.Keyboard.currentKeyState[key] = 1;
1965
1966 // Check if there is space available in the key queue
1967 if ((CORE.Input.Keyboard.keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE) && (action == GLFW_PRESS))
1968 {
1969 // Add character to the queue
1970 CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = key;
1971 CORE.Input.Keyboard.keyPressedQueueCount++;
1972 }
1973
1974 // Check the exit key to set close window
1975 if ((key == CORE.Input.Keyboard.exitKey) && (action == GLFW_PRESS)) glfwSetWindowShouldClose(platform.handle, GLFW_TRUE);
1976}
1977
1978// GLFW3: Char callback, runs on key pressed to get unicode codepoint value
1979static void CharCallback(GLFWwindow *window, unsigned int codepoint)
1980{
1981 // NOTE: Registers any key down considering OS keyboard layout but
1982 // does not detect action events, those should be managed by user...
1983 // REF: https://github.com/glfw/glfw/issues/668#issuecomment-166794907
1984 // REF: https://www.glfw.org/docs/latest/input_guide.html#input_char
1985
1986 // Check if there is space available in the queue
1987 if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE)
1988 {
1989 // Add character to the queue
1990 CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = codepoint;
1991 CORE.Input.Keyboard.charPressedQueueCount++;
1992 }
1993}
1994
1995// GLFW3: Mouse button callback, runs on mouse button pressed
1996static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods)
1997{
1998 // WARNING: GLFW could only return GLFW_PRESS (1) or GLFW_RELEASE (0) for now,
1999 // but future releases may add more actions (i.e. GLFW_REPEAT)
2000 CORE.Input.Mouse.currentButtonState[button] = action;
2001 CORE.Input.Touch.currentTouchState[button] = action;
2002
2003#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES)
2004 // Process mouse events as touches to be able to use mouse-gestures
2005 GestureEvent gestureEvent = { 0 };
2006
2007 // Register touch actions
2008 if ((CORE.Input.Mouse.currentButtonState[button] == 1) && (CORE.Input.Mouse.previousButtonState[button] == 0)) gestureEvent.touchAction = TOUCH_ACTION_DOWN;
2009 else if ((CORE.Input.Mouse.currentButtonState[button] == 0) && (CORE.Input.Mouse.previousButtonState[button] == 1)) gestureEvent.touchAction = TOUCH_ACTION_UP;
2010
2011 // NOTE: TOUCH_ACTION_MOVE event is registered in MouseCursorPosCallback()
2012
2013 // Assign a pointer ID
2014 gestureEvent.pointId[0] = 0;
2015
2016 // Register touch points count
2017 gestureEvent.pointCount = 1;
2018
2019 // Register touch points position, only one point registered
2020 gestureEvent.position[0] = GetMousePosition();
2021
2022 // Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height
2023 gestureEvent.position[0].x /= (float)GetScreenWidth();
2024 gestureEvent.position[0].y /= (float)GetScreenHeight();
2025
2026 // Gesture data is sent to gestures-system for processing
2027 ProcessGestureEvent(gestureEvent);
2028#endif
2029}
2030
2031// GLFW3: Cursor position callback, runs on mouse movement
2032static void MouseCursorPosCallback(GLFWwindow *window, double x, double y)
2033{
2034 CORE.Input.Mouse.currentPosition.x = (float)x;
2035 CORE.Input.Mouse.currentPosition.y = (float)y;
2036 CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
2037
2038#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES)
2039 // Process mouse events as touches to be able to use mouse-gestures
2040 GestureEvent gestureEvent = { 0 };
2041
2042 gestureEvent.touchAction = TOUCH_ACTION_MOVE;
2043
2044 // Assign a pointer ID
2045 gestureEvent.pointId[0] = 0;
2046
2047 // Register touch points count
2048 gestureEvent.pointCount = 1;
2049
2050 // Register touch points position, only one point registered
2051 gestureEvent.position[0] = CORE.Input.Touch.position[0];
2052
2053 // Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height
2054 gestureEvent.position[0].x /= (float)GetScreenWidth();
2055 gestureEvent.position[0].y /= (float)GetScreenHeight();
2056
2057 // Gesture data is sent to gestures-system for processing
2058 ProcessGestureEvent(gestureEvent);
2059#endif
2060}
2061
2062// GLFW3: Mouse wheel scroll callback, runs on mouse wheel changes
2063static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset)
2064{
2065 CORE.Input.Mouse.currentWheelMove = (Vector2){ (float)xoffset, (float)yoffset };
2066}
2067
2068// GLFW3: Cursor ennter callback, when cursor enters the window
2069static void CursorEnterCallback(GLFWwindow *window, int enter)
2070{
2071 if (enter) CORE.Input.Mouse.cursorOnScreen = true;
2072 else CORE.Input.Mouse.cursorOnScreen = false;
2073}
2074
2075// GLFW3: Joystick connected/disconnected callback
2076static void JoystickCallback(int jid, int event)
2077{
2078 if (event == GLFW_CONNECTED)
2079 {
2080 // WARNING: If glfwGetJoystickName() is longer than MAX_GAMEPAD_NAME_LENGTH,
2081 // we can get a not-NULL terminated string, so, we clean destination and only copy up to -1
2082 memset(CORE.Input.Gamepad.name[jid], 0, MAX_GAMEPAD_NAME_LENGTH);
2083 strncpy(CORE.Input.Gamepad.name[jid], glfwGetJoystickName(jid), MAX_GAMEPAD_NAME_LENGTH - 1);
2084 }
2085 else if (event == GLFW_DISCONNECTED)
2086 {
2087 memset(CORE.Input.Gamepad.name[jid], 0, MAX_GAMEPAD_NAME_LENGTH);
2088 }
2089}
2090
2091#ifdef _WIN32
2092# define WIN32_CLIPBOARD_IMPLEMENTATION
2093# include "../external/win32_clipboard.h"
2094#endif
2095// EOF
2096
Copyright 2026  E766CB298A6D1E64 | Git-Thing heavily inspired by cgit