commit 4a6b9e0
uint
·
2026-05-03 23:03:41 +0000 UTC
parent e78c546
add RGFW
4 files changed,
+16059,
-2
M
Makefile
+1,
-1
1@@ -1,7 +1,7 @@
2 CC = cc
3
4 CFLAGS = -std=c99 -Wall -Wextra
5-CPPFLAGS =
6+CPPFLAGS = -Isource/external -Isource/include
7
8 SRCS = source/cterm.c
9 OUT = cterm
M
README
+4,
-1
1@@ -1,3 +1,6 @@
2 cterm
3
4-minimal cross-platform terminal emulator written in c
5+A minimal cross-platform terminal emulator written in C.
6+
7+Thank you ST for source code :)
8+
+20,
-0
1@@ -0,0 +1,20 @@
2+zlib License
3+
4+Copyright (C) 2022-2025 Riley Mabb (@ColleagueRiley)
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 be
17+ appreciated but is not required.
18+2. Altered source versions must be plainly marked as such, and must not be
19+ misrepresented as being the original software.
20+3. This notice may not be removed or altered from any source distribution.
21+
+16034,
-0
1@@ -0,0 +1,16034 @@
2+/*
3+*
4+* RGFW 2.0.0-dev
5+
6+* Copyright (C) 2022-26 Riley Mabb (@ColleagueRiley)
7+*
8+* libpng license
9+*
10+* This software is provided 'as-is', without any express or implied
11+* warranty. In no event will the authors be held liable for any damages
12+* arising from the use of this software.
13+
14+* Permission is granted to anyone to use this software for any purpose,
15+* including commercial applications, and to alter it and redistribute it
16+* freely, subject to the following restrictions:
17+*
18+* 1. The origin of this software must not be misrepresented; you must not
19+* claim that you wrote the original software. If you use this software
20+* in a product, an acknowledgment in the product documentation would be
21+* appreciated but is not required.
22+* 2. Altered source versions must be plainly marked as such, and must not be
23+* misrepresented as being the original software.
24+* 3. This notice may not be removed or altered from any source distribution.
25+*
26+*
27+*/
28+
29+/*
30+ (MAKE SURE RGFW_IMPLEMENTATION is in exactly one header or you use -D RGFW_IMPLEMENTATION)
31+ #define RGFW_IMPLEMENTATION - makes it so source code is included with header
32+*/
33+
34+/*
35+ #define RGFW_IMPLEMENTATION - (required) makes it so the source code is included
36+ #define RGFW_DEBUG - (optional) makes it so RGFW prints debug messages and errors when they're found
37+ #define RGFW_EGL - (optional) compile with OpenGL functions, allowing you to use to use EGL instead of the native OpenGL functions
38+ #define RGFW_DIRECTX - (optional) include integration directX functions (windows only)
39+ #define RGFW_VULKAN - (optional) include helpful vulkan integration functions and macros
40+ #define RGFW_WEBGPU - (optional) use WebGPU for rendering
41+ #define RGFW_NATIVE - (optional) define native RGFW types that use native API structures
42+
43+ #define RGFW_X11 (optional) (unix only) if X11 should be used. This option is turned on by default by unix systems except for MacOS
44+ #define RGFW_WAYLAND (optional) (unix only) use Wayland. (This can be used with X11)
45+ #define RGFW_NO_STATIC_CONTEXT - do not initalizize with a static variable, use the heap if RGFW is not manually initalized
46+ #define RGFW_NO_X11 (optional) (unix only) don't fallback to X11 when using Wayland
47+ #define RGFW_NO_LOAD_WGL (optional) (windows only) if WGL should be loaded dynamically during runtime
48+ #define RGFW_NO_X11_CURSOR (optional) (unix only) don't use XCursor
49+ #define RGFW_NO_X11_CURSOR_PRELOAD (optional) (unix only) use XCursor, but don't link it in code, (you'll have to link it with -lXcursor)
50+ #define RGFW_NO_X11_EXT_PRELOAD (optional) (unix only) use Xext, but don't link it in code, (you'll have to link it with -lXext)
51+ #define RGFW_NO_LOAD_WINMM (optional) (windows only) use winmm (timeBeginPeriod), but don't link it in code, (you'll have to link it with -lwinmm)
52+ #define RGFW_NO_WINMM (optional) (windows only) don't use winmm
53+ #define RGFW_NO_IOKIT (optional) (macOS) don't use IOKit
54+ #define RGFW_NO_UNIX_CLOCK (optional) (unix) don't link unix clock functions
55+ #define RGFW_NO_DWM (windows only) - do not use or link dwmapi
56+ #define RGFW_USE_XDL (optional) (X11) if XDL (XLib Dynamic Loader) should be used to load X11 dynamically during runtime (must include XDL.h along with RGFW)
57+ #define RGFW_COCOA_GRAPHICS_SWITCHING - (optional) (cocoa) use automatic graphics switching (allow the system to choose to use GPU or iGPU)
58+ #define RGFW_COCOA_FRAME_NAME (optional) (cocoa) set frame name
59+ #define RGFW_NO_DPI - do not calculate DPI and don't use libShcore (win32)
60+ #define RGFW_ADVANCED_SMOOTH_RESIZE - use advanced methods for smooth resizing (may result in a spike in memory usage or worse performance) (eg. WM_TIMER and XSyncValue)
61+ #define RGFW_NO_INFO - do not define the RGFW_info struct (without RGFW_IMPLEMENTATION)
62+ #define RGFW_NO_GLXWINDOW - do not use GLXWindow
63+ #define RGFW_NO_ALLOCATE_MONITORS - do not allocate monitors on the heap at all (when there's no pre-allocated space left)
64+ #define RGFW_PREALLOCATED_MONITORS x - choose the default amount of pre-allocated monitors (can be zero)
65+
66+ #define RGFW_ALLOC x - choose the default allocation function (defaults to standard malloc)
67+ #define RGFW_FREE x - choose the default deallocation function (defaults to standard free)
68+ #define RGFW_USERPTR x - choose the default userptr sent to the malloc call, (NULL by default)
69+
70+ #define RGFW_EXPORT - use when building RGFW
71+ #define RGFW_IMPORT - use when linking with RGFW (not as a single-header)
72+
73+ #define RGFW_USE_INT - force the use c-types rather than stdint.h (for systems that might not have stdint.h (msvc))
74+ #define RGFW_bool x - choose what type to use for bool, by default u32 is used
75+*/
76+
77+/*
78+Example to get you started :
79+
80+linux : gcc main.c -lX11 -lXrandr -lm
81+windows : gcc main.c -lgdi32
82+macos : gcc main.c -framework Cocoa -framework CoreVideo -framework IOKit
83+
84+#define RGFW_IMPLEMENTATION
85+#include "RGFW.h"
86+
87+int main() {
88+ RGFW_window* win = RGFW_createWindow("name", 100, 100, 500, 500, 0);
89+
90+ while (RGFW_window_shouldClose(win) == RGFW_FALSE) {
91+ RGFW_pollEvents();
92+ }
93+
94+ RGFW_window_close(win);
95+}
96+
97+ compiling :
98+
99+ if you wish to compile the library all you have to do is create a new file with this in it
100+
101+ rgfw.c
102+ #define RGFW_IMPLEMENTATION
103+ #include "RGFW.h"
104+
105+ You may also want to add
106+ `#define RGFW_EXPORT` when compiling and
107+ `#define RGFW_IMPORT`when linking RGFW on it's own:
108+ this reduces inline functions and prevents bloat in the object file
109+
110+ then you can use gcc (or whatever compile you wish to use) to compile the library into object file
111+
112+ ex. gcc -c RGFW.c -fPIC
113+
114+ after you compile the library into an object file, you can also turn the object file into an static or shared library
115+
116+ (commands ar and gcc can be replaced with whatever equivalent your system uses)
117+
118+ static : ar rcs RGFW.a RGFW.o
119+ shared :
120+ windows:
121+ gcc -shared RGFW.o -lopengl32 -lgdi32 -o RGFW.dll
122+ linux:
123+ gcc -shared RGFW.o -lX11 -lGL -lXrandr -o RGFW.so
124+ macos:
125+ gcc -shared RGFW.o -framework CoreVideo -framework Cocoa -framework OpenGL -framework IOKit
126+*/
127+
128+
129+
130+/*
131+ Credits :
132+ EimaMei/Sacode : Code review, helped with X11, MacOS and Windows support, Silicon, siliapp.h -> referencing
133+
134+ contributors : (feel free to put yourself here if you contribute)
135+ krisvers (@krisvers) -> code review
136+ EimaMei (@SaCode) -> code review
137+ Nycticebus (@Code-Nycticebus) -> bug fixes
138+ Rob Rohan (@robrohan) -> X11 bugs and missing features, MacOS/Cocoa fixing memory issues/bugs
139+ AICDG (@THISISAGOODNAME) -> vulkan support (example)
140+ @Easymode -> support, testing/debugging, bug fixes and reviews
141+ Joshua Rowe (omnisci3nce) - bug fix, review (macOS)
142+ @lesleyrs -> bug fix, review (OpenGL)
143+ Nick Porcino (@meshula) - testing, organization, review (MacOS, examples)
144+ @therealmarrakesh -> documentation
145+ @DarekParodia -> code review (X11) (C++)
146+ @NishiOwO -> fix BSD support, fix OSMesa example
147+ @BaynariKattu -> code review and documentation
148+ Miguel Pinto (@konopimi) -> code review, fix vulkan example
149+ @m-doescode -> code review (wayland)
150+ Robert Gonzalez (@uni-dos) -> code review (wayland)
151+ @TheLastVoyager -> code review
152+ @yehoravramenko -> code review (winapi)
153+ @halocupcake -> code review (OpenGL)
154+ @GideonSerf -> documentation
155+ Alexandre Almeida (@M374LX) -> code review (keycodes)
156+ Vũ Xuân Trường (@wanwanvxt) -> code review (winapi)
157+ Lucas (@lightspeedlucas) -> code review (msvc++)
158+ Jeffery Myers (@JeffM2501) -> code review (msvc)
159+ Zeni (@zenitsuyo) -> documentation
160+ TheYahton (@TheYahton) -> documentation
161+ nonexistant_object (@DiarrheaMcgee)
162+ AC Gaudette (@acgaudette)
163+*/
164+
165+#if _MSC_VER
166+ #pragma comment(lib, "gdi32")
167+ #pragma comment(lib, "shell32")
168+ #pragma comment(lib, "User32")
169+ #pragma comment(lib, "Advapi32")
170+ #pragma warning( push )
171+ #pragma warning( disable : 4996 4191 4127)
172+ #if _MSC_VER < 600
173+ #define RGFW_C89
174+ #endif
175+#else
176+ #if defined(__STDC__) && !defined(__STDC_VERSION__)
177+ #define RGFW_C89
178+ #endif
179+#endif
180+
181+#if defined(RGFW_EGL) && !defined(RGFW_OPENGL)
182+ #define RGFW_OPENGL
183+#endif
184+
185+/* these OS macros look better & are standardized */
186+/* plus it helps with cross-compiling */
187+
188+#ifdef __EMSCRIPTEN__
189+ #define RGFW_WASM
190+#endif
191+
192+#if defined(RGFW_X11) && defined(__APPLE__) && !defined(RGFW_CUSTOM_BACKEND)
193+ #define RGFW_MACOS_X11
194+ #define RGFW_UNIX
195+#endif
196+
197+#if defined(_WIN32) && !defined(RGFW_X11) && !defined(RGFW_UNIX) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND) /* (if you're using X11 on windows some how) */
198+ #define RGFW_WINDOWS
199+#endif
200+#if defined(RGFW_WAYLAND)
201+ #define RGFW_DEBUG /* wayland will be in debug mode by default for now */
202+ #define RGFW_UNIX
203+ #ifdef RGFW_OPENGL
204+ #define RGFW_EGL
205+ #endif
206+ #ifdef RGFW_X11
207+ #define RGFW_DYNAMIC
208+ #endif
209+#endif
210+#if (!defined(RGFW_WAYLAND) && !defined(RGFW_X11)) && (defined(__unix__) || defined(RGFW_MACOS_X11) || defined(RGFW_X11)) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND)
211+ #define RGFW_MACOS_X11
212+ #define RGFW_X11
213+ #define RGFW_UNIX
214+#elif defined(__APPLE__) && !defined(RGFW_MACOS_X11) && !defined(RGFW_X11) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND)
215+ #define RGFW_MACOS
216+#endif
217+
218+#ifndef RGFW_ASSERT
219+ #include <assert.h>
220+ #define RGFW_ASSERT assert
221+#endif
222+
223+#if !defined(__STDC_VERSION__)
224+ #define RGFW_C89
225+#endif
226+
227+#if !defined(RGFW_SNPRINTF) && (defined(RGFW_X11) || defined(RGFW_WAYLAND))
228+ /* required for X11 errors */
229+ #include <stdio.h>
230+ #define RGFW_SNPRINTF snprintf
231+#endif
232+
233+#ifndef RGFW_USERPTR
234+ #define RGFW_USERPTR NULL
235+#endif
236+
237+#ifndef RGFW_UNUSED
238+ #define RGFW_UNUSED(x) (void)(x)
239+#endif
240+
241+#ifndef RGFW_ROUND
242+ #define RGFW_ROUND(x) (i32)((x) >= 0 ? (x) + 0.5f : (x) - 0.5f)
243+#endif
244+
245+#ifndef RGFW_ROUNDF
246+ #define RGFW_ROUNDF(x) (float)((i32)((x) + ((x) < 0.0f ? -0.5f : 0.5f)))
247+#endif
248+
249+#ifndef RGFW_MIN
250+ #define RGFW_MIN(x, y) ((x < y) ? x : y)
251+#endif
252+
253+#ifndef RGFW_ALLOC
254+ #include <stdlib.h>
255+ #define RGFW_ALLOC malloc
256+ #define RGFW_FREE free
257+#endif
258+
259+#if !defined(RGFW_MEMCPY) || !defined(RGFW_STRNCMP) || !defined(RGFW_STRNCPY) || !defined(RGFW_MEMZERO)
260+ #include <string.h>
261+#endif
262+
263+#ifndef RGFW_MEMZERO
264+ #define RGFW_MEMZERO(ptr, num) memset(ptr, 0, num)
265+#endif
266+
267+#ifndef RGFW_MEMCPY
268+ #define RGFW_MEMCPY(dist, src, len) memcpy(dist, src, len)
269+#endif
270+
271+#ifndef RGFW_STRNCMP
272+ #define RGFW_STRNCMP(s1, s2, max) strncmp(s1, s2, max)
273+#endif
274+
275+#ifndef RGFW_STRNCPY
276+ #define RGFW_STRNCPY(dist, src, len) strncpy(dist, src, len)
277+#endif
278+
279+#ifndef RGFW_STRSTR
280+ #define RGFW_STRSTR(str, substr) strstr(str, substr)
281+#endif
282+
283+#ifndef RGFW_STRTOL
284+ /* required for X11 XDnD and X11 Monitor DPI */
285+ #include <stdlib.h>
286+ #define RGFW_STRTOL(str, endptr, base) strtol(str, endptr, base)
287+ #define RGFW_ATOF(num) atof(num)
288+#endif
289+
290+#if !defined(RGFW_PRINTF) && ( defined(RGFW_DEBUG) || defined(RGFW_WAYLAND) )
291+ /* required when using RGFW_DEBUG */
292+ #include <stdio.h>
293+ #define RGFW_PRINTF printf
294+#endif
295+
296+#ifndef RGFW_MAX_EVENTS
297+ #define RGFW_MAX_EVENTS 32
298+#endif
299+#ifndef RGFW_PREALLOCATED_MONITORS
300+ #define RGFW_PREALLOCATED_MONITORS 6 /* the number of preallocated monitors */
301+#elif defined(RGFW_NO_ALLOCATE_MONITORS) && (RGFW_PREALLOCATED_MONITORS == 0)
302+ #warning RGFW monitors have no place to be allocated
303+#endif
304+
305+#ifndef RGFW_COCOA_FRAME_NAME
306+ #define RGFW_COCOA_FRAME_NAME NULL
307+#endif
308+
309+#ifdef RGFW_WIN95 /* for windows 95 testing (not that it really works) */
310+ #define RGFW_NO_PASSTHROUGH
311+#endif
312+
313+#if defined(RGFW_EXPORT) || defined(RGFW_IMPORT)
314+ #if defined(_WIN32)
315+ #if defined(__TINYC__) && (defined(RGFW_EXPORT) || defined(RGFW_IMPORT))
316+ #define __declspec(x) __attribute__((x))
317+ #endif
318+
319+ #if defined(RGFW_EXPORT)
320+ #define RGFWDEF __declspec(dllexport)
321+ #else
322+ #define RGFWDEF __declspec(dllimport)
323+ #endif
324+ #else
325+ #if defined(RGFW_EXPORT)
326+ #define RGFWDEF __attribute__((visibility("default")))
327+ #endif
328+ #endif
329+ #ifndef RGFWDEF
330+ #define RGFWDEF
331+ #endif
332+#endif
333+
334+#ifndef RGFWDEF
335+ #ifdef RGFW_C89
336+ #define RGFWDEF __inline
337+ #else
338+ #define RGFWDEF inline
339+ #endif
340+#endif
341+
342+#if defined(__cplusplus) && !defined(__EMSCRIPTEN__)
343+ extern "C" {
344+#endif
345+
346+/* makes sure the header file part is only defined once by default */
347+#ifndef RGFW_HEADER
348+
349+#define RGFW_HEADER
350+
351+#include <stddef.h>
352+#ifndef RGFW_INT_DEFINED
353+ #ifdef RGFW_USE_INT /* optional for any system that might not have stdint.h */
354+ typedef unsigned char u8;
355+ typedef signed char i8;
356+ typedef unsigned short u16;
357+ typedef signed short i16;
358+ typedef unsigned long int u32;
359+ typedef signed long int i32;
360+ typedef unsigned long long u64;
361+ typedef signed long long i64;
362+ #else /* use stdint standard types instead of c "standard" types */
363+ #include <stdint.h>
364+
365+ typedef uint8_t u8;
366+ typedef int8_t i8;
367+ typedef uint16_t u16;
368+ typedef int16_t i16;
369+ typedef uint32_t u32;
370+ typedef int32_t i32;
371+ typedef uint64_t u64;
372+ typedef int64_t i64;
373+ #endif
374+ #define RGFW_INT_DEFINED
375+#endif
376+
377+typedef ptrdiff_t RGFW_ssize_t;
378+
379+#ifndef RGFW_BOOL_DEFINED
380+ #define RGFW_BOOL_DEFINED
381+ typedef u8 RGFW_bool;
382+#endif
383+
384+#define RGFW_BOOL(x) (RGFW_bool)((x) != 0) /* force a value to be 0 or 1 */
385+#define RGFW_TRUE (RGFW_bool)1
386+#define RGFW_FALSE (RGFW_bool)0
387+
388+#define RGFW_ENUM(type, name) type name; enum
389+#define RGFW_BIT(x) (1 << (x))
390+
391+#ifdef RGFW_VULKAN
392+
393+ #if defined(RGFW_WAYLAND) && defined(RGFW_X11)
394+ #define VK_USE_PLATFORM_WAYLAND_KHR
395+ #define VK_USE_PLATFORM_XLIB_KHR
396+ #define RGFW_VK_SURFACE ((RGFW_usingWayland()) ? ("VK_KHR_wayland_surface") : ("VK_KHR_xlib_surface"))
397+ #elif defined(RGFW_WAYLAND)
398+ #define VK_USE_PLATFORM_WAYLAND_KHR
399+ #define VK_USE_PLATFORM_XLIB_KHR
400+ #define RGFW_VK_SURFACE "VK_KHR_wayland_surface"
401+ #elif defined(RGFW_X11)
402+ #define VK_USE_PLATFORM_XLIB_KHR
403+ #define RGFW_VK_SURFACE "VK_KHR_xlib_surface"
404+ #elif defined(RGFW_WINDOWS)
405+ #define VK_USE_PLATFORM_WIN32_KHR
406+ #define OEMRESOURCE
407+ #define RGFW_VK_SURFACE "VK_KHR_win32_surface"
408+ #elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11)
409+ #define VK_USE_PLATFORM_MACOS_MVK
410+ #define RGFW_VK_SURFACE "VK_MVK_macos_surface"
411+ #else
412+ #define RGFW_VK_SURFACE NULL
413+ #endif
414+
415+#endif
416+
417+
418+/*! @brief The stucture that contains information about the current RGFW instance */
419+typedef struct RGFW_info RGFW_info;
420+
421+/*! @brief The window stucture for interfacing with the window */
422+typedef struct RGFW_window RGFW_window;
423+
424+/*! @brief The source window stucture for interfacing with the underlying windowing API (e.g. winapi, wayland, cocoa, etc) */
425+typedef struct RGFW_window_src RGFW_window_src;
426+
427+/*! @brief The color format for pixel data */
428+typedef RGFW_ENUM(u8, RGFW_format) {
429+ RGFW_formatRGB8 = 0, /*!< 8-bit RGB (3 channels) */
430+ RGFW_formatBGR8, /*!< 8-bit BGR (3 channels) */
431+ RGFW_formatRGBA8, /*!< 8-bit RGBA (4 channels) */
432+ RGFW_formatARGB8, /*!< 8-bit RGBA (4 channels) */
433+ RGFW_formatBGRA8, /*!< 8-bit BGRA (4 channels) */
434+ RGFW_formatABGR8, /*!< 8-bit BGRA (4 channels) */
435+ RGFW_formatCount
436+};
437+
438+/*! @brief layout struct for mapping out format types */
439+typedef struct RGFW_colorLayout { i32 r, g, b, a; u32 channels; } RGFW_colorLayout;
440+
441+/*! @brief function type converting raw image data between formats */
442+typedef void (* RGFW_convertImageDataFunc)(u8* dest_data, u8* src_data, const RGFW_colorLayout* srcLayout, const RGFW_colorLayout* destLayout, size_t count);
443+
444+/*! @brief a stucture for interfacing with the underlying native image (e.g. XImage, HBITMAP, etc) */
445+typedef struct RGFW_nativeImage RGFW_nativeImage;
446+
447+/*! @brief a stucture for interfacing with pixel data as a renderable surface */
448+typedef struct RGFW_surface RGFW_surface;
449+
450+/*! @brief gamma struct for monitors */
451+typedef struct RGFW_gammaRamp {
452+ u16* red; /*!< array for the red channel */
453+ u16* green; /*!< array for the green channel */
454+ u16* blue; /*!< array for the blue channel */
455+ size_t count; /*! count of elements in each channel */
456+} RGFW_gammaRamp;
457+
458+/*! @brief monitor mode data | can be changed by the user (with functions)*/
459+typedef struct RGFW_monitorMode {
460+ i32 w, h; /*!< monitor workarea size */
461+ float refreshRate; /*!< monitor refresh rate */
462+ u8 red, blue, green; /*!< sizeof rgb values */
463+ void* src; /*!< source API mode */
464+} RGFW_monitorMode;
465+
466+/*! @brief structure for monitor node and source monitor data */
467+typedef struct RGFW_monitorNode RGFW_monitorNode;
468+
469+/*! @brief structure for monitor data */
470+typedef struct RGFW_monitor {
471+ i32 x, y; /*!< x - y of the monitor workarea */
472+ char name[128]; /*!< monitor name */
473+ float scaleX, scaleY; /*!< monitor content scale */
474+ float pixelRatio; /*!< pixel ratio for monitor (1.0 for regular, 2.0 for hiDPI) */
475+ float physW, physH; /*!< monitor physical size in inches */
476+ RGFW_monitorMode mode; /*!< current mode of the monitor */
477+ void* userPtr; /*!< pointer for user data */
478+ RGFW_monitorNode* node; /*!< source node data of the monitor */
479+} RGFW_monitor;
480+
481+/*! @brief what type of request you are making for the monitor */
482+typedef RGFW_ENUM(u8, RGFW_modeRequest) {
483+ RGFW_monitorScale = RGFW_BIT(0), /*!< scale the monitor size */
484+ RGFW_monitorRefresh = RGFW_BIT(1), /*!< change the refresh rate */
485+ RGFW_monitorRGB = RGFW_BIT(2), /*!< change the monitor RGB bits size */
486+ RGFW_monitorAll = RGFW_monitorScale | RGFW_monitorRefresh | RGFW_monitorRGB
487+};
488+
489+/*! a raw pointer to the underlying mouse handle for setting and creating custom mouse icons */
490+typedef void RGFW_mouse;
491+
492+/*! @brief RGFW's abstract keycodes */
493+typedef RGFW_ENUM(u8, RGFW_key) {
494+ RGFW_keyNULL = 0,
495+ RGFW_keyEscape = '\033',
496+ RGFW_keyBacktick = '`',
497+ RGFW_key0 = '0',
498+ RGFW_key1 = '1',
499+ RGFW_key2 = '2',
500+ RGFW_key3 = '3',
501+ RGFW_key4 = '4',
502+ RGFW_key5 = '5',
503+ RGFW_key6 = '6',
504+ RGFW_key7 = '7',
505+ RGFW_key8 = '8',
506+ RGFW_key9 = '9',
507+ RGFW_keyMinus = '-',
508+ RGFW_keyEqual = '=',
509+ RGFW_keyEquals = RGFW_keyEqual,
510+ RGFW_keyBackSpace = '\b',
511+ RGFW_keyTab = '\t',
512+ RGFW_keySpace = ' ',
513+ RGFW_keyA = 'a',
514+ RGFW_keyB = 'b',
515+ RGFW_keyC = 'c',
516+ RGFW_keyD = 'd',
517+ RGFW_keyE = 'e',
518+ RGFW_keyF = 'f',
519+ RGFW_keyG = 'g',
520+ RGFW_keyH = 'h',
521+ RGFW_keyI = 'i',
522+ RGFW_keyJ = 'j',
523+ RGFW_keyK = 'k',
524+ RGFW_keyL = 'l',
525+ RGFW_keyM = 'm',
526+ RGFW_keyN = 'n',
527+ RGFW_keyO = 'o',
528+ RGFW_keyP = 'p',
529+ RGFW_keyQ = 'q',
530+ RGFW_keyR = 'r',
531+ RGFW_keyS = 's',
532+ RGFW_keyT = 't',
533+ RGFW_keyU = 'u',
534+ RGFW_keyV = 'v',
535+ RGFW_keyW = 'w',
536+ RGFW_keyX = 'x',
537+ RGFW_keyY = 'y',
538+ RGFW_keyZ = 'z',
539+ RGFW_keyPeriod = '.',
540+ RGFW_keyComma = ',',
541+ RGFW_keySlash = '/',
542+ RGFW_keyBracket = '[',
543+ RGFW_keyCloseBracket = ']',
544+ RGFW_keySemicolon = ';',
545+ RGFW_keyApostrophe = '\'',
546+ RGFW_keyBackSlash = '\\',
547+ RGFW_keyReturn = '\n',
548+ RGFW_keyEnter = RGFW_keyReturn,
549+ RGFW_keyDelete = '\177', /* 127 */
550+ RGFW_keyF1,
551+ RGFW_keyF2,
552+ RGFW_keyF3,
553+ RGFW_keyF4,
554+ RGFW_keyF5,
555+ RGFW_keyF6,
556+ RGFW_keyF7,
557+ RGFW_keyF8,
558+ RGFW_keyF9,
559+ RGFW_keyF10,
560+ RGFW_keyF11,
561+ RGFW_keyF12,
562+ RGFW_keyF13,
563+ RGFW_keyF14,
564+ RGFW_keyF15,
565+ RGFW_keyF16,
566+ RGFW_keyF17,
567+ RGFW_keyF18,
568+ RGFW_keyF19,
569+ RGFW_keyF20,
570+ RGFW_keyF21,
571+ RGFW_keyF22,
572+ RGFW_keyF23,
573+ RGFW_keyF24,
574+ RGFW_keyF25,
575+ RGFW_keyCapsLock,
576+ RGFW_keyShiftL,
577+ RGFW_keyControlL,
578+ RGFW_keyAltL,
579+ RGFW_keySuperL,
580+ RGFW_keyShiftR,
581+ RGFW_keyControlR,
582+ RGFW_keyAltR,
583+ RGFW_keySuperR,
584+ RGFW_keyUp,
585+ RGFW_keyDown,
586+ RGFW_keyLeft,
587+ RGFW_keyRight,
588+ RGFW_keyInsert,
589+ RGFW_keyMenu,
590+ RGFW_keyEnd,
591+ RGFW_keyHome,
592+ RGFW_keyPageUp,
593+ RGFW_keyPageDown,
594+ RGFW_keyNumLock,
595+ RGFW_keyPadSlash,
596+ RGFW_keyPadMultiply,
597+ RGFW_keyPadPlus,
598+ RGFW_keyPadMinus,
599+ RGFW_keyPadEqual,
600+ RGFW_keyPadEquals = RGFW_keyPadEqual,
601+ RGFW_keyPad1,
602+ RGFW_keyPad2,
603+ RGFW_keyPad3,
604+ RGFW_keyPad4,
605+ RGFW_keyPad5,
606+ RGFW_keyPad6,
607+ RGFW_keyPad7,
608+ RGFW_keyPad8,
609+ RGFW_keyPad9,
610+ RGFW_keyPad0,
611+ RGFW_keyPadPeriod,
612+ RGFW_keyPadReturn,
613+ RGFW_keyScrollLock,
614+ RGFW_keyPrintScreen,
615+ RGFW_keyPause,
616+ RGFW_keyWorld1,
617+ RGFW_keyWorld2,
618+ RGFW_keyLast = 256 /* padding for alignment ~(175 by default) */
619+};
620+
621+/*! @brief abstract mouse button codes */
622+typedef RGFW_ENUM(u8, RGFW_mouseButton) {
623+ RGFW_mouseLeft = 0, /*!< left mouse button is pressed */
624+ RGFW_mouseMiddle, /*!< mouse-wheel-button is pressed */
625+ RGFW_mouseRight, /*!< right mouse button is pressed */
626+ RGFW_mouseMisc1, RGFW_mouseMisc2, RGFW_mouseMisc3, RGFW_mouseMisc4, RGFW_mouseMisc5,
627+ RGFW_mouseFinal
628+};
629+
630+/*! abstract key modifier codes */
631+typedef RGFW_ENUM(u8, RGFW_keymod) {
632+ RGFW_modCapsLock = RGFW_BIT(0),
633+ RGFW_modNumLock = RGFW_BIT(1),
634+ RGFW_modControl = RGFW_BIT(2),
635+ RGFW_modAlt = RGFW_BIT(3),
636+ RGFW_modShift = RGFW_BIT(4),
637+ RGFW_modSuper = RGFW_BIT(5),
638+ RGFW_modScrollLock = RGFW_BIT(6)
639+};
640+
641+/*! types of dnd drag actions */
642+typedef RGFW_ENUM(u8, RGFW_dndActionType) {
643+ RGFW_dndActionNone = 0,
644+ RGFW_dndActionEnter, /*!< data has been dragged into the window area */
645+ RGFW_dndActionMove, /*!< the data that was dragged into the window area has moved inside the window */
646+ RGFW_dndActionExit, /*!< the data that was dragged into the window area has left the window */
647+};
648+
649+/*! types of transfered data (clipboard, dnd) */
650+typedef RGFW_ENUM(u8, RGFW_dataTransferType) {
651+ RGFW_dataNone = 0,
652+ RGFW_dataText, /*!< plain text string */
653+ RGFW_dataFile, /*!< file string */
654+ RGFW_dataURL, /*!< URL string */
655+ RGFW_dataImage, /*!< raw image data */
656+ RGFW_dataUnknown /*!< unknown raw data */
657+};
658+
659+/*! internal node for a individual data drop */
660+typedef struct RGFW_dataDropNode {
661+ const char* data; /*!< dropped data */
662+ size_t size; /*!< the size of the data in bytes */
663+ RGFW_dataTransferType type; /*!< the type of data being dropped */
664+ struct RGFW_dataDropNode* next; /*!< the next drop data node if any [when handling callbacks, this will always be NULL because the linked list is built as events are processed] */
665+} RGFW_dataDropNode;
666+
667+/*! @brief codes for the event types that can be sent */
668+typedef RGFW_ENUM(u8, RGFW_eventType) {
669+ RGFW_eventNone = 0, /*!< no event has been sent */
670+ RGFW_keyPressed, /*!< a key has been pressed */
671+ RGFW_keyReleased, /*!< a key has been released */
672+ RGFW_keyChar, /*!< keyboard character input event specifically for utf8 input */
673+ RGFW_mouseButtonPressed, /*!< a mouse button has been pressed (left,middle,right) */
674+ RGFW_mouseButtonReleased, /*!< a mouse button has been released (left,middle,right) */
675+ RGFW_mouseScroll, /*!< a mouse scroll event */
676+ RGFW_mousePosChanged, /*!< the position of the mouse has been changed */
677+ RGFW_mouseRawMotion, /*!< raw mouse motion */
678+ RGFW_mouseEnter, /*!< mouse entered the window */
679+ RGFW_mouseLeave, /*!< mouse left the window */
680+ RGFW_windowMoved, /*!< the window was moved (by the user) */
681+ RGFW_windowResized, /*!< the window was resized (by the user), [on WASM this means the browser was resized] */
682+ RGFW_windowFocusIn, /*!< window is in focus now */
683+ RGFW_windowFocusOut, /*!< window is out of focus now */
684+ RGFW_windowRefresh, /*!< The window content needs to be refreshed */
685+ RGFW_windowClose, /*!< the user attempts to close the window */
686+ RGFW_windowMaximized, /*!< the window was maximized */
687+ RGFW_windowMinimized, /*!< the window was minimized */
688+ RGFW_windowRestored, /*!< the window was restored */
689+ RGFW_dataDrop, /*!< data has been dropped into the window */
690+ RGFW_dataDrag, /*!< the start of a drag and drop event, when data is being dragged */
691+ RGFW_scaleUpdated, /*!< content scale factor changed */
692+ RGFW_monitorConnected, /*!< a monitor has been connected */
693+ RGFW_monitorDisconnected, /*!< a monitor has been disconnected */
694+ RGFW_eventCount /*!< the number of event types there are */
695+};
696+
697+/*! @brief flags for toggling whether or not an event should be processed */
698+typedef RGFW_ENUM(u32, RGFW_eventFlag) {
699+ RGFW_keyPressedFlag = RGFW_BIT(RGFW_keyPressed),
700+ RGFW_keyReleasedFlag = RGFW_BIT(RGFW_keyReleased),
701+ RGFW_keyCharFlag = RGFW_BIT(RGFW_keyChar),
702+ RGFW_mouseScrollFlag = RGFW_BIT(RGFW_mouseScroll),
703+ RGFW_mouseButtonPressedFlag = RGFW_BIT(RGFW_mouseButtonPressed),
704+ RGFW_mouseButtonReleasedFlag = RGFW_BIT(RGFW_mouseButtonReleased),
705+ RGFW_mousePosChangedFlag = RGFW_BIT(RGFW_mousePosChanged),
706+ RGFW_mouseRawMotionFlag = RGFW_BIT(RGFW_mouseRawMotion),
707+ RGFW_mouseEnterFlag = RGFW_BIT(RGFW_mouseEnter),
708+ RGFW_mouseLeaveFlag = RGFW_BIT(RGFW_mouseLeave),
709+ RGFW_windowMovedFlag = RGFW_BIT(RGFW_windowMoved),
710+ RGFW_windowResizedFlag = RGFW_BIT(RGFW_windowResized),
711+ RGFW_windowFocusInFlag = RGFW_BIT(RGFW_windowFocusIn),
712+ RGFW_windowFocusOutFlag = RGFW_BIT(RGFW_windowFocusOut),
713+ RGFW_windowRefreshFlag = RGFW_BIT(RGFW_windowRefresh),
714+ RGFW_windowMaximizedFlag = RGFW_BIT(RGFW_windowMaximized),
715+ RGFW_windowMinimizedFlag = RGFW_BIT(RGFW_windowMinimized),
716+ RGFW_windowRestoredFlag = RGFW_BIT(RGFW_windowRestored),
717+ RGFW_scaleUpdatedFlag = RGFW_BIT(RGFW_scaleUpdated),
718+ RGFW_windowCloseFlag = RGFW_BIT(RGFW_windowClose),
719+ RGFW_dataDropFlag = RGFW_BIT(RGFW_dataDrop),
720+ RGFW_dataDragFlag = RGFW_BIT(RGFW_dataDrag),
721+ RGFW_monitorConnectedFlag = RGFW_BIT(RGFW_monitorConnected),
722+ RGFW_monitorDisconnectedFlag = RGFW_BIT(RGFW_monitorDisconnected),
723+
724+ RGFW_keyEventsFlag = RGFW_keyPressedFlag | RGFW_keyReleasedFlag | RGFW_keyCharFlag,
725+ RGFW_mouseEventsFlag = RGFW_mouseButtonPressedFlag | RGFW_mouseButtonReleasedFlag | RGFW_mousePosChangedFlag | RGFW_mouseEnterFlag | RGFW_mouseLeaveFlag | RGFW_mouseScrollFlag | RGFW_mouseRawMotionFlag,
726+ RGFW_windowEventsFlag = RGFW_windowMovedFlag | RGFW_windowResizedFlag | RGFW_windowRefreshFlag | RGFW_windowMaximizedFlag | RGFW_windowMinimizedFlag | RGFW_windowRestoredFlag | RGFW_scaleUpdatedFlag,
727+ RGFW_windowFocusEventsFlag = RGFW_windowFocusInFlag | RGFW_windowFocusOutFlag,
728+ RGFW_dataDragDropEventsFlag = RGFW_dataDropFlag | RGFW_dataDragFlag,
729+ RGFW_monitorEventsFlag = RGFW_monitorConnectedFlag | RGFW_monitorDisconnectedFlag,
730+ RGFW_allEventFlags = RGFW_keyEventsFlag | RGFW_mouseEventsFlag | RGFW_windowEventsFlag | RGFW_windowFocusEventsFlag | RGFW_dataDragDropEventsFlag | RGFW_windowCloseFlag | RGFW_monitorEventsFlag
731+};
732+
733+/*! Event structure(s) and union for checking/getting events */
734+
735+/*! @brief common event data across all events */
736+typedef struct RGFW_commonEvent {
737+ RGFW_eventType type; /*!< which event has been sent?*/
738+ RGFW_window* win; /*!< the window this event applies to (for event queue events) */
739+} RGFW_commonEvent;
740+
741+/*! @brief event data for all focus events */
742+typedef struct RGFW_windowFocusEvent {
743+ RGFW_eventType type; /*!< which event has been sent?*/
744+ RGFW_window* win; /*!< the window this event applies to (for event queue events) */
745+ RGFW_bool state; /*!< wether or not the window is in focus or not */
746+} RGFW_windowFocusEvent;
747+
748+/*! @brief event data for any mouse button event (press/release) */
749+typedef struct RGFW_mouseButtonEvent {
750+ RGFW_eventType type; /*!< which event has been sent?*/
751+ RGFW_window* win; /*!< the window this event applies to (for event queue events) */
752+ RGFW_mouseButton value; /* !< which mouse button was pressed */
753+ RGFW_bool state; /*!< if the button was pressed or released */
754+} RGFW_mouseButtonEvent;
755+
756+/*! @brief event data for any mouse scroll or raw motion event */
757+typedef struct RGFW_mouseDeltaEvent {
758+ RGFW_eventType type; /*!< which event has been sent?*/
759+ RGFW_window* win; /*!< the window this event applies to (for event queue events) */
760+ float x, y; /*!< the raw mouse scroll or motion delta value */
761+} RGFW_mouseDeltaEvent;
762+
763+/*! @brief event data for a mouse position event (RGFW_mousePosChanged) */
764+typedef struct RGFW_mousePosEvent {
765+ RGFW_eventType type; /*!< which event has been sent?*/
766+ RGFW_window* win; /*!< the window this event applies to (for event queue events) */
767+ i32 x, y; /*!< mouse x, y of event (or drop point) */
768+ RGFW_bool inWindow; /*!< if the mouse is in the window or not */
769+} RGFW_mousePosEvent;
770+
771+/*! @brief event data for a key press/release event */
772+typedef struct RGFW_keyEvent {
773+ RGFW_eventType type; /*!< which event has been sent?*/
774+ RGFW_window* win; /*!< the window this event applies to (for event queue events) */
775+ RGFW_key value; /*!< the physical key of the event, refers to where key is physically */
776+ RGFW_bool repeat; /*!< key press event repeated (the key is being held) */
777+ RGFW_keymod mod; /*!< state of the key modifier state */
778+ RGFW_bool state; /*!< if the key was pressed or released */
779+} RGFW_keyEvent;
780+
781+/*! @brief event data for a key character event */
782+typedef struct RGFW_keyCharEvent {
783+ RGFW_eventType type; /*!< which event has been sent?*/
784+ RGFW_window* win; /*!< the window this event applies to (for event queue events) */
785+ u32 value; /*!< the unicode value of the key */
786+} RGFW_keyCharEvent;
787+
788+/*! @brief event data for any data drop event */
789+typedef struct RGFW_dataDropEvent {
790+ RGFW_eventType type; /*!< which event has been sent?*/
791+ RGFW_window* win; /*!< the window this event applies to (for event queue events) */
792+ const RGFW_dataDropNode* value;
793+} RGFW_dataDropEvent;
794+
795+/*! @brief event data for any data drag event */
796+typedef struct RGFW_dataDragEvent {
797+ RGFW_eventType type; /*!< which event has been sent?*/
798+ RGFW_window* win; /*!< the window this event applies to (for event queue events) */
799+ i32 x, y; /*!< mouse x, y of event (or drop point) */
800+ RGFW_dndActionType action; /*!< the type of drag action, e.g. enter, leave, move */
801+ RGFW_dataTransferType dataType; /*!< the type of data being dragged*/
802+} RGFW_dataDragEvent;
803+
804+/*! @brief event data for when the window scale (DPI) is updated */
805+typedef struct RGFW_scaleUpdatedEvent {
806+ RGFW_eventType type; /*!< which event has been sent?*/
807+ RGFW_window* win; /*!< the window this event applies to (for event queue events) */
808+ float x, y; /*!< DPI scaling */
809+} RGFW_scaleUpdatedEvent;
810+
811+/*! @brief event data for when a monitor is connected, disconnected or updated */
812+typedef struct RGFW_monitorEvent {
813+ RGFW_eventType type; /*!< which event has been sent?*/
814+ RGFW_window* win; /*!< the window this event applies to (for event queue events) */
815+ const RGFW_monitor* monitor; /*!< the monitor that this event applies to */
816+ RGFW_bool state; /*!< if the monitor is connected or disconnected */
817+} RGFW_monitorEvent;
818+
819+/*! @breif event data for when the window is updated, moved, resized or refreshed */
820+typedef struct RGFW_windowUpdateEvent {
821+ RGFW_eventType type; /*!< the specific event type */
822+ RGFW_window* win; /*!< the window that was updated */
823+ i32 x; /*!< the new window x OR the x of the rectanglular refresh area */
824+ i32 y; /*!< the new window y OR the y of the rectanglular refresh area */
825+ i32 w; /*!< the new window width OR the width of the rectanglular refresh area */
826+ i32 h; /*!< the new window height OR the height of the rectanglular refresh area */
827+} RGFW_windowUpdateEvent;
828+
829+/*! @brief union for all of the event stucture types */
830+typedef union RGFW_event {
831+ RGFW_eventType type; /*!< which event has been sent?*/
832+ RGFW_commonEvent common; /*!< common event data (e.g.) type and win */
833+ RGFW_windowFocusEvent focus; /*!< event data for focus in/out events */
834+ RGFW_windowUpdateEvent update; /*!< data for window update/move/resize/refresh events */
835+ RGFW_mouseButtonEvent button; /*!< data for a button press/release */
836+ RGFW_mouseDeltaEvent delta; /*!< data for a mouse scroll or raw motion */
837+ RGFW_mousePosEvent mouse; /*!< data for mouse motion events */
838+ RGFW_keyEvent key; /*!< data for key press/release/hold events */
839+ RGFW_keyCharEvent keyChar; /*!< data for key character events */
840+ RGFW_dataDropEvent drop; /*!< data dropping events */
841+ RGFW_dataDragEvent drag; /*!< data for data dragging events */
842+ RGFW_scaleUpdatedEvent scale; /*!< data for dpi scaling update events */
843+ RGFW_monitorEvent monitor; /*!< data for monitor events */
844+} RGFW_event;
845+
846+/*!
847+ @!brief codes for for RGFW_the code is stupid and C++ waitForEvent
848+ waitMS -> Allows the function to keep checking for events even after there are no more events
849+ if waitMS == 0, the loop will not wait for events
850+ if waitMS > 0, the loop will wait that many miliseconds after there are no more events until it returns
851+ if waitMS == -1 or waitMS == the max size of an unsigned 32-bit int, the loop will not return until it gets another event
852+*/
853+typedef RGFW_ENUM(i32, RGFW_eventWait) {
854+ RGFW_eventNoWait = 0,
855+ RGFW_eventWaitNext = -1
856+};
857+
858+/*! @brief generic event callback function type */
859+typedef void (*RGFW_genericFunc)(const RGFW_event* e);
860+
861+/*! brief structure that holds an array to callback data*/
862+typedef struct RGFW_callbacks {
863+ RGFW_genericFunc arr[RGFW_eventCount]; /*!< an array of all the callbacks */
864+} RGFW_callbacks;
865+
866+/*! @brief optional bitwise arguments for making a windows, these can be OR'd together */
867+typedef RGFW_ENUM(u32, RGFW_windowFlags) {
868+ RGFW_windowNoBorder = RGFW_BIT(0), /*!< the window doesn't have a border / frame / decor */
869+ RGFW_windowNoResize = RGFW_BIT(1), /*!< the window cannot be resized by the user */
870+ RGFW_windowAllowDND = RGFW_BIT(2), /*!< the window supports drag and drop */
871+ RGFW_windowHideMouse = RGFW_BIT(3), /*! the window should hide the mouse (can be toggled later on using `RGFW_window_showMouse`) */
872+ RGFW_windowFullscreen = RGFW_BIT(4), /*!< the window is fullscreen by default */
873+ RGFW_windowTranslucent = RGFW_BIT(5), /*!< the window is translucent (only properly works on X11 and MacOS, although it's meant for for windows) */
874+ RGFW_windowTransparent = RGFW_windowTranslucent, /*!< the window is translucent (only properly works on X11 and MacOS, although it's meant for for windows) */
875+ RGFW_windowCenter = RGFW_BIT(6), /*! center the window on the screen */
876+ RGFW_windowRawMouse = RGFW_BIT(7), /*!< use raw mouse mouse on window creation */
877+ RGFW_windowScaleToMonitor = RGFW_BIT(8), /*! scale the window to the screen */
878+ RGFW_windowHide = RGFW_BIT(9), /*! the window is hidden */
879+ RGFW_windowMaximize = RGFW_BIT(10), /*!< maximize the window on creation */
880+ RGFW_windowCenterCursor = RGFW_BIT(11), /*!< center the cursor to the window on creation */
881+ RGFW_windowFloating = RGFW_BIT(12), /*!< create a floating window */
882+ RGFW_windowFocusOnShow = RGFW_BIT(13), /*!< focus the window when it's shown */
883+ RGFW_windowMinimize = RGFW_BIT(14), /*!< focus the window when it's shown */
884+ RGFW_windowFocus = RGFW_BIT(15), /*!< if the window is in focus */
885+ RGFW_windowCaptureMouse = RGFW_BIT(16), /*!< capture the mouse mouse mouse on window creation */
886+ RGFW_windowOpenGL = RGFW_BIT(17), /*!< create an OpenGL context (you can also do this manually with RGFW_window_createContext_OpenGL) */
887+ RGFW_windowEGL = RGFW_BIT(18), /*!< create an EGL context (you can also do this manually with RGFW_window_createContext_EGL) */
888+ RGFW_noDeinitOnClose = RGFW_BIT(19), /*!< do not auto deinit RGFW if the window closes and this is the last window open */
889+ RGFW_windowedFullscreen = RGFW_windowNoBorder | RGFW_windowMaximize,
890+ RGFW_windowCaptureRawMouse = RGFW_windowCaptureMouse | RGFW_windowRawMouse
891+};
892+
893+/*! @brief the types of icon to set */
894+typedef RGFW_ENUM(u8, RGFW_icon) {
895+ RGFW_iconTaskbar = RGFW_BIT(0),
896+ RGFW_iconWindow = RGFW_BIT(1),
897+ RGFW_iconBoth = RGFW_iconTaskbar | RGFW_iconWindow
898+};
899+
900+/*! @brief standard mouse icons */
901+typedef RGFW_ENUM(u8, RGFW_mouseIcon) {
902+ RGFW_mouseNormal = 0,
903+ RGFW_mouseArrow,
904+ RGFW_mouseIbeam,
905+ RGFW_mouseText = RGFW_mouseIbeam,
906+ RGFW_mouseCrosshair,
907+ RGFW_mousePointingHand,
908+ RGFW_mouseResizeEW,
909+ RGFW_mouseResizeNS,
910+ RGFW_mouseResizeNWSE,
911+ RGFW_mouseResizeNESW,
912+ RGFW_mouseResizeNW,
913+ RGFW_mouseResizeN,
914+ RGFW_mouseResizeNE,
915+ RGFW_mouseResizeE,
916+ RGFW_mouseResizeSE,
917+ RGFW_mouseResizeS,
918+ RGFW_mouseResizeSW,
919+ RGFW_mouseResizeW,
920+ RGFW_mouseResizeAll,
921+ RGFW_mouseNotAllowed,
922+ RGFW_mouseWait,
923+ RGFW_mouseProgress,
924+ RGFW_mouseIconCount,
925+ RGFW_mouseIconFinal = 16 /* padding for alignment */
926+};
927+
928+/*! @breif flash request type */
929+typedef RGFW_ENUM(u8, RGFW_flashRequest) {
930+ RGFW_flashCancel = 0,
931+ RGFW_flashBriefly,
932+ RGFW_flashUntilFocused
933+};
934+
935+/*! @brief the type of debug message */
936+typedef RGFW_ENUM(u8, RGFW_debugType) {
937+ RGFW_typeError = 0, RGFW_typeWarning, RGFW_typeInfo
938+};
939+
940+/*! @brief error codes for known failure types */
941+typedef RGFW_ENUM(u8, RGFW_errorCode) {
942+ RGFW_noError = 0, /*!< no error */
943+ RGFW_errOutOfMemory,
944+ RGFW_errOpenGLContext, RGFW_errEGLContext, /*!< error with the OpenGL context */
945+ RGFW_errWayland, RGFW_errX11,
946+ RGFW_errDirectXContext,
947+ RGFW_errIOKit,
948+ RGFW_errClipboard,
949+ RGFW_errFailedFuncLoad,
950+ RGFW_errBuffer,
951+ RGFW_errMetal,
952+ RGFW_errPlatform,
953+ RGFW_errEventQueue,
954+ RGFW_infoWindow, RGFW_infoBuffer, RGFW_infoGlobal, RGFW_infoOpenGL,
955+ RGFW_warningWayland, RGFW_warningOpenGL
956+};
957+
958+/*! @brief data for debug messages */
959+typedef struct RGFW_debugInfo {
960+ RGFW_debugType type; /*!< the type of message */
961+ RGFW_errorCode code; /*!< the code for the specific type of debug message */
962+ const char* msg; /*!< string message */
963+} RGFW_debugInfo;
964+
965+/*! @brief callback function type for debug messags */
966+typedef void (* RGFW_debugFunc)(const RGFW_debugInfo* info);
967+
968+/*! @brief function pointer equivalent of void* */
969+typedef void (*RGFW_proc)(void);
970+
971+#if defined(RGFW_OPENGL)
972+
973+/*! @brief abstract structure for interfacing with the underlying OpenGL API */
974+typedef struct RGFW_glContext RGFW_glContext;
975+
976+/*! @brief abstract structure for interfacing with the underlying EGL API */
977+typedef struct RGFW_eglContext RGFW_eglContext;
978+
979+/*! values for the releaseBehavior hint */
980+typedef RGFW_ENUM(i32, RGFW_glReleaseBehavior) {
981+ RGFW_glReleaseFlush = 0, /*!< flush the pipeline will be flushed when the context is release */
982+ RGFW_glReleaseNone /*!< do nothing on release */
983+};
984+
985+/*! values for the profile hint */
986+typedef RGFW_ENUM(i32, RGFW_glProfile) {
987+ RGFW_glCore = 0, /*!< the core OpenGL version, e.g. just support for that version */
988+ RGFW_glForwardCompatibility, /*!< only compatibility for newer versions of OpenGL as well as the requested version */
989+ RGFW_glCompatibility, /*!< allow compatibility for older versions of OpenGL as well as the requested version */
990+ RGFW_glES, /*!< use OpenGL ES */
991+ RGFW_glWeb /*!< use WebGL version (otherwise the version is changed to match it's GLES equivalent) */
992+};
993+
994+/*! values for the renderer hint */
995+typedef RGFW_ENUM(i32, RGFW_glRenderer) {
996+ RGFW_glAccelerated = 0, /*!< hardware accelerated (GPU) */
997+ RGFW_glSoftware /*!< software rendered (CPU) */
998+};
999+
1000+/*! OpenGL initalization hints */
1001+typedef struct RGFW_glHints {
1002+ i32 stencil; /*!< set stencil buffer bit size (0 by default) */
1003+ i32 samples; /*!< set number of sample buffers (0 by default) */
1004+ i32 stereo; /*!< hint the context to use stereoscopic frame buffers for 3D (false by default) */
1005+ i32 auxBuffers; /*!< number of aux buffers (0 by default) */
1006+ i32 doubleBuffer; /*!< request double buffering (true by default) */
1007+ i32 red, green, blue, alpha; /*!< set color bit sizes (all 8 by default) */
1008+ i32 depth; /*!< set depth buffer bit size (24 by default) */
1009+ i32 accumRed, accumGreen, accumBlue, accumAlpha; /*!< set accumulated RGBA bit sizes (all 0 by default) */
1010+ RGFW_bool sRGB; /*!< request sRGA format (false by default) */
1011+ RGFW_bool robustness; /*!< request a "robust" (as in memory-safe) context (false by default). For more information check the overview section: https://registry.khronos.org/OpenGL/extensions/EXT/EXT_robustness.txt */
1012+ RGFW_bool debug; /*!< request OpenGL debugging (false by default). */
1013+ RGFW_bool noError; /*!< request no OpenGL errors (false by default). This causes OpenGL errors to be undefined behavior. For more information check the overview section: https://registry.khronos.org/OpenGL/extensions/KHR/KHR_no_error.txt */
1014+ RGFW_glReleaseBehavior releaseBehavior; /*!< hint how the OpenGL driver should behave when changing contexts (RGFW_glReleaseNone by default). For more information check the overview section: https://registry.khronos.org/OpenGL/extensions/KHR/KHR_context_flush_control.txt */
1015+ RGFW_glProfile profile; /*!< set OpenGL API profile (RGFW_glCore by default) */
1016+ i32 major, minor; /*!< set the OpenGL API profile version (by default RGFW_glMajor is 1, RGFW_glMinor is 0) */
1017+ RGFW_glContext* share; /*!< Share this OpenGL context with newly created OpenGL contexts; defaults to NULL. */
1018+ RGFW_eglContext* shareEGL; /*!< Share this EGL context with newly created OpenGL contexts; defaults to NULL. */
1019+ RGFW_glRenderer renderer; /*!< renderer to use e.g. accelerated or software defaults to accelerated */
1020+} RGFW_glHints;
1021+
1022+#endif
1023+
1024+/**!
1025+ * @brief Allocates memory using the allocator defined by RGFW_ALLOC at compile time.
1026+ * @param size The size (in bytes) of the memory block to allocate.
1027+ * @return A pointer to the allocated memory block.
1028+*/
1029+RGFWDEF void* RGFW_alloc(size_t size);
1030+
1031+/**!
1032+ * @brief Frees memory using the deallocator defined by RGFW_FREE at compile time.
1033+ * @param ptr A pointer to the memory block to free.
1034+*/
1035+RGFWDEF void RGFW_free(void* ptr);
1036+
1037+/**!
1038+ * @brief Returns the size (in bytes) of the RGFW_window structure.
1039+ * @return The size of the RGFW_window structure.
1040+*/
1041+RGFWDEF size_t RGFW_sizeofWindow(void);
1042+
1043+/**!
1044+ * @brief Returns the size (in bytes) of the RGFW_window_src structure.
1045+ * @return The size of the RGFW_window_src structure.
1046+*/
1047+RGFWDEF size_t RGFW_sizeofWindowSrc(void);
1048+
1049+/**!
1050+ * @brief (Unix) Toggles the use of Wayland.
1051+ * This is enabled by default when compiled with `RGFW_WAYLAND`.
1052+ * If not using `RGFW_WAYLAND`, Wayland functions are not exposed.
1053+ * This function can be used to force the use of XWayland.
1054+ * @param wayland A boolean value indicating whether to use Wayland (true) or not (false).
1055+*/
1056+RGFWDEF void RGFW_useWayland(RGFW_bool wayland);
1057+
1058+/**!
1059+ * @brief Checks if Wayland is currently being used.
1060+ * @return RGFW_TRUE if using Wayland, RGFW_FALSE otherwise.
1061+*/
1062+RGFWDEF RGFW_bool RGFW_usingWayland(void);
1063+
1064+/**!
1065+ * @brief Retrieves the current Cocoa layer (macOS only).
1066+ * @return A pointer to the Cocoa layer, or NULL if the platform is not in use.
1067+*/
1068+RGFWDEF void* RGFW_getLayer_OSX(void);
1069+
1070+/**!
1071+ * @brief Retrieves the current X11 display connection.
1072+ * @return A pointer to the X11 display, or NULL if the platform is not in use.
1073+*/
1074+RGFWDEF void* RGFW_getDisplay_X11(void);
1075+
1076+/**!
1077+ * @brief Retrieves the current Wayland display connection.
1078+ * @return A pointer to the Wayland display (`struct wl_display*`), or NULL if the platform is not in use.
1079+*/
1080+RGFWDEF struct wl_display* RGFW_getDisplay_Wayland(void);
1081+
1082+/**!
1083+ * @brief Sets the class name for X11 and WinAPI windows.
1084+ * Windows with the same class name will be grouped by the window manager.
1085+ * By default, the class name matches the root window’s name.
1086+ * @param name The class name to assign.
1087+*/
1088+RGFWDEF void RGFW_setClassName(const char* name);
1089+
1090+/**!
1091+ * @brief Sets the X11 instance name.
1092+ * By default, the window name will be used as the instance name.
1093+ * @param name The X11 instance name to set.
1094+*/
1095+RGFWDEF void RGFW_setXInstName(const char* name);
1096+
1097+/**!
1098+ * @brief (macOS only) Changes the current working directory to the application’s resource folder.
1099+*/
1100+RGFWDEF void RGFW_moveToMacOSResourceDir(void);
1101+
1102+/*! copy image to another image, respecting each image's format */
1103+RGFWDEF void RGFW_copyImageData(u8* dest_data, i32 w, i32 h, RGFW_format dest_format, u8* src_data, RGFW_format src_format, RGFW_convertImageDataFunc func);
1104+
1105+/**!
1106+ * @brief Returns the size (in bytes) of the RGFW_nativeImage structure.
1107+ * @return The size of the RGFW_nativeImage structure.
1108+*/
1109+RGFWDEF size_t RGFW_sizeofNativeImage(void);
1110+
1111+/**!
1112+ * @brief Returns the size (in bytes) of the RGFW_surface structure.
1113+ * @return The size of the RGFW_surface structure.
1114+*/
1115+RGFWDEF size_t RGFW_sizeofSurface(void);
1116+
1117+/**!
1118+ * @brief Returns the native format type for the system
1119+ * @return the native format type for the system as a RGFW_format enum value
1120+*/
1121+RGFWDEF RGFW_format RGFW_nativeFormat(void);
1122+
1123+/**!
1124+ * @brief Creates a new surface from raw pixel data.
1125+ * @param data A pointer to the pixel data buffer.
1126+ * @param w The width of the surface in pixels.
1127+ * @param h The height of the surface in pixels.
1128+ * @param format The pixel format of the data.
1129+ * @return A pointer to the newly created RGFW_surface.
1130+ *
1131+ * NOTE: when you create a surface using RGFW_createSurface / ptr, on X11 it uses the root window's visual
1132+ * this means it may fail to render on any other window if the visual does not match
1133+ * RGFW_window_createSurface and RGFW_window_createSurfacePtr exist only for X11 to address this issues
1134+ * Of course, you can also manually set the root window with RGFW_setRootWindow
1135+*/
1136+RGFWDEF RGFW_surface* RGFW_createSurface(u8* data, i32 w, i32 h, RGFW_format format);
1137+
1138+/**!
1139+ * @brief Creates a surface using a pre-allocated RGFW_surface structure.
1140+ * @param data A pointer to the pixel data buffer.
1141+ * @param w The width of the surface in pixels.
1142+ * @param h The height of the surface in pixels.
1143+ * @param format The pixel format of the data.
1144+ * @param surface A pointer to a pre-allocated RGFW_surface structure.
1145+ * @return RGFW_TRUE if successful, RGFW_FALSE otherwise.
1146+*/
1147+RGFWDEF RGFW_bool RGFW_createSurfacePtr(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface);
1148+
1149+/**!
1150+ * @brief Retrieves the native image associated with a surface.
1151+ * @param surface A pointer to the RGFW_surface.
1152+ * @return A pointer to the native RGFW_nativeImage associated with the surface.
1153+*/
1154+RGFWDEF RGFW_nativeImage* RGFW_surface_getNativeImage(RGFW_surface* surface);
1155+
1156+/**!
1157+ * @brief Frees the surface pointer and any buffers used for software rendering.
1158+ * @param surface A pointer to the RGFW_surface to free.
1159+*/
1160+RGFWDEF void RGFW_surface_free(RGFW_surface* surface);
1161+
1162+/**!
1163+ * @brief Frees only the internal buffers used for software rendering, leaving the surface struct intact.
1164+ * @param surface A pointer to the RGFW_surface whose buffers should be freed.
1165+*/
1166+RGFWDEF void RGFW_surface_freePtr(RGFW_surface* surface);
1167+
1168+
1169+/**!
1170+ * @brief create a mouse icon from bitmap data (similar to RGFW_window_setIcon).
1171+ * @param data A pointer to the bitmap pixel data.
1172+ * @param w The width of the mouse icon in pixels.
1173+ * @param h The height of the mouse icon in pixels.
1174+ * @param format The pixel format of the data.
1175+ * @return A pointer to the newly loaded RGFW_mouse structure.
1176+ *
1177+ * @note The icon is not resized by default.
1178+*/
1179+RGFWDEF RGFW_mouse* RGFW_createMouse(u8* data, i32 w, i32 h, RGFW_format format);
1180+
1181+/**!
1182+ * @brief create a standard mouse icon
1183+ * @param mouse The standard cursor type (see RGFW_MOUSE enum).
1184+ * @return A pointer to the newly loaded RGFW_mouse structure.
1185+*/
1186+RGFWDEF RGFW_mouse* RGFW_createMouseStandard(RGFW_mouseIcon mouse);
1187+
1188+/**!
1189+ * @brief Frees the data associated with an RGFW_mouse structure.
1190+ * @param mouse A pointer to the RGFW_mouse to free.
1191+*/
1192+RGFWDEF void RGFW_freeMouse(RGFW_mouse* mouse);
1193+
1194+/**!
1195+ * @brief Get an allocated array of the supported modes of a monitor
1196+ * @param monitor the source monitor object
1197+ * @param count [OUTPUT] the count of the array
1198+ * @return the allocated array of supported modes
1199+*/
1200+RGFWDEF RGFW_monitorMode* RGFW_monitor_getModes(RGFW_monitor* monitor, size_t* count);
1201+
1202+/**!
1203+ * @brief Free RGFW allocated modes array
1204+ * @param monitor the source monitor object
1205+ * @param modes a pointer to an allocated array of modes
1206+*/
1207+RGFWDEF void RGFW_freeModes(RGFW_monitorMode* modes);
1208+
1209+/**!
1210+ * @brief Get the supported modes of a monitor using a pre-allocated array
1211+ * @param monitor the source monitor object
1212+ * @param modes [OUTPUT] a pointer to an allocated array of modes
1213+ * @return the number of (possible) modes, if [modes == NULL] the possible nodes *may* be less than the actual modes
1214+*/
1215+RGFWDEF size_t RGFW_monitor_getModesPtr(RGFW_monitor* monitor, RGFW_monitorMode** modes);
1216+
1217+/**!
1218+ * @brief find the closest monitor mode based on the give mode with size being the highest priority, format being the second and refreshrate being the third.
1219+ * @param monitor the source monitor object
1220+ * @param mode user filled mode to use for comparison
1221+ * @param modes [OUTPUT] a pointer to be filled with the output closest monitor
1222+ * @return returns true if a suitable monitor was found and false if no suitable monitor was found at all
1223+*/
1224+
1225+RGFWDEF RGFW_bool RGFW_monitor_findClosestMode(RGFW_monitor* monitor, RGFW_monitorMode* mode, RGFW_monitorMode* closest);
1226+
1227+/**!
1228+ * @brief Get the allocated gamma ramp
1229+ * @param monitor the source monitor object
1230+*/
1231+RGFWDEF RGFW_gammaRamp* RGFW_monitor_getGammaRamp(RGFW_monitor* monitor);
1232+
1233+/**!
1234+ * @brief Free the gamma ramp allocated by RGFW
1235+ * @param allocated gamma ramp
1236+*/
1237+RGFWDEF void RGFW_freeGammaRamp(RGFW_gammaRamp* ramp);
1238+
1239+/**!
1240+ * @brief Get the monitor's gamma ramp using a pre-allocated struct with allocated data
1241+ * @param monitor the source monitor object
1242+ * @param ramp [OUTPUT] a pointer to an allocated gamma ramp (can be NULL to just get the count)
1243+ * @return the count of the gamma ramp
1244+*/
1245+RGFWDEF size_t RGFW_monitor_getGammaRampPtr(RGFW_monitor* monitor, RGFW_gammaRamp* ramp);
1246+
1247+/**!
1248+ * @brief Set the monitor's gamma ramp using a pre-allocated struct with allocated data
1249+ * @param monitor the source monitor object
1250+ * @param ramp a pointer to an allocated gamma ramp
1251+ * @return a bool if the function was successful
1252+*/
1253+RGFWDEF RGFW_bool RGFW_monitor_setGammaRamp(RGFW_monitor* monitor, RGFW_gammaRamp* ramp);
1254+
1255+/**!
1256+ * @brief Create and set the monitor's gamma ramp with a base gamma exponent
1257+ * @param monitor the source monitor object
1258+ * @param the gamma exponent
1259+ * @return a bool if the function was successful
1260+*/
1261+RGFWDEF RGFW_bool RGFW_monitor_setGamma(RGFW_monitor* monitor, float gamma);
1262+
1263+/**!
1264+ * @brief Create and set the monitor's gamma ramp with a base gamma exponent using a pre-allocated array
1265+ * @param monitor the source monitor object
1266+ * @param gamma the gamma exponent
1267+ * @param pre-allocated gammaramp channel
1268+ * @param count the length of the allocated channel array
1269+ * @return a bool if the function was successful
1270+*/
1271+RGFWDEF RGFW_bool RGFW_monitor_setGammaPtr(RGFW_monitor* monitor, float gamma, u16* ptr, size_t count);
1272+
1273+/**!
1274+ * @brief Get the workarea of a monitor, meaning the parts not occupied by OS graphics (i.e. the taskbar)
1275+ * @param monitor the source monitor object
1276+ * @param x [OUTPUT] the x pos of the workarea
1277+ * @param y [OUTPUT] the y pos of the workarea
1278+ * @param w [OUTPUT] the width of the workarea
1279+ * @param h [OUTPUT] the height of the workarea
1280+ * @return a bool if the function was successful
1281+*/
1282+RGFWDEF RGFW_bool RGFW_monitor_getWorkarea(RGFW_monitor* monitor, i32* x, i32* y, i32* width, i32* height);
1283+
1284+/**!
1285+ * @brief Get the position of a monitor (the same as monitor.x / monitor.y)
1286+ * @param x [OUTPUT] the x position of the monitor
1287+ * @param y [OUTPUT] the y position of the monitor
1288+ * @return a bool if the function was successful
1289+*/
1290+RGFWDEF RGFW_bool RGFW_monitor_getPosition(RGFW_monitor* monitor, i32* x, i32* y);
1291+
1292+/**!
1293+ * @brief Get the name of a monitor (the same as monitor.name)
1294+ * @return the cstring of the monitor's name
1295+*/
1296+RGFWDEF const char* RGFW_monitor_getName(RGFW_monitor* monitor);
1297+
1298+/**!
1299+ * @brief Get the scale of a monitor (the same as monitor.scaleX / monitor.scaleY)
1300+ * @param monitor the source monitor object
1301+ * @param x [OUTPUT] the x scale of the monitor
1302+ * @param y [OUTPUT] the y scale of the monitor
1303+ * @return a bool if the function was successful
1304+*/
1305+RGFWDEF RGFW_bool RGFW_monitor_getScale(RGFW_monitor* monitor, float* x, float* y);
1306+
1307+/**!
1308+ * @brief Get the physical size of a monitor (the same as monitor.physW / monitor.physH)
1309+ * @param monitor the source monitor object
1310+ * @param w [OUTPUT] the physical width of the monitor
1311+ * @param h [OUTPUT] the physical height of the monitor
1312+ * @return a bool if the function was successful
1313+*/
1314+RGFWDEF RGFW_bool RGFW_monitor_getPhysicalSize(RGFW_monitor* monitor, float* w, float* h);
1315+
1316+/**!
1317+ * @brief Set the user pointer of a monitor (the same as monitor.userPtr = userPtr)
1318+ * @param monitor the source monitor object
1319+ * @param userPtr the new user pointer for the monitor
1320+*/
1321+RGFWDEF void RGFW_monitor_setUserPtr(RGFW_monitor* monitor, void* userPtr);
1322+
1323+/**!
1324+ * @brief Get the user pointer of a monitor (the same as monitor.userPtr)
1325+ * @param monitor the source monitor object
1326+ * @return the user pointer of the monitor
1327+*/
1328+RGFWDEF void* RGFW_monitor_getUserPtr(RGFW_monitor* monitor);
1329+
1330+/**!
1331+ * @brief Get the mode of a monitor (the same as monitor.mode)
1332+ * @param monitor the source monitor object
1333+ * @param mode [OUTPUT] current mode the monitor
1334+ * @return a bool if the function was successful
1335+*/
1336+RGFWDEF RGFW_bool RGFW_monitor_getMode(RGFW_monitor* monitor, RGFW_monitorMode* mode);
1337+
1338+/**!
1339+ * @brief Poll and check for monitor updates (this is called internally on monitor update events and RGFW_init)
1340+*/
1341+RGFWDEF void RGFW_pollMonitors(void);
1342+
1343+/**!
1344+ * @brief Allocates and returns an array of all available monitors.
1345+ * @param len [OUTPUT] A pointer to store the number of monitors found.
1346+ * @return An allocated array of pointers to RGFW_monitor structures that must be freed.
1347+*/
1348+RGFWDEF RGFW_monitor** RGFW_getMonitors(size_t* len);
1349+
1350+/**!
1351+ * @brief fills a pre-allocated array with available monitors.
1352+ * @param maximum number of monitors that the passed [monitors] buffer supports, can be zero to get the length alone
1353+ * @param pre-allocated buffer of monitors, can be NULL to get the length alone
1354+ * @param len [OUTPUT] A pointer to store the number of monitors found, if max is not zero and monitors is not NULL, length will be set to max.
1355+ * @return An array of pointers to RGFW_monitor structures or NULL if the function failed.
1356+*/
1357+RGFWDEF RGFW_bool RGFW_getMonitorsPtr(size_t max, RGFW_monitor** monitors, size_t* len);
1358+
1359+/**!
1360+ * @brief Retrieves the primary monitor.
1361+ * @return A pointer to the RGFW_monitor structure representing the primary monitor.
1362+*/
1363+RGFWDEF RGFW_monitor* RGFW_getPrimaryMonitor(void);
1364+
1365+/**!
1366+ * @brief Requests the display mode for a monitor (based on what attributes are directly requested).
1367+ * @param mon The monitor to apply the mode change to.
1368+ * @param mode The desired RGFW_monitorMode.
1369+ * @param request The RGFW_modeRequest describing how to handle the mode change.
1370+ * @return RGFW_TRUE if the mode was successfully applied, otherwise RGFW_FALSE.
1371+*/
1372+RGFWDEF RGFW_bool RGFW_monitor_requestMode(RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request);
1373+
1374+/**!
1375+ * @brief Sets a specific display mode for a monitor directly.
1376+ * @param mon The monitor to apply the mode change to.
1377+ * @param mode The desired RGFW_monitorMode.
1378+ * @param request The RGFW_modeRequest describing how to handle the mode change.
1379+ * @return RGFW_TRUE if the mode was successfully applied, otherwise RGFW_FALSE.
1380+*/
1381+RGFWDEF RGFW_bool RGFW_monitor_setMode(RGFW_monitor* mon, RGFW_monitorMode* mode);
1382+
1383+/**!
1384+ * @brief Compares two monitor modes to check if they are equivalent.
1385+ * @param mon The first monitor mode.
1386+ * @param mon2 The second monitor mode.
1387+ * @param request The RGFW_modeRequest that defines the comparison parameters.
1388+ * @return RGFW_TRUE if both modes are equivalent, otherwise RGFW_FALSE.
1389+*/
1390+RGFWDEF RGFW_bool RGFW_monitorModeCompare(RGFW_monitorMode* mon, RGFW_monitorMode* mon2, RGFW_modeRequest request);
1391+
1392+/**!
1393+ * @brief Scales a monitor’s mode to match a window’s size.
1394+ * @param mon The monitor to be scaled.
1395+ * @param win The window whose size should be used as a reference.
1396+ * @return RGFW_TRUE if the scaling was successful, otherwise RGFW_FALSE.
1397+*/
1398+RGFWDEF RGFW_bool RGFW_monitor_scaleToWindow(RGFW_monitor* mon, struct RGFW_window* win);
1399+
1400+ /**!
1401+ * @brief set (enable or disable) raw mouse mode globally
1402+ * @param the boolean state of raw mouse mode
1403+ *
1404+*/
1405+RGFWDEF void RGFW_setRawMouseMode(RGFW_bool state);
1406+
1407+/**!
1408+ * @brief toggles building the drag-and-drop (DND) linked list
1409+ * @param allow RGFW_TRUE to allow DND building, RGFW_FALSE to disable
1410+ * @note this is for state checking, the list is created by default if you are using the event queue
1411+*/
1412+RGFWDEF void RGFW_setBuildDND(RGFW_bool allow);
1413+
1414+/**!
1415+* @brief sleep until RGFW gets an event or the timer ends (defined by OS)
1416+* @param waitMS how long to wait for the next event (in miliseconds)
1417+*/
1418+RGFWDEF void RGFW_waitForEvent(i32 waitMS);
1419+
1420+/**!
1421+* @brief Set if events should be queued or not (enabled by default if the event queue is checked)
1422+* @param queue boolean value if RGFW should queue events or not
1423+*/
1424+RGFWDEF void RGFW_setQueueEvents(RGFW_bool queue);
1425+
1426+/**!
1427+ * @brief Sets the callback function for the event.
1428+ * @param the event type for the callback
1429+ * @param func The function to be called when the event is triggered.
1430+ * @return The previously set callback function, if any.
1431+*/
1432+RGFWDEF RGFW_genericFunc RGFW_setEventCallback(RGFW_eventType type, RGFW_genericFunc func);
1433+
1434+/**!
1435+ * @brief Sets the callback function for two continuous events.
1436+ * @param func The function to be called when the event is triggered.
1437+ * @param [OUTPUT] The previously set callback function for the first event, if any.
1438+ * @param [OUTPUT] The previously set callback function for the second event, if any.
1439+*/
1440+RGFWDEF void RGFW_setDualEventCallback(RGFW_eventType type, RGFW_genericFunc func, RGFW_genericFunc* first, RGFW_genericFunc* second);
1441+
1442+/**!
1443+ * @brief Sets the callback function for all events.
1444+ * @param func The function to be called when the event is triggered.
1445+ * @param [OUTPUT] a structure that holds an array of all the event callbacks
1446+*/
1447+RGFWDEF void RGFW_setAllEventCallbacks(RGFW_genericFunc func, RGFW_callbacks* callbacks);
1448+
1449+/**!
1450+* @brief check all the events until there are none left and updates window structure attributes
1451+*/
1452+RGFWDEF void RGFW_pollEvents(void);
1453+
1454+/**!
1455+* @brief check all the events until there are none left and updates window structure attributes
1456+* queues events if the queue is checked and/or requested
1457+*/
1458+RGFWDEF void RGFW_stopCheckEvents(void);
1459+
1460+/**!
1461+ * @brief polls and pops the next event
1462+ * @param event [OUTPUT] a pointer to store the retrieved event
1463+ * @return RGFW_TRUE if an event was found, RGFW_FALSE otherwise
1464+ *
1465+ * NOTE: Using this function without a loop may cause event lag.
1466+ * For multi-threaded systems, use RGFW_pollEvents combined with RGFW_checkQueuedEvent.
1467+ *
1468+ * Example:
1469+ * RGFW_event event;
1470+ * while (RGFW_checkEvent(win, &event)) {
1471+ * // handle event
1472+ * }
1473+*/
1474+RGFWDEF RGFW_bool RGFW_checkEvent(RGFW_event* event);
1475+
1476+/**!
1477+ * @brief pops the first queued event
1478+ * @param event [OUTPUT] a pointer to store the retrieved event
1479+ * @return RGFW_TRUE if an event was found, RGFW_FALSE otherwise
1480+*/
1481+RGFWDEF RGFW_bool RGFW_checkQueuedEvent(RGFW_event* event);
1482+
1483+/** * @defgroup Input
1484+* @{ */
1485+
1486+/**!
1487+ * @brief returns true if the key is pressed during the current frame
1488+ * @param key the key code of the key you want to check
1489+ * @return The boolean value if the key is pressed or not
1490+*/
1491+RGFWDEF RGFW_bool RGFW_isKeyPressed(RGFW_key key);
1492+
1493+/**!
1494+ * @brief returns true if the key was released during the current frame
1495+ * @param key the key code of the key you want to check
1496+ * @return The boolean value if the key is released or not
1497+*/
1498+RGFWDEF RGFW_bool RGFW_isKeyReleased(RGFW_key key);
1499+
1500+/**!
1501+ * @brief returns true if the key is down
1502+ * @param key the key code of the key you want to check
1503+ * @return The boolean value if the key is down or not
1504+*/
1505+RGFWDEF RGFW_bool RGFW_isKeyDown(RGFW_key key);
1506+
1507+/**!
1508+ * @brief returns true if the mouse button is pressed during the current frame
1509+ * @param button the mouse button code of the button you want to check
1510+ * @return The boolean value if the button is pressed or not
1511+*/
1512+RGFWDEF RGFW_bool RGFW_isMousePressed(RGFW_mouseButton button);
1513+
1514+/**!
1515+ * @brief returns true if the mouse button is released during the current frame
1516+ * @param button the mouse button code of the button you want to check
1517+ * @return The boolean value if the button is released or not
1518+*/
1519+RGFWDEF RGFW_bool RGFW_isMouseReleased(RGFW_mouseButton button);
1520+
1521+/**!
1522+ * @brief returns true if the mouse button is down
1523+ * @param button the mouse button code of the button you want to check
1524+ * @return The boolean value if the button is down or not
1525+*/
1526+RGFWDEF RGFW_bool RGFW_isMouseDown(RGFW_mouseButton button);
1527+
1528+/**!
1529+ * @brief outputs the current x, y position of the mouse
1530+ * @param X [OUTPUT] a pointer for the output X value
1531+ * @param Y [OUTPUT] a pointer for the output Y value
1532+*/
1533+RGFWDEF void RGFW_getMouseScroll(float* x, float* y);
1534+
1535+/**!
1536+ * @brief outputs the current x, y movement vector of the mouse
1537+ * @param X [OUTPUT] a pointer for the output X vector value
1538+ * @param Y [OUTPUT] a pointer for the output Y vector value
1539+*/
1540+RGFWDEF void RGFW_getMouseVector(float* x, float* y);
1541+/** @} */
1542+
1543+/**!
1544+ * @brief creates a new window
1545+ * @param name the requested title of the window
1546+ * @param x the requested x position of the window
1547+ * @param y the requested y position of the window
1548+ * @param w the requested width of the window
1549+ * @param h the requested height of the window
1550+ * @param flags extra arguments ((u32)0 means no flags used)
1551+ * @return A pointer to the newly created window structure
1552+ *
1553+ * NOTE: (windows) if the executable has an icon resource named RGFW_ICON, it will be set as the initial icon for the window
1554+*/
1555+RGFWDEF RGFW_window* RGFW_createWindow(const char* name, i32 x, i32 y, i32 w, i32 h, RGFW_windowFlags flags);
1556+
1557+/**!
1558+ * @brief creates a new window using a pre-allocated window structure
1559+ * @param name the requested title of the window
1560+ * @param x the requested x position of the window
1561+ * @param y the requested y position of the window
1562+ * @param w the requested width of the window
1563+ * @param h the requested height of the window
1564+ * @param flags extra arguments ((u32)0 means no flags used)
1565+ * @param win a pointer the pre-allocated window structure
1566+ * @return A pointer to the newly created window structure
1567+*/
1568+RGFWDEF RGFW_window* RGFW_createWindowPtr(const char* name, i32 x, i32 y, i32 w, i32 h, RGFW_windowFlags flags, RGFW_window* win);
1569+
1570+/**!
1571+ * @brief creates a new surface structure
1572+ * @param win the source window of the surface
1573+ * @param data a pointer to the raw data of the structure (you allocate this)
1574+ * @param w the width the data
1575+ * @param h the height of the data
1576+ * @return A pointer to the newly created surface structure
1577+ *
1578+ * NOTE: when you create a surface using RGFW_createSurface / ptr, on X11 it uses the root window's visual
1579+ * this means it may fail to render on any other window if the visual does not match
1580+ * RGFW_window_createSurface and RGFW_window_createSurfacePtr exist only for X11 to address this issues
1581+ * Of course, you can also manually set the root window with RGFW_setRootWindow
1582+ */
1583+RGFWDEF RGFW_surface* RGFW_window_createSurface(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format);
1584+
1585+/**!
1586+ * @brief creates a new surface structure using a pre-allocated surface structure
1587+ * @param win the source window of the surface
1588+ * @param data a pointer to the raw data of the structure (you allocate this)
1589+ * @param w the width the data
1590+ * @param h the height of the data
1591+ * @param a pointer to the pre-allocated surface structure
1592+ * @return a bool if the creation was successful or not
1593+*/
1594+RGFWDEF RGFW_bool RGFW_window_createSurfacePtr(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface);
1595+
1596+/**!
1597+ * @brief set the function/callback used for converting surface data between formats
1598+ * @param surface a pointer to the surface
1599+ * @param a function pointer for the function to use [if NULL the default function is used]
1600+*/
1601+RGFWDEF void RGFW_surface_setConvertFunc(RGFW_surface* surface, RGFW_convertImageDataFunc func);
1602+
1603+/**!
1604+ * @brief blits a surface stucture to the window
1605+ * @param win a pointer the window to blit to
1606+ * @param surface a pointer to the surface
1607+*/
1608+RGFWDEF void RGFW_window_blitSurface(RGFW_window* win, RGFW_surface* surface);
1609+
1610+/**!
1611+ * @brief gets the position of the window | with RGFW_window.x and window.y
1612+ * @param x [OUTPUT] the x position of the window
1613+ * @param y [OUTPUT] the y position of the window
1614+ * @return a bool if the function was successful
1615+*/
1616+RGFWDEF RGFW_bool RGFW_window_getPosition(RGFW_window* win, i32* x, i32* y); /*!< */
1617+
1618+/**!
1619+ * @brief gets the size of the window | with RGFW_window.w and window.h
1620+ * @param win a pointer to the window
1621+ * @param w [OUTPUT] the width of the window
1622+ * @param h [OUTPUT] the height of the window
1623+ * @return a bool if the function was successful
1624+*/
1625+RGFWDEF RGFW_bool RGFW_window_getSize(RGFW_window* win, i32* w, i32* h);
1626+
1627+/**!
1628+ * @brief gets the size of the window in exact pixels
1629+ * @param win a pointer to the window
1630+ * @param w [OUTPUT] the width of the window
1631+ * @param h [OUTPUT] the height of the window
1632+ * @return a bool if the function was successful
1633+*/
1634+RGFWDEF RGFW_bool RGFW_window_getSizeInPixels(RGFW_window* win, i32* w, i32* h);
1635+
1636+/**!
1637+ * @brief gets the flags of the window | returns RGFW_window._flags
1638+ * @param win a pointer to the window
1639+ * @return the window flags
1640+*/
1641+RGFWDEF u32 RGFW_window_getFlags(RGFW_window* win);
1642+
1643+/**!
1644+ * @brief returns the exit key assigned to the window
1645+ * @param win a pointer to the target window
1646+ * @return The key code assigned as the exit key
1647+*/
1648+RGFWDEF RGFW_key RGFW_window_getExitKey(RGFW_window* win);
1649+
1650+/**!
1651+ * @brief sets the exit key for the window
1652+ * @param win a pointer to the target window
1653+ * @param key the key code to assign as the exit key
1654+*/
1655+RGFWDEF void RGFW_window_setExitKey(RGFW_window* win, RGFW_key key);
1656+
1657+/**!
1658+ * @brief sets the types of events you want the window to receive
1659+ * @param win a pointer to the target window
1660+ * @param events the event flags to enable (use RGFW_allEventFlags for all)
1661+*/
1662+RGFWDEF void RGFW_window_setEnabledEvents(RGFW_window* win, RGFW_eventFlag events);
1663+
1664+/**!
1665+ * @brief gets the currently enabled events for the window
1666+ * @param win a pointer to the target window
1667+ * @return The enabled event flags for the window
1668+*/
1669+RGFWDEF RGFW_eventFlag RGFW_window_getEnabledEvents(RGFW_window* win);
1670+
1671+/**!
1672+ * @brief enables all events and disables selected ones
1673+ * @param win a pointer to the target window
1674+ * @param events the event flags to disable
1675+*/
1676+RGFWDEF void RGFW_window_setDisabledEvents(RGFW_window* win, RGFW_eventFlag events);
1677+
1678+/**!
1679+ * @brief directly enables or disables a specific event or group of events
1680+ * @param win a pointer to the target window
1681+ * @param event the event flag or group of flags to modify
1682+ * @param state RGFW_TRUE to enable, RGFW_FALSE to disable
1683+*/
1684+RGFWDEF void RGFW_window_setEventState(RGFW_window* win, RGFW_eventFlag event, RGFW_bool state);
1685+
1686+/**!
1687+ * @brief gets the user pointer associated with the window
1688+ * @param win a pointer to the target window
1689+ * @return The user-defined pointer stored in the window
1690+*/
1691+RGFWDEF void* RGFW_window_getUserPtr(RGFW_window* win);
1692+
1693+/**!
1694+ * @brief sets a user pointer for the window
1695+ * @param win a pointer to the target window
1696+ * @param ptr a pointer to associate with the window
1697+*/
1698+RGFWDEF void RGFW_window_setUserPtr(RGFW_window* win, void* ptr);
1699+
1700+/**!
1701+ * @brief retrieves the platform-specific window source pointer
1702+ * @param win a pointer to the target window
1703+ * @return A pointer to the internal RGFW_window_src structure
1704+*/
1705+RGFWDEF RGFW_window_src* RGFW_window_getSrc(RGFW_window* win);
1706+
1707+/**!
1708+ * @brief sets the macOS layer object associated with the window
1709+ * @param win a pointer to the target window
1710+ * @param layer a pointer to the macOS layer object
1711+ * @note Only available on macOS platforms
1712+*/
1713+RGFWDEF void RGFW_window_setLayer_OSX(RGFW_window* win, void* layer);
1714+
1715+/**!
1716+ * @brief retrieves the macOS view object associated with the window
1717+ * @param win a pointer to the target window
1718+ * @return A pointer to the macOS view object, or NULL if not on macOS
1719+*/
1720+RGFWDEF void* RGFW_window_getView_OSX(RGFW_window* win);
1721+
1722+/**!
1723+ * @brief retrieves the macOS window object
1724+ * @param win a pointer to the target window
1725+ * @return A pointer to the macOS window object, or NULL if not on macOS
1726+*/
1727+RGFWDEF void* RGFW_window_getWindow_OSX(RGFW_window* win);
1728+
1729+/**!
1730+ * @brief retrieves the HWND handle for the window
1731+ * @param win a pointer to the target window
1732+ * @return A pointer to the Windows HWND handle, or NULL if not on Windows
1733+*/
1734+RGFWDEF void* RGFW_window_getHWND(RGFW_window* win);
1735+
1736+/**!
1737+ * @brief retrieves the HDC handle for the window
1738+ * @param win a pointer to the target window
1739+ * @return A pointer to the Windows HDC handle, or NULL if not on Windows
1740+*/
1741+RGFWDEF void* RGFW_window_getHDC(RGFW_window* win);
1742+
1743+/**!
1744+ * @brief retrieves the X11 Window handle for the window
1745+ * @param win a pointer to the target window
1746+ * @return The X11 Window handle, or 0 if not on X11
1747+*/
1748+RGFWDEF u64 RGFW_window_getWindow_X11(RGFW_window* win);
1749+
1750+/**!
1751+ * @brief retrieves the Wayland surface handle for the window
1752+ * @param win a pointer to the target window
1753+ * @return A pointer to the Wayland wl_surface, or NULL if not on Wayland
1754+*/
1755+RGFWDEF struct wl_surface* RGFW_window_getWindow_Wayland(RGFW_window* win);
1756+
1757+/** * @defgroup Window_management
1758+* @{ */
1759+
1760+/*! set the window flags (will undo flags if they don't match the old ones) */
1761+RGFWDEF void RGFW_window_setFlags(RGFW_window* win, RGFW_windowFlags);
1762+
1763+/**!
1764+ * @brief polls and pops the next event with the matching target window in event queue, pushes back events that don't match
1765+ * @param win a pointer to the target window
1766+ * @param event [OUTPUT] a pointer to store the retrieved event
1767+ * @return RGFW_TRUE if an event was found, RGFW_FALSE otherwise
1768+ *
1769+ * NOTE: Using this function without a loop may cause event lag.
1770+ * For multi-threaded systems, use RGFW_pollEvents combined with RGFW_window_checkQueuedEvent.
1771+ *
1772+ * Example:
1773+ * RGFW_event event;
1774+ * while (RGFW_window_checkEvent(win, &event)) {
1775+ * // handle event
1776+ * }
1777+*/
1778+RGFWDEF RGFW_bool RGFW_window_checkEvent(RGFW_window* win, RGFW_event* event);
1779+
1780+/**!
1781+ * @brief pops the first queued event with the matching target window, pushes back events that don't match
1782+ * @param win a pointer to the target window
1783+ * @param event [OUTPUT] a pointer to store the retrieved event
1784+ * @return RGFW_TRUE if an event was found, RGFW_FALSE otherwise
1785+*/
1786+RGFWDEF RGFW_bool RGFW_window_checkQueuedEvent(RGFW_window* win, RGFW_event* event);
1787+
1788+/**!
1789+ * @brief checks if a key was pressed while the window is in focus
1790+ * @param win a pointer to the target window
1791+ * @param key the key code to check
1792+ * @return RGFW_TRUE if the key was pressed, RGFW_FALSE otherwise
1793+*/
1794+RGFWDEF RGFW_bool RGFW_window_isKeyPressed(RGFW_window* win, RGFW_key key);
1795+
1796+/**!
1797+ * @brief checks if a key is currently being held down
1798+ * @param win a pointer to the target window
1799+ * @param key the key code to check
1800+ * @return RGFW_TRUE if the key is held down, RGFW_FALSE otherwise
1801+*/
1802+RGFWDEF RGFW_bool RGFW_window_isKeyDown(RGFW_window* win, RGFW_key key);
1803+
1804+/**!
1805+ * @brief checks if a key was released
1806+ * @param win a pointer to the target window
1807+ * @param key the key code to check
1808+ * @return RGFW_TRUE if the key was released, RGFW_FALSE otherwise
1809+*/
1810+RGFWDEF RGFW_bool RGFW_window_isKeyReleased(RGFW_window* win, RGFW_key key);
1811+
1812+/**!
1813+ * @brief checks if a mouse button was pressed
1814+ * @param win a pointer to the target window
1815+ * @param button the mouse button code to check
1816+ * @return RGFW_TRUE if the mouse button was pressed, RGFW_FALSE otherwise
1817+*/
1818+RGFWDEF RGFW_bool RGFW_window_isMousePressed(RGFW_window* win, RGFW_mouseButton button);
1819+
1820+/**!
1821+ * @brief checks if a mouse button is currently held down
1822+ * @param win a pointer to the target window
1823+ * @param button the mouse button code to check
1824+ * @return RGFW_TRUE if the mouse button is down, RGFW_FALSE otherwise
1825+*/
1826+RGFWDEF RGFW_bool RGFW_window_isMouseDown(RGFW_window* win, RGFW_mouseButton button);
1827+
1828+/**!
1829+ * @brief checks if a mouse button was released
1830+ * @param win a pointer to the target window
1831+ * @param button the mouse button code to check
1832+ * @return RGFW_TRUE if the mouse button was released, RGFW_FALSE otherwise
1833+*/
1834+RGFWDEF RGFW_bool RGFW_window_isMouseReleased(RGFW_window* win, RGFW_mouseButton button);
1835+
1836+/**!
1837+ * @brief checks if the mouse left the window (true only for the first frame)
1838+ * @param win a pointer to the target window
1839+ * @return RGFW_TRUE if the mouse left, RGFW_FALSE otherwise
1840+*/
1841+RGFWDEF RGFW_bool RGFW_window_didMouseLeave(RGFW_window* win);
1842+
1843+/**!
1844+ * @brief checks if the mouse entered the window (true only for the first frame)
1845+ * @param win a pointer to the target window
1846+ * @return RGFW_TRUE if the mouse entered, RGFW_FALSE otherwise
1847+*/
1848+RGFWDEF RGFW_bool RGFW_window_didMouseEnter(RGFW_window* win);
1849+
1850+/**!
1851+ * @brief checks if the mouse is currently inside the window bounds
1852+ * @param win a pointer to the target window
1853+ * @return RGFW_TRUE if the mouse is inside, RGFW_FALSE otherwise
1854+*/
1855+RGFWDEF RGFW_bool RGFW_window_isMouseInside(RGFW_window* win);
1856+
1857+/**!
1858+ * @brief checks if there is data being dragged into or within the window
1859+ * @param win a pointer to the target window
1860+ * @return RGFW_TRUE if data is being dragged, RGFW_FALSE otherwise
1861+*/
1862+RGFWDEF RGFW_bool RGFW_window_isDataDragging(RGFW_window* win);
1863+
1864+/**!
1865+ * @brief gets the position of a data drag
1866+ * @param win a pointer to the target window
1867+ * @param x [OUTPUT] pointer to store the x position
1868+ * @param y [OUTPUT] pointer to store the y position
1869+ * @return RGFW_TRUE if there is an active drag, RGFW_FALSE otherwise
1870+*/
1871+RGFWDEF RGFW_bool RGFW_window_getDataDrag(RGFW_window* win, i32* x, i32* y);
1872+
1873+/**!
1874+ * @brief checks if a data drop occurred in the window (first frame only)
1875+ * @param win a pointer to the target window
1876+ * @return RGFW_TRUE if data was dropped, RGFW_FALSE otherwise
1877+*/
1878+RGFWDEF RGFW_bool RGFW_window_didDataDrop(RGFW_window* win);
1879+
1880+/**!
1881+ * @brief retrieves data from a data drop (drag and drop)
1882+ * @param win a pointer to the target window
1883+ * @return a valid pointer to the root drag node if a data drop occurred, NULL otherwise
1884+*/
1885+RGFWDEF RGFW_dataDropNode* RGFW_window_getDataDrop(RGFW_window* win);
1886+
1887+/**!
1888+ * @brief closes the window and frees its associated structure
1889+ * @param win a pointer to the target window
1890+*/
1891+RGFWDEF void RGFW_window_close(RGFW_window* win);
1892+
1893+/**!
1894+ * @brief closes the window without freeing its structure
1895+ * @param win a pointer to the target window
1896+*/
1897+RGFWDEF void RGFW_window_closePtr(RGFW_window* win);
1898+
1899+/**!
1900+ * @brief fetches the size of the window through the OS (and updates the internal values)
1901+ * @param win a pointer to the window
1902+ * @param w [OUTPUT] the width of the window
1903+ * @param h [OUTPUT] the height of the window
1904+ * @return a bool if the function was successful
1905+*/
1906+RGFWDEF RGFW_bool RGFW_window_fetchSize(RGFW_window* win, i32* w, i32* h);
1907+
1908+/**!
1909+ * @brief moves the window to a new position on the screen
1910+ * @param win a pointer to the target window
1911+ * @param x the new x position
1912+ * @param y the new y position
1913+*/
1914+RGFWDEF void RGFW_window_move(RGFW_window* win, i32 x, i32 y);
1915+
1916+/**!
1917+ * @brief moves the window to a specific monitor
1918+ * @param win a pointer to the target window
1919+ * @param m the target monitor
1920+*/
1921+RGFWDEF void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor* m);
1922+
1923+/**!
1924+ * @brief resizes the window to the given dimensions
1925+ * @param win a pointer to the target window
1926+ * @param w the new width
1927+ * @param h the new height
1928+*/
1929+RGFWDEF void RGFW_window_resize(RGFW_window* win, i32 w, i32 h);
1930+
1931+/**!
1932+ * @brief sets the aspect ratio of the window
1933+ * @param win a pointer to the target window
1934+ * @param w the width ratio
1935+ * @param h the height ratio
1936+*/
1937+RGFWDEF void RGFW_window_setAspectRatio(RGFW_window* win, i32 w, i32 h);
1938+
1939+/**!
1940+ * @brief sets the minimum size of the window
1941+ * @param win a pointer to the target window
1942+ * @param w the minimum width
1943+ * @param h the minimum height
1944+*/
1945+RGFWDEF void RGFW_window_setMinSize(RGFW_window* win, i32 w, i32 h);
1946+
1947+/**!
1948+ * @brief sets the maximum size of the window
1949+ * @param win a pointer to the target window
1950+ * @param w the maximum width
1951+ * @param h the maximum height
1952+*/
1953+RGFWDEF void RGFW_window_setMaxSize(RGFW_window* win, i32 w, i32 h);
1954+
1955+/**!
1956+ * @brief sets focus to the window
1957+ * @param win a pointer to the target window
1958+*/
1959+RGFWDEF void RGFW_window_focus(RGFW_window* win);
1960+
1961+/**!
1962+ * @brief checks if the window is currently in focus
1963+ * @param win a pointer to the target window
1964+ * @return RGFW_TRUE if the window is in focus, RGFW_FALSE otherwise
1965+*/
1966+RGFWDEF RGFW_bool RGFW_window_isInFocus(RGFW_window* win);
1967+
1968+/**!
1969+ * @brief raises the window to the top of the stack
1970+ * @param win a pointer to the target window
1971+*/
1972+RGFWDEF void RGFW_window_raise(RGFW_window* win);
1973+
1974+/**!
1975+ * @brief maximizes the window
1976+ * @param win a pointer to the target window
1977+*/
1978+RGFWDEF void RGFW_window_maximize(RGFW_window* win);
1979+
1980+/**!
1981+ * @brief toggles fullscreen mode for the window
1982+ * @param win a pointer to the target window
1983+ * @param fullscreen RGFW_TRUE to enable fullscreen, RGFW_FALSE to disable
1984+*/
1985+RGFWDEF void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen);
1986+
1987+/**!
1988+ * @brief centers the window on the screen
1989+ * @param win a pointer to the target window
1990+*/
1991+RGFWDEF void RGFW_window_center(RGFW_window* win);
1992+
1993+/**!
1994+ * @brief minimizes the window
1995+ * @param win a pointer to the target window
1996+*/
1997+RGFWDEF void RGFW_window_minimize(RGFW_window* win);
1998+
1999+/**!
2000+ * @brief restores the window from minimized state
2001+ * @param win a pointer to the target window
2002+*/
2003+RGFWDEF void RGFW_window_restore(RGFW_window* win);
2004+
2005+/**!
2006+ * @brief makes the window a floating window
2007+ * @param win a pointer to the target window
2008+ * @param floating RGFW_TRUE to float, RGFW_FALSE to disable
2009+*/
2010+RGFWDEF void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating);
2011+
2012+/**!
2013+ * @brief sets the opacity level of the window
2014+ * @param win a pointer to the target window
2015+ * @param opacity the opacity level (0–255)
2016+*/
2017+RGFWDEF void RGFW_window_setOpacity(RGFW_window* win, u8 opacity);
2018+
2019+/**!
2020+ * @brief toggles window borders / frame / decor
2021+ * @param win a pointer to the target window
2022+ * @param border RGFW_TRUE for bordered, RGFW_FALSE for borderless
2023+*/
2024+RGFWDEF void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border);
2025+
2026+/**!
2027+ * @brief checks if the window is borderless (has a border, frame or decor)
2028+ * @param win a pointer to the target window
2029+ * @return RGFW_TRUE if borderless, RGFW_FALSE otherwise
2030+*/
2031+RGFWDEF RGFW_bool RGFW_window_borderless(RGFW_window* win);
2032+
2033+/**!
2034+ * @brief toggles drag-and-drop (DND) support for the window
2035+ * @param win a pointer to the target window
2036+ * @param allow RGFW_TRUE to allow DND, RGFW_FALSE to disable
2037+ * @note RGFW_windowAllowDND must still be passed when creating the window
2038+*/
2039+RGFWDEF void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow);
2040+
2041+/**!
2042+ * @brief checks if drag-and-drop (DND) is allowed
2043+ * @param win a pointer to the target window
2044+ * @return RGFW_TRUE if DND is enabled, RGFW_FALSE otherwise
2045+*/
2046+RGFWDEF RGFW_bool RGFW_window_allowsDND(RGFW_window* win);
2047+
2048+#ifndef RGFW_NO_PASSTHROUGH
2049+/**!
2050+ * @brief toggles mouse passthrough for the window
2051+ * @param win a pointer to the target window
2052+ * @param passthrough RGFW_TRUE to enable passthrough, RGFW_FALSE to disable
2053+*/
2054+RGFWDEF void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough);
2055+#endif
2056+
2057+/**!
2058+ * @brief renames the window
2059+ * @param win a pointer to the target window
2060+ * @param name the new title string for the window
2061+*/
2062+RGFWDEF void RGFW_window_setName(RGFW_window* win, const char* name);
2063+
2064+/**!
2065+ * @brief sets the icon for the window and taskbar
2066+ * @param win a pointer to the target window
2067+ * @param data the image data
2068+ * @param w the width of the icon
2069+ * @param h the height of the icon
2070+ * @param format the image format
2071+ * @return RGFW_TRUE if successful, RGFW_FALSE otherwise
2072+ *
2073+ * NOTE: The image may be resized by default.
2074+*/
2075+RGFWDEF RGFW_bool RGFW_window_setIcon(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format);
2076+
2077+/**!
2078+ * @brief sets the icon for the window and/or taskbar
2079+ * @param win a pointer to the target window
2080+ * @param data the image data
2081+ * @param w the width of the icon
2082+ * @param h the height of the icon
2083+ * @param format the image format
2084+ * @param type the target icon type (taskbar, window, or both)
2085+ * @return RGFW_TRUE if successful, RGFW_FALSE otherwise
2086+*/
2087+RGFWDEF RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_icon type);
2088+
2089+/**!
2090+ * @brief sets the mouse icon for the window using a loaded mouse icon
2091+ * @param win a pointer to the target window
2092+ * @param mouse a pointer to the RGFW_mouse struct containing the icon
2093+*/
2094+RGFWDEF RGFW_bool RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse);
2095+
2096+/**!
2097+ * @brief Sets the mouse to a preloaded [by RGFW] standard system cursor.
2098+ * @param win The target window.
2099+ * @param mouse The standardmouse icon (see RGFW_mouseIcon enum).
2100+ * @return True if the standard cursor was successfully applied.
2101+*/
2102+RGFWDEF RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, RGFW_mouseIcon icon);
2103+
2104+/**!
2105+ * @brief Sets the mouse to the default cursor icon.
2106+ * @param win The target window.
2107+ * @return True if the default cursor was successfully set.
2108+*/
2109+RGFWDEF RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win);
2110+
2111+/**!
2112+ * @brief set (enable or disable) raw mouse mode only for the select window
2113+ * @param win The target window.
2114+ * @param the boolean state of raw mouse mode
2115+ *
2116+*/
2117+RGFWDEF void RGFW_window_setRawMouseMode(RGFW_window* win, RGFW_bool state);
2118+
2119+/**!
2120+ * @brief lock/unlock the cursor.
2121+ * @param win The target window.
2122+ * @param the boolean state of the mouse's capture state
2123+ *
2124+*/
2125+RGFWDEF void RGFW_window_captureMouse(RGFW_window* win, RGFW_bool state);
2126+
2127+/**!
2128+ * @brief lock/unlock the cursor and enable raw mpuise mode.
2129+ * @param win The target window.
2130+ * @param the boolean state of raw mouse mode
2131+ *
2132+*/
2133+RGFWDEF void RGFW_window_captureRawMouse(RGFW_window* win, RGFW_bool state);
2134+
2135+/**!
2136+ * @brief Returns true if the mouse is using raw mouse mode
2137+ * @param win The target window.
2138+ * @return True if the mouse is using raw mouse input mode.
2139+*/
2140+RGFWDEF RGFW_bool RGFW_window_isRawMouseMode(RGFW_window* win);
2141+
2142+
2143+/**!
2144+ * @brief Returns true if the mouse is captured
2145+ * @param win The target window.
2146+ * @return True if the mouse is being captured.
2147+*/
2148+RGFWDEF RGFW_bool RGFW_window_isCaptured(RGFW_window* win);
2149+
2150+/**!
2151+ * @brief Hides the window from view.
2152+ * @param win The target window.
2153+*/
2154+RGFWDEF void RGFW_window_hide(RGFW_window* win);
2155+
2156+/**!
2157+ * @brief Shows the window if it was hidden.
2158+ * @param win The target window.
2159+*/
2160+RGFWDEF void RGFW_window_show(RGFW_window* win);
2161+
2162+/**!
2163+ * @breif request a window flash to get attention from the user
2164+ * @param win the target window
2165+ * @param request the flash operation requested
2166+*/
2167+RGFWDEF void RGFW_window_flash(RGFW_window* win, RGFW_flashRequest request);
2168+
2169+/**!
2170+ * @brief Sets whether the window should close.
2171+ * @param win The target window.
2172+ * @param shouldClose True to signal the window should close, false to keep it open.
2173+ *
2174+ * This can override or trigger the `RGFW_window_shouldClose` state by modifying window flags.
2175+*/
2176+RGFWDEF void RGFW_window_setShouldClose(RGFW_window* win, RGFW_bool shouldClose);
2177+
2178+/**!
2179+ * @brief Retrieves the current global mouse position.
2180+ * @param x [OUTPUT] Pointer to store the X position of the mouse on the screen.
2181+ * @param y [OUTPUT] Pointer to store the Y position of the mouse on the screen.
2182+ * @return True if the position was successfully retrieved.
2183+*/
2184+RGFWDEF RGFW_bool RGFW_getGlobalMouse(i32* x, i32* y);
2185+
2186+/**!
2187+ * @brief Retrieves the mouse position relative to the window.
2188+ * @param win The target window.
2189+ * @param x [OUTPUT] Pointer to store the X position within the window.
2190+ * @param y [OUTPUT] Pointer to store the Y position within the window.
2191+ * @return True if the position was successfully retrieved.
2192+*/
2193+RGFWDEF RGFW_bool RGFW_window_getMouse(RGFW_window* win, i32* x, i32* y);
2194+
2195+/**!
2196+ * @brief Shows or hides the mouse cursor for the window.
2197+ * @param win The target window.
2198+ * @param show True to show the mouse, false to hide it.
2199+*/
2200+RGFWDEF void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show);
2201+
2202+/**!
2203+ * @brief Checks if the mouse is currently hidden in the window.
2204+ * @param win The target window.
2205+ * @return True if the mouse is hidden.
2206+*/
2207+RGFWDEF RGFW_bool RGFW_window_isMouseHidden(RGFW_window* win);
2208+
2209+/**!
2210+ * @brief Moves the mouse to the specified position within the window.
2211+ * @param win The target window.
2212+ * @param x The new X position.
2213+ * @param y The new Y position.
2214+*/
2215+RGFWDEF void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y);
2216+
2217+/**!
2218+ * @brief Checks if the window should close.
2219+ * @param win The target window.
2220+ * @return True if the window should close (for example, if ESC was pressed or a close event occurred).
2221+*/
2222+RGFWDEF RGFW_bool RGFW_window_shouldClose(RGFW_window* win);
2223+
2224+/**!
2225+ * @brief Checks if the window is currently fullscreen.
2226+ * @param win The target window.
2227+ * @return True if the window is fullscreen.
2228+*/
2229+RGFWDEF RGFW_bool RGFW_window_isFullscreen(RGFW_window* win);
2230+
2231+/**!
2232+ * @brief Checks if the window is currently hidden.
2233+ * @param win The target window.
2234+ * @return True if the window is hidden.
2235+*/
2236+RGFWDEF RGFW_bool RGFW_window_isHidden(RGFW_window* win);
2237+
2238+/**!
2239+ * @brief Checks if the window is minimized.
2240+ * @param win The target window.
2241+ * @return True if the window is minimized.
2242+*/
2243+RGFWDEF RGFW_bool RGFW_window_isMinimized(RGFW_window* win);
2244+
2245+/**!
2246+ * @brief Checks if the window is maximized.
2247+ * @param win The target window.
2248+ * @return True if the window is maximized.
2249+*/
2250+RGFWDEF RGFW_bool RGFW_window_isMaximized(RGFW_window* win);
2251+
2252+/**!
2253+ * @brief Checks if the window is floating.
2254+ * @param win The target window.
2255+ * @return True if the window is floating.
2256+*/
2257+RGFWDEF RGFW_bool RGFW_window_isFloating(RGFW_window* win);
2258+/** @} */
2259+
2260+/** * @defgroup Monitor
2261+* @{ */
2262+
2263+/**!
2264+ * @brief Scales the window to match its monitor’s resolution.
2265+ * @param win The target window.
2266+ *
2267+ * This function is automatically called when the flag `RGFW_scaleToMonitor`
2268+ * is used during window creation.
2269+*/
2270+RGFWDEF void RGFW_window_scaleToMonitor(RGFW_window* win);
2271+
2272+/**!
2273+ * @brief Retrieves the monitor structure associated with the window.
2274+ * @param win The target window.
2275+ * @return The monitor structure of the window.
2276+*/
2277+RGFWDEF RGFW_monitor* RGFW_window_getMonitor(RGFW_window* win);
2278+
2279+/** @} */
2280+
2281+/** * @defgroup Clipboard
2282+* @{ */
2283+
2284+/**!
2285+ * @brief Reads clipboard data.
2286+ * @param size [OUTPUT] A pointer that will be filled with the size of the clipboard data.
2287+ * @return A pointer to the clipboard data as a string.
2288+*/
2289+RGFWDEF const char* RGFW_readClipboard(size_t* size);
2290+
2291+/**!
2292+ * @brief Reads clipboard data into a provided buffer, or returns the required length if str is NULL.
2293+ * @param str [OUTPUT] A pointer to the buffer that will receive the clipboard data (or NULL to get required size).
2294+ * @param strCapacity The capacity of the provided buffer.
2295+ * @return The number of bytes read or required length of clipboard data.
2296+*/
2297+RGFWDEF RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity);
2298+
2299+/**!
2300+ * @brief Writes text to the clipboard.
2301+ * @param text The text to be written to the clipboard.
2302+ * @param textLen The length of the text being written.
2303+*/
2304+RGFWDEF void RGFW_writeClipboard(const char* text, u32 textLen);
2305+/** @} */
2306+
2307+
2308+
2309+/** * @defgroup error handling
2310+* @{ */
2311+/**!
2312+ * @brief Sets the callback function to handle debug messages from RGFW.
2313+ * @param func The function pointer to be used as the debug callback.
2314+ * @return The previously set debug callback function.
2315+*/
2316+RGFWDEF RGFW_debugFunc RGFW_setDebugCallback(RGFW_debugFunc func);
2317+
2318+/**!
2319+ * @brief Sends a debug message manually through the currently set debug callback.
2320+ * @param type The type of debug message being sent.
2321+ * @param err The associated error code.
2322+ * @param msg The debug message text.
2323+*/
2324+RGFWDEF void RGFW_debugCallback(RGFW_debugType type, RGFW_errorCode code, const char* msg);
2325+/** @} */
2326+
2327+/** * @defgroup graphics_API
2328+* @{ */
2329+
2330+/*! native rendering API functions */
2331+#if defined(RGFW_OPENGL)
2332+/* these are native opengl specific functions and will NOT work with EGL */
2333+
2334+/*!< make the window the current OpenGL drawing context
2335+
2336+ NOTE:
2337+ if you want to switch the graphics context's thread,
2338+ you have to run RGFW_window_makeCurrentContext_OpenGL(NULL); on the old thread
2339+ then RGFW_window_makeCurrentContext_OpenGL(valid_window) on the new thread
2340+*/
2341+
2342+/**!
2343+ * @brief Sets the global OpenGL hints to the specified pointer.
2344+ * @param hints A pointer to the RGFW_glHints structure containing the desired OpenGL settings.
2345+*/
2346+RGFWDEF void RGFW_setGlobalHints_OpenGL(RGFW_glHints* hints);
2347+
2348+/**!
2349+ * @brief Resets the global OpenGL hints to their default values.
2350+*/
2351+RGFWDEF void RGFW_resetGlobalHints_OpenGL(void);
2352+
2353+/**!
2354+ * @brief Gets the current global OpenGL hints pointer.
2355+ * @return A pointer to the currently active RGFW_glHints structure.
2356+*/
2357+RGFWDEF RGFW_glHints* RGFW_getGlobalHints_OpenGL(void);
2358+
2359+/**!
2360+ * @brief Creates and allocates an OpenGL context for the specified window.
2361+ * @param win A pointer to the target RGFW_window.
2362+ * @param hints A pointer to an RGFW_glHints structure defining context creation parameters.
2363+ * @return A pointer to the newly created RGFW_glContext.
2364+*/
2365+RGFWDEF RGFW_glContext* RGFW_window_createContext_OpenGL(RGFW_window* win, RGFW_glHints* hints);
2366+
2367+/**!
2368+ * @brief Creates an OpenGL context for the specified window using a preallocated context structure.
2369+ * @param win A pointer to the target RGFW_window.
2370+ * @param ctx A pointer to an already allocated RGFW_glContext structure.
2371+ * @param hints A pointer to an RGFW_glHints structure defining context creation parameters.
2372+ * @return RGFW_TRUE on success, RGFW_FALSE on failure.
2373+*/
2374+RGFWDEF RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints);
2375+
2376+/**!
2377+ * @brief Retrieves the OpenGL context associated with a window.
2378+ * @param win A pointer to the RGFW_window.
2379+ * @return A pointer to the associated RGFW_glContext, or NULL if none exists or if the context is EGL-based.
2380+*/
2381+RGFWDEF RGFW_glContext* RGFW_window_getContext_OpenGL(RGFW_window* win);
2382+
2383+/**!
2384+ * @brief Deletes and frees the OpenGL context.
2385+ * @param win A pointer to the RGFW_window.
2386+ * @param ctx A pointer to the RGFW_glContext to delete.
2387+ *
2388+ * @note This is automatically called by RGFW_window_close if the window’s context is not NULL.
2389+*/
2390+RGFWDEF void RGFW_window_deleteContext_OpenGL(RGFW_window* win, RGFW_glContext* ctx);
2391+
2392+/**!
2393+ * @brief Deletes the OpenGL context without freeing its memory.
2394+ * @param win A pointer to the RGFW_window.
2395+ * @param ctx A pointer to the RGFW_glContext to delete.
2396+ *
2397+ * @note This is automatically called by RGFW_window_close if the window’s context is not NULL.
2398+*/
2399+RGFWDEF void RGFW_window_deleteContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx);
2400+
2401+/**!
2402+ * @brief Retrieves the native source context from an RGFW_glContext.
2403+ * @param ctx A pointer to the RGFW_glContext.
2404+ * @return A pointer to the native OpenGL context handle.
2405+*/
2406+RGFWDEF void* RGFW_glContext_getSourceContext(RGFW_glContext* ctx);
2407+
2408+/**!
2409+ * @brief Makes the specified window the current OpenGL rendering target.
2410+ * @param win A pointer to the RGFW_window to make current.
2411+ *
2412+ * @note This is typically called internally by RGFW_window_makeCurrent.
2413+*/
2414+RGFWDEF void RGFW_window_makeCurrentWindow_OpenGL(RGFW_window* win);
2415+
2416+/**!
2417+ * @brief Makes the OpenGL context of the specified window current.
2418+ * @param win A pointer to the RGFW_window whose context should be made current.
2419+ *
2420+ * @note To move a context between threads, call RGFW_window_makeCurrentContext_OpenGL(NULL)
2421+ * on the old thread before making it current on the new one.
2422+*/
2423+RGFWDEF void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win);
2424+
2425+/**!
2426+ * @brief Swaps the OpenGL buffers for the specified window.
2427+ * @param win A pointer to the RGFW_window whose buffers should be swapped.
2428+*/
2429+RGFWDEF void RGFW_window_swapBuffers_OpenGL(RGFW_window* win);
2430+
2431+/**!
2432+ * @brief Retrieves the current OpenGL context.
2433+ * @return A pointer to the currently active OpenGL context (GLX, WGL, Cocoa, or WebGL backend).
2434+*/
2435+RGFWDEF void* RGFW_getCurrentContext_OpenGL(void);
2436+
2437+/**!
2438+ * @brief Retrieves the current OpenGL window.
2439+ * @return A pointer to the RGFW_window currently bound as the OpenGL context target.
2440+*/
2441+RGFWDEF RGFW_window* RGFW_getCurrentWindow_OpenGL(void);
2442+
2443+/**!
2444+ * @brief Sets the OpenGL swap interval (vsync).
2445+ * @param win A pointer to the RGFW_window.
2446+ * @param swapInterval The desired swap interval value (0 to disable vsync, 1 to enable).
2447+*/
2448+RGFWDEF void RGFW_window_swapInterval_OpenGL(RGFW_window* win, i32 swapInterval);
2449+
2450+/**!
2451+ * @brief Retrieves the address of a native OpenGL procedure.
2452+ * @param procname The name of the OpenGL function to look up.
2453+ * @return A pointer to the function, or NULL if not found.
2454+*/
2455+RGFWDEF RGFW_proc RGFW_getProcAddress_OpenGL(const char* procname);
2456+
2457+/**!
2458+ * @brief Checks whether a specific OpenGL or OpenGL ES API extension is supported.
2459+ * @param extension The name of the extension to check.
2460+ * @param len The length of the extension string.
2461+ * @return RGFW_TRUE if supported, RGFW_FALSE otherwise.
2462+*/
2463+RGFWDEF RGFW_bool RGFW_extensionSupported_OpenGL(const char* extension, size_t len);
2464+
2465+/**!
2466+ * @brief Checks whether a specific platform-dependent OpenGL extension is supported.
2467+ * @param extension The name of the extension to check.
2468+ * @param len The length of the extension string.
2469+ * @return RGFW_TRUE if supported, RGFW_FALSE otherwise.
2470+*/
2471+RGFWDEF RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char* extension, size_t len);
2472+
2473+/* these are EGL specific functions, they may fallback to OpenGL */
2474+#ifdef RGFW_EGL
2475+/**!
2476+ * @brief Creates and allocates an OpenGL/EGL context for the specified window.
2477+ * @param win A pointer to the target RGFW_window.
2478+ * @param hints A pointer to an RGFW_glHints structure defining context creation parameters.
2479+ * @return A pointer to the newly created RGFW_eglContext.
2480+*/
2481+RGFWDEF RGFW_eglContext* RGFW_window_createContext_EGL(RGFW_window* win, RGFW_glHints* hints);
2482+
2483+/**!
2484+ * @brief Creates an OpenGL/EGL context for the specified window using a preallocated context structure.
2485+ * @param win A pointer to the target RGFW_window.
2486+ * @param ctx A pointer to an already allocated RGFW_eglContext structure.
2487+ * @param hints A pointer to an RGFW_glHints structure defining context creation parameters.
2488+ * @return RGFW_TRUE on success, RGFW_FALSE on failure.
2489+*/
2490+RGFWDEF RGFW_bool RGFW_window_createContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ctx, RGFW_glHints* hints);
2491+
2492+/**!
2493+ * @brief Frees and deletes an OpenGL/EGL context.
2494+ * @param win A pointer to the RGFW_window.
2495+ * @param ctx A pointer to the RGFW_eglContext to delete.
2496+ *
2497+ * @note Automatically called by RGFW_window_close if RGFW owns the context.
2498+*/
2499+RGFWDEF void RGFW_window_deleteContext_EGL(RGFW_window* win, RGFW_eglContext* ctx);
2500+
2501+/**!
2502+ * @brief Deletes an OpenGL/EGL context without freeing its memory.
2503+ * @param win A pointer to the RGFW_window.
2504+ * @param ctx A pointer to the RGFW_eglContext to delete.
2505+ *
2506+ * @note Automatically called by RGFW_window_close if RGFW owns the context.
2507+*/
2508+RGFWDEF void RGFW_window_deleteContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ctx);
2509+
2510+/**!
2511+ * @brief Retrieves the OpenGL/EGL context associated with a window.
2512+ * @param win A pointer to the RGFW_window.
2513+ * @return A pointer to the associated RGFW_eglContext, or NULL if none exists or if the context is a native OpenGL context.
2514+*/
2515+RGFWDEF RGFW_eglContext* RGFW_window_getContext_EGL(RGFW_window* win);
2516+
2517+/**!
2518+ * @brief Retrieves the EGL display handle.
2519+ * @return A pointer to the native EGLDisplay.
2520+*/
2521+RGFWDEF void* RGFW_getDisplay_EGL(void);
2522+
2523+/**!
2524+ * @brief Retrieves the native source context from an RGFW_eglContext.
2525+ * @param ctx A pointer to the RGFW_eglContext.
2526+ * @return A pointer to the native EGLContext handle.
2527+*/
2528+RGFWDEF void* RGFW_eglContext_getSourceContext(RGFW_eglContext* ctx);
2529+
2530+/**!
2531+ * @brief Retrieves the EGL surface handle from an RGFW_eglContext.
2532+ * @param ctx A pointer to the RGFW_eglContext.
2533+ * @return A pointer to the EGLSurface associated with the context.
2534+*/
2535+RGFWDEF void* RGFW_eglContext_getSurface(RGFW_eglContext* ctx);
2536+
2537+/**!
2538+ * @brief Retrieves the Wayland EGL window handle from an RGFW_eglContext.
2539+ * @param ctx A pointer to the RGFW_eglContext.
2540+ * @return A pointer to the wl_egl_window associated with the EGL context.
2541+*/
2542+RGFWDEF struct wl_egl_window* RGFW_eglContext_wlEGLWindow(RGFW_eglContext* ctx);
2543+
2544+/**!
2545+ * @brief Swaps the EGL buffers for the specified window.
2546+ * @param win A pointer to the RGFW_window whose buffers should be swapped.
2547+ *
2548+ * @note Typically called by RGFW_window_swapInterval.
2549+*/
2550+RGFWDEF void RGFW_window_swapBuffers_EGL(RGFW_window* win);
2551+
2552+/**!
2553+ * @brief Makes the specified window the current EGL rendering target.
2554+ * @param win A pointer to the RGFW_window to make current.
2555+ *
2556+ * @note This is typically called internally by RGFW_window_makeCurrent.
2557+*/
2558+RGFWDEF void RGFW_window_makeCurrentWindow_EGL(RGFW_window* win);
2559+
2560+/**!
2561+ * @brief Makes the EGL context of the specified window current.
2562+ * @param win A pointer to the RGFW_window whose context should be made current.
2563+ *
2564+ * @note To move a context between threads, call RGFW_window_makeCurrentContext_EGL(NULL)
2565+ * on the old thread before making it current on the new one.
2566+*/
2567+RGFWDEF void RGFW_window_makeCurrentContext_EGL(RGFW_window* win);
2568+
2569+/**!
2570+ * @brief Retrieves the current EGL context.
2571+ * @return A pointer to the currently active EGLContext.
2572+*/
2573+RGFWDEF void* RGFW_getCurrentContext_EGL(void);
2574+
2575+/**!
2576+ * @brief Retrieves the current EGL window.
2577+ * @return A pointer to the RGFW_window currently bound as the EGL context target.
2578+*/
2579+RGFWDEF RGFW_window* RGFW_getCurrentWindow_EGL(void);
2580+
2581+/**!
2582+ * @brief Sets the EGL swap interval (vsync).
2583+ * @param win A pointer to the RGFW_window.
2584+ * @param swapInterval The desired swap interval value (0 to disable vsync, 1 to enable).
2585+*/
2586+RGFWDEF void RGFW_window_swapInterval_EGL(RGFW_window* win, i32 swapInterval);
2587+
2588+/**!
2589+ * @brief Retrieves the address of a native OpenGL or OpenGL ES procedure in an EGL context.
2590+ * @param procname The name of the OpenGL function to look up.
2591+ * @return A pointer to the function, or NULL if not found.
2592+*/
2593+RGFWDEF RGFW_proc RGFW_getProcAddress_EGL(const char* procname);
2594+
2595+/**!
2596+ * @brief Checks whether a specific OpenGL or OpenGL ES API extension is supported in the current EGL context.
2597+ * @param extension The name of the extension to check.
2598+ * @param len The length of the extension string.
2599+ * @return RGFW_TRUE if supported, RGFW_FALSE otherwise.
2600+*/
2601+RGFWDEF RGFW_bool RGFW_extensionSupported_EGL(const char* extension, size_t len);
2602+
2603+/**!
2604+ * @brief Checks whether a specific platform-dependent EGL extension is supported in the current context.
2605+ * @param extension The name of the extension to check.
2606+ * @param len The length of the extension string.
2607+ * @return RGFW_TRUE if supported, RGFW_FALSE otherwise.
2608+*/
2609+RGFWDEF RGFW_bool RGFW_extensionSupportedPlatform_EGL(const char* extension, size_t len);
2610+#endif
2611+#endif
2612+
2613+#ifdef RGFW_VULKAN
2614+#include <vulkan/vulkan.h>
2615+
2616+/* if you don't want to use the above macros */
2617+
2618+/**!
2619+ * @brief Retrieves the Vulkan instance extensions required by RGFW.
2620+ * @param count [OUTPUT] A pointer that will receive the number of required extensions (typically 2).
2621+ * @return A pointer to a static array of required Vulkan instance extension names.
2622+*/
2623+RGFWDEF const char** RGFW_getRequiredInstanceExtensions_Vulkan(size_t* count);
2624+
2625+/**!
2626+ * @brief Creates a Vulkan surface for the specified window.
2627+ * @param win A pointer to the RGFW_window for which to create the Vulkan surface.
2628+ * @param instance The Vulkan instance used to create the surface.
2629+ * @param surface [OUTPUT] A pointer to a VkSurfaceKHR handle that will receive the created surface.
2630+ * @return A VkResult indicating success or failure.
2631+*/
2632+RGFWDEF VkResult RGFW_window_createSurface_Vulkan(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface);
2633+
2634+/**!
2635+ * @brief Checks whether the specified Vulkan physical device and queue family support presentation for RGFW.
2636+ * @param instance The Vulkan instance.
2637+ * @param physicalDevice The Vulkan physical device to check.
2638+ * @param queueFamilyIndex The index of the queue family to query for presentation support.
2639+ * @return RGFW_TRUE if presentation is supported, RGFW_FALSE otherwise.
2640+*/
2641+RGFWDEF RGFW_bool RGFW_getPresentationSupport_Vulkan(VkPhysicalDevice physicalDevice, u32 queueFamilyIndex);
2642+#endif
2643+
2644+#ifdef RGFW_DIRECTX
2645+#ifndef RGFW_WINDOWS
2646+ #undef RGFW_DIRECTX
2647+#else
2648+ #define OEMRESOURCE
2649+ #include <dxgi.h>
2650+
2651+ #ifndef __cplusplus
2652+ #define __uuidof(T) IID_##T
2653+ #endif
2654+/**!
2655+ * @brief Creates a DirectX swap chain for the specified RGFW window.
2656+ * @param win A pointer to the RGFW_window for which to create the swap chain.
2657+ * @param pFactory A pointer to the IDXGIFactory used to create the swap chain.
2658+ * @param pDevice A pointer to the DirectX device (e.g., ID3D11Device or ID3D12Device).
2659+ * @param swapchain [OUTPUT] A pointer to an IDXGISwapChain pointer that will receive the created swap chain.
2660+ * @return An integer result code (0 on success, or a DirectX error code on failure).
2661+*/
2662+RGFWDEF int RGFW_window_createSwapChain_DirectX(RGFW_window* win, IDXGIFactory* pFactory, IUnknown* pDevice, IDXGISwapChain** swapchain);
2663+#endif
2664+#endif
2665+
2666+#ifdef RGFW_WEBGPU
2667+ #include <webgpu/webgpu.h>
2668+ /**!
2669+ * @brief Creates a WebGPU surface for the specified RGFW window.
2670+ * @param window A pointer to the RGFW_window for which to create the surface.
2671+ * @param instance The WebGPU instance used to create the surface.
2672+ * @return The created WGPUSurface handle.
2673+ */
2674+ RGFWDEF WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance instance);
2675+#endif
2676+
2677+/** @} */
2678+
2679+/** * @defgroup Supporting
2680+* @{ */
2681+
2682+/**!
2683+ * @brief Sets the root (main) RGFW window.
2684+ * @param win A pointer to the RGFW_window to set as the root window.
2685+*/
2686+RGFWDEF void RGFW_setRootWindow(RGFW_window* win);
2687+
2688+/**!
2689+ * @brief Retrieves the current root RGFW window.
2690+ * @return A pointer to the current root RGFW_window.
2691+*/
2692+RGFWDEF RGFW_window* RGFW_getRootWindow(void);
2693+
2694+/**!
2695+ * @brief Pushes an event into the standard RGFW event queue.
2696+ * @param event A pointer to the RGFW_event to be added to the queue.
2697+*/
2698+RGFWDEF void RGFW_eventQueuePush(const RGFW_event* event);
2699+
2700+/**!
2701+ * @brief Pushes an event into the standard RGFW event queue and call the callback.
2702+ * @param event A pointer to the RGFW_event to be added to the queue.
2703+*/
2704+RGFWDEF void RGFW_eventQueuePushAndCall(const RGFW_event* event);
2705+
2706+/**!
2707+ * @brief Clears all events from the RGFW event queue without processing them.
2708+*/
2709+RGFWDEF void RGFW_eventQueueFlush(void);
2710+
2711+/**!
2712+ * @brief Pops the next event from the RGFW event queue.
2713+ * @return A pointer to the popped RGFW_event, or NULL if the queue is empty.
2714+*/
2715+RGFWDEF RGFW_event* RGFW_eventQueuePop(void);
2716+
2717+/**!
2718+ * @brief Pops the next event from the RGFW event queue that matches the target window, pushes back events that don't matchj.
2719+ * @param win A pointer to the target RGFW_window.
2720+ * @return A pointer to the popped RGFW_event, or NULL if the queue is empty.
2721+*/
2722+RGFWDEF RGFW_event* RGFW_window_eventQueuePop(RGFW_window* win);
2723+
2724+/**!
2725+ * @brief Converts an API keycode to the RGFW unmapped (physical) key.
2726+ * @param keycode The platform-specific keycode.
2727+ * @return The corresponding RGFW keycode.
2728+*/
2729+RGFWDEF RGFW_key RGFW_apiKeyToRGFW(u32 keycode);
2730+
2731+/**!
2732+ * @brief Converts an RGFW keycode to the unmapped (physical) API key.
2733+ * @param keycode The RGFW keycode.
2734+ * @return The corresponding platform-specific keycode.
2735+*/
2736+RGFWDEF u32 RGFW_rgfwToApiKey(RGFW_key keycode);
2737+
2738+/**!
2739+ * @brief Converts an physical RGFW keycode to a mapped RGFW keycode.
2740+ * @param keycode the physical RGFW keycode.
2741+ * @return The corresponding mapped RGFW keycode.
2742+*/
2743+RGFWDEF RGFW_key RGFW_physicalToMappedKey(RGFW_key keycode);
2744+
2745+/**!
2746+ * @brief Retrieves the size of the RGFW_info structure.
2747+ * @return The size (in bytes) of RGFW_info.
2748+*/
2749+RGFWDEF size_t RGFW_sizeofInfo(void);
2750+
2751+/**!
2752+ * @brief Initializes the RGFW library internally.
2753+ * @return 0 on success, or a negative error code on failure.
2754+ * @note This is automatically called when the first window is created.
2755+*/
2756+RGFWDEF i32 RGFW_init(void);
2757+
2758+/**!
2759+ * @brief Deinitializes the current instance of the RGFW library.
2760+ * @note This is automatically called when the last open window is closed.
2761+*/
2762+RGFWDEF void RGFW_deinit(void);
2763+
2764+/**!
2765+ * @brief Initializes RGFW using a user-provided RGFW_info structure.
2766+ * @param info A pointer to an RGFW_info structure to be used for initialization.
2767+ * @return 0 on success, or a negative error code on failure.
2768+*/
2769+RGFWDEF i32 RGFW_init_ptr(RGFW_info* info);
2770+
2771+/**!
2772+ * @brief Deinitializes a specific RGFW instance stored in the provided RGFW_info pointer.
2773+ * @param info A pointer to the RGFW_info structure representing the instance to deinitialize.
2774+*/
2775+RGFWDEF void RGFW_deinit_ptr(RGFW_info* info);
2776+
2777+/**!
2778+ * @brief Sets the global RGFW_info structure pointer.
2779+ * @param info A pointer to the RGFW_info structure to set.
2780+*/
2781+RGFWDEF void RGFW_setInfo(RGFW_info* info);
2782+
2783+/**!
2784+ * @brief Retrieves the global RGFW_info structure pointer.
2785+ * @return A pointer to the current RGFW_info structure.
2786+*/
2787+RGFWDEF RGFW_info* RGFW_getInfo(void);
2788+
2789+/** @} */
2790+#endif /* RGFW_HEADER */
2791+
2792+#if !defined(RGFW_NATIVE_HEADER) && (defined(RGFW_NATIVE) || defined(RGFW_IMPLEMENTATION))
2793+#define RGFW_NATIVE_HEADER
2794+ #if (defined(RGFW_OPENGL) || defined(RGFW_WEGL)) && defined(_MSC_VER)
2795+ #pragma comment(lib, "opengl32")
2796+ #endif
2797+
2798+ #ifdef RGFW_OPENGL
2799+ struct RGFW_eglContext {
2800+ void* ctx;
2801+ void* surface;
2802+ struct wl_egl_window* eglWindow;
2803+ };
2804+
2805+ typedef union RGFW_gfxContext {
2806+ RGFW_glContext* native;
2807+ RGFW_eglContext* egl;
2808+ } RGFW_gfxContext;
2809+
2810+ typedef RGFW_ENUM(u32, RGFW_gfxContextType) {
2811+ RGFW_gfxNativeOpenGL = RGFW_BIT(0),
2812+ RGFW_gfxEGL = RGFW_BIT(1),
2813+ RGFW_gfxOwnedByRGFW = RGFW_BIT(2)
2814+ };
2815+ #endif
2816+
2817+ /*! source data for the window (used by the APIs) */
2818+ #ifdef RGFW_WINDOWS
2819+
2820+ #ifndef WIN32_LEAN_AND_MEAN
2821+ #define WIN32_LEAN_AND_MEAN
2822+ #endif
2823+ #ifndef OEMRESOURCE
2824+ #define OEMRESOURCE
2825+ #endif
2826+
2827+ #include <windows.h>
2828+
2829+ struct RGFW_nativeImage {
2830+ HBITMAP bitmap;
2831+ u8* bitmapBits;
2832+ RGFW_format format;
2833+ HDC hdcMem;
2834+ };
2835+
2836+ #ifdef RGFW_OPENGL
2837+ struct RGFW_glContext { HGLRC ctx; };
2838+ #endif
2839+
2840+ struct RGFW_window_src {
2841+ HWND window; /*!< source window */
2842+ HDC hdc; /*!< source HDC */
2843+ HICON hIconSmall, hIconBig; /*!< source window icons */
2844+ i32 maxSizeW, maxSizeH, minSizeW, minSizeH, aspectRatioW, aspectRatioH; /*!< for setting max/min resize (RGFW_WINDOWS) */
2845+ RGFW_bool actionFrame; /* frame after a caption button was toggled (e.g. minimize, maximize or close) */
2846+ WCHAR highSurrogate;
2847+ #ifdef RGFW_OPENGL
2848+ RGFW_gfxContext ctx;
2849+ RGFW_gfxContextType gfxType;
2850+ #endif
2851+ };
2852+
2853+#elif defined(RGFW_UNIX)
2854+ #ifdef RGFW_X11
2855+ #include <X11/Xlib.h>
2856+ #include <X11/Xutil.h>
2857+
2858+ #include <X11/extensions/Xrandr.h>
2859+ #include <X11/Xresource.h>
2860+
2861+ #ifndef RGFW_XDND_VERSION
2862+ #define RGFW_XDND_VERSION 5
2863+ #endif
2864+ #endif
2865+
2866+ #ifdef RGFW_WAYLAND
2867+ #ifdef RGFW_LIBDECOR
2868+ #include <libdecor-0/libdecor.h>
2869+ #endif
2870+
2871+ #include <wayland-client.h>
2872+ #include <errno.h>
2873+ #endif
2874+
2875+ struct RGFW_nativeImage {
2876+ #ifdef RGFW_X11
2877+ XImage* bitmap;
2878+ #endif
2879+ #ifdef RGFW_WAYLAND
2880+ struct wl_buffer* wl_buffer;
2881+ i32 fd;
2882+ struct wl_shm_pool* pool;
2883+ #endif
2884+ u8* buffer;
2885+ RGFW_format format;
2886+ };
2887+
2888+ #ifdef RGFW_OPENGL
2889+ struct RGFW_glContext {
2890+ #ifdef RGFW_X11
2891+ struct __GLXcontextRec* ctx; /*!< source graphics context */
2892+ Window window;
2893+ #endif
2894+ #ifdef RGFW_WAYLAND
2895+ RGFW_eglContext egl;
2896+ #endif
2897+ };
2898+ #endif
2899+
2900+ struct RGFW_window_src {
2901+ i32 x, y, w, h;
2902+ #ifdef RGFW_OPENGL
2903+ RGFW_gfxContext ctx;
2904+ RGFW_gfxContextType gfxType;
2905+ #endif
2906+#ifdef RGFW_X11
2907+ Window window; /*!< source window */
2908+ Window parent; /*!< parent window */
2909+ GC gc;
2910+ XIC ic;
2911+ u64 flashEnd;
2912+ #ifdef RGFW_ADVANCED_SMOOTH_RESIZE
2913+ i64 counter_value;
2914+ XID counter;
2915+ #endif
2916+#endif /* RGFW_X11 */
2917+
2918+#if defined(RGFW_WAYLAND)
2919+ struct wl_surface* surface;
2920+ struct xdg_surface* xdg_surface;
2921+ struct xdg_toplevel* xdg_toplevel;
2922+ struct zxdg_toplevel_decoration_v1* decoration;
2923+ struct zwp_locked_pointer_v1 *locked_pointer;
2924+ struct xdg_toplevel_icon_v1 *icon;
2925+ u32 decoration_mode;
2926+ /* State flags to configure the window */
2927+ RGFW_bool pending_activated;
2928+ RGFW_bool activated;
2929+ RGFW_bool resizing;
2930+ RGFW_bool pending_maximized;
2931+ RGFW_bool maximized;
2932+ RGFW_bool minimized;
2933+ RGFW_bool configured;
2934+
2935+ RGFW_bool using_custom_cursor;
2936+ struct wl_surface* custom_cursor_surface;
2937+
2938+ RGFW_monitorNode* active_monitor;
2939+
2940+ struct wl_data_source *data_source; // offer data to other clients
2941+
2942+ #ifdef RGFW_LIBDECOR
2943+ struct libdecor* decorContext;
2944+ #endif
2945+#endif /* RGFW_WAYLAND */
2946+ };
2947+
2948+#elif defined(RGFW_MACOS)
2949+ #include <CoreVideo/CoreVideo.h>
2950+
2951+ struct RGFW_nativeImage {
2952+ RGFW_format format;
2953+ u8* buffer;
2954+ void* rep;
2955+ };
2956+
2957+ #ifdef RGFW_OPENGL
2958+ struct RGFW_glContext {
2959+ void* ctx;
2960+ void* format;
2961+ };
2962+ #endif
2963+
2964+ struct RGFW_window_src {
2965+ void* window;
2966+ void* view; /* apple viewpoint thingy */
2967+ void* mouse;
2968+ void* delegate;
2969+ #ifdef RGFW_OPENGL
2970+ RGFW_gfxContext ctx;
2971+ RGFW_gfxContextType gfxType;
2972+ #endif
2973+ };
2974+
2975+#elif defined(RGFW_WASM)
2976+
2977+ #include <emscripten/html5.h>
2978+ #include <emscripten/key_codes.h>
2979+
2980+ struct RGFW_nativeImage {
2981+ RGFW_format format;
2982+ };
2983+
2984+ #ifdef RGFW_OPENGL
2985+ struct RGFW_glContext {
2986+ EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx;
2987+ };
2988+ #endif
2989+
2990+ struct RGFW_window_src {
2991+ #ifdef RGFW_OPENGL
2992+ RGFW_gfxContext ctx;
2993+ RGFW_gfxContextType gfxType;
2994+ #endif
2995+ };
2996+
2997+#endif
2998+
2999+struct RGFW_surface {
3000+ u8* data;
3001+ i32 w, h;
3002+ RGFW_format format;
3003+ RGFW_convertImageDataFunc convertFunc;
3004+ RGFW_nativeImage native;
3005+};
3006+
3007+/*! internal window data that is not specific to the OS */
3008+typedef struct RGFW_windowInternal {
3009+ /*! which key RGFW_window_shouldClose checks. Settting this to RGFW_keyNULL disables the feature. */
3010+ RGFW_key exitKey;
3011+ i32 lastMouseX, lastMouseY; /*!< last cusor point (for raw mouse data) */
3012+
3013+ RGFW_bool shouldClose;
3014+ RGFW_bool rawMouse;
3015+ RGFW_bool captureMouse;
3016+ RGFW_bool inFocus;
3017+ RGFW_bool mouseInside;
3018+ RGFW_keymod mod;
3019+ RGFW_eventFlag enabledEvents;
3020+ u32 flags; /*!< windows flags (for RGFW to check and modify) */
3021+ i32 oldX, oldY, oldW, oldH;
3022+ RGFW_monitorMode oldMode;
3023+ RGFW_mouse* mouse;
3024+} RGFW_windowInternal;
3025+
3026+struct RGFW_window {
3027+ RGFW_window_src src; /*!< src window data */
3028+ RGFW_windowInternal internal; /*!< internal window data that is not specific to the OS */
3029+ void* userPtr; /* ptr for user data */
3030+ i32 x, y, w, h; /*!< position and size of the window */
3031+}; /*!< window structure for the window */
3032+
3033+typedef struct RGFW_windowState {
3034+ RGFW_bool mouseEnter;
3035+ RGFW_bool dataDragging;
3036+ RGFW_bool dataDrop;
3037+ size_t dataSize;
3038+ i32 dropX, dropY;
3039+ RGFW_window* win; /*!< it's not possible for one of these events to happen in the frame that the other event happened */
3040+
3041+ RGFW_bool mouseLeave;
3042+ RGFW_window* winLeave; /*!< if a mouse leaves one window and enters the next */
3043+} RGFW_windowState;
3044+
3045+typedef struct {
3046+ RGFW_bool current;
3047+ RGFW_bool prev;
3048+} RGFW_keyState;
3049+
3050+struct RGFW_monitorNode {
3051+ RGFW_monitor mon;
3052+ RGFW_bool disconnected;
3053+ RGFW_monitorNode* next;
3054+#ifdef RGFW_WAYLAND
3055+ u32 id; /* Add id so wl_outputs can be removed */
3056+ struct wl_output *output;
3057+ struct zxdg_output_v1 *xdg_output;
3058+ RGFW_monitorMode* modes;
3059+ size_t modeCount;
3060+#endif
3061+#if defined(RGFW_X11)
3062+ i32 screen;
3063+ RROutput rrOutput;
3064+ RRCrtc crtc;
3065+#endif
3066+#ifdef RGFW_WINDOWS
3067+ HMONITOR hMonitor;
3068+ WCHAR adapterName[32];
3069+ WCHAR deviceName[32];
3070+#endif
3071+#ifdef RGFW_MACOS
3072+ void* screen;
3073+ CGDirectDisplayID display;
3074+ u32 uintNum;
3075+#endif
3076+};
3077+
3078+typedef struct RGFW_monitorList {
3079+ RGFW_monitorNode* head;
3080+ RGFW_monitorNode* cur;
3081+} RGFW_monitorList;
3082+
3083+typedef struct RGFW_monitors {
3084+ RGFW_monitorList list;
3085+ size_t count;
3086+
3087+ RGFW_monitorNode* primary;
3088+ #if (RGFW_PREALLOCATED_MONITORS)
3089+ RGFW_monitorList freeList;
3090+ RGFW_monitorNode data[RGFW_PREALLOCATED_MONITORS];
3091+ #endif
3092+} RGFW_monitors;
3093+
3094+RGFWDEF RGFW_monitorNode* RGFW_monitors_add(const RGFW_monitor* mon);
3095+RGFWDEF void RGFW_monitors_remove(RGFW_monitorNode* node, RGFW_monitorNode* prev);
3096+
3097+struct RGFW_info {
3098+ RGFW_window* root;
3099+ i32 windowCount;
3100+
3101+ RGFW_mouse* hiddenMouse;
3102+ RGFW_mouse* standardMice[RGFW_mouseIconCount];
3103+
3104+ RGFW_debugFunc debugCallbackSrc;
3105+ RGFW_genericFunc callbacks[RGFW_eventCount];
3106+ RGFW_event events[RGFW_MAX_EVENTS]; /* A circular buffer (FIFO), using eventBottom/Len */
3107+
3108+ i32 eventBottom;
3109+ i32 eventLen;
3110+ RGFW_bool queueEvents;
3111+ RGFW_bool polledEvents;
3112+
3113+ u32 apiKeycodes[RGFW_keyLast];
3114+ #if defined(RGFW_X11) || defined(RGFW_WAYLAND)
3115+ RGFW_key keycodes[256];
3116+ #elif defined(RGFW_WINDOWS)
3117+ RGFW_key keycodes[512];
3118+ #elif defined(RGFW_MACOS)
3119+ RGFW_key keycodes[128];
3120+ #elif defined(RGFW_WASM)
3121+ RGFW_key keycodes[256];
3122+ #endif
3123+
3124+ const char* className;
3125+ RGFW_bool useWaylandBool;
3126+ RGFW_bool stopCheckEvents_bool ;
3127+ u64 timerOffset;
3128+
3129+ char* clipboard_data;
3130+ char* clipboard; /* for writing to the clipboard selection */
3131+ size_t clipboard_len;
3132+
3133+ RGFW_bool dndBuild;
3134+ RGFW_dataDropNode* dndRoot;
3135+ RGFW_dataDropNode* dndCur;
3136+
3137+ #ifdef RGFW_X11
3138+ Display* display;
3139+ XContext context;
3140+ Window helperWindow;
3141+ const char* instName;
3142+ XErrorEvent* x11Error;
3143+ i32 xrandrEventBase;
3144+ XIM im;
3145+ Window x11Source;
3146+ long x11Version;
3147+ i32 x11Format;
3148+ RGFW_dataTransferType x11TransferType;
3149+ #endif
3150+ #ifdef RGFW_WAYLAND
3151+ struct wl_display* wl_display;
3152+ struct xkb_context *xkb_context;
3153+ struct xkb_keymap *keymap;
3154+ struct xkb_state *xkb_state;
3155+ struct zxdg_decoration_manager_v1 *decoration_manager;
3156+ struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
3157+ struct zwp_relative_pointer_v1 *relative_pointer;
3158+ struct zwp_pointer_constraints_v1 *constraint_manager;
3159+ struct xdg_toplevel_icon_manager_v1 *icon_manager;
3160+
3161+ struct zxdg_output_manager_v1 *xdg_output_manager;
3162+
3163+ struct wl_data_device_manager *data_device_manager;
3164+ struct wl_data_device *data_device; // supports clipboard and DND
3165+ struct wp_pointer_warp_v1* wp_pointer_warp;
3166+
3167+ struct wl_keyboard* wl_keyboard;
3168+ struct wl_pointer* wl_pointer;
3169+ struct wl_compositor* compositor;
3170+ struct xdg_wm_base* xdg_wm_base;
3171+ struct wl_shm* shm;
3172+ struct wl_seat *seat;
3173+ struct wl_registry *registry;
3174+ u32 mouse_enter_serial;
3175+ struct wl_cursor_theme* wl_cursor_theme;
3176+ struct wl_surface* cursor_surface;
3177+ struct xkb_compose_state* composeState;
3178+
3179+ RGFW_window* kbOwner;
3180+ RGFW_window* mouseOwner; /* what window has access to the mouse */
3181+
3182+ u32 last_key; /* wayland key repeat data */
3183+ i32 wl_repeat_info_rate, wl_repeat_info_delay;
3184+ u32 last_key_time;
3185+ #endif
3186+
3187+ RGFW_monitors monitors;
3188+
3189+ #ifdef RGFW_UNIX
3190+ int eventWait_forceStop[3];
3191+ i32 clock;
3192+ #endif
3193+
3194+ #ifdef RGFW_MACOS
3195+ void* NSApp;
3196+ i64 flash;
3197+ void* customViewClasses[2]; /* NSView and NSOpenGLView */
3198+ void* customNSAppDelegateClass;
3199+ void* customWindowDelegateClass;
3200+ void* customNSAppDelegate;
3201+ void* tisBundle;
3202+ #endif
3203+
3204+ #ifdef RGFW_OPENGL
3205+ RGFW_window* current;
3206+ #endif
3207+ #ifdef RGFW_EGL
3208+ void* EGL_display;
3209+ #endif
3210+
3211+ RGFW_bool rawMouse; /* global raw mouse toggle */
3212+
3213+ RGFW_windowState windowState; /*! for checking window state events */
3214+
3215+ RGFW_keyState mouseButtons[RGFW_mouseFinal];
3216+ RGFW_keyState keyboard[RGFW_keyLast];
3217+ float scrollX, scrollY;
3218+ float vectorX, vectorY;
3219+};
3220+#endif /* RGFW_NATIVE_HEADER */
3221+
3222+#ifdef RGFW_IMPLEMENTATION
3223+
3224+#ifndef RGFW_NO_MATH
3225+#include <math.h>
3226+#endif
3227+
3228+/* global private API */
3229+
3230+/* for C++ / C89 */
3231+RGFWDEF RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win);
3232+RGFWDEF void RGFW_window_closePlatform(RGFW_window* win);
3233+RGFWDEF RGFW_bool RGFW_window_setMousePlatform(RGFW_window* win, RGFW_mouse* mouse);
3234+
3235+RGFWDEF void RGFW_window_setFlagsInternal(RGFW_window* win, RGFW_windowFlags flags, RGFW_windowFlags cmpFlags);
3236+
3237+RGFWDEF void RGFW_initKeycodes(void);
3238+RGFWDEF void RGFW_initKeycodesPlatform(void);
3239+RGFWDEF void RGFW_resetPrevState(void);
3240+RGFWDEF void RGFW_resetKey(void);
3241+RGFWDEF void RGFW_unloadEGL(void);
3242+RGFWDEF void RGFW_keyUpdateKeyModsEx(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll);
3243+RGFWDEF void RGFW_keyUpdateKeyMods(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool scroll);
3244+RGFWDEF void RGFW_window_showMouseFlags(RGFW_window* win, RGFW_bool show);
3245+RGFWDEF void RGFW_keyUpdateKeyMod(RGFW_window* win, RGFW_keymod mod, RGFW_bool value);
3246+RGFWDEF void RGFW_monitors_refresh(void);
3247+
3248+RGFWDEF void RGFW_windowMaximizedCallback(RGFW_window* win, i32 x, i32 y, i32 w, i32 h);
3249+RGFWDEF void RGFW_windowMinimizedCallback(RGFW_window* win);
3250+RGFWDEF void RGFW_windowRestoredCallback(RGFW_window* win, i32 x, i32 y, i32 w, i32 h);
3251+RGFWDEF void RGFW_windowMovedCallback(RGFW_window* win, i32 x, i32 y);
3252+RGFWDEF void RGFW_windowResizedCallback(RGFW_window* win, i32 w, i32 h);
3253+RGFWDEF void RGFW_windowCloseCallback(RGFW_window* win);
3254+RGFWDEF void RGFW_mousePosCallback(RGFW_window* win, i32 x, i32 y);
3255+RGFWDEF void RGFW_rawMotionCallback(RGFW_window* win, float x, float y);
3256+RGFWDEF void RGFW_windowRefreshCallback(RGFW_window* win, i32 x, i32 y, i32 w, i32 h);
3257+RGFWDEF void RGFW_windowFocusCallback(RGFW_window* win, RGFW_bool inFocus);
3258+RGFWDEF void RGFW_mouseNotifyCallback(RGFW_window* win, i32 x, i32 y, RGFW_bool status);
3259+RGFWDEF void RGFW_dataDropCallback(RGFW_window* win, const char* data, size_t count, RGFW_dataTransferType dataType);
3260+RGFWDEF void RGFW_dataDragCallback(RGFW_window* win, RGFW_dataTransferType dataType, RGFW_dndActionType action, i32 x, i32 y);
3261+RGFWDEF void RGFW_keyCharCallback(RGFW_window* win, u32 codepoint);
3262+RGFWDEF void RGFW_keyCallback(RGFW_window* win, RGFW_key key, RGFW_keymod mod, RGFW_bool repeat, RGFW_bool press);
3263+RGFWDEF void RGFW_mouseButtonCallback(RGFW_window* win, RGFW_mouseButton button, RGFW_bool press);
3264+RGFWDEF void RGFW_mouseScrollCallback(RGFW_window* win, float x, float y);
3265+RGFWDEF void RGFW_scaleUpdatedCallback(RGFW_window* win, float scaleX, float scaleY);
3266+RGFWDEF void RGFW_monitorCallback(RGFW_window* win, const RGFW_monitor* monitor, RGFW_bool connected);
3267+
3268+RGFWDEF void RGFW_setBit(u32* var, u32 mask, RGFW_bool set);
3269+RGFWDEF void RGFW_splitBPP(u32 bpp, RGFW_monitorMode* mode);
3270+
3271+RGFWDEF void RGFW_window_captureMousePlatform(RGFW_window* win, RGFW_bool state);
3272+RGFWDEF void RGFW_window_setRawMouseModePlatform(RGFW_window *win, RGFW_bool state);
3273+
3274+RGFWDEF void RGFW_copyImageData64(u8* dest_data, i32 w, i32 h, RGFW_format dest_format,
3275+ u8* src_data, RGFW_format src_format, RGFW_bool is64bit, RGFW_convertImageDataFunc func);
3276+
3277+RGFWDEF RGFW_bool RGFW_loadEGL(void);
3278+
3279+#ifdef RGFW_OPENGL
3280+typedef struct RGFW_attribStack {
3281+ i32* attribs;
3282+ size_t count;
3283+ size_t max;
3284+} RGFW_attribStack;
3285+RGFWDEF void RGFW_attribStack_init(RGFW_attribStack* stack, i32* attribs, size_t max);
3286+RGFWDEF void RGFW_attribStack_pushAttrib(RGFW_attribStack* stack, i32 attrib);
3287+RGFWDEF void RGFW_attribStack_pushAttribs(RGFW_attribStack* stack, i32 attrib1, i32 attrib2);
3288+
3289+RGFWDEF RGFW_bool RGFW_extensionSupportedStr(const char* extensions, const char* ext, size_t len);
3290+#endif
3291+
3292+#ifdef RGFW_X11
3293+RGFWDEF void RGFW_XCreateWindow (XVisualInfo visual, const char* name, RGFW_windowFlags flags, RGFW_window* win);
3294+#endif
3295+#ifdef RGFW_MACOS
3296+RGFWDEF void RGFW_osx_initView(RGFW_window* win);
3297+#endif
3298+/* end of global private API defs */
3299+
3300+RGFW_info* _RGFW = NULL;
3301+void RGFW_setInfo(RGFW_info* info) { _RGFW = info; }
3302+RGFW_info* RGFW_getInfo(void) { return _RGFW; }
3303+
3304+
3305+void* RGFW_alloc(size_t size) { return RGFW_ALLOC(size); }
3306+void RGFW_free(void* ptr) { RGFW_FREE(ptr); }
3307+
3308+void RGFW_useWayland(RGFW_bool wayland) { RGFW_init(); _RGFW->useWaylandBool = RGFW_BOOL(wayland); }
3309+RGFW_bool RGFW_usingWayland(void) { return _RGFW->useWaylandBool; }
3310+
3311+void RGFW_setRawMouseMode(RGFW_bool state) {
3312+ _RGFW->rawMouse = state;
3313+ RGFW_window_setRawMouseModePlatform(_RGFW->root, state);
3314+}
3315+
3316+void RGFW_clipboard_switch(char* newstr);
3317+void RGFW_clipboard_switch(char* newstr) {
3318+ if (_RGFW->clipboard_data != NULL)
3319+ RGFW_FREE(_RGFW->clipboard_data);
3320+ _RGFW->clipboard_data = newstr;
3321+}
3322+
3323+#define RGFW_CHECK_CLIPBOARD() \
3324+ if (size <= 0 && _RGFW->clipboard_data != NULL) \
3325+ return (const char*)_RGFW->clipboard_data; \
3326+ else if (size <= 0) \
3327+ return "\0";
3328+
3329+const char* RGFW_readClipboard(size_t* len) {
3330+ RGFW_ssize_t size = RGFW_readClipboardPtr(NULL, 0);
3331+ RGFW_CHECK_CLIPBOARD();
3332+ char* str = (char*)RGFW_ALLOC((size_t)size);
3333+ RGFW_ASSERT(str != NULL);
3334+ str[0] = '\0';
3335+
3336+ size = RGFW_readClipboardPtr(str, (size_t)size);
3337+
3338+ RGFW_CHECK_CLIPBOARD();
3339+
3340+ if (len != NULL) *len = (size_t)size;
3341+
3342+ RGFW_clipboard_switch(str);
3343+ return (const char*)str;
3344+}
3345+
3346+/* generic RGFW defines */
3347+
3348+void RGFW_initKeycodes(void) {
3349+ RGFW_MEMZERO(_RGFW->keycodes, sizeof(_RGFW->keycodes));
3350+ RGFW_initKeycodesPlatform();
3351+ size_t i, y;
3352+ for (i = 0; i < RGFW_keyLast; i++) {
3353+ for (y = 0; y < (sizeof(_RGFW->keycodes) / sizeof(RGFW_key)); y++) {
3354+ if (_RGFW->keycodes[y] == i) {
3355+ _RGFW->apiKeycodes[i] = (RGFW_key)y;
3356+ break;
3357+ }
3358+ }
3359+ }
3360+
3361+
3362+ RGFW_resetKey();
3363+}
3364+
3365+RGFW_key RGFW_apiKeyToRGFW(u32 keycode) {
3366+ /* make sure the key isn't out of bounds */
3367+ if (keycode > (sizeof(_RGFW->keycodes) / sizeof(RGFW_key)))
3368+ return 0;
3369+
3370+ return _RGFW->keycodes[keycode];
3371+}
3372+
3373+u32 RGFW_rgfwToApiKey(RGFW_key keycode) {
3374+ /* make sure the key isn't out of bounds */
3375+ return _RGFW->apiKeycodes[keycode];
3376+}
3377+
3378+void RGFW_resetKey(void) { RGFW_MEMZERO(_RGFW->keyboard, sizeof(_RGFW->keyboard)); }
3379+/*
3380+ this is the end of keycode data
3381+*/
3382+
3383+RGFW_genericFunc RGFW_setEventCallback(RGFW_eventType type, RGFW_genericFunc func) {
3384+ RGFW_ASSERT(type > RGFW_eventNone && type < RGFW_eventCount);
3385+ RGFW_init();
3386+
3387+ RGFW_genericFunc old = _RGFW->callbacks[type];
3388+ _RGFW->callbacks[type] = func;
3389+
3390+ return old;
3391+}
3392+
3393+void RGFW_setDualEventCallback(RGFW_eventType type, RGFW_genericFunc func, RGFW_genericFunc* first, RGFW_genericFunc* second) {
3394+ RGFW_genericFunc func1 = RGFW_setEventCallback(type, func);
3395+ RGFW_genericFunc func2 = RGFW_setEventCallback(type + 1, func);
3396+
3397+ if (first) *first = func1;
3398+ if (second) *second = func2;
3399+}
3400+
3401+void RGFW_setAllEventCallbacks(RGFW_genericFunc func, RGFW_callbacks* callbacks) {
3402+ for (RGFW_eventType i = RGFW_eventNone + 1; i < RGFW_eventCount; i++) {
3403+ if (callbacks) callbacks->arr[i] = _RGFW->callbacks[i];
3404+ RGFW_setEventCallback(i, func);
3405+ }
3406+}
3407+
3408+RGFW_debugFunc RGFW_setDebugCallback(RGFW_debugFunc func) {
3409+ RGFW_init();
3410+ RGFW_debugFunc prev = _RGFW->debugCallbackSrc;
3411+ _RGFW->debugCallbackSrc = func;
3412+ return prev;
3413+}
3414+
3415+void RGFW_eventQueuePushAndCall(const RGFW_event* event) {
3416+ RGFW_ASSERT(event->type > RGFW_eventNone && event->type < RGFW_eventCount);
3417+ if (_RGFW->callbacks[event->type]) (_RGFW->callbacks[event->type])(event);
3418+ RGFW_eventQueuePush(event);
3419+}
3420+
3421+void RGFW_windowMaximizedCallback(RGFW_window* win, i32 x, i32 y, i32 w, i32 h) {
3422+ win->internal.flags |= RGFW_windowMaximize;
3423+ win->x = x;
3424+ win->y = y;
3425+ win->w = w;
3426+ win->h = h;
3427+
3428+ if (!(win->internal.enabledEvents & RGFW_windowMaximizedFlag)) return;
3429+
3430+ RGFW_event event;
3431+ event.type = RGFW_windowMaximized;
3432+ event.update.x = x;
3433+ event.update.y = y;
3434+ event.update.w = w;
3435+ event.update.h = h;
3436+ event.common.win = win;
3437+ RGFW_eventQueuePushAndCall(&event);
3438+}
3439+
3440+void RGFW_windowMinimizedCallback(RGFW_window* win) {
3441+ win->internal.flags |= RGFW_windowMinimize;
3442+
3443+ if (!(win->internal.enabledEvents & RGFW_windowMinimizedFlag)) return;
3444+
3445+ RGFW_event event;
3446+ event.type = RGFW_windowMinimized;
3447+ event.update.x = win->x;
3448+ event.update.y = win->y;
3449+ event.update.w = win->w;
3450+ event.update.h = win->h;
3451+ event.common.win = win;
3452+ RGFW_eventQueuePushAndCall(&event);
3453+}
3454+
3455+void RGFW_windowRestoredCallback(RGFW_window* win, i32 x, i32 y, i32 w, i32 h) {
3456+ win->internal.flags &= ~(u32)RGFW_windowMinimize;
3457+ win->x = x;
3458+ win->y = y;
3459+ win->w = w;
3460+ win->h = h;
3461+
3462+ if (RGFW_window_isMaximized(win) == RGFW_FALSE) win->internal.flags &= ~(u32)RGFW_windowMaximize;
3463+
3464+ if (!(win->internal.enabledEvents & RGFW_windowRestoredFlag)) return;
3465+
3466+ RGFW_event event;
3467+ event.type = RGFW_windowRestored;
3468+ event.update.x = x;
3469+ event.update.y = y;
3470+ event.update.w = w;
3471+ event.update.h = h;
3472+ event.common.win = win;
3473+ RGFW_eventQueuePushAndCall(&event);
3474+}
3475+
3476+void RGFW_windowMovedCallback(RGFW_window* win, i32 x, i32 y) {
3477+ win->x = x;
3478+ win->y = y;
3479+ if (!(win->internal.enabledEvents & RGFW_windowMovedFlag)) return;
3480+
3481+ RGFW_event event;
3482+ event.type = RGFW_windowMoved;
3483+ event.update.x = x;
3484+ event.update.x = y;
3485+ event.update.w = win->w;
3486+ event.update.h = win->h;
3487+ event.common.win = win;
3488+ RGFW_eventQueuePushAndCall(&event);
3489+}
3490+
3491+void RGFW_windowResizedCallback(RGFW_window* win, i32 w, i32 h) {
3492+ win->w = w;
3493+ win->h = h;
3494+
3495+ if (!(win->internal.enabledEvents & RGFW_windowResizedFlag)) return;
3496+ RGFW_event event;
3497+ event.type = RGFW_windowResized;
3498+ event.update.x = win->x;
3499+ event.update.y = win->y;
3500+ event.update.w = w;
3501+ event.update.h = h;
3502+ event.common.win = win;
3503+ RGFW_eventQueuePushAndCall(&event);
3504+}
3505+
3506+void RGFW_windowCloseCallback(RGFW_window* win) {
3507+ win->internal.shouldClose = RGFW_TRUE;
3508+
3509+ RGFW_event event;
3510+ event.type = RGFW_windowClose;
3511+ event.common.win = win;
3512+ RGFW_eventQueuePushAndCall(&event);
3513+}
3514+
3515+void RGFW_mousePosCallback(RGFW_window* win, i32 x, i32 y) {
3516+ win->internal.lastMouseX = x;
3517+ win->internal.lastMouseY = y;
3518+
3519+ if (!(win->internal.enabledEvents & RGFW_mousePosChangedFlag)) return;
3520+
3521+ RGFW_event event;
3522+ event.type = RGFW_mousePosChanged;
3523+ event.mouse.x = x;
3524+ event.mouse.y = y;
3525+ event.mouse.inWindow = win->internal.mouseInside;
3526+ event.common.win = win;
3527+ RGFW_eventQueuePushAndCall(&event);
3528+}
3529+
3530+void RGFW_rawMotionCallback(RGFW_window* win, float x, float y) {
3531+ _RGFW->vectorX = x;
3532+ _RGFW->vectorY = y;
3533+ if (!(win->internal.enabledEvents & RGFW_mouseRawMotionFlag)) return;
3534+
3535+ RGFW_event event;
3536+ event.type = RGFW_mouseRawMotion;
3537+ event.delta.x = x;
3538+ event.delta.y = y;
3539+ event.common.win = win;
3540+ RGFW_eventQueuePushAndCall(&event);
3541+}
3542+
3543+void RGFW_windowRefreshCallback(RGFW_window* win, i32 x, i32 y, i32 w, i32 h) {
3544+ if (!(win->internal.enabledEvents & RGFW_windowRefreshFlag)) return;
3545+ RGFW_event event;
3546+ event.type = RGFW_windowRefresh;
3547+ event.update.x = x;
3548+ event.update.y = y;
3549+ event.update.w = w;
3550+ event.update.h = h;
3551+ event.common.win = win;
3552+ RGFW_eventQueuePushAndCall(&event);
3553+}
3554+
3555+void RGFW_windowFocusCallback(RGFW_window* win, RGFW_bool inFocus) {
3556+ win->internal.inFocus = inFocus;
3557+
3558+ if (win->internal.captureMouse) {
3559+ RGFW_window_captureMousePlatform(win, inFocus);
3560+ }
3561+
3562+ RGFW_event event;
3563+ event.common.win = win;
3564+ event.focus.state = inFocus;
3565+
3566+ if (inFocus == RGFW_TRUE) {
3567+ if ((win->internal.flags & RGFW_windowFullscreen))
3568+ RGFW_window_raise(win);
3569+
3570+ event.type = RGFW_windowFocusIn;
3571+ } else if (inFocus == RGFW_FALSE) {
3572+ if ((win->internal.flags & RGFW_windowFullscreen))
3573+ RGFW_window_minimize(win);
3574+
3575+ size_t key;
3576+ for (key = 0; key < RGFW_keyLast; key++) {
3577+ if (RGFW_isKeyDown((u8)key) == RGFW_FALSE) continue;
3578+
3579+ _RGFW->keyboard[key].current = RGFW_FALSE;
3580+ if ((win->internal.enabledEvents & RGFW_BIT(RGFW_keyReleased))) {
3581+ RGFW_keyCallback(win, (u8)key, win->internal.mod, RGFW_FALSE, RGFW_FALSE);
3582+ }
3583+ }
3584+
3585+ RGFW_resetKey();
3586+ event.type = RGFW_windowFocusOut;
3587+ }
3588+
3589+ event.common.win = win;
3590+
3591+ RGFW_eventQueuePushAndCall(&event);
3592+}
3593+
3594+void RGFW_mouseNotifyCallback(RGFW_window* win, i32 x, i32 y, RGFW_bool status) {
3595+ win->internal.mouseInside = status;
3596+ _RGFW->windowState.win = win;
3597+
3598+ win->internal.lastMouseX = x;
3599+ win->internal.lastMouseY = y;
3600+
3601+ RGFW_event event;
3602+ event.common.win = win;
3603+ event.mouse.x = x;
3604+ event.mouse.y = y;
3605+ event.mouse.inWindow = win->internal.mouseInside;
3606+
3607+ if (status) {
3608+ if (!(win->internal.enabledEvents & RGFW_mouseEnterFlag)) return;
3609+ _RGFW->windowState.mouseEnter = RGFW_TRUE;
3610+ _RGFW->windowState.win = win;
3611+ event.type = RGFW_mouseEnter;
3612+ } else {
3613+ if (!(win->internal.enabledEvents & RGFW_mouseLeaveFlag)) return;
3614+ _RGFW->windowState.winLeave = win;
3615+ _RGFW->windowState.mouseLeave = RGFW_TRUE;
3616+ event.type = RGFW_mouseLeave;
3617+ }
3618+
3619+ RGFW_eventQueuePushAndCall(&event);
3620+}
3621+
3622+void RGFW_dataDropCallback(RGFW_window* win, const char* data, size_t size, RGFW_dataTransferType dataType) {
3623+ if (!(win->internal.enabledEvents & RGFW_dataDropFlag) || !(win->internal.flags & RGFW_windowAllowDND))
3624+ return;
3625+
3626+ _RGFW->windowState.win = win;
3627+ _RGFW->windowState.dataDrop = RGFW_TRUE;
3628+ _RGFW->windowState.dataSize = size;
3629+
3630+ RGFW_dataDropNode node;
3631+ RGFW_MEMZERO(&node, sizeof(node));
3632+ node.data = data;
3633+ node.size = size;
3634+ node.type = dataType;
3635+ node.next = NULL;
3636+
3637+ RGFW_event event;
3638+ event.type = RGFW_dataDrop;
3639+ event.drop.value = &node;
3640+ event.drop.win = win;
3641+
3642+ if (_RGFW->callbacks[event.type]) (_RGFW->callbacks[event.type])(&event);
3643+
3644+ if (_RGFW->queueEvents == RGFW_TRUE || _RGFW->dndBuild) {
3645+ if (_RGFW->dndRoot == NULL) {
3646+ _RGFW->dndRoot = (RGFW_dataDropNode*)RGFW_ALLOC(sizeof(RGFW_dataDropNode));
3647+ _RGFW->dndCur = _RGFW->dndRoot;
3648+ } else if (_RGFW->dndCur) {
3649+ _RGFW->dndCur->next = (RGFW_dataDropNode*)RGFW_ALLOC(sizeof(RGFW_dataDropNode));
3650+ _RGFW->dndCur = _RGFW->dndCur->next;
3651+ } else { RGFW_ASSERT(0); }
3652+
3653+ char* dataCopy = (char*)RGFW_ALLOC(size);
3654+ RGFW_MEMCPY(dataCopy, data, size);
3655+ node.data = dataCopy;
3656+
3657+ RGFW_MEMCPY(_RGFW->dndCur, &node, sizeof(node));
3658+
3659+ event.drop.value = _RGFW->dndCur;
3660+ RGFW_eventQueuePush(&event);
3661+ }
3662+}
3663+
3664+void RGFW_dataDragCallback(RGFW_window* win, RGFW_dataTransferType dataType, RGFW_dndActionType action, i32 x, i32 y) {
3665+ if (!(win->internal.enabledEvents & RGFW_dataDragFlag) || !(win->internal.flags & RGFW_windowAllowDND)) return;
3666+
3667+ _RGFW->windowState.win = win;
3668+ _RGFW->windowState.dataDragging = RGFW_TRUE;
3669+ _RGFW->windowState.dropX = x;
3670+ _RGFW->windowState.dropY = y;
3671+
3672+ RGFW_event event;
3673+ event.type = RGFW_dataDrag;
3674+ event.drag.x = x;
3675+ event.drag.y = y;
3676+ event.drag.action = action;
3677+ event.drag.dataType = dataType;
3678+ event.common.win = win;
3679+
3680+ RGFW_eventQueuePushAndCall(&event);
3681+}
3682+
3683+void RGFW_keyCharCallback(RGFW_window* win, u32 codepoint) {
3684+ if (!(win->internal.enabledEvents & RGFW_keyCharFlag)) return;
3685+
3686+ RGFW_event event;
3687+ event.type = RGFW_keyChar;
3688+ event.keyChar.value = codepoint;
3689+ event.common.win = win;
3690+ RGFW_eventQueuePushAndCall(&event);
3691+}
3692+
3693+void RGFW_keyCallback(RGFW_window* win, RGFW_key key, RGFW_keymod mod, RGFW_bool repeat, RGFW_bool press) {
3694+ RGFW_event event;
3695+
3696+ if (press) {
3697+ if (!(win->internal.enabledEvents & RGFW_keyPressedFlag)) return;
3698+ event.type = RGFW_keyPressed;
3699+ } else {
3700+ if (!(win->internal.enabledEvents & RGFW_keyReleasedFlag)) return;
3701+ event.type = RGFW_keyReleased;
3702+ }
3703+
3704+ _RGFW->keyboard[key].prev = _RGFW->keyboard[key].current;
3705+ _RGFW->keyboard[key].current = press;
3706+
3707+ event.key.value = key;
3708+ event.key.repeat = repeat;
3709+ event.key.mod = mod;
3710+ event.key.state = press;
3711+ event.common.win = win;
3712+ RGFW_eventQueuePushAndCall(&event);
3713+}
3714+
3715+void RGFW_mouseButtonCallback(RGFW_window* win, RGFW_mouseButton button, RGFW_bool press) {
3716+ RGFW_event event;
3717+
3718+ if (press) {
3719+ if (!(win->internal.enabledEvents & RGFW_mouseButtonPressedFlag)) return;
3720+ event.type = RGFW_mouseButtonPressed;
3721+ } else {
3722+ if (!(win->internal.enabledEvents & RGFW_mouseButtonReleasedFlag)) return;
3723+ event.type = RGFW_mouseButtonReleased;
3724+ }
3725+
3726+ _RGFW->mouseButtons[button].prev = _RGFW->mouseButtons[button].current;
3727+ _RGFW->mouseButtons[button].current = press;
3728+
3729+ event.button.value = button;
3730+ event.button.state = press;
3731+ event.common.win = win;
3732+ RGFW_eventQueuePushAndCall(&event);
3733+}
3734+
3735+void RGFW_mouseScrollCallback(RGFW_window* win, float x, float y) {
3736+ if (!(win->internal.enabledEvents & RGFW_mouseScrollFlag)) return;
3737+ _RGFW->scrollX = x;
3738+ _RGFW->scrollY = y;
3739+
3740+ RGFW_event event;
3741+ event.type = RGFW_mouseScroll;
3742+ event.delta.x = x;
3743+ event.delta.y = y;
3744+ event.common.win = win;
3745+ RGFW_eventQueuePushAndCall(&event);
3746+}
3747+
3748+void RGFW_scaleUpdatedCallback(RGFW_window* win, float scaleX, float scaleY) {
3749+ if (!(win->internal.enabledEvents & RGFW_scaleUpdatedFlag)) return;
3750+
3751+ RGFW_event event;
3752+ event.type = RGFW_scaleUpdated;
3753+ event.scale.x = scaleX;
3754+ event.scale.y = scaleY;
3755+ event.common.win = win;
3756+ RGFW_eventQueuePushAndCall(&event);
3757+}
3758+
3759+void RGFW_monitorCallback(RGFW_window* win, const RGFW_monitor* monitor, RGFW_bool connected) {
3760+ if (win) {
3761+ if (connected && !(win->internal.enabledEvents & RGFW_monitorConnectedFlag)) return;
3762+ if (!connected && !(win->internal.enabledEvents & RGFW_monitorDisconnectedFlag)) return;
3763+ }
3764+
3765+ RGFW_event event;
3766+ event.type = (connected) ? (RGFW_eventType)(RGFW_monitorConnected) : (RGFW_eventType)(RGFW_monitorDisconnected);
3767+ event.monitor.monitor = monitor;
3768+ event.monitor.state = connected;
3769+ event.common.win = win;
3770+ RGFW_eventQueuePushAndCall(&event);
3771+}
3772+
3773+#ifdef RGFW_DEBUG
3774+#include <stdio.h>
3775+#endif
3776+
3777+void RGFW_debugCallback(RGFW_debugType type, RGFW_errorCode code, const char* msg) {
3778+ RGFW_debugInfo info;
3779+ info.type = type;
3780+ info.code = code;
3781+ info.msg = msg;
3782+
3783+ if (_RGFW && _RGFW->debugCallbackSrc) _RGFW->debugCallbackSrc(&info);
3784+
3785+ #ifdef RGFW_DEBUG
3786+ switch (type) {
3787+ case RGFW_typeInfo: RGFW_PRINTF("RGFW INFO (%i %i): %s", type, code, msg); break;
3788+ case RGFW_typeError: RGFW_PRINTF("RGFW DEBUG (%i %i): %s", type, code, msg); break;
3789+ case RGFW_typeWarning: RGFW_PRINTF("RGFW WARNING (%i %i): %s", type, code, msg); break;
3790+ default: break;
3791+ }
3792+
3793+ RGFW_PRINTF("\n");
3794+ #endif
3795+}
3796+
3797+void RGFW_window_checkMode(RGFW_window* win);
3798+void RGFW_window_checkMode(RGFW_window* win) {
3799+ if (RGFW_window_isMinimized(win) && (win->internal.enabledEvents & RGFW_windowMinimizedFlag)) {
3800+ RGFW_windowMinimizedCallback(win);
3801+ } else if (RGFW_window_isMaximized(win) && (win->internal.enabledEvents & RGFW_windowMaximizedFlag)) {
3802+ RGFW_windowMaximizedCallback(win, win->x, win->y, win->w, win->h);
3803+ } else if ((((win->internal.flags & RGFW_windowMinimize) && !RGFW_window_isMaximized(win)) ||
3804+ (win->internal.flags & RGFW_windowMaximize && !RGFW_window_isMaximized(win))) && (win->internal.enabledEvents & RGFW_windowRestoredFlag)) {
3805+ RGFW_windowRestoredCallback(win, win->x, win->y, win->w, win->h);
3806+ }
3807+}
3808+
3809+/*
3810+no more event call back defines
3811+*/
3812+
3813+size_t RGFW_sizeofInfo(void) { return sizeof(RGFW_info); }
3814+size_t RGFW_sizeofNativeImage(void) { return sizeof(RGFW_nativeImage); }
3815+size_t RGFW_sizeofSurface(void) { return sizeof(RGFW_surface); }
3816+size_t RGFW_sizeofWindow(void) { return sizeof(RGFW_window); }
3817+size_t RGFW_sizeofWindowSrc(void) { return sizeof(RGFW_window_src); }
3818+
3819+RGFW_window_src* RGFW_window_getSrc(RGFW_window* win) { return &win->src; }
3820+RGFW_bool RGFW_window_getPosition(RGFW_window* win, i32* x, i32* y) { if (x) *x = win->x; if (y) *y = win->y; return RGFW_TRUE; }
3821+RGFW_bool RGFW_window_getSize(RGFW_window* win, i32* w, i32* h) { if (w) *w = win->w; if (h) *h = win->h; return RGFW_TRUE; }
3822+u32 RGFW_window_getFlags(RGFW_window* win) { return win->internal.flags; }
3823+RGFW_key RGFW_window_getExitKey(RGFW_window* win) { return win->internal.exitKey; }
3824+void RGFW_window_setExitKey(RGFW_window* win, RGFW_key key) { win->internal.exitKey = key; }
3825+void RGFW_window_setEnabledEvents(RGFW_window* win, RGFW_eventFlag events) { win->internal.enabledEvents = events; }
3826+RGFW_eventFlag RGFW_window_getEnabledEvents(RGFW_window* win) { return win->internal.enabledEvents; }
3827+void RGFW_window_setDisabledEvents(RGFW_window* win, RGFW_eventFlag events) { RGFW_window_setEnabledEvents(win, (RGFW_allEventFlags) & ~(u32)events); }
3828+void RGFW_window_setEventState(RGFW_window* win, RGFW_eventFlag event, RGFW_bool state) { RGFW_setBit(&win->internal.enabledEvents, event, state); }
3829+void* RGFW_window_getUserPtr(RGFW_window* win) { return win->userPtr; }
3830+void RGFW_window_setUserPtr(RGFW_window* win, void* ptr) { win->userPtr = ptr; }
3831+
3832+RGFW_bool RGFW_window_getSizeInPixels(RGFW_window* win, i32* w, i32* h) {
3833+ RGFW_monitor* mon = RGFW_window_getMonitor(win);
3834+ if (mon == NULL) return RGFW_FALSE;
3835+
3836+ if (w) *w = (i32)((float)win->w * mon->pixelRatio);
3837+ if (h) *h = (i32)((float)win->h * mon->pixelRatio);
3838+
3839+ return RGFW_TRUE;
3840+}
3841+
3842+
3843+#if defined(RGFW_USE_XDL) && defined(RGFW_X11)
3844+ #define XDL_IMPLEMENTATION
3845+ #include "XDL.h"
3846+#endif
3847+
3848+#ifndef RGFW_NO_STATIC_CONTEXT
3849+
3850+i32 RGFW_init(void) {
3851+ static RGFW_info _rgfwGlobal;
3852+ return RGFW_init_ptr(&_rgfwGlobal);
3853+}
3854+
3855+
3856+void RGFW_deinit(void) { RGFW_deinit_ptr(_RGFW); }
3857+
3858+#else
3859+
3860+RGFW_info* _rgfwGlobal;
3861+
3862+i32 RGFW_init(void) {
3863+ if (_rgfwGlobal != NULL) {
3864+ RGFW_FREE(_rgfwGlobal);
3865+ }
3866+
3867+ _rgfwGlobal = (RGFW_info*)RGFW_ALLOC(sizeof(RGFW_info));
3868+
3869+ return RGFW_init_ptr(&_rgfwGlobal);
3870+}
3871+
3872+void RGFW_deinit(void) {
3873+ if (_RGFW == _rgfwGlobal) {
3874+ RGFW_FREE(_rgfwGlobal);
3875+ _rgfwGlobal = NULL;
3876+ }
3877+ RGFW_deinit_ptr(_RGFW);
3878+}
3879+
3880+#endif
3881+
3882+i32 RGFW_initPlatform(void);
3883+void RGFW_deinitPlatform(void);
3884+
3885+i32 RGFW_init_ptr(RGFW_info* info) {
3886+ if (info == _RGFW || info == NULL) return 1;
3887+
3888+ RGFW_setInfo(info);
3889+ RGFW_MEMZERO(_RGFW, sizeof(RGFW_info));
3890+ _RGFW->queueEvents = RGFW_FALSE;
3891+ _RGFW->polledEvents = RGFW_FALSE;
3892+#ifdef RGFW_WAYLAND
3893+ _RGFW->useWaylandBool = RGFW_TRUE;
3894+#endif
3895+
3896+ #if (RGFW_PREALLOCATED_MONITORS)
3897+ _RGFW->monitors.freeList.head = &_RGFW->monitors.data[0];
3898+ _RGFW->monitors.freeList.cur = _RGFW->monitors.freeList.head;
3899+
3900+ for (size_t i = 1; i < RGFW_PREALLOCATED_MONITORS; i++) {
3901+ RGFW_monitorNode* newNode = &_RGFW->monitors.data[i];
3902+ _RGFW->monitors.freeList.cur->next = newNode;
3903+ _RGFW->monitors.freeList.cur = _RGFW->monitors.freeList.cur->next;
3904+ }
3905+ #endif
3906+
3907+ _RGFW->monitors.list.head = NULL;
3908+ _RGFW->monitors.list.head = NULL;
3909+ RGFW_initKeycodes();
3910+ i32 out = RGFW_initPlatform();
3911+
3912+ for (size_t i = 0; i < RGFW_mouseIconCount; i++) {
3913+ _RGFW->standardMice[i] = RGFW_createMouseStandard((RGFW_mouseIcon)i);
3914+ }
3915+
3916+ RGFW_pollMonitors();
3917+
3918+ RGFW_debugCallback(RGFW_typeInfo, RGFW_infoGlobal, "global context initialized");
3919+
3920+ return out;
3921+}
3922+
3923+#ifndef RGFW_EGL
3924+void RGFW_unloadEGL(void) { }
3925+#endif
3926+
3927+void RGFW_deinit_ptr(RGFW_info* info) {
3928+ if (info == NULL) return;
3929+
3930+ RGFW_setInfo(info);
3931+ RGFW_unloadEGL();
3932+
3933+ for (RGFW_mouseIcon i = 0; i < RGFW_mouseIconCount; i++) {
3934+ if (_RGFW->standardMice[i]) RGFW_freeMouse(_RGFW->standardMice[i]);
3935+ }
3936+
3937+ RGFW_debugCallback(RGFW_typeInfo, RGFW_infoGlobal, "global context deinitialized");
3938+ RGFW_deinitPlatform();
3939+
3940+ _RGFW->root = NULL;
3941+ _RGFW->windowCount = 0;
3942+ RGFW_setInfo(NULL);
3943+}
3944+
3945+RGFW_window* RGFW_createWindow(const char* name, i32 x, i32 y, i32 w, i32 h, RGFW_windowFlags flags) {
3946+ RGFW_window* win = (RGFW_window*)RGFW_ALLOC(sizeof(RGFW_window));
3947+ RGFW_ASSERT(win != NULL);
3948+ return RGFW_createWindowPtr(name, x, y, w, h, flags, win);
3949+}
3950+
3951+void RGFW_window_close(RGFW_window* win) {
3952+ RGFW_ASSERT(win != NULL);
3953+ RGFW_window_closePtr(win);
3954+ RGFW_FREE(win);
3955+}
3956+
3957+RGFW_window* RGFW_createWindowPtr(const char* name, i32 x, i32 y, i32 w, i32 h, RGFW_windowFlags flags, RGFW_window* win) {
3958+ RGFW_ASSERT(win != NULL);
3959+ if (name == NULL) name = "\0";
3960+
3961+ RGFW_MEMZERO(win, sizeof(RGFW_window));
3962+
3963+ if (_RGFW == NULL) RGFW_init();
3964+ _RGFW->windowCount++;
3965+
3966+ /* rect based the requested flags */
3967+ if (_RGFW->root == NULL) {
3968+ RGFW_setRootWindow(win);
3969+ }
3970+
3971+ /* set and init the new window's data */
3972+ win->x = x;
3973+ win->y = y;
3974+ win->w = w;
3975+ win->h = h;
3976+ win->internal.mouse = _RGFW->standardMice[RGFW_mouseNormal];
3977+ win->internal.flags = flags;
3978+ win->internal.enabledEvents = RGFW_allEventFlags;
3979+
3980+ RGFW_windowFlags reservedFlags = flags & (RGFW_windowScaleToMonitor);
3981+ flags &= ~reservedFlags;
3982+
3983+ RGFW_window* ret = RGFW_createWindowPlatform(name, flags, win);
3984+
3985+ flags |= reservedFlags;
3986+
3987+#ifndef RGFW_X11
3988+ RGFW_window_setFlagsInternal(win, flags, 0);
3989+#endif
3990+
3991+#ifdef RGFW_OPENGL
3992+ win->src.gfxType = 0;
3993+ if (flags & RGFW_windowOpenGL)
3994+ RGFW_window_createContext_OpenGL(win, RGFW_getGlobalHints_OpenGL());
3995+#endif
3996+
3997+#ifdef RGFW_EGL
3998+ if (flags & RGFW_windowEGL)
3999+ RGFW_window_createContext_EGL(win, RGFW_getGlobalHints_OpenGL());
4000+#endif
4001+
4002+ /* X11 creates the window after the OpenGL context is created (because of visual garbage),
4003+ * so we have to wait to set the flags
4004+ * This is required so that way the user can create their own OpenGL context after RGFW_createWindow is used
4005+ * if a window is created, CreateContext will delete the window and create a new one
4006+ * */
4007+#ifdef RGFW_X11
4008+ RGFW_window_setFlagsInternal(win, flags, 0);
4009+#endif
4010+
4011+#ifdef RGFW_MACOS
4012+ /*NOTE: another OpenGL/setFlags related hack, this because OSX the 'view' class must be setup after the NSOpenGL view is made AND after setFlags happens */
4013+ RGFW_osx_initView(win);
4014+#endif
4015+
4016+#ifdef RGFW_WAYLAND
4017+ /* recieve all events needed to configure the surface */
4018+ /* also gets the wl_outputs */
4019+ if (RGFW_usingWayland()) {
4020+ wl_display_roundtrip(_RGFW->wl_display);
4021+ /* NOTE: this is a hack so that way wayland spawns a window, even if nothing is drawn */
4022+ if (!(flags & RGFW_windowOpenGL) && !(flags & RGFW_windowEGL)) {
4023+ u8* data = (u8*)RGFW_ALLOC((u32)(win->w * win->h * 3));
4024+ RGFW_MEMZERO(data, (u32)(win->w * win->h * 3) * sizeof(u8));
4025+ RGFW_surface* surface = RGFW_createSurface(data, win->w, win->h, RGFW_formatBGR8);
4026+ RGFW_window_blitSurface(win, surface);
4027+ RGFW_FREE(data);
4028+ RGFW_surface_free(surface);
4029+ }
4030+ }
4031+#endif
4032+
4033+ if (!(flags & RGFW_windowHideMouse)) {
4034+ RGFW_window_setMouseDefault(win);
4035+ }
4036+
4037+ RGFW_window_setName(win, name);
4038+ if (!(flags & RGFW_windowHide)) {
4039+ flags |= RGFW_windowHide;
4040+ RGFW_window_show(win);
4041+ }
4042+
4043+ RGFW_debugCallback(RGFW_typeInfo, RGFW_infoWindow, "a new window was created");
4044+
4045+ return ret;
4046+}
4047+
4048+void RGFW_window_closePtr(RGFW_window* win) {
4049+ RGFW_ASSERT(win != NULL);
4050+
4051+ if (win->internal.captureMouse) {
4052+ RGFW_window_captureMouse(win, RGFW_FALSE);
4053+ }
4054+
4055+ #ifdef RGFW_EGL
4056+ if ((win->src.gfxType & RGFW_gfxEGL) && win->src.ctx.egl) {
4057+ RGFW_window_deleteContext_EGL(win, win->src.ctx.egl);
4058+ win->src.ctx.egl = NULL;
4059+ }
4060+ #endif
4061+
4062+ #ifdef RGFW_OPENGL
4063+ if ((win->src.gfxType & RGFW_gfxNativeOpenGL) && win->src.ctx.native) {
4064+ RGFW_window_deleteContext_OpenGL(win, win->src.ctx.native);
4065+ win->src.ctx.native = NULL;
4066+ }
4067+ #endif
4068+
4069+ RGFW_window_closePlatform(win);
4070+
4071+ RGFW_clipboard_switch(NULL);
4072+
4073+ _RGFW->windowCount--;
4074+ RGFW_debugCallback(RGFW_typeInfo, RGFW_infoWindow, "a window was freed");
4075+
4076+ if (_RGFW->windowCount == 0 && !(win->internal.flags & RGFW_noDeinitOnClose)) RGFW_deinit();
4077+}
4078+
4079+void RGFW_setQueueEvents(RGFW_bool queue) { _RGFW->queueEvents = RGFW_BOOL(queue); }
4080+
4081+void RGFW_eventQueueFlush(void) { _RGFW->eventLen = 0; }
4082+
4083+void RGFW_eventQueuePush(const RGFW_event* event) {
4084+ if (_RGFW->queueEvents == RGFW_FALSE) return;
4085+ RGFW_ASSERT(_RGFW->eventLen >= 0);
4086+
4087+ if (_RGFW->eventLen >= RGFW_MAX_EVENTS) {
4088+ RGFW_debugCallback(RGFW_typeError, RGFW_errEventQueue, "Event queue limit 'RGFW_MAX_EVENTS' has been reached automatically flushing queue.");
4089+ RGFW_eventQueueFlush();
4090+ return;
4091+ }
4092+
4093+ i32 eventTop = (_RGFW->eventBottom + _RGFW->eventLen) % RGFW_MAX_EVENTS;
4094+ _RGFW->eventLen += 1;
4095+ _RGFW->events[eventTop] = *event;
4096+}
4097+
4098+RGFW_event* RGFW_eventQueuePop(void) {
4099+ RGFW_ASSERT(_RGFW->eventLen >= 0 && _RGFW->eventLen <= RGFW_MAX_EVENTS);
4100+ RGFW_event* ev;
4101+
4102+ if (_RGFW->eventLen == 0) {
4103+ return NULL;
4104+ }
4105+
4106+ ev = &_RGFW->events[_RGFW->eventBottom];
4107+ _RGFW->eventLen -= 1;
4108+ _RGFW->eventBottom = (_RGFW->eventBottom + 1) % RGFW_MAX_EVENTS;
4109+
4110+ return ev;
4111+}
4112+
4113+RGFW_bool RGFW_checkEvent(RGFW_event* event) {
4114+ if (_RGFW->eventLen == 0 && _RGFW->polledEvents == RGFW_FALSE) {
4115+ _RGFW->queueEvents = RGFW_TRUE;
4116+ RGFW_pollEvents();
4117+ _RGFW->polledEvents = RGFW_TRUE;
4118+ }
4119+
4120+ if (RGFW_checkQueuedEvent(event) == RGFW_FALSE) {
4121+ _RGFW->polledEvents = RGFW_FALSE;
4122+ return RGFW_FALSE;
4123+ }
4124+
4125+ return RGFW_TRUE;
4126+}
4127+
4128+RGFW_bool RGFW_checkQueuedEvent(RGFW_event* event) {
4129+ RGFW_event* ev;
4130+ _RGFW->queueEvents = RGFW_TRUE;
4131+ /* check queued events */
4132+ ev = RGFW_eventQueuePop();
4133+ if (ev != NULL) {
4134+ *event = *ev;
4135+ return RGFW_TRUE;
4136+ }
4137+
4138+ return RGFW_FALSE;
4139+}
4140+
4141+void RGFW_resetPrevState(void) {
4142+ size_t i; /*!< reset each previous state */
4143+ for (i = 0; i < RGFW_keyLast; i++) _RGFW->keyboard[i].prev = _RGFW->keyboard[i].current;
4144+ for (i = 0; i < RGFW_mouseFinal; i++) _RGFW->mouseButtons[i].prev = _RGFW->mouseButtons[i].current;
4145+ _RGFW->scrollX = 0.0f;
4146+ _RGFW->scrollY = 0.0f;
4147+ _RGFW->vectorX = (float)0.0f;
4148+ _RGFW->vectorY = (float)0.0f;
4149+ RGFW_MEMZERO(&_RGFW->windowState, sizeof(_RGFW->windowState));
4150+
4151+ for (RGFW_dataDropNode* node = _RGFW->dndRoot; node; ) {
4152+ RGFW_dataDropNode* next = node->next;
4153+ RGFW_FREE(node);
4154+ node = next;
4155+ }
4156+
4157+ _RGFW->dndRoot = NULL;
4158+ _RGFW->dndCur = NULL;
4159+}
4160+
4161+RGFW_bool RGFW_isKeyPressed(RGFW_key key) {
4162+ RGFW_ASSERT(_RGFW != NULL);
4163+ return _RGFW->keyboard[key].current && !_RGFW->keyboard[key].prev;
4164+}
4165+RGFW_bool RGFW_isKeyDown(RGFW_key key) {
4166+ RGFW_ASSERT(_RGFW != NULL);
4167+ return _RGFW->keyboard[key].current;
4168+}
4169+RGFW_bool RGFW_isKeyReleased(RGFW_key key) {
4170+ RGFW_ASSERT(_RGFW != NULL);
4171+ return !_RGFW->keyboard[key].current && _RGFW->keyboard[key].prev;
4172+}
4173+
4174+
4175+RGFW_bool RGFW_isMousePressed(RGFW_mouseButton button) {
4176+ RGFW_ASSERT(_RGFW != NULL);
4177+ return _RGFW->mouseButtons[button].current && !_RGFW->mouseButtons[button].prev;
4178+}
4179+RGFW_bool RGFW_isMouseDown(RGFW_mouseButton button) {
4180+ RGFW_ASSERT(_RGFW != NULL);
4181+ return _RGFW->mouseButtons[button].current;
4182+}
4183+RGFW_bool RGFW_isMouseReleased(RGFW_mouseButton button) {
4184+ RGFW_ASSERT(_RGFW != NULL);
4185+ return !_RGFW->mouseButtons[button].current && _RGFW->mouseButtons[button].prev;
4186+}
4187+
4188+void RGFW_getMouseScroll(float* x, float* y) {
4189+ RGFW_ASSERT(_RGFW != NULL);
4190+ if (x) *x = _RGFW->scrollX;
4191+ if (y) *y = _RGFW->scrollY;
4192+}
4193+
4194+void RGFW_getMouseVector(float* x, float* y) {
4195+ RGFW_ASSERT(_RGFW != NULL);
4196+ if (x) *x = _RGFW->vectorX;
4197+ if (y) *y = _RGFW->vectorY;
4198+}
4199+
4200+RGFW_bool RGFW_window_didMouseLeave(RGFW_window* win) { return _RGFW->windowState.winLeave == win && _RGFW->windowState.mouseLeave; }
4201+RGFW_bool RGFW_window_didMouseEnter(RGFW_window* win) { return _RGFW->windowState.win == win && _RGFW->windowState.mouseEnter; }
4202+RGFW_bool RGFW_window_isMouseInside(RGFW_window* win) { return win->internal.mouseInside; }
4203+
4204+RGFW_bool RGFW_window_isDataDragging(RGFW_window* win) { return RGFW_window_getDataDrag(win, (i32*)NULL, (i32*)NULL); }
4205+RGFW_bool RGFW_window_didDataDrop(RGFW_window* win) { return RGFW_window_getDataDrop(win) != NULL;}
4206+
4207+
4208+RGFW_bool RGFW_window_getDataDrag(RGFW_window* win, i32* x, i32* y) {
4209+ if (_RGFW->windowState.win != win || _RGFW->windowState.dataDragging == RGFW_FALSE) return RGFW_FALSE;
4210+ if (x) *x = _RGFW->windowState.dropX;
4211+ if (y) *y = _RGFW->windowState.dropY;
4212+ return RGFW_TRUE;
4213+}
4214+RGFW_dataDropNode* RGFW_window_getDataDrop(RGFW_window* win) {
4215+ if (_RGFW->windowState.win != win || _RGFW->windowState.dataDrop == RGFW_FALSE) return NULL;
4216+ return _RGFW->dndRoot;
4217+}
4218+
4219+RGFW_bool RGFW_window_checkEvent(RGFW_window* win, RGFW_event* event) {
4220+ if (_RGFW->eventLen == 0 && _RGFW->polledEvents == RGFW_FALSE) {
4221+ _RGFW->queueEvents = RGFW_TRUE;
4222+ RGFW_pollEvents();
4223+ _RGFW->polledEvents = RGFW_TRUE;
4224+ }
4225+
4226+ if (RGFW_window_checkQueuedEvent(win, event) == RGFW_FALSE) {
4227+ _RGFW->polledEvents = RGFW_FALSE;
4228+ return RGFW_FALSE;
4229+ }
4230+
4231+ return RGFW_TRUE;
4232+}
4233+
4234+RGFW_bool RGFW_window_checkQueuedEvent(RGFW_window* win, RGFW_event* event) {
4235+ RGFW_event* ev;
4236+ RGFW_ASSERT(win != NULL);
4237+ _RGFW->queueEvents = RGFW_TRUE;
4238+ /* check queued events */
4239+ ev = RGFW_window_eventQueuePop(win);
4240+ if (ev == NULL) return RGFW_FALSE;
4241+
4242+ *event = *ev;
4243+ return RGFW_TRUE;
4244+}
4245+
4246+RGFW_event* RGFW_window_eventQueuePop(RGFW_window* win) {
4247+ RGFW_event* ev = RGFW_eventQueuePop();
4248+ if (ev == NULL) return ev;
4249+
4250+ for (i32 i = 1; i < _RGFW->eventLen && ev->common.win != win && ev->common.win != NULL; i++) {
4251+ RGFW_eventQueuePush(ev);
4252+ ev = RGFW_eventQueuePop();
4253+ }
4254+
4255+ if (ev->common.win != win && ev->common.win != NULL) {
4256+ return NULL;
4257+ }
4258+
4259+ return ev;
4260+}
4261+
4262+void RGFW_setRootWindow(RGFW_window* win) { _RGFW->root = win; }
4263+RGFW_window* RGFW_getRootWindow(void) { return _RGFW->root; }
4264+
4265+#ifndef RGFW_EGL
4266+RGFW_bool RGFW_loadEGL(void) { return RGFW_FALSE; }
4267+#endif
4268+
4269+void RGFW_window_setFlagsInternal(RGFW_window* win, RGFW_windowFlags flags, RGFW_windowFlags cmpFlags) {
4270+ if (flags & RGFW_windowNoBorder) RGFW_window_setBorder(win, 0);
4271+ else if (cmpFlags & RGFW_windowNoBorder) RGFW_window_setBorder(win, 1);
4272+ if (flags & RGFW_windowMaximize) RGFW_window_maximize(win);
4273+ else if (cmpFlags & RGFW_windowMaximize) RGFW_window_restore(win);
4274+ if (flags & RGFW_windowMinimize) RGFW_window_minimize(win);
4275+ else if (cmpFlags & RGFW_windowMinimize) RGFW_window_restore(win);
4276+ if (flags & RGFW_windowCenter) RGFW_window_center(win);
4277+ if (flags & RGFW_windowCenterCursor) RGFW_window_moveMouse(win, win->x + (win->w / 2), win->y + (win->h / 2));
4278+ if (flags & RGFW_windowFullscreen) RGFW_window_setFullscreen(win, RGFW_TRUE);
4279+ else if (cmpFlags & RGFW_windowFullscreen) RGFW_window_setFullscreen(win, 0);
4280+ if (flags & RGFW_windowHideMouse) RGFW_window_showMouse(win, 0);
4281+ else if (cmpFlags & RGFW_windowHideMouse) RGFW_window_showMouse(win, 1);
4282+ if (flags & RGFW_windowHide) RGFW_window_hide(win);
4283+ else if (cmpFlags & RGFW_windowHide) RGFW_window_show(win);
4284+ if (flags & RGFW_windowFloating) RGFW_window_setFloating(win, 1);
4285+ else if (cmpFlags & RGFW_windowFloating) RGFW_window_setFloating(win, 0);
4286+ if (flags & RGFW_windowRawMouse) RGFW_window_setRawMouseMode(win, RGFW_TRUE);
4287+ else if (cmpFlags & RGFW_windowRawMouse) RGFW_window_setRawMouseMode(win, RGFW_FALSE);
4288+ if (flags & RGFW_windowCaptureMouse) RGFW_window_captureRawMouse(win, RGFW_TRUE);
4289+ else if (cmpFlags & RGFW_windowCaptureMouse) RGFW_window_captureMouse(win, RGFW_FALSE);
4290+ if (flags & RGFW_windowFocus) RGFW_window_focus(win);
4291+ if (flags & RGFW_windowScaleToMonitor) RGFW_window_scaleToMonitor(win);
4292+
4293+ if (flags & RGFW_windowNoResize) {
4294+ RGFW_window_setMaxSize(win, win->w, win->h);
4295+ RGFW_window_setMinSize(win, win->w, win->h);
4296+ } else if (cmpFlags & RGFW_windowNoResize) {
4297+ RGFW_window_setMaxSize(win, 0, 0);
4298+ RGFW_window_setMinSize(win, 0, 0);
4299+ }
4300+
4301+ win->internal.flags = flags;
4302+}
4303+
4304+
4305+void RGFW_window_setFlags(RGFW_window* win, RGFW_windowFlags flags) { RGFW_window_setFlagsInternal(win, flags, win->internal.flags); }
4306+
4307+RGFW_bool RGFW_window_isInFocus(RGFW_window* win) {
4308+#ifdef RGFW_WASM
4309+ return RGFW_TRUE;
4310+#else
4311+ return RGFW_BOOL(win->internal.inFocus);
4312+#endif
4313+}
4314+
4315+void RGFW_setClassName(const char* name) { RGFW_init(); _RGFW->className = name; }
4316+void RGFW_setBuildDND(RGFW_bool state) { _RGFW->dndBuild = state; }
4317+
4318+#ifndef RGFW_X11
4319+void RGFW_setXInstName(const char* name) { RGFW_UNUSED(name); }
4320+#endif
4321+
4322+RGFW_bool RGFW_window_getMouse(RGFW_window* win, i32* x, i32* y) {
4323+ RGFW_ASSERT(win != NULL);
4324+ if (x) *x = win->internal.lastMouseX;
4325+ if (y) *y = win->internal.lastMouseY;
4326+ return RGFW_TRUE;
4327+}
4328+
4329+RGFW_bool RGFW_window_isKeyPressed(RGFW_window* win, RGFW_key key) { return RGFW_isKeyPressed(key) && RGFW_window_isInFocus(win); }
4330+RGFW_bool RGFW_window_isKeyDown(RGFW_window* win, RGFW_key key) { return RGFW_isKeyDown(key) && RGFW_window_isInFocus(win); }
4331+RGFW_bool RGFW_window_isKeyReleased(RGFW_window* win, RGFW_key key) { return RGFW_isKeyReleased(key) && RGFW_window_isInFocus(win); }
4332+
4333+RGFW_bool RGFW_window_isMousePressed(RGFW_window* win, RGFW_mouseButton button) { return RGFW_isMousePressed(button) && RGFW_window_isInFocus(win); }
4334+RGFW_bool RGFW_window_isMouseDown(RGFW_window* win, RGFW_mouseButton button) { return RGFW_isMouseDown(button) && RGFW_window_isInFocus(win); }
4335+RGFW_bool RGFW_window_isMouseReleased(RGFW_window* win, RGFW_mouseButton button) { return RGFW_isMouseReleased(button) && RGFW_window_isInFocus(win); }
4336+
4337+
4338+
4339+#ifndef RGFW_X11
4340+void* RGFW_getDisplay_X11(void) { return NULL; }
4341+u64 RGFW_window_getWindow_X11(RGFW_window* win) { RGFW_UNUSED(win); return 0; }
4342+#endif
4343+
4344+#ifndef RGFW_WAYLAND
4345+struct wl_display* RGFW_getDisplay_Wayland(void) { return NULL; }
4346+struct wl_surface* RGFW_window_getWindow_Wayland(RGFW_window* win) { RGFW_UNUSED(win); return NULL; }
4347+#endif
4348+
4349+#ifndef RGFW_WINDOWS
4350+void* RGFW_window_getHWND(RGFW_window* win) { RGFW_UNUSED(win); return NULL; }
4351+void* RGFW_window_getHDC(RGFW_window* win) { RGFW_UNUSED(win); return NULL; }
4352+#endif
4353+
4354+#ifndef RGFW_MACOS
4355+void* RGFW_window_getView_OSX(RGFW_window* win) { RGFW_UNUSED(win); return NULL; }
4356+void RGFW_window_setLayer_OSX(RGFW_window* win, void* layer) { RGFW_UNUSED(win); RGFW_UNUSED(layer); }
4357+void* RGFW_getLayer_OSX(void) { return NULL; }
4358+void* RGFW_window_getWindow_OSX(RGFW_window* win) { RGFW_UNUSED(win); return NULL; }
4359+#endif
4360+
4361+void RGFW_setBit(u32* var, u32 mask, RGFW_bool set) {
4362+ if (set) *var |= mask;
4363+ else *var &= ~mask;
4364+}
4365+
4366+void RGFW_window_center(RGFW_window* win) {
4367+ RGFW_ASSERT(win != NULL);
4368+ RGFW_monitor* mon = RGFW_window_getMonitor(win);
4369+ if (mon == NULL) return;
4370+
4371+ RGFW_window_move(win, mon->x + ((i32)(mon->mode.w - win->w) / 2), mon->y + ((mon->mode.h - win->h) / 2));
4372+}
4373+
4374+RGFW_bool RGFW_monitor_scaleToWindow(RGFW_monitor* mon, RGFW_window* win) {
4375+ RGFW_monitorMode mode;
4376+ RGFW_ASSERT(win != NULL);
4377+
4378+ mode.w = win->w;
4379+ mode.h = win->h;
4380+ RGFW_bool ret = RGFW_monitor_requestMode(mon, &mode, RGFW_monitorScale);
4381+
4382+ /* move window to monitor origin so it doesn't move to the next monitor */
4383+ RGFW_window_move(win, mon->x, mon->y);
4384+
4385+ return ret;
4386+}
4387+
4388+void RGFW_splitBPP(u32 bpp, RGFW_monitorMode* mode) {
4389+ if (bpp == 32) bpp = 24;
4390+ mode->red = mode->green = mode->blue = (u8)(bpp / 3);
4391+
4392+ u32 delta = bpp - (mode->red * 3); /* handle leftovers */
4393+ if (delta >= 1) mode->green = mode->green + 1;
4394+ if (delta == 2) mode->red = mode->red + 1;
4395+}
4396+
4397+RGFW_bool RGFW_monitorModeCompare(RGFW_monitorMode* mon, RGFW_monitorMode* mon2, RGFW_modeRequest request) {
4398+ RGFW_ASSERT(mon);
4399+ RGFW_ASSERT(mon2);
4400+
4401+ return (((mon->w == mon2->w && mon->h == mon2->h) || !(request & RGFW_monitorScale)) &&
4402+ ((mon->refreshRate == mon2->refreshRate) || !(request & RGFW_monitorRefresh)) &&
4403+ ((mon->red == mon2->red && mon->green == mon2->green && mon->blue == mon2->blue) || !(request & RGFW_monitorRGB)));
4404+}
4405+
4406+RGFW_bool RGFW_window_shouldClose(RGFW_window* win) {
4407+ return (win == NULL || win->internal.shouldClose || (win->internal.exitKey && RGFW_isKeyDown(win->internal.exitKey)));
4408+}
4409+
4410+void RGFW_window_setShouldClose(RGFW_window* win, RGFW_bool shouldClose) {
4411+ if (shouldClose) {
4412+ RGFW_windowCloseCallback(win);
4413+ } else {
4414+ win->internal.shouldClose = RGFW_FALSE;
4415+ }
4416+}
4417+
4418+void RGFW_window_scaleToMonitor(RGFW_window* win) {
4419+ RGFW_monitor* monitor = RGFW_window_getMonitor(win);
4420+ if (monitor->scaleX == 0 && monitor->scaleY == 0)
4421+ return;
4422+
4423+ RGFW_window_resize(win, (i32)(monitor->scaleX * (float)win->w), (i32)(monitor->scaleY * (float)win->h));
4424+}
4425+
4426+void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor* m) {
4427+ RGFW_window_move(win, m->x + win->x, m->y + win->y);
4428+}
4429+
4430+RGFW_surface* RGFW_createSurface(u8* data, i32 w, i32 h, RGFW_format format) {
4431+ RGFW_surface* surface = (RGFW_surface*)RGFW_ALLOC(sizeof(RGFW_surface));
4432+ RGFW_MEMZERO(surface, sizeof(RGFW_surface));
4433+ RGFW_createSurfacePtr(data, w, h, format, surface);
4434+ return surface;
4435+}
4436+
4437+void RGFW_surface_setConvertFunc(RGFW_surface* surface, RGFW_convertImageDataFunc func) {
4438+ surface->convertFunc = func;
4439+}
4440+
4441+void RGFW_surface_free(RGFW_surface* surface) {
4442+ RGFW_surface_freePtr(surface);
4443+ RGFW_FREE(surface);
4444+}
4445+
4446+RGFW_nativeImage* RGFW_surface_getNativeImage(RGFW_surface* surface) {
4447+ return &surface->native;
4448+}
4449+
4450+RGFW_surface* RGFW_window_createSurface(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format) {
4451+ RGFW_surface* surface = (RGFW_surface*)RGFW_ALLOC(sizeof(RGFW_surface));
4452+ RGFW_MEMZERO(surface, sizeof(RGFW_surface));
4453+ RGFW_window_createSurfacePtr(win, data, w, h, format, surface);
4454+ return surface;
4455+}
4456+
4457+#ifndef RGFW_X11
4458+RGFW_bool RGFW_window_createSurfacePtr(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) {
4459+ RGFW_UNUSED(win);
4460+ return RGFW_createSurfacePtr(data, w, h, format, surface);
4461+}
4462+#endif
4463+
4464+const RGFW_colorLayout RGFW_layouts[RGFW_formatCount] = {
4465+ { 0, 1, 2, 3, 3 }, /* RGFW_formatRGB8 */
4466+ { 2, 1, 0, 3, 3 }, /* RGFW_formatBGR8 */
4467+ { 0, 1, 2, 3, 4 }, /* RGFW_formatRGBA8 */
4468+ { 1, 2, 3, 0, 4 }, /* RGFW_formatARGB8 */
4469+ { 2, 1, 0, 3, 4 }, /* RGFW_formatBGRA8 */
4470+ { 3, 2, 1, 0, 4 }, /* RGFW_formatABGR8 */
4471+};
4472+
4473+
4474+void RGFW_copyImageData(u8* dest_data, i32 w, i32 h, RGFW_format dest_format, u8* src_data, RGFW_format src_format, RGFW_convertImageDataFunc func) {
4475+ RGFW_copyImageData64(dest_data, w, h, dest_format, src_data, src_format, RGFW_FALSE, func);
4476+}
4477+
4478+RGFWDEF void RGFW_convertImageData64(u8* dest_data, u8* src_data, const RGFW_colorLayout* srcLayout, const RGFW_colorLayout* destLayout, size_t count, RGFW_bool is64bit);
4479+void RGFW_convertImageData64(u8* dest_data, u8* src_data, const RGFW_colorLayout* srcLayout, const RGFW_colorLayout* destLayout, size_t count, RGFW_bool is64bit) {
4480+ u32 i, i2 = 0;
4481+ u8 rgba[4] = {0};
4482+
4483+ for (i = 0; i < count; i++) {
4484+ const u8* src_px = &src_data[i * srcLayout->channels];
4485+ u8* dst_px = &dest_data[i2 * destLayout->channels];
4486+ rgba[0] = src_px[srcLayout->r];
4487+ rgba[1] = src_px[srcLayout->g];
4488+ rgba[2] = src_px[srcLayout->b];
4489+ rgba[3] = (srcLayout->channels == 4) ? src_px[srcLayout->a] : 255;
4490+
4491+ dst_px[destLayout->r] = rgba[0];
4492+ dst_px[destLayout->g] = rgba[1];
4493+ dst_px[destLayout->b] = rgba[2];
4494+ if (destLayout->channels == 4)
4495+ dst_px[destLayout->a] = rgba[3];
4496+
4497+ i2 += 1 + is64bit;
4498+ }
4499+}
4500+
4501+void RGFW_copyImageData64(u8* dest_data, i32 dest_w, i32 dest_h, RGFW_format dest_format, u8* src_data, RGFW_format src_format, RGFW_bool is64bit, RGFW_convertImageDataFunc func) {
4502+ RGFW_ASSERT(dest_data && src_data);
4503+
4504+ u32 count = (u32)(dest_w * dest_h);
4505+
4506+ if (src_format == dest_format) {
4507+ u32 channels = (dest_format >= RGFW_formatRGBA8) ? 4 : 3;
4508+ RGFW_MEMCPY(dest_data, src_data, count * channels);
4509+ return;
4510+ }
4511+
4512+ const RGFW_colorLayout* srcLayout = &RGFW_layouts[src_format];
4513+ const RGFW_colorLayout* destLayout = &RGFW_layouts[dest_format];
4514+
4515+ if (is64bit || func == NULL) {
4516+ RGFW_convertImageData64(dest_data, src_data, srcLayout, destLayout, count, is64bit);
4517+ } else {
4518+ func(dest_data, src_data, srcLayout, destLayout, count);
4519+ }
4520+}
4521+
4522+RGFW_monitorNode* RGFW_monitors_add(const RGFW_monitor* mon) {
4523+ RGFW_monitorNode* node = NULL;
4524+
4525+ #if (RGFW_PREALLOCATED_MONITORS)
4526+ node = _RGFW->monitors.freeList.head;
4527+ if (node) {
4528+ _RGFW->monitors.freeList.head = node->next;
4529+ if (_RGFW->monitors.freeList.head == NULL) {
4530+ _RGFW->monitors.freeList.cur = NULL;
4531+ }
4532+ } else
4533+ #elif !defined(RGFW_NO_ALLOCATE_MONITORS)
4534+ {
4535+ node = (RGFW_monitorNode*)RGFW_ALLOC(sizeof(RGFW_monitorNode));
4536+ }
4537+ #endif
4538+
4539+ if (node == NULL) return NULL;
4540+
4541+ node->next = NULL;
4542+
4543+ if (_RGFW->monitors.list.head == NULL) {
4544+ _RGFW->monitors.list.head = node;
4545+ } else {
4546+ _RGFW->monitors.list.cur->next = node;
4547+ }
4548+
4549+ _RGFW->monitors.list.cur = node;
4550+
4551+ if (mon) node->mon = *mon;
4552+ node->mon.node = node;
4553+ node->disconnected = RGFW_FALSE;
4554+
4555+ _RGFW->monitors.count += 1;
4556+ return node;
4557+}
4558+
4559+void RGFW_monitors_remove(RGFW_monitorNode* node, RGFW_monitorNode* prev) {
4560+ _RGFW->monitors.count -= 1;
4561+
4562+ /* remove node from the list */
4563+ if (prev != node) {
4564+ prev->next = node->next;
4565+ } else { /* node is the head */
4566+ _RGFW->monitors.list.head = NULL;
4567+ }
4568+
4569+ node->next = NULL;
4570+
4571+ #if (RGFW_PREALLOCATED_MONITORS)
4572+ /* check if the monitor was allocated in the heap or not */
4573+ if (node >= _RGFW->monitors.data && node <= &_RGFW->monitors.data[RGFW_PREALLOCATED_MONITORS - 1]) {
4574+ /* move node to the free list */
4575+ if (_RGFW->monitors.freeList.head == NULL) {
4576+ _RGFW->monitors.freeList.head = node;
4577+ } else {
4578+ _RGFW->monitors.freeList.cur->next = node;
4579+ }
4580+
4581+ _RGFW->monitors.freeList.cur = node;
4582+ } else
4583+ {
4584+ #elif !defined(RGFW_NO_ALLOCATE_MONITORS)
4585+ RGFW_FREE(node);
4586+ #endif
4587+ }
4588+}
4589+
4590+void RGFW_monitors_refresh(void) {
4591+ RGFW_monitorNode* prev = _RGFW->monitors.list.head;
4592+ for (RGFW_monitorNode* node = _RGFW->monitors.list.head; node; node = node->next) {
4593+ if (node->disconnected == RGFW_FALSE) continue;
4594+
4595+ RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_FALSE);
4596+ RGFW_monitors_remove(node, prev);
4597+ prev = node;
4598+ }
4599+}
4600+
4601+RGFW_monitorMode* RGFW_monitor_getModes(RGFW_monitor* monitor, size_t* count) {
4602+ size_t num = RGFW_monitor_getModesPtr(monitor, NULL);
4603+ RGFW_monitorMode* modes = (RGFW_monitorMode*)RGFW_ALLOC(num * sizeof(RGFW_monitorNode));
4604+ num = RGFW_monitor_getModesPtr(monitor, &modes);
4605+
4606+ if (count) *count = num;
4607+ return modes;
4608+}
4609+
4610+void RGFW_freeModes(RGFW_monitorMode* modes) {
4611+ RGFW_FREE(modes);
4612+}
4613+
4614+RGFW_bool RGFW_monitor_findClosestMode(RGFW_monitor* monitor, RGFW_monitorMode* mode, RGFW_monitorMode* closest) {
4615+ size_t count = RGFW_monitor_getModesPtr(monitor, NULL);
4616+ RGFW_monitorMode* modes = (RGFW_monitorMode*)RGFW_ALLOC(count * sizeof(RGFW_monitorNode));
4617+ count = RGFW_monitor_getModesPtr(monitor, &modes);
4618+
4619+ RGFW_monitorMode* chosen = NULL;
4620+
4621+ u32 topScore = 1;
4622+ for (size_t i = 0; i < count; i++) {
4623+ RGFW_monitorMode* mode2 = &modes[i];
4624+
4625+ u32 score = 0;
4626+ if (mode->w == mode2->w && mode->h == mode2->h) score += 1000;
4627+ if (mode->red == mode2->red && mode->green == mode2->green && mode->blue == mode2->blue) score += 100;
4628+ if (mode->refreshRate == mode->refreshRate) score += 10;
4629+
4630+ if (score > topScore) {
4631+ topScore = score;
4632+ chosen = mode2;
4633+ }
4634+ }
4635+
4636+ if (chosen && closest) *closest = *chosen;
4637+
4638+
4639+ RGFW_FREE(modes);
4640+
4641+ return (chosen == NULL) ? RGFW_FALSE : RGFW_TRUE;
4642+}
4643+
4644+RGFW_bool RGFW_monitor_getPosition(RGFW_monitor* monitor, i32* x, i32* y) {
4645+ if (x) *x = monitor->x;
4646+ if (y) *y = monitor->y;
4647+ return RGFW_TRUE;
4648+}
4649+
4650+const char* RGFW_monitor_getName(RGFW_monitor* monitor) {
4651+ return monitor->name;
4652+}
4653+
4654+RGFW_bool RGFW_monitor_getScale(RGFW_monitor* monitor, float* x, float* y) {
4655+ if (x) *x = monitor->scaleX;
4656+ if (y) *y = monitor->scaleY;
4657+ return RGFW_TRUE;
4658+}
4659+
4660+RGFW_bool RGFW_monitor_getPhysicalSize(RGFW_monitor* monitor, float* w, float* h) {
4661+ if (w) *w = monitor->physW;
4662+ if (h) *h = monitor->physH;
4663+ return RGFW_TRUE;
4664+}
4665+
4666+void RGFW_monitor_setUserPtr(RGFW_monitor* monitor, void* userPtr) {
4667+ monitor->userPtr = userPtr;
4668+}
4669+
4670+void* RGFW_monitor_getUserPtr(RGFW_monitor* monitor) {
4671+ return monitor->userPtr;
4672+}
4673+
4674+RGFW_bool RGFW_monitor_getMode(RGFW_monitor* monitor, RGFW_monitorMode* mode) {
4675+ if (mode) *mode = monitor->mode;
4676+ return RGFW_TRUE;
4677+}
4678+
4679+RGFW_gammaRamp* RGFW_monitor_getGammaRamp(RGFW_monitor* monitor) {
4680+ RGFW_gammaRamp* ramp = (RGFW_gammaRamp*)RGFW_ALLOC(sizeof(RGFW_gammaRamp));
4681+ ramp->count = RGFW_monitor_getGammaRampPtr(monitor, NULL);
4682+ ramp->red = (u16*)RGFW_ALLOC(sizeof(u16) * ramp->count);
4683+ ramp->green = (u16*)RGFW_ALLOC(sizeof(u16) * ramp->count);
4684+ ramp->blue = (u16*)RGFW_ALLOC(sizeof(u16) * ramp->count);
4685+ ramp->count = RGFW_monitor_getGammaRampPtr(monitor, ramp);
4686+
4687+ return ramp;
4688+}
4689+
4690+void RGFW_freeGammaRamp(RGFW_gammaRamp* ramp) {
4691+ RGFW_FREE(ramp->red);
4692+ RGFW_FREE(ramp->green);
4693+ RGFW_FREE(ramp->blue);
4694+ RGFW_FREE(ramp);
4695+}
4696+
4697+RGFW_bool RGFW_monitor_setGammaPtr(RGFW_monitor* monitor, float gamma, u16* ptr, size_t count) {
4698+ RGFW_ASSERT(monitor);
4699+ RGFW_ASSERT(gamma > 0.0f);
4700+
4701+ size_t i;
4702+ for (i = 0; i < count; i++) {
4703+ float value = (float)i / (float) (count - 1);
4704+ #ifndef RGFW_NO_MATH
4705+ value = powf(value, 1.f / gamma) * 65535.f + 0.5f;
4706+ #endif
4707+ value = RGFW_MIN(value, 65535.f);
4708+
4709+ ptr[i] = (u16)value;
4710+ }
4711+
4712+ RGFW_gammaRamp ramp;
4713+ ramp.red = ptr;
4714+ ramp.green = ptr;
4715+ ramp.blue = ptr;
4716+ ramp.count = count;
4717+
4718+ return RGFW_monitor_setGammaRamp(monitor, &ramp);
4719+}
4720+
4721+RGFW_bool RGFW_monitor_setGamma(RGFW_monitor* monitor, float gamma) {
4722+ size_t count = RGFW_monitor_getGammaRampPtr(monitor, NULL);
4723+ u16* ptr = (u16*)RGFW_ALLOC(count * sizeof(u16));
4724+
4725+ RGFW_bool ret = RGFW_monitor_setGammaPtr(monitor, gamma, ptr, count);
4726+ RGFW_FREE(ptr);
4727+
4728+ return ret;
4729+}
4730+
4731+RGFW_monitor** RGFW_getMonitors(size_t* len) {
4732+ if (len != NULL) *len = 0;
4733+
4734+ size_t count = 0;
4735+ if (RGFW_getMonitorsPtr(0, NULL, &count) == RGFW_FALSE || count == 0) return NULL;
4736+
4737+ RGFW_monitor** monitors = (RGFW_monitor**)RGFW_ALLOC(sizeof(RGFW_monitor*) * count);
4738+
4739+ if (RGFW_getMonitorsPtr(count, monitors, &count) == RGFW_FALSE) {
4740+ RGFW_FREE(monitors);
4741+ return NULL;
4742+ }
4743+
4744+ if (len != NULL) *len = count;
4745+
4746+ return monitors;
4747+}
4748+
4749+RGFW_bool RGFW_getMonitorsPtr(size_t max, RGFW_monitor** monitors, size_t* len) {
4750+ RGFW_init();
4751+ if (len != NULL) {
4752+ *len = _RGFW->monitors.count;
4753+ }
4754+
4755+ if (monitors == NULL || max == 0) return RGFW_TRUE;
4756+
4757+
4758+ if (len != NULL) {
4759+ *len = max;
4760+ }
4761+
4762+ size_t i = 0;
4763+ RGFW_monitorNode* cur_node = _RGFW->monitors.list.head;
4764+ while (cur_node != NULL && i < max) {
4765+ monitors[i] = &cur_node->mon;
4766+ i++;
4767+ cur_node = cur_node->next;
4768+ }
4769+
4770+ return RGFW_TRUE;
4771+}
4772+
4773+RGFW_monitor* RGFW_getPrimaryMonitor(void) {
4774+ if (_RGFW->monitors.primary == NULL) {
4775+ _RGFW->monitors.primary = _RGFW->monitors.list.head;
4776+ }
4777+
4778+ return &_RGFW->monitors.primary->mon;
4779+}
4780+
4781+RGFW_bool RGFW_window_setIcon(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format) {
4782+ return RGFW_window_setIconEx(win, data, w, h, format, RGFW_iconBoth);
4783+}
4784+
4785+void RGFW_window_captureMouse(RGFW_window* win, RGFW_bool state) {
4786+ win->internal.captureMouse = state;
4787+ RGFW_window_captureMousePlatform(win, state);
4788+}
4789+
4790+void RGFW_window_setRawMouseMode(RGFW_window* win, RGFW_bool state) {
4791+ win->internal.rawMouse = state;
4792+ RGFW_window_setRawMouseModePlatform(win, state);
4793+}
4794+
4795+void RGFW_window_captureRawMouse(RGFW_window* win, RGFW_bool state) {
4796+ RGFW_window_captureMouse(win, state);
4797+ RGFW_window_setRawMouseMode(win, state);
4798+}
4799+
4800+RGFW_bool RGFW_window_isRawMouseMode(RGFW_window* win) { return RGFW_BOOL(win->internal.rawMouse); }
4801+RGFW_bool RGFW_window_isCaptured(RGFW_window* win) { return RGFW_BOOL(win->internal.captureMouse); }
4802+
4803+void RGFW_keyUpdateKeyMod(RGFW_window* win, RGFW_keymod mod, RGFW_bool value) {
4804+ if (value) win->internal.mod |= mod;
4805+ else win->internal.mod &= ~mod;
4806+}
4807+
4808+void RGFW_keyUpdateKeyModsEx(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll) {
4809+ RGFW_keyUpdateKeyMod(win, RGFW_modCapsLock, capital);
4810+ RGFW_keyUpdateKeyMod(win, RGFW_modNumLock, numlock);
4811+ RGFW_keyUpdateKeyMod(win, RGFW_modControl, control);
4812+ RGFW_keyUpdateKeyMod(win, RGFW_modAlt, alt);
4813+ RGFW_keyUpdateKeyMod(win, RGFW_modShift, shift);
4814+ RGFW_keyUpdateKeyMod(win, RGFW_modSuper, super);
4815+ RGFW_keyUpdateKeyMod(win, RGFW_modScrollLock, scroll);
4816+}
4817+
4818+void RGFW_keyUpdateKeyMods(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool scroll) {
4819+ RGFW_keyUpdateKeyModsEx(win, capital, numlock,
4820+ RGFW_isKeyDown(RGFW_keyControlL) || RGFW_isKeyDown(RGFW_keyControlR),
4821+ RGFW_isKeyDown(RGFW_keyAltL) || RGFW_isKeyDown(RGFW_keyAltR),
4822+ RGFW_isKeyDown(RGFW_keyShiftL) || RGFW_isKeyDown(RGFW_keyShiftR),
4823+ RGFW_isKeyDown(RGFW_keySuperL) || RGFW_isKeyDown(RGFW_keySuperR),
4824+ scroll);
4825+}
4826+
4827+void RGFW_window_showMouseFlags(RGFW_window* win, RGFW_bool show) {
4828+ if (show && (win->internal.flags & RGFW_windowHideMouse))
4829+ win->internal.flags ^= RGFW_windowHideMouse;
4830+ else if (!show && !(win->internal.flags & RGFW_windowHideMouse))
4831+ win->internal.flags |= RGFW_windowHideMouse;
4832+}
4833+
4834+RGFW_bool RGFW_window_isMouseHidden(RGFW_window* win) {
4835+ return (RGFW_bool)RGFW_BOOL(((RGFW_window*)win)->internal.flags & RGFW_windowHideMouse);
4836+}
4837+
4838+RGFW_bool RGFW_window_borderless(RGFW_window* win) {
4839+ return (RGFW_bool)RGFW_BOOL(win->internal.flags & RGFW_windowNoBorder);
4840+}
4841+
4842+RGFW_bool RGFW_window_isFullscreen(RGFW_window* win){ return RGFW_BOOL(win->internal.flags & RGFW_windowFullscreen); }
4843+RGFW_bool RGFW_window_allowsDND(RGFW_window* win) { return RGFW_BOOL(win->internal.flags & RGFW_windowAllowDND); }
4844+
4845+RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) {
4846+ return RGFW_window_setMouseStandard(win, RGFW_mouseNormal);
4847+}
4848+
4849+RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, RGFW_mouseIcon icon) {
4850+ RGFW_ASSERT(win);
4851+ RGFW_ASSERT(icon < RGFW_mouseIconCount);
4852+ return RGFW_window_setMouse(win, _RGFW->standardMice[icon]);
4853+}
4854+
4855+RGFW_bool RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) {
4856+ RGFW_ASSERT(win && mouse);
4857+ if (mouse != _RGFW->hiddenMouse) {
4858+ win->internal.mouse = mouse;
4859+ }
4860+
4861+ return RGFW_window_setMousePlatform(win, mouse);
4862+}
4863+
4864+#ifndef RGFW_WINDOWS
4865+void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow) {
4866+ RGFW_setBit(&win->internal.flags, RGFW_windowAllowDND, allow);
4867+}
4868+#endif
4869+
4870+#if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WASM) || defined(RGFW_WAYLAND)
4871+#ifndef __USE_POSIX199309
4872+ #define __USE_POSIX199309
4873+#endif
4874+#include <time.h>
4875+struct timespec;
4876+#endif
4877+
4878+#if defined(RGFW_WAYLAND) || defined(RGFW_X11) || defined(RGFW_WINDOWS)
4879+void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) {
4880+ RGFW_window_showMouseFlags(win, show);
4881+ if (show == RGFW_FALSE) {
4882+ RGFW_window_setMouse(win, _RGFW->hiddenMouse);
4883+ } else {
4884+ RGFW_window_setMouse(win, win->internal.mouse);
4885+ }
4886+}
4887+#endif
4888+
4889+#ifndef RGFW_MACOS
4890+void RGFW_moveToMacOSResourceDir(void) { }
4891+#endif
4892+
4893+RGFWDEF RGFW_bool RGFW_isLatin(const char *string, size_t length);
4894+RGFW_bool RGFW_isLatin(const char *string, size_t length) {
4895+ for (size_t i = 0; i < length; i++) {
4896+ if ((u8)string[i] >= 0x80) {
4897+ return RGFW_TRUE;
4898+ }
4899+ }
4900+ return RGFW_FALSE;
4901+}
4902+
4903+RGFWDEF u32 RGFW_decodeUTF8(const char* string, size_t* starting_index);
4904+u32 RGFW_decodeUTF8(const char* string, size_t* starting_index) {
4905+ static const u32 offsets[] = {
4906+ 0x00000000u, 0x00003080u, 0x000e2080u,
4907+ 0x03c82080u, 0xfa082080u, 0x82082080u
4908+ };
4909+
4910+ u32 codepoint = (u8)string[(*starting_index)];
4911+ size_t count;
4912+ for (count = 1; (string[count + (*starting_index)] & 0xc0) == 0x80; count++) {
4913+ codepoint = (codepoint << 6) + (u8)string[count + (*starting_index)];
4914+ }
4915+
4916+ *starting_index += count;
4917+
4918+ RGFW_ASSERT(count <= 6);
4919+ return codepoint - offsets[count - 1];
4920+}
4921+
4922+/*
4923+ graphics API specific code (end of generic code)
4924+ starts here
4925+*/
4926+
4927+
4928+/*
4929+ OpenGL defines start here (Normal, EGL, OSMesa)
4930+*/
4931+
4932+#if defined(RGFW_OPENGL)
4933+/* EGL, OpenGL */
4934+#define RGFW_DEFAULT_GL_HINTS { \
4935+ /* Stencil */ 0, \
4936+ /* Samples */ 0, \
4937+ /* Stereo */ RGFW_FALSE, \
4938+ /* AuxBuffers */ 0, \
4939+ /* DoubleBuffer */ RGFW_TRUE, \
4940+ /* Red */ 8, \
4941+ /* Green */ 8, \
4942+ /* Blue */ 8, \
4943+ /* Alpha */ 8, \
4944+ /* Depth */ 24, \
4945+ /* AccumRed */ 0, \
4946+ /* AccumGreen */ 0, \
4947+ /* AccumBlue */ 0, \
4948+ /* AccumAlpha */ 0, \
4949+ /* SRGB */ RGFW_FALSE, \
4950+ /* Robustness */ RGFW_FALSE, \
4951+ /* Debug */ RGFW_FALSE, \
4952+ /* NoError */ RGFW_FALSE, \
4953+ /* ReleaseBehavior */ RGFW_glReleaseNone, \
4954+ /* Profile */ RGFW_glCore, \
4955+ /* Major */ 1, \
4956+ /* Minor */ 0, \
4957+ /* Share */ NULL, \
4958+ /* Share_EGL */ NULL, \
4959+ /* renderer */ RGFW_glAccelerated \
4960+}
4961+
4962+RGFW_glHints RGFW_globalHints_OpenGL_SRC = RGFW_DEFAULT_GL_HINTS;
4963+RGFW_glHints* RGFW_globalHints_OpenGL = &RGFW_globalHints_OpenGL_SRC;
4964+
4965+void RGFW_resetGlobalHints_OpenGL(void) {
4966+#if !defined(__cplusplus) || defined(RGFW_MACOS)
4967+ RGFW_globalHints_OpenGL_SRC = (RGFW_glHints)RGFW_DEFAULT_GL_HINTS;
4968+#else
4969+ RGFW_globalHints_OpenGL_SRC = RGFW_DEFAULT_GL_HINTS;
4970+#endif
4971+}
4972+void RGFW_setGlobalHints_OpenGL(RGFW_glHints* hints) { RGFW_globalHints_OpenGL = hints; }
4973+RGFW_glHints* RGFW_getGlobalHints_OpenGL(void) { RGFW_init(); return RGFW_globalHints_OpenGL; }
4974+
4975+
4976+void* RGFW_glContext_getSourceContext(RGFW_glContext* ctx) {
4977+ RGFW_UNUSED(ctx);
4978+
4979+#ifdef RGFW_WAYLAND
4980+ if (RGFW_usingWayland()) return (void*)ctx->egl.ctx;
4981+#endif
4982+
4983+#if defined(RGFW_X11)
4984+ return (void*)ctx->ctx;
4985+#else
4986+ return NULL;
4987+#endif
4988+}
4989+
4990+RGFW_glContext* RGFW_window_createContext_OpenGL(RGFW_window* win, RGFW_glHints* hints) {
4991+ #ifdef RGFW_WAYLAND
4992+ if (RGFW_usingWayland()) {
4993+ return (RGFW_glContext*)RGFW_window_createContext_EGL(win, hints);
4994+ }
4995+ #endif
4996+ RGFW_glContext* ctx = (RGFW_glContext*)RGFW_ALLOC(sizeof(RGFW_glContext));
4997+ if (RGFW_window_createContextPtr_OpenGL(win, ctx, hints) == RGFW_FALSE) {
4998+ RGFW_FREE(ctx);
4999+ win->src.ctx.native = NULL;
5000+ return NULL;
5001+ }
5002+ win->src.gfxType |= RGFW_gfxOwnedByRGFW;
5003+ return ctx;
5004+}
5005+
5006+RGFW_glContext* RGFW_window_getContext_OpenGL(RGFW_window* win) {
5007+ if (win->src.gfxType & RGFW_windowEGL) return NULL;
5008+ return win->src.ctx.native;
5009+}
5010+
5011+void RGFW_window_deleteContext_OpenGL(RGFW_window* win, RGFW_glContext* ctx) {
5012+ RGFW_window_deleteContextPtr_OpenGL(win, ctx);
5013+ if (win->src.gfxType & RGFW_gfxOwnedByRGFW) RGFW_FREE(ctx);
5014+}
5015+
5016+RGFW_bool RGFW_extensionSupportedStr(const char* extensions, const char* ext, size_t len) {
5017+ const char *start = extensions;
5018+ const char *where;
5019+ const char* terminator;
5020+
5021+ if (extensions == NULL || ext == NULL) {
5022+ return RGFW_FALSE;
5023+ }
5024+
5025+ while (ext[len - 1] == '\0' && len > 3) {
5026+ len--;
5027+ }
5028+
5029+ where = RGFW_STRSTR(extensions, ext);
5030+ while (where) {
5031+ terminator = where + len;
5032+ if ((where == start || *(where - 1) == ' ') &&
5033+ (*terminator == ' ' || *terminator == '\0')) {
5034+ return RGFW_TRUE;
5035+ }
5036+ where = RGFW_STRSTR(terminator, ext);
5037+ }
5038+
5039+ return RGFW_FALSE;
5040+}
5041+
5042+RGFWDEF RGFW_bool RGFW_extensionSupported_base(const char* extension, size_t len);
5043+RGFW_bool RGFW_extensionSupported_base(const char* extension, size_t len) {
5044+ #ifdef GL_NUM_EXTENSIONS
5045+ if (RGFW_globalHints_OpenGL->major >= 3) {
5046+ i32 i;
5047+
5048+ GLint count = 0;
5049+
5050+ RGFW_proc RGFW_glGetStringi = RGFW_getProcAddress_OpenGL("glGetStringi");
5051+ RGFW_proc RGFW_glGetIntegerv = RGFW_getProcAddress_OpenGL("glGetIntegerv");
5052+ if (RGFW_glGetIntegerv)
5053+ ((void(*)(GLenum, GLint*))RGFW_glGetIntegerv)(GL_NUM_EXTENSIONS, &count);
5054+
5055+ for (i = 0; RGFW_glGetStringi && i < count; i++) {
5056+ const char* en = ((const char* (*)(u32, u32))RGFW_glGetStringi)(GL_EXTENSIONS, (u32)i);
5057+ if (en && RGFW_STRNCMP(en, extension, len) == 0) {
5058+ return RGFW_TRUE;
5059+ }
5060+ }
5061+ } else
5062+#endif
5063+ {
5064+ RGFW_proc RGFW_glGetString = RGFW_getProcAddress_OpenGL("glGetString");
5065+ #define RGFW_GL_EXTENSIONS 0x1F03
5066+ if (RGFW_glGetString) {
5067+ const char* extensions = ((const char*(*)(u32))RGFW_glGetString)(RGFW_GL_EXTENSIONS);
5068+
5069+ if ((extensions != NULL) && RGFW_extensionSupportedStr(extensions, extension, len)) {
5070+ return RGFW_TRUE;
5071+ }
5072+ }
5073+ }
5074+ return RGFW_FALSE;
5075+}
5076+
5077+RGFW_bool RGFW_extensionSupported_OpenGL(const char* extension, size_t len) {
5078+ if (RGFW_extensionSupported_base(extension, len)) return RGFW_TRUE;
5079+ return RGFW_extensionSupportedPlatform_OpenGL(extension, len);
5080+}
5081+
5082+void RGFW_window_makeCurrentWindow_OpenGL(RGFW_window* win) {
5083+ if (win) {
5084+ _RGFW->current = win;
5085+ }
5086+
5087+ RGFW_window_makeCurrentContext_OpenGL(win);
5088+}
5089+
5090+RGFW_window* RGFW_getCurrentWindow_OpenGL(void) { return _RGFW->current; }
5091+void RGFW_attribStack_init(RGFW_attribStack* stack, i32* attribs, size_t max) { stack->attribs = attribs; stack->count = 0; stack->max = max; }
5092+void RGFW_attribStack_pushAttrib(RGFW_attribStack* stack, i32 attrib) {
5093+ RGFW_ASSERT(stack->count < stack->max);
5094+ stack->attribs[stack->count] = attrib;
5095+ stack->count += 1;
5096+}
5097+void RGFW_attribStack_pushAttribs(RGFW_attribStack* stack, i32 attrib1, i32 attrib2) {
5098+ RGFW_attribStack_pushAttrib(stack, attrib1);
5099+ RGFW_attribStack_pushAttrib(stack, attrib2);
5100+}
5101+
5102+/* EGL */
5103+#ifdef RGFW_EGL
5104+#include <EGL/egl.h>
5105+
5106+PFNEGLINITIALIZEPROC RGFW_eglInitialize;
5107+PFNEGLGETCONFIGSPROC RGFW_eglGetConfigs;
5108+PFNEGLCHOOSECONFIGPROC RGFW_eglChooseConfig;
5109+PFNEGLCREATEWINDOWSURFACEPROC RGFW_eglCreateWindowSurface;
5110+PFNEGLCREATECONTEXTPROC RGFW_eglCreateContext;
5111+PFNEGLMAKECURRENTPROC RGFW_eglMakeCurrent;
5112+PFNEGLGETDISPLAYPROC RGFW_eglGetDisplay;
5113+PFNEGLSWAPBUFFERSPROC RGFW_eglSwapBuffers;
5114+PFNEGLSWAPINTERVALPROC RGFW_eglSwapInterval;
5115+PFNEGLBINDAPIPROC RGFW_eglBindAPI;
5116+PFNEGLDESTROYCONTEXTPROC RGFW_eglDestroyContext;
5117+PFNEGLTERMINATEPROC RGFW_eglTerminate;
5118+PFNEGLDESTROYSURFACEPROC RGFW_eglDestroySurface;
5119+PFNEGLGETCURRENTCONTEXTPROC RGFW_eglGetCurrentContext;
5120+PFNEGLGETPROCADDRESSPROC RGFW_eglGetProcAddress = NULL;
5121+PFNEGLQUERYSTRINGPROC RGFW_eglQueryString;
5122+PFNEGLGETCONFIGATTRIBPROC RGFW_eglGetConfigAttrib;
5123+
5124+#define EGL_SURFACE_MAJOR_VERSION_KHR 0x3098
5125+#define EGL_SURFACE_MINOR_VERSION_KHR 0x30fb
5126+
5127+#ifdef RGFW_WINDOWS
5128+ #include <windows.h>
5129+#elif defined(RGFW_MACOS) || defined(RGFW_UNIX)
5130+ #include <dlfcn.h>
5131+#endif
5132+
5133+#ifdef RGFW_WAYLAND
5134+#include <wayland-egl.h>
5135+#endif
5136+
5137+void* RGFW_eglLibHandle = NULL;
5138+
5139+void* RGFW_getDisplay_EGL(void) { return _RGFW->EGL_display; }
5140+void* RGFW_eglContext_getSourceContext(RGFW_eglContext* ctx) { return ctx->ctx; }
5141+void* RGFW_eglContext_getSurface(RGFW_eglContext* ctx) { return ctx->surface; }
5142+struct wl_egl_window* RGFW_eglContext_wlEGLWindow(RGFW_eglContext* ctx) { return ctx->eglWindow; }
5143+
5144+RGFW_bool RGFW_loadEGL(void) {
5145+ RGFW_init();
5146+ if (RGFW_eglGetProcAddress != NULL) {
5147+ return RGFW_TRUE;
5148+ }
5149+
5150+#ifndef RGFW_WASM
5151+ #ifdef RGFW_WINDOWS
5152+ const char* libNames[] = { "libEGL.dll", "EGL.dll" };
5153+ #elif defined(RGFW_MACOS) || defined(RGFW_UNIX)
5154+ /* Linux and macOS */
5155+ const char* libNames[] = {
5156+ "libEGL.so.1", /* most common */
5157+ "libEGL.so", /* fallback */
5158+ "/System/Library/Frameworks/OpenGL.framework/OpenGL" /* fallback for older macOS EGL-like systems */
5159+ };
5160+ #endif
5161+
5162+ for (size_t i = 0; i < sizeof(libNames) / sizeof(libNames[0]); i++) {
5163+ #ifdef RGFW_WINDOWS
5164+ RGFW_eglLibHandle = (void*)LoadLibraryA(libNames[i]);
5165+ if (RGFW_eglLibHandle) {
5166+ RGFW_eglGetProcAddress = (PFNEGLGETPROCADDRESSPROC)(RGFW_proc)GetProcAddress((HMODULE)RGFW_eglLibHandle, "eglGetProcAddress");
5167+ break;
5168+ }
5169+ #elif defined(RGFW_MACOS) || defined(RGFW_UNIX)
5170+ RGFW_eglLibHandle = dlopen(libNames[i], RTLD_LAZY | RTLD_GLOBAL);
5171+ if (RGFW_eglLibHandle) {
5172+ void* lib = dlsym(RGFW_eglLibHandle, "eglGetProcAddress");
5173+ if (lib != NULL) RGFW_MEMCPY(&RGFW_eglGetProcAddress, &lib, sizeof(PFNEGLGETPROCADDRESSPROC));
5174+ break;
5175+ }
5176+ #endif
5177+ }
5178+
5179+ if (!RGFW_eglLibHandle || !RGFW_eglGetProcAddress) {
5180+ return RGFW_FALSE;
5181+ }
5182+
5183+ RGFW_eglInitialize = (PFNEGLINITIALIZEPROC) RGFW_eglGetProcAddress("eglInitialize");
5184+ RGFW_eglGetConfigs = (PFNEGLGETCONFIGSPROC) RGFW_eglGetProcAddress("eglGetConfigs");
5185+ RGFW_eglChooseConfig = (PFNEGLCHOOSECONFIGPROC) RGFW_eglGetProcAddress("eglChooseConfig");
5186+ RGFW_eglCreateWindowSurface = (PFNEGLCREATEWINDOWSURFACEPROC) RGFW_eglGetProcAddress("eglCreateWindowSurface");
5187+ RGFW_eglCreateContext = (PFNEGLCREATECONTEXTPROC) RGFW_eglGetProcAddress("eglCreateContext");
5188+ RGFW_eglMakeCurrent = (PFNEGLMAKECURRENTPROC) RGFW_eglGetProcAddress("eglMakeCurrent");
5189+ RGFW_eglGetDisplay = (PFNEGLGETDISPLAYPROC) RGFW_eglGetProcAddress("eglGetDisplay");
5190+ RGFW_eglSwapBuffers = (PFNEGLSWAPBUFFERSPROC) RGFW_eglGetProcAddress("eglSwapBuffers");
5191+ RGFW_eglSwapInterval = (PFNEGLSWAPINTERVALPROC) RGFW_eglGetProcAddress("eglSwapInterval");
5192+ RGFW_eglBindAPI = (PFNEGLBINDAPIPROC) RGFW_eglGetProcAddress("eglBindAPI");
5193+ RGFW_eglDestroyContext = (PFNEGLDESTROYCONTEXTPROC) RGFW_eglGetProcAddress("eglDestroyContext");
5194+ RGFW_eglTerminate = (PFNEGLTERMINATEPROC) RGFW_eglGetProcAddress("eglTerminate");
5195+ RGFW_eglDestroySurface = (PFNEGLDESTROYSURFACEPROC) RGFW_eglGetProcAddress("eglDestroySurface");
5196+ RGFW_eglQueryString = (PFNEGLQUERYSTRINGPROC) RGFW_eglGetProcAddress("eglQueryString");
5197+ RGFW_eglGetCurrentContext = (PFNEGLGETCURRENTCONTEXTPROC) RGFW_eglGetProcAddress("eglGetCurrentContext");
5198+ RGFW_eglGetConfigAttrib = (PFNEGLGETCONFIGATTRIBPROC) RGFW_eglGetProcAddress("eglGetConfigAttrib");
5199+
5200+#else
5201+ RGFW_eglGetProcAddress = eglGetProcAddress;
5202+ RGFW_eglInitialize = (PFNEGLINITIALIZEPROC) eglInitialize;
5203+ RGFW_eglGetConfigs = (PFNEGLGETCONFIGSPROC) eglGetConfigs;
5204+ RGFW_eglChooseConfig = (PFNEGLCHOOSECONFIGPROC) eglChooseConfig;
5205+ RGFW_eglCreateWindowSurface = (PFNEGLCREATEWINDOWSURFACEPROC) eglCreateWindowSurface;
5206+ RGFW_eglCreateContext = (PFNEGLCREATECONTEXTPROC) eglCreateContext;
5207+ RGFW_eglMakeCurrent = (PFNEGLMAKECURRENTPROC) eglMakeCurrent;
5208+ RGFW_eglGetDisplay = (PFNEGLGETDISPLAYPROC) eglGetDisplay;
5209+ RGFW_eglSwapBuffers = (PFNEGLSWAPBUFFERSPROC) eglSwapBuffers;
5210+ RGFW_eglSwapInterval = (PFNEGLSWAPINTERVALPROC) eglSwapInterval;
5211+ RGFW_eglBindAPI = (PFNEGLBINDAPIPROC) eglBindAPI;
5212+ RGFW_eglDestroyContext = (PFNEGLDESTROYCONTEXTPROC) eglDestroyContext;
5213+ RGFW_eglTerminate = (PFNEGLTERMINATEPROC) eglTerminate;
5214+ RGFW_eglDestroySurface = (PFNEGLDESTROYSURFACEPROC) eglDestroySurface;
5215+ RGFW_eglQueryString = (PFNEGLQUERYSTRINGPROC) eglQueryString;
5216+ RGFW_eglGetCurrentContext = (PFNEGLGETCURRENTCONTEXTPROC) eglGetCurrentContext;
5217+ RGFW_eglGetConfigAttrib = (PFNEGLGETCONFIGATTRIBPROC)eglGetConfigAttrib;
5218+#endif
5219+
5220+ RGFW_bool out = RGFW_BOOL(RGFW_eglInitialize!= NULL &&
5221+ RGFW_eglGetConfigs!= NULL &&
5222+ RGFW_eglChooseConfig!= NULL &&
5223+ RGFW_eglCreateWindowSurface!= NULL &&
5224+ RGFW_eglCreateContext!= NULL &&
5225+ RGFW_eglMakeCurrent!= NULL &&
5226+ RGFW_eglGetDisplay!= NULL &&
5227+ RGFW_eglSwapBuffers!= NULL &&
5228+ RGFW_eglSwapInterval != NULL &&
5229+ RGFW_eglBindAPI!= NULL &&
5230+ RGFW_eglDestroyContext!= NULL &&
5231+ RGFW_eglTerminate!= NULL &&
5232+ RGFW_eglDestroySurface!= NULL &&
5233+ RGFW_eglQueryString != NULL &&
5234+ RGFW_eglGetCurrentContext != NULL &&
5235+ RGFW_eglGetConfigAttrib != NULL);
5236+
5237+ if (out) {
5238+ #ifdef RGFW_WINDOWS
5239+ HDC dc = GetDC(NULL);
5240+ _RGFW->EGL_display = RGFW_eglGetDisplay((EGLNativeDisplayType) dc);
5241+ ReleaseDC(NULL, dc);
5242+ #elif defined(RGFW_WAYLAND)
5243+ if (_RGFW->useWaylandBool)
5244+ _RGFW->EGL_display = RGFW_eglGetDisplay((EGLNativeDisplayType) _RGFW->wl_display);
5245+ else
5246+ #endif
5247+ #ifdef RGFW_X11
5248+ _RGFW->EGL_display = RGFW_eglGetDisplay((EGLNativeDisplayType) _RGFW->display);
5249+ #else
5250+ {}
5251+ #endif
5252+ #if !defined(RGFW_WAYLAND) && !defined(RGFW_WINDOWS) && !defined(RGFW_X11)
5253+ _RGFW->EGL_display = RGFW_eglGetDisplay(EGL_DEFAULT_DISPLAY);
5254+ #endif
5255+ }
5256+
5257+ RGFW_eglInitialize(_RGFW->EGL_display, NULL, NULL);
5258+ return out;
5259+}
5260+
5261+
5262+void RGFW_unloadEGL(void) {
5263+ if (!RGFW_eglLibHandle) return;
5264+ RGFW_eglTerminate(_RGFW->EGL_display);
5265+ #ifdef RGFW_WINDOWS
5266+ FreeLibrary((HMODULE)RGFW_eglLibHandle);
5267+ #elif defined(RGFW_MACOS) || defined(RGFW_UNIX)
5268+ dlclose(RGFW_eglLibHandle);
5269+ #endif
5270+
5271+ RGFW_eglLibHandle = NULL;
5272+ RGFW_eglGetProcAddress = NULL;
5273+}
5274+
5275+RGFW_bool RGFW_window_createContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ctx, RGFW_glHints* hints) {
5276+ if (RGFW_loadEGL() == RGFW_FALSE) return RGFW_FALSE;
5277+ win->src.ctx.egl = ctx;
5278+ win->src.gfxType = RGFW_gfxEGL;
5279+
5280+#ifdef RGFW_WAYLAND
5281+ if (_RGFW->useWaylandBool)
5282+ win->src.ctx.egl->eglWindow = wl_egl_window_create(win->src.surface, win->w, win->h);
5283+#endif
5284+
5285+ #ifndef EGL_OPENGL_ES1_BIT
5286+ #define EGL_OPENGL_ES1_BIT 0x1
5287+ #endif
5288+
5289+ EGLint egl_config[24];
5290+
5291+ {
5292+ RGFW_attribStack stack;
5293+ RGFW_attribStack_init(&stack, egl_config, 24);
5294+
5295+ RGFW_attribStack_pushAttribs(&stack, EGL_SURFACE_TYPE, EGL_WINDOW_BIT);
5296+ RGFW_attribStack_pushAttrib(&stack, EGL_RENDERABLE_TYPE);
5297+
5298+ if (hints->profile == RGFW_glES) {
5299+ switch (hints->major) {
5300+ case 1: RGFW_attribStack_pushAttrib(&stack, EGL_OPENGL_ES1_BIT); break;
5301+ case 2: RGFW_attribStack_pushAttrib(&stack, EGL_OPENGL_ES2_BIT); break;
5302+ case 3: RGFW_attribStack_pushAttrib(&stack, EGL_OPENGL_ES3_BIT); break;
5303+ default: break;
5304+ }
5305+ } else {
5306+ RGFW_attribStack_pushAttrib(&stack, EGL_OPENGL_BIT);
5307+ }
5308+
5309+ RGFW_attribStack_pushAttribs(&stack, EGL_RED_SIZE, hints->red);
5310+ RGFW_attribStack_pushAttribs(&stack, EGL_GREEN_SIZE, hints->green);
5311+ RGFW_attribStack_pushAttribs(&stack, EGL_BLUE_SIZE, hints->blue);
5312+ RGFW_attribStack_pushAttribs(&stack, EGL_ALPHA_SIZE, hints->alpha);
5313+ RGFW_attribStack_pushAttribs(&stack, EGL_DEPTH_SIZE, hints->depth);
5314+
5315+ RGFW_attribStack_pushAttribs(&stack, EGL_STENCIL_SIZE, hints->stencil);
5316+ if (hints->samples) {
5317+ RGFW_attribStack_pushAttribs(&stack, EGL_SAMPLE_BUFFERS, 1);
5318+ RGFW_attribStack_pushAttribs(&stack, EGL_SAMPLES, hints->samples);
5319+ }
5320+
5321+ RGFW_attribStack_pushAttribs(&stack, EGL_NONE, EGL_NONE);
5322+ }
5323+
5324+ EGLint numConfigs, best_config = -1, best_samples = 0;
5325+
5326+ RGFW_eglChooseConfig(_RGFW->EGL_display, egl_config, NULL, 0, &numConfigs);
5327+ EGLConfig* configs = (EGLConfig*)RGFW_ALLOC(sizeof(EGLConfig) * (u32)numConfigs);
5328+
5329+ RGFW_eglChooseConfig(_RGFW->EGL_display, egl_config, configs, numConfigs, &numConfigs);
5330+
5331+#ifdef RGFW_X11
5332+ RGFW_bool transparent = (win->internal.flags & RGFW_windowTransparent);
5333+ EGLint best_depth = 0;
5334+#endif
5335+
5336+ for (EGLint i = 0; i < numConfigs; i++) {
5337+ EGLint visual_id = 0;
5338+ EGLint samples = 0;
5339+
5340+ RGFW_eglGetConfigAttrib(_RGFW->EGL_display, configs[i], EGL_NATIVE_VISUAL_ID, &visual_id);
5341+ RGFW_eglGetConfigAttrib(_RGFW->EGL_display, configs[i], EGL_SAMPLES, &samples);
5342+
5343+ if (best_config == -1) best_config = i;
5344+
5345+#ifdef RGFW_X11
5346+ if (_RGFW->useWaylandBool == RGFW_FALSE) {
5347+ XVisualInfo vinfo_template;
5348+ vinfo_template.visualid = (VisualID)visual_id;
5349+
5350+ int num_visuals = 0;
5351+ XVisualInfo* vi = XGetVisualInfo(_RGFW->display, VisualIDMask, &vinfo_template, &num_visuals);
5352+ if (!vi) continue;
5353+ if ((!transparent || vi->depth == 32) && best_depth == 0) {
5354+ best_config = i;
5355+ best_depth = vi->depth;
5356+ }
5357+
5358+ if ((!(transparent) || vi->depth == 32) && (samples <= hints->samples && samples > best_samples)) {
5359+ best_depth = vi->depth;
5360+ best_config = i;
5361+ best_samples = samples;
5362+ XFree(vi);
5363+ continue;
5364+ }
5365+ }
5366+#endif
5367+
5368+ if (samples <= hints->samples && samples > best_samples) {
5369+ best_config = i;
5370+ best_samples = samples;
5371+ }
5372+ }
5373+
5374+ EGLConfig config = configs[best_config];
5375+ RGFW_FREE(configs);
5376+#ifdef RGFW_X11
5377+ if (_RGFW->useWaylandBool == RGFW_FALSE) {
5378+ /* This is required so that way the user can create their own OpenGL context after RGFW_createWindow is used */
5379+ XVisualInfo* result;
5380+ XVisualInfo desired;
5381+ EGLint visualID = 0, count = 0;
5382+
5383+ RGFW_eglGetConfigAttrib(_RGFW->EGL_display, config, EGL_NATIVE_VISUAL_ID, &visualID);
5384+ if (visualID) {
5385+ desired.visualid = (VisualID)visualID;
5386+ result = XGetVisualInfo(_RGFW->display, VisualIDMask, &desired, &count);
5387+ } else RGFW_debugCallback(RGFW_typeError, RGFW_errEGLContext, "Failed to fetch a valid EGL VisualID");
5388+
5389+ if (result == NULL || count == 0) {
5390+ if (win->src.window == 0) {
5391+ /* try to create a EGL context anyway (this will work if you're not using a NVidia driver) */
5392+ win->internal.flags &= ~(u32)RGFW_windowEGL;
5393+ RGFW_createWindowPlatform("", win->internal.flags, win);
5394+ }
5395+ RGFW_debugCallback(RGFW_typeError, RGFW_errEGLContext, "Failed to find a valid visual for the EGL config");
5396+ } else {
5397+ RGFW_bool showWindow = RGFW_FALSE;
5398+ if (win->src.window) {
5399+ showWindow = (RGFW_window_isMinimized(win) == RGFW_FALSE);
5400+ RGFW_window_closePlatform(win);
5401+ }
5402+
5403+ RGFW_XCreateWindow(*result, "", win->internal.flags, win);
5404+
5405+ if (showWindow) {
5406+ RGFW_window_show(win);
5407+ }
5408+ XFree(result);
5409+ }
5410+ }
5411+#endif
5412+
5413+ EGLint surf_attribs[9];
5414+
5415+ {
5416+ RGFW_attribStack stack;
5417+ RGFW_attribStack_init(&stack, surf_attribs, 9);
5418+
5419+ const char present_opaque_str[] = "EGL_EXT_present_opaque";
5420+ RGFW_bool opaque_extension_Found = RGFW_extensionSupportedPlatform_EGL(present_opaque_str, sizeof(present_opaque_str));
5421+
5422+ #ifndef EGL_PRESENT_OPAQUE_EXT
5423+ #define EGL_PRESENT_OPAQUE_EXT 0x31df
5424+ #endif
5425+
5426+ #ifndef EGL_GL_COLORSPACE_KHR
5427+ #define EGL_GL_COLORSPACE_KHR 0x309D
5428+ #ifndef EGL_GL_COLORSPACE_SRGB_KHR
5429+ #define EGL_GL_COLORSPACE_SRGB_KHR 0x3089
5430+ #endif
5431+ #endif
5432+
5433+ const char gl_colorspace_str[] = "EGL_KHR_gl_colorspace";
5434+ RGFW_bool gl_colorspace_Found = RGFW_extensionSupportedPlatform_EGL(gl_colorspace_str, sizeof(gl_colorspace_str));
5435+
5436+ if (hints->sRGB && gl_colorspace_Found) {
5437+ RGFW_attribStack_pushAttribs(&stack, EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR);
5438+ }
5439+
5440+ if (!(win->internal.flags & RGFW_windowTransparent) && opaque_extension_Found)
5441+ RGFW_attribStack_pushAttribs(&stack, EGL_PRESENT_OPAQUE_EXT, EGL_TRUE);
5442+
5443+ if (hints->doubleBuffer == 0) {
5444+ RGFW_attribStack_pushAttribs(&stack, EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER);
5445+ }
5446+
5447+ RGFW_attribStack_pushAttribs(&stack, EGL_NONE, EGL_NONE);
5448+ }
5449+ #if defined(RGFW_MACOS)
5450+ void* layer = RGFW_getLayer_OSX();
5451+
5452+ RGFW_window_setLayer_OSX(win, layer);
5453+
5454+ win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, config, (EGLNativeWindowType) layer, surf_attribs);
5455+ #elif defined(RGFW_WINDOWS)
5456+ win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, config, (EGLNativeWindowType) win->src.window, surf_attribs);
5457+ #elif defined(RGFW_WAYLAND)
5458+ if (_RGFW->useWaylandBool)
5459+ win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, config, (EGLNativeWindowType) win->src.ctx.egl->eglWindow, surf_attribs);
5460+ else
5461+ #endif
5462+ #ifdef RGFW_X11
5463+ win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, config, (EGLNativeWindowType) win->src.window, surf_attribs);
5464+ #else
5465+ {}
5466+ #endif
5467+ #ifdef RGFW_WASM
5468+ win->src.ctx.egl->surface = eglCreateWindowSurface(_RGFW->EGL_display, config, 0, 0);
5469+ #endif
5470+
5471+ if (win->src.ctx.egl->surface == NULL) {
5472+ RGFW_debugCallback(RGFW_typeError, RGFW_errEGLContext, "Failed to create an EGL surface.");
5473+ return RGFW_FALSE;
5474+ }
5475+
5476+ EGLint attribs[20];
5477+ {
5478+ RGFW_attribStack stack;
5479+ RGFW_attribStack_init(&stack, attribs, 20);
5480+
5481+ if (hints->major || hints->minor) {
5482+ RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_MAJOR_VERSION, hints->major);
5483+ RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_MINOR_VERSION, hints->minor);
5484+ }
5485+
5486+ if (hints->profile == RGFW_glCore) {
5487+ RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT);
5488+ } else if (hints->profile == RGFW_glCompatibility) {
5489+ RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT);
5490+ } else if (hints->profile == RGFW_glForwardCompatibility) {
5491+ RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE, EGL_TRUE);
5492+ }
5493+
5494+
5495+ RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_ROBUST_ACCESS, hints->robustness);
5496+ RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_DEBUG, hints->debug);
5497+
5498+ #ifndef EGL_CONTEXT_RELEASE_BEHAVIOR_KHR
5499+ #define EGL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x2097
5500+ #endif
5501+
5502+ #ifndef EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR
5503+ #define EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x2098
5504+ #endif
5505+
5506+ if (hints->releaseBehavior == RGFW_glReleaseFlush) {
5507+ RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR);
5508+ } else {
5509+ RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, 0x0000);
5510+ }
5511+
5512+ RGFW_attribStack_pushAttribs(&stack, EGL_NONE, EGL_NONE);
5513+ }
5514+
5515+ if (hints->profile == RGFW_glES)
5516+ RGFW_eglBindAPI(EGL_OPENGL_ES_API);
5517+ else
5518+ RGFW_eglBindAPI(EGL_OPENGL_API);
5519+
5520+ win->src.ctx.egl->ctx = RGFW_eglCreateContext(_RGFW->EGL_display, config, hints->shareEGL, attribs);
5521+
5522+ if (win->src.ctx.egl->ctx == NULL) {
5523+ RGFW_debugCallback(RGFW_typeError, RGFW_errEGLContext, "Failed to create an EGL context.");
5524+ return RGFW_FALSE;
5525+ }
5526+
5527+ RGFW_eglMakeCurrent(_RGFW->EGL_display, win->src.ctx.egl->surface, win->src.ctx.egl->surface, win->src.ctx.egl->ctx);
5528+ RGFW_eglSwapBuffers(_RGFW->EGL_display, win->src.ctx.egl->surface);
5529+ RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "EGL context initalized.");
5530+ return RGFW_TRUE;
5531+}
5532+
5533+RGFW_eglContext* RGFW_window_getContext_EGL(RGFW_window* win) {
5534+ if (win->src.gfxType == RGFW_windowOpenGL) return NULL;
5535+ return win->src.ctx.egl;
5536+}
5537+
5538+void RGFW_window_deleteContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ctx) {
5539+ if (_RGFW->EGL_display == NULL) return;
5540+
5541+ RGFW_eglDestroySurface(_RGFW->EGL_display, ctx->surface);
5542+ RGFW_eglDestroyContext(_RGFW->EGL_display, ctx->ctx);
5543+ RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "EGL context freed");
5544+ #ifdef RGFW_WAYLAND
5545+ if (_RGFW->useWaylandBool == RGFW_FALSE) return;
5546+ wl_egl_window_destroy(win->src.ctx.egl->eglWindow);
5547+ RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "EGL window context freed");
5548+ #endif
5549+ win->src.ctx.egl = NULL;
5550+}
5551+
5552+void RGFW_window_makeCurrentContext_EGL(RGFW_window* win) { if (win) RGFW_ASSERT(win->src.ctx.egl);
5553+ if (win == NULL)
5554+ RGFW_eglMakeCurrent(_RGFW->EGL_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
5555+ else {
5556+ RGFW_eglMakeCurrent(_RGFW->EGL_display, win->src.ctx.egl->surface, win->src.ctx.egl->surface, win->src.ctx.egl->ctx);
5557+ }
5558+}
5559+
5560+void RGFW_window_swapBuffers_EGL(RGFW_window* win) {
5561+ if (RGFW_eglSwapBuffers)
5562+ RGFW_eglSwapBuffers(_RGFW->EGL_display, win->src.ctx.egl->surface);
5563+ else RGFW_window_swapBuffers_OpenGL(win);
5564+}
5565+
5566+void* RGFW_getCurrentContext_EGL(void) {
5567+ return RGFW_eglGetCurrentContext();
5568+}
5569+
5570+RGFW_proc RGFW_getProcAddress_EGL(const char* procname) {
5571+ #if defined(RGFW_WINDOWS)
5572+ RGFW_proc proc = (RGFW_proc) GetProcAddress(RGFW_wgl_dll, procname);
5573+
5574+ if (proc)
5575+ return proc;
5576+ #endif
5577+
5578+ return (RGFW_proc) RGFW_eglGetProcAddress(procname);
5579+}
5580+
5581+RGFW_bool RGFW_extensionSupportedPlatform_EGL(const char* extension, size_t len) {
5582+ if (RGFW_loadEGL() == RGFW_FALSE) return RGFW_FALSE;
5583+ const char* extensions = RGFW_eglQueryString(_RGFW->EGL_display, EGL_EXTENSIONS);
5584+ return extensions != NULL && RGFW_extensionSupportedStr(extensions, extension, len);
5585+}
5586+
5587+void RGFW_window_swapInterval_EGL(RGFW_window* win, i32 swapInterval) {
5588+ RGFW_ASSERT(win != NULL);
5589+ RGFW_eglSwapInterval(_RGFW->EGL_display, swapInterval);
5590+}
5591+
5592+RGFW_bool RGFW_extensionSupported_EGL(const char* extension, size_t len) {
5593+ if (RGFW_extensionSupported_base(extension, len)) return RGFW_TRUE;
5594+ return RGFW_extensionSupportedPlatform_EGL(extension, len);
5595+}
5596+
5597+void RGFW_window_makeCurrentWindow_EGL(RGFW_window* win) {
5598+ _RGFW->current = win;
5599+ RGFW_window_makeCurrentContext_EGL(win);
5600+}
5601+
5602+RGFW_window* RGFW_getCurrentWindow_EGL(void) { return _RGFW->current; }
5603+
5604+RGFW_eglContext* RGFW_window_createContext_EGL(RGFW_window* win, RGFW_glHints* hints) {
5605+ RGFW_eglContext* ctx = (RGFW_eglContext*)RGFW_ALLOC(sizeof(RGFW_eglContext));
5606+ if (RGFW_window_createContextPtr_EGL(win, ctx, hints) == RGFW_FALSE) {
5607+ RGFW_FREE(ctx);
5608+ win->src.ctx.egl = NULL;
5609+ return NULL;
5610+ }
5611+ win->src.gfxType |= RGFW_gfxOwnedByRGFW;
5612+ return ctx;
5613+}
5614+
5615+void RGFW_window_deleteContext_EGL(RGFW_window* win, RGFW_eglContext* ctx) {
5616+ RGFW_window_deleteContextPtr_EGL(win, ctx);
5617+ if (win->src.gfxType & RGFW_gfxOwnedByRGFW) RGFW_FREE(ctx);
5618+}
5619+
5620+#endif /* RGFW_EGL */
5621+
5622+/*
5623+ end of RGFW_EGL defines
5624+*/
5625+#endif /* end of RGFW_GL (OpenGL, EGL, OSMesa )*/
5626+
5627+/*
5628+ RGFW_VULKAN defines
5629+*/
5630+#ifdef RGFW_VULKAN
5631+#ifdef RGFW_MACOS
5632+#include <objc/message.h>
5633+#endif
5634+
5635+const char** RGFW_getRequiredInstanceExtensions_Vulkan(size_t* count) {
5636+ static const char* arr[2] = {VK_KHR_SURFACE_EXTENSION_NAME};
5637+ arr[1] = RGFW_VK_SURFACE;
5638+ if (count != NULL) *count = 2;
5639+
5640+ return (const char**)arr;
5641+}
5642+
5643+#ifndef RGFW_MACOS
5644+VkResult RGFW_window_createSurface_Vulkan(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface) {
5645+ RGFW_ASSERT(win != NULL); RGFW_ASSERT(instance);
5646+ RGFW_ASSERT(surface != NULL);
5647+
5648+ *surface = VK_NULL_HANDLE;
5649+
5650+#ifdef RGFW_X11
5651+
5652+ VkXlibSurfaceCreateInfoKHR x11 = { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, 0, 0, (Display*) _RGFW->display, (Window) win->src.window };
5653+ return vkCreateXlibSurfaceKHR(instance, &x11, NULL, surface);
5654+#endif
5655+#if defined(RGFW_WAYLAND)
5656+
5657+ VkWaylandSurfaceCreateInfoKHR wayland = { VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, 0, 0, (struct wl_display*) _RGFW->wl_display, (struct wl_surface*) win->src.surface };
5658+ return vkCreateWaylandSurfaceKHR(instance, &wayland, NULL, surface);
5659+#elif defined(RGFW_WINDOWS)
5660+ VkWin32SurfaceCreateInfoKHR win32 = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, 0, 0, GetModuleHandle(NULL), (HWND)win->src.window };
5661+
5662+ return vkCreateWin32SurfaceKHR(instance, &win32, NULL, surface);
5663+#endif
5664+}
5665+#endif
5666+
5667+RGFW_bool RGFW_getPresentationSupport_Vulkan(VkPhysicalDevice physicalDevice, u32 queueFamilyIndex) {
5668+ if (_RGFW == NULL) RGFW_init();
5669+#ifdef RGFW_X11
5670+
5671+ Visual* visual = DefaultVisual(_RGFW->display, DefaultScreen(_RGFW->display));
5672+ RGFW_bool out = vkGetPhysicalDeviceXlibPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW->display, XVisualIDFromVisual(visual));
5673+ return out;
5674+#endif
5675+#if defined(RGFW_WAYLAND)
5676+
5677+ RGFW_bool wlout = vkGetPhysicalDeviceWaylandPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW->wl_display);
5678+ return wlout;
5679+#elif defined(RGFW_WINDOWS)
5680+ RGFW_bool out = vkGetPhysicalDeviceWin32PresentationSupportKHR(physicalDevice, queueFamilyIndex);
5681+ return out;
5682+#elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11)
5683+ RGFW_UNUSED(physicalDevice);
5684+ RGFW_UNUSED(queueFamilyIndex);
5685+ return RGFW_FALSE; /* TODO */
5686+#endif
5687+}
5688+#endif /* end of RGFW_vulkan */
5689+
5690+/*
5691+This is where OS specific stuff starts
5692+*/
5693+
5694+/* start of unix (wayland or X11 (unix) ) defines */
5695+
5696+#ifdef RGFW_UNIX
5697+#include <fcntl.h>
5698+#include <poll.h>
5699+#include <unistd.h>
5700+
5701+void RGFW_stopCheckEvents(void) {
5702+
5703+ _RGFW->eventWait_forceStop[2] = 1;
5704+ while (1) {
5705+ const char byte = 0;
5706+ const ssize_t result = write(_RGFW->eventWait_forceStop[1], &byte, 1);
5707+ if (result == 1 || result == -1)
5708+ break;
5709+ }
5710+}
5711+
5712+RGFWDEF u64 RGFW_linux_getTimeNS(void);
5713+u64 RGFW_linux_getTimeNS(void) {
5714+ struct timespec ts;
5715+ const u64 scale_factor = 1000000000;
5716+ clock_gettime(_RGFW->clock, &ts);
5717+ return (u64)ts.tv_sec * scale_factor + (u64)ts.tv_nsec;
5718+}
5719+
5720+void RGFW_waitForEvent(i32 waitMS) {
5721+ if (waitMS == 0) return;
5722+
5723+ if (_RGFW->eventWait_forceStop[0] == 0 || _RGFW->eventWait_forceStop[1] == 0) {
5724+ if (pipe(_RGFW->eventWait_forceStop) != -1) {
5725+ fcntl(_RGFW->eventWait_forceStop[0], F_GETFL, 0);
5726+ fcntl(_RGFW->eventWait_forceStop[0], F_GETFD, 0);
5727+ fcntl(_RGFW->eventWait_forceStop[1], F_GETFL, 0);
5728+ fcntl(_RGFW->eventWait_forceStop[1], F_GETFD, 0);
5729+ }
5730+ }
5731+
5732+ struct pollfd fds[2];
5733+ fds[0].fd = 0;
5734+ fds[0].events = POLLIN;
5735+ fds[0].revents = 0;
5736+ fds[1].fd = _RGFW->eventWait_forceStop[0];
5737+ fds[1].events = POLLIN;
5738+ fds[1].revents = 0;
5739+
5740+
5741+ if (RGFW_usingWayland()) {
5742+ #ifdef RGFW_WAYLAND
5743+ fds[0].fd = wl_display_get_fd(_RGFW->wl_display);
5744+
5745+ /* empty the queue */
5746+ while (wl_display_prepare_read(_RGFW->wl_display) != 0) {
5747+ /* error occured when dispatching the queue */
5748+ if (wl_display_dispatch_pending(_RGFW->wl_display) == -1) {
5749+ return;
5750+ }
5751+ }
5752+
5753+ /* send any pending requests to the compositor */
5754+ while (wl_display_flush(_RGFW->wl_display) == -1) {
5755+
5756+ /* queue is full dispatch them */
5757+ if (errno == EAGAIN) {
5758+ if (wl_display_dispatch_pending(_RGFW->wl_display) == -1) {
5759+ return;
5760+ }
5761+ } else {
5762+ return;
5763+ }
5764+ }
5765+ #endif
5766+ } else {
5767+ #ifdef RGFW_X11
5768+ fds[0].fd = ConnectionNumber(_RGFW->display);
5769+ #endif
5770+ }
5771+
5772+
5773+ u64 start = RGFW_linux_getTimeNS();
5774+ if (RGFW_usingWayland()) {
5775+ #ifdef RGFW_WAYLAND
5776+ while (wl_display_dispatch_pending(_RGFW->wl_display) == 0) {
5777+ if (poll(fds, 1, waitMS) <= 0) {
5778+ wl_display_cancel_read(_RGFW->wl_display);
5779+ break;
5780+ } else {
5781+ if (wl_display_read_events(_RGFW->wl_display) == -1)
5782+ return;
5783+ }
5784+
5785+ if (waitMS != RGFW_eventWaitNext) {
5786+ waitMS -= (i32)(RGFW_linux_getTimeNS() - start) / (i32)1e+6;
5787+ }
5788+ }
5789+
5790+ /* queue contains events from read, dispatch them */
5791+ if (wl_display_dispatch_pending(_RGFW->wl_display) == -1) {
5792+ return;
5793+ }
5794+ #endif
5795+ } else {
5796+ #ifdef RGFW_X11
5797+ while (XPending(_RGFW->display) == 0) {
5798+ if (poll(fds, 1, waitMS) <= 0)
5799+ break;
5800+
5801+ if (waitMS != RGFW_eventWaitNext) {
5802+ waitMS -= (i32)(RGFW_linux_getTimeNS() - start) / (i32)1e+6;
5803+ }
5804+ }
5805+ #endif
5806+ }
5807+
5808+ /* drain any data in the stop request */
5809+ if (_RGFW->eventWait_forceStop[2]) {
5810+ char data[64];
5811+ RGFW_MEMZERO(data, sizeof(data));
5812+ (void)!read(_RGFW->eventWait_forceStop[0], data, sizeof(data));
5813+
5814+ _RGFW->eventWait_forceStop[2] = 0;
5815+ }
5816+}
5817+
5818+char* RGFW_strtok(char* str, const char* delimStr);
5819+char* RGFW_strtok(char* str, const char* delimStr) {
5820+ static char* static_str = NULL;
5821+
5822+ if (str != NULL)
5823+ static_str = str;
5824+
5825+ if (static_str == NULL) {
5826+ return NULL;
5827+ }
5828+
5829+ while (*static_str != '\0') {
5830+ RGFW_bool delim = 0;
5831+ const char* d;
5832+ for (d = delimStr; *d != '\0'; d++) {
5833+ if (*static_str == *d) {
5834+ delim = 1;
5835+ break;
5836+ }
5837+ }
5838+ if (!delim)
5839+ break;
5840+ static_str++;
5841+ }
5842+
5843+ if (*static_str == '\0')
5844+ return NULL;
5845+
5846+ char* token_start = static_str;
5847+ while (*static_str != '\0') {
5848+ int delim = 0;
5849+ const char* d;
5850+ for (d = delimStr; *d != '\0'; d++) {
5851+ if (*static_str == *d) {
5852+ delim = 1;
5853+ break;
5854+ }
5855+ }
5856+
5857+ if (delim) {
5858+ *static_str = '\0';
5859+ static_str++;
5860+ break;
5861+ }
5862+ static_str++;
5863+ }
5864+
5865+ return token_start;
5866+}
5867+
5868+#ifdef RGFW_X11
5869+RGFWDEF i32 RGFW_initPlatform_X11(void);
5870+RGFWDEF void RGFW_deinitPlatform_X11(void);
5871+#endif
5872+#ifdef RGFW_WAYLAND
5873+RGFWDEF i32 RGFW_initPlatform_Wayland(void);
5874+RGFWDEF void RGFW_deinitPlatform_Wayland(void);
5875+#endif
5876+
5877+RGFWDEF void RGFW_load_X11(void);
5878+RGFWDEF void RGFW_load_Wayland(void);
5879+
5880+#if !defined(RGFW_X11) || !defined(RGFW_WAYLAND)
5881+void RGFW_load_X11(void) { }
5882+void RGFW_load_Wayland(void) { }
5883+#endif
5884+
5885+/*
5886+ * Sadly we have to use magic linux keycodes
5887+ * We can't use X11 functions, because that breaks Wayland, but they use the same keycodes so there's no use redeffing them
5888+ * We can't use linux enums, because the headers don't exist on BSD
5889+ */
5890+void RGFW_initKeycodesPlatform(void) {
5891+ _RGFW->keycodes[49] = RGFW_keyBacktick;
5892+ _RGFW->keycodes[19] = RGFW_key0;
5893+ _RGFW->keycodes[10] = RGFW_key1;
5894+ _RGFW->keycodes[11] = RGFW_key2;
5895+ _RGFW->keycodes[12] = RGFW_key3;
5896+ _RGFW->keycodes[13] = RGFW_key4;
5897+ _RGFW->keycodes[14] = RGFW_key5;
5898+ _RGFW->keycodes[15] = RGFW_key6;
5899+ _RGFW->keycodes[16] = RGFW_key7;
5900+ _RGFW->keycodes[17] = RGFW_key8;
5901+ _RGFW->keycodes[18] = RGFW_key9;
5902+ _RGFW->keycodes[65] = RGFW_keySpace;
5903+ _RGFW->keycodes[38] = RGFW_keyA;
5904+ _RGFW->keycodes[56] = RGFW_keyB;
5905+ _RGFW->keycodes[54] = RGFW_keyC;
5906+ _RGFW->keycodes[40] = RGFW_keyD;
5907+ _RGFW->keycodes[26] = RGFW_keyE;
5908+ _RGFW->keycodes[41] = RGFW_keyF;
5909+ _RGFW->keycodes[42] = RGFW_keyG;
5910+ _RGFW->keycodes[43] = RGFW_keyH;
5911+ _RGFW->keycodes[31] = RGFW_keyI;
5912+ _RGFW->keycodes[44] = RGFW_keyJ;
5913+ _RGFW->keycodes[45] = RGFW_keyK;
5914+ _RGFW->keycodes[46] = RGFW_keyL;
5915+ _RGFW->keycodes[58] = RGFW_keyM;
5916+ _RGFW->keycodes[57] = RGFW_keyN;
5917+ _RGFW->keycodes[32] = RGFW_keyO;
5918+ _RGFW->keycodes[33] = RGFW_keyP;
5919+ _RGFW->keycodes[24] = RGFW_keyQ;
5920+ _RGFW->keycodes[27] = RGFW_keyR;
5921+ _RGFW->keycodes[39] = RGFW_keyS;
5922+ _RGFW->keycodes[28] = RGFW_keyT;
5923+ _RGFW->keycodes[30] = RGFW_keyU;
5924+ _RGFW->keycodes[55] = RGFW_keyV;
5925+ _RGFW->keycodes[25] = RGFW_keyW;
5926+ _RGFW->keycodes[53] = RGFW_keyX;
5927+ _RGFW->keycodes[29] = RGFW_keyY;
5928+ _RGFW->keycodes[52] = RGFW_keyZ;
5929+ _RGFW->keycodes[60] = RGFW_keyPeriod;
5930+ _RGFW->keycodes[59] = RGFW_keyComma;
5931+ _RGFW->keycodes[61] = RGFW_keySlash;
5932+ _RGFW->keycodes[34] = RGFW_keyBracket;
5933+ _RGFW->keycodes[35] = RGFW_keyCloseBracket;
5934+ _RGFW->keycodes[47] = RGFW_keySemicolon;
5935+ _RGFW->keycodes[48] = RGFW_keyApostrophe;
5936+ _RGFW->keycodes[51] = RGFW_keyBackSlash;
5937+ _RGFW->keycodes[36] = RGFW_keyReturn;
5938+ _RGFW->keycodes[119] = RGFW_keyDelete;
5939+ _RGFW->keycodes[77] = RGFW_keyNumLock;
5940+ _RGFW->keycodes[106] = RGFW_keyPadSlash;
5941+ _RGFW->keycodes[63] = RGFW_keyPadMultiply;
5942+ _RGFW->keycodes[86] = RGFW_keyPadPlus;
5943+ _RGFW->keycodes[82] = RGFW_keyPadMinus;
5944+ _RGFW->keycodes[87] = RGFW_keyPad1;
5945+ _RGFW->keycodes[88] = RGFW_keyPad2;
5946+ _RGFW->keycodes[89] = RGFW_keyPad3;
5947+ _RGFW->keycodes[83] = RGFW_keyPad4;
5948+ _RGFW->keycodes[84] = RGFW_keyPad5;
5949+ _RGFW->keycodes[85] = RGFW_keyPad6;
5950+ _RGFW->keycodes[81] = RGFW_keyPad9;
5951+ _RGFW->keycodes[90] = RGFW_keyPad0;
5952+ _RGFW->keycodes[91] = RGFW_keyPadPeriod;
5953+ _RGFW->keycodes[104] = RGFW_keyPadReturn;
5954+ _RGFW->keycodes[20] = RGFW_keyMinus;
5955+ _RGFW->keycodes[21] = RGFW_keyEquals;
5956+ _RGFW->keycodes[22] = RGFW_keyBackSpace;
5957+ _RGFW->keycodes[23] = RGFW_keyTab;
5958+ _RGFW->keycodes[66] = RGFW_keyCapsLock;
5959+ _RGFW->keycodes[50] = RGFW_keyShiftL;
5960+ _RGFW->keycodes[37] = RGFW_keyControlL;
5961+ _RGFW->keycodes[64] = RGFW_keyAltL;
5962+ _RGFW->keycodes[133] = RGFW_keySuperL;
5963+ _RGFW->keycodes[105] = RGFW_keyControlR;
5964+ _RGFW->keycodes[134] = RGFW_keySuperR;
5965+ _RGFW->keycodes[62] = RGFW_keyShiftR;
5966+ _RGFW->keycodes[108] = RGFW_keyAltR;
5967+ _RGFW->keycodes[67] = RGFW_keyF1;
5968+ _RGFW->keycodes[68] = RGFW_keyF2;
5969+ _RGFW->keycodes[69] = RGFW_keyF3;
5970+ _RGFW->keycodes[70] = RGFW_keyF4;
5971+ _RGFW->keycodes[71] = RGFW_keyF5;
5972+ _RGFW->keycodes[72] = RGFW_keyF6;
5973+ _RGFW->keycodes[73] = RGFW_keyF7;
5974+ _RGFW->keycodes[74] = RGFW_keyF8;
5975+ _RGFW->keycodes[75] = RGFW_keyF9;
5976+ _RGFW->keycodes[76] = RGFW_keyF10;
5977+ _RGFW->keycodes[95] = RGFW_keyF11;
5978+ _RGFW->keycodes[96] = RGFW_keyF12;
5979+ _RGFW->keycodes[111] = RGFW_keyUp;
5980+ _RGFW->keycodes[116] = RGFW_keyDown;
5981+ _RGFW->keycodes[113] = RGFW_keyLeft;
5982+ _RGFW->keycodes[114] = RGFW_keyRight;
5983+ _RGFW->keycodes[118] = RGFW_keyInsert;
5984+ _RGFW->keycodes[115] = RGFW_keyEnd;
5985+ _RGFW->keycodes[112] = RGFW_keyPageUp;
5986+ _RGFW->keycodes[117] = RGFW_keyPageDown;
5987+ _RGFW->keycodes[9] = RGFW_keyEscape;
5988+ _RGFW->keycodes[110] = RGFW_keyHome;
5989+ _RGFW->keycodes[78] = RGFW_keyScrollLock;
5990+ _RGFW->keycodes[107] = RGFW_keyPrintScreen;
5991+ _RGFW->keycodes[128] = RGFW_keyPause;
5992+ _RGFW->keycodes[191] = RGFW_keyF13;
5993+ _RGFW->keycodes[192] = RGFW_keyF14;
5994+ _RGFW->keycodes[193] = RGFW_keyF15;
5995+ _RGFW->keycodes[194] = RGFW_keyF16;
5996+ _RGFW->keycodes[195] = RGFW_keyF17;
5997+ _RGFW->keycodes[196] = RGFW_keyF18;
5998+ _RGFW->keycodes[197] = RGFW_keyF19;
5999+ _RGFW->keycodes[198] = RGFW_keyF20;
6000+ _RGFW->keycodes[199] = RGFW_keyF21;
6001+ _RGFW->keycodes[200] = RGFW_keyF22;
6002+ _RGFW->keycodes[201] = RGFW_keyF23;
6003+ _RGFW->keycodes[202] = RGFW_keyF24;
6004+ _RGFW->keycodes[203] = RGFW_keyF25;
6005+ _RGFW->keycodes[142] = RGFW_keyPadEqual;
6006+ _RGFW->keycodes[161] = RGFW_keyWorld1; /* non-US key #1 */
6007+ _RGFW->keycodes[162] = RGFW_keyWorld2; /* non-US key #2 */
6008+}
6009+
6010+i32 RGFW_initPlatform(void) {
6011+ #if defined(_POSIX_MONOTONIC_CLOCK)
6012+ struct timespec ts;
6013+ RGFW_MEMZERO(&ts, sizeof(struct timespec));
6014+
6015+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
6016+ _RGFW->clock = CLOCK_MONOTONIC;
6017+ #else
6018+ _RGFW->clock = CLOCK_REALTIME;
6019+ #endif
6020+
6021+#ifdef RGFW_WAYLAND
6022+ RGFW_load_Wayland();
6023+ i32 ret = RGFW_initPlatform_Wayland();
6024+ if (ret == 0) {
6025+ return 0;
6026+ } else {
6027+ #ifdef RGFW_X11
6028+ RGFW_debugCallback(RGFW_typeWarning, RGFW_warningWayland, "Falling back to X11");
6029+ RGFW_useWayland(0);
6030+ #else
6031+ return ret;
6032+ #endif
6033+ }
6034+#endif
6035+#ifdef RGFW_X11
6036+ RGFW_load_X11();
6037+ return RGFW_initPlatform_X11();
6038+#else
6039+ return 0;
6040+#endif
6041+}
6042+
6043+
6044+void RGFW_deinitPlatform(void) {
6045+ if (_RGFW->eventWait_forceStop[0] || _RGFW->eventWait_forceStop[1]){
6046+ close(_RGFW->eventWait_forceStop[0]);
6047+ close(_RGFW->eventWait_forceStop[1]);
6048+ }
6049+#ifdef RGFW_WAYLAND
6050+ if (_RGFW->useWaylandBool) {
6051+ RGFW_deinitPlatform_Wayland();
6052+ return;
6053+ }
6054+#endif
6055+#ifdef RGFW_X11
6056+ RGFW_deinitPlatform_X11();
6057+#endif
6058+}
6059+
6060+RGFWDEF size_t RGFW_unix_stringlen(const char* name);
6061+size_t RGFW_unix_stringlen(const char* name) {
6062+ size_t i = 0;
6063+ while (name[i]) { i++; }
6064+ return i;
6065+}
6066+
6067+RGFWDEF void RGFW_unix_parseURI(RGFW_window* win, char* data);
6068+void RGFW_unix_parseURI(RGFW_window* win, char* data) {
6069+ const char* prefix = (const char*)"file://";
6070+ char* line;
6071+ while ((line = (char*)RGFW_strtok(data, "\r\n"))) {
6072+ data = NULL;
6073+
6074+ if (line[0] == '#')
6075+ continue;
6076+
6077+ char* l;
6078+ for (l = line; 1; l++) {
6079+ if ((l - line) > 7)
6080+ break;
6081+ else if (*l != prefix[(l - line)])
6082+ break;
6083+ else if (*l == '\0' && prefix[(l - line)] == '\0') {
6084+ line += 7;
6085+ while (*line != '/')
6086+ line++;
6087+ break;
6088+ } else if (*l == '\0')
6089+ break;
6090+ }
6091+
6092+ size_t len = RGFW_unix_stringlen(line);
6093+ char* path = (char*)RGFW_ALLOC(len + 1);
6094+
6095+ size_t index = 0;
6096+ while (*line) {
6097+ if (line[0] == '%' && line[1] && line[2]) {
6098+ char digits[3] = {0};
6099+ digits[0] = line[1];
6100+ digits[1] = line[2];
6101+ digits[2] = '\0';
6102+ path[index] = (char) RGFW_STRTOL(digits, NULL, 16);
6103+ line += 2;
6104+ } else {
6105+ if (index >= len) {
6106+ break;
6107+ }
6108+
6109+ path[index] = *line;
6110+ }
6111+
6112+ index++;
6113+ line++;
6114+ }
6115+
6116+ path[len] = '\0';
6117+ RGFW_dataDropCallback(win, (const char*)path, len + 1, RGFW_dataFile);
6118+ RGFW_FREE(path);
6119+ }
6120+}
6121+
6122+
6123+#endif /* end of wayland or X11 defines */
6124+
6125+
6126+/*
6127+
6128+
6129+Start of Linux / Unix defines
6130+
6131+
6132+*/
6133+
6134+#ifdef RGFW_X11
6135+#ifdef RGFW_WAYLAND
6136+#define RGFW_FUNC(func) func##_X11
6137+#else
6138+#define RGFW_FUNC(func) func
6139+#endif
6140+
6141+#include <dlfcn.h>
6142+#include <unistd.h>
6143+
6144+#include <limits.h> /* for data limits (mainly used in drag and drop functions) */
6145+#include <poll.h>
6146+
6147+void RGFW_setXInstName(const char* name) { _RGFW->instName = name; }
6148+#if !defined(RGFW_NO_X11_CURSOR) && defined(RGFW_X11)
6149+ #include <X11/Xcursor/Xcursor.h>
6150+#endif
6151+
6152+#include <X11/Xatom.h>
6153+#include <X11/keysymdef.h>
6154+#include <X11/extensions/sync.h>
6155+
6156+#include <X11/XKBlib.h> /* for converting keycode to string */
6157+#include <X11/cursorfont.h> /* for hiding */
6158+#include <X11/extensions/shapeconst.h>
6159+#include <X11/extensions/shape.h>
6160+#include <X11/extensions/XInput2.h>
6161+
6162+#ifdef RGFW_OPENGL
6163+ #ifndef __gl_h_
6164+ #define __gl_h_
6165+ #define RGFW_gl_ndef
6166+ #define GLubyte unsigned char
6167+ #define GLenum unsigned int
6168+ #define GLint int
6169+ #define GLuint unsigned int
6170+ #define GLsizei int
6171+ #define GLfloat float
6172+ #define GLvoid void
6173+ #define GLbitfield unsigned int
6174+ #define GLintptr ptrdiff_t
6175+ #define GLsizeiptr ptrdiff_t
6176+ #define GLboolean unsigned char
6177+ #endif
6178+
6179+ #include <GL/glx.h> /* GLX defs, xlib.h, gl.h */
6180+ #ifndef GLX_MESA_swap_control
6181+ #define GLX_MESA_swap_control
6182+ #endif
6183+
6184+ #ifdef RGFW_gl_ndef
6185+ #undef __gl_h_
6186+ #undef GLubyte
6187+ #undef GLenum
6188+ #undef GLint
6189+ #undef GLuint
6190+ #undef GLsizei
6191+ #undef GLfloat
6192+ #undef GLvoid
6193+ #undef GLbitfield
6194+ #undef GLintptr
6195+ #undef GLsizeiptr
6196+ #undef GLboolean
6197+ #endif
6198+ typedef GLXContext(*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
6199+#endif
6200+
6201+/* atoms needed for drag and drop */
6202+#if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD)
6203+ typedef XcursorImage* (*PFN_XcursorImageCreate)(int, int);
6204+ typedef void (*PFN_XcursorImageDestroy)(XcursorImage*);
6205+ typedef Cursor(*PFN_XcursorImageLoadCursor)(Display*, const XcursorImage*);
6206+#endif
6207+
6208+#if !defined(RGFW_NO_X11_XI_PRELOAD)
6209+ typedef int (* PFN_XISelectEvents)(Display*,Window,XIEventMask*,int);
6210+ PFN_XISelectEvents XISelectEventsSRC = NULL;
6211+ #define XISelectEvents XISelectEventsSRC
6212+
6213+ void* X11Xihandle = NULL;
6214+#endif
6215+
6216+#if !defined(RGFW_NO_X11_EXT_PRELOAD)
6217+ typedef void (* PFN_XSyncIntToValue)(XSyncValue*, int);
6218+ PFN_XSyncIntToValue XSyncIntToValueSRC = NULL;
6219+ #define XSyncIntToValue XSyncIntToValueSRC
6220+
6221+ typedef Status (* PFN_XSyncSetCounter)(Display*, XSyncCounter, XSyncValue);
6222+ PFN_XSyncSetCounter XSyncSetCounterSRC = NULL;
6223+ #define XSyncSetCounter XSyncSetCounterSRC
6224+
6225+ typedef XSyncCounter (* PFN_XSyncCreateCounter)(Display*, XSyncValue);
6226+ PFN_XSyncCreateCounter XSyncCreateCounterSRC = NULL;
6227+ #define XSyncCreateCounter XSyncCreateCounterSRC
6228+
6229+ typedef void (* PFN_XShapeCombineMask)(Display*,Window,int,int,int,Pixmap,int);
6230+ PFN_XShapeCombineMask XShapeCombineMaskSRC;
6231+ #define XShapeCombineMask XShapeCombineMaskSRC
6232+
6233+ typedef void (* PFN_XShapeCombineRegion)(Display*,Window,int,int,int,Region,int);
6234+ PFN_XShapeCombineRegion XShapeCombineRegionSRC;
6235+ #define XShapeCombineRegion XShapeCombineRegionSRC
6236+ void* X11XEXThandle = NULL;
6237+#endif
6238+
6239+#if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD)
6240+ PFN_XcursorImageLoadCursor XcursorImageLoadCursorSRC = NULL;
6241+ PFN_XcursorImageCreate XcursorImageCreateSRC = NULL;
6242+ PFN_XcursorImageDestroy XcursorImageDestroySRC = NULL;
6243+
6244+ #define XcursorImageLoadCursor XcursorImageLoadCursorSRC
6245+ #define XcursorImageCreate XcursorImageCreateSRC
6246+ #define XcursorImageDestroy XcursorImageDestroySRC
6247+
6248+ void* X11Cursorhandle = NULL;
6249+#endif
6250+
6251+RGFWDEF RGFW_bool RGFW_waitForShowEvent_X11(RGFW_window* win);
6252+RGFW_bool RGFW_waitForShowEvent_X11(RGFW_window* win) {
6253+ XEvent dummy;
6254+ while (!XCheckTypedWindowEvent(_RGFW->display, win->src.window, VisibilityNotify, &dummy)) {
6255+ RGFW_waitForEvent(100);
6256+ }
6257+
6258+ return RGFW_TRUE;
6259+}
6260+
6261+RGFWDEF void RGFW_x11_icCallback(XIC ic, char* clientData, char* callData);
6262+void RGFW_x11_icCallback(XIC ic, char* clientData, char* callData) {
6263+ RGFW_UNUSED(ic); RGFW_UNUSED(callData);
6264+ RGFW_window* win = (RGFW_window*)(void*)clientData;
6265+ win->src.ic = NULL;
6266+}
6267+
6268+RGFWDEF void RGFW_x11_imCallback(XIM im, char* clientData, char* callData);
6269+void RGFW_x11_imCallback(XIM im, char* clientData, char* callData) {
6270+ RGFW_UNUSED(im); RGFW_UNUSED(clientData); RGFW_UNUSED(callData);
6271+ _RGFW->im = NULL;
6272+}
6273+
6274+RGFWDEF void RGFW_x11_imInitCallback(Display* display, XPointer clientData, XPointer callData);
6275+void RGFW_x11_imInitCallback(Display* display, XPointer clientData, XPointer callData) {
6276+ RGFW_UNUSED(display); RGFW_UNUSED(clientData); RGFW_UNUSED(callData);
6277+
6278+ if (_RGFW->im) {
6279+ return;
6280+ }
6281+
6282+ _RGFW->im = XOpenIM(_RGFW->display, 0, NULL, NULL);
6283+ if (_RGFW->im == NULL) {
6284+ return;
6285+ }
6286+
6287+ RGFW_bool found = RGFW_FALSE;
6288+ XIMStyles* styles = NULL;
6289+
6290+ if (XGetIMValues(_RGFW->im, XNQueryInputStyle, &styles, NULL) != NULL) {
6291+ found = RGFW_FALSE;
6292+ } else {
6293+ for (unsigned int i = 0; i < styles->count_styles; i++) {
6294+ if (styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing)) {
6295+ found = RGFW_TRUE;
6296+ break;
6297+ }
6298+ }
6299+
6300+ XFree(styles);
6301+ }
6302+
6303+ if (found == RGFW_FALSE) {
6304+ XCloseIM(_RGFW->im);
6305+ _RGFW->im = NULL;
6306+ }
6307+
6308+ XIMCallback callback;
6309+ callback.callback = (XIMProc) RGFW_x11_imCallback;
6310+ callback.client_data = NULL;
6311+ XSetIMValues(_RGFW->im, XNDestroyCallback, &callback, NULL);
6312+}
6313+
6314+void* RGFW_getDisplay_X11(void) { return _RGFW->display; }
6315+u64 RGFW_window_getWindow_X11(RGFW_window* win) { return (u64)win->src.window; }
6316+
6317+RGFWDEF RGFW_format RGFW_XImage_getFormat(XImage* image);
6318+RGFW_format RGFW_XImage_getFormat(XImage* image) {
6319+ switch (image->bits_per_pixel) {
6320+ case 24:
6321+ if (image->red_mask == 0xFF0000 && image->green_mask == 0x00FF00 && image->blue_mask == 0x0000FF)
6322+ return RGFW_formatRGB8;
6323+ if (image->red_mask == 0x0000FF && image->green_mask == 0x00FF00 && image->blue_mask == 0xFF0000)
6324+ return RGFW_formatBGR8;
6325+ break;
6326+ case 32:
6327+ if (image->red_mask == 0x00FF0000 && image->green_mask == 0x0000FF00 && image->blue_mask == 0x000000FF)
6328+ return RGFW_formatBGRA8;
6329+ if (image->red_mask == 0x000000FF && image->green_mask == 0x0000FF00 && image->blue_mask == 0x00FF0000)
6330+ return RGFW_formatRGBA8;
6331+ if (image->red_mask == 0x0000FF00 && image->green_mask == 0x00FF0000 && image->blue_mask == 0xFF000000)
6332+ return RGFW_formatABGR8;
6333+ if (image->red_mask == 0x00FF0000 && image->green_mask == 0x0000FF00 && image->blue_mask == 0x000000FF)
6334+ return RGFW_formatARGB8; /* ambiguous without alpha */
6335+ break;
6336+ }
6337+ return RGFW_formatARGB8;
6338+}
6339+
6340+
6341+RGFW_bool RGFW_window_createSurfacePtr(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) {
6342+ RGFW_ASSERT(surface != NULL);
6343+ surface->data = data;
6344+ surface->w = w;
6345+ surface->h = h;
6346+ surface->format = format;
6347+
6348+ XWindowAttributes attrs;
6349+ if (XGetWindowAttributes(_RGFW->display, win->src.window, &attrs) == 0) {
6350+ RGFW_debugCallback(RGFW_typeError, RGFW_errBuffer, "Failed to get window attributes.");
6351+ return RGFW_FALSE;
6352+ }
6353+
6354+ surface->native.bitmap = XCreateImage(_RGFW->display, attrs.visual, (u32)attrs.depth,
6355+ ZPixmap, 0, NULL, (u32)surface->w, (u32)surface->h, 32, 0);
6356+
6357+ surface->native.buffer = (u8*)RGFW_ALLOC((size_t)(w * h * 4));
6358+ surface->native.format = RGFW_XImage_getFormat(surface->native.bitmap);
6359+
6360+ if (surface->native.bitmap == NULL) {
6361+ RGFW_debugCallback(RGFW_typeError, RGFW_errBuffer, "Failed to create XImage.");
6362+ return RGFW_FALSE;
6363+ }
6364+
6365+ surface->native.format = RGFW_formatBGRA8;
6366+ return RGFW_TRUE;
6367+}
6368+
6369+RGFW_format RGFW_FUNC(RGFW_nativeFormat)(void) { return RGFW_formatBGRA8; }
6370+
6371+RGFW_bool RGFW_FUNC(RGFW_createSurfacePtr) (u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) {
6372+ return RGFW_window_createSurfacePtr(_RGFW->root, data, w, h, format, surface);
6373+}
6374+
6375+void RGFW_FUNC(RGFW_window_blitSurface) (RGFW_window* win, RGFW_surface* surface) {
6376+ RGFW_ASSERT(surface != NULL);
6377+ surface->native.bitmap->data = (char*)surface->native.buffer;
6378+ RGFW_copyImageData((u8*)surface->native.buffer, surface->w, RGFW_MIN(win->h, surface->h), surface->native.format, surface->data, surface->format, surface->convertFunc);
6379+
6380+ XPutImage(_RGFW->display, win->src.window, win->src.gc, surface->native.bitmap, 0, 0, 0, 0, (u32)RGFW_MIN(win->w, surface->w), (u32)RGFW_MIN(win->h, surface->h));
6381+ surface->native.bitmap->data = NULL;
6382+ return;
6383+}
6384+
6385+void RGFW_FUNC(RGFW_surface_freePtr) (RGFW_surface* surface) {
6386+ RGFW_ASSERT(surface != NULL);
6387+ RGFW_FREE(surface->native.buffer);
6388+ XDestroyImage(surface->native.bitmap);
6389+ return;
6390+}
6391+
6392+#define RGFW_LOAD_ATOM(name) \
6393+ static Atom name = 0; \
6394+ if (name == 0) name = XInternAtom(_RGFW->display, #name, False);
6395+
6396+void RGFW_FUNC(RGFW_window_setBorder) (RGFW_window* win, RGFW_bool border) {
6397+ RGFW_setBit(&win->internal.flags, RGFW_windowNoBorder, !border);
6398+ RGFW_LOAD_ATOM(_MOTIF_WM_HINTS);
6399+
6400+ struct __x11WindowHints {
6401+ unsigned long flags, functions, decorations, status;
6402+ long input_mode;
6403+ } hints;
6404+ hints.flags = 2;
6405+ hints.decorations = border;
6406+
6407+ XChangeProperty(_RGFW->display, win->src.window, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 32, PropModeReplace, (u8*)&hints, 5);
6408+
6409+ if (RGFW_window_isHidden(win) == 0) {
6410+ RGFW_window_hide(win);
6411+ RGFW_window_show(win);
6412+ }
6413+}
6414+
6415+void RGFW_FUNC(RGFW_window_setRawMouseModePlatform) (RGFW_window* win, RGFW_bool state) {
6416+ RGFW_UNUSED(win); RGFW_UNUSED(state);
6417+}
6418+
6419+void RGFW_FUNC(RGFW_window_captureMousePlatform) (RGFW_window* win, RGFW_bool state) {
6420+ if (state) {
6421+ unsigned int event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask;
6422+ XGrabPointer(_RGFW->display, win->src.window, True, event_mask, GrabModeAsync, GrabModeAsync, win->src.window, None, CurrentTime);
6423+ } else {
6424+ XUngrabPointer(_RGFW->display, CurrentTime);
6425+ }
6426+}
6427+
6428+#define RGFW_LOAD_LIBRARY(x, lib) if (x == NULL) x = dlopen(lib, RTLD_LAZY | RTLD_LOCAL)
6429+#define RGFW_PROC_DEF(proc, name) if (name##SRC == NULL && proc != NULL) { \
6430+ void* ptr = dlsym(proc, #name); \
6431+ if (ptr != NULL) RGFW_MEMCPY(&name##SRC, &ptr, sizeof(PFN_##name)); \
6432+}
6433+
6434+RGFWDEF void RGFW_window_getVisual(XVisualInfo* visual, RGFW_bool transparent);
6435+void RGFW_window_getVisual(XVisualInfo* visual, RGFW_bool transparent) {
6436+ visual->visual = DefaultVisual(_RGFW->display, DefaultScreen(_RGFW->display));
6437+ visual->depth = DefaultDepth(_RGFW->display, DefaultScreen(_RGFW->display));
6438+ if (transparent) {
6439+ XMatchVisualInfo(_RGFW->display, DefaultScreen(_RGFW->display), 32, TrueColor, visual); /*!< for RGBA backgrounds */
6440+ if (visual->depth != 32)
6441+ RGFW_debugCallback(RGFW_typeWarning, RGFW_warningOpenGL, "Failed to load a 32-bit depth.");
6442+ }
6443+}
6444+
6445+RGFWDEF int RGFW_XErrorHandler(Display* display, XErrorEvent* ev);
6446+int RGFW_XErrorHandler(Display* display, XErrorEvent* ev) {
6447+ char errorText[512];
6448+ XGetErrorText(display, ev->error_code, errorText, sizeof(errorText));
6449+
6450+ char buf[1024];
6451+ RGFW_SNPRINTF(buf, sizeof(buf), "[X Error] %s\n Error code: %d\n Request code: %d\n Minor code: %d\n Serial: %lu\n",
6452+ errorText,
6453+ ev->error_code, ev->request_code, ev->minor_code, ev->serial);
6454+
6455+ RGFW_debugCallback(RGFW_typeError, RGFW_errX11, buf);
6456+ _RGFW->x11Error = ev;
6457+ return 0;
6458+}
6459+
6460+void RGFW_XCreateWindow (XVisualInfo visual, const char* name, RGFW_windowFlags flags, RGFW_window* win) {
6461+ i64 event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | FocusChangeMask |
6462+ LeaveWindowMask | EnterWindowMask | ExposureMask | VisibilityChangeMask | PropertyChangeMask;
6463+
6464+ /* make X window attrubutes */
6465+ XSetWindowAttributes swa;
6466+ RGFW_MEMZERO(&swa, sizeof(swa));
6467+
6468+ win->src.parent = DefaultRootWindow(_RGFW->display);
6469+
6470+ Colormap cmap;
6471+ swa.colormap = cmap = XCreateColormap(_RGFW->display,
6472+ win->src.parent,
6473+ visual.visual, AllocNone);
6474+ swa.event_mask = event_mask;
6475+ swa.background_pixmap = None;
6476+
6477+ /* create the window */
6478+ win->src.window = XCreateWindow(_RGFW->display, win->src.parent, win->x, win->y, (u32)win->w, (u32)win->h,
6479+ 0, visual.depth, InputOutput, visual.visual,
6480+ CWBorderPixel | CWColormap | CWEventMask, &swa);
6481+
6482+ win->src.flashEnd = 0;
6483+
6484+ XFreeColors(_RGFW->display, cmap, NULL, 0, 0);
6485+
6486+ XSaveContext(_RGFW->display, win->src.window, _RGFW->context, (XPointer)win);
6487+
6488+ win->src.gc = XCreateGC(_RGFW->display, win->src.window, 0, NULL);
6489+
6490+ if (_RGFW->im) {
6491+ XIMCallback callback;
6492+ callback.callback = (XIMProc) RGFW_x11_icCallback;
6493+ callback.client_data = (XPointer) win;
6494+
6495+ win->src.ic = XCreateIC(_RGFW->im, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, win->src.window, XNFocusWindow, win->src.window, XNDestroyCallback, &callback, NULL);
6496+ }
6497+
6498+
6499+ /* In your .desktop app, if you set the property
6500+ StartupWMClass=RGFW that will assoicate the launcher icon
6501+ with your application - robrohan */
6502+ if (_RGFW->className == NULL)
6503+ _RGFW->className = (char*)name;
6504+
6505+ XClassHint hint;
6506+ hint.res_class = (char*)_RGFW->className;
6507+
6508+ if (_RGFW->instName == NULL) hint.res_name = (char*)name;
6509+ else hint.res_name = (char*)_RGFW->instName;
6510+
6511+ XSetClassHint(_RGFW->display, win->src.window, &hint);
6512+
6513+ XWMHints hints;
6514+ hints.flags = StateHint;
6515+ hints.initial_state = NormalState;
6516+
6517+ XSetWMHints(_RGFW->display, win->src.window, &hints);
6518+
6519+ XSelectInput(_RGFW->display, (Drawable) win->src.window, event_mask); /*!< tell X11 what events we want */
6520+
6521+ /* make it so the user can't close the window until the program does */
6522+ RGFW_LOAD_ATOM(WM_DELETE_WINDOW);
6523+ XSetWMProtocols(_RGFW->display, (Drawable) win->src.window, &WM_DELETE_WINDOW, 1);
6524+ /* set the background */
6525+ RGFW_window_setName(win, name);
6526+
6527+ XMoveWindow(_RGFW->display, (Drawable) win->src.window, win->x, win->y); /*!< move the window to it's proper cords */
6528+
6529+ if (flags & RGFW_windowAllowDND) { /* init drag and drop atoms and turn on drag and drop for this window */
6530+ win->internal.flags |= RGFW_windowAllowDND;
6531+
6532+ /* actions */
6533+ Atom XdndAware = XInternAtom(_RGFW->display, "XdndAware", False);
6534+ const u8 version = 5;
6535+
6536+ XChangeProperty(_RGFW->display, win->src.window,
6537+ XdndAware, 4, 32,
6538+ PropModeReplace, &version, 1); /*!< turns on drag and drop */
6539+ }
6540+
6541+#ifdef RGFW_ADVANCED_SMOOTH_RESIZE
6542+ RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST_COUNTER)
6543+ RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST)
6544+
6545+ Atom protcols[2] = {_NET_WM_SYNC_REQUEST, WM_DELETE_WINDOW};
6546+ XSetWMProtocols(_RGFW->display, win->src.window, protcols, 2);
6547+
6548+ XSyncValue initial_value;
6549+ XSyncIntToValue(&initial_value, 0);
6550+ win->src.counter = XSyncCreateCounter(_RGFW->display, initial_value);
6551+
6552+ XChangeProperty(_RGFW->display, win->src.window, _NET_WM_SYNC_REQUEST_COUNTER, XA_CARDINAL, 32, PropModeReplace, (u8*)&win->src.counter, 1);
6553+#endif
6554+
6555+ win->src.x = win->x;
6556+ win->src.y = win->y;
6557+ win->src.w = win->w;
6558+ win->src.h = win->h;
6559+
6560+ XSetWindowBackground(_RGFW->display, win->src.window, None);
6561+ XClearWindow(_RGFW->display, win->src.window);
6562+
6563+ /* stupid hack to make resizing the window less bad */
6564+ XSetWindowBackgroundPixmap(_RGFW->display, win->src.window, None);
6565+}
6566+
6567+RGFW_window* RGFW_FUNC(RGFW_createWindowPlatform) (const char* name, RGFW_windowFlags flags, RGFW_window* win) {
6568+ if ((flags & RGFW_windowOpenGL) || (flags & RGFW_windowEGL)) {
6569+ win->src.window = 0;
6570+ return win;
6571+ }
6572+
6573+ XVisualInfo visual;
6574+ RGFW_window_getVisual(&visual, RGFW_BOOL(win->internal.flags & RGFW_windowTransparent));
6575+ RGFW_XCreateWindow(visual, name, flags, win);
6576+ return win; /*return newly created window */
6577+}
6578+
6579+RGFW_bool RGFW_FUNC(RGFW_getGlobalMouse) (i32* fX, i32* fY) {
6580+ RGFW_init();
6581+ i32 x, y;
6582+ u32 z;
6583+ Window window1, window2;
6584+ XQueryPointer(_RGFW->display, XDefaultRootWindow(_RGFW->display), &window1, &window2, fX, fY, &x, &y, &z);
6585+ return RGFW_TRUE;
6586+}
6587+
6588+RGFWDEF void RGFW_XHandleClipboardSelection(XEvent* event);
6589+void RGFW_XHandleClipboardSelection(XEvent* event) { RGFW_UNUSED(event);
6590+ RGFW_LOAD_ATOM(ATOM_PAIR);
6591+ RGFW_LOAD_ATOM(MULTIPLE);
6592+ RGFW_LOAD_ATOM(TARGETS);
6593+ RGFW_LOAD_ATOM(SAVE_TARGETS);
6594+ RGFW_LOAD_ATOM(UTF8_STRING);
6595+
6596+ const XSelectionRequestEvent* request = &event->xselectionrequest;
6597+ Atom formats[2] = {0};
6598+ formats[0] = UTF8_STRING;
6599+ formats[1] = XA_STRING;
6600+ const int formatCount = sizeof(formats) / sizeof(formats[0]);
6601+
6602+ if (request->target == TARGETS) {
6603+ Atom targets[4] = {0};
6604+ targets[0] = TARGETS;
6605+ targets[1] = MULTIPLE;
6606+ targets[2] = UTF8_STRING;
6607+ targets[3] = XA_STRING;
6608+
6609+ XChangeProperty(_RGFW->display, request->requestor, request->property,
6610+ XA_ATOM, 32, PropModeReplace, (u8*) targets, sizeof(targets) / sizeof(Atom));
6611+ } else if (request->target == MULTIPLE) {
6612+ Atom* targets = NULL;
6613+
6614+ Atom actualType = 0;
6615+ int actualFormat = 0;
6616+ unsigned long count = 0, bytesAfter = 0;
6617+
6618+ XGetWindowProperty(_RGFW->display, request->requestor, request->property, 0, LONG_MAX,
6619+ False, ATOM_PAIR, &actualType, &actualFormat, &count, &bytesAfter, (u8**) &targets);
6620+
6621+ unsigned long i;
6622+ for (i = 0; i < (u32)count; i += 2) {
6623+ if (targets[i] == UTF8_STRING || targets[i] == XA_STRING)
6624+ XChangeProperty(_RGFW->display, request->requestor, targets[i + 1], targets[i],
6625+ 8, PropModeReplace, (const unsigned char *)_RGFW->clipboard, (i32)_RGFW->clipboard_len);
6626+ else
6627+ targets[i + 1] = None;
6628+ }
6629+
6630+ XChangeProperty(_RGFW->display,
6631+ request->requestor, request->property, ATOM_PAIR, 32,
6632+ PropModeReplace, (u8*) targets, (i32)count);
6633+
6634+ XFlush(_RGFW->display);
6635+ XFree(targets);
6636+ } else if (request->target == SAVE_TARGETS)
6637+ XChangeProperty(_RGFW->display, request->requestor, request->property, 0, 32, PropModeReplace, NULL, 0);
6638+ else {
6639+ int i;
6640+ for (i = 0; i < formatCount; i++) {
6641+ if (request->target != formats[i])
6642+ continue;
6643+ XChangeProperty(_RGFW->display, request->requestor, request->property, request->target,
6644+ 8, PropModeReplace, (u8*) _RGFW->clipboard, (i32)_RGFW->clipboard_len);
6645+ }
6646+ }
6647+
6648+ XEvent reply = { SelectionNotify };
6649+ reply.xselection.property = request->property;
6650+ reply.xselection.display = request->display;
6651+ reply.xselection.requestor = request->requestor;
6652+ reply.xselection.selection = request->selection;
6653+ reply.xselection.target = request->target;
6654+ reply.xselection.time = request->time;
6655+
6656+ XSendEvent(_RGFW->display, request->requestor, False, 0, &reply);
6657+ XFlush(_RGFW->display);
6658+}
6659+
6660+i32 RGFW_XHandleClipboardSelectionHelper(void);
6661+
6662+RGFW_key RGFW_FUNC(RGFW_physicalToMappedKey) (RGFW_key key) {
6663+ KeyCode keycode = (KeyCode)RGFW_rgfwToApiKey(key);
6664+ KeySym sym = XkbKeycodeToKeysym(_RGFW->display, keycode, 0, 0);
6665+
6666+ if (sym < 256) {
6667+ return (RGFW_key)sym;
6668+ }
6669+
6670+ switch (sym) {
6671+ case XK_F1: return RGFW_keyF1;
6672+ case XK_F2: return RGFW_keyF2;
6673+ case XK_F3: return RGFW_keyF3;
6674+ case XK_F4: return RGFW_keyF4;
6675+ case XK_F5: return RGFW_keyF5;
6676+ case XK_F6: return RGFW_keyF6;
6677+ case XK_F7: return RGFW_keyF7;
6678+ case XK_F8: return RGFW_keyF8;
6679+ case XK_F9: return RGFW_keyF9;
6680+ case XK_F10: return RGFW_keyF10;
6681+ case XK_F11: return RGFW_keyF11;
6682+ case XK_F12: return RGFW_keyF12;
6683+ case XK_F13: return RGFW_keyF13;
6684+ case XK_F14: return RGFW_keyF14;
6685+ case XK_F15: return RGFW_keyF15;
6686+ case XK_F16: return RGFW_keyF16;
6687+ case XK_F17: return RGFW_keyF17;
6688+ case XK_F18: return RGFW_keyF18;
6689+ case XK_F19: return RGFW_keyF19;
6690+ case XK_F20: return RGFW_keyF20;
6691+ case XK_F21: return RGFW_keyF21;
6692+ case XK_F22: return RGFW_keyF22;
6693+ case XK_F23: return RGFW_keyF23;
6694+ case XK_F24: return RGFW_keyF24;
6695+ case XK_F25: return RGFW_keyF25;
6696+ case XK_Shift_L: return RGFW_keyShiftL;
6697+ case XK_Shift_R: return RGFW_keyShiftR;
6698+ case XK_Control_L: return RGFW_keyControlL;
6699+ case XK_Control_R: return RGFW_keyControlR;
6700+ case XK_Alt_L: return RGFW_keyAltL;
6701+ case XK_Alt_R: return RGFW_keyAltR;
6702+ case XK_Super_L: return RGFW_keySuperL;
6703+ case XK_Super_R: return RGFW_keySuperR;
6704+ case XK_Caps_Lock: return RGFW_keyCapsLock;
6705+ case XK_Num_Lock: return RGFW_keyNumLock;
6706+ case XK_Scroll_Lock:return RGFW_keyScrollLock;
6707+ case XK_Up: return RGFW_keyUp;
6708+ case XK_Down: return RGFW_keyDown;
6709+ case XK_Left: return RGFW_keyLeft;
6710+ case XK_Right: return RGFW_keyRight;
6711+ case XK_Home: return RGFW_keyHome;
6712+ case XK_End: return RGFW_keyEnd;
6713+ case XK_Page_Up: return RGFW_keyPageUp;
6714+ case XK_Page_Down: return RGFW_keyPageDown;
6715+ case XK_Insert: return RGFW_keyInsert;
6716+ case XK_Menu: return RGFW_keyMenu;
6717+ case XK_KP_Add: return RGFW_keyPadPlus;
6718+ case XK_KP_Subtract: return RGFW_keyPadMinus;
6719+ case XK_KP_Multiply: return RGFW_keyPadMultiply;
6720+ case XK_KP_Divide: return RGFW_keyPadSlash;
6721+ case XK_KP_Equal: return RGFW_keyPadEqual;
6722+ case XK_KP_Enter: return RGFW_keyPadReturn;
6723+ case XK_KP_Decimal: return RGFW_keyPadPeriod;
6724+ case XK_KP_0: return RGFW_keyPad0;
6725+ case XK_KP_1: return RGFW_keyPad1;
6726+ case XK_KP_2: return RGFW_keyPad2;
6727+ case XK_KP_3: return RGFW_keyPad3;
6728+ case XK_KP_4: return RGFW_keyPad4;
6729+ case XK_KP_5: return RGFW_keyPad5;
6730+ case XK_KP_6: return RGFW_keyPad6;
6731+ case XK_KP_7: return RGFW_keyPad7;
6732+ case XK_KP_8: return RGFW_keyPad8;
6733+ case XK_KP_9: return RGFW_keyPad9;
6734+ case XK_Print: return RGFW_keyPrintScreen;
6735+ case XK_Pause: return RGFW_keyPause;
6736+ default: break;
6737+ }
6738+
6739+ return RGFW_keyNULL;
6740+}
6741+
6742+RGFWDEF void RGFW_XHandleEvent(void);
6743+void RGFW_XHandleEvent(void) {
6744+ RGFW_LOAD_ATOM(XdndTypeList);
6745+ RGFW_LOAD_ATOM(XdndSelection);
6746+ RGFW_LOAD_ATOM(XdndEnter);
6747+ RGFW_LOAD_ATOM(XdndPosition);
6748+ RGFW_LOAD_ATOM(XdndStatus);
6749+ RGFW_LOAD_ATOM(XdndLeave);
6750+ RGFW_LOAD_ATOM(XdndDrop);
6751+ RGFW_LOAD_ATOM(XdndFinished);
6752+ RGFW_LOAD_ATOM(XdndActionCopy);
6753+ RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST);
6754+ RGFW_LOAD_ATOM(WM_PROTOCOLS);
6755+ RGFW_LOAD_ATOM(WM_STATE);
6756+ RGFW_LOAD_ATOM(_NET_WM_STATE);
6757+
6758+ static float deltaX = 0.0f;
6759+ static float deltaY = 0.0f;
6760+
6761+ XEvent E;
6762+
6763+ XNextEvent(_RGFW->display, &E);
6764+
6765+ if (E.type != GenericEvent) {
6766+ deltaX = 0.0f;
6767+ deltaY = 0.0f;
6768+ }
6769+
6770+ if (E.type == _RGFW->xrandrEventBase + RRNotify) {
6771+ RGFW_pollMonitors();
6772+ return;
6773+ }
6774+
6775+ switch (E.type) {
6776+ case SelectionRequest:
6777+ RGFW_XHandleClipboardSelection(&E);
6778+ return;
6779+ case GenericEvent: {
6780+ XGetEventData(_RGFW->display, &E.xcookie);
6781+ switch (E.xcookie.evtype) {
6782+ case XI_RawMotion: {
6783+ XIRawEvent* raw = (XIRawEvent *)E.xcookie.data;
6784+ if (raw->valuators.mask_len == 0) {
6785+ XFreeEventData(_RGFW->display, &E.xcookie);
6786+ return;
6787+ }
6788+
6789+ i32 index = 0;
6790+ if (XIMaskIsSet(raw->valuators.mask, 0) != 0) {
6791+ deltaX += (float)raw->raw_values[index];
6792+ index += 1;
6793+ }
6794+
6795+ if (XIMaskIsSet(raw->valuators.mask, 1) != 0)
6796+ deltaY += (float)raw->raw_values[index];
6797+
6798+ _RGFW->vectorX = (float)deltaX;
6799+ _RGFW->vectorY = (float)deltaY;
6800+ RGFW_rawMotionCallback(_RGFW->root, _RGFW->vectorX, _RGFW->vectorY);
6801+ }
6802+ default: break;
6803+ }
6804+
6805+ XFreeEventData(_RGFW->display, &E.xcookie);
6806+ return;
6807+ }
6808+ }
6809+
6810+ RGFW_window* win = NULL;
6811+ if (XFindContext(_RGFW->display, E.xany.window, _RGFW->context, (XPointer*) &win) != 0) {
6812+ return;
6813+ }
6814+
6815+ if (win->src.flashEnd) {
6816+ if ((win->src.flashEnd <= RGFW_linux_getTimeNS()) || RGFW_window_isInFocus(win)) {
6817+ RGFW_window_flash(win, RGFW_flashCancel);
6818+ }
6819+ }
6820+
6821+
6822+ /*
6823+ Repeated key presses are sent as a release followed by another press at the same time.
6824+ We want to convert that into a single key press event with the repeat flag set
6825+ */
6826+
6827+ RGFW_bool keyRepeat = RGFW_FALSE;
6828+
6829+ if (E.type == KeyRelease && XEventsQueued(_RGFW->display, QueuedAfterReading)) {
6830+ XEvent NE;
6831+ XPeekEvent(_RGFW->display, &NE);
6832+ if (NE.type == KeyPress && E.xkey.time == NE.xkey.time && E.xkey.keycode == NE.xkey.keycode) {
6833+ /* Use the next KeyPress event */
6834+ XNextEvent(_RGFW->display, &E);
6835+ keyRepeat = RGFW_TRUE;
6836+ }
6837+ }
6838+
6839+ switch (E.type) {
6840+ case KeyPress: {
6841+ if (!(win->internal.enabledEvents & RGFW_keyPressedFlag)) return;
6842+ RGFW_key value = (u8)RGFW_apiKeyToRGFW(E.xkey.keycode);
6843+
6844+ XkbStateRec state;
6845+ XkbGetState(_RGFW->display, XkbUseCoreKbd, &state);
6846+ RGFW_keyUpdateKeyMods(win, (state.locked_mods & LockMask), (state.locked_mods & Mod2Mask), (state.locked_mods & Mod3Mask));
6847+
6848+ if (win->src.ic && XFilterEvent(&E, None) == False) {
6849+ char buffer[100];
6850+ char* chars = buffer;
6851+
6852+ Status status;
6853+ size_t count = (size_t)Xutf8LookupString(win->src.ic, &E.xkey, buffer, sizeof(buffer) - 1, NULL, &status);
6854+
6855+ if (status == XBufferOverflow) {
6856+ chars = (char*)RGFW_ALLOC(count + 1);
6857+ count = (size_t)Xutf8LookupString(win->src.ic, &E.xkey, chars, (int)count, NULL, &status);
6858+ }
6859+
6860+ if (status == XLookupChars || status == XLookupBoth) {
6861+ chars[count] = '\0';
6862+ for (size_t index = 0; index < count;
6863+ RGFW_keyCharCallback(win, RGFW_decodeUTF8(&chars[index], &index))
6864+ );
6865+ }
6866+
6867+ if (chars != buffer)
6868+ RGFW_FREE(chars);
6869+ } else {
6870+ Window root = DefaultRootWindow(_RGFW->display);
6871+ Window ret_root, ret_child;
6872+ int root_x, root_y, win_x, win_y;
6873+ unsigned int mask;
6874+ XQueryPointer(_RGFW->display, root, &ret_root, &ret_child, &root_x, &root_y, &win_x, &win_y, &mask);
6875+ KeySym sym = (KeySym)XkbKeycodeToKeysym(_RGFW->display, (KeyCode)E.xkey.keycode, 0, (KeyCode)mask & ShiftMask ? 1 : 0);
6876+
6877+ if ((mask & LockMask) && sym >= XK_a && sym <= XK_z)
6878+ sym = (mask & ShiftMask) ? sym + 32 : sym - 32;
6879+ if ((u8)sym != (u32)sym)
6880+ sym = 0;
6881+
6882+ RGFW_keyCharCallback(win, (u8)sym);
6883+ }
6884+
6885+ RGFW_keyCallback(win, value, win->internal.mod, keyRepeat, RGFW_TRUE);
6886+ break;
6887+ }
6888+ case KeyRelease: {
6889+ if (!(win->internal.enabledEvents & RGFW_keyReleasedFlag)) return;
6890+
6891+ RGFW_key value = (u8)RGFW_apiKeyToRGFW(E.xkey.keycode);
6892+
6893+ XkbStateRec state;
6894+ XkbGetState(_RGFW->display, XkbUseCoreKbd, &state);
6895+ RGFW_keyUpdateKeyMods(win, (state.locked_mods & LockMask), (state.locked_mods & Mod2Mask), (state.locked_mods & Mod3Mask));
6896+
6897+ RGFW_keyCallback(win, value, win->internal.mod, RGFW_FALSE, RGFW_FALSE);
6898+ break;
6899+ }
6900+ case ButtonPress: {
6901+ RGFW_bool scroll = RGFW_FALSE;
6902+ if (E.xbutton.button >= Button4 && E.xbutton.button <= 7) {
6903+ scroll = RGFW_TRUE;
6904+ }
6905+
6906+ float scrollX = 0.0f;
6907+ float scrollY = 0.0f;
6908+ RGFW_mouseButton value = 0;
6909+
6910+ switch (E.xbutton.button) {
6911+ case Button1: value = RGFW_mouseLeft; break;
6912+ case Button2: value = RGFW_mouseMiddle; break;
6913+ case Button3: value = RGFW_mouseRight; break;
6914+ case Button4: scrollY = 1.0; break;
6915+ case Button5: scrollY = -1.0; break;
6916+ case 6: scrollX = 1.0f; break;
6917+ case 7: scrollX = -1.0f; break;
6918+ default:
6919+ value = (u8)E.xbutton.button - Button1 - 4;
6920+ break;
6921+ }
6922+
6923+ if (scroll) {
6924+ RGFW_mouseScrollCallback(win, scrollX, scrollY);
6925+ break;
6926+ }
6927+
6928+ RGFW_mouseButtonCallback(win, value, RGFW_TRUE);
6929+ break;
6930+ }
6931+ case ButtonRelease: {
6932+ if (E.xbutton.button >= Button4 && E.xbutton.button <= 7) break;
6933+
6934+ RGFW_mouseButton value = 0;
6935+ switch(E.xbutton.button) {
6936+ case Button1: value = RGFW_mouseLeft; break;
6937+ case Button2: value = RGFW_mouseMiddle; break;
6938+ case Button3: value = RGFW_mouseRight; break;
6939+ default:
6940+ value = (u8)E.xbutton.button - Button1 - 4;
6941+ break;
6942+ }
6943+
6944+ RGFW_mouseButtonCallback(win, value, RGFW_FALSE);
6945+ break;
6946+ }
6947+ case MotionNotify:
6948+ RGFW_mousePosCallback(win, E.xmotion.x, E.xmotion.y);
6949+ break;
6950+
6951+ case Expose: {
6952+ RGFW_windowRefreshCallback(win, 0, 0, win->w, win->h);
6953+
6954+#ifdef RGFW_ADVANCED_SMOOTH_RESIZE
6955+ XSyncValue value;
6956+ XSyncIntToValue(&value, (i32)win->src.counter_value);
6957+ XSyncSetCounter(_RGFW->display, win->src.counter, value);
6958+#endif
6959+ break;
6960+ }
6961+
6962+ case PropertyNotify:
6963+ if (E.xproperty.state != PropertyNewValue) break;
6964+
6965+ if (E.xproperty.atom == WM_STATE) {
6966+ if (RGFW_window_isMinimized(win) && !(win->internal.flags & RGFW_windowMinimized)) {
6967+ RGFW_windowMinimizedCallback(win);
6968+ break;
6969+ }
6970+ } else if (E.xproperty.atom == _NET_WM_STATE) {
6971+ if (RGFW_window_isMaximized(win) && !(win->internal.flags & RGFW_windowMaximize)) {
6972+ RGFW_windowMaximizedCallback(win, win->x, win->y, win->w, win->h);
6973+ break;
6974+ }
6975+ }
6976+
6977+ RGFW_window_checkMode(win);
6978+ break;
6979+ case MapNotify: case UnmapNotify: RGFW_window_checkMode(win); break;
6980+ case ClientMessage: {
6981+ RGFW_LOAD_ATOM(WM_DELETE_WINDOW);
6982+ /* if the client closed the window */
6983+ if (E.xclient.data.l[0] == (long)WM_DELETE_WINDOW) {
6984+ RGFW_windowCloseCallback(win);
6985+ break;
6986+ }
6987+#ifdef RGFW_ADVANCED_SMOOTH_RESIZE
6988+ if (E.xclient.message_type == WM_PROTOCOLS && (Atom)E.xclient.data.l[0] == _NET_WM_SYNC_REQUEST) {
6989+ RGFW_windowRefreshCallback(win, 0, 0, win->w, win->h);
6990+ win->src.counter_value = 0;
6991+ win->src.counter_value |= E.xclient.data.l[2];
6992+ win->src.counter_value |= (E.xclient.data.l[3] << 32);
6993+
6994+ XSyncValue value;
6995+ XSyncIntToValue(&value, (i32)win->src.counter_value);
6996+ XSyncSetCounter(_RGFW->display, win->src.counter, value);
6997+ break;
6998+ }
6999+#endif
7000+ if ((win->internal.flags & RGFW_windowAllowDND) == 0 || _RGFW->x11Version > RGFW_XDND_VERSION) {
7001+ return;
7002+ }
7003+
7004+ i32 dragX = 0;
7005+ i32 dragY = 0;
7006+
7007+ if (E.xclient.message_type == XdndEnter) {
7008+ unsigned long count;
7009+ Atom* formats;
7010+ Atom real_formats[3];
7011+ Bool list = E.xclient.data.l[1] & 1;
7012+
7013+ _RGFW->x11Source = (Window)E.xclient.data.l[0];
7014+ _RGFW->x11Version = E.xclient.data.l[1] >> 24;
7015+ _RGFW->x11Format = None;
7016+ if (list) {
7017+ Atom actualType;
7018+ i32 actualFormat;
7019+ unsigned long bytesAfter;
7020+
7021+ XGetWindowProperty(
7022+ _RGFW->display, _RGFW->x11Source, XdndTypeList,
7023+ 0, LONG_MAX, False, 4,
7024+ &actualType, &actualFormat, &count, &bytesAfter, (u8**)&formats
7025+ );
7026+ } else {
7027+ count = 0;
7028+
7029+ size_t i;
7030+ for (i = 2; i < (2 + 3); i++) {
7031+ if (E.xclient.data.l[i] != None) {
7032+ real_formats[count] = (unsigned long int)E.xclient.data.l[i];
7033+ count += 1;
7034+ }
7035+ }
7036+
7037+ formats = real_formats;
7038+ }
7039+
7040+ Atom XtextPlain = XInternAtom(_RGFW->display, "text/plain", False);
7041+ Atom XtextUriList = XInternAtom(_RGFW->display, "text/uri-list", False);
7042+
7043+ size_t i;
7044+ for (i = 0; i < count; i++) {
7045+ if (formats[i] == XtextUriList) _RGFW->x11TransferType = RGFW_dataFile;
7046+ else if (formats[i] == XtextPlain) _RGFW->x11TransferType = RGFW_dataText;
7047+ else continue;
7048+
7049+ _RGFW->x11Format = (int)formats[i];
7050+ break;
7051+ }
7052+
7053+ if (list && formats) {
7054+ XFree(formats);
7055+ }
7056+
7057+
7058+ RGFW_dataDragCallback(win, _RGFW->x11TransferType , RGFW_dndActionEnter, dragX, dragY);
7059+ } else if (E.xclient.message_type == XdndPosition) {
7060+ const i32 xabs = (E.xclient.data.l[2] >> 16) & 0xffff;
7061+ const i32 yabs = (E.xclient.data.l[2]) & 0xffff;
7062+ Window dummy;
7063+ i32 xpos, ypos;
7064+
7065+ XTranslateCoordinates(
7066+ _RGFW->display, XDefaultRootWindow(_RGFW->display), win->src.window,
7067+ xabs, yabs, &xpos, &ypos, &dummy
7068+ );
7069+
7070+ dragX = xpos;
7071+ dragY = ypos;
7072+
7073+ RGFW_mousePosCallback(win, xpos, ypos);
7074+ XEvent reply = { ClientMessage };
7075+ reply.xclient.window = _RGFW->x11Source;
7076+ reply.xclient.message_type = XdndStatus;
7077+ reply.xclient.format = 32;
7078+ reply.xclient.data.l[0] = (long)win->src.window;
7079+ reply.xclient.data.l[2] = 0;
7080+ reply.xclient.data.l[3] = 0;
7081+
7082+ if (_RGFW->x11Format) {
7083+ reply.xclient.data.l[1] = 1;
7084+ if (_RGFW->x11Version >= 2)
7085+ reply.xclient.data.l[4] = (long)XdndActionCopy;
7086+ }
7087+
7088+ XSendEvent(_RGFW->display, _RGFW->x11Source, False, NoEventMask, &reply);
7089+ XFlush(_RGFW->display);
7090+
7091+
7092+ RGFW_dataDragCallback(win, _RGFW->x11TransferType, RGFW_dndActionMove, dragX, dragY);
7093+ } else if (E.xclient.message_type == XdndLeave) {
7094+ RGFW_dataDragCallback(win, _RGFW->x11TransferType, RGFW_dndActionExit, dragX, dragY);
7095+ } else if (E.xclient.message_type == XdndDrop) {
7096+ if (_RGFW->x11Format) {
7097+ Time time = (_RGFW->x11Version >= 1)
7098+ ? (Time)E.xclient.data.l[2]
7099+ : CurrentTime;
7100+ XConvertSelection(
7101+ _RGFW->display, XdndSelection, (Atom)_RGFW->x11Format,
7102+ XdndSelection, win->src.window, time
7103+ );
7104+ } else if (_RGFW->x11Version >= 2) {
7105+ XEvent reply = { ClientMessage };
7106+ reply.xclient.window = _RGFW->x11Source;
7107+ reply.xclient.message_type = XdndFinished;
7108+ reply.xclient.format = 32;
7109+ reply.xclient.data.l[0] = (long)win->src.window;
7110+ reply.xclient.data.l[1] = 0;
7111+ reply.xclient.data.l[2] = None;
7112+
7113+ XSendEvent(_RGFW->display, _RGFW->x11Source, False, NoEventMask, &reply);
7114+ XFlush(_RGFW->display);
7115+ }
7116+ }
7117+ } break;
7118+ case SelectionNotify: {
7119+ /* this is only for checking for xdnd drops */
7120+ if (!(win->internal.enabledEvents & RGFW_dataDropFlag) || E.xselection.property != XdndSelection || !(win->internal.flags & RGFW_windowAllowDND))
7121+ return;
7122+ char* data;
7123+ unsigned long result;
7124+
7125+ Atom actualType;
7126+ i32 actualFormat;
7127+ unsigned long bytesAfter;
7128+
7129+ XGetWindowProperty(_RGFW->display, E.xselection.requestor, E.xselection.property, 0, LONG_MAX, False, E.xselection.target, &actualType, &actualFormat, &result, &bytesAfter, (u8**) &data);
7130+
7131+ if (result != 0) {
7132+ RGFW_unix_parseURI(win, data);
7133+
7134+ if (data)
7135+ XFree(data);
7136+ }
7137+
7138+ if (_RGFW->x11Version >= 2) {
7139+ XEvent reply = { ClientMessage };
7140+ reply.xclient.window = _RGFW->x11Source;
7141+ reply.xclient.message_type = XdndFinished;
7142+ reply.xclient.format = 32;
7143+ reply.xclient.data.l[0] = (long)win->src.window;
7144+ reply.xclient.data.l[1] = (long int)result;
7145+ reply.xclient.data.l[2] = (long int)XdndActionCopy;
7146+ XSendEvent(_RGFW->display, _RGFW->x11Source, False, NoEventMask, &reply);
7147+ XFlush(_RGFW->display);
7148+ }
7149+ break;
7150+ }
7151+ case FocusIn:
7152+ if (win->src.ic) XSetICFocus(win->src.ic);
7153+ RGFW_windowFocusCallback(win, 1);
7154+ break;
7155+ case FocusOut:
7156+ if (win->src.ic) XUnsetICFocus(win->src.ic);
7157+ RGFW_windowFocusCallback(win, 0);
7158+ break;
7159+ case EnterNotify: {
7160+ RGFW_mouseNotifyCallback(win, E.xcrossing.x, E.xcrossing.y, RGFW_TRUE);
7161+ break;
7162+ }
7163+
7164+ case LeaveNotify: {
7165+ RGFW_mouseNotifyCallback(win, win->internal.lastMouseX, win->internal.lastMouseY, RGFW_FALSE);
7166+ break;
7167+ }
7168+ case ReparentNotify:
7169+ win->src.parent = E.xreparent.parent;
7170+ break;
7171+ case ConfigureNotify: {
7172+ /* detect resize */
7173+ if (E.xconfigure.width != win->src.w || E.xconfigure.height != win->src.h) {
7174+ RGFW_window_checkMode(win);
7175+ win->src.w = E.xconfigure.width;
7176+ win->src.h = E.xconfigure.height;
7177+ RGFW_windowResizedCallback(win, E.xconfigure.width, E.xconfigure.height);
7178+ }
7179+
7180+ i32 x = E.xconfigure.x;
7181+ i32 y = E.xconfigure.y;
7182+
7183+ /*
7184+ if the event came from the server and we're not a direct child of the root window then
7185+ we're using local coords which need to be translated into screen coords
7186+ */
7187+ Window root = DefaultRootWindow(_RGFW->display);
7188+ if (E.xany.send_event == 0 && win->src.parent != root) {
7189+ Window dummy = 0;
7190+ XTranslateCoordinates(_RGFW->display, win->src.parent, root, x, y, &x, &y, &dummy);
7191+ }
7192+
7193+ /* detect move */
7194+ if (E.xconfigure.x != win->src.x || E.xconfigure.y != win->src.y) {
7195+ win->src.x = E.xconfigure.x;
7196+ win->src.y = E.xconfigure.y;
7197+ RGFW_windowMovedCallback(win, E.xconfigure.x, E.xconfigure.y);
7198+ }
7199+ return;
7200+ }
7201+ default:
7202+ break;
7203+ }
7204+
7205+ XFlush(_RGFW->display);
7206+}
7207+
7208+RGFW_bool RGFW_FUNC(RGFW_window_fetchSize) (RGFW_window* win, i32* w, i32* h) {
7209+ XWindowAttributes attribs;
7210+ XGetWindowAttributes(_RGFW->display, win->src.window, &attribs);
7211+
7212+ win->w = attribs.width;
7213+ win->h = attribs.height;
7214+
7215+ return RGFW_window_getSize(win, w, h);
7216+}
7217+
7218+void RGFW_FUNC(RGFW_pollEvents) (void) {
7219+ RGFW_resetPrevState();
7220+
7221+ XPending(_RGFW->display);
7222+ /* if there is no unread queued events, get a new one */
7223+ while (QLength(_RGFW->display)) {
7224+ RGFW_XHandleEvent();
7225+ }
7226+}
7227+
7228+void RGFW_FUNC(RGFW_window_move) (RGFW_window* win, i32 x, i32 y) {
7229+ RGFW_ASSERT(win != NULL);
7230+ win->x = x;
7231+ win->y = y;
7232+
7233+ XMoveWindow(_RGFW->display, win->src.window, x, y);
7234+ return;
7235+}
7236+
7237+
7238+void RGFW_FUNC(RGFW_window_resize) (RGFW_window* win, i32 w, i32 h) {
7239+ RGFW_ASSERT(win != NULL);
7240+ win->w = (i32)w;
7241+ win->h = (i32)h;
7242+
7243+ XResizeWindow(_RGFW->display, win->src.window, (u32)w, (u32)h);
7244+
7245+ if ((win->internal.flags & RGFW_windowNoResize)) {
7246+ XSizeHints sh;
7247+ sh.flags = (1L << 4) | (1L << 5);
7248+ sh.min_width = sh.max_width = (i32)w;
7249+ sh.min_height = sh.max_height = (i32)h;
7250+
7251+ XSetWMSizeHints(_RGFW->display, (Drawable) win->src.window, &sh, XA_WM_NORMAL_HINTS);
7252+ }
7253+ return;
7254+}
7255+
7256+void RGFW_FUNC(RGFW_window_setAspectRatio) (RGFW_window* win, i32 w, i32 h) {
7257+ RGFW_ASSERT(win != NULL);
7258+
7259+
7260+ if (w == 0 && h == 0)
7261+ return;
7262+ XSizeHints hints;
7263+ long flags;
7264+
7265+ XGetWMNormalHints(_RGFW->display, win->src.window, &hints, &flags);
7266+
7267+ hints.flags |= PAspect;
7268+
7269+ hints.min_aspect.x = hints.max_aspect.x = (i32)w;
7270+ hints.min_aspect.y = hints.max_aspect.y = (i32)h;
7271+
7272+ XSetWMNormalHints(_RGFW->display, win->src.window, &hints);
7273+ return;
7274+}
7275+
7276+void RGFW_FUNC(RGFW_window_setMinSize) (RGFW_window* win, i32 w, i32 h) {
7277+ RGFW_ASSERT(win != NULL);
7278+
7279+ long flags;
7280+ XSizeHints hints;
7281+ RGFW_MEMZERO(&hints, sizeof(XSizeHints));
7282+
7283+ XGetWMNormalHints(_RGFW->display, win->src.window, &hints, &flags);
7284+
7285+ hints.flags |= PMinSize;
7286+
7287+ hints.min_width = (i32)w;
7288+ hints.min_height = (i32)h;
7289+
7290+ XSetWMNormalHints(_RGFW->display, win->src.window, &hints);
7291+ return;
7292+}
7293+
7294+void RGFW_FUNC(RGFW_window_setMaxSize) (RGFW_window* win, i32 w, i32 h) {
7295+ RGFW_ASSERT(win != NULL);
7296+
7297+ long flags;
7298+ XSizeHints hints;
7299+ RGFW_MEMZERO(&hints, sizeof(XSizeHints));
7300+
7301+ XGetWMNormalHints(_RGFW->display, win->src.window, &hints, &flags);
7302+
7303+ hints.flags |= PMaxSize;
7304+
7305+ hints.max_width = (i32)w;
7306+ hints.max_height = (i32)h;
7307+
7308+ XSetWMNormalHints(_RGFW->display, win->src.window, &hints);
7309+ return;
7310+}
7311+
7312+void RGFW_toggleXMaximized(RGFW_window* win, RGFW_bool maximized);
7313+void RGFW_toggleXMaximized(RGFW_window* win, RGFW_bool maximized) {
7314+ RGFW_ASSERT(win != NULL);
7315+ RGFW_LOAD_ATOM(_NET_WM_STATE);
7316+ RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_VERT);
7317+ RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ);
7318+
7319+ XEvent xev = {0};
7320+ xev.type = ClientMessage;
7321+ xev.xclient.window = win->src.window;
7322+ xev.xclient.message_type = _NET_WM_STATE;
7323+ xev.xclient.format = 32;
7324+ xev.xclient.data.l[0] = maximized;
7325+ xev.xclient.data.l[1] = (long int)_NET_WM_STATE_MAXIMIZED_HORZ;
7326+ xev.xclient.data.l[2] = (long int)_NET_WM_STATE_MAXIMIZED_VERT;
7327+ xev.xclient.data.l[3] = 0;
7328+ xev.xclient.data.l[4] = 0;
7329+
7330+ XSendEvent(_RGFW->display, DefaultRootWindow(_RGFW->display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
7331+}
7332+
7333+void RGFW_FUNC(RGFW_window_maximize) (RGFW_window* win) {
7334+ win->internal.oldX = win->x;
7335+ win->internal.oldY = win->y;
7336+ win->internal.oldW = win->w;
7337+ win->internal.oldH = win->h;
7338+
7339+ RGFW_toggleXMaximized(win, 1);
7340+ RGFW_window_fetchSize(win, NULL, NULL);
7341+ return;
7342+}
7343+
7344+void RGFW_FUNC(RGFW_window_focus) (RGFW_window* win) {
7345+ RGFW_ASSERT(win);
7346+
7347+ XWindowAttributes attr;
7348+ XGetWindowAttributes(_RGFW->display, win->src.window, &attr);
7349+ if (attr.map_state != IsViewable) return;
7350+
7351+ XSetInputFocus(_RGFW->display, win->src.window, RevertToPointerRoot, CurrentTime);
7352+ XFlush(_RGFW->display);
7353+}
7354+
7355+void RGFW_FUNC(RGFW_window_raise) (RGFW_window* win) {
7356+ RGFW_ASSERT(win);
7357+ XMapRaised(_RGFW->display, win->src.window);
7358+ RGFW_window_setFullscreen(win, RGFW_window_isFullscreen(win));
7359+}
7360+
7361+void RGFW_window_setXAtom(RGFW_window* win, Atom netAtom, RGFW_bool fullscreen);
7362+void RGFW_window_setXAtom(RGFW_window* win, Atom netAtom, RGFW_bool fullscreen) {
7363+ RGFW_ASSERT(win != NULL);
7364+ RGFW_LOAD_ATOM(_NET_WM_STATE);
7365+
7366+ XEvent xev = {0};
7367+ xev.xclient.type = ClientMessage;
7368+ xev.xclient.serial = 0;
7369+ xev.xclient.send_event = True;
7370+ xev.xclient.message_type = _NET_WM_STATE;
7371+ xev.xclient.window = win->src.window;
7372+ xev.xclient.format = 32;
7373+ xev.xclient.data.l[0] = fullscreen;
7374+ xev.xclient.data.l[1] = (long int)netAtom;
7375+ xev.xclient.data.l[2] = 0;
7376+
7377+ XSendEvent(_RGFW->display, DefaultRootWindow(_RGFW->display), False, SubstructureNotifyMask | SubstructureRedirectMask, &xev);
7378+}
7379+
7380+void RGFW_FUNC(RGFW_window_setFullscreen)(RGFW_window* win, RGFW_bool fullscreen) {
7381+ RGFW_ASSERT(win != NULL);
7382+
7383+ if (fullscreen) {
7384+ win->internal.flags |= RGFW_windowFullscreen;
7385+ win->internal.oldX = win->x;
7386+ win->internal.oldY = win->y;
7387+ win->internal.oldW = win->w;
7388+ win->internal.oldH = win->h;
7389+ }
7390+ else win->internal.flags &= ~(u32)RGFW_windowFullscreen;
7391+
7392+ XRaiseWindow(_RGFW->display, win->src.window);
7393+
7394+ RGFW_LOAD_ATOM(_NET_WM_STATE_FULLSCREEN);
7395+ RGFW_window_setXAtom(win, _NET_WM_STATE_FULLSCREEN, fullscreen);
7396+
7397+ if (!(win->internal.flags & RGFW_windowTransparent)) {
7398+ const unsigned char value = fullscreen;
7399+ RGFW_LOAD_ATOM(_NET_WM_BYPASS_COMPOSITOR);
7400+ XChangeProperty(
7401+ _RGFW->display, win->src.window,
7402+ _NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32,
7403+ PropModeReplace, &value, 1);
7404+ }
7405+}
7406+
7407+void RGFW_FUNC(RGFW_window_setFloating)(RGFW_window* win, RGFW_bool floating) {
7408+ RGFW_ASSERT(win != NULL);
7409+ RGFW_LOAD_ATOM(_NET_WM_STATE_ABOVE);
7410+ RGFW_window_setXAtom(win, _NET_WM_STATE_ABOVE, floating);
7411+}
7412+
7413+void RGFW_FUNC(RGFW_window_setOpacity)(RGFW_window* win, u8 opacity) {
7414+ RGFW_ASSERT(win != NULL);
7415+ const u32 value = (u32) (0xffffffffu * (double) opacity);
7416+ RGFW_LOAD_ATOM(NET_WM_WINDOW_OPACITY);
7417+ XChangeProperty(_RGFW->display, win->src.window,
7418+ NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32, PropModeReplace, (unsigned char*) &value, 1);
7419+}
7420+
7421+void RGFW_FUNC(RGFW_window_minimize)(RGFW_window* win) {
7422+ RGFW_ASSERT(win != NULL);
7423+
7424+ if (RGFW_window_isMaximized(win)) return;
7425+
7426+ win->internal.oldX = win->x;
7427+ win->internal.oldY = win->y;
7428+ win->internal.oldW = win->w;
7429+ win->internal.oldH = win->h;
7430+ XIconifyWindow(_RGFW->display, win->src.window, DefaultScreen(_RGFW->display));
7431+ XFlush(_RGFW->display);
7432+}
7433+
7434+void RGFW_FUNC(RGFW_window_restore)(RGFW_window* win) {
7435+ RGFW_ASSERT(win != NULL);
7436+ RGFW_toggleXMaximized(win, RGFW_FALSE);
7437+ RGFW_window_move(win, win->internal.oldX, win->internal.oldY);
7438+ RGFW_window_resize(win, win->internal.oldW, win->internal.oldH);
7439+
7440+ RGFW_window_show(win);
7441+ XFlush(_RGFW->display);
7442+}
7443+
7444+RGFW_bool RGFW_FUNC(RGFW_window_isFloating)(RGFW_window* win) {
7445+ RGFW_LOAD_ATOM(_NET_WM_STATE);
7446+ RGFW_LOAD_ATOM(_NET_WM_STATE_ABOVE);
7447+
7448+ Atom actual_type;
7449+ int actual_format;
7450+ unsigned long nitems, bytes_after;
7451+ Atom* prop_return = NULL;
7452+
7453+ int status = XGetWindowProperty(_RGFW->display, win->src.window, _NET_WM_STATE, 0, (~0L), False, XA_ATOM,
7454+ &actual_type, &actual_format, &nitems, &bytes_after,
7455+ (unsigned char **)&prop_return);
7456+
7457+ if (status != Success || actual_type != XA_ATOM)
7458+ return RGFW_FALSE;
7459+
7460+ unsigned long i;
7461+ for (i = 0; i < nitems; i++)
7462+ if (prop_return[i] == _NET_WM_STATE_ABOVE) return RGFW_TRUE;
7463+
7464+ if (prop_return)
7465+ XFree(prop_return);
7466+ return RGFW_FALSE;
7467+}
7468+
7469+void RGFW_FUNC(RGFW_window_setName)(RGFW_window* win, const char* name) {
7470+ RGFW_ASSERT(win != NULL);
7471+ if (name == NULL) name = "\0";
7472+
7473+ Xutf8SetWMProperties(_RGFW->display, win->src.window, name, name, NULL, 0, NULL, NULL, NULL);
7474+ XStoreName(_RGFW->display, win->src.window, name);
7475+
7476+ RGFW_LOAD_ATOM(_NET_WM_NAME); RGFW_LOAD_ATOM(UTF8_STRING);
7477+
7478+ XChangeProperty(
7479+ _RGFW->display, win->src.window, _NET_WM_NAME, UTF8_STRING,
7480+ 8, PropModeReplace, (u8*)name, (int)RGFW_unix_stringlen(name)
7481+ );
7482+}
7483+
7484+#ifndef RGFW_NO_PASSTHROUGH
7485+void RGFW_FUNC(RGFW_window_setMousePassthrough) (RGFW_window* win, RGFW_bool passthrough) {
7486+ RGFW_ASSERT(win != NULL);
7487+ if (passthrough) {
7488+ Region region = XCreateRegion();
7489+ XShapeCombineRegion(_RGFW->display, win->src.window, ShapeInput, 0, 0, region, ShapeSet);
7490+ XDestroyRegion(region);
7491+
7492+ return;
7493+ }
7494+
7495+ XShapeCombineMask(_RGFW->display, win->src.window, ShapeInput, 0, 0, None, ShapeSet);
7496+}
7497+#endif /* RGFW_NO_PASSTHROUGH */
7498+
7499+RGFW_bool RGFW_FUNC(RGFW_window_setIconEx) (RGFW_window* win, u8* data_src, i32 w, i32 h, RGFW_format format, RGFW_icon type) {
7500+ Atom _NET_WM_ICON = XInternAtom(_RGFW->display, "_NET_WM_ICON", False);
7501+ RGFW_ASSERT(win != NULL);
7502+ if (data_src == NULL) {
7503+ RGFW_bool res = (RGFW_bool)XChangeProperty(
7504+ _RGFW->display, win->src.window, _NET_WM_ICON, XA_CARDINAL, 32,
7505+ PropModeReplace, (u8*)NULL, 0
7506+ );
7507+ return res;
7508+ }
7509+
7510+ i32 count = (i32)(2 + (w * h));
7511+
7512+ unsigned long* data = (unsigned long*) RGFW_ALLOC((u32)count * sizeof(unsigned long));
7513+ RGFW_ASSERT(data != NULL);
7514+
7515+ RGFW_MEMZERO(data, (u32)count * sizeof(unsigned long));
7516+ data[0] = (unsigned long)w;
7517+ data[1] = (unsigned long)h;
7518+
7519+ RGFW_copyImageData64((u8*)&data[2], w, h, RGFW_formatBGRA8, data_src, format, RGFW_TRUE, NULL);
7520+ RGFW_bool res = RGFW_TRUE;
7521+ if (type & RGFW_iconTaskbar) {
7522+ res = (RGFW_bool)XChangeProperty(
7523+ _RGFW->display, win->src.window, _NET_WM_ICON, XA_CARDINAL, 32,
7524+ PropModeReplace, (u8*)data, count
7525+ );
7526+ }
7527+
7528+ RGFW_copyImageData64((u8*)&data[2], w, h, RGFW_formatBGRA8, data_src, format, RGFW_FALSE, NULL);
7529+
7530+ if (type & RGFW_iconWindow) {
7531+ XWMHints wm_hints;
7532+ wm_hints.flags = IconPixmapHint;
7533+
7534+ i32 depth = DefaultDepth(_RGFW->display, DefaultScreen(_RGFW->display));
7535+ XImage *image = XCreateImage(_RGFW->display, DefaultVisual(_RGFW->display, DefaultScreen(_RGFW->display)),
7536+ (u32)depth, ZPixmap, 0, (char *)&data[2], (u32)w, (u32)h, 32, 0);
7537+
7538+ wm_hints.icon_pixmap = XCreatePixmap(_RGFW->display, win->src.window, (u32)w, (u32)h, (u32)depth);
7539+ XPutImage(_RGFW->display, wm_hints.icon_pixmap, DefaultGC(_RGFW->display, DefaultScreen(_RGFW->display)), image, 0, 0, 0, 0, (u32)w, (u32)h);
7540+ image->data = NULL;
7541+ XDestroyImage(image);
7542+
7543+ XSetWMHints(_RGFW->display, win->src.window, &wm_hints);
7544+ }
7545+
7546+ RGFW_FREE(data);
7547+ XFlush(_RGFW->display);
7548+ return RGFW_BOOL(res);
7549+}
7550+
7551+RGFW_mouse* RGFW_FUNC(RGFW_createMouseStandard) (RGFW_mouseIcon mouse) {
7552+ u32 mouseIcon = 0;
7553+
7554+ switch (mouse) {
7555+ case RGFW_mouseNormal: mouseIcon = XC_left_ptr; break;
7556+ case RGFW_mouseArrow: mouseIcon = XC_left_ptr; break;
7557+ case RGFW_mouseIbeam: mouseIcon = XC_xterm; break;
7558+ case RGFW_mouseWait: mouseIcon = XC_watch; break;
7559+ case RGFW_mouseCrosshair: mouseIcon = XC_tcross; break;
7560+ case RGFW_mouseProgress: mouseIcon = XC_watch; break;
7561+ case RGFW_mouseResizeNWSE: mouseIcon = XC_top_left_corner; break;
7562+ case RGFW_mouseResizeNESW: mouseIcon = XC_top_right_corner; break;
7563+ case RGFW_mouseResizeEW: mouseIcon = XC_sb_h_double_arrow; break;
7564+ case RGFW_mouseResizeNS: mouseIcon = XC_sb_v_double_arrow; break;
7565+ case RGFW_mouseResizeNW: mouseIcon = XC_top_left_corner; break;
7566+ case RGFW_mouseResizeN: mouseIcon = XC_top_side; break;
7567+ case RGFW_mouseResizeNE: mouseIcon = XC_top_right_corner; break;
7568+ case RGFW_mouseResizeE: mouseIcon = XC_right_side; break;
7569+ case RGFW_mouseResizeSE: mouseIcon = XC_bottom_right_corner; break;
7570+ case RGFW_mouseResizeS: mouseIcon = XC_bottom_side; break;
7571+ case RGFW_mouseResizeSW: mouseIcon = XC_bottom_left_corner; break;
7572+ case RGFW_mouseResizeW: mouseIcon = XC_left_side; break;
7573+ case RGFW_mouseResizeAll: mouseIcon = XC_fleur; break;
7574+ case RGFW_mouseNotAllowed: mouseIcon = XC_pirate; break;
7575+ case RGFW_mousePointingHand: mouseIcon = XC_hand2; break;
7576+ default: return NULL;
7577+ }
7578+
7579+ Cursor cursor = XCreateFontCursor(_RGFW->display, mouseIcon);
7580+ return (RGFW_mouse*)cursor;
7581+}
7582+
7583+RGFW_mouse* RGFW_FUNC(RGFW_createMouse) (u8* data, i32 w, i32 h, RGFW_format format) {
7584+ RGFW_ASSERT(data);
7585+#ifndef RGFW_NO_X11_CURSOR
7586+ RGFW_init();
7587+ XcursorImage* native = XcursorImageCreate((i32)w, (i32)h);
7588+ native->xhot = 0;
7589+ native->yhot = 0;
7590+ RGFW_MEMZERO(native->pixels, (u32)(w * h * 4));
7591+ RGFW_copyImageData((u8*)native->pixels, w, h, RGFW_formatBGRA8, data, format, NULL);
7592+
7593+ Cursor cursor = XcursorImageLoadCursor(_RGFW->display, native);
7594+ XcursorImageDestroy(native);
7595+
7596+ return (void*)cursor;
7597+#else
7598+ RGFW_UNUSED(data); RGFW_UNUSED(w); RGFW_UNUSED(h); RGFW_UNUSED(format);
7599+ return NULL;
7600+#endif
7601+}
7602+
7603+RGFW_bool RGFW_FUNC(RGFW_window_setMousePlatform)(RGFW_window* win, RGFW_mouse* mouse) {
7604+ RGFW_ASSERT(win && mouse);
7605+ XDefineCursor(_RGFW->display, win->src.window, (Cursor)mouse);
7606+ return RGFW_TRUE;
7607+}
7608+
7609+void RGFW_FUNC(RGFW_freeMouse)(RGFW_mouse* mouse) {
7610+ RGFW_ASSERT(mouse);
7611+ XFreeCursor(_RGFW->display, (Cursor)mouse);
7612+}
7613+
7614+void RGFW_FUNC(RGFW_window_moveMouse)(RGFW_window* win, i32 x, i32 y) {
7615+ RGFW_ASSERT(win != NULL);
7616+
7617+ XEvent event;
7618+ XQueryPointer(_RGFW->display, DefaultRootWindow(_RGFW->display),
7619+ &event.xbutton.root, &event.xbutton.window,
7620+ &event.xbutton.x_root, &event.xbutton.y_root,
7621+ &event.xbutton.x, &event.xbutton.y,
7622+ &event.xbutton.state);
7623+
7624+ win->internal.lastMouseX = x - win->x;
7625+ win->internal.lastMouseY = y - win->y;
7626+ if (event.xbutton.x == x && event.xbutton.y == y)
7627+ return;
7628+
7629+ XWarpPointer(_RGFW->display, None, win->src.window, 0, 0, 0, 0, (int) x - win->x, (int) y - win->y);
7630+}
7631+
7632+void RGFW_FUNC(RGFW_window_hide)(RGFW_window* win) {
7633+ win->internal.flags |= (u32)RGFW_windowHide;
7634+ XUnmapWindow(_RGFW->display, win->src.window);
7635+
7636+ XFlush(_RGFW->display);
7637+}
7638+
7639+void RGFW_FUNC(RGFW_window_show) (RGFW_window* win) {
7640+ win->internal.flags &= ~(u32)RGFW_windowHide;
7641+ if (win->internal.flags & RGFW_windowFocusOnShow) RGFW_window_focus(win);
7642+
7643+ if (RGFW_window_isHidden(win) == RGFW_FALSE) {
7644+ return;
7645+ }
7646+
7647+ XMapWindow(_RGFW->display, win->src.window);
7648+ RGFW_window_move(win, win->x, win->y);
7649+
7650+ RGFW_waitForShowEvent_X11(win);
7651+ RGFW_window_setFullscreen(win, RGFW_window_isFullscreen(win));
7652+ return;
7653+}
7654+
7655+void RGFW_FUNC(RGFW_window_flash) (RGFW_window* win, RGFW_flashRequest request) {
7656+ if (RGFW_window_isInFocus(win) && request) {
7657+ return;
7658+ }
7659+
7660+ XWMHints* wmhints = XGetWMHints(_RGFW->display, win->src.window);
7661+ if (wmhints == NULL) return;
7662+
7663+ if (request) {
7664+ wmhints->flags |= XUrgencyHint;
7665+ if (request == RGFW_flashBriefly)
7666+ win->src.flashEnd = RGFW_linux_getTimeNS() + (u64)1e+9;
7667+ if (request == RGFW_flashUntilFocused)
7668+ win->src.flashEnd = (u64)-1;
7669+ } else {
7670+ win->src.flashEnd = 0;
7671+ wmhints->flags &= ~XUrgencyHint;
7672+ }
7673+
7674+ XSetWMHints(_RGFW->display, win->src.window, wmhints);
7675+ XFree(wmhints);
7676+}
7677+
7678+RGFW_ssize_t RGFW_FUNC(RGFW_readClipboardPtr)(char* str, size_t strCapacity) {
7679+ RGFW_init();
7680+ RGFW_LOAD_ATOM(XSEL_DATA); RGFW_LOAD_ATOM(UTF8_STRING); RGFW_LOAD_ATOM(CLIPBOARD);
7681+ if (XGetSelectionOwner(_RGFW->display, CLIPBOARD) == _RGFW->helperWindow) {
7682+ if (str != NULL)
7683+ RGFW_STRNCPY(str, _RGFW->clipboard, _RGFW->clipboard_len - 1);
7684+ _RGFW->clipboard[_RGFW->clipboard_len - 1] = '\0';
7685+ return (RGFW_ssize_t)_RGFW->clipboard_len - 1;
7686+ }
7687+
7688+ XEvent event;
7689+ int format;
7690+ unsigned long N, sizeN;
7691+ char* data;
7692+ Atom target;
7693+
7694+ XConvertSelection(_RGFW->display, CLIPBOARD, UTF8_STRING, XSEL_DATA, _RGFW->helperWindow, CurrentTime);
7695+ XSync(_RGFW->display, 0);
7696+ while (1) {
7697+ XNextEvent(_RGFW->display, &event);
7698+ if (event.type != SelectionNotify) continue;
7699+
7700+ if (event.xselection.selection != CLIPBOARD || event.xselection.property == 0)
7701+ return -1;
7702+ break;
7703+ }
7704+
7705+ XGetWindowProperty(event.xselection.display, event.xselection.requestor,
7706+ event.xselection.property, 0L, (~0L), 0, AnyPropertyType, &target,
7707+ &format, &sizeN, &N, (u8**) &data);
7708+
7709+ RGFW_ssize_t size;
7710+ if (sizeN > strCapacity && str != NULL)
7711+ size = -1;
7712+
7713+ if ((target == UTF8_STRING || target == XA_STRING) && str != NULL) {
7714+ RGFW_MEMCPY(str, data, sizeN);
7715+ str[sizeN] = '\0';
7716+ XFree(data);
7717+ } else if (str != NULL) size = -1;
7718+
7719+ XDeleteProperty(event.xselection.display, event.xselection.requestor, event.xselection.property);
7720+ size = (RGFW_ssize_t)sizeN;
7721+
7722+ return size;
7723+}
7724+
7725+i32 RGFW_XHandleClipboardSelectionHelper(void) {
7726+ RGFW_LOAD_ATOM(SAVE_TARGETS);
7727+
7728+ XEvent event;
7729+ XPending(_RGFW->display);
7730+
7731+ if (QLength(_RGFW->display) || XEventsQueued(_RGFW->display, QueuedAlready) + XEventsQueued(_RGFW->display, QueuedAfterReading))
7732+ XNextEvent(_RGFW->display, &event);
7733+ else
7734+ return 0;
7735+
7736+ switch (event.type) {
7737+ case SelectionRequest:
7738+ RGFW_XHandleClipboardSelection(&event);
7739+ return 0;
7740+ case SelectionNotify:
7741+ if (event.xselection.target == SAVE_TARGETS)
7742+ return 0;
7743+ break;
7744+ default: break;
7745+ }
7746+
7747+ return 0;
7748+}
7749+
7750+void RGFW_FUNC(RGFW_writeClipboard)(const char* text, u32 textLen) {
7751+ RGFW_LOAD_ATOM(SAVE_TARGETS); RGFW_LOAD_ATOM(CLIPBOARD);
7752+ RGFW_init();
7753+
7754+ /* request ownership of the clipboard section and request to convert it, this means its our job to convert it */
7755+ XSetSelectionOwner(_RGFW->display, CLIPBOARD, _RGFW->helperWindow, CurrentTime);
7756+ if (XGetSelectionOwner(_RGFW->display, CLIPBOARD) != _RGFW->helperWindow) {
7757+ RGFW_debugCallback(RGFW_typeError, RGFW_errClipboard, "X11 failed to become owner of clipboard selection");
7758+ return;
7759+ }
7760+
7761+ if (_RGFW->clipboard)
7762+ RGFW_FREE(_RGFW->clipboard);
7763+
7764+ _RGFW->clipboard = (char*)RGFW_ALLOC(textLen);
7765+ RGFW_ASSERT(_RGFW->clipboard != NULL);
7766+
7767+ RGFW_STRNCPY(_RGFW->clipboard, text, textLen - 1);
7768+ _RGFW->clipboard[textLen - 1] = '\0';
7769+ _RGFW->clipboard_len = textLen;
7770+ return;
7771+}
7772+
7773+RGFW_bool RGFW_FUNC(RGFW_window_isHidden)(RGFW_window* win) {
7774+ RGFW_ASSERT(win != NULL);
7775+ XWindowAttributes windowAttributes;
7776+ XGetWindowAttributes(_RGFW->display, win->src.window, &windowAttributes);
7777+
7778+ return (windowAttributes.map_state != IsViewable);
7779+}
7780+
7781+RGFW_bool RGFW_FUNC(RGFW_window_isMinimized)(RGFW_window* win) {
7782+ RGFW_ASSERT(win != NULL);
7783+ RGFW_LOAD_ATOM(WM_STATE);
7784+
7785+ Atom actual_type;
7786+ i32 actual_format;
7787+ unsigned long nitems, bytes_after;
7788+ unsigned char* prop_data;
7789+
7790+ i32 status = XGetWindowProperty(_RGFW->display, win->src.window, WM_STATE, 0, 2, False,
7791+ AnyPropertyType, &actual_type, &actual_format,
7792+ &nitems, &bytes_after, &prop_data);
7793+
7794+ if (status == Success && nitems >= 1 && prop_data == (unsigned char*)IconicState) {
7795+ XFree(prop_data);
7796+ return RGFW_TRUE;
7797+ }
7798+
7799+ if (prop_data != NULL)
7800+ XFree(prop_data);
7801+
7802+ XWindowAttributes windowAttributes;
7803+ XGetWindowAttributes(_RGFW->display, win->src.window, &windowAttributes);
7804+ return windowAttributes.map_state != IsViewable;
7805+}
7806+
7807+RGFW_bool RGFW_FUNC(RGFW_window_isMaximized)(RGFW_window* win) {
7808+ RGFW_ASSERT(win != NULL);
7809+ RGFW_LOAD_ATOM(_NET_WM_STATE);
7810+ RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_VERT);
7811+ RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ);
7812+
7813+ Atom actual_type;
7814+ i32 actual_format;
7815+ unsigned long nitems, bytes_after;
7816+ unsigned char* prop_data;
7817+
7818+ i32 status = XGetWindowProperty(_RGFW->display, win->src.window, _NET_WM_STATE, 0, 1024, False,
7819+ XA_ATOM, &actual_type, &actual_format,
7820+ &nitems, &bytes_after, &prop_data);
7821+
7822+ if (status != Success) {
7823+ if (prop_data != NULL)
7824+ XFree(prop_data);
7825+
7826+ return RGFW_FALSE;
7827+ }
7828+
7829+ u64 i;
7830+ for (i = 0; i < nitems; i++) {
7831+ if (prop_data[i] == _NET_WM_STATE_MAXIMIZED_VERT ||
7832+ prop_data[i] == _NET_WM_STATE_MAXIMIZED_HORZ) {
7833+ XFree(prop_data);
7834+ return RGFW_TRUE;
7835+ }
7836+ }
7837+
7838+ if (prop_data != NULL)
7839+ XFree(prop_data);
7840+
7841+ return RGFW_FALSE;
7842+}
7843+
7844+RGFWDEF void RGFW_XGetSystemContentDPI(float* dpi);
7845+void RGFW_XGetSystemContentDPI(float* dpi) {
7846+ if (dpi == NULL) return;
7847+ float dpiOutput = 96.0f;
7848+
7849+ char* rms = XResourceManagerString(_RGFW->display);
7850+ if (rms == NULL) return;
7851+
7852+ XrmDatabase db = XrmGetStringDatabase(rms);
7853+ if (db == NULL) return;
7854+
7855+ XrmValue value;
7856+ char* type = NULL;
7857+
7858+ if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value) && type && RGFW_STRNCMP(type, "String", 7) == 0)
7859+ dpiOutput = (float)RGFW_ATOF(value.addr);
7860+ XrmDestroyDatabase(db);
7861+
7862+ if (dpi) *dpi = dpiOutput;
7863+}
7864+
7865+RGFWDEF XRRModeInfo* RGFW_XGetMode(XRRCrtcInfo* ci, XRRScreenResources* res, RRMode mode, RGFW_monitorMode* foundMode);
7866+XRRModeInfo* RGFW_XGetMode(XRRCrtcInfo* ci, XRRScreenResources* res, RRMode mode, RGFW_monitorMode* foundMode) {
7867+ XRRModeInfo* mi = None;
7868+ for (i32 j = 0; j < res->nmode; j++) {
7869+ if (res->modes[j].id == mode)
7870+ mi = &res->modes[j];
7871+ }
7872+
7873+ if (mi == None) return NULL;
7874+
7875+ if ((mi->modeFlags & RR_Interlace) != 0) return NULL;
7876+
7877+ foundMode->w = (i32)mi->width;
7878+ foundMode->h = (i32)mi->height;
7879+ if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270) {
7880+ foundMode->w = (i32)mi->height;
7881+ foundMode->h = (i32)mi->width;
7882+ } else {
7883+ foundMode->w = (i32)mi->width;
7884+ foundMode->h = (i32)mi->height;
7885+ }
7886+
7887+ RGFW_splitBPP((u32)DefaultDepth(_RGFW->display, DefaultScreen(_RGFW->display)), foundMode);
7888+
7889+ foundMode->src = (void*)mode;
7890+
7891+ foundMode->refreshRate = 0;
7892+ if (mi->hTotal == 0 || mi->vTotal == 0)
7893+ return mi;
7894+
7895+ u32 vTotal = mi->vTotal;
7896+
7897+ if (mi->modeFlags & RR_DoubleScan) {
7898+ vTotal *= 2;
7899+ }
7900+
7901+ if (mi->modeFlags & RR_Interlace) {
7902+ vTotal /= 2;
7903+ }
7904+
7905+ i32 numerator = (i32)mi->dotClock;
7906+ i32 denominator = (i32)(mi->hTotal * vTotal);
7907+ float refreshRate = 0;
7908+
7909+ if (denominator <= 0) {
7910+ denominator = 1;
7911+ }
7912+
7913+ refreshRate = ((float)numerator / (float)denominator);
7914+
7915+ foundMode->refreshRate = RGFW_ROUNDF((refreshRate * 100)) / 100.0f;
7916+ return mi;
7917+}
7918+
7919+void RGFW_FUNC(RGFW_pollMonitors) (void) {
7920+ RGFW_init();
7921+
7922+ Window root = XDefaultRootWindow(_RGFW->display);
7923+ XRRScreenResources* res = XRRGetScreenResourcesCurrent(_RGFW->display, root);
7924+ if (res == 0) {
7925+ return;
7926+ }
7927+
7928+ RROutput primary = XRRGetOutputPrimary(_RGFW->display, root);
7929+
7930+ for (RGFW_monitorNode* node = _RGFW->monitors.list.head; node; node = node->next) {
7931+ node->disconnected = RGFW_TRUE;
7932+ }
7933+
7934+ for (i32 i = 0; i < res->noutput; i++) {
7935+ RGFW_monitorNode* node = NULL;
7936+ for (node = _RGFW->monitors.list.head; node; node = node->next) {
7937+ if (node->rrOutput == res->outputs[i]) {
7938+ break;
7939+ }
7940+ }
7941+
7942+ if (node) {
7943+ node->disconnected = RGFW_FALSE;
7944+ if (node->rrOutput == primary) {
7945+ _RGFW->monitors.primary = node;
7946+ }
7947+ continue;
7948+ }
7949+
7950+ RGFW_monitor monitor;
7951+
7952+ XRROutputInfo* info = XRRGetOutputInfo(_RGFW->display, res, res->outputs[i]);
7953+ if (info == NULL) continue;
7954+ if (info->connection != RR_Connected || info->crtc == None) {
7955+ XRRFreeOutputInfo(info);
7956+ continue;
7957+ }
7958+
7959+ XRRCrtcInfo* ci = XRRGetCrtcInfo(_RGFW->display, res, info->crtc);
7960+
7961+ if (ci == NULL) {
7962+ continue;
7963+ }
7964+
7965+ float physW = (float)info->mm_width / 25.4f;
7966+ float physH = (float)info->mm_height / 25.4f;
7967+
7968+ RGFW_STRNCPY(monitor.name, info->name, sizeof(monitor.name) - 1);
7969+ monitor.name[sizeof(monitor.name) - 1] = '\0';
7970+
7971+ if (physW > 0.0f && physH > 0.0f) {
7972+ monitor.physW = physW;
7973+ monitor.physH = physH;
7974+ } else {
7975+ monitor.physW = (float) ((float)ci->width / 96.f);
7976+ monitor.physH = (float) ((float)ci->height / 96.f);
7977+ }
7978+
7979+ monitor.x = ci->x;
7980+ monitor.y = ci->y;
7981+
7982+ float dpi = 96.0f;
7983+ RGFW_XGetSystemContentDPI(&dpi);
7984+
7985+ monitor.scaleX = dpi / 96.0f;
7986+ monitor.scaleY = dpi / 96.0f;
7987+
7988+ monitor.pixelRatio = dpi >= 192.0f ? 2.0f : 1.0f;
7989+
7990+ XRRModeInfo* mi = RGFW_XGetMode(ci, res, ci->mode, &monitor.mode);
7991+
7992+ if (mi == NULL) {
7993+ break;
7994+ }
7995+
7996+ XRRFreeCrtcInfo(ci);
7997+
7998+ node = RGFW_monitors_add(&monitor);
7999+ if (node == NULL) break;
8000+
8001+ node->rrOutput = res->outputs[i];
8002+ node->crtc = info->crtc;
8003+
8004+ if (node->rrOutput == primary) {
8005+ _RGFW->monitors.primary = node;
8006+ }
8007+
8008+ XRRFreeOutputInfo(info);
8009+ info = NULL;
8010+
8011+ RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_TRUE);
8012+ }
8013+
8014+ XRRFreeScreenResources(res);
8015+
8016+ RGFW_monitors_refresh();
8017+}
8018+
8019+RGFW_bool RGFW_FUNC(RGFW_monitor_getWorkarea) (RGFW_monitor* monitor, i32* x, i32* y, i32* width, i32* height) {
8020+ RGFW_LOAD_ATOM(_NET_WORKAREA);
8021+ RGFW_LOAD_ATOM(_NET_CURRENT_DESKTOP);
8022+
8023+ Window root = DefaultRootWindow(_RGFW->display);
8024+
8025+ i32 areaX = monitor->x;
8026+ i32 areaY = monitor->y;
8027+ i32 areaW = monitor->mode.w;
8028+ i32 areaH = monitor->mode.h;
8029+
8030+ if (_NET_WORKAREA && _NET_CURRENT_DESKTOP) {
8031+ Atom* extents = NULL;
8032+ Atom* desktop = NULL;
8033+
8034+ Atom actualType = 0;
8035+ int actualFormat = 0;
8036+ unsigned long extentCount = 0, bytesAfter = 0;
8037+ XGetWindowProperty(_RGFW->display, root, _NET_WORKAREA, 0, LONG_MAX, False, XA_CARDINAL, &actualType, &actualFormat, &extentCount, &bytesAfter, (u8**) &extents);
8038+
8039+ unsigned long count;
8040+ XGetWindowProperty(_RGFW->display, root, _NET_CURRENT_DESKTOP, 0, LONG_MAX, False, XA_CARDINAL, &actualType, &actualFormat, &count, &bytesAfter, (u8**) &desktop);
8041+
8042+ if (count) {
8043+ if (extentCount >= 4 && *desktop < extentCount / 4) {
8044+ i32 globalX = (i32)extents[*desktop * 4 + 0];
8045+ i32 globalY = (i32)extents[*desktop * 4 + 1];
8046+ i32 globalW = (i32)extents[*desktop * 4 + 2];
8047+ i32 globalH = (i32)extents[*desktop * 4 + 3];
8048+
8049+ if (areaX < globalX) {
8050+ areaW -= globalX - areaX;
8051+ areaX = globalX;
8052+ }
8053+
8054+ if (areaY < globalY) {
8055+ areaH -= globalY - areaY;
8056+ areaY = globalY;
8057+ }
8058+
8059+ if (areaX + areaW > globalX + globalW)
8060+ areaW = globalX - areaX + globalW;
8061+ if (areaY + areaH > globalY + globalH)
8062+ areaH = globalY - areaY + globalH;
8063+ }
8064+ }
8065+
8066+ if (extents)
8067+ XFree(extents);
8068+ if (desktop)
8069+ XFree(desktop);
8070+ }
8071+
8072+ if (x) *x = areaX;
8073+ if (y) *y = areaY;
8074+ if (width) *width = areaW;
8075+ if (height) *height = areaH;
8076+
8077+ return RGFW_TRUE;
8078+}
8079+
8080+size_t RGFW_FUNC(RGFW_monitor_getModesPtr) (RGFW_monitor* monitor, RGFW_monitorMode** modes) {
8081+ size_t count = 0;
8082+
8083+ XRRScreenResources* res = XRRGetScreenResourcesCurrent(_RGFW->display, DefaultRootWindow(_RGFW->display));
8084+ if (res == NULL) return 0;
8085+
8086+ XRRCrtcInfo* ci = XRRGetCrtcInfo(_RGFW->display, res, monitor->node->crtc);
8087+ XRROutputInfo* oi = XRRGetOutputInfo(_RGFW->display, res, monitor->node->rrOutput);
8088+ count = (size_t)oi->nmode;
8089+
8090+ int i;
8091+ for (i = 0; modes && i < oi->nmode; i++) {
8092+ XRRModeInfo* mi = RGFW_XGetMode(ci, res, oi->modes[i], &((*modes)[i]));
8093+ RGFW_UNUSED(mi);
8094+ }
8095+
8096+ XRRFreeOutputInfo(oi);
8097+ XRRFreeCrtcInfo(ci);
8098+ XRRFreeScreenResources(res);
8099+
8100+ return count;
8101+}
8102+
8103+size_t RGFW_FUNC(RGFW_monitor_getGammaRampPtr) (RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
8104+ RGFW_UNUSED(monitor); RGFW_UNUSED(ramp);
8105+ size_t size = (size_t)XRRGetCrtcGammaSize(_RGFW->display, monitor->node->crtc);
8106+ XRRCrtcGamma* gamma = XRRGetCrtcGamma(_RGFW->display, monitor->node->crtc);
8107+
8108+ if (ramp) {
8109+ RGFW_MEMCPY(ramp->red, gamma->red, size * sizeof(unsigned short));
8110+ RGFW_MEMCPY(ramp->green, gamma->green, size * sizeof(unsigned short));
8111+ RGFW_MEMCPY(ramp->blue, gamma->blue, size * sizeof(unsigned short));
8112+ }
8113+
8114+ XRRFreeGamma(gamma);
8115+ return size;
8116+}
8117+
8118+RGFW_bool RGFW_FUNC(RGFW_monitor_setGammaRamp) (RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
8119+ RGFW_UNUSED(monitor); RGFW_UNUSED(ramp);
8120+
8121+ size_t size = (size_t)XRRGetCrtcGammaSize(_RGFW->display, monitor->node->crtc);
8122+ if (size != ramp->count) {
8123+ RGFW_debugCallback(RGFW_typeError, RGFW_errX11, "X11: Gamma ramp size must match current ramp size");
8124+ return RGFW_FALSE;
8125+ }
8126+
8127+ XRRCrtcGamma* gamma = XRRAllocGamma((int)ramp->count);
8128+
8129+ memcpy(gamma->red, ramp->red, ramp->count * sizeof(unsigned short));
8130+ memcpy(gamma->green, ramp->green, ramp->count * sizeof(unsigned short));
8131+ memcpy(gamma->blue, ramp->blue, ramp->count * sizeof(unsigned short));
8132+
8133+ XRRSetCrtcGamma(_RGFW->display, monitor->node->crtc, gamma);
8134+ XRRFreeGamma(gamma);
8135+
8136+ return RGFW_TRUE;
8137+}
8138+
8139+RGFW_bool RGFW_FUNC(RGFW_monitor_setMode)(RGFW_monitor* mon, RGFW_monitorMode* mode) {
8140+ RGFW_bool out = RGFW_FALSE;
8141+
8142+ XRRScreenResources* res = XRRGetScreenResourcesCurrent(_RGFW->display, DefaultRootWindow(_RGFW->display));
8143+ XRRCrtcInfo* ci = XRRGetCrtcInfo(_RGFW->display, res, mon->node->crtc);
8144+
8145+ if (XRRSetCrtcConfig(_RGFW->display, res, mon->node->crtc, CurrentTime, ci->x, ci->y, (RRMode)mode->src, ci->rotation, ci->outputs, ci->noutput) == True) {
8146+ out = RGFW_TRUE;
8147+ }
8148+
8149+ XRRFreeCrtcInfo(ci);
8150+ XRRFreeScreenResources(res);
8151+ return out;
8152+}
8153+
8154+RGFW_bool RGFW_FUNC(RGFW_monitor_requestMode)(RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request) {
8155+ RGFW_init();
8156+
8157+ RGFW_bool output = RGFW_FALSE;
8158+
8159+ XRRScreenResources* res = XRRGetScreenResourcesCurrent(_RGFW->display, DefaultRootWindow(_RGFW->display));
8160+ if (res == NULL) return RGFW_FALSE;
8161+
8162+ XRRCrtcInfo* ci = XRRGetCrtcInfo(_RGFW->display, res, mon->node->crtc);
8163+ XRROutputInfo* oi = XRRGetOutputInfo(_RGFW->display, res, mon->node->rrOutput);
8164+
8165+ RRMode native = None;
8166+
8167+ int i;
8168+ for (i = 0; i < oi->nmode; i++) {
8169+ RGFW_monitorMode foundMode;
8170+ XRRModeInfo* mi = RGFW_XGetMode(ci, res, oi->modes[i], &foundMode);
8171+ if (mi == NULL) {
8172+ continue;
8173+ }
8174+
8175+ if (RGFW_monitorModeCompare(mode, &foundMode, request)) {
8176+ native = mi->id;
8177+ output = RGFW_TRUE;
8178+ mon->mode = foundMode;
8179+ break;
8180+ }
8181+ }
8182+
8183+ if (native) {
8184+ XRRSetCrtcConfig(_RGFW->display, res, mon->node->crtc, CurrentTime, ci->x, ci->y, native, ci->rotation, ci->outputs, ci->noutput);
8185+ }
8186+
8187+ XRRFreeOutputInfo(oi);
8188+ XRRFreeCrtcInfo(ci);
8189+ XRRFreeScreenResources(res);
8190+ return output;
8191+}
8192+
8193+RGFW_monitor* RGFW_FUNC(RGFW_window_getMonitor) (RGFW_window* win) {
8194+ RGFW_ASSERT(win != NULL);
8195+
8196+ XWindowAttributes attrs;
8197+ if (!XGetWindowAttributes(_RGFW->display, win->src.window, &attrs)) {
8198+ return NULL;
8199+ }
8200+
8201+ for (RGFW_monitorNode* node = _RGFW->monitors.list.head; node; node = node->next) {
8202+ if ((attrs.x < node->mon.x + node->mon.mode.w) && (attrs.x + attrs.width > node->mon.x) && (attrs.y < node->mon.y + node->mon.mode.h) && (attrs.y + attrs.height > node->mon.y))
8203+ return &node->mon;
8204+ }
8205+
8206+
8207+ return &_RGFW->monitors.list.head->mon;
8208+}
8209+
8210+#ifdef RGFW_OPENGL
8211+RGFW_bool RGFW_FUNC(RGFW_window_createContextPtr_OpenGL) (RGFW_window* win, RGFW_glContext* context, RGFW_glHints* hints) {
8212+ /* for checking extensions later */
8213+ const char sRGBARBstr[] = "GLX_ARB_framebuffer_sRGB";
8214+ const char sRGBEXTstr[] = "GLX_EXT_framebuffer_sRGB";
8215+ const char noErorrStr[] = "GLX_ARB_create_context_no_error";
8216+ const char flushStr[] = "GLX_ARB_context_flush_control";
8217+ const char robustStr[] = "GLX_ARB_create_context_robustness";
8218+
8219+ /* basic RGFW int */
8220+ win->src.ctx.native = context;
8221+ win->src.gfxType = RGFW_gfxNativeOpenGL;
8222+
8223+ /* This is required so that way the user can create their own OpenGL context after RGFW_createWindow is used */
8224+ RGFW_bool showWindow = RGFW_FALSE;
8225+ if (win->src.window) {
8226+ showWindow = (RGFW_window_isMinimized(win) == RGFW_FALSE);
8227+ RGFW_window_closePlatform(win);
8228+ }
8229+
8230+ RGFW_bool transparent = (win->internal.flags & RGFW_windowTransparent);
8231+
8232+ /* start by creating a GLX config / X11 Viusal */
8233+ XVisualInfo visual;
8234+ GLXFBConfig bestFbc;
8235+
8236+ i32 visual_attribs[40];
8237+ RGFW_attribStack stack;
8238+ RGFW_attribStack_init(&stack, visual_attribs, 40);
8239+ RGFW_attribStack_pushAttribs(&stack, GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR);
8240+ RGFW_attribStack_pushAttribs(&stack, GLX_X_RENDERABLE, 1);
8241+ RGFW_attribStack_pushAttribs(&stack, GLX_RENDER_TYPE, GLX_RGBA_BIT);
8242+ RGFW_attribStack_pushAttribs(&stack, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT);
8243+ RGFW_attribStack_pushAttribs(&stack, GLX_DOUBLEBUFFER, 1);
8244+ RGFW_attribStack_pushAttribs(&stack, GLX_ALPHA_SIZE, hints->alpha);
8245+ RGFW_attribStack_pushAttribs(&stack, GLX_DEPTH_SIZE, hints->depth);
8246+ RGFW_attribStack_pushAttribs(&stack, GLX_STENCIL_SIZE, hints->stencil);
8247+ RGFW_attribStack_pushAttribs(&stack, GLX_STEREO, hints->stereo);
8248+ RGFW_attribStack_pushAttribs(&stack, GLX_AUX_BUFFERS, hints->auxBuffers);
8249+ RGFW_attribStack_pushAttribs(&stack, GLX_RED_SIZE, hints->red);
8250+ RGFW_attribStack_pushAttribs(&stack, GLX_GREEN_SIZE, hints->green);
8251+ RGFW_attribStack_pushAttribs(&stack, GLX_BLUE_SIZE, hints->blue);
8252+ RGFW_attribStack_pushAttribs(&stack, GLX_ACCUM_RED_SIZE, hints->accumRed);
8253+ RGFW_attribStack_pushAttribs(&stack, GLX_ACCUM_GREEN_SIZE, hints->accumGreen);
8254+ RGFW_attribStack_pushAttribs(&stack, GLX_ACCUM_BLUE_SIZE, hints->accumBlue);
8255+ RGFW_attribStack_pushAttribs(&stack, GLX_ACCUM_ALPHA_SIZE, hints->accumAlpha);
8256+
8257+ if (hints->sRGB) {
8258+ if (RGFW_extensionSupportedPlatform_OpenGL(sRGBARBstr, sizeof(sRGBARBstr)))
8259+ RGFW_attribStack_pushAttribs(&stack, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, hints->sRGB);
8260+ if (RGFW_extensionSupportedPlatform_OpenGL(sRGBEXTstr, sizeof(sRGBEXTstr)))
8261+ RGFW_attribStack_pushAttribs(&stack, GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, hints->sRGB);
8262+ }
8263+
8264+ RGFW_attribStack_pushAttribs(&stack, 0, 0);
8265+
8266+ /* find the configs */
8267+ i32 fbcount;
8268+ GLXFBConfig* fbc = glXChooseFBConfig(_RGFW->display, DefaultScreen(_RGFW->display), visual_attribs, &fbcount);
8269+
8270+ i32 best_fbc = -1;
8271+ i32 best_depth = 0;
8272+ i32 best_samples = 0;
8273+
8274+ if (fbcount == 0) {
8275+ RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to find any valid GLX visual configs.");
8276+ return 0;
8277+ }
8278+
8279+ /* search through all found configs to find the best match */
8280+ i32 i;
8281+ for (i = 0; i < fbcount; i++) {
8282+ XVisualInfo* vi = glXGetVisualFromFBConfig(_RGFW->display, fbc[i]);
8283+ if (vi == NULL)
8284+ continue;
8285+
8286+ i32 samp_buf, samples;
8287+ glXGetFBConfigAttrib(_RGFW->display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf);
8288+ glXGetFBConfigAttrib(_RGFW->display, fbc[i], GLX_SAMPLES, &samples);
8289+
8290+ if (best_fbc == -1) best_fbc = i;
8291+ if ((!(transparent) || vi->depth == 32) && best_depth == 0) {
8292+ best_fbc = i;
8293+ best_depth = vi->depth;
8294+ }
8295+ if ((!(transparent) || vi->depth == 32) && samples <= hints->samples && samples > best_samples) {
8296+ best_fbc = i;
8297+ best_depth = vi->depth;
8298+ best_samples = samples;
8299+ }
8300+ XFree(vi);
8301+ }
8302+
8303+ if (best_fbc == -1) {
8304+ RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to get a valid GLX visual.");
8305+ return 0;
8306+ }
8307+
8308+ /* we found a config */
8309+ bestFbc = fbc[best_fbc];
8310+ XVisualInfo* vi = glXGetVisualFromFBConfig(_RGFW->display, bestFbc);
8311+ if (vi->depth != 32 && transparent)
8312+ RGFW_debugCallback(RGFW_typeWarning, RGFW_warningOpenGL, "Failed to to find a matching visual with a 32-bit depth.");
8313+
8314+ if (best_samples < hints->samples)
8315+ RGFW_debugCallback(RGFW_typeWarning, RGFW_warningOpenGL, "Failed to load a matching sample count.");
8316+
8317+ XFree(fbc);
8318+ visual = *vi;
8319+ XFree(vi);
8320+
8321+ /* use the visual to create a new window */
8322+ RGFW_XCreateWindow(visual, "", win->internal.flags, win);
8323+
8324+ if (showWindow) {
8325+ RGFW_window_show(win);
8326+ }
8327+
8328+ /* create the actual OpenGL context */
8329+ i32 context_attribs[40];
8330+ RGFW_attribStack_init(&stack, context_attribs, 40);
8331+
8332+ i32 mask = 0;
8333+ switch (hints->profile) {
8334+ case RGFW_glES: mask |= GLX_CONTEXT_ES_PROFILE_BIT_EXT; break;
8335+ case RGFW_glForwardCompatibility: mask |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; break;
8336+ case RGFW_glCompatibility: mask |= GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; break;
8337+ case RGFW_glCore: mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; break;
8338+ default: mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; break;
8339+ }
8340+
8341+ RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_PROFILE_MASK_ARB, mask);
8342+
8343+ if (hints->minor || hints->major) {
8344+ RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_MAJOR_VERSION_ARB, hints->major);
8345+ RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_MINOR_VERSION_ARB, hints->minor);
8346+ }
8347+
8348+
8349+ if (RGFW_extensionSupportedPlatform_OpenGL(flushStr, sizeof(flushStr))) {
8350+ if (hints->releaseBehavior == RGFW_glReleaseFlush) {
8351+ RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB);
8352+ } else if (hints->releaseBehavior == RGFW_glReleaseNone) {
8353+ RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB);
8354+ }
8355+ }
8356+
8357+ i32 flags = 0;
8358+ if (hints->debug) flags |= GLX_CONTEXT_DEBUG_BIT_ARB;
8359+ if (hints->robustness && RGFW_extensionSupportedPlatform_OpenGL(robustStr, sizeof(robustStr))) flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB;
8360+ if (flags) {
8361+ RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_FLAGS_ARB, flags);
8362+ }
8363+
8364+ if (RGFW_extensionSupportedPlatform_OpenGL(noErorrStr, sizeof(noErorrStr))) {
8365+ RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_OPENGL_NO_ERROR_ARB, hints->noError);
8366+ }
8367+
8368+ RGFW_attribStack_pushAttribs(&stack, 0, 0);
8369+
8370+ /* create the context */
8371+ glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
8372+ char str[] = "glXCreateContextAttribsARB";
8373+ glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)glXGetProcAddressARB((u8*) str);
8374+
8375+ GLXContext ctx = NULL;
8376+ if (hints->share) {
8377+ ctx = hints->share->ctx;
8378+ }
8379+
8380+ if (glXCreateContextAttribsARB == NULL) {
8381+ RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load proc address 'glXCreateContextAttribsARB', loading a generic OpenGL context.");
8382+ win->src.ctx.native->ctx = glXCreateContext(_RGFW->display, &visual, ctx, True);
8383+ } else {
8384+ _RGFW->x11Error = NULL;
8385+ win->src.ctx.native->ctx = glXCreateContextAttribsARB(_RGFW->display, bestFbc, ctx, True, context_attribs);
8386+ if (_RGFW->x11Error || win->src.ctx.native->ctx == NULL) {
8387+ RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to create an OpenGL context with AttribsARB, loading a generic OpenGL context.");
8388+ win->src.ctx.native->ctx = glXCreateContext(_RGFW->display, &visual, ctx, True);
8389+ }
8390+ }
8391+
8392+ #ifndef RGFW_NO_GLXWINDOW
8393+ win->src.ctx.native->window = glXCreateWindow(_RGFW->display, bestFbc, win->src.window, NULL);
8394+ #else
8395+ win->src.ctx.native->window = win->src.window;
8396+ #endif
8397+
8398+ glXMakeCurrent(_RGFW->display, (Drawable)win->src.ctx.native->window, (GLXContext)win->src.ctx.native->ctx);
8399+ RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized.");
8400+
8401+ RGFW_window_swapInterval_OpenGL(win, 0);
8402+
8403+ return RGFW_TRUE;
8404+}
8405+
8406+void RGFW_FUNC(RGFW_window_deleteContextPtr_OpenGL) (RGFW_window* win, RGFW_glContext* ctx) {
8407+ #ifndef RGFW_NO_GLXWINDOW
8408+ if (win->src.ctx.native->window != win->src.window) {
8409+ glXDestroyWindow(_RGFW->display, win->src.ctx.native->window);
8410+ }
8411+ #endif
8412+
8413+ glXDestroyContext(_RGFW->display, ctx->ctx);
8414+ win->src.ctx.native = NULL;
8415+ RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context freed.");
8416+}
8417+
8418+RGFW_bool RGFW_FUNC(RGFW_extensionSupportedPlatform_OpenGL)(const char * extension, size_t len) {
8419+ RGFW_init();
8420+ const char* extensions = glXQueryExtensionsString(_RGFW->display, XDefaultScreen(_RGFW->display));
8421+ return (extensions != NULL) && RGFW_extensionSupportedStr(extensions, extension, len);
8422+}
8423+
8424+RGFW_proc RGFW_FUNC(RGFW_getProcAddress_OpenGL)(const char* procname) { return glXGetProcAddress((u8*) procname); }
8425+
8426+void RGFW_FUNC(RGFW_window_makeCurrentContext_OpenGL) (RGFW_window* win) { if (win) RGFW_ASSERT(win->src.ctx.native);
8427+ if (win == NULL)
8428+ glXMakeCurrent(NULL, (Drawable)NULL, (GLXContext) NULL);
8429+ else
8430+ glXMakeCurrent(_RGFW->display, (Drawable)win->src.ctx.native->window, (GLXContext) win->src.ctx.native->ctx);
8431+ return;
8432+}
8433+void* RGFW_FUNC(RGFW_getCurrentContext_OpenGL) (void) { return glXGetCurrentContext(); }
8434+void RGFW_FUNC(RGFW_window_swapBuffers_OpenGL) (RGFW_window* win) { RGFW_ASSERT(win->src.ctx.native); glXSwapBuffers(_RGFW->display, win->src.ctx.native->window); }
8435+
8436+void RGFW_FUNC(RGFW_window_swapInterval_OpenGL) (RGFW_window* win, i32 swapInterval) {
8437+ RGFW_ASSERT(win != NULL);
8438+ /* cached pfn to avoid calling glXGetProcAddress more than once */
8439+ static PFNGLXSWAPINTERVALEXTPROC pfn = NULL;
8440+ static int (*pfn2)(int) = NULL;
8441+
8442+ if (pfn == NULL) {
8443+ u8 str[] = "glXSwapIntervalEXT";
8444+ pfn = (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddress(str);
8445+ if (pfn == NULL) {
8446+ pfn = (PFNGLXSWAPINTERVALEXTPROC)1;
8447+ const char* array[] = {"GLX_MESA_swap_control", "GLX_SGI_swap_control"};
8448+
8449+ size_t i;
8450+ for (i = 0; i < sizeof(array) / sizeof(char*) && pfn2 == NULL; i++) {
8451+ pfn2 = (int(*)(int))glXGetProcAddress((u8*)array[i]);
8452+ }
8453+
8454+ if (pfn2 != NULL) {
8455+ RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load swap interval function, fallingback to the native swapinterval function");
8456+ } else {
8457+ RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load swap interval function");
8458+ }
8459+ }
8460+ }
8461+
8462+ if (pfn != (PFNGLXSWAPINTERVALEXTPROC)1) {
8463+ pfn(_RGFW->display, win->src.ctx.native->window, swapInterval);
8464+ }
8465+ else if (pfn2 != NULL) {
8466+ pfn2(swapInterval);
8467+ }
8468+}
8469+#endif /* RGFW_OPENGL */
8470+
8471+i32 RGFW_initPlatform_X11(void) {
8472+ #ifdef RGFW_USE_XDL
8473+ XDL_init();
8474+ #endif
8475+
8476+ #if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD)
8477+ #if defined(__CYGWIN__)
8478+ RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor-1.so");
8479+ #elif defined(__OpenBSD__) || defined(__NetBSD__)
8480+ RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor.so");
8481+ #else
8482+ RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor.so.1");
8483+ #endif
8484+ RGFW_PROC_DEF(X11Cursorhandle, XcursorImageCreate);
8485+ RGFW_PROC_DEF(X11Cursorhandle, XcursorImageDestroy);
8486+ RGFW_PROC_DEF(X11Cursorhandle, XcursorImageLoadCursor);
8487+ #endif
8488+
8489+ #if !defined(RGFW_NO_X11_XI_PRELOAD)
8490+ #if defined(__CYGWIN__)
8491+ RGFW_LOAD_LIBRARY(X11Xihandle, "libXi-6.so");
8492+ #elif defined(__OpenBSD__) || defined(__NetBSD__)
8493+ RGFW_LOAD_LIBRARY(X11Xihandle, "libXi.so");
8494+ #else
8495+ RGFW_LOAD_LIBRARY(X11Xihandle, "libXi.so.6");
8496+ #endif
8497+ RGFW_PROC_DEF(X11Xihandle, XISelectEvents);
8498+ #endif
8499+
8500+ #if !defined(RGFW_NO_X11_EXT_PRELOAD)
8501+ #if defined(__CYGWIN__)
8502+ RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext-6.so");
8503+ #elif defined(__OpenBSD__) || defined(__NetBSD__)
8504+ RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext.so");
8505+ #else
8506+ RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext.so.6");
8507+ #endif
8508+ RGFW_PROC_DEF(X11XEXThandle, XSyncCreateCounter);
8509+ RGFW_PROC_DEF(X11XEXThandle, XSyncIntToValue);
8510+ RGFW_PROC_DEF(X11XEXThandle, XSyncSetCounter);
8511+ RGFW_PROC_DEF(X11XEXThandle, XShapeCombineRegion);
8512+ RGFW_PROC_DEF(X11XEXThandle, XShapeCombineMask);
8513+ #endif
8514+
8515+ XInitThreads(); /*!< init X11 threading */
8516+ _RGFW->display = XOpenDisplay(0);
8517+ _RGFW->context = XUniqueContext();
8518+
8519+ XSetWindowAttributes wa;
8520+ RGFW_MEMZERO(&wa, sizeof(wa));
8521+ wa.event_mask = PropertyChangeMask;
8522+ _RGFW->helperWindow = XCreateWindow(_RGFW->display, XDefaultRootWindow(_RGFW->display), 0, 0, 1, 1, 0, 0,
8523+ InputOnly, DefaultVisual(_RGFW->display, DefaultScreen(_RGFW->display)), CWEventMask, &wa);
8524+
8525+ u8 RGFW_blk[] = { 0, 0, 0, 0 };
8526+ _RGFW->hiddenMouse = RGFW_createMouse(RGFW_blk, 1, 1, RGFW_formatRGBA8);
8527+
8528+ _RGFW->clipboard = NULL;
8529+
8530+ XkbComponentNamesRec rec;
8531+ XkbDescPtr desc = XkbGetMap(_RGFW->display, 0, XkbUseCoreKbd);
8532+ XkbDescPtr evdesc;
8533+ XSetErrorHandler(RGFW_XErrorHandler);
8534+ u8 old[256];
8535+
8536+ XkbGetNames(_RGFW->display, XkbKeyNamesMask, desc);
8537+
8538+ RGFW_MEMZERO(&rec, sizeof(rec));
8539+ char evdev[] = "evdev";
8540+ rec.keycodes = evdev;
8541+ evdesc = XkbGetKeyboardByName(_RGFW->display, XkbUseCoreKbd, &rec, XkbGBN_KeyNamesMask, XkbGBN_KeyNamesMask, False);
8542+ /* memo: RGFW_keycodes[x11 keycode] = rgfw keycode */
8543+ if(evdesc != NULL && desc != NULL) {
8544+ int i, j;
8545+ for(i = 0; i < (int)sizeof(old); i++){
8546+ old[i] = _RGFW->keycodes[i];
8547+ _RGFW->keycodes[i] = 0;
8548+ }
8549+ for(i = evdesc->min_key_code; i <= evdesc->max_key_code; i++){
8550+ for(j = desc->min_key_code; j <= desc->max_key_code; j++){
8551+ if(RGFW_STRNCMP(evdesc->names->keys[i].name, desc->names->keys[j].name, XkbKeyNameLength) == 0){
8552+ _RGFW->keycodes[j] = old[i];
8553+ break;
8554+ }
8555+ }
8556+ }
8557+ XkbFreeKeyboard(desc, 0, True);
8558+ XkbFreeKeyboard(evdesc, 0, True);
8559+ }
8560+
8561+ XSetLocaleModifiers("");
8562+ XRegisterIMInstantiateCallback(_RGFW->display, NULL, NULL, NULL, RGFW_x11_imInitCallback, NULL);
8563+
8564+ unsigned char mask[XIMaskLen(XI_RawMotion)];
8565+ RGFW_MEMZERO(mask, sizeof(mask));
8566+ XISetMask(mask, XI_RawMotion);
8567+
8568+ XIEventMask em;
8569+ em.deviceid = XIAllMasterDevices;
8570+ em.mask_len = sizeof(mask);
8571+ em.mask = mask;
8572+
8573+ XISelectEvents(_RGFW->display, XDefaultRootWindow(_RGFW->display), &em, 1);
8574+
8575+ i32 errorBase;
8576+ if (XRRQueryExtension(_RGFW->display, &_RGFW->xrandrEventBase, &errorBase)) {
8577+ XRRSelectInput(_RGFW->display, RootWindow(_RGFW->display, DefaultScreen(_RGFW->display)), RROutputChangeNotifyMask);
8578+ }
8579+
8580+ return 0;
8581+}
8582+
8583+void RGFW_deinitPlatform_X11(void) {
8584+ #define RGFW_FREE_LIBRARY(x) if (x != NULL) dlclose(x); x = NULL;
8585+ /* to save the clipboard on the x server after the window is closed */
8586+ RGFW_LOAD_ATOM(CLIPBOARD_MANAGER); RGFW_LOAD_ATOM(CLIPBOARD);
8587+ RGFW_LOAD_ATOM(SAVE_TARGETS);
8588+ if (XGetSelectionOwner(_RGFW->display, CLIPBOARD) == _RGFW->helperWindow) {
8589+ XConvertSelection(_RGFW->display, CLIPBOARD_MANAGER, SAVE_TARGETS, None, _RGFW->helperWindow, CurrentTime);
8590+ while (RGFW_XHandleClipboardSelectionHelper());
8591+ }
8592+
8593+ XUnregisterIMInstantiateCallback(_RGFW->display, NULL, NULL, NULL, RGFW_x11_imInitCallback, NULL);
8594+
8595+ if (_RGFW->im) {
8596+ XCloseIM(_RGFW->im);
8597+ _RGFW->im = NULL;
8598+ }
8599+
8600+ if (_RGFW->clipboard) {
8601+ RGFW_FREE(_RGFW->clipboard);
8602+ _RGFW->clipboard = NULL;
8603+ }
8604+
8605+ if (_RGFW->hiddenMouse) {
8606+ RGFW_freeMouse(_RGFW->hiddenMouse);
8607+ _RGFW->hiddenMouse = NULL;
8608+ }
8609+
8610+ XDestroyWindow(_RGFW->display, (Drawable) _RGFW->helperWindow); /*!< close the window */
8611+ XCloseDisplay(_RGFW->display); /*!< kill connection to the x server */
8612+
8613+ #if !defined(RGFW_NO_X11_CURSOR_PRELOAD) && !defined(RGFW_NO_X11_CURSOR)
8614+ RGFW_FREE_LIBRARY(X11Cursorhandle);
8615+ #endif
8616+ #if !defined(RGFW_NO_X11_XI_PRELOAD)
8617+ RGFW_FREE_LIBRARY(X11Xihandle);
8618+ #endif
8619+
8620+ #ifdef RGFW_USE_XDL
8621+ XDL_close();
8622+ #endif
8623+
8624+ #if !defined(RGFW_NO_X11_EXT_PRELOAD)
8625+ RGFW_FREE_LIBRARY(X11XEXThandle);
8626+ #endif
8627+}
8628+
8629+void RGFW_FUNC(RGFW_window_closePlatform)(RGFW_window* win) {
8630+ if (win->src.ic) {
8631+ XDestroyIC(win->src.ic);
8632+ win->src.ic = NULL;
8633+ }
8634+
8635+ XFreeGC(_RGFW->display, win->src.gc);
8636+ XDeleteContext(_RGFW->display, win->src.window, _RGFW->context);
8637+ XDestroyWindow(_RGFW->display, (Drawable) win->src.window); /*!< close the window */
8638+ return;
8639+}
8640+
8641+#ifdef RGFW_WEBGPU
8642+WGPUSurface RGFW_FUNC(RGFW_window_createSurface_WebGPU) (RGFW_window* window, WGPUInstance instance) {
8643+ WGPUSurfaceDescriptor surfaceDesc = {0};
8644+ WGPUSurfaceSourceXlibWindow fromXlib = {0};
8645+ fromXlib.chain.sType = WGPUSType_SurfaceSourceXlibWindow;
8646+ fromXlib.display = _RGFW->display;
8647+ fromXlib.window = window->src.window;
8648+
8649+ surfaceDesc.nextInChain = (WGPUChainedStruct*)&fromXlib.chain;
8650+ return wgpuInstanceCreateSurface(instance, &surfaceDesc);
8651+}
8652+#endif
8653+
8654+#endif
8655+/*
8656+ End of X11 linux / wayland / unix defines
8657+*/
8658+
8659+/*
8660+
8661+ Start of Wayland defayland
8662+*/
8663+
8664+#ifdef RGFW_WAYLAND
8665+#ifdef RGFW_X11
8666+#undef RGFW_FUNC /* remove previous define */
8667+#define RGFW_FUNC(func) func##_Wayland
8668+#else
8669+#define RGFW_FUNC(func) func
8670+#endif
8671+
8672+/*
8673+Wayland TODO: (out of date)
8674+- fix RGFW_keyPressed lock state
8675+
8676+ RGFW_windowMoved, the window was moved (by the user)
8677+ RGFW_windowRefresh The window content needs to be refreshed
8678+
8679+ RGFW_dataDrop a file has been dropped into the window
8680+ RGFW_dataDrag
8681+
8682+- window args:
8683+ #define RGFW_windowNoResize the window cannot be resized by the user
8684+ #define RGFW_windowAllowDND the window supports drag and drop
8685+ #define RGFW_scaleToMonitor scale the window to the screen
8686+
8687+- other missing functions functions ("TODO wayland") (~30 functions)
8688+- fix buffer rendering weird behavior
8689+*/
8690+#include <errno.h>
8691+#include <unistd.h>
8692+#include <sys/mman.h>
8693+#include <xkbcommon/xkbcommon.h>
8694+#include <xkbcommon/xkbcommon-keysyms.h>
8695+#include <xkbcommon/xkbcommon-compose.h>
8696+#include <dirent.h>
8697+#include <linux/kd.h>
8698+#include <wayland-cursor.h>
8699+#include <fcntl.h>
8700+
8701+struct wl_display* RGFW_getDisplay_Wayland(void) { return _RGFW->wl_display; }
8702+struct wl_surface* RGFW_window_getWindow_Wayland(RGFW_window* win) { return win->src.surface; }
8703+
8704+
8705+/* wayland global garbage (wayland bad, X11 is fine (ish) (not really)) */
8706+#include "xdg-shell.h"
8707+#include "xdg-toplevel-icon-v1.h"
8708+#include "xdg-decoration-unstable-v1.h"
8709+#include "relative-pointer-unstable-v1.h"
8710+#include "pointer-constraints-unstable-v1.h"
8711+#include "xdg-output-unstable-v1.h"
8712+#include "pointer-warp-v1.h"
8713+
8714+void RGFW_toggleWaylandMaximized(RGFW_window* win, RGFW_bool maximized);
8715+
8716+static void RGFW_wl_setOpaque(RGFW_window* win) {
8717+ struct wl_region* wl_region = wl_compositor_create_region(_RGFW->compositor);
8718+
8719+ if (!wl_region) return; /* return if no region was created */
8720+
8721+ wl_region_add(wl_region, 0, 0, win->w, win->h);
8722+ wl_surface_set_opaque_region(win->src.surface, wl_region);
8723+ wl_region_destroy(wl_region);
8724+
8725+}
8726+
8727+static void RGFW_wl_xdg_wm_base_ping_handler(void* data, struct xdg_wm_base* wm_base,
8728+ u32 serial) {
8729+ RGFW_UNUSED(data);
8730+ xdg_wm_base_pong(wm_base, serial);
8731+}
8732+static void RGFW_wl_xdg_surface_configure_handler(void* data, struct xdg_surface* xdg_surface,
8733+ u32 serial) {
8734+
8735+ xdg_surface_ack_configure(xdg_surface, serial);
8736+
8737+ RGFW_window* win = (RGFW_window*)data;
8738+
8739+ if (win == NULL) {
8740+ win = _RGFW->kbOwner;
8741+ if (win == NULL)
8742+ return;
8743+ }
8744+
8745+ /* useful for libdecor */
8746+ if (win->src.activated != win->src.pending_activated) {
8747+ win->src.activated = win->src.pending_activated;
8748+ }
8749+
8750+ if (win->src.maximized != win->src.pending_maximized) {
8751+ RGFW_toggleWaylandMaximized(win, win->src.pending_maximized);
8752+
8753+ RGFW_window_checkMode(win);
8754+ }
8755+
8756+
8757+ if (win->src.resizing) {
8758+
8759+ RGFW_windowResizedCallback(win, win->w, win->h);
8760+ RGFW_window_resize(win, win->w, win->h);
8761+ if (!(win->internal.flags & RGFW_windowTransparent)) {
8762+ RGFW_wl_setOpaque(win);
8763+ }
8764+ }
8765+
8766+ win->src.configured = RGFW_TRUE;
8767+}
8768+
8769+static void RGFW_wl_xdg_toplevel_configure_handler(void* data, struct xdg_toplevel* toplevel,
8770+ i32 width, i32 height, struct wl_array* states) {
8771+
8772+ RGFW_UNUSED(toplevel);
8773+ RGFW_window* win = (RGFW_window*)data;
8774+
8775+
8776+ win->src.pending_activated = RGFW_FALSE;
8777+ win->src.pending_maximized = RGFW_FALSE;
8778+ win->src.resizing = RGFW_FALSE;
8779+
8780+
8781+ enum xdg_toplevel_state* state;
8782+ wl_array_for_each(state, states) {
8783+ switch (*state) {
8784+ case XDG_TOPLEVEL_STATE_ACTIVATED:
8785+ win->src.pending_activated = RGFW_TRUE;
8786+ break;
8787+ case XDG_TOPLEVEL_STATE_MAXIMIZED:
8788+ win->src.pending_maximized = RGFW_TRUE;
8789+ break;
8790+ default:
8791+ break;
8792+ }
8793+
8794+ }
8795+ /* if width and height are not zero and are not the same as the window */
8796+ /* the window is resizing so update the values */
8797+ if ((width && height) && (win->w != width || win->h != height)) {
8798+ win->src.resizing = RGFW_TRUE;
8799+ win->src.w = win->w = width;
8800+ win->src.h = win->h = height;
8801+ }
8802+}
8803+
8804+static void RGFW_wl_xdg_toplevel_close_handler(void* data, struct xdg_toplevel *toplevel) {
8805+ RGFW_UNUSED(toplevel);
8806+ RGFW_window* win = (RGFW_window*)data;
8807+
8808+ if (!win->internal.shouldClose) {
8809+ RGFW_windowCloseCallback(win);
8810+ }
8811+}
8812+
8813+static void RGFW_wl_xdg_decoration_configure_handler(void* data,
8814+ struct zxdg_toplevel_decoration_v1* zxdg_toplevel_decoration_v1, u32 mode) {
8815+ RGFW_window* win = (RGFW_window*)data; RGFW_UNUSED(zxdg_toplevel_decoration_v1);
8816+
8817+ /* this is expected to run once */
8818+ /* set the decoration mode set by earlier request */
8819+ if (mode != win->src.decoration_mode) {
8820+ win->src.decoration_mode = mode;
8821+ }
8822+}
8823+
8824+static void RGFW_wl_shm_format_handler(void* data, struct wl_shm *shm, u32 format) {
8825+ RGFW_UNUSED(data); RGFW_UNUSED(shm); RGFW_UNUSED(format);
8826+}
8827+
8828+static void RGFW_wl_relative_pointer_motion(void *data, struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1,
8829+ u32 time_hi, u32 time_lo, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t dx_unaccel, wl_fixed_t dy_unaccel) {
8830+
8831+ RGFW_UNUSED(zwp_relative_pointer_v1); RGFW_UNUSED(time_hi); RGFW_UNUSED(time_lo);
8832+ RGFW_UNUSED(dx_unaccel); RGFW_UNUSED(dy_unaccel);
8833+
8834+ RGFW_info* RGFW = (RGFW_info*)data;
8835+
8836+ RGFW_ASSERT(RGFW->mouseOwner != NULL);
8837+ RGFW_window* win = RGFW->mouseOwner;
8838+
8839+ RGFW_ASSERT(win);
8840+
8841+ float vecX = (float)wl_fixed_to_double(dx);
8842+ float vecY = (float)wl_fixed_to_double(dy);
8843+ RGFW_rawMotionCallback(win, vecX, vecY);
8844+}
8845+
8846+static void RGFW_wl_pointer_locked(void *data, struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1) {
8847+ RGFW_UNUSED(zwp_locked_pointer_v1);
8848+ RGFW_info* RGFW = (RGFW_info*)data;
8849+ wl_pointer_set_cursor(RGFW->wl_pointer, RGFW->mouse_enter_serial, NULL, 0, 0); /* draw no cursor */
8850+}
8851+
8852+static void RGFW_wl_pointer_enter(void* data, struct wl_pointer* pointer, u32 serial,
8853+ struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) {
8854+ RGFW_info* RGFW = (RGFW_info*)data;
8855+ RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
8856+
8857+ /* save when the pointer is locked or using default cursor */
8858+ RGFW->mouse_enter_serial = serial;
8859+ win->internal.mouseInside = RGFW_TRUE;
8860+ RGFW->windowState.mouseEnter = RGFW_TRUE;
8861+
8862+ RGFW->mouseOwner = win;
8863+
8864+ /* set the cursor */
8865+ if (win->src.using_custom_cursor) {
8866+ wl_pointer_set_cursor(pointer, serial, win->src.custom_cursor_surface, 0, 0);
8867+ }
8868+ else {
8869+ RGFW_window_setMouseDefault(win);
8870+ }
8871+
8872+ i32 x = (i32)wl_fixed_to_double(surface_x);
8873+ i32 y = (i32)wl_fixed_to_double(surface_y);
8874+ RGFW_mouseNotifyCallback(win, x, y, RGFW_TRUE);
8875+}
8876+
8877+static void RGFW_wl_pointer_leave(void* data, struct wl_pointer *pointer, u32 serial, struct wl_surface *surface) {
8878+ RGFW_UNUSED(pointer); RGFW_UNUSED(serial);
8879+ RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
8880+ RGFW_info* RGFW = (RGFW_info*)data;
8881+ if (RGFW->mouseOwner == win)
8882+ RGFW->mouseOwner = NULL;
8883+
8884+ RGFW_mouseNotifyCallback(win, win->internal.lastMouseX, win->internal.lastMouseY, RGFW_FALSE);
8885+}
8886+
8887+static void RGFW_wl_pointer_motion(void* data, struct wl_pointer *pointer, u32 time, wl_fixed_t x, wl_fixed_t y) {
8888+ RGFW_UNUSED(pointer); RGFW_UNUSED(time);
8889+ RGFW_info* RGFW = (RGFW_info*)data;
8890+ RGFW_ASSERT(RGFW->mouseOwner != NULL);
8891+
8892+ RGFW_window* win = RGFW->mouseOwner;
8893+
8894+ i32 convertedX = (i32)wl_fixed_to_double(x);
8895+ i32 convertedY = (i32)wl_fixed_to_double(y);
8896+
8897+ RGFW_mousePosCallback(win, convertedX, convertedY);
8898+}
8899+
8900+static void RGFW_wl_pointer_button(void* data, struct wl_pointer *pointer, u32 serial, u32 time, u32 button, u32 state) {
8901+ RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(serial);
8902+ RGFW_info* RGFW = (RGFW_info*)data;
8903+
8904+ RGFW_ASSERT(RGFW->mouseOwner != NULL);
8905+ RGFW_window* win = RGFW->mouseOwner;
8906+
8907+ u32 b = (button - 0x110);
8908+
8909+ /* flip right and middle button codes */
8910+ if (b == 1) b = 2;
8911+ else if (b == 2) b = 1;
8912+
8913+ RGFW_mouseButtonCallback(win, (u8)b, RGFW_BOOL(state));
8914+}
8915+
8916+static void RGFW_wl_pointer_axis(void* data, struct wl_pointer *pointer, u32 time, u32 axis, wl_fixed_t value) {
8917+ RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(axis);
8918+
8919+ RGFW_info* RGFW = (RGFW_info*)data;
8920+ RGFW_ASSERT(RGFW->mouseOwner != NULL);
8921+ RGFW_window* win = RGFW->mouseOwner;
8922+
8923+ float scrollX = 0.0;
8924+ float scrollY = 0.0;
8925+
8926+ if (!(win->internal.enabledEvents & (RGFW_BIT(RGFW_mouseScroll)))) return;
8927+
8928+ if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
8929+ scrollX = (float)(-wl_fixed_to_double(value) / 10.0);
8930+ else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
8931+ scrollY = (float)(-wl_fixed_to_double(value) / 10.0);
8932+
8933+ RGFW_mouseScrollCallback(win, scrollX, scrollY);
8934+}
8935+
8936+
8937+static void RGFW_doNothing(void) { }
8938+
8939+static void RGFW_wl_keyboard_keymap(void* data, struct wl_keyboard *keyboard, u32 format, i32 fd, u32 size) {
8940+ RGFW_UNUSED(keyboard); RGFW_UNUSED(format);
8941+ RGFW_info* RGFW = (RGFW_info*)data;
8942+
8943+ char *keymap_string = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0);
8944+ xkb_keymap_unref(RGFW->keymap);
8945+ RGFW->keymap = xkb_keymap_new_from_string(RGFW->xkb_context, keymap_string, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
8946+
8947+ munmap(keymap_string, size);
8948+ close(fd);
8949+ xkb_state_unref(RGFW->xkb_state);
8950+ RGFW->xkb_state = xkb_state_new(RGFW->keymap);
8951+
8952+ const char* locale = getenv("LC_ALL");
8953+ if (!locale)
8954+ locale = getenv("LC_CTYPE");
8955+ if (!locale)
8956+ locale = getenv("LANG");
8957+ if (!locale)
8958+ locale = "C";
8959+
8960+ struct xkb_compose_table* composeTable = xkb_compose_table_new_from_locale(RGFW->xkb_context, locale, XKB_COMPOSE_COMPILE_NO_FLAGS);
8961+ if (composeTable) {
8962+ RGFW->composeState = xkb_compose_state_new(composeTable, XKB_COMPOSE_STATE_NO_FLAGS);
8963+ xkb_compose_table_unref(composeTable);
8964+ }
8965+}
8966+
8967+static void RGFW_wl_keyboard_enter(void* data, struct wl_keyboard *keyboard, u32 serial, struct wl_surface *surface, struct wl_array *keys) {
8968+ RGFW_UNUSED(keyboard); RGFW_UNUSED(keys);
8969+
8970+ RGFW_info* RGFW = (RGFW_info*)data;
8971+ RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
8972+ RGFW->kbOwner = win;
8973+
8974+
8975+ // this is to prevent race conditions
8976+ if (RGFW->data_device != NULL && win->src.data_source != NULL) {
8977+ wl_data_device_set_selection(RGFW->data_device, win->src.data_source, serial);
8978+ }
8979+ /* is set when RGFW_window_minimize is called; if the minimize button is */
8980+ /* pressed this flag is not set since there is no event to listen for */
8981+ if (win->src.minimized == RGFW_TRUE) win->src.minimized = RGFW_FALSE;
8982+
8983+ RGFW_windowFocusCallback(win, RGFW_TRUE);
8984+}
8985+
8986+static void RGFW_wl_keyboard_leave(void* data, struct wl_keyboard *keyboard, u32 serial, struct wl_surface *surface) {
8987+ RGFW_UNUSED(keyboard); RGFW_UNUSED(serial);
8988+
8989+ RGFW_info* RGFW = (RGFW_info*)data;
8990+ RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
8991+ if (RGFW->kbOwner == win)
8992+ RGFW->kbOwner = NULL;
8993+
8994+ RGFW_windowFocusCallback(win, RGFW_FALSE);
8995+}
8996+
8997+static xkb_keysym_t RGFW_wl_composeSymbol(RGFW_info* RGFW, xkb_keysym_t sym) {
8998+ if (sym == XKB_KEY_NoSymbol || !RGFW->composeState)
8999+ return sym;
9000+ if (xkb_compose_state_feed(RGFW->composeState, sym) != XKB_COMPOSE_FEED_ACCEPTED)
9001+ return sym;
9002+ switch (xkb_compose_state_get_status(RGFW->composeState)) {
9003+ case XKB_COMPOSE_COMPOSED:
9004+ return xkb_compose_state_get_one_sym(RGFW->composeState);
9005+ case XKB_COMPOSE_COMPOSING:
9006+ case XKB_COMPOSE_CANCELLED:
9007+ return XKB_KEY_NoSymbol;
9008+ case XKB_COMPOSE_NOTHING:
9009+ default:
9010+ return sym;
9011+ }
9012+}
9013+
9014+static void RGFW_wl_send_key_event(u32 key) {
9015+ const xkb_keysym_t* keysyms;
9016+ if (xkb_state_key_get_syms(_RGFW->xkb_state, key + 8, &keysyms) == 1) {
9017+ xkb_keysym_t keysym = RGFW_wl_composeSymbol(_RGFW, keysyms[0]);
9018+ u32 codepoint = xkb_keysym_to_utf32(keysym);
9019+ if (codepoint != 0) {
9020+ RGFW_keyCharCallback(_RGFW->kbOwner, codepoint);
9021+ }
9022+ }
9023+}
9024+
9025+static void RGFW_wl_keyboard_key(void* data, struct wl_keyboard *keyboard, u32 serial, u32 time, u32 key, u32 state) {
9026+ RGFW_UNUSED(keyboard); RGFW_UNUSED(serial);
9027+
9028+ RGFW_info* RGFW = (RGFW_info*)data;
9029+ if (RGFW->kbOwner == NULL) return;
9030+
9031+ RGFW_window *RGFW_key_win = RGFW->kbOwner;
9032+ RGFW_key RGFWkey = RGFW_apiKeyToRGFW(key + 8);
9033+
9034+ RGFW_keyUpdateKeyMods(RGFW_key_win, RGFW_BOOL(xkb_keymap_mod_get_index(RGFW->keymap, "Lock")), RGFW_BOOL(xkb_keymap_mod_get_index(RGFW->keymap, "Mod2")), RGFW_BOOL(xkb_keymap_mod_get_index(RGFW->keymap, "ScrollLock")));
9035+ RGFW_keyCallback(RGFW_key_win, (u8)RGFWkey, RGFW_key_win->internal.mod, RGFW_isKeyDown((u8)RGFWkey) && RGFW_BOOL(state), RGFW_BOOL(state));
9036+
9037+ /* [comment by Kala Telo (@kala-telo) and edited by Riley Mabb (@ColleagueRiley)]
9038+ we send the event at the moment we receive it, and
9039+ repeated key presses will be handled by RGFW_pollEvents
9040+ if the compositor doesn't support proxy (seat?) version
9041+ of at least 4, it won't initialize wl_repeat_info_rate,
9042+ and by spec, rate of 0 means disabled, thus repeating
9043+ keys are disabled by being zero-initialized
9044+ */
9045+ RGFW->last_key = state ? key : 0;
9046+ RGFW->last_key_time = time + (u32)_RGFW->wl_repeat_info_delay;
9047+ if (state) {
9048+ RGFW_wl_send_key_event(_RGFW->last_key);
9049+ }
9050+}
9051+
9052+static void RGFW_wl_keyboard_modifiers(void* data, struct wl_keyboard *keyboard, u32 serial, u32 mods_depressed, u32 mods_latched, u32 mods_locked, u32 group) {
9053+ RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time);
9054+ RGFW_info* RGFW = (RGFW_info*)data;
9055+ xkb_state_update_mask(RGFW->xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
9056+}
9057+
9058+static void RGFW_wl_keyboard_repeat_info(void* data, struct wl_keyboard *keyboard, i32 rate, i32 delay) {
9059+ RGFW_UNUSED(data);
9060+ RGFW_UNUSED(keyboard);
9061+ _RGFW->wl_repeat_info_rate = rate;
9062+ _RGFW->wl_repeat_info_delay = delay;
9063+}
9064+
9065+static void RGFW_wl_seat_capabilities(void* data, struct wl_seat *seat, u32 capabilities) {
9066+ RGFW_info* RGFW = (RGFW_info*)data;
9067+ static struct wl_pointer_listener pointer_listener;
9068+ RGFW_MEMZERO(&pointer_listener, sizeof(pointer_listener));
9069+ pointer_listener.enter = &RGFW_wl_pointer_enter;
9070+ pointer_listener.leave = &RGFW_wl_pointer_leave;
9071+ pointer_listener.motion = &RGFW_wl_pointer_motion;
9072+ pointer_listener.button = &RGFW_wl_pointer_button;
9073+ pointer_listener.axis = &RGFW_wl_pointer_axis;
9074+
9075+ static struct wl_keyboard_listener keyboard_listener;
9076+ RGFW_MEMZERO(&keyboard_listener, sizeof(keyboard_listener));
9077+ keyboard_listener.keymap = &RGFW_wl_keyboard_keymap;
9078+ keyboard_listener.enter = &RGFW_wl_keyboard_enter;
9079+ keyboard_listener.leave = &RGFW_wl_keyboard_leave;
9080+ keyboard_listener.key = &RGFW_wl_keyboard_key;
9081+ keyboard_listener.modifiers = &RGFW_wl_keyboard_modifiers;
9082+ keyboard_listener.repeat_info = &RGFW_wl_keyboard_repeat_info;
9083+
9084+ if ((capabilities & WL_SEAT_CAPABILITY_POINTER) && !RGFW->wl_pointer) {
9085+ RGFW->wl_pointer = wl_seat_get_pointer(seat);
9086+ wl_pointer_add_listener(RGFW->wl_pointer, &pointer_listener, RGFW);
9087+ }
9088+ if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && !RGFW->wl_keyboard) {
9089+ RGFW->wl_keyboard = wl_seat_get_keyboard(seat);
9090+ wl_keyboard_add_listener(RGFW->wl_keyboard, &keyboard_listener, RGFW);
9091+ }
9092+
9093+ if (!(capabilities & WL_SEAT_CAPABILITY_POINTER) && RGFW->wl_pointer) {
9094+ wl_pointer_destroy(RGFW->wl_pointer);
9095+ }
9096+ if (!(capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && RGFW->wl_keyboard) {
9097+ wl_keyboard_destroy(RGFW->wl_keyboard);
9098+ }
9099+}
9100+
9101+static void RGFW_wl_output_set_geometry(void *data, struct wl_output *wl_output,
9102+ i32 x, i32 y, i32 physical_width, i32 physical_height,
9103+ i32 subpixel, const char *make, const char *model, i32 transform) {
9104+
9105+ RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon;
9106+ monitor->x = x;
9107+ monitor->y = y;
9108+
9109+ monitor->physW = (float)physical_width / 25.4f;
9110+ monitor->physH = (float)physical_height / 25.4f;
9111+
9112+ RGFW_UNUSED(wl_output);
9113+ RGFW_UNUSED(subpixel);
9114+ RGFW_UNUSED(make);
9115+ RGFW_UNUSED(model);
9116+ RGFW_UNUSED(transform);
9117+}
9118+
9119+static void RGFW_wl_output_handle_mode(void *data, struct wl_output *wl_output, u32 flags,
9120+ i32 width, i32 height, i32 refresh) {
9121+
9122+ RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon;
9123+
9124+ RGFW_monitorMode mode;
9125+ mode.w = width;
9126+ mode.h = height;
9127+ mode.refreshRate = (float)refresh / 1000.0f;
9128+ mode.src = wl_output;
9129+
9130+ monitor->node->modeCount += 1;
9131+
9132+ RGFW_monitorMode* modes = (RGFW_monitorMode*)RGFW_ALLOC(monitor->node->modeCount * sizeof(RGFW_monitorMode));
9133+
9134+ if (monitor->node->modeCount > 1) {
9135+ RGFW_monitor_getModesPtr(monitor, &modes);
9136+ RGFW_FREE(monitor->node->modes);
9137+ }
9138+
9139+ modes[monitor->node->modeCount - 1] = mode;
9140+ monitor->node->modes = modes;
9141+
9142+ if (flags & WL_OUTPUT_MODE_CURRENT) {
9143+ monitor->mode = mode;
9144+ } else {
9145+ }
9146+}
9147+
9148+static void RGFW_wl_output_set_scale(void *data, struct wl_output *wl_output, i32 factor) {
9149+ RGFW_UNUSED(wl_output);
9150+ RGFW_monitor* mon = &((RGFW_monitorNode*)data)->mon;
9151+
9152+ mon->scaleX = (float)factor;
9153+ mon->scaleY = (float)factor;
9154+}
9155+
9156+static void RGFW_wl_output_set_name(void *data, struct wl_output *wl_output, const char *name) {
9157+ RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon;
9158+
9159+ RGFW_STRNCPY(monitor->name, name, sizeof(monitor->name) - 1);
9160+ monitor->name[sizeof(monitor->name) - 1] = '\0';
9161+
9162+ RGFW_UNUSED(wl_output);
9163+
9164+}
9165+
9166+static void RGFW_xdg_output_logical_pos(void *data, struct zxdg_output_v1 *zxdg_output_v1, i32 x, i32 y) {
9167+ RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon;
9168+ monitor->x = x;
9169+ monitor->y = y;
9170+ RGFW_UNUSED(zxdg_output_v1);
9171+}
9172+
9173+static void RGFW_xdg_output_logical_size(void *data, struct zxdg_output_v1 *zxdg_output_v1, i32 width, i32 height) {
9174+ RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon;
9175+
9176+ float mon_float_width = (float) monitor->mode.w;
9177+ float mon_float_height = (float) monitor->mode.h;
9178+
9179+ float scaleX = (mon_float_width / (float) width);
9180+ float scaleY = (mon_float_height / (float) height);
9181+ RGFW_UNUSED(scaleY);
9182+
9183+ float dpi = scaleX * 96.0f;
9184+
9185+ monitor->pixelRatio = dpi >= 192.0f ? 2.0f : 1.0f;
9186+
9187+ /* under xwayland the monitor changes w & h when compositor scales it */
9188+ monitor->mode.w = width;
9189+ monitor->mode.h = height;
9190+ RGFW_UNUSED(zxdg_output_v1);
9191+}
9192+
9193+
9194+static void RGFW_wl_output_handle_done(void* data, struct wl_output* output) {
9195+ RGFW_UNUSED(output);
9196+
9197+ RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon;
9198+
9199+ if (monitor->physW <= 0 || monitor->physH <= 0) {
9200+ monitor->physW = (i32) ((float)monitor->mode.w / 96.0f);
9201+ monitor->physH = (i32) ((float)monitor->mode.h / 96.0f);
9202+ }
9203+
9204+ if (((RGFW_monitorNode*)data)->disconnected == RGFW_FALSE) {
9205+ return;
9206+ }
9207+
9208+ ((RGFW_monitorNode*)data)->disconnected = RGFW_TRUE;
9209+
9210+ RGFW_monitorCallback(_RGFW->root, monitor, RGFW_TRUE);
9211+}
9212+
9213+static void RGFW_wl_create_outputs(struct wl_registry *const registry, u32 id) {
9214+ struct wl_output *output = wl_registry_bind(registry, id, &wl_output_interface, wl_proxy_get_version((struct wl_proxy*)_RGFW->seat));
9215+ RGFW_monitorNode* node;
9216+ RGFW_monitor mon;
9217+
9218+ if (!output) return;
9219+
9220+ char RGFW_mon_default_name[10];
9221+
9222+ RGFW_SNPRINTF(RGFW_mon_default_name, sizeof(RGFW_mon_default_name), "monitor-%li", _RGFW->monitors.count);
9223+ RGFW_STRNCPY(mon.name, RGFW_mon_default_name, sizeof(mon.name) - 1);
9224+ mon.name[sizeof(mon.name) - 1] = '\0';
9225+
9226+ /* set in case compositor does not send one */
9227+ /* or no xdg_output support */
9228+ mon.scaleY = mon.scaleX = mon.pixelRatio = 1.0f;
9229+
9230+ node = RGFW_monitors_add(&mon);
9231+ if (node == NULL) return;
9232+
9233+ node->modeCount = 0;
9234+ node->disconnected = RGFW_TRUE;
9235+ node->id = id;
9236+ node->output = output;
9237+
9238+ static const struct wl_output_listener wl_output_listener = {
9239+ .geometry = RGFW_wl_output_set_geometry,
9240+ .mode = RGFW_wl_output_handle_mode,
9241+ .done = RGFW_wl_output_handle_done,
9242+ .scale = RGFW_wl_output_set_scale,
9243+ .name = RGFW_wl_output_set_name,
9244+ .description = (void (*)(void *, struct wl_output *, const char *))&RGFW_doNothing
9245+ };
9246+
9247+ /* the wl_output will have a reference to the node */
9248+ wl_output_set_user_data(output, node);
9249+
9250+ /* pass the monitor so we can access it in the callback functions */
9251+ wl_output_add_listener(output, &wl_output_listener, node);
9252+
9253+ if (!_RGFW->xdg_output_manager)
9254+ return; /* compositor does not support it */
9255+
9256+ static const struct zxdg_output_v1_listener xdg_output_listener = {
9257+ .name = (void (*)(void *,struct zxdg_output_v1 *, const char *))&RGFW_doNothing,
9258+ .done = (void (*)(void *,struct zxdg_output_v1 *))&RGFW_doNothing,
9259+ .description = (void (*)(void *,struct zxdg_output_v1 *, const char *))&RGFW_doNothing,
9260+ .logical_position = RGFW_xdg_output_logical_pos,
9261+ .logical_size = RGFW_xdg_output_logical_size
9262+ };
9263+
9264+ node->xdg_output = zxdg_output_manager_v1_get_xdg_output(_RGFW->xdg_output_manager, node->output);
9265+ zxdg_output_v1_add_listener(node->xdg_output, &xdg_output_listener, node);
9266+}
9267+
9268+static void RGFW_wl_surface_enter(void *data, struct wl_surface *wl_surface, struct wl_output *output) {
9269+ RGFW_UNUSED(wl_surface);
9270+
9271+ RGFW_window* win = (RGFW_window*)data;
9272+ RGFW_monitorNode* node = wl_output_get_user_data(output);
9273+ if (node == NULL) return;
9274+
9275+ win->src.active_monitor = node;
9276+}
9277+
9278+static void RGFW_wl_data_source_send(void *data, struct wl_data_source *wl_data_source, const char *mime_type, i32 fd) {
9279+ RGFW_UNUSED(data); RGFW_UNUSED(wl_data_source);
9280+
9281+ // a client can accept our clipboard
9282+ if (RGFW_STRNCMP(mime_type, "text/plain;charset=utf-8", 25) == 0) {
9283+ // do not write \0
9284+ write(fd, _RGFW->clipboard, _RGFW->clipboard_len - 1);
9285+ }
9286+
9287+ close(fd);
9288+}
9289+
9290+static void RGFW_wl_data_source_cancelled(void *data, struct wl_data_source *wl_data_source) {
9291+
9292+ RGFW_info* RGFW = (RGFW_info*)data;
9293+
9294+ if (RGFW->kbOwner->src.data_source == wl_data_source) {
9295+ RGFW->kbOwner->src.data_source = NULL;
9296+ }
9297+
9298+ wl_data_source_destroy(wl_data_source);
9299+
9300+}
9301+
9302+static void RGFW_wl_data_device_data_offer(void *data, struct wl_data_device *wl_data_device, struct wl_data_offer *wl_data_offer) {
9303+
9304+ RGFW_UNUSED(data); RGFW_UNUSED(wl_data_device);
9305+ static const struct wl_data_offer_listener wl_data_offer_listener = {
9306+ .offer = (void (*)(void *data, struct wl_data_offer *wl_data_offer, const char *))RGFW_doNothing,
9307+ .source_actions = (void (*)(void *data, struct wl_data_offer *wl_data_offer, u32 dnd_action))RGFW_doNothing,
9308+ .action = (void (*)(void *data, struct wl_data_offer *wl_data_offer, u32 dnd_action))RGFW_doNothing
9309+ };
9310+ wl_data_offer_add_listener(wl_data_offer, &wl_data_offer_listener, NULL);
9311+}
9312+
9313+static void RGFW_wl_data_device_selection(void *data, struct wl_data_device *wl_data_device, struct wl_data_offer *wl_data_offer) {
9314+ RGFW_UNUSED(data); RGFW_UNUSED(wl_data_device);
9315+ /* Clipboard is empty */
9316+ if (wl_data_offer == NULL) {
9317+ return;
9318+ }
9319+
9320+ int pfds[2];
9321+ pipe(pfds);
9322+
9323+ wl_data_offer_receive(wl_data_offer, "text/plain;charset=utf-8", pfds[1]);
9324+ close(pfds[1]);
9325+
9326+ wl_display_roundtrip(_RGFW->wl_display);
9327+
9328+ char buf[1024];
9329+
9330+ ssize_t n = read(pfds[0], buf, sizeof(buf));
9331+
9332+ _RGFW->clipboard = (char*)RGFW_ALLOC((size_t)n);
9333+ RGFW_ASSERT(_RGFW->clipboard != NULL);
9334+ RGFW_STRNCPY(_RGFW->clipboard, buf, (size_t)n);
9335+
9336+ _RGFW->clipboard_len = (size_t)n + 1;
9337+
9338+ close(pfds[0]);
9339+
9340+ wl_data_offer_destroy(wl_data_offer);
9341+
9342+}
9343+
9344+static void RGFW_wl_global_registry_handler(void* data, struct wl_registry *registry, u32 id, const char *interface, u32 version) {
9345+
9346+ static struct wl_seat_listener seat_listener = {&RGFW_wl_seat_capabilities, (void (*)(void *, struct wl_seat *, const char *))&RGFW_doNothing};
9347+ static const struct wl_shm_listener shm_listener = { .format = RGFW_wl_shm_format_handler };
9348+
9349+ RGFW_info* RGFW = (RGFW_info*)data;
9350+ RGFW_UNUSED(version);
9351+
9352+ if (RGFW_STRNCMP(interface, "wl_compositor", 16) == 0) {
9353+ RGFW->compositor = wl_registry_bind(registry, id, &wl_compositor_interface, 4);
9354+ } else if (RGFW_STRNCMP(interface, "xdg_wm_base", 12) == 0) {
9355+ RGFW->xdg_wm_base = wl_registry_bind(registry, id, &xdg_wm_base_interface, 1);
9356+ } else if (RGFW_STRNCMP(interface, zxdg_decoration_manager_v1_interface.name, 255) == 0) {
9357+ RGFW->decoration_manager = wl_registry_bind(registry, id, &zxdg_decoration_manager_v1_interface, 1);
9358+ } else if (RGFW_STRNCMP(interface, zwp_pointer_constraints_v1_interface.name, 255) == 0) {
9359+ RGFW->constraint_manager = wl_registry_bind(registry, id, &zwp_pointer_constraints_v1_interface, 1);
9360+ } else if (RGFW_STRNCMP(interface, zwp_relative_pointer_manager_v1_interface.name, 255) == 0) {
9361+ RGFW->relative_pointer_manager = wl_registry_bind(registry, id, &zwp_relative_pointer_manager_v1_interface, 1);
9362+ } else if (RGFW_STRNCMP(interface, xdg_toplevel_icon_manager_v1_interface.name, 255) == 0) {
9363+ RGFW->icon_manager = wl_registry_bind(registry, id, &xdg_toplevel_icon_manager_v1_interface, 1);
9364+ } else if (RGFW_STRNCMP(interface, "wl_shm", 7) == 0) {
9365+ RGFW->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
9366+ wl_shm_add_listener(RGFW->shm, &shm_listener, RGFW);
9367+ } else if (RGFW_STRNCMP(interface,"wl_seat", 8) == 0) {
9368+ RGFW->seat = wl_registry_bind(registry, id, &wl_seat_interface, version < 4 ? 3 : 4);
9369+ wl_seat_add_listener(RGFW->seat, &seat_listener, RGFW);
9370+ } else if (RGFW_STRNCMP(interface, zxdg_output_manager_v1_interface.name, 255) == 0) {
9371+ RGFW->xdg_output_manager = wl_registry_bind(registry, id, &zxdg_output_manager_v1_interface, 1);
9372+ } else if (RGFW_STRNCMP(interface,"wl_output", 10) == 0) {
9373+ RGFW_wl_create_outputs(registry, id);
9374+ } else if (RGFW_STRNCMP(interface, wp_pointer_warp_v1_interface.name, 255) == 0) {
9375+ RGFW->wp_pointer_warp = wl_registry_bind(registry, id, &wp_pointer_warp_v1_interface, 1);
9376+ } else if (RGFW_STRNCMP(interface,"wl_data_device_manager", 23) == 0) {
9377+ RGFW->data_device_manager = wl_registry_bind(registry, id, &wl_data_device_manager_interface, 1);
9378+ }
9379+}
9380+
9381+static void RGFW_wl_global_registry_remove(void* data, struct wl_registry *registry, u32 id) {
9382+ RGFW_UNUSED(data); RGFW_UNUSED(registry);
9383+ RGFW_info* RGFW = (RGFW_info*)data;
9384+ RGFW_monitorNode* prev = RGFW->monitors.list.head;
9385+ RGFW_monitorNode* node = NULL;
9386+ if (prev == NULL) return;
9387+
9388+ if (prev->id != id) {
9389+ /* find the first node that has a matching id */
9390+ while(prev->next != NULL && prev->next->id != id) {
9391+ prev = prev->next;
9392+ }
9393+
9394+ if (prev->next == NULL) return;
9395+ node = prev->next;
9396+ } else {
9397+ node = prev;
9398+ }
9399+
9400+ if (node->output) {
9401+ wl_output_destroy(node->output);
9402+ }
9403+
9404+ if (node->xdg_output) {
9405+ zxdg_output_v1_destroy(node->xdg_output);
9406+ }
9407+
9408+ if (node->modeCount) {
9409+ RGFW_FREE(node->modes);
9410+ node->modeCount = 0;
9411+ }
9412+
9413+ RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_FALSE);
9414+ RGFW_monitors_remove(node, prev);
9415+}
9416+
9417+static void RGFW_wl_randname(char *buf) {
9418+ struct timespec ts;
9419+ clock_gettime(CLOCK_REALTIME, &ts);
9420+ long r = ts.tv_nsec;
9421+
9422+ int i;
9423+ for (i = 0; i < 6; i++) {
9424+ buf[i] = (char)('A'+(r&15)+(r&16)*2);
9425+ r >>= 5;
9426+ }
9427+}
9428+
9429+static int RGFW_wl_anonymous_shm_open(void) {
9430+ char name[] = "/RGFW-wayland-XXXXXX";
9431+ int retries = 100;
9432+
9433+ do {
9434+ RGFW_wl_randname(name + RGFW_unix_stringlen(name) - 6);
9435+
9436+ --retries;
9437+ /* shm_open guarantees that O_CLOEXEC is set */
9438+ int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
9439+ if (fd >= 0) {
9440+ shm_unlink(name);
9441+ return fd;
9442+ }
9443+ } while (retries > 0 && errno == EEXIST);
9444+
9445+ return -1;
9446+}
9447+
9448+static int RGFW_wl_create_shm_file(off_t size) {
9449+ int fd = RGFW_wl_anonymous_shm_open();
9450+ if (fd < 0) {
9451+ return fd;
9452+ }
9453+
9454+ if (ftruncate(fd, size) < 0) {
9455+ close(fd);
9456+ return -1;
9457+ }
9458+
9459+ return fd;
9460+}
9461+
9462+i32 RGFW_initPlatform_Wayland(void) {
9463+ _RGFW->wl_display = wl_display_connect(NULL);
9464+ if (_RGFW->wl_display == NULL) {
9465+ RGFW_debugCallback(RGFW_typeError, RGFW_errWayland, "Failed to load Wayland display");
9466+ return -1;
9467+ }
9468+
9469+ _RGFW->compositor = NULL;
9470+ static const struct wl_registry_listener registry_listener = {
9471+ .global = RGFW_wl_global_registry_handler,
9472+ .global_remove = RGFW_wl_global_registry_remove,
9473+ };
9474+
9475+ _RGFW->registry = wl_display_get_registry(_RGFW->wl_display);
9476+ wl_registry_add_listener(_RGFW->registry, ®istry_listener, _RGFW);
9477+
9478+ wl_display_roundtrip(_RGFW->wl_display); /* bind to globals */
9479+
9480+ if (_RGFW->compositor == NULL) {
9481+ RGFW_debugCallback(RGFW_typeError, RGFW_errWayland, "Can't find compositor.");
9482+ return 1;
9483+ }
9484+
9485+ if (_RGFW->wl_cursor_theme == NULL) {
9486+ _RGFW->wl_cursor_theme = wl_cursor_theme_load(NULL, 24, _RGFW->shm);
9487+ _RGFW->cursor_surface = wl_compositor_create_surface(_RGFW->compositor);
9488+ }
9489+
9490+ u8 RGFW_blk[] = { 0, 0, 0, 0 };
9491+ _RGFW->hiddenMouse = RGFW_createMouse(RGFW_blk, 1, 1, RGFW_formatRGBA8);
9492+
9493+ static const struct xdg_wm_base_listener xdg_wm_base_listener = {
9494+ .ping = RGFW_wl_xdg_wm_base_ping_handler,
9495+ };
9496+
9497+ xdg_wm_base_add_listener(_RGFW->xdg_wm_base, &xdg_wm_base_listener, NULL);
9498+
9499+ _RGFW->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
9500+
9501+ static const struct wl_data_device_listener wl_data_device_listener = {
9502+ .data_offer = RGFW_wl_data_device_data_offer,
9503+ .enter = (void (*)(void *, struct wl_data_device *, u32, struct wl_surface*, wl_fixed_t, wl_fixed_t, struct wl_data_offer *))&RGFW_doNothing,
9504+ .leave = (void (*)(void *, struct wl_data_device *))&RGFW_doNothing,
9505+ .motion = (void (*)(void *, struct wl_data_device *, u32, wl_fixed_t, wl_fixed_t))&RGFW_doNothing,
9506+ .drop = (void (*)(void *, struct wl_data_device *))&RGFW_doNothing,
9507+ .selection = RGFW_wl_data_device_selection
9508+ };
9509+
9510+ if (_RGFW->seat && _RGFW->data_device_manager) {
9511+ _RGFW->data_device = wl_data_device_manager_get_data_device(_RGFW->data_device_manager, _RGFW->seat);
9512+ wl_data_device_add_listener(_RGFW->data_device, &wl_data_device_listener, NULL);
9513+ }
9514+
9515+ return 0;
9516+}
9517+
9518+void RGFW_deinitPlatform_Wayland(void) {
9519+ if (_RGFW->clipboard) {
9520+ RGFW_FREE(_RGFW->clipboard);
9521+ _RGFW->clipboard = NULL;
9522+ }
9523+
9524+ if (_RGFW->wl_pointer) {
9525+ wl_pointer_destroy(_RGFW->wl_pointer);
9526+ }
9527+ if (_RGFW->wl_keyboard) {
9528+ wl_keyboard_destroy(_RGFW->wl_keyboard);
9529+ }
9530+
9531+ wl_registry_destroy(_RGFW->registry);
9532+ if (_RGFW->decoration_manager != NULL)
9533+ zxdg_decoration_manager_v1_destroy(_RGFW->decoration_manager);
9534+ if (_RGFW->relative_pointer_manager != NULL) {
9535+ zwp_relative_pointer_manager_v1_destroy(_RGFW->relative_pointer_manager);
9536+ }
9537+
9538+ if (_RGFW->relative_pointer) {
9539+ zwp_relative_pointer_v1_destroy(_RGFW->relative_pointer);
9540+ }
9541+
9542+ if (_RGFW->constraint_manager != NULL) {
9543+ zwp_pointer_constraints_v1_destroy(_RGFW->constraint_manager);
9544+ }
9545+
9546+ if (_RGFW->xdg_output_manager != NULL)
9547+ if (_RGFW->icon_manager != NULL) {
9548+ xdg_toplevel_icon_manager_v1_destroy(_RGFW->icon_manager);
9549+ }
9550+
9551+ if (_RGFW->xdg_output_manager) {
9552+ zxdg_output_manager_v1_destroy(_RGFW->xdg_output_manager);
9553+ }
9554+
9555+ if (_RGFW->data_device_manager) {
9556+ wl_data_device_manager_destroy(_RGFW->data_device_manager);
9557+ }
9558+
9559+ if (_RGFW->data_device) {
9560+ wl_data_device_destroy(_RGFW->data_device);
9561+ }
9562+
9563+ if (_RGFW->wl_cursor_theme != NULL) {
9564+ wl_cursor_theme_destroy(_RGFW->wl_cursor_theme);
9565+ }
9566+
9567+ if (_RGFW->wp_pointer_warp != NULL) {
9568+ wp_pointer_warp_v1_destroy(_RGFW->wp_pointer_warp);
9569+ }
9570+
9571+ RGFW_freeMouse(_RGFW->hiddenMouse);
9572+
9573+ RGFW_monitorNode* node = _RGFW->monitors.list.head;
9574+
9575+ while (node != NULL) {
9576+ if (node->output) {
9577+ wl_output_destroy(node->output);
9578+ }
9579+
9580+ if (node->xdg_output) {
9581+ zxdg_output_v1_destroy(node->xdg_output);
9582+ }
9583+
9584+ _RGFW->monitors.count -= 1;
9585+ node = node->next;
9586+
9587+ }
9588+
9589+ wl_surface_destroy(_RGFW->cursor_surface);
9590+ wl_shm_destroy(_RGFW->shm);
9591+ wl_seat_release(_RGFW->seat);
9592+ xdg_wm_base_destroy(_RGFW->xdg_wm_base);
9593+ wl_compositor_destroy(_RGFW->compositor);
9594+ wl_display_disconnect(_RGFW->wl_display);
9595+}
9596+
9597+RGFW_format RGFW_FUNC(RGFW_nativeFormat)(void) { return RGFW_formatBGRA8; }
9598+
9599+RGFW_bool RGFW_FUNC(RGFW_createSurfacePtr) (u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) {
9600+ RGFW_ASSERT(surface != NULL);
9601+ surface->data = data;
9602+ surface->w = w;
9603+ surface->h = h;
9604+ surface->format = format;
9605+ RGFW_debugCallback(RGFW_typeInfo, RGFW_infoBuffer, "Creating a 4 channel buffer");
9606+
9607+ u32 size = (u32)(surface->w * surface->h * 4);
9608+ int fd = RGFW_wl_create_shm_file(size);
9609+ if (fd < 0) {
9610+ RGFW_debugCallback(RGFW_typeError, RGFW_errBuffer, "Failed to create a buffer.");
9611+ return RGFW_FALSE;
9612+ }
9613+
9614+ surface->native.pool = wl_shm_create_pool(_RGFW->shm, fd, (i32)size);
9615+
9616+ surface->native.buffer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
9617+ if (surface->native.buffer == MAP_FAILED) {
9618+ RGFW_debugCallback(RGFW_typeError, RGFW_errBuffer, "mmap failed.");
9619+ return RGFW_FALSE;
9620+ }
9621+
9622+ surface->native.fd = fd;
9623+ surface->native.format = RGFW_formatBGRA8;
9624+ return RGFW_TRUE;
9625+}
9626+
9627+void RGFW_FUNC(RGFW_window_blitSurface) (RGFW_window* win, RGFW_surface* surface) {
9628+ RGFW_ASSERT(surface != NULL);
9629+
9630+ surface->native.wl_buffer = wl_shm_pool_create_buffer(surface->native.pool, 0, RGFW_MIN(win->w, surface->w), RGFW_MIN(win->h, surface->h), (i32)surface->w * 4, WL_SHM_FORMAT_ARGB8888);
9631+ RGFW_copyImageData(surface->native.buffer, surface->w, RGFW_MIN(win->h, surface->h), surface->native.format, surface->data, surface->format, surface->convertFunc);
9632+
9633+ wl_surface_attach(win->src.surface, surface->native.wl_buffer, 0, 0);
9634+ wl_surface_damage(win->src.surface, 0, 0, RGFW_MIN(win->w, surface->w), RGFW_MIN(win->h, surface->h));
9635+ wl_surface_commit(win->src.surface);
9636+
9637+ wl_buffer_destroy(surface->native.wl_buffer);
9638+
9639+ surface->native.wl_buffer = NULL;
9640+}
9641+
9642+void RGFW_FUNC(RGFW_surface_freePtr) (RGFW_surface* surface) {
9643+ RGFW_ASSERT(surface != NULL);
9644+
9645+ if (surface->native.pool) wl_shm_pool_destroy(surface->native.pool);
9646+ if (surface->native.fd) close(surface->native.fd);
9647+ if (surface->native.buffer) munmap(surface->native.buffer, (size_t)(surface->w * surface->h * 4));
9648+}
9649+
9650+void RGFW_FUNC(RGFW_window_setBorder) (RGFW_window* win, RGFW_bool border) {
9651+ RGFW_setBit(&win->internal.flags, RGFW_windowNoBorder, !border);
9652+
9653+ /* for now just toggle between SSD & CSD depending on the bool */
9654+ if (_RGFW->decoration_manager != NULL) {
9655+ zxdg_toplevel_decoration_v1_set_mode(win->src.decoration, (border ? ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE : ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE));
9656+ }
9657+}
9658+
9659+void RGFW_FUNC(RGFW_window_setRawMouseModePlatform) (RGFW_window* win, RGFW_bool state) {
9660+ RGFW_ASSERT(win);
9661+ if (_RGFW->relative_pointer_manager == NULL) return;
9662+
9663+ if (state == RGFW_FALSE) {
9664+ if (_RGFW->relative_pointer != NULL)
9665+ zwp_relative_pointer_v1_destroy(_RGFW->relative_pointer);
9666+ _RGFW->relative_pointer = NULL;
9667+ return;
9668+ }
9669+
9670+ if (_RGFW->relative_pointer != NULL) return;
9671+
9672+ _RGFW->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(_RGFW->relative_pointer_manager, _RGFW->wl_pointer);
9673+
9674+ static const struct zwp_relative_pointer_v1_listener relative_motion_listener = {
9675+ .relative_motion = RGFW_wl_relative_pointer_motion
9676+ };
9677+
9678+ zwp_relative_pointer_v1_add_listener(_RGFW->relative_pointer, &relative_motion_listener, _RGFW);
9679+}
9680+
9681+void RGFW_FUNC(RGFW_window_captureMousePlatform) (RGFW_window* win, RGFW_bool state) {
9682+ RGFW_ASSERT(win);
9683+
9684+ /* compositor has no support or window already is locked do nothing */
9685+ if (_RGFW->constraint_manager == NULL) return;
9686+
9687+ if (state == RGFW_FALSE) {
9688+ if (win->src.locked_pointer != NULL)
9689+ zwp_locked_pointer_v1_destroy(win->src.locked_pointer);
9690+ win->src.locked_pointer = NULL;
9691+ return;
9692+ }
9693+
9694+
9695+ if (win->src.locked_pointer != NULL) return;
9696+ win->src.locked_pointer = zwp_pointer_constraints_v1_lock_pointer(_RGFW->constraint_manager, win->src.surface, _RGFW->wl_pointer, NULL, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
9697+
9698+ static const struct zwp_locked_pointer_v1_listener locked_listener = {
9699+ .locked = RGFW_wl_pointer_locked,
9700+ .unlocked = (void (*)(void *, struct zwp_locked_pointer_v1 *))RGFW_doNothing
9701+ };
9702+
9703+ zwp_locked_pointer_v1_add_listener(win->src.locked_pointer, &locked_listener, _RGFW);
9704+}
9705+
9706+RGFW_window* RGFW_FUNC(RGFW_createWindowPlatform) (const char* name, RGFW_windowFlags flags, RGFW_window* win) {
9707+ RGFW_debugCallback(RGFW_typeWarning, RGFW_warningWayland, "RGFW Wayland support is experimental");
9708+
9709+ static const struct xdg_surface_listener xdg_surface_listener = {
9710+ .configure = RGFW_wl_xdg_surface_configure_handler,
9711+ };
9712+
9713+ static const struct wl_surface_listener wl_surface_listener = {
9714+ .enter = RGFW_wl_surface_enter,
9715+ .leave = (void (*)(void *, struct wl_surface *, struct wl_output *))&RGFW_doNothing,
9716+ .preferred_buffer_scale = (void (*)(void *, struct wl_surface *, i32))&RGFW_doNothing,
9717+ .preferred_buffer_transform = (void (*)(void *, struct wl_surface *, u32))&RGFW_doNothing
9718+ };
9719+
9720+ win->src.surface = wl_compositor_create_surface(_RGFW->compositor);
9721+ wl_surface_add_listener(win->src.surface, &wl_surface_listener, win);
9722+
9723+ /* create a surface for a custom cursor */
9724+ win->src.custom_cursor_surface = wl_compositor_create_surface(_RGFW->compositor);
9725+
9726+ win->src.xdg_surface = xdg_wm_base_get_xdg_surface(_RGFW->xdg_wm_base, win->src.surface);
9727+ xdg_surface_add_listener(win->src.xdg_surface, &xdg_surface_listener, win);
9728+
9729+ xdg_wm_base_set_user_data(_RGFW->xdg_wm_base, win);
9730+
9731+ win->src.xdg_toplevel = xdg_surface_get_toplevel(win->src.xdg_surface);
9732+
9733+ if (_RGFW->className == NULL)
9734+ _RGFW->className = (char*)name;
9735+
9736+ xdg_toplevel_set_app_id(win->src.xdg_toplevel, name);
9737+
9738+ xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->w, win->h);
9739+
9740+ if (!(win->internal.flags & RGFW_windowTransparent)) { /* no transparency */
9741+ RGFW_wl_setOpaque(win);
9742+ }
9743+
9744+ static const struct xdg_toplevel_listener xdg_toplevel_listener = {
9745+ .configure = RGFW_wl_xdg_toplevel_configure_handler,
9746+ .close = RGFW_wl_xdg_toplevel_close_handler,
9747+ };
9748+
9749+ xdg_toplevel_add_listener(win->src.xdg_toplevel, &xdg_toplevel_listener, win);
9750+
9751+ /* compositor supports both SSD & CSD
9752+ So choose accordingly
9753+ */
9754+ if (_RGFW->decoration_manager) {
9755+ u32 decoration_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE;
9756+ win->src.decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(
9757+ _RGFW->decoration_manager, win->src.xdg_toplevel);
9758+
9759+ static const struct zxdg_toplevel_decoration_v1_listener xdg_decoration_listener = {
9760+ .configure = RGFW_wl_xdg_decoration_configure_handler
9761+ };
9762+
9763+ zxdg_toplevel_decoration_v1_add_listener(win->src.decoration, &xdg_decoration_listener, win);
9764+
9765+ /* we want no decorations */
9766+ if ((flags & RGFW_windowNoBorder)) {
9767+ decoration_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
9768+ }
9769+
9770+ zxdg_toplevel_decoration_v1_set_mode(win->src.decoration, decoration_mode);
9771+
9772+ /* no xdg_decoration support */
9773+ } else if (!(flags & RGFW_windowNoBorder)) {
9774+ /* TODO, some fallback */
9775+ #ifdef RGFW_LIBDECOR
9776+ static struct libdecor_interface interface = {
9777+ .error = NULL,
9778+ };
9779+
9780+ static struct libdecor_frame_interface frameInterface = {0}; /*= {
9781+ RGFW_wl_handle_configure,
9782+ RGFW_wl_handle_close,
9783+ RGFW_wl_handle_commit,
9784+ RGFW_wl_handle_dismiss_popup,
9785+ };*/
9786+
9787+ win->src.decorContext = libdecor_new(_RGFW->wl_display, &interface);
9788+ if (win->src.decorContext) {
9789+ struct libdecor_frame *frame = libdecor_decorate(win->src.decorContext, win->src.surface, &frameInterface, win);
9790+ if (!frame) {
9791+ libdecor_unref(win->src.decorContext);
9792+ win->src.decorContext = NULL;
9793+ } else {
9794+ libdecor_frame_set_app_id(frame, "my-libdecor-app");
9795+ libdecor_frame_set_title(frame, "My Libdecor Window");
9796+ }
9797+ }
9798+ #endif
9799+ }
9800+
9801+ if (_RGFW->icon_manager != NULL) {
9802+ /* set the default wayland icon */
9803+ xdg_toplevel_icon_manager_v1_set_icon(_RGFW->icon_manager, win->src.xdg_toplevel, NULL);
9804+ }
9805+
9806+ wl_surface_commit(win->src.surface);
9807+
9808+ while (win->src.configured == RGFW_FALSE) {
9809+ wl_display_dispatch(_RGFW->wl_display);
9810+ }
9811+
9812+ RGFW_UNUSED(name);
9813+
9814+ return win;
9815+}
9816+
9817+RGFW_bool RGFW_FUNC(RGFW_getGlobalMouse) (i32* x, i32* y) {
9818+ RGFW_init();
9819+ if (x) *x = 0;
9820+ if (y) *y = 0;
9821+ return RGFW_FALSE;
9822+}
9823+
9824+RGFW_key RGFW_FUNC(RGFW_physicalToMappedKey)(RGFW_key key) {
9825+ u32 keycode = RGFW_rgfwToApiKey(key);
9826+ xkb_keycode_t kc = keycode + 8;
9827+ xkb_keysym_t sym = xkb_state_key_get_one_sym(_RGFW->xkb_state, kc);
9828+ if (sym < 256) {
9829+ return (RGFW_key)sym;
9830+ }
9831+
9832+ switch (sym) {
9833+ case XKB_KEY_F1: return RGFW_keyF1;
9834+ case XKB_KEY_F2: return RGFW_keyF2;
9835+ case XKB_KEY_F3: return RGFW_keyF3;
9836+ case XKB_KEY_F4: return RGFW_keyF4;
9837+ case XKB_KEY_F5: return RGFW_keyF5;
9838+ case XKB_KEY_F6: return RGFW_keyF6;
9839+ case XKB_KEY_F7: return RGFW_keyF7;
9840+ case XKB_KEY_F8: return RGFW_keyF8;
9841+ case XKB_KEY_F9: return RGFW_keyF9;
9842+ case XKB_KEY_F10: return RGFW_keyF10;
9843+ case XKB_KEY_F11: return RGFW_keyF11;
9844+ case XKB_KEY_F12: return RGFW_keyF12;
9845+ case XKB_KEY_F13: return RGFW_keyF13;
9846+ case XKB_KEY_F14: return RGFW_keyF14;
9847+ case XKB_KEY_F15: return RGFW_keyF15;
9848+ case XKB_KEY_F16: return RGFW_keyF16;
9849+ case XKB_KEY_F17: return RGFW_keyF17;
9850+ case XKB_KEY_F18: return RGFW_keyF18;
9851+ case XKB_KEY_F19: return RGFW_keyF19;
9852+ case XKB_KEY_F20: return RGFW_keyF20;
9853+ case XKB_KEY_F21: return RGFW_keyF21;
9854+ case XKB_KEY_F22: return RGFW_keyF22;
9855+ case XKB_KEY_F23: return RGFW_keyF23;
9856+ case XKB_KEY_F24: return RGFW_keyF24;
9857+ case XKB_KEY_F25: return RGFW_keyF25;
9858+ case XKB_KEY_Shift_L: return RGFW_keyShiftL;
9859+ case XKB_KEY_Shift_R: return RGFW_keyShiftR;
9860+ case XKB_KEY_Control_L: return RGFW_keyControlL;
9861+ case XKB_KEY_Control_R: return RGFW_keyControlR;
9862+ case XKB_KEY_Alt_L: return RGFW_keyAltL;
9863+ case XKB_KEY_Alt_R: return RGFW_keyAltR;
9864+ case XKB_KEY_Super_L: return RGFW_keySuperL;
9865+ case XKB_KEY_Super_R: return RGFW_keySuperR;
9866+ case XKB_KEY_Caps_Lock: return RGFW_keyCapsLock;
9867+ case XKB_KEY_Num_Lock: return RGFW_keyNumLock;
9868+ case XKB_KEY_Scroll_Lock:return RGFW_keyScrollLock;
9869+ case XKB_KEY_Up: return RGFW_keyUp;
9870+ case XKB_KEY_Down: return RGFW_keyDown;
9871+ case XKB_KEY_Left: return RGFW_keyLeft;
9872+ case XKB_KEY_Right: return RGFW_keyRight;
9873+ case XKB_KEY_Home: return RGFW_keyHome;
9874+ case XKB_KEY_End: return RGFW_keyEnd;
9875+ case XKB_KEY_Page_Up: return RGFW_keyPageUp;
9876+ case XKB_KEY_Page_Down: return RGFW_keyPageDown;
9877+ case XKB_KEY_Insert: return RGFW_keyInsert;
9878+ case XKB_KEY_Menu: return RGFW_keyMenu;
9879+ case XKB_KEY_KP_Add: return RGFW_keyPadPlus;
9880+ case XKB_KEY_KP_Subtract: return RGFW_keyPadMinus;
9881+ case XKB_KEY_KP_Multiply: return RGFW_keyPadMultiply;
9882+ case XKB_KEY_KP_Divide: return RGFW_keyPadSlash;
9883+ case XKB_KEY_KP_Equal: return RGFW_keyPadEqual;
9884+ case XKB_KEY_KP_Enter: return RGFW_keyPadReturn;
9885+ case XKB_KEY_KP_Decimal: return RGFW_keyPadPeriod;
9886+ case XKB_KEY_KP_0: return RGFW_keyPad0;
9887+ case XKB_KEY_KP_1: return RGFW_keyPad1;
9888+ case XKB_KEY_KP_2: return RGFW_keyPad2;
9889+ case XKB_KEY_KP_3: return RGFW_keyPad3;
9890+ case XKB_KEY_KP_4: return RGFW_keyPad4;
9891+ case XKB_KEY_KP_5: return RGFW_keyPad5;
9892+ case XKB_KEY_KP_6: return RGFW_keyPad6;
9893+ case XKB_KEY_KP_7: return RGFW_keyPad7;
9894+ case XKB_KEY_KP_8: return RGFW_keyPad8;
9895+ case XKB_KEY_KP_9: return RGFW_keyPad9;
9896+ case XKB_KEY_Print: return RGFW_keyPrintScreen;
9897+ case XKB_KEY_Pause: return RGFW_keyPause;
9898+ default: break;
9899+ }
9900+
9901+ return RGFW_keyNULL;
9902+}
9903+
9904+RGFW_bool RGFW_FUNC(RGFW_window_fetchSize) (RGFW_window* win, i32* w, i32* h) {
9905+ return RGFW_window_getSize(win, w, h);
9906+}
9907+
9908+void RGFW_FUNC(RGFW_pollEvents) (void) {
9909+ RGFW_resetPrevState();
9910+
9911+ /* send buffered requests to compositor */
9912+ while (wl_display_flush(_RGFW->wl_display) == -1) {
9913+ /* compositor not responding to new requests */
9914+ /* so let's dispatch some events so the compositor responds */
9915+ if (errno == EAGAIN) {
9916+ if (wl_display_dispatch_pending(_RGFW->wl_display) == -1) {
9917+ return;
9918+ }
9919+ } else {
9920+ return;
9921+ }
9922+ }
9923+ if (_RGFW->wl_repeat_info_rate != 0 && _RGFW->last_key) {
9924+ u32 now = (u32)(RGFW_linux_getTimeNS() / 1000000);
9925+ if (now > _RGFW->last_key_time) {
9926+ RGFW_wl_send_key_event(_RGFW->last_key);
9927+ _RGFW->last_key_time = now + 1000 / (u32)_RGFW->wl_repeat_info_rate;
9928+ }
9929+ }
9930+
9931+ /* read the events; if empty this reads from the */
9932+ /* wayland file descriptor */
9933+ if (wl_display_dispatch(_RGFW->wl_display) == -1) {
9934+ return;
9935+ }
9936+
9937+}
9938+
9939+void RGFW_FUNC(RGFW_window_move) (RGFW_window* win, i32 x, i32 y) {
9940+ RGFW_ASSERT(win != NULL);
9941+ win->x = x;
9942+ win->y = y;
9943+}
9944+
9945+
9946+void RGFW_FUNC(RGFW_window_resize) (RGFW_window* win, i32 w, i32 h) {
9947+ RGFW_ASSERT(win != NULL);
9948+ win->w = w;
9949+ win->h = h;
9950+ if (_RGFW->compositor) {
9951+ xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->w, win->h);
9952+ #ifdef RGFW_OPENGL
9953+ if (win->src.ctx.egl)
9954+ wl_egl_window_resize(win->src.ctx.egl->eglWindow, (i32)w, (i32)h, 0, 0);
9955+ #endif
9956+ }
9957+}
9958+
9959+void RGFW_FUNC(RGFW_window_setAspectRatio) (RGFW_window* win, i32 w, i32 h) {
9960+ RGFW_ASSERT(win != NULL);
9961+
9962+ if (w == 0 && h == 0)
9963+ return;
9964+ xdg_toplevel_set_max_size(win->src.xdg_toplevel, (i32)w, (i32)h);
9965+}
9966+
9967+void RGFW_FUNC(RGFW_window_setMinSize) (RGFW_window* win, i32 w, i32 h) {
9968+ RGFW_ASSERT(win != NULL);
9969+ xdg_toplevel_set_min_size(win->src.xdg_toplevel, w, h);
9970+}
9971+
9972+void RGFW_FUNC(RGFW_window_setMaxSize) (RGFW_window* win, i32 w, i32 h) {
9973+ RGFW_ASSERT(win != NULL);
9974+ xdg_toplevel_set_max_size(win->src.xdg_toplevel, w, h);
9975+}
9976+
9977+void RGFW_toggleWaylandMaximized(RGFW_window* win, RGFW_bool maximized) {
9978+ win->src.maximized = maximized;
9979+ if (maximized) {
9980+ xdg_toplevel_set_maximized(win->src.xdg_toplevel);
9981+ } else {
9982+ xdg_toplevel_unset_maximized(win->src.xdg_toplevel);
9983+ }
9984+}
9985+
9986+void RGFW_FUNC(RGFW_window_maximize) (RGFW_window* win) {
9987+ win->internal.oldX = win->x;
9988+ win->internal.oldY = win->y;
9989+ win->internal.oldW = win->w;
9990+ win->internal.oldH = win->h;
9991+ RGFW_toggleWaylandMaximized(win, 1);
9992+ RGFW_window_fetchSize(win, NULL, NULL);
9993+ return;
9994+}
9995+
9996+void RGFW_FUNC(RGFW_window_focus)(RGFW_window* win) {
9997+ RGFW_ASSERT(win);
9998+}
9999+
10000+void RGFW_FUNC(RGFW_window_raise)(RGFW_window* win) {
10001+ RGFW_ASSERT(win);
10002+}
10003+
10004+void RGFW_FUNC(RGFW_window_setFullscreen)(RGFW_window* win, RGFW_bool fullscreen) {
10005+ RGFW_ASSERT(win != NULL);
10006+ if (fullscreen) {
10007+
10008+ win->internal.flags |= RGFW_windowFullscreen;
10009+ win->internal.oldX = win->x;
10010+ win->internal.oldY = win->y;
10011+ win->internal.oldW = win->w;
10012+ win->internal.oldH = win->h;
10013+ xdg_toplevel_set_fullscreen(win->src.xdg_toplevel, NULL); /* let the compositor decide */
10014+ } else {
10015+ win->internal.flags &= ~(u32)RGFW_windowFullscreen;
10016+ xdg_toplevel_unset_fullscreen(win->src.xdg_toplevel);
10017+ }
10018+
10019+}
10020+
10021+void RGFW_FUNC(RGFW_window_setFloating) (RGFW_window* win, RGFW_bool floating) {
10022+ RGFW_ASSERT(win != NULL);
10023+ RGFW_UNUSED(floating);
10024+}
10025+
10026+void RGFW_FUNC(RGFW_window_setOpacity) (RGFW_window* win, u8 opacity) {
10027+ RGFW_ASSERT(win != NULL);
10028+ RGFW_UNUSED(opacity);
10029+}
10030+
10031+void RGFW_FUNC(RGFW_window_minimize)(RGFW_window* win) {
10032+ RGFW_ASSERT(win != NULL);
10033+ if (RGFW_window_isMaximized(win)) return;
10034+ win->internal.oldX = win->x;
10035+ win->internal.oldY = win->y;
10036+ win->internal.oldW = win->w;
10037+ win->internal.oldH = win->h;
10038+ win->src.minimized = RGFW_TRUE;
10039+ xdg_toplevel_set_minimized(win->src.xdg_toplevel);
10040+}
10041+
10042+void RGFW_FUNC(RGFW_window_restore)(RGFW_window* win) {
10043+ RGFW_ASSERT(win != NULL);
10044+ RGFW_toggleWaylandMaximized(win, RGFW_FALSE);
10045+
10046+ RGFW_window_move(win, win->internal.oldX, win->internal.oldY);
10047+ RGFW_window_resize(win, win->internal.oldW, win->internal.oldH);
10048+
10049+ RGFW_window_show(win);
10050+ RGFW_window_move(win, win->internal.oldX, win->internal.oldY);
10051+ RGFW_window_resize(win, win->internal.oldW, win->internal.oldH);
10052+
10053+ RGFW_window_show(win);
10054+}
10055+
10056+RGFW_bool RGFW_FUNC(RGFW_window_isFloating)(RGFW_window* win) {
10057+ return (!RGFW_window_isFullscreen(win) && !RGFW_window_isMaximized(win));
10058+}
10059+
10060+void RGFW_FUNC(RGFW_window_setName) (RGFW_window* win, const char* name) {
10061+ RGFW_ASSERT(win != NULL);
10062+ if (name == NULL) name = "\0";
10063+
10064+ if (_RGFW->compositor)
10065+ xdg_toplevel_set_title(win->src.xdg_toplevel, name);
10066+}
10067+
10068+#ifndef RGFW_NO_PASSTHROUGH
10069+void RGFW_FUNC(RGFW_window_setMousePassthrough) (RGFW_window* win, RGFW_bool passthrough) {
10070+ RGFW_ASSERT(win != NULL);
10071+ RGFW_UNUSED(passthrough);
10072+}
10073+#endif /* RGFW_NO_PASSTHROUGH */
10074+
10075+RGFW_bool RGFW_FUNC(RGFW_window_setIconEx) (RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_icon type) {
10076+ RGFW_ASSERT(win != NULL);
10077+ RGFW_UNUSED(type);
10078+
10079+ if (_RGFW->icon_manager == NULL || w != h) return RGFW_FALSE;
10080+
10081+ if (win->src.icon) {
10082+ xdg_toplevel_icon_v1_destroy(win->src.icon);
10083+ win->src.icon= NULL;
10084+ }
10085+
10086+ RGFW_surface* surface = RGFW_createSurface(data, w, h, format);
10087+
10088+ if (surface == NULL) return RGFW_FALSE;
10089+
10090+ RGFW_copyImageData(surface->native.buffer, RGFW_MIN(w, surface->w), RGFW_MIN(h, surface->h), surface->native.format, surface->data, surface->format, NULL);
10091+
10092+ win->src.icon = xdg_toplevel_icon_manager_v1_create_icon(_RGFW->icon_manager);
10093+ xdg_toplevel_icon_v1_add_buffer(win->src.icon, surface->native.wl_buffer, 1);
10094+ xdg_toplevel_icon_manager_v1_set_icon(_RGFW->icon_manager, win->src.xdg_toplevel, win->src.icon);
10095+
10096+ RGFW_surface_free(surface);
10097+ return RGFW_TRUE;
10098+}
10099+
10100+RGFW_mouse* RGFW_FUNC(RGFW_createMouseStandard) (RGFW_mouseIcon mouse) {
10101+ char* cursorName = NULL;
10102+ switch (mouse) {
10103+ case RGFW_mouseNormal: cursorName = (char*)"left_ptr"; break;
10104+ case RGFW_mouseArrow: cursorName = (char*)"left_ptr"; break;
10105+ case RGFW_mouseIbeam: cursorName = (char*)"xterm"; break;
10106+ case RGFW_mouseCrosshair: cursorName = (char*)"crosshair"; break;
10107+ case RGFW_mousePointingHand: cursorName = (char*)"hand2"; break;
10108+ case RGFW_mouseResizeEW: cursorName = (char*)"sb_h_double_arrow"; break;
10109+ case RGFW_mouseResizeNS: cursorName = (char*)"sb_v_double_arrow"; break;
10110+ case RGFW_mouseResizeNWSE: cursorName = (char*)"top_left_corner"; break; /* or fd_double_arrow */
10111+ case RGFW_mouseResizeNESW: cursorName = (char*)"top_right_corner"; break; /* or bd_double_arrow */
10112+ case RGFW_mouseResizeNW: cursorName = (char*)"top_left_corner"; break;
10113+ case RGFW_mouseResizeN: cursorName = (char*)"top_side"; break;
10114+ case RGFW_mouseResizeNE: cursorName = (char*)"top_right_corner"; break;
10115+ case RGFW_mouseResizeE: cursorName = (char*)"right_side"; break;
10116+ case RGFW_mouseResizeSE: cursorName = (char*)"bottom_right_corner"; break;
10117+ case RGFW_mouseResizeS: cursorName = (char*)"bottom_side"; break;
10118+ case RGFW_mouseResizeSW: cursorName = (char*)"bottom_left_corner"; break;
10119+ case RGFW_mouseResizeW: cursorName = (char*)"left_side"; break;
10120+ case RGFW_mouseResizeAll: cursorName = (char*)"fleur"; break;
10121+ case RGFW_mouseNotAllowed: cursorName = (char*)"not-allowed"; break;
10122+ case RGFW_mouseWait: cursorName = (char*)"watch"; break;
10123+ case RGFW_mouseProgress: cursorName = (char*)"watch"; break;
10124+ default: return NULL;
10125+ }
10126+
10127+ struct wl_cursor* wlcursor = wl_cursor_theme_get_cursor(_RGFW->wl_cursor_theme, cursorName);
10128+ if (wlcursor == NULL)
10129+ return NULL;
10130+ struct wl_cursor_image* cursor_image = wlcursor->images[0];
10131+ struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(cursor_image);
10132+
10133+ RGFW_surface* surface = RGFW_ALLOC(sizeof(RGFW_surface));
10134+ RGFW_MEMZERO(surface, sizeof(RGFW_surface));
10135+ surface->w = (i32)cursor_image->width;
10136+ surface->h = (i32)cursor_image->height;
10137+ surface->native.wl_buffer = cursor_buffer;
10138+
10139+ return (RGFW_mouse*)surface;
10140+}
10141+
10142+RGFW_mouse* RGFW_FUNC(RGFW_createMouse)(u8* data, i32 w, i32 h, RGFW_format format) {
10143+ RGFW_surface* surface = RGFW_createSurface(data, w, h, format);
10144+ if (surface == NULL) return NULL;
10145+
10146+ surface->native.wl_buffer = wl_shm_pool_create_buffer(surface->native.pool, 0, surface->w, surface->h, (i32)surface->w * 4, WL_SHM_FORMAT_ARGB8888);
10147+
10148+ RGFW_copyImageData(surface->native.buffer, RGFW_MIN(w, surface->w), RGFW_MIN(h, surface->h), surface->native.format, surface->data, surface->format, NULL);
10149+
10150+ return (RGFW_mouse*)surface;
10151+}
10152+
10153+RGFW_bool RGFW_FUNC(RGFW_window_setMousePlatform)(RGFW_window* win, RGFW_mouse* mouse) {
10154+ RGFW_ASSERT(win); RGFW_ASSERT(mouse);
10155+ RGFW_surface* surface = (RGFW_surface*)mouse;
10156+
10157+ win->src.using_custom_cursor = RGFW_TRUE;
10158+
10159+ wl_surface_attach(win->src.custom_cursor_surface, surface->native.wl_buffer, 0, 0);
10160+ wl_surface_damage(win->src.custom_cursor_surface, 0, 0, surface->w, surface->h);
10161+ wl_surface_commit(win->src.custom_cursor_surface);
10162+
10163+ return RGFW_TRUE;
10164+}
10165+
10166+void RGFW_FUNC(RGFW_freeMouse)(RGFW_mouse* mouse) {
10167+ if (mouse != NULL) {
10168+ RGFW_surface* surface = (RGFW_surface*)mouse;
10169+
10170+ if (surface->native.buffer && surface->native.wl_buffer) {
10171+ wl_buffer_destroy(surface->native.wl_buffer);
10172+ }
10173+
10174+ RGFW_surface_free(surface);
10175+ }
10176+}
10177+
10178+void RGFW_FUNC(RGFW_window_moveMouse)(RGFW_window* win, i32 x, i32 y) {
10179+ if (_RGFW->wp_pointer_warp != NULL) {
10180+ wp_pointer_warp_v1_warp_pointer(_RGFW->wp_pointer_warp, win->src.surface, _RGFW->wl_pointer, wl_fixed_from_int(x), wl_fixed_from_int(y), _RGFW->mouse_enter_serial);
10181+ }
10182+}
10183+
10184+void RGFW_FUNC(RGFW_window_hide) (RGFW_window* win) {
10185+ wl_surface_attach(win->src.surface, NULL, 0, 0);
10186+ wl_surface_commit(win->src.surface);
10187+ win->internal.flags |= RGFW_windowHide;
10188+}
10189+
10190+void RGFW_FUNC(RGFW_window_show) (RGFW_window* win) {
10191+ win->internal.flags &= ~(u32)RGFW_windowHide;
10192+ if (win->internal.flags & RGFW_windowFocusOnShow) RGFW_window_focus(win);
10193+ /* wl_surface_attach(win->src.surface, win->x, win->y, win->w, win->h, 0, 0); */
10194+ wl_surface_commit(win->src.surface);
10195+}
10196+
10197+void RGFW_FUNC(RGFW_window_flash) (RGFW_window* win, RGFW_flashRequest request) {
10198+ if (RGFW_window_isInFocus(win) && request) {
10199+ return;
10200+ }
10201+}
10202+
10203+RGFW_ssize_t RGFW_FUNC(RGFW_readClipboardPtr) (char* str, size_t strCapacity) {
10204+
10205+ RGFW_UNUSED(strCapacity);
10206+
10207+ if (str != NULL)
10208+ RGFW_STRNCPY(str, _RGFW->clipboard, _RGFW->clipboard_len - 1);
10209+ _RGFW->clipboard[_RGFW->clipboard_len - 1] = '\0';
10210+ return (RGFW_ssize_t)_RGFW->clipboard_len - 1;
10211+}
10212+
10213+void RGFW_FUNC(RGFW_writeClipboard) (const char* text, u32 textLen) {
10214+
10215+ // compositor does not support wl_data_device_manager
10216+ // clients cannot read rgfw's clipboard
10217+ if (_RGFW->data_device_manager == NULL) return;
10218+ // clear the clipboard
10219+ if (_RGFW->clipboard)
10220+ RGFW_FREE(_RGFW->clipboard);
10221+
10222+ // set the contents
10223+ _RGFW->clipboard = (char*)RGFW_ALLOC(textLen);
10224+ RGFW_ASSERT(_RGFW->clipboard != NULL);
10225+ RGFW_STRNCPY(_RGFW->clipboard, text, textLen - 1);
10226+ _RGFW->clipboard[textLen - 1] = '\0';
10227+ _RGFW->clipboard_len = textLen;
10228+
10229+ // means we already wrote to the clipboard
10230+ // so destroy it to create a new one
10231+ RGFW_window* win = _RGFW->kbOwner;
10232+
10233+ if (win->src.data_source != NULL) {
10234+ wl_data_source_destroy(win->src.data_source);
10235+ win->src.data_source = NULL;
10236+ }
10237+
10238+ // advertise to other clients that we offer text
10239+ win->src.data_source = wl_data_device_manager_create_data_source(_RGFW->data_device_manager);
10240+
10241+ // basic error checking
10242+ if (win->src.data_source == NULL) {
10243+ RGFW_debugCallback(RGFW_typeError, RGFW_errClipboard, "Could not create clipboard data source");
10244+ return;
10245+ }
10246+ wl_data_source_offer(win->src.data_source , "text/plain;charset=utf-8");
10247+
10248+ // needed RGFW_doNothing because wayland will call the functions
10249+ // if not set they are random data that lead to a crash
10250+ static const struct wl_data_source_listener data_source_listener = {
10251+ .target = (void (*)(void *, struct wl_data_source *, const char *))&RGFW_doNothing,
10252+ .action = (void (*)(void *, struct wl_data_source *, u32))&RGFW_doNothing,
10253+ .dnd_drop_performed = (void (*)(void *, struct wl_data_source *))&RGFW_doNothing,
10254+ .dnd_finished = (void (*)(void *, struct wl_data_source *))&RGFW_doNothing,
10255+ .send = RGFW_wl_data_source_send,
10256+ .cancelled = RGFW_wl_data_source_cancelled
10257+ };
10258+
10259+ wl_data_source_add_listener(win->src.data_source, &data_source_listener, _RGFW);
10260+
10261+}
10262+
10263+RGFW_bool RGFW_FUNC(RGFW_window_isHidden) (RGFW_window* win) {
10264+ RGFW_ASSERT(win != NULL);
10265+ return RGFW_FALSE;
10266+}
10267+
10268+RGFW_bool RGFW_FUNC(RGFW_window_isMinimized) (RGFW_window* win) {
10269+ RGFW_ASSERT(win != NULL);
10270+ return win->src.minimized;
10271+}
10272+
10273+RGFW_bool RGFW_FUNC(RGFW_window_isMaximized) (RGFW_window* win) {
10274+ RGFW_ASSERT(win != NULL);
10275+ return win->src.maximized;
10276+}
10277+
10278+void RGFW_FUNC(RGFW_pollMonitors) (void) {
10279+ _RGFW->monitors.primary = _RGFW->monitors.list.head;
10280+}
10281+
10282+
10283+RGFW_bool RGFW_FUNC(RGFW_monitor_getWorkarea) (RGFW_monitor* monitor, i32* x, i32* y, i32* width, i32* height) {
10284+ /* NOTE: Wayland has no way to get the actual workarea as far as I'm aware :( */
10285+ if (x) *x = monitor->x;
10286+ if (y) *y = monitor->y;
10287+ if (width) *width = monitor->mode.w;
10288+ if (height) *height = monitor->mode.h;
10289+ return RGFW_TRUE;
10290+}
10291+
10292+size_t RGFW_FUNC(RGFW_monitor_getModesPtr) (RGFW_monitor* monitor, RGFW_monitorMode** modes) {
10293+ if (modes) {
10294+ RGFW_MEMCPY((*modes), monitor->node->modes, monitor->node->modeCount * sizeof(RGFW_monitorMode));
10295+ }
10296+
10297+ return monitor->node->modeCount;
10298+}
10299+
10300+size_t RGFW_FUNC(RGFW_monitor_getGammaRampPtr) (RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
10301+ RGFW_UNUSED(monitor); RGFW_UNUSED(ramp);
10302+ return 0;
10303+}
10304+
10305+RGFW_bool RGFW_FUNC(RGFW_monitor_setGammaRamp) (RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
10306+ RGFW_UNUSED(monitor); RGFW_UNUSED(ramp);
10307+ return RGFW_FALSE;
10308+}
10309+
10310+RGFW_bool RGFW_FUNC(RGFW_monitor_requestMode) (RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request) {
10311+ for (size_t i = 0; i < mon->node->modeCount; i++) {
10312+ if (RGFW_monitorModeCompare(mode, &mon->node->modes[i], request) == RGFW_FALSE) {
10313+ continue;
10314+ }
10315+
10316+ RGFW_monitor_setMode(mon, &mon->node->modes[i]);
10317+ return RGFW_TRUE;
10318+ }
10319+
10320+ return RGFW_FALSE;
10321+}
10322+
10323+RGFW_bool RGFW_FUNC(RGFW_monitor_setMode) (RGFW_monitor* mon, RGFW_monitorMode* mode) {
10324+ RGFW_UNUSED(mon); RGFW_UNUSED(mode);
10325+ return RGFW_FALSE;
10326+}
10327+
10328+RGFW_monitor* RGFW_FUNC(RGFW_window_getMonitor) (RGFW_window* win) {
10329+ RGFW_ASSERT(win);
10330+ if (win->src.active_monitor == NULL) {
10331+ /* TODO: fix race condition [probably a problem with wayland] */
10332+ return RGFW_getPrimaryMonitor();
10333+ }
10334+
10335+ return &win->src.active_monitor->mon;
10336+}
10337+
10338+#ifdef RGFW_OPENGL
10339+RGFW_bool RGFW_FUNC(RGFW_extensionSupportedPlatform_OpenGL) (const char * extension, size_t len) { return RGFW_extensionSupportedPlatform_EGL(extension, len); }
10340+RGFW_proc RGFW_FUNC(RGFW_getProcAddress_OpenGL) (const char* procname) { return RGFW_getProcAddress_EGL(procname); }
10341+
10342+
10343+RGFW_bool RGFW_FUNC(RGFW_window_createContextPtr_OpenGL)(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints) {
10344+ RGFW_bool out = RGFW_window_createContextPtr_EGL(win, &ctx->egl, hints);
10345+ win->src.gfxType = RGFW_gfxNativeOpenGL;
10346+
10347+ RGFW_window_swapInterval_OpenGL(win, 0);
10348+ return out;
10349+}
10350+void RGFW_FUNC(RGFW_window_deleteContextPtr_OpenGL) (RGFW_window* win, RGFW_glContext* ctx) { RGFW_window_deleteContextPtr_EGL(win, &ctx->egl); win->src.ctx.native = NULL; }
10351+
10352+void RGFW_FUNC(RGFW_window_makeCurrentContext_OpenGL) (RGFW_window* win) { RGFW_window_makeCurrentContext_EGL(win); }
10353+void* RGFW_FUNC(RGFW_getCurrentContext_OpenGL) (void) { return RGFW_getCurrentContext_EGL(); }
10354+void RGFW_FUNC(RGFW_window_swapBuffers_OpenGL) (RGFW_window* win) { RGFW_window_swapBuffers_EGL(win); }
10355+void RGFW_FUNC(RGFW_window_swapInterval_OpenGL) (RGFW_window* win, i32 swapInterval) { RGFW_window_swapInterval_EGL(win, swapInterval); }
10356+#endif /* RGFW_OPENGL */
10357+
10358+void RGFW_FUNC(RGFW_window_closePlatform)(RGFW_window* win) {
10359+ RGFW_ASSERT(win != NULL);
10360+ RGFW_debugCallback(RGFW_typeInfo, RGFW_infoWindow, "a window was freed");
10361+ #ifdef RGFW_LIBDECOR
10362+ if (win->src.decorContext)
10363+ libdecor_unref(win->src.decorContext);
10364+ #endif
10365+
10366+ if (win->src.decoration) {
10367+ zxdg_toplevel_decoration_v1_destroy(win->src.decoration);
10368+ }
10369+
10370+ if (win->src.xdg_toplevel) {
10371+ xdg_toplevel_destroy(win->src.xdg_toplevel);
10372+ }
10373+
10374+ wl_surface_destroy(win->src.custom_cursor_surface);
10375+
10376+ if (win->src.locked_pointer) {
10377+ zwp_locked_pointer_v1_destroy(win->src.locked_pointer);
10378+ }
10379+
10380+ if (win->src.icon) {
10381+ xdg_toplevel_icon_v1_destroy(win->src.icon);
10382+ }
10383+
10384+ xdg_surface_destroy(win->src.xdg_surface);
10385+ wl_surface_destroy(win->src.surface);
10386+}
10387+
10388+#ifdef RGFW_WEBGPU
10389+WGPUSurface RGFW_FUNC(RGFW_window_createSurface_WebGPU) (RGFW_window* window, WGPUInstance instance) {
10390+ WGPUSurfaceDescriptor surfaceDesc = {0};
10391+ WGPUSurfaceSourceWaylandSurface fromWl = {0};
10392+ fromWl.chain.sType = WGPUSType_SurfaceSourceWaylandSurface;
10393+ fromWl.display = _RGFW->wl_display;
10394+ fromWl.surface = window->src.surface;
10395+
10396+ surfaceDesc.nextInChain = (WGPUChainedStruct*)&fromWl.chain;
10397+ return wgpuInstanceCreateSurface(instance, &surfaceDesc);
10398+}
10399+#endif
10400+
10401+
10402+
10403+#endif /* RGFW_WAYLAND */
10404+/*
10405+ End of Wayland defines
10406+*/
10407+
10408+/*
10409+
10410+ Start of Windows defines
10411+
10412+
10413+*/
10414+
10415+#ifdef RGFW_WINDOWS
10416+#ifndef WIN32_LEAN_AND_MEAN
10417+ #define WIN32_LEAN_AND_MEAN
10418+#endif
10419+
10420+#ifndef OEMRESOURCE
10421+ #define OEMRESOURCE
10422+#endif
10423+
10424+#include <windows.h>
10425+
10426+#ifndef OCR_NORMAL
10427+#define OCR_NORMAL 32512
10428+#define OCR_IBEAM 32513
10429+#define OCR_WAIT 32514
10430+#define OCR_CROSS 32515
10431+#define OCR_UP 32516
10432+#define OCR_SIZENWSE 32642
10433+#define OCR_SIZENESW 32643
10434+#define OCR_SIZEWE 32644
10435+#define OCR_SIZENS 32645
10436+#define OCR_SIZEALL 32646
10437+#define OCR_NO 32648
10438+#define OCR_HAND 32649
10439+#define OCR_APPSTARTING 32650
10440+#endif
10441+
10442+#include <windowsx.h>
10443+#include <shellapi.h>
10444+#include <shellscalingapi.h>
10445+#include <wchar.h>
10446+#include <locale.h>
10447+#include <winuser.h>
10448+
10449+#ifndef WM_DPICHANGED
10450+#define WM_DPICHANGED 0x02E0
10451+#endif
10452+
10453+RGFWDEF DWORD RGFW_winapi_window_getStyle(RGFW_window* win, RGFW_windowFlags flags);
10454+DWORD RGFW_winapi_window_getStyle(RGFW_window* win, RGFW_windowFlags flags) {
10455+ RGFW_UNUSED(win);
10456+ DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
10457+
10458+ if ((flags & RGFW_windowFullscreen)) {
10459+ style |= WS_POPUP;
10460+ } else {
10461+ style |= WS_SYSMENU | WS_MINIMIZEBOX;
10462+
10463+ if (!(flags & RGFW_windowNoBorder)) {
10464+ style |= WS_CAPTION;
10465+
10466+ if (!(flags & RGFW_windowNoResize))
10467+ style |= WS_MAXIMIZEBOX | WS_THICKFRAME;
10468+ }
10469+ else
10470+ style |= WS_POPUP;
10471+ }
10472+
10473+ return style;
10474+}
10475+
10476+RGFWDEF DWORD RGFW_winapi_window_getExStyle(RGFW_window* win, RGFW_windowFlags flags);
10477+DWORD RGFW_winapi_window_getExStyle(RGFW_window* win, RGFW_windowFlags flags) {
10478+ DWORD style = WS_EX_APPWINDOW;
10479+ if (flags & RGFW_windowFullscreen || (flags & RGFW_windowFloating || RGFW_window_isFloating(win))) {
10480+ style |= WS_EX_TOPMOST;
10481+ }
10482+
10483+ return style;
10484+}
10485+
10486+RGFW_bool RGFW_createUTF8FromWideStringWin32(const WCHAR* source, char* out, size_t max);
10487+
10488+#define GL_FRONT 0x0404
10489+#define GL_BACK 0x0405
10490+#define GL_LEFT 0x0406
10491+#define GL_RIGHT 0x0407
10492+
10493+typedef int (*PFN_wglGetSwapIntervalEXT)(void);
10494+PFN_wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc = NULL;
10495+#define wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc
10496+
10497+/* these two wgl functions need to be preloaded */
10498+typedef HGLRC (WINAPI *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC hdc, HGLRC hglrc, const int *attribList);
10499+PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL;
10500+
10501+HMODULE RGFW_wgl_dll = NULL;
10502+
10503+#ifndef RGFW_NO_LOAD_WGL
10504+ typedef HGLRC(WINAPI* PFN_wglCreateContext)(HDC);
10505+ typedef BOOL(WINAPI* PFN_wglDeleteContext)(HGLRC);
10506+ typedef PROC(WINAPI* PFN_wglGetProcAddress)(LPCSTR);
10507+ typedef BOOL(WINAPI* PFN_wglMakeCurrent)(HDC, HGLRC);
10508+ typedef HDC(WINAPI* PFN_wglGetCurrentDC)(void);
10509+ typedef HGLRC(WINAPI* PFN_wglGetCurrentContext)(void);
10510+ typedef BOOL(WINAPI* PFN_wglShareLists)(HGLRC, HGLRC);
10511+
10512+ PFN_wglCreateContext wglCreateContextSRC;
10513+ PFN_wglDeleteContext wglDeleteContextSRC;
10514+ PFN_wglGetProcAddress wglGetProcAddressSRC;
10515+ PFN_wglMakeCurrent wglMakeCurrentSRC;
10516+ PFN_wglGetCurrentDC wglGetCurrentDCSRC;
10517+ PFN_wglGetCurrentContext wglGetCurrentContextSRC;
10518+ PFN_wglShareLists wglShareListsSRC;
10519+
10520+ #define wglCreateContext wglCreateContextSRC
10521+ #define wglDeleteContext wglDeleteContextSRC
10522+ #define wglGetProcAddress wglGetProcAddressSRC
10523+ #define wglMakeCurrent wglMakeCurrentSRC
10524+ #define wglGetCurrentDC wglGetCurrentDCSRC
10525+ #define wglGetCurrentContext wglGetCurrentContextSRC
10526+ #define wglShareLists wglShareListsSRC
10527+#endif
10528+
10529+void* RGFW_window_getHWND(RGFW_window* win) { return win->src.window; }
10530+void* RGFW_window_getHDC(RGFW_window* win) { return win->src.hdc; }
10531+
10532+#ifdef RGFW_OPENGL
10533+RGFWDEF void RGFW_win32_loadOpenGLFuncs(HWND dummyWin);
10534+
10535+typedef HRESULT (APIENTRY* PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats);
10536+PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL;
10537+
10538+typedef BOOL(APIENTRY* PFNWGLSWAPINTERVALEXTPROC)(int interval);
10539+PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
10540+#endif
10541+
10542+#ifndef RGFW_NO_DWM
10543+HMODULE RGFW_dwm_dll = NULL;
10544+#ifndef _DWMAPI_H_
10545+typedef struct { DWORD dwFlags; int fEnable; HRGN hRgnBlur; int fTransitionOnMaximized;} DWM_BLURBEHIND;
10546+#endif
10547+typedef HRESULT (WINAPI * PFN_DwmEnableBlurBehindWindow)(HWND, const DWM_BLURBEHIND*);
10548+PFN_DwmEnableBlurBehindWindow DwmEnableBlurBehindWindowSRC = NULL;
10549+
10550+typedef HRESULT (WINAPI * PFN_DwmSetWindowAttribute)(HWND, DWORD, LPCVOID, DWORD);
10551+PFN_DwmSetWindowAttribute DwmSetWindowAttributeSRC = NULL;
10552+#endif
10553+void RGFW_win32_makeWindowTransparent(RGFW_window* win);
10554+void RGFW_win32_makeWindowTransparent(RGFW_window* win) {
10555+ if (!(win->internal.flags & RGFW_windowTransparent)) return;
10556+
10557+ #ifndef RGFW_NO_DWM
10558+ if (DwmEnableBlurBehindWindowSRC != NULL) {
10559+ DWM_BLURBEHIND bb = {0, 0, 0, 0};
10560+ bb.dwFlags = 0x1;
10561+ bb.fEnable = TRUE;
10562+ bb.hRgnBlur = NULL;
10563+ DwmEnableBlurBehindWindowSRC(win->src.window, &bb);
10564+
10565+ } else
10566+ #endif
10567+ {
10568+ SetWindowLong(win->src.window, GWL_EXSTYLE, WS_EX_LAYERED);
10569+ SetLayeredWindowAttributes(win->src.window, 0, 128, LWA_ALPHA);
10570+ }
10571+}
10572+
10573+RGFWDEF RGFW_bool RGFW_win32_getDarkModeState(void);
10574+RGFW_bool RGFW_win32_getDarkModeState(void) {
10575+ u32 lightMode = 1;
10576+#if (_WIN32_WINNT >= 0x0600)
10577+ DWORD len = sizeof(lightMode);
10578+
10579+ RegGetValueW(
10580+ HKEY_CURRENT_USER,
10581+ L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
10582+ L"AppsUseLightTheme", RRF_RT_REG_DWORD, NULL, &lightMode, &len
10583+ );
10584+#endif
10585+
10586+ return (lightMode == 0);
10587+}
10588+
10589+RGFWDEF void RGFW_win32_makeWindowDarkMode(RGFW_window* win, RGFW_bool state);
10590+void RGFW_win32_makeWindowDarkMode(RGFW_window* win, RGFW_bool state) {
10591+ BOOL value = (state == RGFW_TRUE) ? TRUE : FALSE;
10592+ DwmSetWindowAttributeSRC(win->src.window, 20 /* DWMWA_USE_IMMERSIVE_DARK_MODE */, &value, sizeof(value));
10593+}
10594+
10595+LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
10596+LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
10597+ RGFW_window* win = (RGFW_window*)GetPropW(hWnd, L"RGFW");
10598+ if (win == NULL) return DefWindowProcW(hWnd, message, wParam, lParam);
10599+
10600+ static BYTE keyboardState[256];
10601+ GetKeyboardState(keyboardState);
10602+
10603+ RECT frame;
10604+ ZeroMemory(&frame, sizeof(frame));
10605+ DWORD style = RGFW_winapi_window_getStyle(win, win->internal.flags);
10606+ DWORD exStyle = RGFW_winapi_window_getExStyle(win, win->internal.flags);
10607+ AdjustWindowRectEx(&frame, style, FALSE, exStyle);
10608+
10609+ switch (message) {
10610+ case WM_DISPLAYCHANGE:
10611+ RGFW_pollMonitors();
10612+ break;
10613+ case WM_CLOSE:
10614+ case WM_QUIT:
10615+ RGFW_windowCloseCallback(win);
10616+ return 0;
10617+ case WM_ACTIVATE: {
10618+ RGFW_bool inFocus = RGFW_BOOL(LOWORD(wParam) != WA_INACTIVE);
10619+ RGFW_windowFocusCallback(win, inFocus);
10620+
10621+ return DefWindowProcW(hWnd, message, wParam, lParam);
10622+ }
10623+ case WM_MOVE:
10624+ if (win->internal.captureMouse) {
10625+ RGFW_window_captureMousePlatform(win, RGFW_TRUE);
10626+ }
10627+
10628+ RGFW_windowMovedCallback(win, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
10629+ return DefWindowProcW(hWnd, message, wParam, lParam);
10630+ case WM_SIZE: {
10631+ if (win->internal.captureMouse) {
10632+ RGFW_window_captureMousePlatform(win, RGFW_TRUE);
10633+ }
10634+
10635+ RGFW_windowResizedCallback(win, LOWORD(lParam), HIWORD(lParam));
10636+ RGFW_window_checkMode(win);
10637+ return DefWindowProcW(hWnd, message, wParam, lParam);
10638+ }
10639+ case WM_MOUSEACTIVATE: {
10640+ if (HIWORD(lParam) == WM_LBUTTONDOWN) {
10641+ if (LOWORD(lParam) != HTCLIENT)
10642+ win->src.actionFrame = RGFW_TRUE;
10643+ }
10644+
10645+ break;
10646+ }
10647+ case WM_CAPTURECHANGED: {
10648+ if (lParam == 0 && win->src.actionFrame) {
10649+ RGFW_window_captureMousePlatform(win, win->internal.captureMouse);
10650+ win->src.actionFrame = RGFW_FALSE;
10651+ }
10652+
10653+ break;
10654+ }
10655+ #ifndef RGFW_NO_DPI
10656+ case WM_DPICHANGED: {
10657+ const float scaleX = HIWORD(wParam) / (float) 96;
10658+ const float scaleY = LOWORD(wParam) / (float) 96;
10659+
10660+ RGFW_scaleUpdatedCallback(win, scaleX, scaleY);
10661+ return DefWindowProcW(hWnd, message, wParam, lParam);
10662+ }
10663+ #endif
10664+ case WM_SIZING: {
10665+ if (win->src.aspectRatioW == 0 && win->src.aspectRatioH == 0) {
10666+ break;
10667+ }
10668+
10669+ RECT* area = (RECT*)lParam;
10670+ i32 edge = (i32)wParam;
10671+
10672+ double ratio = (double)win->src.aspectRatioW / (double) win->src.aspectRatioH;
10673+
10674+ if (edge == WMSZ_LEFT || edge == WMSZ_BOTTOMLEFT || edge == WMSZ_RIGHT || edge == WMSZ_BOTTOMRIGHT) {
10675+ area->bottom = area->top + (frame.bottom - frame.top) + (i32) (((area->right - area->left) - (frame.right - frame.left)) / ratio);
10676+ } else if (edge == WMSZ_TOPLEFT || edge == WMSZ_TOPRIGHT) {
10677+ area->top = area->bottom - (frame.bottom - frame.top) - (i32) (((area->right - area->left) - (frame.right - frame.left)) / ratio);
10678+ } else if (edge == WMSZ_TOP || edge == WMSZ_BOTTOM) {
10679+ area->right = area->left + (frame.right - frame.left) + (i32) (((area->bottom - area->top) - (frame.bottom - frame.top)) * ratio);
10680+ }
10681+
10682+ return TRUE;
10683+ }
10684+ case WM_GETMINMAXINFO: {
10685+ MINMAXINFO* mmi = (MINMAXINFO*) lParam;
10686+ RGFW_bool resize = ((win->src.minSizeW == win->src.maxSizeW) && (win->src.minSizeH == win->src.maxSizeH));
10687+ RGFW_setBit(&win->internal.flags, RGFW_windowNoResize, resize);
10688+
10689+ mmi->ptMinTrackSize.x = (LONG)(win->src.minSizeW + (frame.right - frame.left));
10690+ mmi->ptMinTrackSize.y = (LONG)(win->src.minSizeH + (frame.bottom - frame.top));
10691+ if (win->src.maxSizeW == 0 && win->src.maxSizeH == 0)
10692+ return DefWindowProcW(hWnd, message, wParam, lParam);
10693+
10694+ mmi->ptMaxTrackSize.x = (LONG)(win->src.maxSizeW + (frame.right - frame.left));
10695+ mmi->ptMaxTrackSize.y = (LONG)(win->src.maxSizeH + (frame.bottom - frame.top));
10696+ return DefWindowProcW(hWnd, message, wParam, lParam);
10697+ }
10698+ case WM_PAINT: {
10699+ PAINTSTRUCT ps;
10700+ BeginPaint(hWnd, &ps);
10701+ RGFW_windowRefreshCallback(win, 0, 0, win->w, win->h);
10702+ EndPaint(hWnd, &ps);
10703+
10704+ return DefWindowProcW(hWnd, message, wParam, lParam);
10705+ }
10706+ #if(_WIN32_WINNT >= 0x0600)
10707+ case WM_DWMCOMPOSITIONCHANGED:
10708+ case WM_DWMCOLORIZATIONCOLORCHANGED:
10709+ RGFW_win32_makeWindowTransparent(win);
10710+ break;
10711+ #endif
10712+
10713+ case WM_ENTERSIZEMOVE: {
10714+ if (win->src.actionFrame)
10715+ RGFW_window_captureMousePlatform(win, win->internal.captureMouse);
10716+
10717+ #ifdef RGFW_ADVANCED_SMOOTH_RESIZE
10718+ SetTimer(win->src.window, 1, USER_TIMER_MINIMUM, NULL); break;
10719+ #endif
10720+ break;
10721+ }
10722+ case WM_EXITSIZEMOVE: {
10723+ if (win->src.actionFrame)
10724+ RGFW_window_captureMousePlatform(win, win->internal.captureMouse);
10725+
10726+ #ifdef RGFW_ADVANCED_SMOOTH_RESIZE
10727+ KillTimer(win->src.window, 1); break;
10728+ #endif
10729+ break;
10730+ }
10731+ case WM_TIMER:
10732+ RGFW_windowRefreshCallback(win, 0, 0, win->w, win->h);
10733+ break;
10734+
10735+ case WM_NCLBUTTONDOWN: {
10736+ /* workaround for half-second pause when starting to move window
10737+ see: https://gamedev.net/forums/topic/672094-keeping-things-moving-during-win32-moveresize-events/5254386/
10738+ */
10739+ POINT point = { 0, 0 };
10740+ if (SendMessage(win->src.window, WM_NCHITTEST, wParam, lParam) != HTCAPTION || GetCursorPos(&point) == FALSE)
10741+ break;
10742+
10743+ ScreenToClient(win->src.window, &point);
10744+ PostMessage(win->src.window, WM_MOUSEMOVE, 0, (u32)(point.x)|((u32)(point.y) << 16));
10745+ break;
10746+ }
10747+ case WM_MOUSELEAVE:
10748+ RGFW_mouseNotifyCallback(win, win->internal.lastMouseX, win->internal.lastMouseY, RGFW_FALSE);
10749+ break;
10750+
10751+ case WM_CHAR:
10752+ case WM_SYSCHAR: {
10753+ if (wParam >= 0xd800 && wParam <= 0xdbff)
10754+ win->src.highSurrogate = (WCHAR) wParam;
10755+ else {
10756+ u32 codepoint = 0;
10757+
10758+ if (wParam >= 0xdc00 && wParam <= 0xdfff) {
10759+ if (win->src.highSurrogate) {
10760+ codepoint += (u32)((win->src.highSurrogate - 0xd800) << 10);
10761+ codepoint += (u32)((WCHAR) wParam - 0xdc00);
10762+ codepoint += 0x10000;
10763+ }
10764+ }
10765+ else
10766+ codepoint = (WCHAR) wParam;
10767+
10768+ win->src.highSurrogate = 0;
10769+ RGFW_keyCharCallback(win, (u32)codepoint);
10770+ }
10771+
10772+ return 0;
10773+ }
10774+
10775+ case WM_UNICHAR: {
10776+ if (wParam == UNICODE_NOCHAR) {
10777+ return TRUE;
10778+ }
10779+
10780+ RGFW_keyCharCallback(win, (u32)wParam);
10781+ return 0;
10782+ }
10783+ case WM_SYSKEYUP: case WM_KEYUP: {
10784+ if (!(win->internal.enabledEvents & RGFW_keyReleasedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam);
10785+ i32 scancode = (HIWORD(lParam) & (KF_EXTENDED | 0xff));
10786+ if (scancode == 0)
10787+ scancode = (i32)MapVirtualKeyW((UINT)wParam, MAPVK_VK_TO_VSC);
10788+
10789+ switch (scancode) {
10790+ case 0x54: scancode = 0x137; break; /* Alt+PrtS */
10791+ case 0x146: scancode = 0x45; break; /* Ctrl+Pause */
10792+ case 0x136: scancode = 0x36; break; /* CJK IME sets the extended bit for right Shift */
10793+ default: break;
10794+ }
10795+
10796+ RGFW_key value = (u8)RGFW_apiKeyToRGFW((u32) scancode);
10797+
10798+ if (wParam == VK_CONTROL) {
10799+ if (HIWORD(lParam) & KF_EXTENDED)
10800+ value = RGFW_keyControlR;
10801+ else value = RGFW_keyControlL;
10802+ }
10803+
10804+ RGFW_keyUpdateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001), (GetKeyState(VK_SCROLL) & 0x0001));
10805+ RGFW_keyCallback(win, value, win->internal.mod, RGFW_FALSE, RGFW_FALSE);
10806+ break;
10807+ }
10808+ case WM_SYSKEYDOWN: case WM_KEYDOWN: {
10809+ if (!(win->internal.enabledEvents & RGFW_keyPressedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam);
10810+ i32 scancode = (HIWORD(lParam) & (KF_EXTENDED | 0xff));
10811+ if (scancode == 0)
10812+ scancode = (i32)MapVirtualKeyW((u32)wParam, MAPVK_VK_TO_VSC);
10813+
10814+ switch (scancode) {
10815+ case 0x54: scancode = 0x137; break; /* Alt+PrtS */
10816+ case 0x146: scancode = 0x45; break; /* Ctrl+Pause */
10817+ case 0x136: scancode = 0x36; break; /* CJK IME sets the extended bit for right Shift */
10818+ default: break;
10819+ }
10820+
10821+ RGFW_key value = (u8)RGFW_apiKeyToRGFW((u32) scancode);
10822+ if (wParam == VK_CONTROL) {
10823+ if (HIWORD(lParam) & KF_EXTENDED)
10824+ value = RGFW_keyControlR;
10825+ else value = RGFW_keyControlL;
10826+ }
10827+
10828+ RGFW_bool repeat = RGFW_isKeyDown(value);
10829+
10830+ RGFW_keyUpdateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001), (GetKeyState(VK_SCROLL) & 0x0001));
10831+ RGFW_keyCallback(win, value, win->internal.mod, repeat, 1);
10832+ break;
10833+ }
10834+ case WM_MOUSEMOVE: {
10835+ if (win->internal.mouseInside == RGFW_FALSE) {
10836+ RGFW_mouseNotifyCallback(win, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), RGFW_TRUE);
10837+ }
10838+
10839+ RGFW_mousePosCallback(win, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
10840+ break;
10841+ }
10842+ case WM_INPUT: {
10843+ if (!(win->internal.rawMouse || _RGFW->rawMouse)) return DefWindowProcW(hWnd, message, wParam, lParam);
10844+ unsigned size = sizeof(RAWINPUT);
10845+ static RAWINPUT raw;
10846+
10847+ GetRawInputData((HRAWINPUT)lParam, RID_INPUT, &raw, &size, sizeof(RAWINPUTHEADER));
10848+
10849+ if (raw.header.dwType != RIM_TYPEMOUSE || (raw.data.mouse.lLastX == 0 && raw.data.mouse.lLastY == 0) )
10850+ break;
10851+
10852+ float vecX = 0.0f;
10853+ float vecY = 0.0f;
10854+
10855+ if (raw.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) {
10856+ POINT pos = {0, 0};
10857+ int width, height;
10858+
10859+ if (raw.data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP) {
10860+ pos.x += GetSystemMetrics(SM_XVIRTUALSCREEN);
10861+ pos.y += GetSystemMetrics(SM_YVIRTUALSCREEN);
10862+ width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
10863+ height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
10864+ }
10865+ else {
10866+ width = GetSystemMetrics(SM_CXSCREEN);
10867+ height = GetSystemMetrics(SM_CYSCREEN);
10868+ }
10869+
10870+ pos.x += (int) (((float)raw.data.mouse.lLastX / 65535.f) * (float)width);
10871+ pos.y += (int) (((float)raw.data.mouse.lLastY / 65535.f) * (float)height);
10872+ ScreenToClient(win->src.window, &pos);
10873+
10874+ vecX = (float)(pos.x - win->internal.lastMouseX);
10875+ vecY = (float)(pos.y - win->internal.lastMouseY);
10876+ } else {
10877+ vecX = (float)(raw.data.mouse.lLastX);
10878+ vecY = (float)(raw.data.mouse.lLastY);
10879+ }
10880+
10881+ RGFW_rawMotionCallback(win, vecX, vecY);
10882+ break;
10883+ }
10884+ case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: case WM_XBUTTONDOWN: {
10885+ RGFW_mouseButton value = 0;
10886+ if (message == WM_XBUTTONDOWN)
10887+ value = RGFW_mouseMisc1 + (GET_XBUTTON_WPARAM(wParam) == XBUTTON2);
10888+ else value = (message == WM_LBUTTONDOWN) ? (u8)RGFW_mouseLeft :
10889+ (message == WM_RBUTTONDOWN) ? (u8)RGFW_mouseRight : (u8)RGFW_mouseMiddle;
10890+
10891+ RGFW_mouseButtonCallback(win, value, 1);
10892+ break;
10893+ }
10894+ case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MBUTTONUP: case WM_XBUTTONUP: {
10895+ RGFW_mouseButton value = 0;
10896+ if (message == WM_XBUTTONUP)
10897+ value = RGFW_mouseMisc1 + (GET_XBUTTON_WPARAM(wParam) == XBUTTON2);
10898+ else value = (message == WM_LBUTTONUP) ? (u8)RGFW_mouseLeft :
10899+ (message == WM_RBUTTONUP) ? (u8)RGFW_mouseRight : (u8)RGFW_mouseMiddle;
10900+
10901+ RGFW_mouseButtonCallback(win, value, 0);
10902+ break;
10903+ }
10904+ case WM_MOUSEWHEEL: {
10905+ float scrollY = (float)((i16) HIWORD(wParam) / (double) WHEEL_DELTA);
10906+ RGFW_mouseScrollCallback(win, 0.0f, scrollY);
10907+ break;
10908+ }
10909+ case 0x020E: {/* WM_MOUSEHWHEEL */
10910+ float scrollX = -(float)((i16) HIWORD(wParam) / (double) WHEEL_DELTA);
10911+ RGFW_mouseScrollCallback(win, scrollX, 0.0f);
10912+ break;
10913+ }
10914+ case WM_DROPFILES: {
10915+ HDROP drop = (HDROP) wParam;
10916+ POINT pt;
10917+
10918+ /* Move the mouse to the position of the drop */
10919+ DragQueryPoint(drop, &pt);
10920+ RGFW_dataDragCallback(win, RGFW_dataFile, RGFW_dndActionMove, pt.x, pt.y);
10921+
10922+ if (!(win->internal.enabledEvents & RGFW_dataDrop)) return DefWindowProcW(hWnd, message, wParam, lParam);
10923+ size_t count = DragQueryFileW(drop, 0xffffffff, NULL, 0);
10924+
10925+ u32 i;
10926+ for (i = 0; i < count; i++) {
10927+ UINT length = DragQueryFileW(drop, i, NULL, 0);
10928+ if (length == 0)
10929+ continue;
10930+
10931+ WCHAR* buffer = (WCHAR*)RGFW_ALLOC(sizeof(WCHAR) * (length + 1));
10932+ char* cbuffer = (char*)RGFW_ALLOC(length + 1);
10933+
10934+ DragQueryFileW(drop, i, buffer, length + 1);
10935+
10936+ RGFW_createUTF8FromWideStringWin32(buffer, cbuffer, length);
10937+
10938+ RGFW_dataDropCallback(win, cbuffer, length + 1, RGFW_dataFile);
10939+ RGFW_FREE(buffer);
10940+ RGFW_FREE(cbuffer);
10941+ }
10942+
10943+ DragFinish(drop);
10944+
10945+ break;
10946+ }
10947+ default: break;
10948+ }
10949+
10950+ return DefWindowProcW(hWnd, message, wParam, lParam);
10951+}
10952+
10953+#ifndef RGFW_NO_DPI
10954+ HMODULE RGFW_Shcore_dll = NULL;
10955+ typedef HRESULT (WINAPI *PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*,UINT*);
10956+ PFN_GetDpiForMonitor GetDpiForMonitorSRC = NULL;
10957+ #define GetDpiForMonitor GetDpiForMonitorSRC
10958+#endif
10959+
10960+#if !defined(RGFW_NO_LOAD_WINMM) && !defined(RGFW_NO_WINMM)
10961+ HMODULE RGFW_winmm_dll = NULL;
10962+ typedef u32 (WINAPI * PFN_timeBeginPeriod)(u32);
10963+ typedef PFN_timeBeginPeriod PFN_timeEndPeriod;
10964+ PFN_timeBeginPeriod timeBeginPeriodSRC, timeEndPeriodSRC;
10965+ #define timeBeginPeriod timeBeginPeriodSRC
10966+ #define timeEndPeriod timeEndPeriodSRC
10967+#elif !defined(RGFW_NO_WINMM)
10968+ __declspec(dllimport) u32 __stdcall timeBeginPeriod(u32 uPeriod);
10969+ __declspec(dllimport) u32 __stdcall timeEndPeriod(u32 uPeriod);
10970+#endif
10971+#define RGFW_PROC_DEF(proc, name) if (name##SRC == NULL && proc != NULL) { \
10972+ name##SRC = (PFN_##name)(RGFW_proc)GetProcAddress((proc), (#name)); \
10973+ RGFW_ASSERT(name##SRC != NULL); \
10974+ }
10975+
10976+RGFW_format RGFW_nativeFormat(void) { return RGFW_formatBGRA8; }
10977+
10978+RGFW_bool RGFW_createSurfacePtr(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) {
10979+ RGFW_ASSERT(surface != NULL);
10980+ surface->data = data;
10981+ surface->w = w;
10982+ surface->h = h;
10983+ surface->format = format;
10984+
10985+ BITMAPV5HEADER bi;
10986+ ZeroMemory(&bi, sizeof(bi));
10987+ bi.bV5Size = sizeof(bi);
10988+ bi.bV5Width = (i32)w;
10989+ bi.bV5Height = -((LONG) h);
10990+ bi.bV5Planes = 1;
10991+ bi.bV5BitCount = (format >= RGFW_formatRGBA8) ? 32 : 24;
10992+ bi.bV5Compression = BI_RGB;
10993+
10994+ surface->native.bitmap = CreateDIBSection(_RGFW->root->src.hdc,
10995+ (BITMAPINFO*) &bi, DIB_RGB_COLORS,
10996+ (void**) &surface->native.bitmapBits,
10997+ NULL, (DWORD) 0);
10998+
10999+ surface->native.format = (format >= RGFW_formatRGBA8) ? (RGFW_format) RGFW_formatBGRA8 : (RGFW_format) RGFW_formatBGR8;
11000+
11001+ if (surface->native.bitmap == NULL) {
11002+ RGFW_debugCallback(RGFW_typeError, RGFW_errBuffer, "Failed to create DIB section.");
11003+ return RGFW_FALSE;
11004+ }
11005+
11006+ surface->native.hdcMem = CreateCompatibleDC(_RGFW->root->src.hdc);
11007+ SelectObject(surface->native.hdcMem, surface->native.bitmap);
11008+
11009+ return RGFW_TRUE;
11010+}
11011+
11012+void RGFW_surface_freePtr(RGFW_surface* surface) {
11013+ RGFW_ASSERT(surface != NULL);
11014+
11015+ DeleteDC(surface->native.hdcMem);
11016+ DeleteObject(surface->native.bitmap);
11017+}
11018+
11019+void RGFW_window_blitSurface(RGFW_window* win, RGFW_surface* surface) {
11020+ RGFW_copyImageData(surface->native.bitmapBits, surface->w, RGFW_MIN(win->h, surface->h), surface->native.format, surface->data, surface->format, surface->convertFunc);
11021+ BitBlt(win->src.hdc, 0, 0, RGFW_MIN(win->w, surface->w), RGFW_MIN(win->h, surface->h), surface->native.hdcMem, 0, 0, SRCCOPY);
11022+}
11023+
11024+void RGFW_window_setRawMouseModePlatform(RGFW_window* win, RGFW_bool state) {
11025+ RGFW_UNUSED(win);
11026+ RAWINPUTDEVICE id = { 0x01, 0x02, 0, win->src.window };
11027+ id.dwFlags = (state == RGFW_TRUE) ? 0 : RIDEV_REMOVE;
11028+
11029+ RegisterRawInputDevices(&id, 1, sizeof(id));
11030+}
11031+
11032+void RGFW_window_captureMousePlatform(RGFW_window* win, RGFW_bool state) {
11033+ if (state == RGFW_FALSE) {
11034+ ClipCursor(NULL);
11035+ return;
11036+ }
11037+
11038+ RECT clipRect;
11039+ GetClientRect(win->src.window, &clipRect);
11040+ ClientToScreen(win->src.window, (POINT*) &clipRect.left);
11041+ ClientToScreen(win->src.window, (POINT*) &clipRect.right);
11042+ ClipCursor(&clipRect);
11043+}
11044+
11045+#define RGFW_LOAD_LIBRARY(x, lib) if (x == NULL) { x = LoadLibraryA(lib); RGFW_ASSERT(x != NULL); }
11046+
11047+#ifdef RGFW_DIRECTX
11048+int RGFW_window_createSwapChain_DirectX(RGFW_window* win, IDXGIFactory* pFactory, IUnknown* pDevice, IDXGISwapChain** swapchain) {
11049+ RGFW_ASSERT(win && pFactory && pDevice && swapchain);
11050+
11051+ static DXGI_SWAP_CHAIN_DESC swapChainDesc;
11052+ RGFW_MEMZERO(&swapChainDesc, sizeof(swapChainDesc));
11053+ swapChainDesc.BufferCount = 2;
11054+ swapChainDesc.BufferDesc.Width = win->w;
11055+ swapChainDesc.BufferDesc.Height = win->h;
11056+ swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
11057+ swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
11058+ swapChainDesc.OutputWindow = (HWND)win->src.window;
11059+ swapChainDesc.SampleDesc.Count = 1;
11060+ swapChainDesc.SampleDesc.Quality = 0;
11061+ swapChainDesc.Windowed = TRUE;
11062+ swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
11063+
11064+ HRESULT hr = pFactory->lpVtbl->CreateSwapChain(pFactory, (IUnknown*)pDevice, &swapChainDesc, swapchain);
11065+ if (FAILED(hr)) {
11066+ RGFW_debugCallback(RGFW_typeError, RGFW_errDirectXContext, "Failed to create DirectX swap chain!");
11067+ return -2;
11068+ }
11069+
11070+ return 0;
11071+}
11072+#endif
11073+
11074+/* we're doing it with magic numbers because some keys are missing */
11075+void RGFW_initKeycodesPlatform(void) {
11076+ _RGFW->keycodes[0x00B] = RGFW_key0;
11077+ _RGFW->keycodes[0x002] = RGFW_key1;
11078+ _RGFW->keycodes[0x003] = RGFW_key2;
11079+ _RGFW->keycodes[0x004] = RGFW_key3;
11080+ _RGFW->keycodes[0x005] = RGFW_key4;
11081+ _RGFW->keycodes[0x006] = RGFW_key5;
11082+ _RGFW->keycodes[0x007] = RGFW_key6;
11083+ _RGFW->keycodes[0x008] = RGFW_key7;
11084+ _RGFW->keycodes[0x009] = RGFW_key8;
11085+ _RGFW->keycodes[0x00A] = RGFW_key9;
11086+ _RGFW->keycodes[0x01E] = RGFW_keyA;
11087+ _RGFW->keycodes[0x030] = RGFW_keyB;
11088+ _RGFW->keycodes[0x02E] = RGFW_keyC;
11089+ _RGFW->keycodes[0x020] = RGFW_keyD;
11090+ _RGFW->keycodes[0x012] = RGFW_keyE;
11091+ _RGFW->keycodes[0x021] = RGFW_keyF;
11092+ _RGFW->keycodes[0x022] = RGFW_keyG;
11093+ _RGFW->keycodes[0x023] = RGFW_keyH;
11094+ _RGFW->keycodes[0x017] = RGFW_keyI;
11095+ _RGFW->keycodes[0x024] = RGFW_keyJ;
11096+ _RGFW->keycodes[0x025] = RGFW_keyK;
11097+ _RGFW->keycodes[0x026] = RGFW_keyL;
11098+ _RGFW->keycodes[0x032] = RGFW_keyM;
11099+ _RGFW->keycodes[0x031] = RGFW_keyN;
11100+ _RGFW->keycodes[0x018] = RGFW_keyO;
11101+ _RGFW->keycodes[0x019] = RGFW_keyP;
11102+ _RGFW->keycodes[0x010] = RGFW_keyQ;
11103+ _RGFW->keycodes[0x013] = RGFW_keyR;
11104+ _RGFW->keycodes[0x01F] = RGFW_keyS;
11105+ _RGFW->keycodes[0x014] = RGFW_keyT;
11106+ _RGFW->keycodes[0x016] = RGFW_keyU;
11107+ _RGFW->keycodes[0x02F] = RGFW_keyV;
11108+ _RGFW->keycodes[0x011] = RGFW_keyW;
11109+ _RGFW->keycodes[0x02D] = RGFW_keyX;
11110+ _RGFW->keycodes[0x015] = RGFW_keyY;
11111+ _RGFW->keycodes[0x02C] = RGFW_keyZ;
11112+ _RGFW->keycodes[0x028] = RGFW_keyApostrophe;
11113+ _RGFW->keycodes[0x02B] = RGFW_keyBackSlash;
11114+ _RGFW->keycodes[0x033] = RGFW_keyComma;
11115+ _RGFW->keycodes[0x00D] = RGFW_keyEquals;
11116+ _RGFW->keycodes[0x029] = RGFW_keyBacktick;
11117+ _RGFW->keycodes[0x01A] = RGFW_keyBracket;
11118+ _RGFW->keycodes[0x00C] = RGFW_keyMinus;
11119+ _RGFW->keycodes[0x034] = RGFW_keyPeriod;
11120+ _RGFW->keycodes[0x01B] = RGFW_keyCloseBracket;
11121+ _RGFW->keycodes[0x027] = RGFW_keySemicolon;
11122+ _RGFW->keycodes[0x035] = RGFW_keySlash;
11123+ _RGFW->keycodes[0x056] = RGFW_keyWorld2;
11124+ _RGFW->keycodes[0x00E] = RGFW_keyBackSpace;
11125+ _RGFW->keycodes[0x153] = RGFW_keyDelete;
11126+ _RGFW->keycodes[0x14F] = RGFW_keyEnd;
11127+ _RGFW->keycodes[0x01C] = RGFW_keyEnter;
11128+ _RGFW->keycodes[0x001] = RGFW_keyEscape;
11129+ _RGFW->keycodes[0x147] = RGFW_keyHome;
11130+ _RGFW->keycodes[0x152] = RGFW_keyInsert;
11131+ _RGFW->keycodes[0x15D] = RGFW_keyMenu;
11132+ _RGFW->keycodes[0x151] = RGFW_keyPageDown;
11133+ _RGFW->keycodes[0x149] = RGFW_keyPageUp;
11134+ _RGFW->keycodes[0x045] = RGFW_keyPause;
11135+ _RGFW->keycodes[0x039] = RGFW_keySpace;
11136+ _RGFW->keycodes[0x00F] = RGFW_keyTab;
11137+ _RGFW->keycodes[0x03A] = RGFW_keyCapsLock;
11138+ _RGFW->keycodes[0x145] = RGFW_keyNumLock;
11139+ _RGFW->keycodes[0x046] = RGFW_keyScrollLock;
11140+ _RGFW->keycodes[0x03B] = RGFW_keyF1;
11141+ _RGFW->keycodes[0x03C] = RGFW_keyF2;
11142+ _RGFW->keycodes[0x03D] = RGFW_keyF3;
11143+ _RGFW->keycodes[0x03E] = RGFW_keyF4;
11144+ _RGFW->keycodes[0x03F] = RGFW_keyF5;
11145+ _RGFW->keycodes[0x040] = RGFW_keyF6;
11146+ _RGFW->keycodes[0x041] = RGFW_keyF7;
11147+ _RGFW->keycodes[0x042] = RGFW_keyF8;
11148+ _RGFW->keycodes[0x043] = RGFW_keyF9;
11149+ _RGFW->keycodes[0x044] = RGFW_keyF10;
11150+ _RGFW->keycodes[0x057] = RGFW_keyF11;
11151+ _RGFW->keycodes[0x058] = RGFW_keyF12;
11152+ _RGFW->keycodes[0x064] = RGFW_keyF13;
11153+ _RGFW->keycodes[0x065] = RGFW_keyF14;
11154+ _RGFW->keycodes[0x066] = RGFW_keyF15;
11155+ _RGFW->keycodes[0x067] = RGFW_keyF16;
11156+ _RGFW->keycodes[0x068] = RGFW_keyF17;
11157+ _RGFW->keycodes[0x069] = RGFW_keyF18;
11158+ _RGFW->keycodes[0x06A] = RGFW_keyF19;
11159+ _RGFW->keycodes[0x06B] = RGFW_keyF20;
11160+ _RGFW->keycodes[0x06C] = RGFW_keyF21;
11161+ _RGFW->keycodes[0x06D] = RGFW_keyF22;
11162+ _RGFW->keycodes[0x06E] = RGFW_keyF23;
11163+ _RGFW->keycodes[0x076] = RGFW_keyF24;
11164+ _RGFW->keycodes[0x038] = RGFW_keyAltL;
11165+ _RGFW->keycodes[0x01D] = RGFW_keyControlL;
11166+ _RGFW->keycodes[0x02A] = RGFW_keyShiftL;
11167+ _RGFW->keycodes[0x15B] = RGFW_keySuperL;
11168+ _RGFW->keycodes[0x137] = RGFW_keyPrintScreen;
11169+ _RGFW->keycodes[0x138] = RGFW_keyAltR;
11170+ _RGFW->keycodes[0x11D] = RGFW_keyControlR;
11171+ _RGFW->keycodes[0x036] = RGFW_keyShiftR;
11172+ _RGFW->keycodes[0x15C] = RGFW_keySuperR;
11173+ _RGFW->keycodes[0x150] = RGFW_keyDown;
11174+ _RGFW->keycodes[0x14B] = RGFW_keyLeft;
11175+ _RGFW->keycodes[0x14D] = RGFW_keyRight;
11176+ _RGFW->keycodes[0x148] = RGFW_keyUp;
11177+ _RGFW->keycodes[0x052] = RGFW_keyPad0;
11178+ _RGFW->keycodes[0x04F] = RGFW_keyPad1;
11179+ _RGFW->keycodes[0x050] = RGFW_keyPad2;
11180+ _RGFW->keycodes[0x051] = RGFW_keyPad3;
11181+ _RGFW->keycodes[0x04B] = RGFW_keyPad4;
11182+ _RGFW->keycodes[0x04C] = RGFW_keyPad5;
11183+ _RGFW->keycodes[0x04D] = RGFW_keyPad6;
11184+ _RGFW->keycodes[0x047] = RGFW_keyPad7;
11185+ _RGFW->keycodes[0x048] = RGFW_keyPad8;
11186+ _RGFW->keycodes[0x049] = RGFW_keyPad9;
11187+ _RGFW->keycodes[0x04E] = RGFW_keyPadPlus;
11188+ _RGFW->keycodes[0x053] = RGFW_keyPadPeriod;
11189+ _RGFW->keycodes[0x135] = RGFW_keyPadSlash;
11190+ _RGFW->keycodes[0x11C] = RGFW_keyPadReturn;
11191+ _RGFW->keycodes[0x059] = RGFW_keyPadEqual;
11192+ _RGFW->keycodes[0x037] = RGFW_keyPadMultiply;
11193+ _RGFW->keycodes[0x04A] = RGFW_keyPadMinus;
11194+}
11195+
11196+
11197+i32 RGFW_initPlatform(void) {
11198+#ifndef RGFW_NO_DPI
11199+ #if (_WIN32_WINNT >= 0x0600)
11200+ SetProcessDPIAware();
11201+ #endif
11202+#endif
11203+
11204+ #ifndef RGFW_NO_WINMM
11205+ #ifndef RGFW_NO_LOAD_WINMM
11206+ RGFW_LOAD_LIBRARY(RGFW_winmm_dll, "winmm.dll");
11207+ RGFW_PROC_DEF(RGFW_winmm_dll, timeBeginPeriod);
11208+ RGFW_PROC_DEF(RGFW_winmm_dll, timeEndPeriod);
11209+ #endif
11210+ timeBeginPeriod(1);
11211+ #endif
11212+
11213+ #ifndef RGFW_NO_DWM
11214+ RGFW_LOAD_LIBRARY(RGFW_dwm_dll, "dwmapi.dll");
11215+ RGFW_PROC_DEF(RGFW_dwm_dll, DwmEnableBlurBehindWindow);
11216+ RGFW_PROC_DEF(RGFW_dwm_dll, DwmSetWindowAttribute);
11217+ #endif
11218+
11219+ RGFW_LOAD_LIBRARY(RGFW_wgl_dll, "opengl32.dll");
11220+ #ifndef RGFW_NO_LOAD_WGL
11221+ RGFW_PROC_DEF(RGFW_wgl_dll, wglCreateContext);
11222+ RGFW_PROC_DEF(RGFW_wgl_dll, wglDeleteContext);
11223+ RGFW_PROC_DEF(RGFW_wgl_dll, wglGetProcAddress);
11224+ RGFW_PROC_DEF(RGFW_wgl_dll, wglMakeCurrent);
11225+ RGFW_PROC_DEF(RGFW_wgl_dll, wglGetCurrentDC);
11226+ RGFW_PROC_DEF(RGFW_wgl_dll, wglGetCurrentContext);
11227+ RGFW_PROC_DEF(RGFW_wgl_dll, wglShareLists);
11228+ #endif
11229+
11230+ u8 RGFW_blk[] = { 0, 0, 0, 0 };
11231+ _RGFW->hiddenMouse = RGFW_createMouse(RGFW_blk, 1, 1, RGFW_formatRGBA8);
11232+ return 1;
11233+}
11234+
11235+RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win) {
11236+ if (name[0] == 0) name = (char*) " ";
11237+ win->src.hIconSmall = win->src.hIconBig = NULL;
11238+ win->src.maxSizeW = 0;
11239+ win->src.maxSizeH = 0;
11240+ win->src.minSizeW = 0;
11241+ win->src.minSizeH = 0;
11242+ win->src.aspectRatioW = 0;
11243+ win->src.aspectRatioH = 0;
11244+
11245+ HINSTANCE inh = GetModuleHandleA(NULL);
11246+
11247+ #ifndef __cplusplus
11248+ WNDCLASSW Class = {0}; /*!< Setup the Window class. */
11249+ #else
11250+ WNDCLASSW Class = {};
11251+ #endif
11252+
11253+ if (_RGFW->className == NULL)
11254+ _RGFW->className = (char*)name;
11255+
11256+ wchar_t wide_class[256];
11257+ MultiByteToWideChar(CP_UTF8, 0, _RGFW->className, -1, wide_class, 255);
11258+
11259+ Class.lpszClassName = wide_class;
11260+ Class.hInstance = inh;
11261+ Class.hCursor = LoadCursor(NULL, IDC_ARROW);
11262+ Class.lpfnWndProc = WndProcW;
11263+ Class.cbClsExtra = sizeof(RGFW_window*);
11264+
11265+ Class.hIcon = (HICON)LoadImageA(GetModuleHandleW(NULL), "RGFW_ICON", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
11266+ if (Class.hIcon == NULL)
11267+ Class.hIcon = (HICON)LoadImageA(NULL, (LPCSTR)IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
11268+
11269+ RegisterClassW(&Class);
11270+
11271+ DWORD window_style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
11272+
11273+ if (!(flags & RGFW_windowNoBorder)) {
11274+ window_style |= WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX;
11275+
11276+ if (!(flags & RGFW_windowNoResize))
11277+ window_style |= WS_SIZEBOX | WS_MAXIMIZEBOX;
11278+ } else
11279+ window_style |= WS_POPUP | WS_VISIBLE | WS_SYSMENU;
11280+
11281+ wchar_t wide_name[256];
11282+ MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_name, 255);
11283+ HWND dummyWin = CreateWindowW(Class.lpszClassName, (wchar_t*)wide_name, window_style, win->x, win->y, win->w, win->h, 0, 0, inh, 0);
11284+
11285+#ifdef RGFW_OPENGL
11286+ RGFW_win32_loadOpenGLFuncs(dummyWin);
11287+#endif
11288+
11289+ DestroyWindow(dummyWin);
11290+
11291+ RECT rect = { 0, 0, win->w, win->h};
11292+ DWORD style = RGFW_winapi_window_getStyle(win, flags);
11293+ DWORD exStyle = RGFW_winapi_window_getExStyle(win, flags);
11294+ AdjustWindowRectEx(&rect, style, FALSE, exStyle);
11295+
11296+ win->src.window = CreateWindowW(Class.lpszClassName, (wchar_t*)wide_name, window_style, win->x + rect.left, win->y + rect.top, rect.right - rect.left, rect.bottom - rect.top, 0, 0, inh, 0);
11297+ SetPropW(win->src.window, L"RGFW", win);
11298+ RGFW_window_resize(win, win->w, win->h); /* so WM_GETMINMAXINFO gets called again */
11299+
11300+ if (flags & RGFW_windowAllowDND) {
11301+ win->internal.flags |= RGFW_windowAllowDND;
11302+ RGFW_window_setDND(win, 1);
11303+ }
11304+ win->src.hdc = GetDC(win->src.window);
11305+
11306+ RGFW_win32_makeWindowDarkMode(win, RGFW_win32_getDarkModeState());
11307+ RGFW_win32_makeWindowTransparent(win);
11308+ return win;
11309+}
11310+
11311+void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) {
11312+ RGFW_setBit(&win->internal.flags, RGFW_windowNoBorder, !border);
11313+
11314+ RECT rect;
11315+ GetClientRect(win->src.window, &rect);
11316+
11317+ LONG style = GetWindowLong(win->src.window, GWL_STYLE);
11318+ style |= (LONG)RGFW_winapi_window_getStyle(win, win->internal.flags);
11319+
11320+ if (border == 0) {
11321+ style &= ~WS_OVERLAPPEDWINDOW;
11322+ } else {
11323+ if (win->internal.flags & RGFW_windowNoResize) style &= ~WS_MAXIMIZEBOX;
11324+ style |= WS_OVERLAPPEDWINDOW;
11325+ }
11326+
11327+ DWORD exStyle = RGFW_winapi_window_getExStyle(win, win->internal.flags);
11328+ ClientToScreen(win->src.window, (POINT*) &rect.left);
11329+ ClientToScreen(win->src.window, (POINT*) &rect.right);
11330+
11331+ AdjustWindowRectEx(&rect, (DWORD)style, FALSE, exStyle);
11332+ SetWindowLong(win->src.window, GWL_STYLE, style);
11333+
11334+ SetWindowLongW(win->src.window, GWL_STYLE, style);
11335+ SetWindowPos(win->src.window, HWND_TOP, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOZORDER);
11336+}
11337+
11338+void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow) {
11339+ RGFW_setBit(&win->internal.flags, RGFW_windowAllowDND, allow);
11340+ DragAcceptFiles(win->src.window, allow);
11341+}
11342+
11343+RGFW_bool RGFW_getGlobalMouse(i32* x, i32* y) {
11344+ POINT p;
11345+ GetCursorPos(&p);
11346+ if (x) *x = p.x;
11347+ if (y) *y = p.y;
11348+ return RGFW_TRUE;
11349+}
11350+
11351+void RGFW_window_setAspectRatio(RGFW_window* win, i32 w, i32 h) {
11352+ RGFW_ASSERT(win != NULL);
11353+ win->src.aspectRatioW = w;
11354+ win->src.aspectRatioH = h;
11355+}
11356+
11357+void RGFW_window_setMinSize(RGFW_window* win, i32 w, i32 h) {
11358+ RGFW_ASSERT(win != NULL);
11359+ win->src.minSizeW = w;
11360+ win->src.minSizeH = h;
11361+}
11362+
11363+void RGFW_window_setMaxSize(RGFW_window* win, i32 w, i32 h) {
11364+ RGFW_ASSERT(win != NULL);
11365+ win->src.maxSizeW = w;
11366+ win->src.maxSizeH = h;
11367+}
11368+
11369+void RGFW_window_focus(RGFW_window* win) {
11370+ RGFW_ASSERT(win);
11371+ SetForegroundWindow(win->src.window);
11372+ SetFocus(win->src.window);
11373+}
11374+
11375+void RGFW_window_raise(RGFW_window* win) {
11376+ RGFW_ASSERT(win);
11377+ BringWindowToTop(win->src.window);
11378+ SetWindowPos(win->src.window, HWND_TOP, win->x, win->y, win->w, win->h, SWP_NOSIZE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
11379+}
11380+
11381+void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) {
11382+ RGFW_ASSERT(win != NULL);
11383+
11384+ RGFW_monitor* mon = RGFW_window_getMonitor(win);
11385+
11386+ if (fullscreen == RGFW_FALSE) {
11387+ RGFW_monitor_setMode(mon, &win->internal.oldMode);
11388+
11389+ RGFW_window_setBorder(win, 1);
11390+
11391+ RECT rect = { 0, 0, win->internal.oldW, win->internal.oldH};
11392+ DWORD style = RGFW_winapi_window_getStyle(win, win->internal.flags);
11393+ DWORD exStyle = RGFW_winapi_window_getExStyle(win, win->internal.flags);
11394+ AdjustWindowRectEx(&rect, style, FALSE, exStyle);
11395+ SetWindowPos(win->src.window, HWND_TOP, win->internal.oldX, win->internal.oldY, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER);
11396+
11397+ win->internal.flags &= ~(u32)RGFW_windowFullscreen;
11398+ win->x = win->internal.oldX;
11399+ win->y = win->internal.oldY;
11400+ win->w = win->internal.oldW;
11401+ win->h = win->internal.oldH;
11402+ return;
11403+ }
11404+
11405+ win->internal.oldX = win->x;
11406+ win->internal.oldY = win->y;
11407+ win->internal.oldW = win->w;
11408+ win->internal.oldH = win->h;
11409+ win->internal.oldMode = mon->mode;
11410+ win->internal.flags |= RGFW_windowFullscreen;
11411+
11412+ RGFW_window_setBorder(win, 0);
11413+
11414+ SetWindowPos(win->src.window, HWND_TOPMOST, (i32)mon->x, (i32)mon->y, 0, 0, SWP_NOOWNERZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOSIZE);
11415+ win->x = mon->x;
11416+ win->y = mon->y;
11417+
11418+ RGFW_monitor_scaleToWindow(mon, win);
11419+ SetWindowPos(win->src.window, HWND_TOPMOST, 0, 0, (i32)mon->mode.w, (i32)mon->mode.h, SWP_NOOWNERZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE);
11420+ win->w = mon->mode.w;
11421+ win->h = mon->mode.h;
11422+}
11423+
11424+void RGFW_window_maximize(RGFW_window* win) {
11425+ RGFW_ASSERT(win != NULL);
11426+ RGFW_window_hide(win);
11427+ ShowWindow(win->src.window, SW_MAXIMIZE);
11428+ RGFW_window_fetchSize(win, NULL, NULL);
11429+}
11430+
11431+void RGFW_window_minimize(RGFW_window* win) {
11432+ RGFW_ASSERT(win != NULL);
11433+ ShowWindow(win->src.window, SW_MINIMIZE);
11434+}
11435+
11436+void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) {
11437+ RGFW_ASSERT(win != NULL);
11438+ if (floating) SetWindowPos(win->src.window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
11439+ else SetWindowPos(win->src.window, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
11440+}
11441+
11442+void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) {
11443+ SetWindowLong(win->src.window, GWL_EXSTYLE, WS_EX_LAYERED);
11444+ SetLayeredWindowAttributes(win->src.window, 0, opacity, LWA_ALPHA);
11445+}
11446+
11447+void RGFW_window_restore(RGFW_window* win) { RGFW_window_show(win); }
11448+
11449+RGFW_bool RGFW_window_isFloating(RGFW_window* win) {
11450+ return (GetWindowLongPtr(win->src.window, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
11451+}
11452+
11453+void RGFW_stopCheckEvents(void) {
11454+ PostMessageW(_RGFW->root->src.window, WM_NULL, 0, 0);
11455+}
11456+
11457+void RGFW_waitForEvent(i32 waitMS) {
11458+ MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD)waitMS, QS_ALLINPUT);
11459+}
11460+
11461+RGFW_key RGFW_physicalToMappedKey(RGFW_key key) {
11462+ UINT vsc = RGFW_rgfwToApiKey(key);
11463+ BYTE keyboardState[256] = {0};
11464+
11465+ if (!GetKeyboardState(keyboardState))
11466+ return key;
11467+
11468+ UINT vk = MapVirtualKeyW(vsc, MAPVK_VSC_TO_VK);
11469+ HKL layout = GetKeyboardLayout(0);
11470+
11471+ wchar_t charBuffer[4] = {0};
11472+ int result = ToUnicodeEx(vk, vsc, keyboardState, charBuffer, 1, 0, layout);
11473+
11474+ if (result == 1 && charBuffer[0] < 256) {
11475+ return (RGFW_key)charBuffer[0];
11476+ }
11477+
11478+ switch (vk) {
11479+ case VK_F1: return RGFW_keyF1;
11480+ case VK_F2: return RGFW_keyF2;
11481+ case VK_F3: return RGFW_keyF3;
11482+ case VK_F4: return RGFW_keyF4;
11483+ case VK_F5: return RGFW_keyF5;
11484+ case VK_F6: return RGFW_keyF6;
11485+ case VK_F7: return RGFW_keyF7;
11486+ case VK_F8: return RGFW_keyF8;
11487+ case VK_F9: return RGFW_keyF9;
11488+ case VK_F10: return RGFW_keyF10;
11489+ case VK_F11: return RGFW_keyF11;
11490+ case VK_F12: return RGFW_keyF12;
11491+ case VK_F13: return RGFW_keyF13;
11492+ case VK_F14: return RGFW_keyF14;
11493+ case VK_F15: return RGFW_keyF15;
11494+ case VK_F16: return RGFW_keyF16;
11495+ case VK_F17: return RGFW_keyF17;
11496+ case VK_F18: return RGFW_keyF18;
11497+ case VK_F19: return RGFW_keyF19;
11498+ case VK_F20: return RGFW_keyF20;
11499+ case VK_F21: return RGFW_keyF21;
11500+ case VK_F22: return RGFW_keyF22;
11501+ case VK_F23: return RGFW_keyF23;
11502+ case VK_F24: return RGFW_keyF24;
11503+ case VK_LSHIFT: return RGFW_keyShiftL;
11504+ case VK_RSHIFT: return RGFW_keyShiftR;
11505+ case VK_LCONTROL: return RGFW_keyControlL;
11506+ case VK_RCONTROL: return RGFW_keyControlR;
11507+ case VK_LMENU: return RGFW_keyAltL;
11508+ case VK_RMENU: return RGFW_keyAltR;
11509+ case VK_LWIN: return RGFW_keySuperL;
11510+ case VK_RWIN: return RGFW_keySuperR;
11511+ case VK_CAPITAL: return RGFW_keyCapsLock;
11512+ case VK_NUMLOCK: return RGFW_keyNumLock;
11513+ case VK_SCROLL: return RGFW_keyScrollLock;
11514+ case VK_UP: return RGFW_keyUp;
11515+ case VK_DOWN: return RGFW_keyDown;
11516+ case VK_LEFT: return RGFW_keyLeft;
11517+ case VK_RIGHT: return RGFW_keyRight;
11518+ case VK_HOME: return RGFW_keyHome;
11519+ case VK_END: return RGFW_keyEnd;
11520+ case VK_PRIOR: return RGFW_keyPageUp;
11521+ case VK_NEXT: return RGFW_keyPageDown;
11522+ case VK_INSERT: return RGFW_keyInsert;
11523+ case VK_APPS: return RGFW_keyMenu;
11524+ case VK_ADD: return RGFW_keyPadPlus;
11525+ case VK_SUBTRACT: return RGFW_keyPadMinus;
11526+ case VK_MULTIPLY: return RGFW_keyPadMultiply;
11527+ case VK_DIVIDE: return RGFW_keyPadSlash;
11528+ case VK_RETURN: return RGFW_keyPadReturn;
11529+ case VK_DECIMAL: return RGFW_keyPadPeriod;
11530+ case VK_NUMPAD0: return RGFW_keyPad0;
11531+ case VK_NUMPAD1: return RGFW_keyPad1;
11532+ case VK_NUMPAD2: return RGFW_keyPad2;
11533+ case VK_NUMPAD3: return RGFW_keyPad3;
11534+ case VK_NUMPAD4: return RGFW_keyPad4;
11535+ case VK_NUMPAD5: return RGFW_keyPad5;
11536+ case VK_NUMPAD6: return RGFW_keyPad6;
11537+ case VK_NUMPAD7: return RGFW_keyPad7;
11538+ case VK_NUMPAD8: return RGFW_keyPad8;
11539+ case VK_NUMPAD9: return RGFW_keyPad9;
11540+ case VK_SNAPSHOT: return RGFW_keyPrintScreen;
11541+ case VK_PAUSE: return RGFW_keyPause;
11542+ default: return RGFW_keyNULL;
11543+ }
11544+
11545+ return RGFW_keyNULL;
11546+}
11547+
11548+RGFW_bool RGFW_window_fetchSize(RGFW_window* win, i32* w, i32* h) {
11549+ RECT area;
11550+ GetClientRect(win->src.window, &area);
11551+
11552+ win->w = area.right;
11553+ win->h = area.bottom;
11554+
11555+ return RGFW_window_getSize(win, w, h);
11556+}
11557+
11558+void RGFW_pollEvents(void) {
11559+ RGFW_resetPrevState();
11560+ MSG msg;
11561+ while (PeekMessageA(&msg, NULL, 0u, 0u, PM_REMOVE)) {
11562+ TranslateMessage(&msg);
11563+ DispatchMessageA(&msg);
11564+ }
11565+}
11566+
11567+RGFW_bool RGFW_window_isHidden(RGFW_window* win) {
11568+ RGFW_ASSERT(win != NULL);
11569+ return IsWindowVisible(win->src.window) == 0 && !RGFW_window_isMinimized(win);
11570+}
11571+
11572+RGFW_bool RGFW_window_isMinimized(RGFW_window* win) {
11573+ RGFW_ASSERT(win != NULL);
11574+
11575+ #ifndef __cplusplus
11576+ WINDOWPLACEMENT placement = {0};
11577+ #else
11578+ WINDOWPLACEMENT placement = {};
11579+ #endif
11580+ GetWindowPlacement(win->src.window, &placement);
11581+ return placement.showCmd == SW_SHOWMINIMIZED;
11582+}
11583+
11584+RGFW_bool RGFW_window_isMaximized(RGFW_window* win) {
11585+ RGFW_ASSERT(win != NULL);
11586+
11587+ #ifndef __cplusplus
11588+ WINDOWPLACEMENT placement = {0};
11589+ #else
11590+ WINDOWPLACEMENT placement = {};
11591+ #endif
11592+ GetWindowPlacement(win->src.window, &placement);
11593+ return placement.showCmd == SW_SHOWMAXIMIZED || IsZoomed(win->src.window);
11594+}
11595+
11596+RGFW_bool RGFW_monitor_getWorkarea(RGFW_monitor* monitor, i32* x, i32* y, i32* width, i32* height) {
11597+ MONITORINFOEX mi;
11598+ mi.cbSize = sizeof(MONITORINFOEX);
11599+ GetMonitorInfoA(monitor->node->hMonitor, (LPMONITORINFO)&mi);
11600+
11601+ if (x) *x = mi.rcWork.left;
11602+ if (y) *y = mi.rcWork.top;
11603+ if (width) *width = mi.rcWork.right - mi.rcWork.left;
11604+ if (height) *height = mi.rcWork.bottom - mi.rcWork.top;
11605+
11606+ return RGFW_TRUE;
11607+}
11608+
11609+size_t RGFW_monitor_getGammaRampPtr(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
11610+ WORD values[3][256];
11611+
11612+ HDC dc = CreateDCW(L"DISPLAY", monitor->node->adapterName, NULL, NULL);
11613+ GetDeviceGammaRamp(dc, values);
11614+ DeleteDC(dc);
11615+
11616+ if (ramp) {
11617+ memcpy(ramp->red, values[0], sizeof(values[0]));
11618+ memcpy(ramp->green, values[1], sizeof(values[1]));
11619+ memcpy(ramp->blue, values[2], sizeof(values[2]));
11620+ }
11621+
11622+ return sizeof(values[0]) / sizeof(WORD);
11623+}
11624+
11625+RGFW_bool RGFW_monitor_setGammaRamp(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
11626+ WORD values[3][256];
11627+ if (ramp->count != 256) {
11628+ RGFW_debugCallback(RGFW_typeError, RGFW_errX11, "Win32: Gamma ramp size must be 256");
11629+ return RGFW_FALSE;
11630+ }
11631+
11632+ memcpy(values[0], ramp->red, sizeof(values[0]));
11633+ memcpy(values[1], ramp->green, sizeof(values[1]));
11634+ memcpy(values[2], ramp->blue, sizeof(values[2]));
11635+
11636+ HDC dc = CreateDCW(L"DISPLAY", monitor->node->adapterName, NULL, NULL);
11637+ SetDeviceGammaRamp(dc, values);
11638+ DeleteDC(dc);
11639+ return RGFW_TRUE;
11640+}
11641+
11642+BOOL CALLBACK RGFW_win32_getMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData);
11643+BOOL CALLBACK RGFW_win32_getMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
11644+ RGFW_UNUSED(hMonitor);
11645+ RGFW_UNUSED(hdcMonitor);
11646+ RGFW_UNUSED(lprcMonitor);
11647+ RGFW_UNUSED(dwData);
11648+
11649+ MONITORINFOEXW mi;
11650+ ZeroMemory(&mi, sizeof(mi));
11651+ mi.cbSize = sizeof(mi);
11652+
11653+ if (GetMonitorInfoW(hMonitor, (MONITORINFO*) &mi)) {
11654+ RGFW_monitorNode* node = (RGFW_monitorNode*)dwData;
11655+ if (wcscmp(mi.szDevice, node->adapterName) == 0) {
11656+ node->hMonitor = hMonitor;
11657+ }
11658+ }
11659+
11660+ return TRUE;
11661+}
11662+
11663+RGFWDEF void RGFW_win32_getMode(DEVMODEW* dm, RGFW_monitorMode* mode);
11664+void RGFW_win32_getMode(DEVMODEW* dm, RGFW_monitorMode* mode) {
11665+ mode->w = (i32)dm->dmPelsWidth;
11666+ mode->h = (i32)dm->dmPelsHeight;
11667+ RGFW_splitBPP(dm->dmBitsPerPel, mode);
11668+
11669+ switch (dm->dmDisplayFrequency) {
11670+ case 119:
11671+ case 59:
11672+ case 29:
11673+ mode->refreshRate = ((float)(dm->dmDisplayFrequency + 1) * 1000.0f) / 1001.f;
11674+ break;
11675+ default:
11676+ mode->refreshRate = (float)dm->dmDisplayFrequency;
11677+ break;
11678+ }
11679+}
11680+
11681+size_t RGFW_monitor_getModesPtr(RGFW_monitor* monitor, RGFW_monitorMode** modes){
11682+ size_t count = 0;
11683+ DWORD modeIndex = 0;
11684+
11685+ for (;;) {
11686+ DEVMODEW dm;
11687+ ZeroMemory(&dm, sizeof(dm));
11688+ dm.dmSize = sizeof(dm);
11689+
11690+ if (!EnumDisplaySettingsW(monitor->node->adapterName, modeIndex, &dm))
11691+ break;
11692+
11693+ if (ChangeDisplaySettingsExW(monitor->node->adapterName, &dm, NULL, CDS_TEST, NULL) != DISP_CHANGE_SUCCESSFUL) {
11694+ continue;
11695+ }
11696+
11697+ modeIndex++;
11698+
11699+ if (dm.dmBitsPerPel < 15)
11700+ continue;
11701+
11702+ if (modes) {
11703+ RGFW_monitorMode mode;
11704+ RGFW_win32_getMode(&dm, &mode);
11705+
11706+ size_t i;
11707+ for (i = 0; i < count; i++) {
11708+ if (RGFW_monitorModeCompare(&(*modes)[i], &mode, RGFW_monitorAll) == RGFW_TRUE) {
11709+ break;
11710+ }
11711+ }
11712+
11713+ if (i < count) {
11714+ continue;
11715+ }
11716+
11717+ (*modes)[count] = mode;
11718+ }
11719+
11720+ count += 1;
11721+ }
11722+
11723+ return count;
11724+}
11725+
11726+RGFWDEF void RGFW_win32_createMonitor(DISPLAY_DEVICEW* adapter, DISPLAY_DEVICEW* dd);
11727+void RGFW_win32_createMonitor(DISPLAY_DEVICEW* adapter, DISPLAY_DEVICEW* dd) {
11728+ DEVMODEW dm;
11729+ ZeroMemory(&dm, sizeof(dm));
11730+ dm.dmSize = sizeof(dm);
11731+
11732+ if (!EnumDisplaySettingsW(adapter->DeviceName, ENUM_CURRENT_SETTINGS, &dm)) {
11733+ return;
11734+ }
11735+
11736+ RGFW_monitorNode* node = RGFW_monitors_add(NULL);
11737+
11738+ wcscpy(node->adapterName, adapter->DeviceName);
11739+ wcscpy(node->deviceName, dd->DeviceName);
11740+
11741+ RGFW_createUTF8FromWideStringWin32(dd->DeviceString, node->mon.name, sizeof(node->mon.name));
11742+ node->mon.name[sizeof(node->mon.name) - 1] = '\0';
11743+
11744+ RECT rect;
11745+ rect.left = (LONG)dm.dmPosition.x;
11746+ rect.top = (LONG)dm.dmPosition.y;
11747+ rect.right = (LONG)((LONG)dm.dmPosition.x + (LONG)dm.dmPelsWidth);
11748+ rect.bottom = (LONG)((long)dm.dmPosition.y + (LONG)dm.dmPelsHeight);
11749+ EnumDisplayMonitors(NULL, &rect, RGFW_win32_getMonitorHandle, (LPARAM)node);
11750+
11751+ RGFW_win32_getMode(&dm, &node->mon.mode);
11752+
11753+ MONITORINFOEXW monitorInfo;
11754+ monitorInfo.cbSize = sizeof(MONITORINFOEXW);
11755+ GetMonitorInfoW(node->hMonitor, (LPMONITORINFO)&monitorInfo);
11756+
11757+ node->mon.x = monitorInfo.rcMonitor.left;
11758+ node->mon.y = monitorInfo.rcMonitor.top;
11759+
11760+ HDC hdc = CreateDCW(monitorInfo.szDevice, NULL, NULL, NULL);
11761+ /* get pixels per inch */
11762+ float dpiX = (float)GetDeviceCaps(hdc, LOGPIXELSX);
11763+ float dpiY = (float)GetDeviceCaps(hdc, LOGPIXELSX);
11764+
11765+ node->mon.scaleX = dpiX / 96.0f;
11766+ node->mon.scaleY = dpiY / 96.0f;
11767+ node->mon.pixelRatio = dpiX >= 192.0f ? 2.0f : 1.0f;
11768+
11769+ node->mon.physW = (float)GetDeviceCaps(hdc, HORZSIZE) / 25.4f;
11770+ node->mon.physH = (float)GetDeviceCaps(hdc, VERTSIZE) / 25.4f;
11771+ DeleteDC(hdc);
11772+
11773+#ifndef RGFW_NO_DPI
11774+ RGFW_LOAD_LIBRARY(RGFW_Shcore_dll, "shcore.dll");
11775+ RGFW_PROC_DEF(RGFW_Shcore_dll, GetDpiForMonitor);
11776+
11777+ if (GetDpiForMonitor != NULL) {
11778+ u32 x, y;
11779+ GetDpiForMonitor(node->hMonitor, MDT_EFFECTIVE_DPI, &x, &y);
11780+ node->mon.scaleX = (float) (x) / (float) 96.0f;
11781+ node->mon.scaleY = (float) (y) / (float) 96.0f;
11782+ node->mon.pixelRatio = dpiX >= 192.0f ? 2.0f : 1.0f;
11783+ }
11784+#endif
11785+
11786+ if (monitorInfo.dwFlags & MONITORINFOF_PRIMARY) {
11787+ _RGFW->monitors.primary = node;
11788+ }
11789+
11790+ RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_TRUE);
11791+}
11792+
11793+void RGFW_pollMonitors(void) {
11794+ for (RGFW_monitorNode* node = _RGFW->monitors.list.head; node; node = node->next) {
11795+ node->disconnected = RGFW_TRUE;
11796+ }
11797+
11798+ /* loop through display adapters (GPU) */
11799+ DISPLAY_DEVICEW adapter;
11800+ DWORD adapterNum;
11801+ for (adapterNum = 0; ; adapterNum++) {
11802+ ZeroMemory(&adapter, sizeof(adapter));
11803+ adapter.cb = sizeof(adapter);
11804+
11805+ if (!EnumDisplayDevicesW(NULL, adapterNum, &adapter, 0))
11806+ break;
11807+
11808+ if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE))
11809+ continue;
11810+
11811+ DISPLAY_DEVICEW dd;
11812+ dd.cb = sizeof(dd);
11813+
11814+ /* loop through display devices (monitors) */
11815+ DWORD deviceNum;
11816+ for (deviceNum = 0; ; deviceNum++) {
11817+ ZeroMemory(&dd, sizeof(dd));
11818+ dd.cb = sizeof(dd);
11819+
11820+ if (!EnumDisplayDevicesW(adapter.DeviceName, deviceNum, &dd, 0))
11821+ break;
11822+
11823+ if (!(dd.StateFlags & DISPLAY_DEVICE_ACTIVE))
11824+ continue;
11825+
11826+ RGFW_monitorNode* node;
11827+ for (node = _RGFW->monitors.list.head; node; node = node->next) {
11828+ if (node->disconnected == RGFW_TRUE && wcscmp(node->deviceName, dd.DeviceName) == 0) {
11829+ node->disconnected = RGFW_FALSE;
11830+ EnumDisplayMonitors(NULL, NULL, RGFW_win32_getMonitorHandle, (LPARAM) &node->mon);
11831+ break;
11832+ }
11833+ }
11834+
11835+ if (node) {
11836+ continue;
11837+ }
11838+
11839+ RGFW_win32_createMonitor(&adapter, &dd);
11840+ }
11841+
11842+ /* if there are no display devices, just use the monitor directly (hack borrowed from GLFW (I'm not giving it back)) */
11843+ if (deviceNum == 0) {
11844+ RGFW_monitorNode* node;
11845+ for (node = _RGFW->monitors.list.head; node; node = node->next) {
11846+ if (node->disconnected == RGFW_TRUE && wcscmp(node->adapterName, adapter.DeviceName) == 0) {
11847+ node->disconnected = RGFW_FALSE;
11848+ break;
11849+ }
11850+ }
11851+
11852+ if (node) {
11853+ continue;
11854+ }
11855+
11856+ RGFW_win32_createMonitor(&adapter, NULL);
11857+ }
11858+ }
11859+
11860+ RGFW_monitors_refresh();
11861+}
11862+
11863+RGFW_monitor* RGFW_window_getMonitor(RGFW_window* win) {
11864+ HMONITOR src = MonitorFromWindow(win->src.window, MONITOR_DEFAULTTOPRIMARY);
11865+ RGFW_monitorNode* node = _RGFW->monitors.list.head;
11866+
11867+ for (node = _RGFW->monitors.list.head; node; node = node->next) {
11868+ if (node->hMonitor == src) {
11869+ return &node->mon;
11870+ }
11871+ }
11872+
11873+ return RGFW_getPrimaryMonitor();
11874+}
11875+
11876+RGFW_bool RGFW_monitor_setMode(RGFW_monitor* mon, RGFW_monitorMode* mode) {
11877+ DEVMODEW dm;
11878+ ZeroMemory(&dm, sizeof(dm));
11879+ dm.dmSize = sizeof(dm);
11880+
11881+ dm.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT;
11882+ dm.dmPelsWidth = (u32)mode->w;
11883+ dm.dmPelsHeight = (u32)mode->h;
11884+
11885+ dm.dmFields |= DM_DISPLAYFREQUENCY;
11886+ dm.dmDisplayFrequency = (DWORD)mode->refreshRate;
11887+
11888+ dm.dmFields |= DM_BITSPERPEL;
11889+ dm.dmBitsPerPel = (DWORD)(mode->red + mode->green + mode->blue);
11890+
11891+ if (ChangeDisplaySettingsExW(mon->node->adapterName, &dm, NULL, CDS_TEST, NULL) == DISP_CHANGE_SUCCESSFUL) {
11892+ if (ChangeDisplaySettingsExW(mon->node->adapterName, &dm, NULL, CDS_UPDATEREGISTRY, NULL) == DISP_CHANGE_SUCCESSFUL) {
11893+ RGFW_win32_getMode(&dm, &mon->mode);
11894+ return RGFW_TRUE;
11895+ }
11896+ return RGFW_FALSE;
11897+ } else return RGFW_FALSE;
11898+}
11899+
11900+RGFW_bool RGFW_monitor_requestMode(RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request) {
11901+HMONITOR src = mon->node->hMonitor;
11902+
11903+ MONITORINFOEX monitorInfo;
11904+ monitorInfo.cbSize = sizeof(MONITORINFOEX);
11905+ GetMonitorInfoA(src, (LPMONITORINFO)&monitorInfo);
11906+
11907+ DEVMODEW dm;
11908+ ZeroMemory(&dm, sizeof(dm));
11909+ dm.dmSize = sizeof(dm);
11910+
11911+ DWORD index = 0;
11912+
11913+ for (;;) {
11914+ if (EnumDisplaySettingsW(mon->node->adapterName, index, &dm) == 0) {
11915+ break;
11916+ }
11917+
11918+ index += 1;
11919+
11920+ if (request & RGFW_monitorScale) {
11921+ dm.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT;
11922+ dm.dmPelsWidth = (u32)mode->w;
11923+ dm.dmPelsHeight = (u32)mode->h;
11924+ }
11925+
11926+ if (request & RGFW_monitorRefresh) {
11927+ dm.dmFields |= DM_DISPLAYFREQUENCY;
11928+ dm.dmDisplayFrequency = (DWORD)mode->refreshRate;
11929+ }
11930+
11931+ if (request & RGFW_monitorRGB) {
11932+ dm.dmFields |= DM_BITSPERPEL;
11933+ dm.dmBitsPerPel = (DWORD)(mode->red + mode->green + mode->blue);
11934+ }
11935+
11936+ if (ChangeDisplaySettingsExW(mon->node->adapterName, &dm, NULL, CDS_TEST, NULL) == DISP_CHANGE_SUCCESSFUL) {
11937+ if (ChangeDisplaySettingsExW(mon->node->adapterName, &dm, NULL, CDS_UPDATEREGISTRY, NULL) == DISP_CHANGE_SUCCESSFUL) {
11938+ RGFW_win32_getMode(&dm, &mon->mode);
11939+ return RGFW_TRUE;
11940+ }
11941+ return RGFW_FALSE;
11942+ }
11943+ }
11944+
11945+ return RGFW_FALSE;
11946+}
11947+
11948+HICON RGFW_loadHandleImage(u8* data, i32 w, i32 h, RGFW_format format, BOOL icon);
11949+HICON RGFW_loadHandleImage(u8* data, i32 w, i32 h, RGFW_format format, BOOL icon) {
11950+ BITMAPV5HEADER bi;
11951+ ZeroMemory(&bi, sizeof(bi));
11952+ bi.bV5Size = sizeof(bi);
11953+ bi.bV5Width = (i32)w;
11954+ bi.bV5Height = -((LONG) h);
11955+ bi.bV5Planes = 1;
11956+ bi.bV5BitCount = (WORD)32;
11957+ bi.bV5Compression = BI_RGB;
11958+ HDC dc = GetDC(NULL);
11959+ u8* target = NULL;
11960+
11961+ HBITMAP color = CreateDIBSection(dc,
11962+ (BITMAPINFO*) &bi, DIB_RGB_COLORS, (void**) &target,
11963+ NULL, (DWORD) 0);
11964+
11965+ RGFW_copyImageData(target, w, h, RGFW_formatBGRA8, data, format, NULL);
11966+ ReleaseDC(NULL, dc);
11967+
11968+ HBITMAP mask = CreateBitmap((i32)w, (i32)h, 1, 1, NULL);
11969+
11970+ ICONINFO ii;
11971+ ZeroMemory(&ii, sizeof(ii));
11972+ ii.fIcon = icon;
11973+ ii.xHotspot = (u32)w / 2;
11974+ ii.yHotspot = (u32)h / 2;
11975+ ii.hbmMask = mask;
11976+ ii.hbmColor = color;
11977+
11978+ HICON handle = CreateIconIndirect(&ii);
11979+
11980+ DeleteObject(color);
11981+ DeleteObject(mask);
11982+
11983+ return handle;
11984+}
11985+
11986+RGFW_mouse* RGFW_createMouseStandard(RGFW_mouseIcon mouse) {
11987+ u32 mouseIcon = 0;
11988+
11989+ switch (mouse) {
11990+ case RGFW_mouseNormal: mouseIcon = OCR_NORMAL; break;
11991+ case RGFW_mouseArrow: mouseIcon = OCR_NORMAL; break;
11992+ case RGFW_mouseIbeam: mouseIcon = OCR_IBEAM; break;
11993+ case RGFW_mouseWait: mouseIcon = OCR_WAIT; break;
11994+ case RGFW_mouseCrosshair: mouseIcon = OCR_CROSS; break;
11995+ case RGFW_mouseProgress: mouseIcon = OCR_APPSTARTING; break;
11996+ case RGFW_mouseResizeNWSE: mouseIcon = OCR_SIZENWSE; break;
11997+ case RGFW_mouseResizeNESW: mouseIcon = OCR_SIZENESW; break;
11998+ case RGFW_mouseResizeEW: mouseIcon = OCR_SIZEWE; break;
11999+ case RGFW_mouseResizeNS: mouseIcon = OCR_SIZENS; break;
12000+ case RGFW_mouseResizeAll: mouseIcon = OCR_SIZEALL; break;
12001+ case RGFW_mouseNotAllowed: mouseIcon = OCR_NO; break;
12002+ case RGFW_mousePointingHand: mouseIcon = OCR_HAND; break;
12003+ case RGFW_mouseResizeNW: mouseIcon = OCR_SIZENWSE; break;
12004+ case RGFW_mouseResizeN: mouseIcon = OCR_SIZENS; break;
12005+ case RGFW_mouseResizeNE: mouseIcon = OCR_SIZENESW; break;
12006+ case RGFW_mouseResizeE: mouseIcon = OCR_SIZEWE; break;
12007+ case RGFW_mouseResizeSE: mouseIcon = OCR_SIZENWSE; break;
12008+ case RGFW_mouseResizeS: mouseIcon = OCR_SIZENS; break;
12009+ case RGFW_mouseResizeSW: mouseIcon = OCR_SIZENESW; break;
12010+ case RGFW_mouseResizeW: mouseIcon = OCR_SIZEWE; break;
12011+ default: return NULL;
12012+ }
12013+
12014+ char* icon = MAKEINTRESOURCEA(mouseIcon);
12015+ return LoadCursorA(NULL, icon);
12016+}
12017+
12018+RGFW_mouse* RGFW_createMouse(u8* data, i32 w, i32 h, RGFW_format format) {
12019+ HCURSOR cursor = (HCURSOR) RGFW_loadHandleImage(data, w, h, format, FALSE);
12020+ return cursor;
12021+}
12022+
12023+RGFW_bool RGFW_window_setMousePlatform(RGFW_window* win, RGFW_mouse* mouse) {
12024+ RGFW_ASSERT(win && mouse);
12025+ SetClassLongPtrA(win->src.window, GCLP_HCURSOR, (LPARAM) mouse);
12026+ SetCursor((HCURSOR)mouse);
12027+
12028+ return RGFW_FALSE;
12029+}
12030+
12031+void RGFW_freeMouse(RGFW_mouse* mouse) {
12032+ RGFW_ASSERT(mouse);
12033+ DestroyCursor((HCURSOR)mouse);
12034+}
12035+
12036+void RGFW_window_hide(RGFW_window* win) {
12037+ ShowWindow(win->src.window, SW_HIDE);
12038+}
12039+
12040+void RGFW_window_show(RGFW_window* win) {
12041+ if (win->internal.flags & RGFW_windowFocusOnShow) RGFW_window_focus(win);
12042+ ShowWindow(win->src.window, SW_RESTORE);
12043+}
12044+
12045+void RGFW_window_flash(RGFW_window* win, RGFW_flashRequest request) {
12046+ if (RGFW_window_isInFocus(win) && request) {
12047+ return;
12048+ }
12049+
12050+ FLASHWINFO desc;
12051+ RGFW_MEMZERO(&desc, sizeof(desc));
12052+
12053+ desc.cbSize = sizeof(desc);
12054+ desc.hwnd = win->src.window;
12055+
12056+ switch (request) {
12057+ case RGFW_flashCancel:
12058+ desc.dwFlags = FLASHW_STOP;
12059+ break;
12060+ case RGFW_flashBriefly:
12061+ desc.dwFlags = FLASHW_TRAY;
12062+ desc.uCount = 1;
12063+ break;
12064+ case RGFW_flashUntilFocused:
12065+ desc.dwFlags = (FLASHW_TRAY | FLASHW_TIMERNOFG);
12066+ break;
12067+ default: break;
12068+ }
12069+
12070+ FlashWindowEx(&desc);
12071+}
12072+
12073+#define RGFW_FREE_LIBRARY(x) if (x != NULL) FreeLibrary(x); x = NULL;
12074+void RGFW_deinitPlatform(void) {
12075+ #ifndef RGFW_NO_DPI
12076+ RGFW_FREE_LIBRARY(RGFW_Shcore_dll);
12077+ #endif
12078+
12079+ #ifndef RGFW_NO_WINMM
12080+ timeEndPeriod(1);
12081+ #ifndef RGFW_NO_LOAD_WINMM
12082+ RGFW_FREE_LIBRARY(RGFW_winmm_dll);
12083+ #endif
12084+ #endif
12085+
12086+ RGFW_FREE_LIBRARY(RGFW_wgl_dll);
12087+
12088+ RGFW_freeMouse(_RGFW->hiddenMouse);
12089+}
12090+
12091+
12092+void RGFW_window_closePlatform(RGFW_window* win) {
12093+ RemovePropW(win->src.window, L"RGFW");
12094+ ReleaseDC(win->src.window, win->src.hdc); /*!< delete device context */
12095+ DestroyWindow(win->src.window); /*!< delete window */
12096+
12097+ if (win->src.hIconSmall) DestroyIcon(win->src.hIconSmall);
12098+ if (win->src.hIconBig) DestroyIcon(win->src.hIconBig);
12099+}
12100+
12101+void RGFW_window_move(RGFW_window* win, i32 x, i32 y) {
12102+ RGFW_ASSERT(win != NULL);
12103+
12104+ win->x = x;
12105+ win->y = y;
12106+ SetWindowPos(win->src.window, HWND_TOP, win->x, win->y, 0, 0, SWP_NOSIZE);
12107+}
12108+
12109+void RGFW_window_resize(RGFW_window* win, i32 w, i32 h) {
12110+ RGFW_ASSERT(win != NULL);
12111+
12112+ win->w = w;
12113+ win->h = h;
12114+ RECT rect = { 0, 0, w, h};
12115+ DWORD style = RGFW_winapi_window_getStyle(win, win->internal.flags);
12116+ DWORD exStyle = RGFW_winapi_window_getExStyle(win, win->internal.flags);
12117+ AdjustWindowRectEx(&rect, style, FALSE, exStyle);
12118+ SetWindowPos(win->src.window, HWND_TOP, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER);
12119+}
12120+
12121+void RGFW_window_setName(RGFW_window* win, const char* name) {
12122+ RGFW_ASSERT(win != NULL);
12123+ if (name == NULL) name = "\0";
12124+
12125+ wchar_t wide_name[256];
12126+ MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_name, 256);
12127+ SetWindowTextW(win->src.window, wide_name);
12128+}
12129+
12130+#ifndef RGFW_NO_PASSTHROUGH
12131+void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) {
12132+ RGFW_ASSERT(win != NULL);
12133+ COLORREF key = 0;
12134+ BYTE alpha = 0;
12135+ DWORD flags = 0;
12136+ i32 exStyle = GetWindowLongW(win->src.window, GWL_EXSTYLE);
12137+
12138+ if (exStyle & WS_EX_LAYERED)
12139+ GetLayeredWindowAttributes(win->src.window, &key, &alpha, &flags);
12140+
12141+ if (passthrough)
12142+ exStyle |= (WS_EX_TRANSPARENT | WS_EX_LAYERED);
12143+ else {
12144+ exStyle &= ~WS_EX_TRANSPARENT;
12145+ if (exStyle & WS_EX_LAYERED && !(flags & LWA_ALPHA))
12146+ exStyle &= ~WS_EX_LAYERED;
12147+ }
12148+
12149+ SetWindowLongW(win->src.window, GWL_EXSTYLE, exStyle);
12150+
12151+ if (passthrough)
12152+ SetLayeredWindowAttributes(win->src.window, key, alpha, flags);
12153+}
12154+#endif
12155+
12156+RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_icon type) {
12157+ RGFW_ASSERT(win != NULL);
12158+ #ifndef RGFW_WIN95
12159+ if (win->src.hIconSmall && (type & RGFW_iconWindow)) DestroyIcon(win->src.hIconSmall);
12160+ if (win->src.hIconBig && (type & RGFW_iconTaskbar)) DestroyIcon(win->src.hIconBig);
12161+
12162+ if (data == NULL) {
12163+ HICON defaultIcon = LoadIcon(NULL, IDI_APPLICATION);
12164+ if (type & RGFW_iconWindow)
12165+ SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)defaultIcon);
12166+ if (type & RGFW_iconTaskbar)
12167+ SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)defaultIcon);
12168+ return RGFW_TRUE;
12169+ }
12170+
12171+ if (type & RGFW_iconWindow) {
12172+ win->src.hIconSmall = RGFW_loadHandleImage(data, w, h, format, TRUE);
12173+ SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)win->src.hIconSmall);
12174+ }
12175+ if (type & RGFW_iconTaskbar) {
12176+ win->src.hIconBig = RGFW_loadHandleImage(data, w, h, format, TRUE);
12177+ SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)win->src.hIconBig);
12178+ }
12179+ return RGFW_TRUE;
12180+ #else
12181+ RGFW_UNUSED(img);
12182+ RGFW_UNUSED(type);
12183+ return RGFW_FALSE;
12184+ #endif
12185+}
12186+
12187+RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) {
12188+ /* Open the clipboard */
12189+ if (OpenClipboard(NULL) == 0)
12190+ return -1;
12191+
12192+ /* Get the clipboard data as a Unicode string */
12193+ HANDLE hData = GetClipboardData(CF_UNICODETEXT);
12194+ if (hData == NULL) {
12195+ CloseClipboard();
12196+ return -1;
12197+ }
12198+
12199+ wchar_t* wstr = (wchar_t*) GlobalLock(hData);
12200+
12201+ RGFW_ssize_t textLen = 0;
12202+
12203+ {
12204+ setlocale(LC_ALL, "en_US.UTF-8");
12205+
12206+ textLen = (RGFW_ssize_t)wcstombs(NULL, wstr, 0) + 1;
12207+ if (str != NULL && (RGFW_ssize_t)strCapacity <= textLen - 1)
12208+ textLen = 0;
12209+
12210+ if (str != NULL && textLen) {
12211+ if (textLen > 1)
12212+ wcstombs(str, wstr, (size_t)(textLen));
12213+
12214+ str[textLen - 1] = '\0';
12215+ }
12216+ }
12217+
12218+ /* Release the clipboard data */
12219+ GlobalUnlock(hData);
12220+ CloseClipboard();
12221+
12222+ return textLen;
12223+}
12224+
12225+void RGFW_writeClipboard(const char* text, u32 textLen) {
12226+ HANDLE object;
12227+ WCHAR* buffer;
12228+
12229+ object = GlobalAlloc(GMEM_MOVEABLE, (1 + textLen) * sizeof(WCHAR));
12230+ if (!object)
12231+ return;
12232+
12233+ buffer = (WCHAR*) GlobalLock(object);
12234+ if (!buffer) {
12235+ GlobalFree(object);
12236+ return;
12237+ }
12238+
12239+ MultiByteToWideChar(CP_UTF8, 0, text, -1, buffer, (i32)textLen);
12240+ GlobalUnlock(object);
12241+
12242+ if (!OpenClipboard(_RGFW->root->src.window)) {
12243+ GlobalFree(object);
12244+ return;
12245+ }
12246+
12247+ EmptyClipboard();
12248+ SetClipboardData(CF_UNICODETEXT, object);
12249+ CloseClipboard();
12250+}
12251+
12252+void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y) {
12253+ RGFW_ASSERT(win != NULL);
12254+ win->internal.lastMouseX = x - win->x;
12255+ win->internal.lastMouseY = y - win->y;
12256+ SetCursorPos(x, y);
12257+}
12258+
12259+#ifdef RGFW_OPENGL
12260+RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char * extension, size_t len) {
12261+ const char* extensions = NULL;
12262+
12263+ RGFW_proc proc = RGFW_getProcAddress_OpenGL("wglGetExtensionsStringARB");
12264+ RGFW_proc proc2 = RGFW_getProcAddress_OpenGL("wglGetExtensionsStringEXT");
12265+
12266+ if (proc)
12267+ extensions = ((const char* (*)(HDC))proc)(wglGetCurrentDC());
12268+ else if (proc2)
12269+ extensions = ((const char*(*)(void))proc2)();
12270+ return extensions != NULL && RGFW_extensionSupportedStr(extensions, extension, len);
12271+}
12272+
12273+RGFW_proc RGFW_getProcAddress_OpenGL(const char* procname) {
12274+ RGFW_proc proc = (RGFW_proc)wglGetProcAddress(procname);
12275+ if (proc)
12276+ return proc;
12277+
12278+ return (RGFW_proc) GetProcAddress(RGFW_wgl_dll, procname);
12279+}
12280+
12281+void RGFW_win32_loadOpenGLFuncs(HWND dummyWin) {
12282+ if (wglSwapIntervalEXT != NULL && wglChoosePixelFormatARB != NULL && wglChoosePixelFormatARB != NULL)
12283+ return;
12284+
12285+ HDC dummy_dc = GetDC(dummyWin);
12286+ u32 pfd_flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
12287+
12288+ PIXELFORMATDESCRIPTOR pfd = {sizeof(pfd), 1, pfd_flags, PFD_TYPE_RGBA, 32, 8, PFD_MAIN_PLANE, 32, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 32, 8, 0, PFD_MAIN_PLANE, 0, 0, 0, 0};
12289+
12290+ int dummy_pixel_format = ChoosePixelFormat(dummy_dc, &pfd);
12291+ SetPixelFormat(dummy_dc, dummy_pixel_format, &pfd);
12292+
12293+ HGLRC dummy_context = wglCreateContext(dummy_dc);
12294+
12295+ HGLRC cur = wglGetCurrentContext();
12296+ wglMakeCurrent(dummy_dc, dummy_context);
12297+
12298+ wglCreateContextAttribsARB = ((PFNWGLCREATECONTEXTATTRIBSARBPROC(WINAPI *)(const char*)) wglGetProcAddress)("wglCreateContextAttribsARB");
12299+ wglChoosePixelFormatARB = ((PFNWGLCHOOSEPIXELFORMATARBPROC(WINAPI *)(const char*)) wglGetProcAddress)("wglChoosePixelFormatARB");
12300+
12301+ wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)(RGFW_proc)wglGetProcAddress("wglSwapIntervalEXT");
12302+ if (wglSwapIntervalEXT == NULL) {
12303+ RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load swap interval function");
12304+ }
12305+
12306+ wglMakeCurrent(dummy_dc, cur);
12307+ wglDeleteContext(dummy_context);
12308+ ReleaseDC(dummyWin, dummy_dc);
12309+}
12310+
12311+#define WGL_ACCELERATION_ARB 0x2003
12312+#define WGL_FULL_ACCELERATION_ARB 0x2027
12313+#define WGL_DRAW_TO_WINDOW_ARB 0x2001
12314+#define WGL_PIXEL_TYPE_ARB 0x2013
12315+#define WGL_TYPE_RGBA_ARB 0x202b
12316+#define WGL_SUPPORT_OPENGL_ARB 0x2010
12317+#define WGL_COLOR_BITS_ARB 0x2014
12318+#define WGL_DOUBLE_BUFFER_ARB 0x2011
12319+#define WGL_ALPHA_BITS_ARB 0x201b
12320+#define WGL_DEPTH_BITS_ARB 0x2022
12321+#define WGL_STENCIL_BITS_ARB 0x2023
12322+#define WGL_STEREO_ARB 0x2012
12323+#define WGL_AUX_BUFFERS_ARB 0x2024
12324+#define WGL_RED_BITS_ARB 0x2015
12325+#define WGL_GREEN_BITS_ARB 0x2017
12326+#define WGL_BLUE_BITS_ARB 0x2019
12327+#define WGL_ACCUM_RED_BITS_ARB 0x201e
12328+#define WGL_ACCUM_GREEN_BITS_ARB 0x201f
12329+#define WGL_ACCUM_BLUE_BITS_ARB 0x2020
12330+#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021
12331+#define WGL_COLORSPACE_SRGB_EXT 0x3089
12332+#define WGL_CONTEXT_OPENGL_NO_ERROR_ARB 0x31b3
12333+#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
12334+#define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0x0000
12335+#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
12336+#define WGL_CONTEXT_FLAGS_ARB 0x2094
12337+#define WGL_ACCESS_READ_WRITE_NV 0x00000001
12338+#define WGL_COVERAGE_SAMPLES_NV 0x2042
12339+#define WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004
12340+#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
12341+#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
12342+#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
12343+#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
12344+#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
12345+#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
12346+#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9
12347+#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
12348+#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001
12349+#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
12350+
12351+RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints) {
12352+ const char flushControl[] = "WGL_ARB_context_flush_control";
12353+ const char noError[] = "WGL_ARB_create_context_no_error";
12354+ const char robustness[] = "WGL_ARB_create_context_robustness";
12355+
12356+ win->src.ctx.native = ctx;
12357+ win->src.gfxType = RGFW_gfxNativeOpenGL;
12358+
12359+ PIXELFORMATDESCRIPTOR pfd;
12360+ pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
12361+ pfd.nVersion = 1;
12362+ pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
12363+ pfd.iPixelType = PFD_TYPE_RGBA;
12364+ pfd.iLayerType = PFD_MAIN_PLANE;
12365+ pfd.cColorBits = 32;
12366+ pfd.cAlphaBits = 8;
12367+ pfd.cDepthBits = 24;
12368+ pfd.cStencilBits = (BYTE)hints->stencil;
12369+ pfd.cAuxBuffers = (BYTE)hints->auxBuffers;
12370+ if (hints->stereo) pfd.dwFlags |= PFD_STEREO;
12371+
12372+ /* try to create the pixel format we want for OpenGL and then try to create an OpenGL context for the specified version */
12373+ if (hints->renderer == RGFW_glSoftware)
12374+ pfd.dwFlags |= PFD_GENERIC_FORMAT | PFD_GENERIC_ACCELERATED;
12375+
12376+ /* get pixel format, default to a basic pixel format */
12377+ int pixel_format = ChoosePixelFormat(win->src.hdc, &pfd);
12378+ if (wglChoosePixelFormatARB != NULL) {
12379+ i32 pixel_format_attribs[50];
12380+ RGFW_attribStack stack;
12381+ RGFW_attribStack_init(&stack, pixel_format_attribs, 50);
12382+
12383+ RGFW_attribStack_pushAttribs(&stack, WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB);
12384+ RGFW_attribStack_pushAttribs(&stack, WGL_DRAW_TO_WINDOW_ARB, 1);
12385+ RGFW_attribStack_pushAttribs(&stack, WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB);
12386+ RGFW_attribStack_pushAttribs(&stack, WGL_SUPPORT_OPENGL_ARB, 1);
12387+ RGFW_attribStack_pushAttribs(&stack, WGL_COLOR_BITS_ARB, 32);
12388+ RGFW_attribStack_pushAttribs(&stack, WGL_DOUBLE_BUFFER_ARB, 1);
12389+ RGFW_attribStack_pushAttribs(&stack, WGL_ALPHA_BITS_ARB, hints->alpha);
12390+ RGFW_attribStack_pushAttribs(&stack, WGL_DEPTH_BITS_ARB, hints->depth);
12391+ RGFW_attribStack_pushAttribs(&stack, WGL_STENCIL_BITS_ARB, hints->stencil);
12392+ RGFW_attribStack_pushAttribs(&stack, WGL_STEREO_ARB, hints->stereo);
12393+ RGFW_attribStack_pushAttribs(&stack, WGL_AUX_BUFFERS_ARB, hints->auxBuffers);
12394+ RGFW_attribStack_pushAttribs(&stack, WGL_RED_BITS_ARB, hints->red);
12395+ RGFW_attribStack_pushAttribs(&stack, WGL_GREEN_BITS_ARB, hints->blue);
12396+ RGFW_attribStack_pushAttribs(&stack, WGL_BLUE_BITS_ARB, hints->green);
12397+ RGFW_attribStack_pushAttribs(&stack, WGL_ACCUM_RED_BITS_ARB, hints->accumRed);
12398+ RGFW_attribStack_pushAttribs(&stack, WGL_ACCUM_GREEN_BITS_ARB, hints->accumGreen);
12399+ RGFW_attribStack_pushAttribs(&stack, WGL_ACCUM_BLUE_BITS_ARB, hints->accumBlue);
12400+ RGFW_attribStack_pushAttribs(&stack, WGL_ACCUM_ALPHA_BITS_ARB, hints->accumAlpha);
12401+
12402+ if(hints->sRGB) {
12403+ if (hints->profile != RGFW_glES)
12404+ RGFW_attribStack_pushAttribs(&stack, WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, 1);
12405+ else
12406+ RGFW_attribStack_pushAttribs(&stack, WGL_COLORSPACE_SRGB_EXT, hints->sRGB);
12407+ }
12408+
12409+ RGFW_attribStack_pushAttribs(&stack, WGL_COVERAGE_SAMPLES_NV, hints->samples);
12410+
12411+ RGFW_attribStack_pushAttribs(&stack, 0, 0);
12412+
12413+ int new_pixel_format;
12414+ UINT num_formats;
12415+ wglChoosePixelFormatARB(win->src.hdc, pixel_format_attribs, 0, 1, &new_pixel_format, &num_formats);
12416+ if (!num_formats)
12417+ RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to create a pixel format for WGL");
12418+ else pixel_format = new_pixel_format;
12419+ }
12420+
12421+ PIXELFORMATDESCRIPTOR suggested;
12422+ if (!DescribePixelFormat(win->src.hdc, pixel_format, sizeof(suggested), &suggested) ||
12423+ !SetPixelFormat(win->src.hdc, pixel_format, &pfd))
12424+ RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to set the WGL pixel format");
12425+
12426+ if (wglCreateContextAttribsARB != NULL) {
12427+ /* create OpenGL/WGL context for the specified version */
12428+ i32 attribs[40];
12429+ RGFW_attribStack stack;
12430+ RGFW_attribStack_init(&stack, attribs, 50);
12431+
12432+
12433+ i32 mask = 0;
12434+ switch (hints->profile) {
12435+ case RGFW_glES: mask |= WGL_CONTEXT_ES_PROFILE_BIT_EXT; break;
12436+ case RGFW_glCompatibility: mask |= WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; break;
12437+ case RGFW_glForwardCompatibility: mask |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; break;
12438+ case RGFW_glCore: mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB; break;
12439+ default: mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB; break;
12440+ }
12441+
12442+ RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_PROFILE_MASK_ARB, mask);
12443+
12444+ if (hints->minor || hints->major) {
12445+ RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_MAJOR_VERSION_ARB, hints->major);
12446+ RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_MINOR_VERSION_ARB, hints->minor);
12447+ }
12448+
12449+ if (RGFW_extensionSupportedPlatform_OpenGL(noError, sizeof(noError)))
12450+ RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_OPENGL_NO_ERROR_ARB, hints->noError);
12451+
12452+ if (RGFW_extensionSupportedPlatform_OpenGL(flushControl, sizeof(flushControl))) {
12453+ if (hints->releaseBehavior == RGFW_glReleaseFlush) {
12454+ RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); /* WGL_CONTEXT_RELEASE_BEHAVIOR_ARB */
12455+ } else if (hints->releaseBehavior == RGFW_glReleaseNone) {
12456+ RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB);
12457+ }
12458+ }
12459+
12460+ i32 flags = 0;
12461+ if (hints->debug) flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
12462+ if (hints->robustness && RGFW_extensionSupportedPlatform_OpenGL(robustness, sizeof(robustness))) flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB;
12463+ if (flags) {
12464+ RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_FLAGS_ARB, flags);
12465+ }
12466+
12467+
12468+ RGFW_attribStack_pushAttribs(&stack, 0, 0);
12469+
12470+ win->src.ctx.native->ctx = (HGLRC)wglCreateContextAttribsARB(win->src.hdc, NULL, attribs);
12471+ }
12472+
12473+ if (wglCreateContextAttribsARB == NULL || win->src.ctx.native->ctx == NULL) { /* fall back to a default context (probably OpenGL 2 or something) */
12474+ RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to create an accelerated OpenGL Context.");
12475+ win->src.ctx.native->ctx = wglCreateContext(win->src.hdc);
12476+ }
12477+
12478+ ReleaseDC(win->src.window, win->src.hdc);
12479+ win->src.hdc = GetDC(win->src.window);
12480+
12481+ if (hints->share) {
12482+ wglShareLists((HGLRC)RGFW_getCurrentContext_OpenGL(), hints->share->ctx);
12483+ }
12484+
12485+ wglMakeCurrent(win->src.hdc, win->src.ctx.native->ctx);
12486+ RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized.");
12487+ return RGFW_TRUE;
12488+}
12489+
12490+void RGFW_window_deleteContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx) {
12491+ wglDeleteContext((HGLRC) ctx->ctx); /*!< delete OpenGL context */
12492+ win->src.ctx.native->ctx = NULL;
12493+ RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context freed.");
12494+}
12495+
12496+void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win) {
12497+ if (win == NULL)
12498+ wglMakeCurrent(NULL, NULL);
12499+ else
12500+ wglMakeCurrent(win->src.hdc, (HGLRC) win->src.ctx.native->ctx);
12501+}
12502+void* RGFW_getCurrentContext_OpenGL(void) {
12503+ return wglGetCurrentContext();
12504+}
12505+void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) {
12506+ RGFW_ASSERT(win->src.ctx.native);
12507+ SwapBuffers(win->src.hdc);
12508+}
12509+
12510+void RGFW_window_swapInterval_OpenGL(RGFW_window* win, i32 swapInterval) {
12511+ RGFW_ASSERT(win != NULL);
12512+ if (wglSwapIntervalEXT == NULL || wglSwapIntervalEXT(swapInterval) == FALSE)
12513+ RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to set swap interval");
12514+}
12515+#endif
12516+
12517+RGFW_bool RGFW_createUTF8FromWideStringWin32(const WCHAR* source, char* output, size_t max) {
12518+ i32 size = 0;
12519+ if (source == NULL) {
12520+ return RGFW_FALSE;
12521+ }
12522+ size = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL);
12523+ if (!size) {
12524+ return RGFW_FALSE;
12525+ }
12526+
12527+ if (size > (i32)max)
12528+ size = (i32)max;
12529+
12530+ if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, output, size, NULL, NULL)) {
12531+ return RGFW_FALSE;
12532+ }
12533+
12534+ output[size] = 0;
12535+ return RGFW_TRUE;
12536+}
12537+
12538+#ifdef RGFW_WEBGPU
12539+WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance instance) {
12540+ WGPUSurfaceDescriptor surfaceDesc = {0};
12541+ WGPUSurfaceSourceWindowsHWND fromHwnd = {0};
12542+ fromHwnd.chain.sType = WGPUSType_SurfaceSourceWindowsHWND;
12543+ fromHwnd.hwnd = window->src.window;
12544+
12545+ fromHwnd.hinstance = GetModuleHandle(NULL);
12546+
12547+ surfaceDesc.nextInChain = (WGPUChainedStruct*)&fromHwnd.chain;
12548+ return wgpuInstanceCreateSurface(instance, &surfaceDesc);
12549+}
12550+#endif
12551+
12552+#endif /* RGFW_WINDOWS */
12553+
12554+/*
12555+ End of Windows defines
12556+*/
12557+
12558+
12559+
12560+/*
12561+
12562+ Start of MacOS defines
12563+
12564+
12565+*/
12566+
12567+#if defined(RGFW_MACOS)
12568+/*
12569+ based on silicon.h
12570+ start of cocoa wrapper
12571+*/
12572+
12573+#include <CoreGraphics/CoreGraphics.h>
12574+#include <ApplicationServices/ApplicationServices.h>
12575+#include <objc/runtime.h>
12576+#include <objc/message.h>
12577+#include <mach/mach_time.h>
12578+
12579+#include <Carbon/Carbon.h>
12580+
12581+typedef TISInputSourceRef (*PFN_TISCopyCurrentKeyboardLayoutInputSource)(void);
12582+PFN_TISCopyCurrentKeyboardLayoutInputSource TISCopyCurrentKeyboardLayoutInputSourceSrc;
12583+#define TISCopyCurrentKeyboardLayoutInputSource TISCopyCurrentKeyboardLayoutInputSourceSrc
12584+
12585+typedef CFDataRef (*PFN_TISGetInputSourceProperty)(TISInputSourceRef, CFStringRef);
12586+PFN_TISGetInputSourceProperty TISGetInputSourcePropertySrc;
12587+#define TISGetInputSourceProperty TISGetInputSourcePropertySrc
12588+
12589+typedef u8 (*PFN_LMGetKbdType)(void);
12590+PFN_LMGetKbdType LMGetKbdTypeSrc;
12591+#define LMGetKbdType LMGetKbdTypeSrc
12592+
12593+CFStringRef kTISPropertyUnicodeKeyLayoutDataSrc;
12594+
12595+#ifndef __OBJC__
12596+typedef CGRect NSRect;
12597+typedef CGPoint NSPoint;
12598+typedef CGSize NSSize;
12599+
12600+typedef const char* NSPasteboardType;
12601+typedef unsigned long NSUInteger;
12602+typedef long NSInteger;
12603+typedef NSInteger NSModalResponse;
12604+
12605+typedef enum NSRequestUserAttentionType {
12606+ NSCriticalRequest = 0,
12607+ NSInformationalRequest = 10
12608+} NSRequestUserAttentionType;
12609+
12610+typedef enum NSApplicationActivationPolicy {
12611+ NSApplicationActivationPolicyRegular,
12612+ NSApplicationActivationPolicyAccessory,
12613+ NSApplicationActivationPolicyProhibited
12614+} NSApplicationActivationPolicy;
12615+
12616+typedef RGFW_ENUM(u32, NSBackingStoreType) {
12617+ NSBackingStoreRetained = 0,
12618+ NSBackingStoreNonretained = 1,
12619+ NSBackingStoreBuffered = 2
12620+};
12621+
12622+typedef RGFW_ENUM(u32, NSWindowStyleMask) {
12623+ NSWindowStyleMaskBorderless = 0,
12624+ NSWindowStyleMaskTitled = 1 << 0,
12625+ NSWindowStyleMaskClosable = 1 << 1,
12626+ NSWindowStyleMaskMiniaturizable = 1 << 2,
12627+ NSWindowStyleMaskResizable = 1 << 3,
12628+ NSWindowStyleMaskTexturedBackground = 1 << 8, /* deprecated */
12629+ NSWindowStyleMaskUnifiedTitleAndToolbar = 1 << 12,
12630+ NSWindowStyleMaskFullScreen = 1 << 14,
12631+ NSWindowStyleMaskFullSizeContentView = 1 << 15,
12632+ NSWindowStyleMaskUtilityWindow = 1 << 4,
12633+ NSWindowStyleMaskDocModalWindow = 1 << 6,
12634+ NSWindowStyleMaskNonactivatingpanel = 1 << 7,
12635+ NSWindowStyleMaskHUDWindow = 1 << 13
12636+};
12637+
12638+#define NSPasteboardTypeString "public.utf8-plain-text"
12639+
12640+typedef RGFW_ENUM(i32, NSDragOperation) {
12641+ NSDragOperationNone = 0,
12642+ NSDragOperationCopy = 1,
12643+ NSDragOperationLink = 2,
12644+ NSDragOperationGeneric = 4,
12645+ NSDragOperationPrivate = 8,
12646+ NSDragOperationMove = 16,
12647+ NSDragOperationDelete = 32,
12648+ NSDragOperationEvery = (int)ULONG_MAX
12649+};
12650+
12651+typedef RGFW_ENUM(NSInteger, NSOpenGLContextParameter) {
12652+ NSOpenGLContextParameterSwapInterval = 222, /* 1 param. 0 -> Don't sync, 1 -> Sync to vertical retrace */
12653+ NSOpenGLContextParametectxaceOrder = 235, /* 1 param. 1 -> Above Window (default), -1 -> Below Window */
12654+ NSOpenGLContextParametectxaceOpacity = 236, /* 1 param. 1-> Surface is opaque (default), 0 -> non-opaque */
12655+ NSOpenGLContextParametectxaceBackingSize = 304, /* 2 params. Width/height of surface backing size */
12656+ NSOpenGLContextParameterReclaimResources = 308, /* 0 params. */
12657+ NSOpenGLContextParameterCurrentRendererID = 309, /* 1 param. Retrieves the current renderer ID */
12658+ NSOpenGLContextParameterGPUVertexProcessing = 310, /* 1 param. Currently processing vertices with GPU (get) */
12659+ NSOpenGLContextParameterGPUFragmentProcessing = 311, /* 1 param. Currently processing fragments with GPU (get) */
12660+ NSOpenGLContextParameterHasDrawable = 314, /* 1 param. Boolean returned if drawable is attached */
12661+ NSOpenGLContextParameterMPSwapsInFlight = 315, /* 1 param. Max number of swaps queued by the MP GL engine */
12662+
12663+ NSOpenGLContextParameterSwapRectangle API_DEPRECATED("", macos(10.0, 10.14)) = 200, /* 4 params. Set or get the swap rectangle {x, y, w, h} */
12664+ NSOpenGLContextParameterSwapRectangleEnable API_DEPRECATED("", macos(10.0, 10.14)) = 201, /* Enable or disable the swap rectangle */
12665+ NSOpenGLContextParameterRasterizationEnable API_DEPRECATED("", macos(10.0, 10.14)) = 221, /* Enable or disable all rasterization */
12666+ NSOpenGLContextParameterStateValidation API_DEPRECATED("", macos(10.0, 10.14)) = 301, /* Validate state for multi-screen functionality */
12667+ NSOpenGLContextParametectxaceSurfaceVolatile API_DEPRECATED("", macos(10.0, 10.14)) = 306, /* 1 param. Surface volatile state */
12668+};
12669+
12670+typedef RGFW_ENUM(NSInteger, NSWindowButton) {
12671+ NSWindowCloseButton = 0,
12672+ NSWindowMiniaturizeButton = 1,
12673+ NSWindowZoomButton = 2,
12674+ NSWindowToolbarButton = 3,
12675+ NSWindowDocumentIconButton = 4,
12676+ NSWindowDocumentVersionsButton = 6,
12677+ NSWindowFullScreenButton = 7,
12678+};
12679+
12680+#define NSPasteboardTypeURL "public.url"
12681+#define NSPasteboardTypeFileURL "public.file-url"
12682+#define NSTrackingMouseEnteredAndExited 0x01
12683+#define NSTrackingMouseMoved 0x02
12684+#define NSTrackingCursorUpdate 0x04
12685+#define NSTrackingActiveWhenFirstResponder 0x10
12686+#define NSTrackingActiveInKeyWindow 0x20
12687+#define NSTrackingActiveInActiveApp 0x40
12688+#define NSTrackingActiveAlways 0x80
12689+#define NSTrackingAssumeInside 0x100
12690+#define NSTrackingInVisibleRect 0x200
12691+#define NSTrackingEnabledDuringMouseDrag 0x400
12692+enum {
12693+ NSOpenGLPFAAllRenderers = 1, /* choose from all available renderers */
12694+ NSOpenGLPFATripleBuffer = 3, /* choose a triple buffered pixel format */
12695+ NSOpenGLPFADoubleBuffer = 5, /* choose a double buffered pixel format */
12696+ NSOpenGLPFAAuxBuffers = 7, /* number of aux buffers */
12697+ NSOpenGLPFAColorSize = 8, /* number of color buffer bits */
12698+ NSOpenGLPFAAlphaSize = 11, /* number of alpha component bits */
12699+ NSOpenGLPFADepthSize = 12, /* number of depth buffer bits */
12700+ NSOpenGLPFAStencilSize = 13, /* number of stencil buffer bits */
12701+ NSOpenGLPFAAccumSize = 14, /* number of accum buffer bits */
12702+ NSOpenGLPFAMinimumPolicy = 51, /* never choose smaller buffers than requested */
12703+ NSOpenGLPFAMaximumPolicy = 52, /* choose largest buffers of type requested */
12704+ NSOpenGLPFASampleBuffers = 55, /* number of multi sample buffers */
12705+ NSOpenGLPFASamples = 56, /* number of samples per multi sample buffer */
12706+ NSOpenGLPFAAuxDepthStencil = 57, /* each aux buffer has its own depth stencil */
12707+ NSOpenGLPFAColorFloat = 58, /* color buffers store floating point pixels */
12708+ NSOpenGLPFAMultisample = 59, /* choose multisampling */
12709+ NSOpenGLPFASupersample = 60, /* choose supersampling */
12710+ NSOpenGLPFASampleAlpha = 61, /* request alpha filtering */
12711+ NSOpenGLPFARendererID = 70, /* request renderer by ID */
12712+ NSOpenGLPFANoRecovery = 72, /* disable all failure recovery systems */
12713+ NSOpenGLPFAAccelerated = 73, /* choose a hardware accelerated renderer */
12714+ NSOpenGLPFAClosestPolicy = 74, /* choose the closest color buffer to request */
12715+ NSOpenGLPFABackingStore = 76, /* back buffer contents are valid after swap */
12716+ NSOpenGLPFAScreenMask = 84, /* bit mask of supported physical screens */
12717+ NSOpenGLPFAAllowOfflineRenderers = 96, /* allow use of offline renderers */
12718+ NSOpenGLPFAAcceleratedCompute = 97, /* choose a hardware accelerated compute device */
12719+ NSOpenGLPFAOpenGLProfile = 99, /* specify an OpenGL Profile to use */
12720+ NSOpenGLProfileVersionLegacy = 0x1000, /* The requested profile is a legacy (pre-OpenGL 3.0) profile. */
12721+ NSOpenGLProfileVersion3_2Core = 0x3200, /* The 3.2 Profile of OpenGL */
12722+ NSOpenGLProfileVersion4_1Core = 0x3200, /* The 4.1 profile of OpenGL */
12723+ NSOpenGLPFAVirtualScreenCount = 128, /* number of virtual screens in this format */
12724+ NSOpenGLPFAStereo = 6,
12725+ NSOpenGLPFAOffScreen = 53,
12726+ NSOpenGLPFAFullScreen = 54,
12727+ NSOpenGLPFASingleRenderer = 71,
12728+ NSOpenGLPFARobust = 75,
12729+ NSOpenGLPFAMPSafe = 78,
12730+ NSOpenGLPFAWindow = 80,
12731+ NSOpenGLPFAMultiScreen = 81,
12732+ NSOpenGLPFACompliant = 83,
12733+ NSOpenGLPFAPixelBuffer = 90,
12734+ NSOpenGLPFARemotePixelBuffer = 91,
12735+};
12736+
12737+typedef RGFW_ENUM(u32, NSEventType) { /* various types of events */
12738+ NSEventTypeApplicationDefined = 15,
12739+};
12740+typedef unsigned long long NSEventMask;
12741+
12742+typedef enum NSEventModifierFlags {
12743+ NSEventModifierFlagCapsLock = 1 << 16,
12744+ NSEventModifierFlagShift = 1 << 17,
12745+ NSEventModifierFlagControl = 1 << 18,
12746+ NSEventModifierFlagOption = 1 << 19,
12747+ NSEventModifierFlagCommand = 1 << 20,
12748+ NSEventModifierFlagNumericPad = 1 << 21
12749+} NSEventModifierFlags;
12750+
12751+typedef RGFW_ENUM(NSUInteger, NSBitmapFormat) {
12752+ NSBitmapFormatAlphaFirst = 1 << 0, /* 0 means is alpha last (RGBA, CMYKA, etc.) */
12753+ NSBitmapFormatAlphaNonpremultiplied = 1 << 1, /* 0 means is premultiplied */
12754+ NSBitmapFormatFloatingpointSamples = 1 << 2, /* 0 is integer */
12755+
12756+ NSBitmapFormatSixteenBitLittleEndian = (1 << 8),
12757+ NSBitmapFormatThirtyTwoBitLittleEndian = (1 << 9),
12758+ NSBitmapFormatSixteenBitBigEndian = (1 << 10),
12759+ NSBitmapFormatThirtyTwoBitBigEndian = (1 << 11)
12760+};
12761+
12762+#else
12763+#import <AppKit/AppKit.h>
12764+#include <Foundation/Foundation.h>
12765+#endif /* notdef __OBJC__ */
12766+
12767+#ifdef __arm64__
12768+ /* ARM just uses objc_msgSend */
12769+#define abi_objc_msgSend_stret objc_msgSend
12770+#define abi_objc_msgSend_fpret objc_msgSend
12771+#else /* __i386__ */
12772+ /* x86 just uses abi_objc_msgSend_fpret and (NSColor *)objc_msgSend_id respectively */
12773+#define abi_objc_msgSend_stret objc_msgSend_stret
12774+#define abi_objc_msgSend_fpret objc_msgSend_fpret
12775+#endif
12776+
12777+#define NSAlloc(nsclass) objc_msgSend_id((id)nsclass, sel_registerName("alloc"))
12778+#define objc_msgSend_bool(x, y) ((BOOL (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
12779+#define objc_msgSend_void(x, y) ((void (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
12780+#define objc_msgSend_void_id(x, y, z) ((void (*)(id, SEL, id))objc_msgSend) ((id)x, (SEL)y, (id)z)
12781+#define objc_msgSend_uint(x, y) ((NSUInteger (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
12782+#define objc_msgSend_void_bool(x, y, z) ((void (*)(id, SEL, BOOL))objc_msgSend) ((id)(x), (SEL)y, (BOOL)z)
12783+#define objc_msgSend_bool_void(x, y) ((BOOL (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
12784+#define objc_msgSend_void_SEL(x, y, z) ((void (*)(id, SEL, SEL))objc_msgSend) ((id)(x), (SEL)y, (SEL)z)
12785+#define objc_msgSend_id(x, y) ((id (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
12786+#define objc_msgSend_id_id(x, y, z) ((id (*)(id, SEL, id))objc_msgSend) ((id)(x), (SEL)y, (id)z)
12787+#define objc_msgSend_id_bool(x, y, z) ((BOOL (*)(id, SEL, id))objc_msgSend) ((id)(x), (SEL)y, (id)z)
12788+#define objc_msgSend_int(x, y, z) ((id (*)(id, SEL, int))objc_msgSend) ((id)(x), (SEL)y, (int)z)
12789+#define objc_msgSend_arr(x, y, z) ((id (*)(id, SEL, int))objc_msgSend) ((id)(x), (SEL)y, (int)z)
12790+#define objc_msgSend_ptr(x, y, z) ((id (*)(id, SEL, void*))objc_msgSend) ((id)(x), (SEL)y, (void*)z)
12791+#define objc_msgSend_class(x, y) ((id (*)(Class, SEL))objc_msgSend) ((Class)(x), (SEL)y)
12792+#define objc_msgSend_class_char(x, y, z) ((id (*)(Class, SEL, char*))objc_msgSend) ((Class)(x), (SEL)y, (char*)z)
12793+
12794+#define NSRelease(obj) objc_msgSend_void((id)obj, sel_registerName("release"))
12795+RGFWDEF id NSString_stringWithUTF8String(const char* str);
12796+id NSString_stringWithUTF8String(const char* str) {
12797+ return ((id(*)(id, SEL, const char*))objc_msgSend) ((id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), str);
12798+}
12799+
12800+RGFWDEF float RGFW_cocoaYTransform(float y);
12801+float RGFW_cocoaYTransform(float y) { return (float)(CGDisplayBounds(CGMainDisplayID()).size.height - (double)y - (double)1.0f); }
12802+
12803+const char* NSString_to_char(id str);
12804+const char* NSString_to_char(id str) {
12805+ return ((const char* (*)(id, SEL)) objc_msgSend) ((id)(id)str, sel_registerName("UTF8String"));
12806+}
12807+
12808+unsigned char* NSBitmapImageRep_bitmapData(id imageRep);
12809+unsigned char* NSBitmapImageRep_bitmapData(id imageRep) {
12810+ return ((unsigned char* (*)(id, SEL))objc_msgSend) ((id)imageRep, sel_registerName("bitmapData"));
12811+}
12812+
12813+id NSBitmapImageRep_initWithBitmapData(unsigned char** planes, NSInteger width, NSInteger height, NSInteger bps, NSInteger spp, bool alpha, bool isPlanar, const char* colorSpaceName, NSBitmapFormat bitmapFormat, NSInteger rowBytes, NSInteger pixelBits);
12814+id NSBitmapImageRep_initWithBitmapData(unsigned char** planes, NSInteger width, NSInteger height, NSInteger bps, NSInteger spp, bool alpha, bool isPlanar, const char* colorSpaceName, NSBitmapFormat bitmapFormat, NSInteger rowBytes, NSInteger pixelBits) {
12815+ SEL func = sel_registerName("initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bitmapFormat:bytesPerRow:bitsPerPixel:");
12816+
12817+ return (id) ((id(*)(id, SEL, unsigned char**, NSInteger, NSInteger, NSInteger, NSInteger, bool, bool, id, NSBitmapFormat, NSInteger, NSInteger))objc_msgSend)
12818+ (NSAlloc((id)objc_getClass("NSBitmapImageRep")), func, planes, width, height, bps, spp, alpha, isPlanar, NSString_stringWithUTF8String(colorSpaceName), bitmapFormat, rowBytes, pixelBits);
12819+}
12820+
12821+id NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha);
12822+id NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha) {
12823+ Class nsclass = objc_getClass("NSColor");
12824+ SEL func = sel_registerName("colorWithSRGBRed:green:blue:alpha:");
12825+ return ((id(*)(id, SEL, CGFloat, CGFloat, CGFloat, CGFloat))objc_msgSend)
12826+ ((id)nsclass, func, red, green, blue, alpha);
12827+}
12828+
12829+id NSPasteboard_generalPasteboard(void);
12830+id NSPasteboard_generalPasteboard(void) {
12831+ return (id) objc_msgSend_id((id)objc_getClass("NSPasteboard"), sel_registerName("generalPasteboard"));
12832+}
12833+
12834+id* cstrToNSStringArray(char** strs, size_t len);
12835+id* cstrToNSStringArray(char** strs, size_t len) {
12836+ static id nstrs[6];
12837+ size_t i;
12838+ for (i = 0; i < len; i++)
12839+ nstrs[i] = NSString_stringWithUTF8String(strs[i]);
12840+
12841+ return nstrs;
12842+}
12843+
12844+const char* NSPasteboard_stringForType(id pasteboard, NSPasteboardType dataType, size_t* len);
12845+const char* NSPasteboard_stringForType(id pasteboard, NSPasteboardType dataType, size_t* len) {
12846+ SEL func = sel_registerName("stringForType:");
12847+ id nsstr = NSString_stringWithUTF8String((const char*)dataType);
12848+ id nsString = ((id(*)(id, SEL, id))objc_msgSend)(pasteboard, func, nsstr);
12849+ const char* str = NSString_to_char(nsString);
12850+ if (len != NULL)
12851+ *len = (size_t)((NSUInteger(*)(id, SEL, int))objc_msgSend)(nsString, sel_registerName("maximumLengthOfBytesUsingEncoding:"), 4);
12852+ return str;
12853+}
12854+
12855+id c_array_to_NSArray(void* array, size_t len);
12856+id c_array_to_NSArray(void* array, size_t len) {
12857+ return ((id (*)(id, SEL, void*, NSUInteger))objc_msgSend) (NSAlloc(objc_getClass("NSArray")), sel_registerName("initWithObjects:count:"), array, len);
12858+}
12859+
12860+
12861+void NSregisterForDraggedTypes(id view, NSPasteboardType* newTypes, size_t len);
12862+void NSregisterForDraggedTypes(id view, NSPasteboardType* newTypes, size_t len) {
12863+ id* ntypes = cstrToNSStringArray((char**)newTypes, len);
12864+
12865+ id array = c_array_to_NSArray(ntypes, len);
12866+ objc_msgSend_void_id(view, sel_registerName("registerForDraggedTypes:"), array);
12867+ NSRelease(array);
12868+}
12869+
12870+NSInteger NSPasteBoard_declareTypes(id pasteboard, NSPasteboardType* newTypes, size_t len, void* owner);
12871+NSInteger NSPasteBoard_declareTypes(id pasteboard, NSPasteboardType* newTypes, size_t len, void* owner) {
12872+ id* ntypes = cstrToNSStringArray((char**)newTypes, len);
12873+
12874+ SEL func = sel_registerName("declareTypes:owner:");
12875+
12876+ id array = c_array_to_NSArray(ntypes, len);
12877+
12878+ NSInteger output = ((NSInteger(*)(id, SEL, id, void*))objc_msgSend)
12879+ (pasteboard, func, array, owner);
12880+ NSRelease(array);
12881+
12882+ return output;
12883+}
12884+
12885+#define NSRetain(obj) objc_msgSend_void((id)obj, sel_registerName("retain"))
12886+
12887+/*
12888+ End of cocoa wrapper
12889+*/
12890+
12891+static id RGFW__osxCustomInitWithRGFWWindow(id self, SEL _cmd, RGFW_window* win) {
12892+ RGFW_UNUSED(_cmd);
12893+ struct objc_super s = { self, class_getSuperclass(object_getClass(self)) };
12894+
12895+ CGRect rect;
12896+ rect.origin.x = 0;
12897+ rect.origin.y = 0;
12898+ rect.size.width = (double)win->w;
12899+ rect.size.height = (double)win->h;
12900+
12901+ self = ((id (*)(struct objc_super*, SEL, CGRect))objc_msgSendSuper)(
12902+ &s, sel_registerName("initWithFrame:"), rect
12903+ );
12904+
12905+ if (self != nil) {
12906+ object_setInstanceVariable(self, "RGFW_window", win);
12907+ object_setInstanceVariable(self, "trackingArea", nil);
12908+
12909+ object_setInstanceVariable(
12910+ self, "markedText",
12911+ ((id (*)(id, SEL))objc_msgSend)(
12912+ ((id (*)(Class, SEL))objc_msgSend)(objc_getClass("NSMutableAttributedString"), sel_registerName("alloc")),
12913+ sel_registerName("init")
12914+ )
12915+ );
12916+
12917+ ((void (*)(id, SEL))objc_msgSend)(self, sel_registerName("updateTrackingAreas"));
12918+
12919+ ((void (*)(id, SEL, id))objc_msgSend)(
12920+ self, sel_registerName("registerForDraggedTypes:"),
12921+ ((id (*)(Class, SEL, id))objc_msgSend)(
12922+ objc_getClass("NSArray"),
12923+ sel_registerName("arrayWithObject:"),
12924+ ((id (*)(Class, SEL, const char*))objc_msgSend)(
12925+ objc_getClass("NSString"),
12926+ sel_registerName("stringWithUTF8String:"),
12927+ "public.url"
12928+ )
12929+ )
12930+ );
12931+ }
12932+
12933+ return self;
12934+}
12935+
12936+static u32 RGFW_OnClose(id self) {
12937+ RGFW_window* win = NULL;
12938+ object_getInstanceVariable(self, (const char*)"RGFW_window", (void**)&win);
12939+ if (win == NULL) return true;
12940+
12941+ RGFW_windowCloseCallback(win);
12942+ return false;
12943+}
12944+
12945+/* NOTE(EimaMei): Fixes the constant clicking when the app is running under a terminal. */
12946+static bool RGFW__osxAcceptsFirstResponder(void) { return true; }
12947+static bool RGFW__osxPerformKeyEquivalent(id event) { RGFW_UNUSED(event); return true; }
12948+
12949+static NSDragOperation RGFW__osxDraggingEntered(id self, SEL sel, id sender) {
12950+ RGFW_UNUSED(sel);
12951+
12952+ RGFW_window* win = NULL;
12953+ object_getInstanceVariable(self, "RGFW_window", (void**)&win);
12954+ if (win == NULL)
12955+ return 0;
12956+
12957+ NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation"));
12958+ RGFW_dataDragCallback(win, RGFW_dataFile, RGFW_dndActionEnter, (i32) p.x, (i32) (win->h - p.y));
12959+ return NSDragOperationCopy;
12960+}
12961+static NSDragOperation RGFW__osxDraggingUpdated(id self, SEL sel, id sender) {
12962+ RGFW_UNUSED(sel);
12963+
12964+ RGFW_window* win = NULL;
12965+ object_getInstanceVariable(self, "RGFW_window", (void**)&win);
12966+ if (win == NULL)
12967+ return 0;
12968+ if (!(win->internal.enabledEvents & RGFW_dataDragFlag)) return NSDragOperationCopy;
12969+
12970+ NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation"));
12971+ RGFW_dataDragCallback(win, RGFW_dataFile, RGFW_dndActionMove, (i32) p.x, (i32) (win->h - p.y));
12972+ return NSDragOperationCopy;
12973+}
12974+static bool RGFW__osxPrepareForDragOperation(id self) {
12975+ RGFW_window* win = NULL;
12976+ object_getInstanceVariable(self, "RGFW_window", (void**)&win);
12977+ if (win == NULL || (!(win->internal.enabledEvents & RGFW_dataDropFlag)))
12978+ return true;
12979+
12980+ if (!(win->internal.flags & RGFW_windowAllowDND)) {
12981+ return false;
12982+ }
12983+
12984+ return true;
12985+}
12986+
12987+static void RGFW__osxDraggingEnded(id self, SEL sel, id sender) {
12988+ RGFW_UNUSED(sel);
12989+
12990+ RGFW_window* win = NULL;
12991+ object_getInstanceVariable(self, "RGFW_window", (void**)&win);
12992+ if (win == NULL)
12993+ return;
12994+ if (!(win->internal.enabledEvents & RGFW_dataDragFlag)) return;
12995+
12996+ NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation"));
12997+ RGFW_dataDragCallback(win, RGFW_dataFile, RGFW_dndActionExit, (i32) p.x, (i32) (win->h - p.y));
12998+ return;
12999+}
13000+
13001+static bool RGFW__osxPerformDragOperation(id self, SEL sel, id sender) {
13002+ RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel);
13003+ RGFW_window* win = NULL;
13004+ object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13005+ if (win == NULL || (!(win->internal.enabledEvents & RGFW_dataDropFlag)))
13006+ return false;
13007+
13008+ /* id pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard")); */
13009+
13010+ id pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard"));
13011+
13012+ /* Get the types of data available on the pasteboard */
13013+ id types = objc_msgSend_id(pasteBoard, sel_registerName("types"));
13014+
13015+ /* Get the string type for file URLs */
13016+ id fileURLsType = objc_msgSend_class_char(objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "NSFilenamesPboardType");
13017+
13018+ /* Check if the pasteboard contains file URLs */
13019+ if (objc_msgSend_id_bool(types, sel_registerName("containsObject:"), fileURLsType) == 0) {
13020+ RGFW_debugCallback(RGFW_typeError, RGFW_errClipboard, "No files found on the pasteboard.");
13021+ return 0;
13022+ }
13023+
13024+ id fileURLs = objc_msgSend_id_id(pasteBoard, sel_registerName("propertyListForType:"), fileURLsType);
13025+ int count = ((int (*)(id, SEL))objc_msgSend)(fileURLs, sel_registerName("count"));
13026+
13027+ if (count == 0)
13028+ return 0;
13029+
13030+ u32 i;
13031+ for (i = 0; i < (u32)count; i++) {
13032+ id fileURL = objc_msgSend_arr(fileURLs, sel_registerName("objectAtIndex:"), i);
13033+ const char *filePath = ((const char* (*)(id, SEL))objc_msgSend)(fileURL, sel_registerName("UTF8String"));
13034+ int string_count = ((int (*)(id, SEL))objc_msgSend)(fileURL, sel_registerName("count"));
13035+
13036+ RGFW_dataDropCallback(win, filePath, (size_t)string_count + 1, RGFW_dataFile);
13037+ }
13038+
13039+ return false;
13040+}
13041+
13042+#ifndef RGFW_NO_IOKIT
13043+#include <IOKit/IOKitLib.h>
13044+
13045+float RGFW_osx_getFallbackRefreshRate(CGDirectDisplayID displayID);
13046+float RGFW_osx_getFallbackRefreshRate(CGDirectDisplayID displayID) {
13047+ float refreshRate = 0;
13048+ io_iterator_t it;
13049+ io_service_t service;
13050+ CFNumberRef indexRef, clockRef, countRef;
13051+ u32 clock, count;
13052+
13053+#ifdef kIOMainPortDefault
13054+ if (IOServiceGetMatchingServices(kIOMainPortDefault, IOServiceMatching("IOFramebuffer"), &it) != 0)
13055+#elif defined(kIOMasterPortDefault)
13056+ if (IOServiceGetMatchingServices(kIOMainPortDefault, IOServiceMatching("IOFramebuffer"), &it) != 0)
13057+#endif
13058+ return RGFW_FALSE;
13059+
13060+ while ((service = IOIteratorNext(it)) != 0) {
13061+ u32 index;
13062+ indexRef = (CFNumberRef)IORegistryEntryCreateCFProperty(service, CFSTR("IOFramebufferOpenGLIndex"), kCFAllocatorDefault, kNilOptions);
13063+ if (indexRef == 0) continue;
13064+
13065+ if (CFNumberGetValue(indexRef, kCFNumberIntType, &index) && CGOpenGLDisplayMaskToDisplayID(1 << index) == displayID) {
13066+ CFRelease(indexRef);
13067+ break;
13068+ }
13069+
13070+ CFRelease(indexRef);
13071+ }
13072+
13073+ if (service) {
13074+ clockRef = (CFNumberRef)IORegistryEntryCreateCFProperty(service, CFSTR("IOFBCurrentPixelClock"), kCFAllocatorDefault, kNilOptions);
13075+ if (clockRef) {
13076+ if (CFNumberGetValue(clockRef, kCFNumberIntType, &clock) && clock) {
13077+ countRef = (CFNumberRef)IORegistryEntryCreateCFProperty(service, CFSTR("IOFBCurrentPixelCount"), kCFAllocatorDefault, kNilOptions);
13078+ if (countRef && CFNumberGetValue(countRef, kCFNumberIntType, &count) && count) {
13079+ refreshRate = (float)((double)clock / (double) count);
13080+ CFRelease(countRef);
13081+ }
13082+ }
13083+ CFRelease(clockRef);
13084+ }
13085+ }
13086+
13087+ IOObjectRelease(it);
13088+ return refreshRate;
13089+}
13090+#endif
13091+
13092+void RGFW_moveToMacOSResourceDir(void) {
13093+ char resourcesPath[256];
13094+
13095+ CFBundleRef bundle = CFBundleGetMainBundle();
13096+ if (!bundle)
13097+ return;
13098+
13099+ CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle);
13100+ CFStringRef last = CFURLCopyLastPathComponent(resourcesURL);
13101+
13102+ if (
13103+ CFStringCompare(CFSTR("Resources"), last, 0) != kCFCompareEqualTo ||
13104+ CFURLGetFileSystemRepresentation(resourcesURL, true, (u8*) resourcesPath, 255) == 0
13105+ ) {
13106+ CFRelease(last);
13107+ CFRelease(resourcesURL);
13108+ return;
13109+ }
13110+
13111+ CFRelease(last);
13112+ CFRelease(resourcesURL);
13113+
13114+ chdir(resourcesPath);
13115+}
13116+
13117+static void RGFW__osxDidChangeScreenParameters(id self, SEL _cmd, id notification) {
13118+ RGFW_UNUSED(self); RGFW_UNUSED(_cmd); RGFW_UNUSED(notification);
13119+ RGFW_pollMonitors();
13120+}
13121+
13122+static void RGFW__osxWindowDeminiaturize(id self, SEL sel) {
13123+ RGFW_UNUSED(sel);
13124+ RGFW_window* win = NULL;
13125+ object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13126+ if (win == NULL) return;
13127+
13128+ RGFW_windowRestoredCallback(win, win->x, win->y, win->w, win->h);
13129+
13130+}
13131+static void RGFW__osxWindowMiniaturize(id self, SEL sel) {
13132+ RGFW_UNUSED(sel);
13133+ RGFW_window* win = NULL;
13134+ object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13135+ if (win == NULL) return;
13136+
13137+ RGFW_windowMinimizedCallback(win);
13138+
13139+}
13140+
13141+static void RGFW__osxWindowBecameKey(id self, SEL sel) {
13142+ RGFW_UNUSED(sel);
13143+ RGFW_window* win = NULL;
13144+ object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13145+ if (win == NULL) return;
13146+
13147+ RGFW_windowFocusCallback(win, RGFW_TRUE);
13148+}
13149+
13150+static void RGFW__osxWindowResignKey(id self, SEL sel) {
13151+ RGFW_UNUSED(sel);
13152+ RGFW_window* win = NULL;
13153+ object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13154+ if (win == NULL) return;
13155+
13156+ RGFW_windowFocusCallback(win, RGFW_FALSE);
13157+}
13158+
13159+static void RGFW__osxDidWindowResize(id self, SEL _cmd, id notification) {
13160+ RGFW_UNUSED(_cmd); RGFW_UNUSED(notification);
13161+ RGFW_window* win = NULL;
13162+ object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13163+ if (win == NULL) return;
13164+
13165+ NSRect frame;
13166+ if (win->src.view) frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame"));
13167+ else return;
13168+
13169+ if (frame.size.width == 0 || frame.size.height == 0) return;
13170+ win->w = (i32)frame.size.width;
13171+ win->h = (i32)frame.size.height;
13172+
13173+ RGFW_monitor* mon = RGFW_window_getMonitor(win);
13174+ if (mon == NULL) return;
13175+
13176+ if ((i32)mon->mode.w == win->w && (i32)mon->mode.h - 102 <= win->h) {
13177+ RGFW_windowMaximizedCallback(win, 0, 0, win->w, win->h);
13178+ } else if (win->internal.flags & RGFW_windowMaximize) {
13179+ RGFW_windowRestoredCallback(win, win->x, win->y, win->w, win->h);
13180+ }
13181+
13182+ RGFW_windowResizedCallback(win, win->w, win->h);
13183+}
13184+
13185+static void RGFW__osxWindowMove(id self, SEL sel) {
13186+ RGFW_UNUSED(sel);
13187+ RGFW_window* win = NULL;
13188+ object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13189+ if (win == NULL) return;
13190+
13191+ NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame"));
13192+ NSRect content = ((NSRect(*)(id, SEL, NSRect))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("contentRectForFrameRect:"), frame);
13193+
13194+ float y = RGFW_cocoaYTransform((float)(content.origin.y + content.size.height - 1));
13195+
13196+ RGFW_windowMovedCallback(win, (i32)content.origin.x, (i32)y);
13197+}
13198+
13199+static void RGFW__osxViewDidChangeBackingProperties(id self, SEL _cmd) {
13200+ RGFW_UNUSED(_cmd);
13201+ RGFW_window* win = NULL;
13202+ object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13203+ if (win == NULL) return;
13204+
13205+ RGFW_monitor* mon = RGFW_window_getMonitor(win);
13206+ if (mon == NULL) return;
13207+
13208+ RGFW_scaleUpdatedCallback(win, mon->scaleX, mon->scaleY);
13209+}
13210+
13211+static BOOL RGFW__osxWantsUpdateLayer(id self, SEL _cmd) { RGFW_UNUSED(self); RGFW_UNUSED(_cmd); return YES; }
13212+
13213+static void RGFW__osxUpdateLayer(id self, SEL _cmd) {
13214+ RGFW_UNUSED(self); RGFW_UNUSED(_cmd);
13215+ RGFW_window* win = NULL;
13216+ object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13217+ if (win == NULL) return;
13218+ RGFW_windowRefreshCallback(win, 0, 0, win->w, win->h);
13219+}
13220+
13221+static void RGFW__osxDrawRect(id self, SEL _cmd, CGRect rect) {
13222+ RGFW_UNUSED(rect); RGFW_UNUSED(_cmd);
13223+ RGFW_window* win = NULL;
13224+ object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13225+ if (win == NULL) return;
13226+
13227+ RGFW_windowRefreshCallback(win, 0, 0, win->w, win->h);
13228+}
13229+
13230+static void RGFW__osxMouseEntered(id self, SEL _cmd, id event) {
13231+ RGFW_UNUSED(_cmd);
13232+ RGFW_window* win = NULL;
13233+ object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13234+ if (win == NULL) return;
13235+
13236+ NSPoint p = ((NSPoint(*)(id, SEL))objc_msgSend)(event, sel_registerName("locationInWindow"));
13237+ RGFW_mouseNotifyCallback(win, (i32)p.x, (i32)(win->h - p.y), 1);
13238+}
13239+
13240+static void RGFW__osxMouseExited(id self, SEL _cmd, id event) {
13241+ RGFW_UNUSED(_cmd); RGFW_UNUSED(event);
13242+ RGFW_window* win = NULL;
13243+ object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13244+ if (win == NULL) return;
13245+
13246+ RGFW_mouseNotifyCallback(win, win->internal.lastMouseX, win->internal.lastMouseY, RGFW_FALSE);
13247+}
13248+
13249+static void RGFW__osxKeyDown(id self, SEL _cmd, id event) {
13250+ RGFW_UNUSED(_cmd);
13251+ RGFW_window* win = NULL;
13252+ object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13253+ if (win == NULL || !(win->internal.enabledEvents & RGFW_keyPressedFlag)) return;
13254+
13255+ u32 key = (u16)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("keyCode"));
13256+
13257+ RGFW_key value = (u8)RGFW_apiKeyToRGFW(key);
13258+ RGFW_bool repeat = RGFW_isKeyDown(value);
13259+
13260+ RGFW_keyCallback(win, value, win->internal.mod, repeat, 1);
13261+
13262+ id nsstring = ((id(*)(id, SEL))objc_msgSend)(event, sel_registerName("charactersIgnoringModifiers"));
13263+ const char* string = NSString_to_char(nsstring);
13264+ size_t count = (size_t)((int (*)(id, SEL))objc_msgSend)(nsstring, sel_registerName("length"));
13265+
13266+ for (size_t index = 0; index < count;
13267+ RGFW_keyCharCallback(win, RGFW_decodeUTF8(&string[index], &index))
13268+ );
13269+}
13270+
13271+static void RGFW__osxKeyUp(id self, SEL _cmd, id event) {
13272+ RGFW_UNUSED(_cmd);
13273+ RGFW_window* win = NULL;
13274+ object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13275+ if (win == NULL || !(win->internal.enabledEvents & RGFW_keyReleasedFlag)) return;
13276+
13277+ u32 key = (u16)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("keyCode"));
13278+
13279+ RGFW_key value = (u8)RGFW_apiKeyToRGFW(key);
13280+
13281+ RGFW_keyCallback(win, value, win->internal.mod, RGFW_FALSE, 0);
13282+}
13283+
13284+static void RGFW__osxFlagsChanged(id self, SEL _cmd, id event) {
13285+ RGFW_UNUSED(_cmd);
13286+ RGFW_window* win = NULL;
13287+ object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13288+ if (win == NULL) return;
13289+
13290+ RGFW_key value = 0;
13291+ RGFW_bool pressed = RGFW_FALSE;
13292+
13293+ u32 flags = (u32)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("modifierFlags"));
13294+ RGFW_keyUpdateKeyModsEx(win,
13295+ ((u32)(flags & NSEventModifierFlagCapsLock) % 255),
13296+ ((flags & NSEventModifierFlagNumericPad) % 255),
13297+ ((flags & NSEventModifierFlagControl) % 255),
13298+ ((flags & NSEventModifierFlagOption) % 255),
13299+ ((flags & NSEventModifierFlagShift) % 255),
13300+ ((flags & NSEventModifierFlagCommand) % 255), 0);
13301+ u8 i;
13302+ for (i = 0; i < 9; i++)
13303+ _RGFW->keyboard[i + RGFW_keyCapsLock].prev = _RGFW->keyboard[i + RGFW_keyCapsLock].current;
13304+
13305+ for (i = 0; i < 5; i++) {
13306+ u32 shift = (1 << (i + 16));
13307+ RGFW_key key = i + RGFW_keyCapsLock;
13308+ if ((flags & shift) && !RGFW_isKeyDown((u8)key)) {
13309+ pressed = RGFW_TRUE;
13310+ value = (u8)key;
13311+ break;
13312+ }
13313+ if (!(flags & shift) && RGFW_isKeyDown((u8)key)) {
13314+ pressed = RGFW_FALSE;
13315+ value = (u8)key;
13316+ break;
13317+ }
13318+ }
13319+
13320+ RGFW_keyCallback(win, value, win->internal.mod, RGFW_isKeyDown(value) && pressed, pressed);
13321+
13322+ if (value != RGFW_keyCapsLock) {
13323+ RGFW_keyCallback(win, value + 4, win->internal.mod, RGFW_isKeyDown(value + 4) && pressed, pressed);
13324+ }
13325+
13326+}
13327+
13328+static void RGFW__osxMouseMoved(id self, SEL _cmd, id event) {
13329+ RGFW_UNUSED(_cmd);
13330+ RGFW_window* win = NULL;
13331+ object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13332+ if (win == NULL) return;
13333+
13334+ NSPoint p = ((NSPoint(*)(id, SEL))objc_msgSend)(event, sel_registerName("locationInWindow"));
13335+
13336+ CGFloat vecX = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(event, sel_registerName("deltaX"));
13337+ CGFloat vecY = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(event, sel_registerName("deltaY"));
13338+
13339+ RGFW_mousePosCallback(win, (i32)p.x, (i32)(win->h - p.y));
13340+ RGFW_rawMotionCallback(win, (float)vecX, (float)vecY);
13341+}
13342+
13343+static void RGFW__osxMouseDown(id self, SEL _cmd, id event) {
13344+ RGFW_UNUSED(_cmd);
13345+ RGFW_window* win = NULL;
13346+ object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13347+ if (win == NULL) return;
13348+
13349+ u32 buttonNumber = (u32)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("buttonNumber"));
13350+
13351+ RGFW_mouseButton value = 0;
13352+ switch (buttonNumber) {
13353+ case 0: value = RGFW_mouseLeft; break;
13354+ case 1: value = RGFW_mouseRight; break;
13355+ case 2: value = RGFW_mouseMiddle; break;
13356+ default: value = (u8)buttonNumber;
13357+ }
13358+
13359+ RGFW_mouseButtonCallback(win, value, 1);
13360+}
13361+
13362+static void RGFW__osxMouseUp(id self, SEL _cmd, id event) {
13363+ RGFW_UNUSED(_cmd);
13364+ RGFW_window* win = NULL;
13365+ object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13366+ if (win == NULL) return;
13367+
13368+ u32 buttonNumber = (u32)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("buttonNumber"));
13369+
13370+ RGFW_mouseButton value = 0;
13371+ switch (buttonNumber) {
13372+ case 0: value = RGFW_mouseLeft; break;
13373+ case 1: value = RGFW_mouseRight; break;
13374+ case 2: value = RGFW_mouseMiddle; break;
13375+ default: value = (u8)buttonNumber;
13376+ }
13377+
13378+ RGFW_mouseButtonCallback(win, value, 0);
13379+}
13380+
13381+static void RGFW__osxScrollWheel(id self, SEL _cmd, id event) {
13382+ RGFW_UNUSED(_cmd);
13383+ RGFW_window* win = NULL;
13384+ object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13385+ if (win == NULL) return;
13386+
13387+ float deltaX = (float)((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(event, sel_registerName("deltaX"));
13388+ float deltaY = (float)((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(event, sel_registerName("deltaY"));
13389+
13390+ RGFW_mouseScrollCallback(win, deltaX, deltaY);
13391+}
13392+
13393+RGFW_format RGFW_nativeFormat(void) { return RGFW_formatRGBA8; }
13394+
13395+RGFW_bool RGFW_createSurfacePtr(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) {
13396+ surface->data = data;
13397+ surface->w = w;
13398+ surface->h = h;
13399+ surface->format = format;
13400+ surface->native.format = RGFW_formatRGBA8;
13401+
13402+ surface->native.buffer = (u8*)RGFW_ALLOC((size_t)(w * h * 4));
13403+ return RGFW_TRUE;
13404+}
13405+
13406+void RGFW_surface_freePtr(RGFW_surface* surface) {
13407+ RGFW_FREE(surface->native.buffer);
13408+}
13409+
13410+void RGFW_window_blitSurface(RGFW_window* win, RGFW_surface* surface) {
13411+ id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
13412+ pool = objc_msgSend_id(pool, sel_registerName("init"));
13413+
13414+ int minW = RGFW_MIN(win->w, surface->w);
13415+ int minH = RGFW_MIN(win->h, surface->h);
13416+
13417+ RGFW_monitor* mon = RGFW_window_getMonitor(win);
13418+ if (mon == NULL) return;
13419+
13420+ minW = (i32)((float)minW * mon->pixelRatio);
13421+ minH = (i32)((float)minH * mon->pixelRatio);
13422+
13423+ surface->native.rep = (void*)NSBitmapImageRep_initWithBitmapData(&surface->native.buffer, minW, minH, 8, 4, true, false, "NSDeviceRGBColorSpace", 1 << 1, (u32)surface->w * 4, 32);
13424+
13425+ id image = ((id (*)(Class, SEL))objc_msgSend)(objc_getClass("NSImage"), sel_getUid("alloc"));
13426+ NSSize size = (NSSize){(double)minW, (double)minH};
13427+ image = ((id (*)(id, SEL, NSSize))objc_msgSend)((id)image, sel_getUid("initWithSize:"), size);
13428+
13429+ RGFW_copyImageData(NSBitmapImageRep_bitmapData((id)surface->native.rep), surface->w, minH, RGFW_formatRGBA8, surface->data, surface->native.format, surface->convertFunc);
13430+ ((void (*)(id, SEL, id))objc_msgSend)((id)image, sel_getUid("addRepresentation:"), (id)surface->native.rep);
13431+
13432+ id layer = ((id (*)(id, SEL))objc_msgSend)((id)win->src.view, sel_getUid("layer"));
13433+ ((void (*)(id, SEL, id))objc_msgSend)(layer, sel_getUid("setContents:"), (id)image);
13434+
13435+ NSRelease(image);
13436+ NSRelease(surface->native.rep);
13437+
13438+ objc_msgSend_bool_void(pool, sel_registerName("drain"));
13439+}
13440+
13441+void* RGFW_window_getView_OSX(RGFW_window* win) { return win->src.view; }
13442+
13443+void RGFW_window_setLayer_OSX(RGFW_window* win, void* layer) {
13444+ objc_msgSend_void_id((id)win->src.view, sel_registerName("setLayer:"), (id)layer);
13445+}
13446+
13447+void* RGFW_getLayer_OSX(void) {
13448+ return objc_msgSend_class((id)objc_getClass("CAMetalLayer"), (SEL)sel_registerName("layer"));
13449+}
13450+void* RGFW_window_getWindow_OSX(RGFW_window* win) { return win->src.window; }
13451+
13452+void RGFW_initKeycodesPlatform(void) {
13453+ _RGFW->keycodes[0x1D] = RGFW_key0;
13454+ _RGFW->keycodes[0x12] = RGFW_key1;
13455+ _RGFW->keycodes[0x13] = RGFW_key2;
13456+ _RGFW->keycodes[0x14] = RGFW_key3;
13457+ _RGFW->keycodes[0x15] = RGFW_key4;
13458+ _RGFW->keycodes[0x17] = RGFW_key5;
13459+ _RGFW->keycodes[0x16] = RGFW_key6;
13460+ _RGFW->keycodes[0x1A] = RGFW_key7;
13461+ _RGFW->keycodes[0x1C] = RGFW_key8;
13462+ _RGFW->keycodes[0x19] = RGFW_key9;
13463+ _RGFW->keycodes[0x00] = RGFW_keyA;
13464+ _RGFW->keycodes[0x0B] = RGFW_keyB;
13465+ _RGFW->keycodes[0x08] = RGFW_keyC;
13466+ _RGFW->keycodes[0x02] = RGFW_keyD;
13467+ _RGFW->keycodes[0x0E] = RGFW_keyE;
13468+ _RGFW->keycodes[0x03] = RGFW_keyF;
13469+ _RGFW->keycodes[0x05] = RGFW_keyG;
13470+ _RGFW->keycodes[0x04] = RGFW_keyH;
13471+ _RGFW->keycodes[0x22] = RGFW_keyI;
13472+ _RGFW->keycodes[0x26] = RGFW_keyJ;
13473+ _RGFW->keycodes[0x28] = RGFW_keyK;
13474+ _RGFW->keycodes[0x25] = RGFW_keyL;
13475+ _RGFW->keycodes[0x2E] = RGFW_keyM;
13476+ _RGFW->keycodes[0x2D] = RGFW_keyN;
13477+ _RGFW->keycodes[0x1F] = RGFW_keyO;
13478+ _RGFW->keycodes[0x23] = RGFW_keyP;
13479+ _RGFW->keycodes[0x0C] = RGFW_keyQ;
13480+ _RGFW->keycodes[0x0F] = RGFW_keyR;
13481+ _RGFW->keycodes[0x01] = RGFW_keyS;
13482+ _RGFW->keycodes[0x11] = RGFW_keyT;
13483+ _RGFW->keycodes[0x20] = RGFW_keyU;
13484+ _RGFW->keycodes[0x09] = RGFW_keyV;
13485+ _RGFW->keycodes[0x0D] = RGFW_keyW;
13486+ _RGFW->keycodes[0x07] = RGFW_keyX;
13487+ _RGFW->keycodes[0x10] = RGFW_keyY;
13488+ _RGFW->keycodes[0x06] = RGFW_keyZ;
13489+ _RGFW->keycodes[0x27] = RGFW_keyApostrophe;
13490+ _RGFW->keycodes[0x2A] = RGFW_keyBackSlash;
13491+ _RGFW->keycodes[0x2B] = RGFW_keyComma;
13492+ _RGFW->keycodes[0x18] = RGFW_keyEquals;
13493+ _RGFW->keycodes[0x32] = RGFW_keyBacktick;
13494+ _RGFW->keycodes[0x21] = RGFW_keyBracket;
13495+ _RGFW->keycodes[0x1B] = RGFW_keyMinus;
13496+ _RGFW->keycodes[0x2F] = RGFW_keyPeriod;
13497+ _RGFW->keycodes[0x1E] = RGFW_keyCloseBracket;
13498+ _RGFW->keycodes[0x29] = RGFW_keySemicolon;
13499+ _RGFW->keycodes[0x2C] = RGFW_keySlash;
13500+ _RGFW->keycodes[0x0A] = RGFW_keyWorld1;
13501+ _RGFW->keycodes[0x33] = RGFW_keyBackSpace;
13502+ _RGFW->keycodes[0x39] = RGFW_keyCapsLock;
13503+ _RGFW->keycodes[0x75] = RGFW_keyDelete;
13504+ _RGFW->keycodes[0x7D] = RGFW_keyDown;
13505+ _RGFW->keycodes[0x77] = RGFW_keyEnd;
13506+ _RGFW->keycodes[0x24] = RGFW_keyEnter;
13507+ _RGFW->keycodes[0x35] = RGFW_keyEscape;
13508+ _RGFW->keycodes[0x7A] = RGFW_keyF1;
13509+ _RGFW->keycodes[0x78] = RGFW_keyF2;
13510+ _RGFW->keycodes[0x63] = RGFW_keyF3;
13511+ _RGFW->keycodes[0x76] = RGFW_keyF4;
13512+ _RGFW->keycodes[0x60] = RGFW_keyF5;
13513+ _RGFW->keycodes[0x61] = RGFW_keyF6;
13514+ _RGFW->keycodes[0x62] = RGFW_keyF7;
13515+ _RGFW->keycodes[0x64] = RGFW_keyF8;
13516+ _RGFW->keycodes[0x65] = RGFW_keyF9;
13517+ _RGFW->keycodes[0x6D] = RGFW_keyF10;
13518+ _RGFW->keycodes[0x67] = RGFW_keyF11;
13519+ _RGFW->keycodes[0x6F] = RGFW_keyF12;
13520+ _RGFW->keycodes[0x69] = RGFW_keyPrintScreen;
13521+ _RGFW->keycodes[0x6B] = RGFW_keyF14;
13522+ _RGFW->keycodes[0x71] = RGFW_keyF15;
13523+ _RGFW->keycodes[0x6A] = RGFW_keyF16;
13524+ _RGFW->keycodes[0x40] = RGFW_keyF17;
13525+ _RGFW->keycodes[0x4F] = RGFW_keyF18;
13526+ _RGFW->keycodes[0x50] = RGFW_keyF19;
13527+ _RGFW->keycodes[0x5A] = RGFW_keyF20;
13528+ _RGFW->keycodes[0x73] = RGFW_keyHome;
13529+ _RGFW->keycodes[0x72] = RGFW_keyInsert;
13530+ _RGFW->keycodes[0x7B] = RGFW_keyLeft;
13531+ _RGFW->keycodes[0x3A] = RGFW_keyAltL;
13532+ _RGFW->keycodes[0x3B] = RGFW_keyControlL;
13533+ _RGFW->keycodes[0x38] = RGFW_keyShiftL;
13534+ _RGFW->keycodes[0x37] = RGFW_keySuperL;
13535+ _RGFW->keycodes[0x6E] = RGFW_keyMenu;
13536+ _RGFW->keycodes[0x47] = RGFW_keyNumLock;
13537+ _RGFW->keycodes[0x79] = RGFW_keyPageDown;
13538+ _RGFW->keycodes[0x74] = RGFW_keyPageUp;
13539+ _RGFW->keycodes[0x7C] = RGFW_keyRight;
13540+ _RGFW->keycodes[0x3D] = RGFW_keyAltR;
13541+ _RGFW->keycodes[0x3E] = RGFW_keyControlR;
13542+ _RGFW->keycodes[0x3C] = RGFW_keyShiftR;
13543+ _RGFW->keycodes[0x36] = RGFW_keySuperR;
13544+ _RGFW->keycodes[0x31] = RGFW_keySpace;
13545+ _RGFW->keycodes[0x30] = RGFW_keyTab;
13546+ _RGFW->keycodes[0x7E] = RGFW_keyUp;
13547+ _RGFW->keycodes[0x52] = RGFW_keyPad0;
13548+ _RGFW->keycodes[0x53] = RGFW_keyPad1;
13549+ _RGFW->keycodes[0x54] = RGFW_keyPad2;
13550+ _RGFW->keycodes[0x55] = RGFW_keyPad3;
13551+ _RGFW->keycodes[0x56] = RGFW_keyPad4;
13552+ _RGFW->keycodes[0x57] = RGFW_keyPad5;
13553+ _RGFW->keycodes[0x58] = RGFW_keyPad6;
13554+ _RGFW->keycodes[0x59] = RGFW_keyPad7;
13555+ _RGFW->keycodes[0x5B] = RGFW_keyPad8;
13556+ _RGFW->keycodes[0x5C] = RGFW_keyPad9;
13557+ _RGFW->keycodes[0x45] = RGFW_keyPadSlash;
13558+ _RGFW->keycodes[0x41] = RGFW_keyPadPeriod;
13559+ _RGFW->keycodes[0x4B] = RGFW_keyPadSlash;
13560+ _RGFW->keycodes[0x4C] = RGFW_keyPadReturn;
13561+ _RGFW->keycodes[0x51] = RGFW_keyPadEqual;
13562+ _RGFW->keycodes[0x43] = RGFW_keyPadMultiply;
13563+ _RGFW->keycodes[0x4E] = RGFW_keyPadMinus;
13564+}
13565+
13566+i32 RGFW_initPlatform(void) {
13567+ _RGFW->tisBundle = (void*)CFBundleGetBundleWithIdentifier(CFSTR("com.apple.HIToolbox"));
13568+
13569+ TISGetInputSourcePropertySrc = (PFN_TISGetInputSourceProperty)CFBundleGetFunctionPointerForName((CFBundleRef)_RGFW->tisBundle, CFSTR("TISGetInputSourceProperty"));
13570+ TISCopyCurrentKeyboardLayoutInputSourceSrc = (PFN_TISCopyCurrentKeyboardLayoutInputSource)CFBundleGetFunctionPointerForName((CFBundleRef)_RGFW->tisBundle, CFSTR("TISCopyCurrentKeyboardLayoutInputSource"));
13571+ LMGetKbdTypeSrc = (PFN_LMGetKbdType)CFBundleGetFunctionPointerForName((CFBundleRef)_RGFW->tisBundle, CFSTR("LMGetKbdType"));
13572+
13573+ CFStringRef* cfStr = (CFStringRef*)CFBundleGetDataPointerForName((CFBundleRef)_RGFW->tisBundle, CFSTR("kTISPropertyUnicodeKeyLayoutData"));;
13574+ if (cfStr) kTISPropertyUnicodeKeyLayoutDataSrc = *cfStr;
13575+
13576+ class_addMethod(objc_getClass("NSObject"), sel_registerName("windowShouldClose:"), (IMP)(void*)RGFW_OnClose, 0);
13577+
13578+ /* NOTE(EimaMei): Fixes the 'Boop' sfx from constantly playing each time you click a key. Only a problem when running in the terminal. */
13579+ class_addMethod(objc_getClass("NSWindowClass"), sel_registerName("acceptsFirstResponder:"), (IMP)(void*)RGFW__osxAcceptsFirstResponder, 0);
13580+ class_addMethod(objc_getClass("NSWindowClass"), sel_registerName("performKeyEquivalent:"), (IMP)(void*)RGFW__osxPerformKeyEquivalent, 0);
13581+
13582+ _RGFW->NSApp = objc_msgSend_id(objc_getClass("NSApplication"), sel_registerName("sharedApplication"));
13583+
13584+ NSRetain(_RGFW->NSApp);
13585+
13586+ _RGFW->customNSAppDelegateClass = objc_allocateClassPair(objc_getClass("NSObject"), "RGFWNSAppDelegate", 0);
13587+ class_addMethod((Class)_RGFW->customNSAppDelegateClass, sel_registerName("applicationDidChangeScreenParameters:"), (IMP)RGFW__osxDidChangeScreenParameters, "v@:@");
13588+ objc_registerClassPair((Class)_RGFW->customNSAppDelegateClass);
13589+ _RGFW->customNSAppDelegate = objc_msgSend_id(NSAlloc(_RGFW->customNSAppDelegateClass), sel_registerName("init"));
13590+
13591+ objc_msgSend_void_id(_RGFW->NSApp, sel_registerName("setDelegate:"), _RGFW->customNSAppDelegate);
13592+
13593+ ((void (*)(id, SEL, NSUInteger))objc_msgSend) ((id)_RGFW->NSApp, sel_registerName("setActivationPolicy:"), NSApplicationActivationPolicyRegular);
13594+
13595+ _RGFW->customViewClasses[0] = objc_allocateClassPair(objc_getClass("NSView"), "RGFWCustomView", 0);
13596+ _RGFW->customViewClasses[1] = objc_allocateClassPair(objc_getClass("NSOpenGLView"), "RGFWOpenGLCustomView", 0);
13597+ for (size_t i = 0; i < 2; i++) {
13598+ class_addIvar((Class)_RGFW->customViewClasses[i], "RGFW_window", sizeof(RGFW_window*), sizeof(RGFW_window*), "L");
13599+ class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("drawRect:"), (IMP)RGFW__osxDrawRect, "v@:{CGRect=ffff}");
13600+ class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("viewDidChangeBackingProperties"), (IMP)RGFW__osxViewDidChangeBackingProperties, "v@:");
13601+ class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseDown:"), (IMP)RGFW__osxMouseDown, "v@:@");
13602+ class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("rightMouseDown:"), (IMP)RGFW__osxMouseDown, "v@:@");
13603+ class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("otherMouseDown:"), (IMP)RGFW__osxMouseDown, "v@:@");
13604+ class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseUp:"), (IMP)RGFW__osxMouseUp, "v@:@");
13605+ class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("rightMouseUp:"), (IMP)RGFW__osxMouseUp, "v@:@");
13606+ class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("otherMouseUp:"), (IMP)RGFW__osxMouseUp, "v@:@");
13607+ class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("scrollWheel:"), (IMP)RGFW__osxScrollWheel, "v@:@");
13608+ class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseDragged:"), (IMP)RGFW__osxMouseMoved, "v@:@");
13609+ class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("rightMouseDragged:"), (IMP)RGFW__osxMouseMoved, "v@:@");
13610+ class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("otherMouseDragged:"), (IMP)RGFW__osxMouseMoved, "v@:@");
13611+ class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("keyDown:"), (IMP)RGFW__osxKeyDown, "v@:@");
13612+ class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("keyUp:"), (IMP)RGFW__osxKeyUp, "v@:@");
13613+ class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseMoved:"), (IMP)RGFW__osxMouseMoved, "v@:@");
13614+ class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseEntered:"), (IMP)RGFW__osxMouseEntered, "v@:@");
13615+ class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseExited:"), (IMP)RGFW__osxMouseExited, "v@:@");
13616+ class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("flagsChanged:"), (IMP)RGFW__osxFlagsChanged, "v@:@");
13617+ class_addMethod((Class)_RGFW->customViewClasses[i], sel_getUid("acceptsFirstResponder"), (IMP)RGFW__osxAcceptsFirstResponder, "B@:");
13618+ class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("initWithRGFWWindow:"), (IMP)RGFW__osxCustomInitWithRGFWWindow, "@@:{CGRect={CGPoint=dd}{CGSize=dd}}");
13619+ class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("wantsUpdateLayer"), (IMP)RGFW__osxWantsUpdateLayer, "B@:");
13620+ class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("updateLayer"), (IMP)RGFW__osxUpdateLayer, "v@:");
13621+ objc_registerClassPair((Class)_RGFW->customViewClasses[i]);
13622+ }
13623+
13624+ _RGFW->customWindowDelegateClass = objc_allocateClassPair(objc_getClass("NSObject"), "RGFWWindowDelegate", 0);
13625+ class_addIvar((Class)_RGFW->customWindowDelegateClass, "RGFW_window", sizeof(RGFW_window*), sizeof(RGFW_window*), "L");
13626+ class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidResize:"), (IMP)RGFW__osxDidWindowResize, "v@:@");
13627+ class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidMove:"), (IMP) RGFW__osxWindowMove, "");
13628+ class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidMiniaturize:"), (IMP) RGFW__osxWindowMiniaturize, "");
13629+ class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidDeminiaturize:"), (IMP) RGFW__osxWindowDeminiaturize, "");
13630+ class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidBecomeKey:"), (IMP) RGFW__osxWindowBecameKey, "");
13631+ class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidResignKey:"), (IMP) RGFW__osxWindowResignKey, "");
13632+ class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("draggingEntered:"), (IMP)RGFW__osxDraggingEntered, "l@:@");
13633+ class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("draggingUpdated:"), (IMP)RGFW__osxDraggingUpdated, "l@:@");
13634+ class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("draggingExited:"), (IMP)RGFW__osxDraggingEnded, "v@:@");
13635+ class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("draggingEnded:"), (IMP)RGFW__osxDraggingEnded, "v@:@");
13636+ class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("prepareForDragOperation:"), (IMP)RGFW__osxPrepareForDragOperation, "B@:@");
13637+ class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("performDragOperation:"), (IMP)RGFW__osxPerformDragOperation, "B@:@");
13638+ objc_registerClassPair((Class)_RGFW->customWindowDelegateClass);
13639+ return 0;
13640+}
13641+
13642+void RGFW_osx_initView(RGFW_window* win) {
13643+ NSRect contentRect;
13644+ contentRect.origin.x = 0;
13645+ contentRect.origin.y = 0;
13646+ contentRect.size.width = (double)win->w;
13647+ contentRect.size.height = (double)win->h;
13648+ ((void(*)(id, SEL, CGRect))objc_msgSend)((id)win->src.view, sel_registerName("setFrame:"), contentRect);
13649+
13650+
13651+ if (RGFW_COCOA_FRAME_NAME)
13652+ objc_msgSend_ptr(win->src.view, sel_registerName("setFrameAutosaveName:"), RGFW_COCOA_FRAME_NAME);
13653+
13654+ object_setInstanceVariable((id)win->src.view, "RGFW_window", win);
13655+ objc_msgSend_void_id((id)win->src.window, sel_registerName("setContentView:"), win->src.view);
13656+ objc_msgSend_void_bool(win->src.view, sel_registerName("setWantsLayer:"), true);
13657+ objc_msgSend_int((id)win->src.view, sel_registerName("setLayerContentsPlacement:"), 4);
13658+
13659+ id trackingArea = objc_msgSend_id(objc_getClass("NSTrackingArea"), sel_registerName("alloc"));
13660+ trackingArea = ((id (*)(id, SEL, NSRect, NSUInteger, id, id))objc_msgSend)(
13661+ trackingArea,
13662+ sel_registerName("initWithRect:options:owner:userInfo:"),
13663+ contentRect,
13664+ NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingInVisibleRect,
13665+ (id)win->src.view,
13666+ nil
13667+ );
13668+
13669+ ((void (*)(id, SEL, id))objc_msgSend)((id)win->src.view, sel_registerName("addTrackingArea:"), trackingArea);
13670+ ((void (*)(id, SEL))objc_msgSend)(trackingArea, sel_registerName("release"));
13671+}
13672+
13673+RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win) {
13674+ /* RR Create an autorelease pool */
13675+ id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
13676+ pool = objc_msgSend_id(pool, sel_registerName("init"));
13677+
13678+ RGFW_window_setMouseDefault(win);
13679+
13680+ NSRect windowRect;
13681+ windowRect.origin.x = (double)win->x;
13682+ windowRect.origin.y = (double)RGFW_cocoaYTransform((float)(win->y + win->h - 1));
13683+ windowRect.size.width = (double)win->w;
13684+ windowRect.size.height = (double)win->h;
13685+ NSBackingStoreType macArgs = (NSBackingStoreType)(NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSBackingStoreBuffered | NSWindowStyleMaskTitled);
13686+
13687+ if (!(flags & RGFW_windowNoResize))
13688+ macArgs = (NSBackingStoreType)(macArgs | (NSBackingStoreType)NSWindowStyleMaskResizable);
13689+ if (!(flags & RGFW_windowNoBorder))
13690+ macArgs = (NSBackingStoreType)(macArgs | (NSBackingStoreType)NSWindowStyleMaskTitled);
13691+ {
13692+ void* nsclass = objc_getClass("NSWindow");
13693+ SEL func = sel_registerName("initWithContentRect:styleMask:backing:defer:");
13694+
13695+ win->src.window = ((id(*)(id, SEL, NSRect, NSWindowStyleMask, NSBackingStoreType, bool))objc_msgSend)
13696+ (NSAlloc(nsclass), func, windowRect, (NSWindowStyleMask)macArgs, macArgs, false);
13697+ }
13698+
13699+ id str = NSString_stringWithUTF8String(name);
13700+ objc_msgSend_void_id((id)win->src.window, sel_registerName("setTitle:"), str);
13701+
13702+ win->src.delegate = (void*)objc_msgSend_id(NSAlloc((Class)_RGFW->customWindowDelegateClass), sel_registerName("init"));
13703+ object_setInstanceVariable((id)win->src.delegate, "RGFW_window", win);
13704+
13705+ objc_msgSend_void_id((id)win->src.window, sel_registerName("setDelegate:"), (id)win->src.delegate);
13706+
13707+ if (flags & RGFW_windowAllowDND) {
13708+ win->internal.flags |= RGFW_windowAllowDND;
13709+
13710+ NSPasteboardType types[] = {NSPasteboardTypeURL, NSPasteboardTypeFileURL, NSPasteboardTypeString};
13711+ NSregisterForDraggedTypes((id)win->src.window, types, 3);
13712+ }
13713+
13714+ objc_msgSend_void_bool((id)win->src.window, sel_registerName("setAcceptsMouseMovedEvents:"), true);
13715+
13716+ if (flags & RGFW_windowTransparent) {
13717+ objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), false);
13718+
13719+ objc_msgSend_void_id((id)win->src.window, sel_registerName("setBackgroundColor:"),
13720+ NSColor_colorWithSRGB(0, 0, 0, 0));
13721+ }
13722+
13723+ /* Show the window */
13724+ objc_msgSend_void_bool((id)_RGFW->NSApp, sel_registerName("activateIgnoringOtherApps:"), true);
13725+
13726+ if (_RGFW->root == NULL) {
13727+ objc_msgSend_void(win->src.window, sel_registerName("makeMainWindow"));
13728+ }
13729+
13730+ objc_msgSend_void(win->src.window, sel_registerName("makeKeyWindow"));
13731+
13732+ NSRetain(win->src.window);
13733+
13734+ win->src.view = ((id(*)(id, SEL, RGFW_window*))objc_msgSend) (NSAlloc((Class)_RGFW->customViewClasses[0]), sel_registerName("initWithRGFWWindow:"), win);
13735+ return win;
13736+}
13737+
13738+void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) {
13739+ NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame"));
13740+ NSRect content = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame"));
13741+ double offset = 0;
13742+
13743+ RGFW_setBit(&win->internal.flags, RGFW_windowNoBorder, !border);
13744+ NSBackingStoreType storeType = (NSBackingStoreType)(NSWindowStyleMaskBorderless | NSWindowStyleMaskFullSizeContentView);
13745+ if (border)
13746+ storeType = (NSBackingStoreType)(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable);
13747+ if (!(win->internal.flags & RGFW_windowNoResize)) {
13748+ storeType = (NSBackingStoreType)(storeType | (NSBackingStoreType)NSWindowStyleMaskResizable);
13749+ }
13750+
13751+ ((void (*)(id, SEL, NSBackingStoreType))objc_msgSend)((id)win->src.window, sel_registerName("setStyleMask:"), storeType);
13752+
13753+ if (!border) {
13754+ id miniaturizeButton = objc_msgSend_int((id)win->src.window, sel_registerName("standardWindowButton:"), NSWindowMiniaturizeButton);
13755+ id titleBarView = objc_msgSend_id(miniaturizeButton, sel_registerName("superview"));
13756+ objc_msgSend_void_bool(titleBarView, sel_registerName("setHidden:"), true);
13757+
13758+ offset = (double)(frame.size.height - content.size.height);
13759+ }
13760+
13761+ RGFW_window_resize(win, win->w, win->h + (i32)offset);
13762+ win->h -= (i32)offset;
13763+}
13764+
13765+RGFW_bool RGFW_getGlobalMouse(i32* x, i32* y) {
13766+ RGFW_ASSERT(_RGFW->root != NULL);
13767+
13768+ CGEventRef e = CGEventCreate(NULL);
13769+ CGPoint point = CGEventGetLocation(e);
13770+ CFRelease(e);
13771+
13772+ if (x) *x = (i32)point.x;
13773+ if (y) *y = (i32)point.y;
13774+ return RGFW_TRUE;
13775+}
13776+
13777+void RGFW_stopCheckEvents(void) {
13778+ id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
13779+ eventPool = objc_msgSend_id(eventPool, sel_registerName("init"));
13780+
13781+ id e = (id) ((id(*)(Class, SEL, NSEventType, NSPoint, NSEventModifierFlags, void*, NSInteger, void**, short, NSInteger, NSInteger))objc_msgSend)
13782+ (objc_getClass("NSEvent"), sel_registerName("otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:"),
13783+ NSEventTypeApplicationDefined, (NSPoint){0, 0}, (NSEventModifierFlags)0, NULL, (NSInteger)0, NULL, 0, 0, 0);
13784+
13785+ ((void (*)(id, SEL, id, bool))objc_msgSend)
13786+ ((id)_RGFW->NSApp, sel_registerName("postEvent:atStart:"), e, 1);
13787+
13788+ objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
13789+}
13790+
13791+void RGFW_waitForEvent(i32 waitMS) {
13792+ id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
13793+ eventPool = objc_msgSend_id(eventPool, sel_registerName("init"));
13794+
13795+ void* date = (void*) ((id(*)(Class, SEL, double))objc_msgSend)
13796+ (objc_getClass("NSDate"), sel_registerName("dateWithTimeIntervalSinceNow:"), waitMS);
13797+
13798+ SEL eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:");
13799+ id e = (id) ((id(*)(id, SEL, NSEventMask, void*, id, bool))objc_msgSend)
13800+ ((id)_RGFW->NSApp, eventFunc,
13801+ ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true);
13802+
13803+ if (e) {
13804+ ((void (*)(id, SEL, id, bool))objc_msgSend)
13805+ ((id)_RGFW->NSApp, sel_registerName("postEvent:atStart:"), e, 1);
13806+ }
13807+
13808+ objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
13809+}
13810+
13811+RGFW_key RGFW_physicalToMappedKey(RGFW_key key) {
13812+ u16 keycode = (u16)RGFW_rgfwToApiKey(key);
13813+ TISInputSourceRef source = TISCopyCurrentKeyboardLayoutInputSource();
13814+ if (source == NULL)
13815+ return key;
13816+
13817+ CFDataRef layoutData = TISGetInputSourceProperty(source, kTISPropertyUnicodeKeyLayoutDataSrc);
13818+
13819+ if (layoutData == NULL) {
13820+ CFRelease(source);
13821+ return key;
13822+ }
13823+
13824+ UCKeyboardLayout *layout = (UCKeyboardLayout*)(void*)CFDataGetBytePtr(layoutData);
13825+
13826+ UInt32 deadKeyState = 0;
13827+ UniChar chars[4];
13828+ UniCharCount len = 0;
13829+ u32 type = LMGetKbdType();
13830+ OSStatus status = UCKeyTranslate(layout, keycode, kUCKeyActionDown, 0, type, kUCKeyTranslateNoDeadKeysBit, &deadKeyState, 4, &len, chars );
13831+
13832+ CFRelease(source);
13833+
13834+ if (status == noErr && len == 1 && chars[0] < 256) {
13835+ return (RGFW_key)chars[0];
13836+ }
13837+
13838+ return key;
13839+}
13840+
13841+RGFW_bool RGFW_window_fetchSize(RGFW_window* win, i32* w, i32* h) {
13842+ NSRect content = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame"));
13843+
13844+ win->w = (i32)content.size.width;
13845+ win->h = (i32)content.size.height;
13846+
13847+ return RGFW_window_getSize(win, w, h);
13848+}
13849+
13850+void RGFW_pollEvents(void) {
13851+ RGFW_resetPrevState();
13852+
13853+ id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
13854+ eventPool = objc_msgSend_id(eventPool, sel_registerName("init"));
13855+ SEL eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:");
13856+
13857+ while (1) {
13858+ void* date = NULL;
13859+ id e = (id) ((id(*)(id, SEL, NSEventMask, void*, id, bool))objc_msgSend)
13860+ ((id)_RGFW->NSApp, eventFunc, ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true);
13861+
13862+ if (e == NULL) {
13863+ break;
13864+ }
13865+
13866+ objc_msgSend_void_id((id)_RGFW->NSApp, sel_registerName("sendEvent:"), e);
13867+ }
13868+
13869+ objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
13870+}
13871+
13872+
13873+void RGFW_window_move(RGFW_window* win, i32 x, i32 y) {
13874+ RGFW_ASSERT(win != NULL);
13875+
13876+ NSRect content = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame"));
13877+
13878+ win->x = x;
13879+ win->y = (i32)RGFW_cocoaYTransform((float)y + (float)content.size.height - 1.0f);
13880+
13881+ ((void(*)(id,SEL,NSPoint))objc_msgSend)((id)win->src.window, sel_registerName("setFrameOrigin:"), (NSPoint){(double)x, (double)y});
13882+}
13883+
13884+void RGFW_window_resize(RGFW_window* win, i32 w, i32 h) {
13885+ RGFW_ASSERT(win != NULL);
13886+
13887+ NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame"));
13888+ NSRect content = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame"));
13889+ float offset = (float)(frame.size.height - content.size.height);
13890+
13891+ win->w = w;
13892+ win->h = h;
13893+
13894+
13895+ ((void(*)(id, SEL, CGRect))objc_msgSend)((id)win->src.view, sel_registerName("setFrame:"), (NSRect){{0, 0}, {(double)win->w, (double)win->h}});
13896+ ((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend)
13897+ ((id)win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{(double)win->x, (double)win->y}, {(double)win->w, (double)win->h + (double)offset}}, true, true);
13898+}
13899+
13900+void RGFW_window_focus(RGFW_window* win) {
13901+ RGFW_ASSERT(win);
13902+ objc_msgSend_void_bool((id)_RGFW->NSApp, sel_registerName("activateIgnoringOtherApps:"), true);
13903+ ((void (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_registerName("makeKeyWindow"));
13904+}
13905+
13906+void RGFW_window_raise(RGFW_window* win) {
13907+ RGFW_ASSERT(win != NULL);
13908+ ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("orderFront:"), (SEL)NULL);
13909+ objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGNormalWindowLevelKey);
13910+}
13911+
13912+void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) {
13913+ RGFW_ASSERT(win != NULL);
13914+ if (fullscreen && (win->internal.flags & RGFW_windowFullscreen)) return;
13915+ if (!fullscreen && !(win->internal.flags & RGFW_windowFullscreen)) return;
13916+
13917+ if (fullscreen) {
13918+ win->internal.oldX = win->x;
13919+ win->internal.oldY = win->y;
13920+ win->internal.oldW = win->w;
13921+ win->internal.oldH = win->h;
13922+
13923+ win->internal.flags |= RGFW_windowFullscreen;
13924+
13925+ RGFW_monitor* mon = RGFW_window_getMonitor(win);
13926+ RGFW_monitor_scaleToWindow(mon, win);
13927+
13928+ RGFW_window_setBorder(win, RGFW_FALSE);
13929+
13930+ if (mon != NULL) {
13931+ win->x = mon->x;
13932+ win->y = mon->y;
13933+ win->w = mon->mode.w;
13934+ win->h = mon->mode.h;
13935+ RGFW_window_resize(win, mon->mode.w, mon->mode.h);
13936+ RGFW_window_move(win, mon->x, mon->y);
13937+ }
13938+
13939+ ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("orderFront:"), (SEL)NULL);
13940+ objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), 25);
13941+ }
13942+
13943+ objc_msgSend_void_SEL(win->src.window, sel_registerName("toggleFullScreen:"), NULL);
13944+
13945+ if (!fullscreen) {
13946+ win->x = win->internal.oldX;
13947+ win->y = win->internal.oldY;
13948+ win->w = win->internal.oldW;
13949+ win->h = win->internal.oldH;
13950+ win->internal.flags &= ~(u32)RGFW_windowFullscreen;
13951+
13952+ RGFW_window_resize(win, win->w, win->h);
13953+ RGFW_window_move(win, win->x, win->y);
13954+ }
13955+}
13956+
13957+void RGFW_window_maximize(RGFW_window* win) {
13958+ RGFW_ASSERT(win != NULL);
13959+ if (RGFW_window_isMaximized(win)) return;
13960+
13961+ win->internal.flags |= RGFW_windowMaximize;
13962+ objc_msgSend_void_SEL(win->src.window, sel_registerName("zoom:"), NULL);
13963+ RGFW_window_fetchSize(win, NULL, NULL);
13964+}
13965+
13966+void RGFW_window_minimize(RGFW_window* win) {
13967+ RGFW_ASSERT(win != NULL);
13968+ objc_msgSend_void_SEL(win->src.window, sel_registerName("performMiniaturize:"), NULL);
13969+}
13970+
13971+void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) {
13972+ RGFW_ASSERT(win != NULL);
13973+ if (floating) objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGFloatingWindowLevelKey);
13974+ else objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGNormalWindowLevelKey);
13975+}
13976+
13977+void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) {
13978+ objc_msgSend_int(win->src.window, sel_registerName("setAlphaValue:"), opacity);
13979+ objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), (opacity < (u8)255));
13980+
13981+ if (opacity)
13982+ objc_msgSend_void_id((id)win->src.window, sel_registerName("setBackgroundColor:"), NSColor_colorWithSRGB(0, 0, 0, opacity));
13983+
13984+}
13985+
13986+void RGFW_window_restore(RGFW_window* win) {
13987+ RGFW_ASSERT(win != NULL);
13988+
13989+ if (RGFW_window_isMaximized(win))
13990+ objc_msgSend_void_SEL(win->src.window, sel_registerName("zoom:"), NULL);
13991+
13992+ objc_msgSend_void_SEL(win->src.window, sel_registerName("deminiaturize:"), NULL);
13993+ RGFW_window_show(win);
13994+}
13995+
13996+RGFW_bool RGFW_window_isFloating(RGFW_window* win) {
13997+ RGFW_ASSERT(win != NULL);
13998+ int level = ((int (*)(id, SEL))objc_msgSend) ((id)(win->src.window), (SEL)sel_registerName("level"));
13999+ return level > kCGNormalWindowLevelKey;
14000+}
14001+
14002+void RGFW_window_setName(RGFW_window* win, const char* name) {
14003+ RGFW_ASSERT(win != NULL);
14004+ if (name == NULL) name = "\0";
14005+
14006+ id str = NSString_stringWithUTF8String(name);
14007+ objc_msgSend_void_id((id)win->src.window, sel_registerName("setTitle:"), str);
14008+}
14009+
14010+#ifndef RGFW_NO_PASSTHROUGH
14011+void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) {
14012+ objc_msgSend_void_bool(win->src.window, sel_registerName("setIgnoresMouseEvents:"), passthrough);
14013+}
14014+#endif
14015+
14016+void RGFW_window_setAspectRatio(RGFW_window* win, i32 w, i32 h) {
14017+ if (w == 0 && h == 0) { w = 1; h = 1; };
14018+
14019+ ((void (*)(id, SEL, NSSize))objc_msgSend)
14020+ ((id)win->src.window, sel_registerName("setContentAspectRatio:"), (NSSize){(CGFloat)w, (CGFloat)h});
14021+}
14022+
14023+void RGFW_window_setMinSize(RGFW_window* win, i32 w, i32 h) {
14024+ ((void (*)(id, SEL, NSSize))objc_msgSend) ((id)win->src.window, sel_registerName("setMinSize:"), (NSSize){(CGFloat)w, (CGFloat)h});
14025+}
14026+
14027+void RGFW_window_setMaxSize(RGFW_window* win, i32 w, i32 h) {
14028+ if (w == 0 && h == 0) {
14029+ RGFW_monitor* mon = RGFW_window_getMonitor(win);
14030+ if (mon != NULL) {
14031+ w = mon->mode.w;
14032+ h = mon->mode.h;
14033+ }
14034+ }
14035+
14036+ ((void (*)(id, SEL, NSSize))objc_msgSend)
14037+ ((id)win->src.window, sel_registerName("setMaxSize:"), (NSSize){(CGFloat)w, (CGFloat)h});
14038+}
14039+
14040+RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_icon type) {
14041+ RGFW_ASSERT(win != NULL);
14042+ RGFW_UNUSED(type);
14043+
14044+ id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
14045+ pool = objc_msgSend_id(pool, sel_registerName("init"));
14046+
14047+ if (data == NULL) {
14048+ objc_msgSend_void_id((id)_RGFW->NSApp, sel_registerName("setApplicationIconImage:"), NULL);
14049+ objc_msgSend_bool_void(pool, sel_registerName("drain"));
14050+ return RGFW_TRUE;
14051+ }
14052+
14053+ id representation = NSBitmapImageRep_initWithBitmapData(NULL, w, h, 8, (NSInteger)4, true, false, "NSCalibratedRGBColorSpace", 1 << 1, w * 4, 32);
14054+ RGFW_copyImageData(NSBitmapImageRep_bitmapData(representation), w, h, RGFW_formatRGBA8, data, format, NULL);
14055+
14056+ id dock_image = ((id(*)(id, SEL, NSSize))objc_msgSend) (NSAlloc((id)objc_getClass("NSImage")), sel_registerName("initWithSize:"), ((NSSize){(CGFloat)w, (CGFloat)h}));
14057+
14058+ objc_msgSend_void_id(dock_image, sel_registerName("addRepresentation:"), representation);
14059+
14060+ objc_msgSend_void_id((id)_RGFW->NSApp, sel_registerName("setApplicationIconImage:"), dock_image);
14061+
14062+ NSRelease(dock_image);
14063+ NSRelease(representation);
14064+
14065+ objc_msgSend_bool_void(pool, sel_registerName("drain"));
14066+
14067+ return RGFW_TRUE;
14068+}
14069+
14070+id NSCursor_arrowStr(const char* str);
14071+id NSCursor_arrowStr(const char* str) {
14072+ void* nclass = objc_getClass("NSCursor");
14073+ SEL func = sel_registerName(str);
14074+ id mouse = (id) objc_msgSend_id(nclass, func);
14075+ NSRetain(mouse);
14076+ return mouse;
14077+}
14078+
14079+RGFW_mouse* RGFW_createMouseStandard(RGFW_mouseIcon mouse) {
14080+ switch (mouse) {
14081+ case RGFW_mouseNormal: return NSCursor_arrowStr("arrowCursor");
14082+ case RGFW_mouseArrow: return NSCursor_arrowStr("arrowCursor");
14083+ case RGFW_mouseIbeam: return NSCursor_arrowStr("IBeamCursor");
14084+ case RGFW_mouseCrosshair: return NSCursor_arrowStr("crosshairCursor");
14085+ case RGFW_mousePointingHand: return NSCursor_arrowStr("pointingHandCursor");
14086+ case RGFW_mouseResizeEW: return NSCursor_arrowStr("resizeLeftRightCursor");
14087+ case RGFW_mouseResizeE: return NSCursor_arrowStr("resizeLeftRightCursor");
14088+ case RGFW_mouseResizeW: return NSCursor_arrowStr("resizeLeftRightCursor");
14089+ case RGFW_mouseResizeNS: return NSCursor_arrowStr("resizeUpDownCursor");
14090+ case RGFW_mouseResizeN: return NSCursor_arrowStr("resizeUpDownCursor");
14091+ case RGFW_mouseResizeS: return NSCursor_arrowStr("resizeUpDownCursor");
14092+ case RGFW_mouseResizeNWSE: return NSCursor_arrowStr("_windowResizeNorthWestSouthEastCursor");
14093+ case RGFW_mouseResizeNW: return NSCursor_arrowStr("_windowResizeNorthWestSouthEastCursor");
14094+ case RGFW_mouseResizeSE: return NSCursor_arrowStr("_windowResizeNorthWestSouthEastCursor");
14095+ case RGFW_mouseResizeNESW: return NSCursor_arrowStr("_windowResizeNorthEastSouthWestCursor");
14096+ case RGFW_mouseResizeNE: return NSCursor_arrowStr("_windowResizeNorthEastSouthWestCursor");
14097+ case RGFW_mouseResizeSW: return NSCursor_arrowStr("_windowResizeNorthEastSouthWestCursor");
14098+ case RGFW_mouseResizeAll: return NSCursor_arrowStr("openHandCursor");
14099+ case RGFW_mouseNotAllowed: return NSCursor_arrowStr("operationNotAllowedCursor");
14100+ case RGFW_mouseWait: return NSCursor_arrowStr("arrowCursor");
14101+ case RGFW_mouseProgress: return NSCursor_arrowStr("arrowCursor");
14102+ default: return NULL;
14103+ }
14104+ return NULL;
14105+}
14106+
14107+RGFW_mouse* RGFW_createMouse(u8* data, i32 w, i32 h, RGFW_format format) {
14108+ id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
14109+ pool = objc_msgSend_id(pool, sel_registerName("init"));
14110+
14111+ if (data == NULL) {
14112+ objc_msgSend_void(NSCursor_arrowStr("arrowCursor"), sel_registerName("set"));
14113+
14114+ objc_msgSend_bool_void(pool, sel_registerName("drain"));
14115+ return NULL;
14116+ }
14117+
14118+ id representation = (id)NSBitmapImageRep_initWithBitmapData(NULL, w, h, 8, (NSInteger)4, true, false, "NSCalibratedRGBColorSpace", 1 << 1, w * 4, 32);
14119+ RGFW_copyImageData(NSBitmapImageRep_bitmapData(representation), w, h, RGFW_formatRGBA8, data, format, NULL);
14120+
14121+ id cursor_image = ((id(*)(id, SEL, NSSize))objc_msgSend) (NSAlloc((id)objc_getClass("NSImage")), sel_registerName("initWithSize:"), ((NSSize){(CGFloat)w, (CGFloat)h}));
14122+
14123+ objc_msgSend_void_id(cursor_image, sel_registerName("addRepresentation:"), representation);
14124+
14125+ id cursor = (id) ((id(*)(id, SEL, id, NSPoint))objc_msgSend)
14126+ (NSAlloc(objc_getClass("NSCursor")), sel_registerName("initWithImage:hotSpot:"), cursor_image, (NSPoint){0.0, 0.0});
14127+
14128+ NSRelease(cursor_image);
14129+ NSRelease(representation);
14130+
14131+ objc_msgSend_bool_void(pool, sel_registerName("drain"));
14132+
14133+ return (void*)cursor;
14134+}
14135+
14136+RGFW_bool RGFW_window_setMousePlatform(RGFW_window* win, RGFW_mouse* mouse) {
14137+ RGFW_ASSERT(win != NULL); RGFW_ASSERT(mouse);
14138+ CGDisplayShowCursor(kCGDirectMainDisplay);
14139+ objc_msgSend_void((id)mouse, sel_registerName("set"));
14140+ win->src.mouse = mouse;
14141+ return RGFW_TRUE;
14142+}
14143+
14144+void RGFW_freeMouse(RGFW_mouse* mouse) {
14145+ RGFW_ASSERT(mouse);
14146+ NSRelease((id)mouse);
14147+}
14148+
14149+void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) {
14150+ RGFW_window_showMouseFlags(win, show);
14151+ if (show) CGDisplayShowCursor(kCGDirectMainDisplay);
14152+ else CGDisplayHideCursor(kCGDirectMainDisplay);
14153+}
14154+
14155+void RGFW_window_setRawMouseModePlatform(RGFW_window* win, RGFW_bool state) {
14156+ RGFW_UNUSED(win); RGFW_UNUSED(state);
14157+}
14158+
14159+void RGFW_window_captureMousePlatform(RGFW_window* win, RGFW_bool state) {
14160+ RGFW_UNUSED(win);
14161+ CGAssociateMouseAndMouseCursorPosition(!(state == RGFW_TRUE));
14162+}
14163+
14164+void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y) {
14165+ RGFW_UNUSED(win);
14166+
14167+ win->internal.lastMouseX = x - win->x;
14168+ win->internal.lastMouseY = y - win->y;
14169+ CGWarpMouseCursorPosition((CGPoint){(CGFloat)x, (CGFloat)y});
14170+}
14171+
14172+
14173+void RGFW_window_hide(RGFW_window* win) {
14174+ objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), false);
14175+}
14176+
14177+void RGFW_window_show(RGFW_window* win) {
14178+ if (win->internal.flags & RGFW_windowFocusOnShow)
14179+ ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("makeKeyAndOrderFront:"), NULL);
14180+
14181+ ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("orderFront:"), NULL);
14182+ objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), true);
14183+}
14184+
14185+void RGFW_window_flash(RGFW_window* win, RGFW_flashRequest request) {
14186+ if (RGFW_window_isInFocus(win) && request) {
14187+ return;
14188+ }
14189+
14190+ id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
14191+ pool = objc_msgSend_id(pool, sel_registerName("init"));
14192+
14193+ if (_RGFW->flash) {
14194+ ((void (*)(id, SEL, NSInteger))objc_msgSend) ((id)_RGFW->NSApp, sel_registerName("cancelUserAttentionRequest:"), _RGFW->flash);
14195+ }
14196+
14197+ switch (request) {
14198+ case RGFW_flashBriefly:
14199+ _RGFW->flash = ((NSInteger (*)(id, SEL, NSInteger))objc_msgSend) ((id)_RGFW->NSApp, sel_registerName("requestUserAttention:"), NSInformationalRequest);
14200+ break;
14201+ case RGFW_flashUntilFocused:
14202+ _RGFW->flash = ((NSInteger (*)(id, SEL, NSInteger))objc_msgSend) ((id)_RGFW->NSApp, sel_registerName("requestUserAttention:"), NSCriticalRequest);
14203+ break;
14204+ default: break;
14205+ }
14206+
14207+ objc_msgSend_bool_void(pool, sel_registerName("drain"));
14208+}
14209+
14210+RGFW_bool RGFW_window_isHidden(RGFW_window* win) {
14211+ RGFW_ASSERT(win != NULL);
14212+
14213+ bool visible = objc_msgSend_bool(win->src.window, sel_registerName("isVisible"));
14214+ return visible == NO && !RGFW_window_isMinimized(win);
14215+}
14216+
14217+RGFW_bool RGFW_window_isMinimized(RGFW_window* win) {
14218+ RGFW_ASSERT(win != NULL);
14219+
14220+ return objc_msgSend_bool(win->src.window, sel_registerName("isMiniaturized")) == YES;
14221+}
14222+
14223+RGFW_bool RGFW_window_isMaximized(RGFW_window* win) {
14224+ RGFW_ASSERT(win != NULL);
14225+ RGFW_bool b = (RGFW_bool)objc_msgSend_bool(win->src.window, sel_registerName("isZoomed"));
14226+ return b;
14227+}
14228+
14229+RGFWDEF id RGFW_getNSScreenForDisplayUInt(u32 uintNum);
14230+id RGFW_getNSScreenForDisplayUInt(u32 uintNum) {
14231+ Class NSScreenClass = objc_getClass("NSScreen");
14232+
14233+ id screens = objc_msgSend_id(NSScreenClass, sel_registerName("screens"));
14234+
14235+ NSUInteger count = (NSUInteger)objc_msgSend_uint(screens, sel_registerName("count"));
14236+ NSUInteger i;
14237+ for (i = 0; i < count; i++) {
14238+ id screen = ((id (*)(id, SEL, int))objc_msgSend) (screens, sel_registerName("objectAtIndex:"), (int)i);
14239+ id description = objc_msgSend_id(screen, sel_registerName("deviceDescription"));
14240+ id screenNumberKey = NSString_stringWithUTF8String("NSScreenNumber");
14241+ id screenNumber = objc_msgSend_id_id(description, sel_registerName("objectForKey:"), screenNumberKey);
14242+
14243+ if (CGDisplayUnitNumber((CGDirectDisplayID)objc_msgSend_uint(screenNumber, sel_registerName("unsignedIntValue"))) == uintNum) {
14244+ return screen;
14245+ }
14246+ }
14247+
14248+ return NULL;
14249+}
14250+
14251+float RGFW_osx_getRefreshRate(CGDirectDisplayID display, CGDisplayModeRef mode);
14252+float RGFW_osx_getRefreshRate(CGDirectDisplayID display, CGDisplayModeRef mode) {
14253+ if (mode) {
14254+ float refreshRate = (float)CGDisplayModeGetRefreshRate(mode);
14255+ if (refreshRate != 0) return refreshRate;
14256+ }
14257+
14258+#ifndef RGFW_NO_IOKIT
14259+ float res = RGFW_osx_getFallbackRefreshRate(display);
14260+ if (res != 0) return res;
14261+#else
14262+ RGFW_UNUSED(display);
14263+#endif
14264+ return 60;
14265+}
14266+
14267+void RGFW_pollMonitors(void) {
14268+ u32 count;
14269+
14270+ if (CGGetActiveDisplayList(0, NULL, &count) != kCGErrorSuccess) {
14271+ return;
14272+ }
14273+
14274+ CGDirectDisplayID* displays = (CGDirectDisplayID*)RGFW_ALLOC(sizeof(CGDirectDisplayID) * count);
14275+ if (CGGetActiveDisplayList(count, displays, &count) != kCGErrorSuccess) {
14276+ return;
14277+ }
14278+
14279+
14280+ for (RGFW_monitorNode* node = _RGFW->monitors.list.head; node; node = node->next) {
14281+ node->disconnected = RGFW_TRUE;
14282+ }
14283+
14284+ CGDirectDisplayID primary = CGMainDisplayID();
14285+
14286+ u32 i;
14287+ for (i = 0; i < count; i++) {
14288+ RGFW_monitor monitor;
14289+
14290+ u32 uintNum = CGDisplayUnitNumber(displays[i]);
14291+ id screen = RGFW_getNSScreenForDisplayUInt(uintNum);
14292+
14293+ RGFW_monitorNode* node;
14294+ for (node = _RGFW->monitors.list.head; node; node = node->next) {
14295+ if (node->uintNum == uintNum) break;
14296+ }
14297+
14298+ if (node) {
14299+ node->screen = (void*)screen;
14300+ node->display = displays[i];
14301+ node->disconnected = RGFW_FALSE;
14302+ if (displays[i] == primary) {
14303+ _RGFW->monitors.primary = node;
14304+ }
14305+ continue;
14306+ }
14307+
14308+ const char name[] = "MacOS\0";
14309+ RGFW_MEMCPY(monitor.name, name, 6);
14310+
14311+ CGRect bounds = CGDisplayBounds(displays[i]);
14312+ monitor.x = (i32)bounds.origin.x;
14313+ monitor.y = (i32)RGFW_cocoaYTransform((float)(bounds.origin.y + bounds.size.height - 1));
14314+
14315+ CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displays[i]);
14316+ monitor.mode.w = (i32)CGDisplayModeGetWidth(mode);
14317+ monitor.mode.h = (i32)CGDisplayModeGetHeight(mode);
14318+ monitor.mode.src = (void*)mode;
14319+ monitor.mode.red = 8; monitor.mode.green = 8; monitor.mode.blue = 8;
14320+
14321+ monitor.mode.refreshRate = RGFW_osx_getRefreshRate(displays[i], mode);
14322+ CFRelease(mode);
14323+
14324+ CGSize screenSizeMM = CGDisplayScreenSize(displays[i]);
14325+ monitor.physW = (float)screenSizeMM.width / 25.4f;
14326+ monitor.physH = (float)screenSizeMM.height / 25.4f;
14327+
14328+ float ppi_width = ((float)monitor.mode.w / monitor.physW);
14329+ float ppi_height = ((float)monitor.mode.h / monitor.physH);
14330+
14331+ monitor.pixelRatio = (float)((CGFloat (*)(id, SEL))abi_objc_msgSend_fpret) (screen, sel_registerName("backingScaleFactor"));
14332+ float dpi = 96.0f * monitor.pixelRatio;
14333+
14334+ monitor.scaleX = ((((float) (ppi_width) / dpi) * 10.0f)) / 10.0f;
14335+ monitor.scaleY = ((((float) (ppi_height) / dpi) * 10.0f)) / 10.0f;
14336+
14337+ node = RGFW_monitors_add(&monitor);
14338+
14339+ node->screen = (void*)screen;
14340+ node->uintNum = uintNum;
14341+ node->display = displays[i];
14342+
14343+ if (displays[i] == primary) {
14344+ _RGFW->monitors.primary = node;
14345+ }
14346+
14347+ RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_TRUE);
14348+ }
14349+
14350+ RGFW_FREE(displays);
14351+
14352+ RGFW_monitors_refresh();
14353+}
14354+
14355+RGFW_bool RGFW_monitor_getWorkarea(RGFW_monitor* monitor, i32* x, i32* y, i32* width, i32* height) {
14356+ NSRect frameRect = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)monitor->node->screen, sel_registerName("visibleFrame"));
14357+
14358+ if (x) *x = (i32)frameRect.origin.x;
14359+ if (y) *y = (i32)RGFW_cocoaYTransform((float)(frameRect.origin.y + frameRect.size.height - (double)1.0f));
14360+ if (width) *width = (i32)frameRect.size.width;
14361+ if (height) *height = (i32)frameRect.size.height;
14362+
14363+ return RGFW_TRUE;
14364+}
14365+
14366+size_t RGFW_monitor_getGammaRampPtr(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
14367+ id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
14368+ pool = objc_msgSend_id(pool, sel_registerName("init"));
14369+
14370+ u32 size = CGDisplayGammaTableCapacity(monitor->node->display);
14371+ CGGammaValue* values = (CGGammaValue*)RGFW_ALLOC(size * 3 * sizeof(CGGammaValue));
14372+
14373+ CGGetDisplayTransferByTable(monitor->node->display, size, values, values + size, values + size * 2, &size);
14374+
14375+ for (u32 i = 0; ramp && i < size; i++) {
14376+ ramp->red[i] = (u16) (values[i] * 65535);
14377+ ramp->green[i] = (u16) (values[i + size] * 65535);
14378+ ramp->blue[i] = (u16) (values[i + size * 2] * 65535);
14379+ }
14380+
14381+ RGFW_FREE(values);
14382+
14383+ objc_msgSend_bool_void(pool, sel_registerName("drain"));
14384+ return size;
14385+}
14386+
14387+RGFW_bool RGFW_monitor_setGammaRamp(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
14388+ id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
14389+ pool = objc_msgSend_id(pool, sel_registerName("init"));
14390+
14391+ CGGammaValue* values = (CGGammaValue*)RGFW_ALLOC(ramp->count * 3 * sizeof(CGGammaValue));
14392+
14393+ for (u32 i = 0; i < ramp->count; i++) {
14394+ values[i] = ramp->red[i] / 65535.f;
14395+ values[i + ramp->count] = ramp->green[i] / 65535.f;
14396+ values[i + ramp->count * 2] = ramp->blue[i] / 65535.f;
14397+ }
14398+
14399+ CGSetDisplayTransferByTable(monitor->node->display, (u32)ramp->count, values, values + ramp->count, values + ramp->count * 2);
14400+
14401+ RGFW_FREE(values);
14402+
14403+ objc_msgSend_bool_void(pool, sel_registerName("drain"));
14404+
14405+ return RGFW_TRUE;
14406+}
14407+
14408+size_t RGFW_monitor_getModesPtr(RGFW_monitor* mon, RGFW_monitorMode** modes) {
14409+ CGDirectDisplayID display = mon->node->display;
14410+ CFArrayRef allModes = CGDisplayCopyAllDisplayModes(display, NULL);
14411+
14412+ if (allModes == NULL) {
14413+ return RGFW_FALSE;
14414+ }
14415+
14416+ size_t count = (size_t)CFArrayGetCount(allModes);
14417+
14418+ CFIndex i;
14419+ for (i = 0; i < (CFIndex)count && modes; i++) {
14420+ CGDisplayModeRef cmode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, i);
14421+
14422+ RGFW_monitorMode foundMode;
14423+ foundMode.w = (i32)CGDisplayModeGetWidth(cmode);
14424+ foundMode.h = (i32)CGDisplayModeGetHeight(cmode);
14425+ foundMode.refreshRate = RGFW_osx_getRefreshRate(display, cmode);
14426+ foundMode.red = 8; foundMode.green = 8; foundMode.blue = 8;
14427+ foundMode.src = (void*)cmode;
14428+ (*modes)[i] = foundMode;
14429+ }
14430+
14431+ CFRelease(allModes);
14432+ return count;
14433+}
14434+
14435+RGFW_bool RGFW_monitor_setMode(RGFW_monitor* mon, RGFW_monitorMode* mode) {
14436+ if (CGDisplaySetDisplayMode(mon->node->display, (CGDisplayModeRef)mode->src, NULL) == kCGErrorSuccess) {
14437+ return RGFW_TRUE;
14438+ }
14439+
14440+ return RGFW_FALSE;
14441+}
14442+
14443+RGFW_bool RGFW_monitor_requestMode(RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request) {
14444+ CGDirectDisplayID display = mon->node->display;
14445+ CFArrayRef allModes = CGDisplayCopyAllDisplayModes(display, NULL);
14446+
14447+ if (allModes == NULL) {
14448+ return RGFW_FALSE;
14449+ }
14450+
14451+ CGDisplayModeRef native = NULL;
14452+
14453+ CFIndex i;
14454+ for (i = 0; i < CFArrayGetCount(allModes); i++) {
14455+ CGDisplayModeRef cmode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, i);
14456+
14457+ RGFW_monitorMode foundMode;
14458+ foundMode.w = (i32)CGDisplayModeGetWidth(cmode);
14459+ foundMode.h = (i32)CGDisplayModeGetHeight(cmode);
14460+ foundMode.refreshRate = RGFW_osx_getRefreshRate(display, cmode);
14461+ foundMode.red = 8; foundMode.green = 8; foundMode.blue = 8;
14462+ foundMode.src = (void*)cmode;
14463+
14464+ if (RGFW_monitorModeCompare(mode, &foundMode, request)) {
14465+ native = cmode;
14466+ mon->mode = foundMode;
14467+ break;
14468+ }
14469+ }
14470+
14471+ CFRelease(allModes);
14472+
14473+ if (native) {
14474+ if (CGDisplaySetDisplayMode(display, native, NULL) == kCGErrorSuccess) {
14475+ return RGFW_TRUE;
14476+ }
14477+ }
14478+
14479+ return RGFW_FALSE;
14480+}
14481+
14482+RGFW_monitor* RGFW_window_getMonitor(RGFW_window* win) {
14483+ id screen = objc_msgSend_id(win->src.window, sel_registerName("screen"));
14484+ id description = objc_msgSend_id(screen, sel_registerName("deviceDescription"));
14485+ id screenNumberKey = NSString_stringWithUTF8String("NSScreenNumber");
14486+ id screenNumber = objc_msgSend_id_id(description, sel_registerName("objectForKey:"), screenNumberKey);
14487+
14488+ CGDirectDisplayID display = (CGDirectDisplayID)objc_msgSend_uint(screenNumber, sel_registerName("unsignedIntValue"));
14489+
14490+ RGFW_monitorNode* node = _RGFW->monitors.list.head;
14491+ for (node = _RGFW->monitors.list.head; node; node = node->next) {
14492+ if (node->display == display && (id)node->screen == screen) {
14493+ break;
14494+ }
14495+ }
14496+
14497+ if (node == NULL) {
14498+ node = _RGFW->monitors.primary ? _RGFW->monitors.primary : _RGFW->monitors.list.head;
14499+ }
14500+
14501+ if (node == NULL) return NULL;
14502+ return &node->mon;
14503+}
14504+
14505+RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) {
14506+ size_t clip_len;
14507+ char* clip = (char*)NSPasteboard_stringForType(NSPasteboard_generalPasteboard(), NSPasteboardTypeString, &clip_len);
14508+ if (clip == NULL) return -1;
14509+
14510+ if (str != NULL) {
14511+ if (strCapacity < clip_len)
14512+ return 0;
14513+
14514+ RGFW_MEMCPY(str, clip, clip_len);
14515+
14516+ str[clip_len] = '\0';
14517+ }
14518+
14519+ return (RGFW_ssize_t)clip_len;
14520+}
14521+
14522+void RGFW_writeClipboard(const char* text, u32 textLen) {
14523+ RGFW_UNUSED(textLen);
14524+
14525+ NSPasteboardType array[] = { NSPasteboardTypeString, NULL };
14526+ NSPasteBoard_declareTypes(NSPasteboard_generalPasteboard(), array, 1, NULL);
14527+
14528+ SEL func = sel_registerName("setString:forType:");
14529+ ((bool (*)(id, SEL, id, id))objc_msgSend)
14530+ (NSPasteboard_generalPasteboard(), func, NSString_stringWithUTF8String(text), NSString_stringWithUTF8String((const char*)NSPasteboardTypeString));
14531+}
14532+
14533+#ifdef RGFW_OPENGL
14534+void NSOpenGLContext_setValues(id context, const int* vals, NSOpenGLContextParameter param);
14535+void NSOpenGLContext_setValues(id context, const int* vals, NSOpenGLContextParameter param) {
14536+ ((void (*)(id, SEL, const int*, NSOpenGLContextParameter))objc_msgSend)
14537+ (context, sel_registerName("setValues:forParameter:"), vals, param);
14538+}
14539+
14540+
14541+/* MacOS OpenGL API spares us yet again (there are no extensions) */
14542+RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char * extension, size_t len) { RGFW_UNUSED(extension); RGFW_UNUSED(len); return RGFW_FALSE; }
14543+
14544+RGFW_proc RGFW_getProcAddress_OpenGL(const char* procname) {
14545+ static CFBundleRef RGFWnsglFramework = NULL;
14546+ if (RGFWnsglFramework == NULL)
14547+ RGFWnsglFramework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
14548+
14549+ CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault, procname, kCFStringEncodingASCII);
14550+
14551+ RGFW_proc symbol = (RGFW_proc)CFBundleGetFunctionPointerForName(RGFWnsglFramework, symbolName);
14552+
14553+ CFRelease(symbolName);
14554+
14555+ return symbol;
14556+}
14557+
14558+RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints) {
14559+ win->src.ctx.native = ctx;
14560+ win->src.gfxType = RGFW_gfxNativeOpenGL;
14561+
14562+ i32 attribs[40];
14563+ size_t render_type_index = 0;
14564+ {
14565+ RGFW_attribStack stack;
14566+ RGFW_attribStack_init(&stack, attribs, 40);
14567+
14568+ i32 colorBits = (i32)(hints->red + hints->green + hints->blue + hints->alpha) / 4;
14569+ RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAColorSize, colorBits);
14570+
14571+ RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAAlphaSize, hints->alpha);
14572+ RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFADepthSize, hints->depth);
14573+ RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAStencilSize, hints->stencil);
14574+ RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAAuxBuffers, hints->auxBuffers);
14575+ RGFW_attribStack_pushAttrib(&stack, NSOpenGLPFAClosestPolicy);
14576+ if (hints->samples) {
14577+ RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFASampleBuffers, 1);
14578+ RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFASamples, hints->samples);
14579+ } else RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFASampleBuffers, 0);
14580+
14581+ if (hints->doubleBuffer)
14582+ RGFW_attribStack_pushAttrib(&stack, NSOpenGLPFADoubleBuffer);
14583+
14584+ #ifdef RGFW_COCOA_GRAPHICS_SWITCHING
14585+ RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAAllowOfflineRenderers, kCGLPFASupportsAutomaticGraphicsSwitching);
14586+ #endif
14587+ #if MAC_OS_X_VERSION_MAX_ALLOWED < 101200
14588+ if (hints->stereo) RGFW_attribStack_pushAttrib(&stack, NSOpenGLPFAStereo);
14589+ #endif
14590+
14591+ /* macOS has the surface attribs and the OpenGL attribs connected for some reason maybe this is to give macOS more control to limit openGL/the OpenGL version? */
14592+ RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAOpenGLProfile,
14593+ (hints->major >= 4) ? NSOpenGLProfileVersion4_1Core : (hints->major >= 3) ?
14594+ NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy);
14595+
14596+ if (hints->major <= 2) {
14597+ i32 accumSize = (i32)(hints->accumRed + hints->accumGreen + hints->accumBlue + hints->accumAlpha) / 4;
14598+ RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAAccumSize, accumSize);
14599+ }
14600+
14601+ if (hints->renderer == RGFW_glSoftware) {
14602+ RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFARendererID, kCGLRendererGenericFloatID);
14603+ } else {
14604+ RGFW_attribStack_pushAttrib(&stack, NSOpenGLPFAAccelerated);
14605+ }
14606+ render_type_index = stack.count - 1;
14607+
14608+ RGFW_attribStack_pushAttribs(&stack, 0, 0);
14609+ }
14610+
14611+ void* format = (void*) ((id(*)(id, SEL, const u32*))objc_msgSend) (NSAlloc((id)objc_getClass("NSOpenGLPixelFormat")), sel_registerName("initWithAttributes:"), (u32*)attribs);
14612+ if (format == NULL) {
14613+ RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load pixel format for OpenGL");
14614+
14615+ assert(render_type_index + 3 < (sizeof(attribs) / sizeof(attribs[0])));
14616+ attribs[render_type_index] = NSOpenGLPFARendererID;
14617+ attribs[render_type_index + 1] = kCGLRendererGenericFloatID;
14618+ attribs[render_type_index + 3] = 0;
14619+
14620+ format = (void*) ((id(*)(id, SEL, const u32*))objc_msgSend) (NSAlloc((id)objc_getClass("NSOpenGLPixelFormat")), sel_registerName("initWithAttributes:"), (u32*)attribs);
14621+ if (format == NULL)
14622+ RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "and loading software rendering OpenGL failed");
14623+ else
14624+ RGFW_debugCallback(RGFW_typeWarning, RGFW_warningOpenGL, "Switching to software rendering");
14625+ }
14626+
14627+ /* the pixel format can be passed directly to OpenGL context creation to create a context
14628+ this is because the format also includes information about the OpenGL version (which may be a bad thing) */
14629+
14630+ if (win->src.view)
14631+ NSRelease(win->src.view);
14632+ win->src.view = (id) ((id(*)(id, SEL, NSRect, u32*))objc_msgSend) (NSAlloc(_RGFW->customViewClasses[1]),
14633+ sel_registerName("initWithFrame:pixelFormat:"), (NSRect){{0, 0}, {(double)win->w, (double)win->h}}, (u32*)format);
14634+
14635+ id share = NULL;
14636+ if (hints->share) {
14637+ share = (id)hints->share->ctx;
14638+ }
14639+
14640+ win->src.ctx.native->ctx = ((id (*)(id, SEL, id, id))objc_msgSend)(NSAlloc(objc_getClass("NSOpenGLContext")),
14641+ sel_registerName("initWithFormat:shareContext:"),
14642+ (id)format, share);
14643+
14644+ win->src.ctx.native->format = format;
14645+
14646+ objc_msgSend_void_id(win->src.view, sel_registerName("setOpenGLContext:"), win->src.ctx.native->ctx);
14647+ if (win->internal.flags & RGFW_windowTransparent) {
14648+ i32 opacity = 0;
14649+ #define NSOpenGLCPSurfaceOpacity 236
14650+ NSOpenGLContext_setValues((id)win->src.ctx.native->ctx, &opacity, (NSOpenGLContextParameter)NSOpenGLCPSurfaceOpacity);
14651+
14652+ }
14653+
14654+ objc_msgSend_void(win->src.ctx.native->ctx, sel_registerName("makeCurrentContext"));
14655+
14656+ objc_msgSend_void_id((id)win->src.window, sel_registerName("setContentView:"), win->src.view);
14657+ objc_msgSend_void_bool(win->src.view, sel_registerName("setWantsLayer:"), true);
14658+ objc_msgSend_int((id)win->src.view, sel_registerName("setLayerContentsPlacement:"), 4);
14659+
14660+ RGFW_window_swapInterval_OpenGL(win, 0);
14661+
14662+ RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized.");
14663+ return RGFW_TRUE;
14664+}
14665+
14666+void RGFW_window_deleteContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx) {
14667+ objc_msgSend_void(ctx->format, sel_registerName("release"));
14668+ win->src.ctx.native->format = NULL;
14669+
14670+ objc_msgSend_void(ctx->ctx, sel_registerName("release"));
14671+ win->src.ctx.native->ctx = NULL;
14672+ RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context freed.");
14673+}
14674+
14675+void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win) {
14676+ if (win) RGFW_ASSERT(win->src.ctx.native);
14677+ if (win != NULL)
14678+ objc_msgSend_void(win->src.ctx.native->ctx, sel_registerName("makeCurrentContext"));
14679+ else
14680+ objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("clearCurrentContext"));
14681+}
14682+void* RGFW_getCurrentContext_OpenGL(void) {
14683+ return objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("currentContext"));
14684+}
14685+
14686+void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) {
14687+ RGFW_ASSERT(win && win->src.ctx.native);
14688+ objc_msgSend_void(win->src.ctx.native->ctx, sel_registerName("flushBuffer"));
14689+}
14690+void RGFW_window_swapInterval_OpenGL(RGFW_window* win, i32 swapInterval) {
14691+ RGFW_ASSERT(win != NULL && win->src.ctx.native != NULL);
14692+ NSOpenGLContext_setValues((id)win->src.ctx.native->ctx, &swapInterval, (NSOpenGLContextParameter)222);
14693+}
14694+#endif
14695+
14696+void RGFW_deinitPlatform(void) {
14697+ objc_msgSend_void_id(_RGFW->NSApp, sel_registerName("setDelegate:"), NULL);
14698+
14699+ objc_msgSend_void_id(_RGFW->NSApp, sel_registerName("stop:"), NULL);
14700+ NSRelease(_RGFW->NSApp);
14701+ _RGFW->NSApp = NULL;
14702+
14703+ NSRelease(_RGFW->customNSAppDelegate);
14704+
14705+ _RGFW->customNSAppDelegate = NULL;
14706+
14707+ objc_disposeClassPair((Class)_RGFW->customViewClasses[0]);
14708+ objc_disposeClassPair((Class)_RGFW->customViewClasses[1]);
14709+ objc_disposeClassPair((Class)_RGFW->customWindowDelegateClass);
14710+ objc_disposeClassPair((Class)_RGFW->customNSAppDelegateClass);
14711+}
14712+
14713+void RGFW_window_closePlatform(RGFW_window* win) {
14714+ objc_msgSend_void_id((id)win->src.window, sel_registerName("setDelegate:"), NULL);
14715+ NSRelease((id)win->src.delegate);
14716+ NSRelease(win->src.view);
14717+
14718+ objc_msgSend_id(win->src.window, sel_registerName("close"));
14719+ NSRelease(win->src.window);
14720+}
14721+
14722+#ifdef RGFW_VULKAN
14723+VkResult RGFW_window_createSurface_Vulkan(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface) {
14724+ RGFW_ASSERT(win != NULL); RGFW_ASSERT(instance);
14725+ RGFW_ASSERT(surface != NULL);
14726+
14727+ *surface = VK_NULL_HANDLE;
14728+ id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
14729+ pool = objc_msgSend_id(pool, sel_registerName("init"));
14730+
14731+ id nsView = (id)win->src.view;
14732+ if (!nsView) {
14733+ RGFW_debugCallback(RGFW_typeError, RGFW_errMetal, "NSView is NULL for macOS window");
14734+ return -1;
14735+ }
14736+
14737+
14738+ id layer = ((id (*)(id, SEL))objc_msgSend)(nsView, sel_registerName("layer"));
14739+
14740+ void* metalLayer = RGFW_getLayer_OSX();
14741+ if (metalLayer == NULL) {
14742+ return -1;
14743+ }
14744+ ((void (*)(id, SEL, id))objc_msgSend)((id)nsView, sel_registerName("setLayer:"), metalLayer);
14745+ ((void (*)(id, SEL, BOOL))objc_msgSend)(nsView, sel_registerName("setWantsLayer:"), YES);
14746+
14747+ VkResult result;
14748+/*
14749+ VkMetalSurfaceCreateInfoEXT macos;
14750+ macos.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
14751+ macos.slayer = metalLayer;
14752+ RGFW_MEMZERO(&macos, sizeof(macos));
14753+ result = vkCreateMacOSSurfaceMVK(instance, &macos, NULL, surface);
14754+*/
14755+
14756+ VkMacOSSurfaceCreateInfoMVK macos;
14757+ RGFW_MEMZERO(&macos, sizeof(macos));
14758+ macos.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
14759+ macos.pView = nsView;
14760+
14761+ result = vkCreateMacOSSurfaceMVK(instance, &macos, NULL, surface);
14762+
14763+ objc_msgSend_bool_void(pool, sel_registerName("drain"));
14764+
14765+ return result;
14766+}
14767+#endif
14768+
14769+#ifdef RGFW_WEBGPU
14770+WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance instance) {
14771+ WGPUSurfaceDescriptor surfaceDesc = {0};
14772+ id* nsView = (id*)window->src.view;
14773+ if (!nsView) {
14774+ RGFW_debugCallback(RGFW_typeError, RGFW_errMetal, "NSView is NULL for macOS window");
14775+ return NULL;
14776+ }
14777+
14778+ ((void (*)(id, SEL, BOOL))objc_msgSend)(nsView, sel_registerName("setWantsLayer:"), YES);
14779+ id layer = ((id (*)(id, SEL))objc_msgSend)(nsView, sel_registerName("layer"));
14780+
14781+ void* metalLayer = RGFW_getLayer_OSX();
14782+ if (metalLayer == NULL) {
14783+ return NULL;
14784+ }
14785+ ((void (*)(id, SEL, id))objc_msgSend)((id)nsView, sel_registerName("setLayer:"), metalLayer);
14786+ layer = metalLayer;
14787+
14788+ WGPUSurfaceSourceMetalLayer fromMetal = {0};
14789+ fromMetal.chain.sType = WGPUSType_SurfaceSourceMetalLayer;
14790+#ifdef __OBJC__
14791+ fromMetal.layer = (__bridge CAMetalLayer*)layer; /* Use __bridge for ARC compatibility if mixing C/Obj-C */
14792+#else
14793+ fromMetal.layer = layer;
14794+#endif
14795+
14796+ surfaceDesc.nextInChain = (WGPUChainedStruct*)&fromMetal.chain;
14797+ return wgpuInstanceCreateSurface(instance, &surfaceDesc);
14798+}
14799+#endif
14800+
14801+#endif /* RGFW_MACOS */
14802+
14803+/*
14804+ End of MaOS defines
14805+*/
14806+
14807+/*
14808+ WASM defines
14809+*/
14810+
14811+#ifdef RGFW_WASM
14812+EM_BOOL Emscripten_on_resize(int eventType, const EmscriptenUiEvent* E, void* userData) {
14813+ RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
14814+ RGFW_windowResizedCallback(_RGFW->root, E->windowInnerWidth, E->windowInnerHeight);
14815+ return EM_TRUE;
14816+}
14817+
14818+EM_BOOL Emscripten_on_fullscreenchange(int eventType, const EmscriptenFullscreenChangeEvent* E, void* userData) {
14819+ RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
14820+
14821+ if (!(_RGFW->root->internal.enabledEvents & RGFW_windowResizedFlag)) return EM_TRUE;
14822+
14823+ static u8 fullscreen = RGFW_FALSE;
14824+ static i32 originalW, originalH;
14825+
14826+ if (fullscreen == RGFW_FALSE) {
14827+ originalW = _RGFW->root->w;
14828+ originalH = _RGFW->root->h;
14829+ }
14830+
14831+ fullscreen = !fullscreen;
14832+ _RGFW->root->w = E->screenWidth;
14833+ _RGFW->root->h = E->screenHeight;
14834+
14835+ EM_ASM("Module.canvas.focus();");
14836+
14837+ if (fullscreen == RGFW_FALSE) {
14838+ _RGFW->root->w = originalW;
14839+ _RGFW->root->h = originalH;
14840+ } else {
14841+ #if __EMSCRIPTEN_major__ >= 1 && __EMSCRIPTEN_minor__ >= 29 && __EMSCRIPTEN_tiny__ >= 0
14842+ EmscriptenFullscreenStrategy FSStrat = {0};
14843+ FSStrat.scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH;
14844+ FSStrat.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF;
14845+ FSStrat.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT;
14846+ emscripten_request_fullscreen_strategy("#canvas", 1, &FSStrat);
14847+ #else
14848+ emscripten_request_fullscreen("#canvas", 1);
14849+ #endif
14850+ }
14851+
14852+ emscripten_set_canvas_element_size("#canvas", _RGFW->root->w, _RGFW->root->h);
14853+ RGFW_windowResizedCallback(_RGFW->root, _RGFW->root->w, _RGFW->root->h);
14854+ return EM_TRUE;
14855+}
14856+
14857+EM_BOOL Emscripten_on_focusin(int eventType, const EmscriptenFocusEvent* E, void* userData) {
14858+ RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(E);
14859+
14860+ RGFW_windowFocusCallback(_RGFW->root, 1);
14861+ return EM_TRUE;
14862+}
14863+
14864+EM_BOOL Emscripten_on_focusout(int eventType, const EmscriptenFocusEvent* E, void* userData) {
14865+ RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(E);
14866+
14867+ RGFW_windowFocusCallback(_RGFW->root, 0);
14868+ return EM_TRUE;
14869+}
14870+
14871+EM_BOOL Emscripten_on_mousemove(int eventType, const EmscriptenMouseEvent* E, void* userData) {
14872+ RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
14873+ RGFW_mousePosCallback(_RGFW->root, E->targetX, E->targetY);
14874+ RGFW_rawMotionCallback(_RGFW->root, E->movementX, E->movementY);
14875+ return EM_TRUE;
14876+}
14877+
14878+EM_BOOL Emscripten_on_mousedown(int eventType, const EmscriptenMouseEvent* E, void* userData) {
14879+ RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
14880+
14881+ int button = E->button;
14882+ if (button > 2)
14883+ button += 2;
14884+
14885+ RGFW_mouseButtonCallback(_RGFW->root, button, 1);
14886+ return EM_TRUE;
14887+}
14888+
14889+EM_BOOL Emscripten_on_mouseup(int eventType, const EmscriptenMouseEvent* E, void* userData) {
14890+ RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
14891+
14892+ int button = E->button;
14893+ if (button > 2)
14894+ button += 2;
14895+
14896+ RGFW_mouseButtonCallback(_RGFW->root, button, 0);
14897+ return EM_TRUE;
14898+}
14899+
14900+EM_BOOL Emscripten_on_wheel(int eventType, const EmscriptenWheelEvent* E, void* userData) {
14901+ RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
14902+
14903+ RGFW_mouseScrollCallback(_RGFW->root, E->deltaX, E->deltaY);
14904+
14905+ return EM_TRUE;
14906+}
14907+
14908+EM_BOOL Emscripten_on_touchstart(int eventType, const EmscriptenTouchEvent* E, void* userData) {
14909+ RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
14910+
14911+ if (!(_RGFW->root->internal.enabledEvents & RGFW_mouseButtonPressedFlag)) return EM_TRUE;
14912+
14913+ size_t i;
14914+ for (i = 0; i < (size_t)E->numTouches; i++) {
14915+ RGFW_mousePosCallback(_RGFW->root, E->touches[i].targetX, E->touches[i].targetY);
14916+ RGFW_rawMotionCallback(_RGFW->root, 0, 0);
14917+ RGFW_mouseButtonCallback(_RGFW->root, RGFW_mouseLeft, 1);
14918+ }
14919+
14920+ return EM_TRUE;
14921+}
14922+
14923+EM_BOOL Emscripten_on_touchmove(int eventType, const EmscriptenTouchEvent* E, void* userData) {
14924+ RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
14925+
14926+ if (!(_RGFW->root->internal.enabledEvents & RGFW_mousePosChangedFlag)) return EM_TRUE;
14927+
14928+ size_t i;
14929+ for (i = 0; i < (size_t)E->numTouches; i++) {
14930+ RGFW_mousePosCallback(_RGFW->root, E->touches[i].targetX, E->touches[i].targetY);
14931+ RGFW_rawMotionCallback(_RGFW->root, 0, 0);
14932+ }
14933+ return EM_TRUE;
14934+}
14935+
14936+EM_BOOL Emscripten_on_touchend(int eventType, const EmscriptenTouchEvent* E, void* userData) {
14937+ RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
14938+
14939+ if (!(_RGFW->root->internal.enabledEvents & RGFW_mouseButtonReleasedFlag)) return EM_TRUE;
14940+
14941+ size_t i;
14942+ for (i = 0; i < (size_t)E->numTouches; i++) {
14943+ RGFW_mousePosCallback(_RGFW->root, E->touches[i].targetX, E->touches[i].targetY);
14944+ RGFW_rawMotionCallback(_RGFW->root, 0, 0);
14945+ RGFW_mouseButtonCallback(_RGFW->root, RGFW_mouseLeft, 0);
14946+ }
14947+ return EM_TRUE;
14948+}
14949+
14950+EM_BOOL Emscripten_on_touchcancel(int eventType, const EmscriptenTouchEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); return EM_TRUE; }
14951+
14952+RGFW_key RGFW_WASMPhysicalToRGFW(u32 hash);
14953+
14954+void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyEvent(char* code, u32 codepoint, RGFW_bool press) {
14955+ const char* iCode = code;
14956+
14957+ u32 hash = 0;
14958+ while(*iCode) hash = ((hash ^ 0x7E057D79U) << 3) ^ (unsigned int)*iCode++;
14959+
14960+ u32 physicalKey = RGFW_WASMPhysicalToRGFW(hash);
14961+
14962+ RGFW_keyCallback(_RGFW->root, physicalKey, _RGFW->root->internal.mod, RGFW_isKeyDown((u8)physicalKey) && press, press);
14963+ if (press) {
14964+; RGFW_keyCharCallback(_RGFW->root, codepoint);
14965+ }
14966+}
14967+
14968+void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyMods(RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll) {
14969+ RGFW_keyUpdateKeyModsEx(_RGFW->root, capital, numlock, control, alt, shift, super, scroll);
14970+}
14971+
14972+void EMSCRIPTEN_KEEPALIVE Emscripten_onDrop(char* file, size_t size) {
14973+ RGFW_dataDropCallback(_RGFW->root, file, size, RGFW_dataFile);
14974+}
14975+
14976+void RGFW_stopCheckEvents(void) {
14977+ _RGFW->stopCheckEvents_bool = RGFW_TRUE;
14978+}
14979+
14980+RGFW_bool RGFW_createSurfacePtr(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) {
14981+ surface->data = data;
14982+ surface->w = w;
14983+ surface->h = h;
14984+ surface->format = format;
14985+ return RGFW_TRUE;
14986+}
14987+
14988+void RGFW_window_blitSurface(RGFW_window* win, RGFW_surface* surface) {
14989+ /* TODO: Needs fixing. */
14990+ RGFW_copyImageData(surface->data, surface->w, RGFW_MIN(win->h, surface->h), RGFW_formatRGBA8, surface->data, surface->format, surface->convertFunc);
14991+ EM_ASM_({
14992+ var data = Module.HEAPU8.slice($0, $0 + $1 * $2 * 4);
14993+ let context = document.getElementById("canvas").getContext("2d");
14994+ let image = context.getImageData(0, 0, $1, $2);
14995+ image.data.set(data);
14996+ context.putImageData(image, 0, $4 - $2);
14997+ }, surface->data, surface->w, surface->h, RGFW_MIN(win->h, surface->w), RGFW_MIN(win->h, surface->h));
14998+}
14999+
15000+void RGFW_surface_freePtr(RGFW_surface* surface) { }
15001+
15002+#include <sys/stat.h>
15003+#include <sys/types.h>
15004+#include <errno.h>
15005+#include <stdio.h>
15006+
15007+void EMSCRIPTEN_KEEPALIVE RGFW_mkdir(char* name) { mkdir(name, 0755); }
15008+
15009+void EMSCRIPTEN_KEEPALIVE RGFW_writeFile(const char *path, const char *data, size_t len) {
15010+ FILE* file = fopen(path, "w+");
15011+ if (file == NULL)
15012+ return;
15013+
15014+ fwrite(data, sizeof(char), len, file);
15015+ fclose(file);
15016+}
15017+
15018+void RGFW_initKeycodesPlatform(void) {
15019+ _RGFW->keycodes[DOM_VK_BACK_QUOTE] = RGFW_keyBacktick;
15020+ _RGFW->keycodes[DOM_VK_0] = RGFW_key0;
15021+ _RGFW->keycodes[DOM_VK_1] = RGFW_key1;
15022+ _RGFW->keycodes[DOM_VK_2] = RGFW_key2;
15023+ _RGFW->keycodes[DOM_VK_3] = RGFW_key3;
15024+ _RGFW->keycodes[DOM_VK_4] = RGFW_key4;
15025+ _RGFW->keycodes[DOM_VK_5] = RGFW_key5;
15026+ _RGFW->keycodes[DOM_VK_6] = RGFW_key6;
15027+ _RGFW->keycodes[DOM_VK_7] = RGFW_key7;
15028+ _RGFW->keycodes[DOM_VK_8] = RGFW_key8;
15029+ _RGFW->keycodes[DOM_VK_9] = RGFW_key9;
15030+ _RGFW->keycodes[DOM_VK_SPACE] = RGFW_keySpace;
15031+ _RGFW->keycodes[DOM_VK_A] = RGFW_keyA;
15032+ _RGFW->keycodes[DOM_VK_B] = RGFW_keyB;
15033+ _RGFW->keycodes[DOM_VK_C] = RGFW_keyC;
15034+ _RGFW->keycodes[DOM_VK_D] = RGFW_keyD;
15035+ _RGFW->keycodes[DOM_VK_E] = RGFW_keyE;
15036+ _RGFW->keycodes[DOM_VK_F] = RGFW_keyF;
15037+ _RGFW->keycodes[DOM_VK_G] = RGFW_keyG;
15038+ _RGFW->keycodes[DOM_VK_H] = RGFW_keyH;
15039+ _RGFW->keycodes[DOM_VK_I] = RGFW_keyI;
15040+ _RGFW->keycodes[DOM_VK_J] = RGFW_keyJ;
15041+ _RGFW->keycodes[DOM_VK_K] = RGFW_keyK;
15042+ _RGFW->keycodes[DOM_VK_L] = RGFW_keyL;
15043+ _RGFW->keycodes[DOM_VK_M] = RGFW_keyM;
15044+ _RGFW->keycodes[DOM_VK_N] = RGFW_keyN;
15045+ _RGFW->keycodes[DOM_VK_O] = RGFW_keyO;
15046+ _RGFW->keycodes[DOM_VK_P] = RGFW_keyP;
15047+ _RGFW->keycodes[DOM_VK_Q] = RGFW_keyQ;
15048+ _RGFW->keycodes[DOM_VK_R] = RGFW_keyR;
15049+ _RGFW->keycodes[DOM_VK_S] = RGFW_keyS;
15050+ _RGFW->keycodes[DOM_VK_T] = RGFW_keyT;
15051+ _RGFW->keycodes[DOM_VK_U] = RGFW_keyU;
15052+ _RGFW->keycodes[DOM_VK_V] = RGFW_keyV;
15053+ _RGFW->keycodes[DOM_VK_W] = RGFW_keyW;
15054+ _RGFW->keycodes[DOM_VK_X] = RGFW_keyX;
15055+ _RGFW->keycodes[DOM_VK_Y] = RGFW_keyY;
15056+ _RGFW->keycodes[DOM_VK_Z] = RGFW_keyZ;
15057+ _RGFW->keycodes[DOM_VK_PERIOD] = RGFW_keyPeriod;
15058+ _RGFW->keycodes[DOM_VK_COMMA] = RGFW_keyComma;
15059+ _RGFW->keycodes[DOM_VK_SLASH] = RGFW_keySlash;
15060+ _RGFW->keycodes[DOM_VK_OPEN_BRACKET] = RGFW_keyBracket;
15061+ _RGFW->keycodes[DOM_VK_CLOSE_BRACKET] = RGFW_keyCloseBracket;
15062+ _RGFW->keycodes[DOM_VK_SEMICOLON] = RGFW_keySemicolon;
15063+ _RGFW->keycodes[DOM_VK_QUOTE] = RGFW_keyApostrophe;
15064+ _RGFW->keycodes[DOM_VK_BACK_SLASH] = RGFW_keyBackSlash;
15065+ _RGFW->keycodes[DOM_VK_RETURN] = RGFW_keyReturn;
15066+ _RGFW->keycodes[DOM_VK_DELETE] = RGFW_keyDelete;
15067+ _RGFW->keycodes[DOM_VK_NUM_LOCK] = RGFW_keyNumLock;
15068+ _RGFW->keycodes[DOM_VK_DIVIDE] = RGFW_keyPadSlash;
15069+ _RGFW->keycodes[DOM_VK_MULTIPLY] = RGFW_keyPadMultiply;
15070+ _RGFW->keycodes[DOM_VK_SUBTRACT] = RGFW_keyPadMinus;
15071+ _RGFW->keycodes[DOM_VK_NUMPAD1] = RGFW_keyPad1;
15072+ _RGFW->keycodes[DOM_VK_NUMPAD2] = RGFW_keyPad2;
15073+ _RGFW->keycodes[DOM_VK_NUMPAD3] = RGFW_keyPad3;
15074+ _RGFW->keycodes[DOM_VK_NUMPAD4] = RGFW_keyPad4;
15075+ _RGFW->keycodes[DOM_VK_NUMPAD5] = RGFW_keyPad5;
15076+ _RGFW->keycodes[DOM_VK_NUMPAD6] = RGFW_keyPad6;
15077+ _RGFW->keycodes[DOM_VK_NUMPAD9] = RGFW_keyPad9;
15078+ _RGFW->keycodes[DOM_VK_NUMPAD0] = RGFW_keyPad0;
15079+ _RGFW->keycodes[DOM_VK_DECIMAL] = RGFW_keyPadPeriod;
15080+ _RGFW->keycodes[DOM_VK_RETURN] = RGFW_keyPadReturn;
15081+ _RGFW->keycodes[DOM_VK_HYPHEN_MINUS] = RGFW_keyMinus;
15082+ _RGFW->keycodes[DOM_VK_EQUALS] = RGFW_keyEquals;
15083+ _RGFW->keycodes[DOM_VK_BACK_SPACE] = RGFW_keyBackSpace;
15084+ _RGFW->keycodes[DOM_VK_TAB] = RGFW_keyTab;
15085+ _RGFW->keycodes[DOM_VK_CAPS_LOCK] = RGFW_keyCapsLock;
15086+ _RGFW->keycodes[DOM_VK_SHIFT] = RGFW_keyShiftL;
15087+ _RGFW->keycodes[DOM_VK_CONTROL] = RGFW_keyControlL;
15088+ _RGFW->keycodes[DOM_VK_ALT] = RGFW_keyAltL;
15089+ _RGFW->keycodes[DOM_VK_META] = RGFW_keySuperL;
15090+ _RGFW->keycodes[DOM_VK_F1] = RGFW_keyF1;
15091+ _RGFW->keycodes[DOM_VK_F2] = RGFW_keyF2;
15092+ _RGFW->keycodes[DOM_VK_F3] = RGFW_keyF3;
15093+ _RGFW->keycodes[DOM_VK_F4] = RGFW_keyF4;
15094+ _RGFW->keycodes[DOM_VK_F5] = RGFW_keyF5;
15095+ _RGFW->keycodes[DOM_VK_F6] = RGFW_keyF6;
15096+ _RGFW->keycodes[DOM_VK_F7] = RGFW_keyF7;
15097+ _RGFW->keycodes[DOM_VK_F8] = RGFW_keyF8;
15098+ _RGFW->keycodes[DOM_VK_F9] = RGFW_keyF9;
15099+ _RGFW->keycodes[DOM_VK_F10] = RGFW_keyF10;
15100+ _RGFW->keycodes[DOM_VK_F11] = RGFW_keyF11;
15101+ _RGFW->keycodes[DOM_VK_F12] = RGFW_keyF12;
15102+ _RGFW->keycodes[DOM_VK_UP] = RGFW_keyUp;
15103+ _RGFW->keycodes[DOM_VK_DOWN] = RGFW_keyDown;
15104+ _RGFW->keycodes[DOM_VK_LEFT] = RGFW_keyLeft;
15105+ _RGFW->keycodes[DOM_VK_RIGHT] = RGFW_keyRight;
15106+ _RGFW->keycodes[DOM_VK_INSERT] = RGFW_keyInsert;
15107+ _RGFW->keycodes[DOM_VK_END] = RGFW_keyEnd;
15108+ _RGFW->keycodes[DOM_VK_PAGE_UP] = RGFW_keyPageUp;
15109+ _RGFW->keycodes[DOM_VK_PAGE_DOWN] = RGFW_keyPageDown;
15110+ _RGFW->keycodes[DOM_VK_ESCAPE] = RGFW_keyEscape;
15111+ _RGFW->keycodes[DOM_VK_HOME] = RGFW_keyHome;
15112+ _RGFW->keycodes[DOM_VK_SCROLL_LOCK] = RGFW_keyScrollLock;
15113+ _RGFW->keycodes[DOM_VK_PRINTSCREEN] = RGFW_keyPrintScreen;
15114+ _RGFW->keycodes[DOM_VK_PAUSE] = RGFW_keyPause;
15115+ _RGFW->keycodes[DOM_VK_F13] = RGFW_keyF13;
15116+ _RGFW->keycodes[DOM_VK_F14] = RGFW_keyF14;
15117+ _RGFW->keycodes[DOM_VK_F15] = RGFW_keyF15;
15118+ _RGFW->keycodes[DOM_VK_F16] = RGFW_keyF16;
15119+ _RGFW->keycodes[DOM_VK_F17] = RGFW_keyF17;
15120+ _RGFW->keycodes[DOM_VK_F18] = RGFW_keyF18;
15121+ _RGFW->keycodes[DOM_VK_F19] = RGFW_keyF19;
15122+ _RGFW->keycodes[DOM_VK_F20] = RGFW_keyF20;
15123+ _RGFW->keycodes[DOM_VK_F21] = RGFW_keyF21;
15124+ _RGFW->keycodes[DOM_VK_F22] = RGFW_keyF22;
15125+ _RGFW->keycodes[DOM_VK_F23] = RGFW_keyF23;
15126+ _RGFW->keycodes[DOM_VK_F24] = RGFW_keyF24;
15127+}
15128+
15129+i32 RGFW_initPlatform(void) {
15130+ RGFW_monitorNode* node = NULL;
15131+ RGFW_monitor monitor;
15132+
15133+ monitor.name[0] = '\0';
15134+
15135+ monitor.x = 0;
15136+ monitor.y = 0;
15137+
15138+ monitor.pixelRatio = EM_ASM_DOUBLE({return window.devicePixelRatio || 1;});
15139+ monitor.mode.w = EM_ASM_INT({return window.innerWidth || 0;});
15140+ monitor.mode.h = EM_ASM_INT({return window.innerHeight || 0;});
15141+
15142+ monitor.physW = (float)RGFW_ROUND((float)monitor.mode.w * monitor.pixelRatio);
15143+ monitor.physH = (float)RGFW_ROUND((float)monitor.mode.h * monitor.pixelRatio);
15144+
15145+ float dpi = 96.0f * monitor.pixelRatio;
15146+ monitor.scaleX = dpi / 96.0f;
15147+ monitor.scaleY = dpi / 96.0f;
15148+
15149+ RGFW_splitBPP(32, &monitor.mode);
15150+
15151+ monitor.mode.refreshRate = 0;
15152+
15153+ node = RGFW_monitors_add(&monitor);
15154+ if (node != NULL) {
15155+ _RGFW->monitors.primary = node;
15156+ RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_TRUE);
15157+ }
15158+
15159+ return 0;
15160+}
15161+
15162+RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win) {
15163+ emscripten_set_canvas_element_size("#canvas", win->w, win->h);
15164+ emscripten_set_window_title(name);
15165+
15166+ /* load callbacks */
15167+ emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_resize);
15168+ emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, NULL, EM_FALSE, Emscripten_on_fullscreenchange);
15169+ emscripten_set_mousemove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousemove);
15170+ emscripten_set_touchstart_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchstart);
15171+ emscripten_set_touchend_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchend);
15172+ emscripten_set_touchmove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchmove);
15173+ emscripten_set_touchcancel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchcancel);
15174+ emscripten_set_mousedown_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousedown);
15175+ emscripten_set_mouseup_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mouseup);
15176+ emscripten_set_wheel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_wheel);
15177+ emscripten_set_focusin_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusin);
15178+ emscripten_set_focusout_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusout);
15179+
15180+ if (flags & RGFW_windowAllowDND) {
15181+ win->internal.flags |= RGFW_windowAllowDND;
15182+ }
15183+
15184+ EM_ASM({
15185+ window.addEventListener("keydown",
15186+ (event) => {
15187+ var code = stringToNewUTF8(event.code);
15188+ Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta"), event.getModifierState("ScrollLock"));
15189+
15190+ var codepoint = event.key.charCodeAt(0);
15191+ if(codepoint < 0x7f && event.key.length > 1) {
15192+ codepoint = 0;
15193+ }
15194+
15195+ Module._RGFW_handleKeyEvent(code, codepoint, 1);
15196+ _free(code);
15197+ },
15198+ true);
15199+ window.addEventListener("keyup",
15200+ (event) => {
15201+ var code = stringToNewUTF8(event.code);
15202+ Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta"), event.getModifierState("ScrollLock"));
15203+ Module._RGFW_handleKeyEvent(code, 0, 0);
15204+ _free(code);
15205+ },
15206+ true);
15207+ });
15208+
15209+ EM_ASM({
15210+ var canvas = document.getElementById('canvas');
15211+ canvas.addEventListener('drop', function(e) {
15212+ e.preventDefault();
15213+ if (e.dataTransfer.file < 0)
15214+ return;
15215+
15216+ var count = e.dataTransfer.files.length;
15217+
15218+ /* Read and save the files to emscripten's files */
15219+ var drop_dir = '.rgfw_dropped_files';
15220+ Module._RGFW_mkdir(drop_dir);
15221+
15222+ for (var i = 0; i < count; i++) {
15223+ var file = e.dataTransfer.files[i];
15224+
15225+ var path = '/' + drop_dir + '/' + file.name.replace("//", '_');
15226+ var reader = new FileReader();
15227+
15228+ reader.onloadend = (e) => {
15229+ if (reader.readyState != 2) {
15230+ out('failed to read dropped file: '+file.name+': '+reader.error);
15231+ }
15232+ else {
15233+ var data = e.target.result;
15234+
15235+ Module._RGFW_writeFile(path, new Uint8Array(data), file.size);
15236+ }
15237+ };
15238+
15239+ reader.readAsArrayBuffer(file);
15240+ var filename = stringToNewUTF8(path);
15241+
15242+ Module._Emscripten_onDrop(filename, path.length + 1);
15243+ free(filename);
15244+ }
15245+
15246+ }, true);
15247+
15248+ canvas.addEventListener('dragover', function(e) { e.preventDefault(); return false; }, true);
15249+ });
15250+
15251+ return win;
15252+}
15253+
15254+RGFW_key RGFW_physicalToMappedKey(RGFW_key key) {
15255+ return key;
15256+}
15257+
15258+RGFW_bool RGFW_window_fetchSize(RGFW_window* win, i32* w, i32* h) {
15259+ return RGFW_window_getSize(win, w, h);
15260+}
15261+
15262+void RGFW_pollEvents(void) {
15263+ RGFW_resetPrevState();
15264+ emscripten_sleep(0);
15265+}
15266+
15267+void RGFW_window_resize(RGFW_window* win, i32 w, i32 h) {
15268+ RGFW_UNUSED(win);
15269+ emscripten_set_canvas_element_size("#canvas", w, h);
15270+}
15271+
15272+RGFW_mouse* RGFW_createMouseStandard(RGFW_mouseIcon mouse) {
15273+ char* cursorName = NULL;
15274+
15275+ switch (mouse) {
15276+ case RGFW_mouseNormal: cursorName = (char*)"default"; break;
15277+ case RGFW_mouseArrow: cursorName = (char*)"default"; break;
15278+ case RGFW_mouseIbeam: cursorName = (char*)"text"; break;
15279+ case RGFW_mouseCrosshair: cursorName = (char*)"crosshair"; break;
15280+ case RGFW_mousePointingHand: cursorName = (char*)"pointer"; break;
15281+ case RGFW_mouseResizeEW: cursorName = (char*)"ew-resize"; break;
15282+ case RGFW_mouseResizeNS: cursorName = (char*)"ns-resize"; break;
15283+ case RGFW_mouseResizeNWSE: cursorName = (char*)"nwse-resize"; break;
15284+ case RGFW_mouseResizeNESW: cursorName = (char*)"nesw-resize"; break;
15285+ case RGFW_mouseResizeNW: cursorName = (char*)"nw-resize"; break;
15286+ case RGFW_mouseResizeN: cursorName = (char*)"n-resize"; break;
15287+ case RGFW_mouseResizeNE: cursorName = (char*)"ne-resize"; break;
15288+ case RGFW_mouseResizeE: cursorName = (char*)"e-resize"; break;
15289+ case RGFW_mouseResizeSE: cursorName = (char*)"se-resize"; break;
15290+ case RGFW_mouseResizeS: cursorName = (char*)"s-resize"; break;
15291+ case RGFW_mouseResizeSW: cursorName = (char*)"sw-resize"; break;
15292+ case RGFW_mouseResizeW: cursorName = (char*)"w-resize"; break;
15293+ case RGFW_mouseResizeAll: cursorName = (char*)"move"; break;
15294+ case RGFW_mouseNotAllowed: cursorName = (char*)"not-allowed"; break;
15295+ case RGFW_mouseWait: cursorName = (char*)"wait"; break;
15296+ case RGFW_mouseProgress: cursorName = (char*)"progress"; break;
15297+ default: return NULL;
15298+ }
15299+
15300+ return (RGFW_mouse*)cursorName;
15301+}
15302+
15303+/* NOTE: I don't know if this is possible */
15304+void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y) { RGFW_UNUSED(win); RGFW_UNUSED(x); RGFW_UNUSED(y); }
15305+/* this one might be possible but it looks iffy */
15306+RGFW_mouse* RGFW_createMouse(u8* data, i32 w, i32 h, RGFW_format format) { RGFW_UNUSED(data); RGFW_UNUSED(w); RGFW_UNUSED(h); RGFW_UNUSED(format); return NULL; }
15307+
15308+RGFW_bool RGFW_window_setMousePlatform(RGFW_window* win, RGFW_mouse* mouse) {
15309+ RGFW_ASSERT(win != NULL);
15310+ RGFW_ASSERT(mouse != NULL);
15311+
15312+ EM_ASM( { document.getElementById("canvas").style.cursor = UTF8ToString($0); }, (char*)mouse);
15313+ return RGFW_TRUE;
15314+}
15315+void RGFW_freeMouse(RGFW_mouse* mouse) { RGFW_UNUSED(mouse); }
15316+
15317+void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) {
15318+ RGFW_window_showMouseFlags(win, show);
15319+ if (show)
15320+ RGFW_window_setMouseDefault(win);
15321+ else
15322+ EM_ASM(document.getElementById('canvas').style.cursor = 'none';);
15323+}
15324+
15325+RGFW_bool RGFW_getGlobalMouse(i32* x, i32* y) {
15326+ if(x) *x = EM_ASM_INT({
15327+ return window.mouseX || 0;
15328+ });
15329+ if (y) *y = EM_ASM_INT({
15330+ return window.mouseY || 0;
15331+ });
15332+ return RGFW_TRUE;
15333+}
15334+
15335+void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) {
15336+ RGFW_UNUSED(win);
15337+
15338+ EM_ASM_({
15339+ var canvas = document.getElementById('canvas');
15340+ if ($0) {
15341+ canvas.style.pointerEvents = 'none';
15342+ } else {
15343+ canvas.style.pointerEvents = 'auto';
15344+ }
15345+ }, passthrough);
15346+}
15347+
15348+void RGFW_writeClipboard(const char* text, u32 textLen) {
15349+ RGFW_UNUSED(textLen);
15350+ EM_ASM({ navigator.clipboard.writeText(UTF8ToString($0)); }, text);
15351+}
15352+
15353+
15354+RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) {
15355+ RGFW_UNUSED(str); RGFW_UNUSED(strCapacity);
15356+ /*
15357+ placeholder code for later
15358+ I'm not sure if this is possible do the the async stuff
15359+ */
15360+ return 0;
15361+}
15362+
15363+#ifdef RGFW_OPENGL
15364+RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints) {
15365+ win->src.ctx.native = ctx;
15366+ win->src.gfxType = RGFW_gfxNativeOpenGL;
15367+
15368+ EmscriptenWebGLContextAttributes attrs;
15369+ emscripten_webgl_init_context_attributes(&attrs);
15370+ attrs.alpha = hints->alpha;
15371+ attrs.depth = hints->depth;
15372+ attrs.stencil = hints->stencil;
15373+ attrs.antialias = hints->samples;
15374+ attrs.premultipliedAlpha = EM_TRUE;
15375+ attrs.preserveDrawingBuffer = EM_FALSE;
15376+
15377+ if (hints->doubleBuffer == 0)
15378+ attrs.renderViaOffscreenBackBuffer = 0;
15379+ else
15380+ attrs.renderViaOffscreenBackBuffer = hints->auxBuffers;
15381+
15382+ attrs.failIfMajorPerformanceCaveat = EM_FALSE;
15383+
15384+ attrs.enableExtensionsByDefault = EM_TRUE;
15385+ attrs.explicitSwapControl = EM_TRUE;
15386+
15387+ if (hints->profile == RGFW_glWeb) {
15388+ attrs.majorVersion = (hints->major == 0) ? 1 : hints->major;
15389+ attrs.minorVersion = hints->minor;
15390+ } else {
15391+ attrs.majorVersion = (hints->major == 0) ? 1 : hints->major - 1;
15392+ attrs.minorVersion = hints->minor;
15393+ }
15394+
15395+ win->src.ctx.native->ctx = emscripten_webgl_create_context("#canvas", &attrs);
15396+ emscripten_webgl_make_context_current(win->src.ctx.native->ctx);
15397+
15398+ #ifdef LEGACY_GL_EMULATION
15399+ EM_ASM("Module.useWebGL = true; GLImmediate.init();");
15400+ RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized.");
15401+ #endif
15402+
15403+ RGFW_window_swapInterval_OpenGL(win, 0);
15404+
15405+ return RGFW_TRUE;
15406+}
15407+
15408+void RGFW_window_deleteContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx) {
15409+ emscripten_webgl_destroy_context(ctx->ctx);
15410+ win->src.ctx.native->ctx = 0;
15411+ RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context freed.");
15412+}
15413+
15414+void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win) {
15415+ if (win) RGFW_ASSERT(win->src.ctx.native);
15416+ if (win == NULL)
15417+ emscripten_webgl_make_context_current(0);
15418+ else
15419+ emscripten_webgl_make_context_current(win->src.ctx.native->ctx);
15420+}
15421+
15422+void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) {
15423+ RGFW_ASSERT(win && win->src.ctx.native);
15424+ emscripten_webgl_commit_frame();
15425+}
15426+void* RGFW_getCurrentContext_OpenGL(void) { return (void*)emscripten_webgl_get_current_context(); }
15427+
15428+RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char* extension, size_t len) {
15429+ return EM_ASM_INT({
15430+ var ext = UTF8ToString($0, $1);
15431+ var canvas = document.querySelector('canvas');
15432+ var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
15433+ if (!gl) return 0;
15434+
15435+ var supported = gl.getSupportedExtensions();
15436+ return supported && supported.includes(ext) ? 1 : 0;
15437+ }, extension, len);
15438+ return RGFW_FALSE;
15439+}
15440+
15441+RGFW_proc RGFW_getProcAddress_OpenGL(const char* procname) {
15442+ return (RGFW_proc)emscripten_webgl_get_proc_address(procname);
15443+ return NULL;
15444+}
15445+
15446+#endif
15447+
15448+void RGFW_window_swapInterval_OpenGL(RGFW_window* win, i32 swapInterval) { RGFW_UNUSED(win); RGFW_UNUSED(swapInterval); }
15449+
15450+void RGFW_deinitPlatform(void) { }
15451+
15452+void RGFW_window_closePlatform(RGFW_window* win) { }
15453+
15454+int RGFW_innerWidth(void) { return EM_ASM_INT({ return window.innerWidth; }); }
15455+int RGFW_innerHeight(void) { return EM_ASM_INT({ return window.innerHeight; }); }
15456+
15457+void RGFW_window_setRawMouseModePlatform(RGFW_window* win, RGFW_bool state) {
15458+ RGFW_UNUSED(win); RGFW_UNUSED(state);
15459+}
15460+
15461+void RGFW_window_captureMousePlatform(RGFW_window* win, RGFW_bool state) {
15462+ RGFW_UNUSED(win);
15463+ if (state) {
15464+ emscripten_request_pointerlock("#canvas", 1);
15465+ } else {
15466+ emscripten_exit_pointerlock();
15467+ }
15468+}
15469+
15470+void RGFW_window_setName(RGFW_window* win, const char* name) {
15471+ RGFW_UNUSED(win);
15472+ if (name == NULL) name = "\0";
15473+
15474+ emscripten_set_window_title(name);
15475+}
15476+
15477+void RGFW_window_maximize(RGFW_window* win) {
15478+ RGFW_ASSERT(win != NULL);
15479+
15480+ RGFW_monitor* mon = RGFW_window_getMonitor(win);
15481+ if (mon != NULL) {
15482+ RGFW_window_resize(win, mon->mode.w, mon->mode.h);
15483+ }
15484+
15485+ RGFW_window_move(win, 0, 0);
15486+ RGFW_window_fetchSize(win, NULL, NULL);
15487+}
15488+
15489+void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) {
15490+ RGFW_ASSERT(win != NULL);
15491+ if (fullscreen) {
15492+ win->internal.flags |= RGFW_windowFullscreen;
15493+ EM_ASM( Module.requestFullscreen(false, true); );
15494+ return;
15495+ }
15496+ win->internal.flags &= ~(u32)RGFW_windowFullscreen;
15497+ EM_ASM( Module.exitFullscreen(false, true); );
15498+}
15499+
15500+void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) {
15501+ RGFW_UNUSED(win);
15502+ EM_ASM({
15503+ var element = document.getElementById("canvas");
15504+ if (element)
15505+ element.style.opacity = $1;
15506+ }, "elementId", opacity);
15507+}
15508+
15509+#ifdef RGFW_WEBGPU
15510+WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance instance) {
15511+ WGPUSurfaceDescriptor surfaceDesc = {0};
15512+ WGPUEmscriptenSurfaceSourceCanvasHTMLSelector canvasDesc = {0};
15513+ canvasDesc.chain.sType = WGPUSType_EmscriptenSurfaceSourceCanvasHTMLSelector;
15514+ canvasDesc.selector = (WGPUStringView){.data = "#canvas", .length = 7};
15515+
15516+ surfaceDesc.nextInChain = &canvasDesc.chain;
15517+ return wgpuInstanceCreateSurface(instance, &surfaceDesc);
15518+}
15519+#endif
15520+
15521+RGFW_key RGFW_WASMPhysicalToRGFW(u32 hash) {
15522+ switch(hash) { /* 0x0000 */
15523+ case 0x67243A2DU /* Escape */: return RGFW_keyEscape; /* 0x0001 */
15524+ case 0x67251058U /* Digit0 */: return RGFW_key0; /* 0x0002 */
15525+ case 0x67251059U /* Digit1 */: return RGFW_key1; /* 0x0003 */
15526+ case 0x6725105AU /* Digit2 */: return RGFW_key2; /* 0x0004 */
15527+ case 0x6725105BU /* Digit3 */: return RGFW_key3; /* 0x0005 */
15528+ case 0x6725105CU /* Digit4 */: return RGFW_key4; /* 0x0006 */
15529+ case 0x6725105DU /* Digit5 */: return RGFW_key5; /* 0x0007 */
15530+ case 0x6725105EU /* Digit6 */: return RGFW_key6; /* 0x0008 */
15531+ case 0x6725105FU /* Digit7 */: return RGFW_key7; /* 0x0009 */
15532+ case 0x67251050U /* Digit8 */: return RGFW_key8; /* 0x000A */
15533+ case 0x67251051U /* Digit9 */: return RGFW_key9; /* 0x000B */
15534+ case 0x92E14DD3U /* Minus */: return RGFW_keyMinus; /* 0x000C */
15535+ case 0x92E1FBACU /* Equal */: return RGFW_keyEquals; /* 0x000D */
15536+ case 0x36BF1CB5U /* Backspace */: return RGFW_keyBackSpace; /* 0x000E */
15537+ case 0x7B8E51E2U /* Tab */: return RGFW_keyTab; /* 0x000F */
15538+ case 0x2C595B51U /* KeyQ */: return RGFW_keyQ; /* 0x0010 */
15539+ case 0x2C595B57U /* KeyW */: return RGFW_keyW; /* 0x0011 */
15540+ case 0x2C595B45U /* KeyE */: return RGFW_keyE; /* 0x0012 */
15541+ case 0x2C595B52U /* KeyR */: return RGFW_keyR; /* 0x0013 */
15542+ case 0x2C595B54U /* KeyT */: return RGFW_keyT; /* 0x0014 */
15543+ case 0x2C595B59U /* KeyY */: return RGFW_keyY; /* 0x0015 */
15544+ case 0x2C595B55U /* KeyU */: return RGFW_keyU; /* 0x0016 */
15545+ case 0x2C595B4FU /* KeyO */: return RGFW_keyO; /* 0x0018 */
15546+ case 0x2C595B50U /* KeyP */: return RGFW_keyP; /* 0x0019 */
15547+ case 0x45D8158CU /* BracketLeft */: return RGFW_keyCloseBracket; /* 0x001A */
15548+ case 0xDEEABF7CU /* BracketRight */: return RGFW_keyBracket; /* 0x001B */
15549+ case 0x92E1C5D2U /* Enter */: return RGFW_keyReturn; /* 0x001C */
15550+ case 0xE058958CU /* ControlLeft */: return RGFW_keyControlL; /* 0x001D */
15551+ case 0x2C595B41U /* KeyA */: return RGFW_keyA; /* 0x001E */
15552+ case 0x2C595B53U /* KeyS */: return RGFW_keyS; /* 0x001F */
15553+ case 0x2C595B44U /* KeyD */: return RGFW_keyD; /* 0x0020 */
15554+ case 0x2C595B46U /* KeyF */: return RGFW_keyF; /* 0x0021 */
15555+ case 0x2C595B47U /* KeyG */: return RGFW_keyG; /* 0x0022 */
15556+ case 0x2C595B48U /* KeyH */: return RGFW_keyH; /* 0x0023 */
15557+ case 0x2C595B4AU /* KeyJ */: return RGFW_keyJ; /* 0x0024 */
15558+ case 0x2C595B4BU /* KeyK */: return RGFW_keyK; /* 0x0025 */
15559+ case 0x2C595B4CU /* KeyL */: return RGFW_keyL; /* 0x0026 */
15560+ case 0x2707219EU /* Semicolon */: return RGFW_keySemicolon; /* 0x0027 */
15561+ case 0x92E0B58DU /* Quote */: return RGFW_keyApostrophe; /* 0x0028 */
15562+ case 0x36BF358DU /* Backquote */: return RGFW_keyBacktick; /* 0x0029 */
15563+ case 0x26B1958CU /* ShiftLeft */: return RGFW_keyShiftL; /* 0x002A */
15564+ case 0x36BF2438U /* Backslash */: return RGFW_keyBackSlash; /* 0x002B */
15565+ case 0x2C595B5AU /* KeyZ */: return RGFW_keyZ; /* 0x002C */
15566+ case 0x2C595B58U /* KeyX */: return RGFW_keyX; /* 0x002D */
15567+ case 0x2C595B43U /* KeyC */: return RGFW_keyC; /* 0x002E */
15568+ case 0x2C595B56U /* KeyV */: return RGFW_keyV; /* 0x002F */
15569+ case 0x2C595B42U /* KeyB */: return RGFW_keyB; /* 0x0030 */
15570+ case 0x2C595B4EU /* KeyN */: return RGFW_keyN; /* 0x0031 */
15571+ case 0x2C595B4DU /* KeyM */: return RGFW_keyM; /* 0x0032 */
15572+ case 0x92E1A1C1U /* Comma */: return RGFW_keyComma; /* 0x0033 */
15573+ case 0x672FFAD4U /* Period */: return RGFW_keyPeriod; /* 0x0034 */
15574+ case 0x92E0A438U /* Slash */: return RGFW_keySlash; /* 0x0035 */
15575+ case 0xC5A6BF7CU /* ShiftRight */: return RGFW_keyShiftR;
15576+ case 0x5D64DA91U /* NumpadMultiply */: return RGFW_keyPadMultiply;
15577+ case 0xC914958CU /* AltLeft */: return RGFW_keyAltL; /* 0x0038 */
15578+ case 0x92E09CB5U /* Space */: return RGFW_keySpace; /* 0x0039 */
15579+ case 0xB8FAE73BU /* CapsLock */: return RGFW_keyCapsLock; /* 0x003A */
15580+ case 0x7174B789U /* F1 */: return RGFW_keyF1; /* 0x003B */
15581+ case 0x7174B78AU /* F2 */: return RGFW_keyF2; /* 0x003C */
15582+ case 0x7174B78BU /* F3 */: return RGFW_keyF3; /* 0x003D */
15583+ case 0x7174B78CU /* F4 */: return RGFW_keyF4; /* 0x003E */
15584+ case 0x7174B78DU /* F5 */: return RGFW_keyF5; /* 0x003F */
15585+ case 0x7174B78EU /* F6 */: return RGFW_keyF6; /* 0x0040 */
15586+ case 0x7174B78FU /* F7 */: return RGFW_keyF7; /* 0x0041 */
15587+ case 0x7174B780U /* F8 */: return RGFW_keyF8; /* 0x0042 */
15588+ case 0x7174B781U /* F9 */: return RGFW_keyF9; /* 0x0043 */
15589+ case 0x7B8E57B0U /* F10 */: return RGFW_keyF10; /* 0x0044 */
15590+ case 0xC925FCDFU /* Numpad7 */: return RGFW_keyPadMultiply; /* 0x0047 */
15591+ case 0xC925FCD0U /* Numpad8 */: return RGFW_keyPad8; /* 0x0048 */
15592+ case 0xC925FCD1U /* Numpad9 */: return RGFW_keyPad9; /* 0x0049 */
15593+ case 0x5EA3E8A4U /* NumpadSubtract */: return RGFW_keyMinus; /* 0x004A */
15594+ case 0xC925FCDCU /* Numpad4 */: return RGFW_keyPad4; /* 0x004B */
15595+ case 0xC925FCDDU /* Numpad5 */: return RGFW_keyPad5; /* 0x004C */
15596+ case 0xC925FCDEU /* Numpad6 */: return RGFW_keyPad6; /* 0x004D */
15597+ case 0xC925FCD9U /* Numpad1 */: return RGFW_keyPad1; /* 0x004F */
15598+ case 0xC925FCDAU /* Numpad2 */: return RGFW_keyPad2; /* 0x0050 */
15599+ case 0xC925FCDBU /* Numpad3 */: return RGFW_keyPad3; /* 0x0051 */
15600+ case 0xC925FCD8U /* Numpad0 */: return RGFW_keyPad0; /* 0x0052 */
15601+ case 0x95852DACU /* NumpadDecimal */: return RGFW_keyPeriod; /* 0x0053 */
15602+ case 0x7B8E57B1U /* F11 */: return RGFW_keyF11; /* 0x0057 */
15603+ case 0x7B8E57B2U /* F12 */: return RGFW_keyF12; /* 0x0058 */
15604+ case 0x7B8E57B3U /* F13 */: return DOM_PK_F13; /* 0x0064 */
15605+ case 0x7B8E57B4U /* F14 */: return DOM_PK_F14; /* 0x0065 */
15606+ case 0x7B8E57B5U /* F15 */: return DOM_PK_F15; /* 0x0066 */
15607+ case 0x7B8E57B6U /* F16 */: return DOM_PK_F16; /* 0x0067 */
15608+ case 0x7B8E57B7U /* F17 */: return DOM_PK_F17; /* 0x0068 */
15609+ case 0x7B8E57B8U /* F18 */: return DOM_PK_F18; /* 0x0069 */
15610+ case 0x7B8E57B9U /* F19 */: return DOM_PK_F19; /* 0x006A */
15611+ case 0x7B8E57A8U /* F20 */: return DOM_PK_F20; /* 0x006B */
15612+ case 0x7B8E57A9U /* F21 */: return DOM_PK_F21; /* 0x006C */
15613+ case 0x7B8E57AAU /* F22 */: return DOM_PK_F22; /* 0x006D */
15614+ case 0x7B8E57ABU /* F23 */: return DOM_PK_F23; /* 0x006E */
15615+ case 0x7393FBACU /* NumpadEqual */: return RGFW_keyPadReturn;
15616+ case 0xB88EBF7CU /* AltRight */: return RGFW_keyAltR; /* 0xE038 */
15617+ case 0xC925873BU /* NumLock */: return RGFW_keyNumLock; /* 0xE045 */
15618+ case 0x2C595F45U /* Home */: return RGFW_keyHome; /* 0xE047 */
15619+ case 0xC91BB690U /* ArrowUp */: return RGFW_keyUp; /* 0xE048 */
15620+ case 0x672F9210U /* PageUp */: return RGFW_keyPageUp; /* 0xE049 */
15621+ case 0x3799258CU /* ArrowLeft */: return RGFW_keyLeft; /* 0xE04B */
15622+ case 0x4CE33F7CU /* ArrowRight */: return RGFW_keyRight; /* 0xE04D */
15623+ case 0x7B8E55DCU /* End */: return RGFW_keyEnd; /* 0xE04F */
15624+ case 0x3799379EU /* ArrowDown */: return RGFW_keyDown; /* 0xE050 */
15625+ case 0xBA90179EU /* PageDown */: return RGFW_keyPageDown; /* 0xE051 */
15626+ case 0x6723CB2CU /* Insert */: return RGFW_keyInsert; /* 0xE052 */
15627+ case 0x6725C50DU /* Delete */: return RGFW_keyDelete; /* 0xE053 */
15628+ case 0x6723658CU /* OSLeft */: return RGFW_keySuperL; /* 0xE05B */
15629+ case 0x39643F7CU /* MetaRight */: return RGFW_keySuperR; /* 0xE05C */
15630+ case 0x380B9C8CU /* NumpadAdd */: return DOM_PK_NUMPAD_ADD; /* 0x004E */
15631+ default: return DOM_PK_UNKNOWN;
15632+ }
15633+
15634+ return 0;
15635+}
15636+
15637+RGFW_monitor* RGFW_window_getMonitor(RGFW_window* win) {
15638+ RGFW_UNUSED(win);
15639+ return RGFW_getPrimaryMonitor();
15640+}
15641+
15642+/* unsupported functions */
15643+void RGFW_pollMonitors(void) { }
15644+void RGFW_window_focus(RGFW_window* win) { RGFW_UNUSED(win); }
15645+void RGFW_window_raise(RGFW_window* win) { RGFW_UNUSED(win); }
15646+RGFW_bool RGFW_monitor_requestMode(RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request) { RGFW_UNUSED(mon); RGFW_UNUSED(mode); RGFW_UNUSED(request); return RGFW_FALSE; }
15647+RGFW_bool RGFW_monitor_getWorkarea(RGFW_monitor* monitor, i32* x, i32* y, i32* width, i32* height) { RGFW_UNUSED(monitor); RGFW_UNUSED(x); RGFW_UNUSED(width); RGFW_UNUSED(height); return RGFW_FALSE; }
15648+size_t RGFW_monitor_getGammaRampPtr(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) { RGFW_UNUSED(monitor); RGFW_UNUSED(ramp); return 0; }
15649+RGFW_bool RGFW_monitor_setGammaRamp(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) { RGFW_UNUSED(monitor); RGFW_UNUSED(ramp); return RGFW_FALSE; }
15650+size_t RGFW_monitor_getModesPtr(RGFW_monitor* mon, RGFW_monitorMode** modes) { RGFW_UNUSED(mon); RGFW_UNUSED(modes); return 0; }
15651+RGFW_bool RGFW_monitor_setMode(RGFW_monitor* mon, RGFW_monitorMode* mode) { RGFW_UNUSED(mon); RGFW_UNUSED(mode); return RGFW_FALSE; }
15652+void RGFW_window_move(RGFW_window* win, i32 x, i32 y) { RGFW_UNUSED(win); RGFW_UNUSED(x); RGFW_UNUSED(y); }
15653+void RGFW_window_setAspectRatio(RGFW_window* win, i32 w, i32 h) { RGFW_UNUSED(win); RGFW_UNUSED(w); RGFW_UNUSED(h); }
15654+void RGFW_window_setMinSize(RGFW_window* win, i32 w, i32 h) { RGFW_UNUSED(win); RGFW_UNUSED(w); RGFW_UNUSED(h); }
15655+void RGFW_window_setMaxSize(RGFW_window* win, i32 w, i32 h) { RGFW_UNUSED(win); RGFW_UNUSED(w); RGFW_UNUSED(h); }
15656+void RGFW_window_minimize(RGFW_window* win) { RGFW_UNUSED(win); }
15657+void RGFW_window_restore(RGFW_window* win) { RGFW_UNUSED(win); }
15658+void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) { RGFW_UNUSED(win); RGFW_UNUSED(floating); }
15659+void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { RGFW_UNUSED(win); RGFW_UNUSED(border); }
15660+RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_icon type) { RGFW_UNUSED(win); RGFW_UNUSED(data); RGFW_UNUSED(w); RGFW_UNUSED(h); RGFW_UNUSED(format); RGFW_UNUSED(type); return RGFW_FALSE; }
15661+void RGFW_window_hide(RGFW_window* win) { RGFW_UNUSED(win); }
15662+void RGFW_window_show(RGFW_window* win) {RGFW_UNUSED(win); }
15663+void RGFW_window_flash(RGFW_window* win, RGFW_flashRequest request) { RGFW_UNUSED(win); RGFW_UNUSED(request); }
15664+RGFW_bool RGFW_window_isHidden(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; }
15665+RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; }
15666+RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; }
15667+RGFW_bool RGFW_window_isFloating(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; }
15668+void RGFW_waitForEvent(i32 waitMS) { RGFW_UNUSED(waitMS); }
15669+#endif
15670+
15671+/* end of web asm defines */
15672+
15673+/*
15674+ * RGFW function pointer backend, made to allow you to compile for Wayland but fallback to X11
15675+*/
15676+#ifdef RGFW_DYNAMIC
15677+typedef RGFW_window* (*RGFW_createWindowPlatform_ptr)(const char* name, RGFW_windowFlags flags, RGFW_window* win);
15678+typedef RGFW_bool (*RGFW_getMouse_ptr)(i32* x, i32* y);
15679+typedef RGFW_key (*RGFW_physicalToMappedKey_ptr)(RGFW_key key);
15680+typedef void (*RGFW_pollEvents_ptr)(void);
15681+typedef RGFW_bool (*RGFW_window_fetchSize_ptr)(RGFW_window* win, i32* w, i32* h);
15682+typedef void (*RGFW_pollMonitors_ptr)(void);
15683+typedef void (*RGFW_window_move_ptr)(RGFW_window* win, i32 x, i32 y);
15684+typedef void (*RGFW_window_resize_ptr)(RGFW_window* win, i32 w, i32 h);
15685+typedef void (*RGFW_window_setAspectRatio_ptr)(RGFW_window* win, i32 w, i32 h);
15686+typedef void (*RGFW_window_setMinSize_ptr)(RGFW_window* win, i32 w, i32 h);
15687+typedef void (*RGFW_window_setMaxSize_ptr)(RGFW_window* win, i32 w, i32 h);
15688+typedef void (*RGFW_window_maximize_ptr)(RGFW_window* win);
15689+typedef void (*RGFW_window_focus_ptr)(RGFW_window* win);
15690+typedef void (*RGFW_window_raise_ptr)(RGFW_window* win);
15691+typedef void (*RGFW_window_setFullscreen_ptr)(RGFW_window* win, RGFW_bool fullscreen);
15692+typedef void (*RGFW_window_setFloating_ptr)(RGFW_window* win, RGFW_bool floating);
15693+typedef void (*RGFW_window_setOpacity_ptr)(RGFW_window* win, u8 opacity);
15694+typedef void (*RGFW_window_minimize_ptr)(RGFW_window* win);
15695+typedef void (*RGFW_window_restore_ptr)(RGFW_window* win);
15696+typedef RGFW_bool (*RGFW_window_isFloating_ptr)(RGFW_window* win);
15697+typedef void (*RGFW_window_setName_ptr)(RGFW_window* win, const char* name);
15698+typedef void (*RGFW_window_setMousePassthrough_ptr)(RGFW_window* win, RGFW_bool passthrough);
15699+typedef RGFW_bool (*RGFW_window_setIconEx_ptr)(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, u8 type);
15700+typedef RGFW_mouse* (*RGFW_createMouse_ptr)(u8* data, i32 w, i32 h, RGFW_format format);
15701+typedef RGFW_mouse* (*RGFW_createMouseStandard_ptr)(RGFW_mouseIcon icons);
15702+typedef RGFW_bool (*RGFW_window_setMousePlatform_ptr)(RGFW_window* win, RGFW_mouse* mouse);
15703+typedef void (*RGFW_window_moveMouse_ptr)(RGFW_window* win, i32 x, i32 y);
15704+typedef void (*RGFW_window_hide_ptr)(RGFW_window* win);
15705+typedef void (*RGFW_window_show_ptr)(RGFW_window* win);
15706+typedef void (*RGFW_window_flash_ptr)(RGFW_window* win, RGFW_flashRequest request);
15707+typedef RGFW_ssize_t (*RGFW_readClipboardPtr_ptr)(char* str, size_t strCapacity);
15708+typedef void (*RGFW_writeClipboard_ptr)(const char* text, u32 textLen);
15709+typedef RGFW_bool (*RGFW_window_isHidden_ptr)(RGFW_window* win);
15710+typedef RGFW_bool (*RGFW_window_isMinimized_ptr)(RGFW_window* win);
15711+typedef RGFW_bool (*RGFW_window_isMaximized_ptr)(RGFW_window* win);
15712+typedef RGFW_bool (*RGFW_monitor_requestMode_ptr)(RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request);
15713+typedef RGFW_bool (*RGFW_monitor_getWorkarea_ptr)(RGFW_monitor* mon, i32* x, i32* y, i32* w, i32* h);
15714+typedef size_t (*RGFW_monitor_getModesPtr_ptr)(RGFW_monitor* mon, RGFW_monitorMode** modes);
15715+typedef size_t (*RGFW_monitor_getGammaRampPtr_ptr) (RGFW_monitor* monitor, RGFW_gammaRamp* ramp);
15716+typedef RGFW_bool (*RGFW_monitor_setGammaRamp_ptr) (RGFW_monitor* monitor, RGFW_gammaRamp* ramp);
15717+typedef RGFW_bool (*RGFW_monitor_setMode_ptr)(RGFW_monitor* mon, RGFW_monitorMode* mode);
15718+typedef RGFW_monitor* (*RGFW_window_getMonitor_ptr)(RGFW_window* win);
15719+typedef void (*RGFW_window_closePlatform_ptr)(RGFW_window* win);
15720+typedef RGFW_format (*RGFW_nativeFormat_ptr)(void);
15721+typedef RGFW_bool (*RGFW_createSurfacePtr_ptr)(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface);
15722+typedef void (*RGFW_window_blitSurface_ptr)(RGFW_window* win, RGFW_surface* surface);
15723+typedef void (*RGFW_surface_freePtr_ptr)(RGFW_surface* surface);
15724+typedef void (*RGFW_freeMouse_ptr)(RGFW_mouse* mouse);
15725+typedef void (*RGFW_window_setBorder_ptr)(RGFW_window* win, RGFW_bool border);
15726+typedef void (*RGFW_window_captureMousePlatform_ptr)(RGFW_window* win, RGFW_bool state);
15727+typedef void (*RGFW_window_setRawMouseModePlatform_ptr)(RGFW_window* win, RGFW_bool state);
15728+#ifdef RGFW_OPENGL
15729+typedef void (*RGFW_window_makeCurrentContext_OpenGL_ptr)(RGFW_window* win);
15730+typedef void* (*RGFW_getCurrentContext_OpenGL_ptr)(void);
15731+typedef void (*RGFW_window_swapBuffers_OpenGL_ptr)(RGFW_window* win);
15732+typedef void (*RGFW_window_swapInterval_OpenGL_ptr)(RGFW_window* win, i32 swapInterval);
15733+typedef RGFW_bool (*RGFW_extensionSupportedPlatform_OpenGL_ptr)(const char* extension, size_t len);
15734+typedef RGFW_proc (*RGFW_getProcAddress_OpenGL_ptr)(const char* procname);
15735+typedef RGFW_bool (*RGFW_window_createContextPtr_OpenGL_ptr)(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints);
15736+typedef void (*RGFW_window_deleteContextPtr_OpenGL_ptr)(RGFW_window* win, RGFW_glContext* ctx);
15737+#endif
15738+#ifdef RGFW_WEBGPU
15739+typedef WGPUSurface (*RGFW_window_createSurface_WebGPU_ptr)(RGFW_window* window, WGPUInstance instance);
15740+#endif
15741+
15742+/* Structure to hold all function pointers */
15743+typedef struct RGFW_FunctionPointers {
15744+ RGFW_nativeFormat_ptr nativeFormat;
15745+ RGFW_createSurfacePtr_ptr createSurfacePtr;
15746+ RGFW_window_blitSurface_ptr window_blitSurface;
15747+ RGFW_surface_freePtr_ptr surface_freePtr;
15748+ RGFW_freeMouse_ptr freeMouse;
15749+ RGFW_window_setBorder_ptr window_setBorder;
15750+ RGFW_window_captureMousePlatform_ptr window_captureMousePlatform;
15751+ RGFW_window_setRawMouseModePlatform_ptr window_setRawMouseModePlatform;
15752+ RGFW_createWindowPlatform_ptr createWindowPlatform;
15753+ RGFW_getMouse_ptr getGlobalMouse;
15754+ RGFW_physicalToMappedKey_ptr physicalToMappedKey;
15755+ RGFW_window_fetchSize_ptr window_fetchSize;
15756+ RGFW_pollEvents_ptr pollEvents;
15757+ RGFW_pollMonitors_ptr pollMonitors;
15758+ RGFW_window_move_ptr window_move;
15759+ RGFW_window_resize_ptr window_resize;
15760+ RGFW_window_setAspectRatio_ptr window_setAspectRatio;
15761+ RGFW_window_setMinSize_ptr window_setMinSize;
15762+ RGFW_window_setMaxSize_ptr window_setMaxSize;
15763+ RGFW_window_maximize_ptr window_maximize;
15764+ RGFW_window_focus_ptr window_focus;
15765+ RGFW_window_raise_ptr window_raise;
15766+ RGFW_window_setFullscreen_ptr window_setFullscreen;
15767+ RGFW_window_setFloating_ptr window_setFloating;
15768+ RGFW_window_setOpacity_ptr window_setOpacity;
15769+ RGFW_window_minimize_ptr window_minimize;
15770+ RGFW_window_restore_ptr window_restore;
15771+ RGFW_window_isFloating_ptr window_isFloating;
15772+ RGFW_window_setName_ptr window_setName;
15773+ RGFW_window_setMousePassthrough_ptr window_setMousePassthrough;
15774+ RGFW_window_setIconEx_ptr window_setIconEx;
15775+ RGFW_createMouse_ptr loadMouse;
15776+ RGFW_createMouseStandard_ptr loadMouseStandard;
15777+ RGFW_window_setMousePlatform_ptr window_setMousePlatform;
15778+ RGFW_window_moveMouse_ptr window_moveMouse;
15779+ RGFW_window_hide_ptr window_hide;
15780+ RGFW_window_show_ptr window_show;
15781+ RGFW_window_flash_ptr window_flash;
15782+ RGFW_readClipboardPtr_ptr readClipboardPtr;
15783+ RGFW_writeClipboard_ptr writeClipboard;
15784+ RGFW_window_isHidden_ptr window_isHidden;
15785+ RGFW_window_isMinimized_ptr window_isMinimized;
15786+ RGFW_window_isMaximized_ptr window_isMaximized;
15787+ RGFW_monitor_requestMode_ptr monitor_requestMode;
15788+ RGFW_monitor_getWorkarea_ptr monitor_getWorkarea;
15789+ RGFW_monitor_getModesPtr_ptr monitor_getModesPtr;
15790+ RGFW_monitor_getGammaRampPtr_ptr monitor_getGammaRampPtr;
15791+ RGFW_monitor_setGammaRamp_ptr monitor_setGammaRamp;
15792+ RGFW_monitor_setMode_ptr monitor_setMode;
15793+ RGFW_window_getMonitor_ptr window_getMonitor;
15794+ RGFW_window_closePlatform_ptr window_closePlatform;
15795+#ifdef RGFW_OPENGL
15796+ RGFW_extensionSupportedPlatform_OpenGL_ptr extensionSupportedPlatform_OpenGL;
15797+ RGFW_getProcAddress_OpenGL_ptr getProcAddress_OpenGL;
15798+ RGFW_window_createContextPtr_OpenGL_ptr window_createContextPtr_OpenGL;
15799+ RGFW_window_deleteContextPtr_OpenGL_ptr window_deleteContextPtr_OpenGL;
15800+ RGFW_window_makeCurrentContext_OpenGL_ptr window_makeCurrentContext_OpenGL;
15801+ RGFW_getCurrentContext_OpenGL_ptr getCurrentContext_OpenGL;
15802+ RGFW_window_swapBuffers_OpenGL_ptr window_swapBuffers_OpenGL;
15803+ RGFW_window_swapInterval_OpenGL_ptr window_swapInterval_OpenGL;
15804+#endif
15805+#ifdef RGFW_WEBGPU
15806+ RGFW_window_createSurface_WebGPU_ptr window_createSurface_WebGPU;
15807+#endif
15808+} RGFW_functionPointers;
15809+
15810+RGFW_functionPointers RGFW_api;
15811+
15812+RGFW_format RGFW_nativeFormat(void) { return RGFW_api.nativeFormat(); }
15813+RGFW_bool RGFW_createSurfacePtr(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) { return RGFW_api.createSurfacePtr(data, w, h, format, surface); }
15814+void RGFW_surface_freePtr(RGFW_surface* surface) { RGFW_api.surface_freePtr(surface); }
15815+void RGFW_freeMouse(RGFW_mouse* mouse) { RGFW_api.freeMouse(mouse); }
15816+void RGFW_window_blitSurface(RGFW_window* win, RGFW_surface* surface) { RGFW_api.window_blitSurface(win, surface); }
15817+void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { RGFW_api.window_setBorder(win, border); }
15818+void RGFW_window_captureMousePlatform(RGFW_window* win, RGFW_bool state) { RGFW_api.window_captureMousePlatform(win, state); }
15819+void RGFW_window_setRawMouseModePlatform(RGFW_window* win, RGFW_bool state) { RGFW_api.window_setRawMouseModePlatform(win, state); }
15820+RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win) { RGFW_init(); return RGFW_api.createWindowPlatform(name, flags, win); }
15821+RGFW_bool RGFW_getGlobalMouse(i32* x, i32* y) { return RGFW_api.getGlobalMouse(x, y); }
15822+RGFW_key RGFW_physicalToMappedKey(RGFW_key key) { return RGFW_api.physicalToMappedKey(key); }
15823+void RGFW_pollEvents(void) { RGFW_api.pollEvents(); }
15824+RGFW_bool RGFW_window_fetchSize(RGFW_window* win, i32* w, i32* h) { return RGFW_api.window_fetchSize(win, w, h); }
15825+void RGFW_pollMonitors(void) { RGFW_api.pollMonitors(); }
15826+void RGFW_window_move(RGFW_window* win, i32 x, i32 y) { RGFW_api.window_move(win, x, y); }
15827+void RGFW_window_resize(RGFW_window* win, i32 w, i32 h) { RGFW_api.window_resize(win, w, h); }
15828+void RGFW_window_setAspectRatio(RGFW_window* win, i32 w, i32 h) { RGFW_api.window_setAspectRatio(win, w, h); }
15829+void RGFW_window_setMinSize(RGFW_window* win, i32 w, i32 h) { RGFW_api.window_setMinSize(win, w, h); }
15830+void RGFW_window_setMaxSize(RGFW_window* win, i32 w, i32 h) { RGFW_api.window_setMaxSize(win, w, h); }
15831+void RGFW_window_maximize(RGFW_window* win) { RGFW_api.window_maximize(win); }
15832+void RGFW_window_focus(RGFW_window* win) { RGFW_api.window_focus(win); }
15833+void RGFW_window_raise(RGFW_window* win) { RGFW_api.window_raise(win); }
15834+void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) { RGFW_api.window_setFullscreen(win, fullscreen); }
15835+void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) { RGFW_api.window_setFloating(win, floating); }
15836+void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) { RGFW_api.window_setOpacity(win, opacity); }
15837+void RGFW_window_minimize(RGFW_window* win) { RGFW_api.window_minimize(win); }
15838+void RGFW_window_restore(RGFW_window* win) { RGFW_api.window_restore(win); }
15839+RGFW_bool RGFW_window_isFloating(RGFW_window* win) { return RGFW_api.window_isFloating(win); }
15840+void RGFW_window_setName(RGFW_window* win, const char* name) { RGFW_api.window_setName(win, name); }
15841+
15842+#ifndef RGFW_NO_PASSTHROUGH
15843+void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) { RGFW_api.window_setMousePassthrough(win, passthrough); }
15844+#endif
15845+
15846+RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, u8 type) { return RGFW_api.window_setIconEx(win, data, w, h, format, type); }
15847+RGFW_mouse* RGFW_createMouse(u8* data, i32 w, i32 h, RGFW_format format) { return RGFW_api.loadMouse(data, w, h, format); }
15848+RGFW_mouse* RGFW_createMouseStandard(RGFW_mouseIcon icon) { return RGFW_api.loadMouseStandard(icon); }
15849+RGFW_bool RGFW_window_setMousePlatform(RGFW_window* win, RGFW_mouse* mouse) { return RGFW_api.window_setMousePlatform(win, mouse); }
15850+void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y) { RGFW_api.window_moveMouse(win, x, y); }
15851+void RGFW_window_hide(RGFW_window* win) { RGFW_api.window_hide(win); }
15852+void RGFW_window_show(RGFW_window* win) { RGFW_api.window_show(win); }
15853+void RGFW_window_flash(RGFW_window* win, RGFW_flashRequest request) { RGFW_api.window_flash(win, request); }
15854+RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) { return RGFW_api.readClipboardPtr(str, strCapacity); }
15855+void RGFW_writeClipboard(const char* text, u32 textLen) { RGFW_api.writeClipboard(text, textLen); }
15856+RGFW_bool RGFW_window_isHidden(RGFW_window* win) { return RGFW_api.window_isHidden(win); }
15857+RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { return RGFW_api.window_isMinimized(win); }
15858+RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { return RGFW_api.window_isMaximized(win); }
15859+RGFW_bool RGFW_monitor_requestMode(RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request) { return RGFW_api.monitor_requestMode(mon, mode, request); }
15860+RGFW_bool RGFW_monitor_getWorkarea(RGFW_monitor* monitor, i32* x, i32* y, i32* width, i32* height) { return RGFW_api.monitor_getWorkarea(monitor, x, y, width, height); }
15861+size_t RGFW_monitor_getGammaRampPtr(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) { return RGFW_api.monitor_getGammaRampPtr(monitor, ramp); }
15862+RGFW_bool RGFW_monitor_setGammaRamp(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) { return RGFW_api.monitor_setGammaRamp(monitor, ramp); }
15863+size_t RGFW_monitor_getModesPtr(RGFW_monitor* mon, RGFW_monitorMode** modes) { return RGFW_api.monitor_getModesPtr(mon, modes); }
15864+RGFW_bool RGFW_monitor_setMode(RGFW_monitor* mon, RGFW_monitorMode* mode) { return RGFW_api.monitor_setMode(mon, mode); }
15865+RGFW_monitor* RGFW_window_getMonitor(RGFW_window* win) { return RGFW_api.window_getMonitor(win); }
15866+void RGFW_window_closePlatform(RGFW_window* win) { RGFW_api.window_closePlatform(win); }
15867+
15868+#ifdef RGFW_OPENGL
15869+RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char* extension, size_t len) { return RGFW_api.extensionSupportedPlatform_OpenGL(extension, len); }
15870+RGFW_proc RGFW_getProcAddress_OpenGL(const char* procname) { return RGFW_api.getProcAddress_OpenGL(procname); }
15871+RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints) { return RGFW_api.window_createContextPtr_OpenGL(win, ctx, hints); }
15872+void RGFW_window_deleteContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx) { RGFW_api.window_deleteContextPtr_OpenGL(win, ctx); }
15873+void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win) { RGFW_api.window_makeCurrentContext_OpenGL(win); }
15874+void* RGFW_getCurrentContext_OpenGL(void) { return RGFW_api.getCurrentContext_OpenGL(); }
15875+void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { RGFW_api.window_swapBuffers_OpenGL(win); }
15876+void RGFW_window_swapInterval_OpenGL(RGFW_window* win, i32 swapInterval) { RGFW_api.window_swapInterval_OpenGL(win, swapInterval); }
15877+#endif
15878+
15879+#ifdef RGFW_WEBGPU
15880+WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance instance) { return RGFW_api.window_createSurface_WebGPU(window, instance); }
15881+#endif
15882+#endif /* RGFW_DYNAMIC */
15883+
15884+/*
15885+ * start of X11 AND wayland defines
15886+ * this allows a single executable to support x11 AND wayland
15887+ * falling back to x11 if wayland fails to initalize
15888+*/
15889+#if defined(RGFW_WAYLAND) && defined(RGFW_X11)
15890+void RGFW_load_X11(void) {
15891+ RGFW_api.nativeFormat = RGFW_nativeFormat_X11;
15892+ RGFW_api.createSurfacePtr = RGFW_createSurfacePtr_X11;
15893+ RGFW_api.window_blitSurface = RGFW_window_blitSurface_X11;
15894+ RGFW_api.surface_freePtr = RGFW_surface_freePtr_X11;
15895+ RGFW_api.freeMouse = RGFW_freeMouse_X11;
15896+ RGFW_api.window_setBorder = RGFW_window_setBorder_X11;
15897+ RGFW_api.window_captureMousePlatform = RGFW_window_captureMousePlatform_X11;
15898+ RGFW_api.window_setRawMouseModePlatform = RGFW_window_setRawMouseModePlatform_X11;
15899+ RGFW_api.createWindowPlatform = RGFW_createWindowPlatform_X11;
15900+ RGFW_api.getGlobalMouse = RGFW_getGlobalMouse_X11;
15901+ RGFW_api.physicalToMappedKey = RGFW_physicalToMappedKey_X11;
15902+ RGFW_api.pollEvents = RGFW_pollEvents_X11;
15903+ RGFW_api.window_fetchSize = RGFW_window_fetchSize_X11;
15904+ RGFW_api.pollMonitors = RGFW_pollMonitors_X11;
15905+ RGFW_api.window_move = RGFW_window_move_X11;
15906+ RGFW_api.window_resize = RGFW_window_resize_X11;
15907+ RGFW_api.window_setAspectRatio = RGFW_window_setAspectRatio_X11;
15908+ RGFW_api.window_setMinSize = RGFW_window_setMinSize_X11;
15909+ RGFW_api.window_setMaxSize = RGFW_window_setMaxSize_X11;
15910+ RGFW_api.window_maximize = RGFW_window_maximize_X11;
15911+ RGFW_api.window_focus = RGFW_window_focus_X11;
15912+ RGFW_api.window_raise = RGFW_window_raise_X11;
15913+ RGFW_api.window_setFullscreen = RGFW_window_setFullscreen_X11;
15914+ RGFW_api.window_setFloating = RGFW_window_setFloating_X11;
15915+ RGFW_api.window_setOpacity = RGFW_window_setOpacity_X11;
15916+ RGFW_api.window_minimize = RGFW_window_minimize_X11;
15917+ RGFW_api.window_restore = RGFW_window_restore_X11;
15918+ RGFW_api.window_isFloating = RGFW_window_isFloating_X11;
15919+ RGFW_api.window_setName = RGFW_window_setName_X11;
15920+#ifndef RGFW_NO_PASSTHROUGH
15921+ RGFW_api.window_setMousePassthrough = RGFW_window_setMousePassthrough_X11;
15922+#endif
15923+ RGFW_api.window_setIconEx = RGFW_window_setIconEx_X11;
15924+ RGFW_api.loadMouse = RGFW_createMouse_X11;
15925+ RGFW_api.window_setMousePlatform = RGFW_window_setMousePlatform_X11;
15926+ RGFW_api.window_moveMouse = RGFW_window_moveMouse_X11;
15927+ RGFW_api.window_hide = RGFW_window_hide_X11;
15928+ RGFW_api.window_show = RGFW_window_show_X11;
15929+ RGFW_api.window_flash = RGFW_window_flash_X11;
15930+ RGFW_api.readClipboardPtr = RGFW_readClipboardPtr_X11;
15931+ RGFW_api.writeClipboard = RGFW_writeClipboard_X11;
15932+ RGFW_api.window_isHidden = RGFW_window_isHidden_X11;
15933+ RGFW_api.window_isMinimized = RGFW_window_isMinimized_X11;
15934+ RGFW_api.window_isMaximized = RGFW_window_isMaximized_X11;
15935+ RGFW_api.monitor_requestMode = RGFW_monitor_requestMode_X11;
15936+ RGFW_api.monitor_getModesPtr = RGFW_monitor_getModesPtr_X11;
15937+ RGFW_api.monitor_setGammaRamp = RGFW_monitor_setGammaRamp_X11;
15938+ RGFW_api.monitor_getGammaRampPtr = RGFW_monitor_getGammaRampPtr_X11;
15939+ RGFW_api.monitor_setMode = RGFW_monitor_setMode_X11;
15940+ RGFW_api.window_getMonitor = RGFW_window_getMonitor_X11;
15941+ RGFW_api.window_closePlatform = RGFW_window_closePlatform_X11;
15942+#ifdef RGFW_OPENGL
15943+ RGFW_api.extensionSupportedPlatform_OpenGL = RGFW_extensionSupportedPlatform_OpenGL_X11;
15944+ RGFW_api.getProcAddress_OpenGL = RGFW_getProcAddress_OpenGL_X11;
15945+ RGFW_api.window_createContextPtr_OpenGL = RGFW_window_createContextPtr_OpenGL_X11;
15946+ RGFW_api.window_deleteContextPtr_OpenGL = RGFW_window_deleteContextPtr_OpenGL_X11;
15947+ RGFW_api.window_makeCurrentContext_OpenGL = RGFW_window_makeCurrentContext_OpenGL_X11;
15948+ RGFW_api.getCurrentContext_OpenGL = RGFW_getCurrentContext_OpenGL_X11;
15949+ RGFW_api.window_swapBuffers_OpenGL = RGFW_window_swapBuffers_OpenGL_X11;
15950+ RGFW_api.window_swapInterval_OpenGL = RGFW_window_swapInterval_OpenGL_X11;
15951+#endif
15952+#ifdef RGFW_WEBGPU
15953+ RGFW_api.window_createSurface_WebGPU = RGFW_window_createSurface_WebGPU_X11;
15954+#endif
15955+}
15956+
15957+void RGFW_load_Wayland(void) {
15958+ RGFW_api.nativeFormat = RGFW_nativeFormat_Wayland;
15959+ RGFW_api.createSurfacePtr = RGFW_createSurfacePtr_Wayland;
15960+ RGFW_api.window_blitSurface = RGFW_window_blitSurface_Wayland;
15961+ RGFW_api.surface_freePtr = RGFW_surface_freePtr_Wayland;
15962+ RGFW_api.freeMouse = RGFW_freeMouse_Wayland;
15963+ RGFW_api.window_setBorder = RGFW_window_setBorder_Wayland;
15964+ RGFW_api.window_captureMousePlatform = RGFW_window_captureMousePlatform_Wayland;
15965+ RGFW_api.window_setRawMouseModePlatform = RGFW_window_setRawMouseModePlatform_Wayland;
15966+ RGFW_api.createWindowPlatform = RGFW_createWindowPlatform_Wayland;
15967+ RGFW_api.getGlobalMouse = RGFW_getGlobalMouse_Wayland;
15968+ RGFW_api.physicalToMappedKey = RGFW_physicalToMappedKey_Wayland;
15969+ RGFW_api.pollEvents = RGFW_pollEvents_Wayland;
15970+ RGFW_api.window_fetchSize = RGFW_window_fetchSize_Wayland;
15971+ RGFW_api.pollMonitors = RGFW_pollMonitors_Wayland;
15972+ RGFW_api.window_move = RGFW_window_move_Wayland;
15973+ RGFW_api.window_resize = RGFW_window_resize_Wayland;
15974+ RGFW_api.window_setAspectRatio = RGFW_window_setAspectRatio_Wayland;
15975+ RGFW_api.window_setMinSize = RGFW_window_setMinSize_Wayland;
15976+ RGFW_api.window_setMaxSize = RGFW_window_setMaxSize_Wayland;
15977+ RGFW_api.window_maximize = RGFW_window_maximize_Wayland;
15978+ RGFW_api.window_focus = RGFW_window_focus_Wayland;
15979+ RGFW_api.window_raise = RGFW_window_raise_Wayland;
15980+ RGFW_api.window_setFullscreen = RGFW_window_setFullscreen_Wayland;
15981+ RGFW_api.window_setFloating = RGFW_window_setFloating_Wayland;
15982+ RGFW_api.window_setOpacity = RGFW_window_setOpacity_Wayland;
15983+ RGFW_api.window_minimize = RGFW_window_minimize_Wayland;
15984+ RGFW_api.window_restore = RGFW_window_restore_Wayland;
15985+ RGFW_api.window_isFloating = RGFW_window_isFloating_Wayland;
15986+ RGFW_api.window_setName = RGFW_window_setName_Wayland;
15987+#ifndef RGFW_NO_PASSTHROUGH
15988+ RGFW_api.window_setMousePassthrough = RGFW_window_setMousePassthrough_Wayland;
15989+#endif
15990+ RGFW_api.window_setIconEx = RGFW_window_setIconEx_Wayland;
15991+ RGFW_api.loadMouse = RGFW_createMouse_Wayland;
15992+ RGFW_api.window_setMousePlatform = RGFW_window_setMousePlatform_Wayland;
15993+ RGFW_api.window_moveMouse = RGFW_window_moveMouse_Wayland;
15994+ RGFW_api.window_hide = RGFW_window_hide_Wayland;
15995+ RGFW_api.window_show = RGFW_window_show_Wayland;
15996+ RGFW_api.window_flash = RGFW_window_flash_X11;
15997+ RGFW_api.readClipboardPtr = RGFW_readClipboardPtr_Wayland;
15998+ RGFW_api.writeClipboard = RGFW_writeClipboard_Wayland;
15999+ RGFW_api.window_isHidden = RGFW_window_isHidden_Wayland;
16000+ RGFW_api.window_isMinimized = RGFW_window_isMinimized_Wayland;
16001+ RGFW_api.window_isMaximized = RGFW_window_isMaximized_Wayland;
16002+ RGFW_api.monitor_requestMode = RGFW_monitor_requestMode_Wayland;
16003+ RGFW_api.monitor_getModesPtr = RGFW_monitor_getModesPtr_Wayland;
16004+ RGFW_api.monitor_setGammaRamp = RGFW_monitor_setGammaRamp_Wayland;
16005+ RGFW_api.monitor_getGammaRampPtr = RGFW_monitor_getGammaRampPtr_Wayland;
16006+ RGFW_api.monitor_setMode = RGFW_monitor_setMode_Wayland;
16007+ RGFW_api.window_getMonitor = RGFW_window_getMonitor_Wayland;
16008+ RGFW_api.window_closePlatform = RGFW_window_closePlatform_Wayland;
16009+#ifdef RGFW_OPENGL
16010+ RGFW_api.extensionSupportedPlatform_OpenGL = RGFW_extensionSupportedPlatform_OpenGL_Wayland;
16011+ RGFW_api.getProcAddress_OpenGL = RGFW_getProcAddress_OpenGL_Wayland;
16012+ RGFW_api.window_createContextPtr_OpenGL = RGFW_window_createContextPtr_OpenGL_Wayland;
16013+ RGFW_api.window_deleteContextPtr_OpenGL = RGFW_window_deleteContextPtr_OpenGL_Wayland;
16014+ RGFW_api.window_makeCurrentContext_OpenGL = RGFW_window_makeCurrentContext_OpenGL_Wayland;
16015+ RGFW_api.getCurrentContext_OpenGL = RGFW_getCurrentContext_OpenGL_Wayland;
16016+ RGFW_api.window_swapBuffers_OpenGL = RGFW_window_swapBuffers_OpenGL_Wayland;
16017+ RGFW_api.window_swapInterval_OpenGL = RGFW_window_swapInterval_OpenGL_Wayland;
16018+#endif
16019+#ifdef RGFW_WEBGPU
16020+ RGFW_api.window_createSurface_WebGPU = RGFW_window_createSurface_WebGPU_Wayland;
16021+#endif
16022+}
16023+#endif /* wayland AND x11 */
16024+/* end of X11 AND wayland defines */
16025+
16026+#endif /* RGFW_IMPLEMENTATION */
16027+
16028+#if defined(__cplusplus) && !defined(__EMSCRIPTEN__)
16029+}
16030+#endif
16031+
16032+#if _MSC_VER
16033+ #pragma warning( pop )
16034+#endif
16035+