Logo

index : raylib-jai

---

  • summary
  • about
  • tree
  • log
  • branches
<< path: root/public/raylib-jai.git/html/Raylib/raylib/src/external/RGFW/RGFW.h blob: 427db016855ba11be2d81a6e2c1952d62df4b688 [raw] [clear marker]

        
0/*
1*
2* RGFW 2.0.0-dev
3
4* Copyright (C) 2022-26 Riley Mabb (@ColleagueRiley)
5*
6* libpng license
7*
8* This software is provided 'as-is', without any express or implied
9* warranty. In no event will the authors be held liable for any damages
10* arising from the use of this software.
11
12* Permission is granted to anyone to use this software for any purpose,
13* including commercial applications, and to alter it and redistribute it
14* freely, subject to the following restrictions:
15*
16* 1. The origin of this software must not be misrepresented; you must not
17* claim that you wrote the original software. If you use this software
18* in a product, an acknowledgment in the product documentation would be
19* appreciated but is not required.
20* 2. Altered source versions must be plainly marked as such, and must not be
21* misrepresented as being the original software.
22* 3. This notice may not be removed or altered from any source distribution.
23*
24*
25*/
26
27/*
28 (MAKE SURE RGFW_IMPLEMENTATION is in exactly one header or you use -D RGFW_IMPLEMENTATION)
29 #define RGFW_IMPLEMENTATION - makes it so source code is included with header
30*/
31
32/*
33 #define RGFW_IMPLEMENTATION - (required) makes it so the source code is included
34 #define RGFW_DEBUG - (optional) makes it so RGFW prints debug messages and errors when they're found
35 #define RGFW_EGL - (optional) compile with OpenGL functions, allowing you to use to use EGL instead of the native OpenGL functions
36 #define RGFW_DIRECTX - (optional) include integration directX functions (windows only)
37 #define RGFW_VULKAN - (optional) include helpful vulkan integration functions and macros
38 #define RGFW_WEBGPU - (optional) use WebGPU for rendering
39 #define RGFW_NATIVE - (optional) define native RGFW types that use native API structures
40
41 #define RGFW_X11 (optional) (unix only) if X11 should be used. This option is turned on by default by unix systems except for MacOS
42 #define RGFW_WAYLAND (optional) (unix only) use Wayland. (This can be used with X11)
43 #define RGFW_NO_X11 (optional) (unix only) don't fallback to X11 when using Wayland
44 #define RGFW_NO_LOAD_WGL (optional) (windows only) if WGL should be loaded dynamically during runtime
45 #define RGFW_NO_X11_CURSOR (optional) (unix only) don't use XCursor
46 #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)
47 #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)
48 #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)
49 #define RGFW_NO_WINMM (optional) (windows only) don't use winmm
50 #define RGFW_NO_IOKIT (optional) (macOS) don't use IOKit
51 #define RGFW_NO_UNIX_CLOCK (optional) (unix) don't link unix clock functions
52 #define RGFW_NO_DWM (windows only) - do not use or link dwmapi
53 #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)
54 #define RGFW_COCOA_GRAPHICS_SWITCHING - (optional) (cocoa) use automatic graphics switching (allow the system to choose to use GPU or iGPU)
55 #define RGFW_COCOA_FRAME_NAME (optional) (cocoa) set frame name
56 #define RGFW_NO_DPI - do not calculate DPI and don't use libShcore (win32)
57 #define RGFW_NO_XRANDR - do use XRandr (X11)
58 #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)
59 #define RGFW_NO_INFO - do not define the RGFW_info struct (without RGFW_IMPLEMENTATION)
60 #define RGFW_NO_GLXWINDOW - do not use GLXWindow
61
62 #define RGFW_ALLOC x - choose the default allocation function (defaults to standard malloc)
63 #define RGFW_FREE x - choose the default deallocation function (defaults to standard free)
64 #define RGFW_USERPTR x - choose the default userptr sent to the malloc call, (NULL by default)
65
66 #define RGFW_EXPORT - use when building RGFW
67 #define RGFW_IMPORT - use when linking with RGFW (not as a single-header)
68
69 #define RGFW_USE_INT - force the use c-types rather than stdint.h (for systems that might not have stdint.h (msvc))
70 #define RGFW_bool x - choose what type to use for bool, by default u32 is used
71*/
72
73/*
74Example to get you started :
75
76linux : gcc main.c -lX11 -lXrandr -lGL
77windows : gcc main.c -lopengl32 -lgdi32
78macos : gcc main.c -framework Cocoa -framework CoreVideo -framework OpenGL -framework IOKit
79
80#define RGFW_IMPLEMENTATION
81#include "RGFW.h"
82
83u8 icon[4 * 3 * 3] = {0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF};
84
85int main() {
86 RGFW_window* win = RGFW_createWindow("name", 100, 100, 500, 500, (u64)0);
87 RGFW_event event;
88
89 RGFW_window_setExitKey(win, RGFW_escape);
90 RGFW_window_setIcon(win, icon, 3, 3, RGFW_formatRGBA8);
91
92 while (RGFW_window_shouldClose(win) == RGFW_FALSE) {
93 while (RGFW_window_checkEvent(win, &event)) {
94 if (event.type == RGFW_quit)
95 break;
96 }
97 }
98
99 RGFW_window_close(win);
100}
101
102 compiling :
103
104 if you wish to compile the library all you have to do is create a new file with this in it
105
106 rgfw.c
107 #define RGFW_IMPLEMENTATION
108 #include "RGFW.h"
109
110 You may also want to add
111 `#define RGFW_EXPORT` when compiling and
112 `#define RGFW_IMPORT`when linking RGFW on it's own:
113 this reduces inline functions and prevents bloat in the object file
114
115 then you can use gcc (or whatever compile you wish to use) to compile the library into object file
116
117 ex. gcc -c RGFW.c -fPIC
118
119 after you compile the library into an object file, you can also turn the object file into an static or shared library
120
121 (commands ar and gcc can be replaced with whatever equivalent your system uses)
122
123 static : ar rcs RGFW.a RGFW.o
124 shared :
125 windows:
126 gcc -shared RGFW.o -lopengl32 -lgdi32 -o RGFW.dll
127 linux:
128 gcc -shared RGFW.o -lX11 -lGL -lXrandr -o RGFW.so
129 macos:
130 gcc -shared RGFW.o -framework CoreVideo -framework Cocoa -framework OpenGL -framework IOKit
131*/
132
133
134
135/*
136 Credits :
137 EimaMei/Sacode : Code review, helped with X11, MacOS and Windows support, Silicon, siliapp.h -> referencing
138
139 stb : This project is heavily inspired by the stb single header files
140
141 SDL, GLFW and other online resources : reference implementations
142
143 contributors : (feel free to put yourself here if you contribute)
144 krisvers (@krisvers) -> code review
145 EimaMei (@SaCode) -> code review
146 Nycticebus (@Code-Nycticebus) -> bug fixes
147 Rob Rohan (@robrohan) -> X11 bugs and missing features, MacOS/Cocoa fixing memory issues/bugs
148 AICDG (@THISISAGOODNAME) -> vulkan support (example)
149 @Easymode -> support, testing/debugging, bug fixes and reviews
150 Joshua Rowe (omnisci3nce) - bug fix, review (macOS)
151 @lesleyrs -> bug fix, review (OpenGL)
152 Nick Porcino (@meshula) - testing, organization, review (MacOS, examples)
153 @therealmarrakesh -> documentation
154 @DarekParodia -> code review (X11) (C++)
155 @NishiOwO -> fix BSD support, fix OSMesa example
156 @BaynariKattu -> code review and documentation
157 Miguel Pinto (@konopimi) -> code review, fix vulkan example
158 @m-doescode -> code review (wayland)
159 Robert Gonzalez (@uni-dos) -> code review (wayland)
160 @TheLastVoyager -> code review
161 @yehoravramenko -> code review (winapi)
162 @halocupcake -> code review (OpenGL)
163 @GideonSerf -> documentation
164 Alexandre Almeida (@M374LX) -> code review (keycodes)
165 Vũ Xuân Trường (@wanwanvxt) -> code review (winapi)
166 Lucas (@lightspeedlucas) -> code review (msvc++)
167 Jeffery Myers (@JeffM2501) -> code review (msvc)
168 Zeni (@zenitsuyo) -> documentation
169 TheYahton (@TheYahton) -> documentation
170 nonexistant_object (@DiarrheaMcgee)
171 AC Gaudette (@acgaudette)
172*/
173
174#if _MSC_VER
175 #pragma comment(lib, "gdi32")
176 #pragma comment(lib, "shell32")
177 #pragma comment(lib, "User32")
178 #pragma comment(lib, "Advapi32")
179 #pragma warning( push )
180 #pragma warning( disable : 4996 4191 4127)
181 #if _MSC_VER < 600
182 #define RGFW_C89
183 #endif
184#else
185 #if defined(__STDC__) && !defined(__STDC_VERSION__)
186 #define RGFW_C89
187 #endif
188#endif
189
190#if defined(RGFW_EGL) && !defined(RGFW_OPENGL)
191 #define RGFW_OPENGL
192#endif
193
194/* these OS macros look better & are standardized */
195/* plus it helps with cross-compiling */
196
197#ifdef __EMSCRIPTEN__
198 #define RGFW_WASM
199#endif
200
201#if defined(RGFW_X11) && defined(__APPLE__) && !defined(RGFW_CUSTOM_BACKEND)
202 #define RGFW_MACOS_X11
203 #define RGFW_UNIX
204#endif
205
206#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) */
207 #define RGFW_WINDOWS
208#endif
209#if defined(RGFW_WAYLAND)
210 #define RGFW_DEBUG /* wayland will be in debug mode by default for now */
211 #define RGFW_UNIX
212 #ifdef RGFW_OPENGL
213 #define RGFW_EGL
214 #endif
215 #ifdef RGFW_X11
216 #define RGFW_DYNAMIC
217 #endif
218#endif
219#if (!defined(RGFW_WAYLAND) && !defined(RGFW_X11)) && (defined(__unix__) || defined(RGFW_MACOS_X11) || defined(RGFW_X11)) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND)
220 #define RGFW_MACOS_X11
221 #define RGFW_X11
222 #define RGFW_UNIX
223#elif defined(__APPLE__) && !defined(RGFW_MACOS_X11) && !defined(RGFW_X11) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND)
224 #define RGFW_MACOS
225#endif
226
227#ifndef RGFW_ASSERT
228 #include <assert.h>
229 #define RGFW_ASSERT assert
230#endif
231
232#if !defined(__STDC_VERSION__)
233 #define RGFW_C89
234#endif
235
236#if !defined(RGFW_SNPRINTF) && (defined(RGFW_X11) || defined(RGFW_WAYLAND))
237
238 /* required for X11 errors */
239 #include <stdio.h>
240
241 #ifdef RGFW_C89
242 #include <stdarg.h>
243 static int RGFW_c89_snprintf(char *dst, size_t size, const char *format, ...) {
244 va_list args;
245 size_t count = 0;
246 va_start(args, format);
247 count = (size_t)vsprintf(dst, format, args);
248 RGFW_ASSERT(count + 1 < size && "Buffer overflow");
249 va_end(args);
250 return (int)count;
251 }
252 #define RGFW_SNPRINTF RGFW_c89_snprintf
253 #else
254 #define RGFW_SNPRINTF snprintf
255 #endif /*RGFW_C89*/
256#endif
257
258#ifndef RGFW_USERPTR
259 #define RGFW_USERPTR NULL
260#endif
261
262#ifndef RGFW_UNUSED
263 #define RGFW_UNUSED(x) (void)(x)
264#endif
265
266#ifndef RGFW_ROUND
267 #define RGFW_ROUND(x) (i32)((x) >= 0 ? (x) + 0.5f : (x) - 0.5f)
268#endif
269
270#ifndef RGFW_ROUNDF
271 #define RGFW_ROUNDF(x) (float)((i32)((x) + ((x) < 0.0f ? -0.5f : 0.5f)))
272#endif
273
274#ifndef RGFW_MIN
275 #define RGFW_MIN(x, y) ((x < y) ? x : y)
276#endif
277
278#ifndef RGFW_ALLOC
279 #include <stdlib.h>
280 #define RGFW_ALLOC malloc
281 #define RGFW_FREE free
282#endif
283
284#if !defined(RGFW_MEMCPY) || !defined(RGFW_STRNCMP) || !defined(RGFW_STRNCPY) || !defined(RGFW_MEMSET)
285 #include <string.h>
286#endif
287
288#ifndef RGFW_MEMSET
289 #define RGFW_MEMSET(ptr, value, num) memset(ptr, value, num)
290#endif
291
292#ifndef RGFW_MEMCPY
293 #define RGFW_MEMCPY(dist, src, len) memcpy(dist, src, len)
294#endif
295
296#ifndef RGFW_STRNCMP
297 #define RGFW_STRNCMP(s1, s2, max) strncmp(s1, s2, max)
298#endif
299
300#ifndef RGFW_STRNCPY
301 #define RGFW_STRNCPY(dist, src, len) strncpy(dist, src, len)
302#endif
303
304#ifndef RGFW_STRSTR
305 #define RGFW_STRSTR(str, substr) strstr(str, substr)
306#endif
307
308#ifndef RGFW_STRTOL
309 /* required for X11 XDnD and X11 Monitor DPI */
310 #include <stdlib.h>
311 #define RGFW_STRTOL(str, endptr, base) strtol(str, endptr, base)
312 #define RGFW_ATOF(num) atof(num)
313#endif
314
315#if !defined(RGFW_PRINTF) && ( defined(RGFW_DEBUG) || defined(RGFW_WAYLAND) )
316 /* required when using RGFW_DEBUG */
317 #include <stdio.h>
318 #define RGFW_PRINTF printf
319#endif
320
321#ifndef RGFW_MAX_PATH
322 #define RGFW_MAX_PATH 260 /* max length of a path (for drag andn drop) */
323#endif
324#ifndef RGFW_MAX_DROPS
325 #define RGFW_MAX_DROPS 260 /* max items you can drop at once */
326#endif
327
328#ifndef RGFW_MAX_EVENTS
329 #define RGFW_MAX_EVENTS 32
330#endif
331
332#ifndef RGFW_MAX_MONITORS
333 #define RGFW_MAX_MONITORS 6
334#endif
335
336#ifndef RGFW_COCOA_FRAME_NAME
337 #define RGFW_COCOA_FRAME_NAME NULL
338#endif
339
340#ifdef RGFW_WIN95 /* for windows 95 testing (not that it really works) */
341 #define RGFW_NO_PASSTHROUGH
342#endif
343
344#if defined(RGFW_EXPORT) || defined(RGFW_IMPORT)
345 #if defined(_WIN32)
346 #if defined(__TINYC__) && (defined(RGFW_EXPORT) || defined(RGFW_IMPORT))
347 #define __declspec(x) __attribute__((x))
348 #endif
349
350 #if defined(RGFW_EXPORT)
351 #define RGFWDEF __declspec(dllexport)
352 #else
353 #define RGFWDEF __declspec(dllimport)
354 #endif
355 #else
356 #if defined(RGFW_EXPORT)
357 #define RGFWDEF __attribute__((visibility("default")))
358 #endif
359 #endif
360 #ifndef RGFWDEF
361 #define RGFWDEF
362 #endif
363#endif
364
365#ifndef RGFWDEF
366 #ifdef RGFW_C89
367 #define RGFWDEF __inline
368 #else
369 #define RGFWDEF inline
370 #endif
371#endif
372
373#if defined(__cplusplus) && !defined(__EMSCRIPTEN__)
374 extern "C" {
375#endif
376
377/* makes sure the header file part is only defined once by default */
378#ifndef RGFW_HEADER
379
380#define RGFW_HEADER
381
382#include <stddef.h>
383#ifndef RGFW_INT_DEFINED
384 #ifdef RGFW_USE_INT /* optional for any system that might not have stdint.h */
385 typedef unsigned char u8;
386 typedef signed char i8;
387 typedef unsigned short u16;
388 typedef signed short i16;
389 typedef unsigned long int u32;
390 typedef signed long int i32;
391 typedef unsigned long long u64;
392 typedef signed long long i64;
393 #else /* use stdint standard types instead of c "standard" types */
394 #include <stdint.h>
395
396 typedef uint8_t u8;
397 typedef int8_t i8;
398 typedef uint16_t u16;
399 typedef int16_t i16;
400 typedef uint32_t u32;
401 typedef int32_t i32;
402 typedef uint64_t u64;
403 typedef int64_t i64;
404 #endif
405 #define RGFW_INT_DEFINED
406#endif
407
408typedef ptrdiff_t RGFW_ssize_t;
409
410#ifndef RGFW_BOOL_DEFINED
411 #define RGFW_BOOL_DEFINED
412 typedef u8 RGFW_bool;
413#endif
414
415#define RGFW_BOOL(x) (RGFW_bool)((x) != 0) /* force a value to be 0 or 1 */
416#define RGFW_TRUE (RGFW_bool)1
417#define RGFW_FALSE (RGFW_bool)0
418
419#define RGFW_ENUM(type, name) type name; enum
420#define RGFW_BIT(x) (1 << (x))
421
422#ifdef RGFW_VULKAN
423
424 #if defined(RGFW_WAYLAND) && defined(RGFW_X11)
425 #define VK_USE_PLATFORM_WAYLAND_KHR
426 #define VK_USE_PLATFORM_XLIB_KHR
427 #define RGFW_VK_SURFACE ((RGFW_usingWayland()) ? ("VK_KHR_wayland_surface") : ("VK_KHR_xlib_surface"))
428 #elif defined(RGFW_WAYLAND)
429 #define VK_USE_PLATFORM_WAYLAND_KHR
430 #define VK_USE_PLATFORM_XLIB_KHR
431 #define RGFW_VK_SURFACE "VK_KHR_wayland_surface"
432 #elif defined(RGFW_X11)
433 #define VK_USE_PLATFORM_XLIB_KHR
434 #define RGFW_VK_SURFACE "VK_KHR_xlib_surface"
435 #elif defined(RGFW_WINDOWS)
436 #define VK_USE_PLATFORM_WIN32_KHR
437 #define OEMRESOURCE
438 #define RGFW_VK_SURFACE "VK_KHR_win32_surface"
439 #elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11)
440 #define VK_USE_PLATFORM_MACOS_MVK
441 #define RGFW_VK_SURFACE "VK_MVK_macos_surface"
442 #else
443 #define RGFW_VK_SURFACE NULL
444 #endif
445
446#endif
447
448
449/*! @brief The stucture that contains information about the current RGFW instance */
450typedef struct RGFW_info RGFW_info;
451
452/*! @brief The window stucture for interfacing with the window */
453typedef struct RGFW_window RGFW_window;
454
455/*! @brief The source window stucture for interfacing with the underlying windowing API (e.g. winapi, wayland, cocoa, etc) */
456typedef struct RGFW_window_src RGFW_window_src;
457
458/*! @brief The color format for pixel data */
459typedef RGFW_ENUM(u8, RGFW_format) {
460 RGFW_formatRGB8 = 0, /*!< 8-bit RGB (3 channels) */
461 RGFW_formatBGR8, /*!< 8-bit BGR (3 channels) */
462 RGFW_formatRGBA8, /*!< 8-bit RGBA (4 channels) */
463 RGFW_formatARGB8, /*!< 8-bit RGBA (4 channels) */
464 RGFW_formatBGRA8, /*!< 8-bit BGRA (4 channels) */
465 RGFW_formatABGR8, /*!< 8-bit BGRA (4 channels) */
466 RGFW_formatCount
467};
468
469/*! @brief layout struct for mapping out format types */
470typedef struct RGFW_colorLayout { i32 r, g, b, a; u32 channels; } RGFW_colorLayout;
471
472/*! @brief function type converting raw image data between formats */
473typedef void (* RGFW_convertImageDataFunc)(u8* dest_data, u8* src_data, const RGFW_colorLayout* srcLayout, const RGFW_colorLayout* destLayout, size_t count);
474
475/*! @brief a stucture for interfacing with the underlying native image (e.g. XImage, HBITMAP, etc) */
476typedef struct RGFW_nativeImage RGFW_nativeImage;
477
478/*! @brief a stucture for interfacing with pixel data as a renderable surface */
479typedef struct RGFW_surface RGFW_surface;
480
481/*! @brief gamma struct for monitors */
482typedef struct RGFW_gammaRamp {
483 u16* red; /*!< array for the red channel */
484 u16* green; /*!< array for the green channel */
485 u16* blue; /*!< array for the blue channel */
486 size_t count; /*! count of elements in each channel */
487} RGFW_gammaRamp;
488
489/*! @brief monitor mode data | can be changed by the user (with functions)*/
490typedef struct RGFW_monitorMode {
491 i32 w, h; /*!< monitor workarea size */
492 float refreshRate; /*!< monitor refresh rate */
493 u8 red, blue, green; /*!< sizeof rgb values */
494 void* src; /*!< source API mode */
495} RGFW_monitorMode;
496
497/*! @brief structure for monitor node and source monitor data */
498typedef struct RGFW_monitorNode RGFW_monitorNode;
499
500/*! @brief structure for monitor data */
501typedef struct RGFW_monitor {
502 i32 x, y; /*!< x - y of the monitor workarea */
503 char name[128]; /*!< monitor name */
504 float scaleX, scaleY; /*!< monitor content scale */
505 float pixelRatio; /*!< pixel ratio for monitor (1.0 for regular, 2.0 for hiDPI) */
506 float physW, physH; /*!< monitor physical size in inches */
507 RGFW_monitorMode mode; /*!< current mode of the monitor */
508 void* userPtr; /*!< pointer for user data */
509 RGFW_monitorNode* node; /*!< source node data of the monitor */
510} RGFW_monitor;
511
512/*! @brief what type of request you are making for the monitor */
513typedef RGFW_ENUM(u8, RGFW_modeRequest) {
514 RGFW_monitorScale = RGFW_BIT(0), /*!< scale the monitor size */
515 RGFW_monitorRefresh = RGFW_BIT(1), /*!< change the refresh rate */
516 RGFW_monitorRGB = RGFW_BIT(2), /*!< change the monitor RGB bits size */
517 RGFW_monitorAll = RGFW_monitorScale | RGFW_monitorRefresh | RGFW_monitorRGB
518};
519
520/*! a raw pointer to the underlying mouse handle for setting and creating custom mouse icons */
521typedef void RGFW_mouse;
522
523/*! @brief RGFW's abstract keycodes */
524typedef RGFW_ENUM(u8, RGFW_key) {
525 RGFW_keyNULL = 0,
526 RGFW_escape = '\033',
527 RGFW_backtick = '`',
528 RGFW_0 = '0',
529 RGFW_1 = '1',
530 RGFW_2 = '2',
531 RGFW_3 = '3',
532 RGFW_4 = '4',
533 RGFW_5 = '5',
534 RGFW_6 = '6',
535 RGFW_7 = '7',
536 RGFW_8 = '8',
537 RGFW_9 = '9',
538 RGFW_minus = '-',
539 RGFW_equal = '=',
540 RGFW_equals = RGFW_equal,
541 RGFW_backSpace = '\b',
542 RGFW_tab = '\t',
543 RGFW_space = ' ',
544 RGFW_a = 'a',
545 RGFW_b = 'b',
546 RGFW_c = 'c',
547 RGFW_d = 'd',
548 RGFW_e = 'e',
549 RGFW_f = 'f',
550 RGFW_g = 'g',
551 RGFW_h = 'h',
552 RGFW_i = 'i',
553 RGFW_j = 'j',
554 RGFW_k = 'k',
555 RGFW_l = 'l',
556 RGFW_m = 'm',
557 RGFW_n = 'n',
558 RGFW_o = 'o',
559 RGFW_p = 'p',
560 RGFW_q = 'q',
561 RGFW_r = 'r',
562 RGFW_s = 's',
563 RGFW_t = 't',
564 RGFW_u = 'u',
565 RGFW_v = 'v',
566 RGFW_w = 'w',
567 RGFW_x = 'x',
568 RGFW_y = 'y',
569 RGFW_z = 'z',
570 RGFW_period = '.',
571 RGFW_comma = ',',
572 RGFW_slash = '/',
573 RGFW_bracket = '[',
574 RGFW_closeBracket = ']',
575 RGFW_semicolon = ';',
576 RGFW_apostrophe = '\'',
577 RGFW_backSlash = '\\',
578 RGFW_return = '\n',
579 RGFW_enter = RGFW_return,
580 RGFW_delete = '\177', /* 127 */
581 RGFW_F1,
582 RGFW_F2,
583 RGFW_F3,
584 RGFW_F4,
585 RGFW_F5,
586 RGFW_F6,
587 RGFW_F7,
588 RGFW_F8,
589 RGFW_F9,
590 RGFW_F10,
591 RGFW_F11,
592 RGFW_F12,
593 RGFW_F13,
594 RGFW_F14,
595 RGFW_F15,
596 RGFW_F16,
597 RGFW_F17,
598 RGFW_F18,
599 RGFW_F19,
600 RGFW_F20,
601 RGFW_F21,
602 RGFW_F22,
603 RGFW_F23,
604 RGFW_F24,
605 RGFW_F25,
606 RGFW_capsLock,
607 RGFW_shiftL,
608 RGFW_controlL,
609 RGFW_altL,
610 RGFW_superL,
611 RGFW_shiftR,
612 RGFW_controlR,
613 RGFW_altR,
614 RGFW_superR,
615 RGFW_up,
616 RGFW_down,
617 RGFW_left,
618 RGFW_right,
619 RGFW_insert,
620 RGFW_menu,
621 RGFW_end,
622 RGFW_home,
623 RGFW_pageUp,
624 RGFW_pageDown,
625 RGFW_numLock,
626 RGFW_kpSlash,
627 RGFW_kpMultiply,
628 RGFW_kpPlus,
629 RGFW_kpMinus,
630 RGFW_kpEqual,
631 RGFW_kpEquals = RGFW_kpEqual,
632 RGFW_kp1,
633 RGFW_kp2,
634 RGFW_kp3,
635 RGFW_kp4,
636 RGFW_kp5,
637 RGFW_kp6,
638 RGFW_kp7,
639 RGFW_kp8,
640 RGFW_kp9,
641 RGFW_kp0,
642 RGFW_kpPeriod,
643 RGFW_kpReturn,
644 RGFW_scrollLock,
645 RGFW_printScreen,
646 RGFW_pause,
647 RGFW_world1,
648 RGFW_world2,
649 RGFW_keyLast = 256 /* padding for alignment ~(175 by default) */
650};
651
652/*! @brief abstract mouse button codes */
653typedef RGFW_ENUM(u8, RGFW_mouseButton) {
654 RGFW_mouseLeft = 0, /*!< left mouse button is pressed */
655 RGFW_mouseMiddle, /*!< mouse-wheel-button is pressed */
656 RGFW_mouseRight, /*!< right mouse button is pressed */
657 RGFW_mouseMisc1, RGFW_mouseMisc2, RGFW_mouseMisc3, RGFW_mouseMisc4, RGFW_mouseMisc5,
658 RGFW_mouseFinal
659};
660
661/*! abstract key modifier codes */
662typedef RGFW_ENUM(u8, RGFW_keymod) {
663 RGFW_modCapsLock = RGFW_BIT(0),
664 RGFW_modNumLock = RGFW_BIT(1),
665 RGFW_modControl = RGFW_BIT(2),
666 RGFW_modAlt = RGFW_BIT(3),
667 RGFW_modShift = RGFW_BIT(4),
668 RGFW_modSuper = RGFW_BIT(5),
669 RGFW_modScrollLock = RGFW_BIT(6)
670};
671
672/*! @brief codes for the event types that can be sent */
673typedef RGFW_ENUM(u8, RGFW_eventType) {
674 RGFW_eventNone = 0, /*!< no event has been sent */
675 RGFW_keyPressed, /*!< a key has been pressed */
676 RGFW_keyReleased, /*!< a key has been released */
677 RGFW_keyChar, /*!< keyboard character input event specifically for utf8 input */
678 RGFW_mouseButtonPressed, /*!< a mouse button has been pressed (left,middle,right) */
679 RGFW_mouseButtonReleased, /*!< a mouse button has been released (left,middle,right) */
680 RGFW_mouseScroll, /*!< a mouse scroll event */
681 RGFW_mousePosChanged, /*!< the position of the mouse has been changed */
682 /*! mouse event note
683 the x and y of the mouse can be found in the vector, RGFW_x, y
684
685 RGFW_event.button.value holds which mouse button was pressed
686 */
687 RGFW_windowMoved, /*!< the window was moved (by the user) */
688 RGFW_windowResized, /*!< the window was resized (by the user), [on WASM this means the browser was resized] */
689 RGFW_focusIn, /*!< window is in focus now */
690 RGFW_focusOut, /*!< window is out of focus now */
691 RGFW_mouseEnter, /* mouse entered the window */
692 RGFW_mouseLeave, /* mouse left the window */
693 RGFW_windowRefresh, /* The window content needs to be refreshed */
694
695 /* attribs change event note
696 The event data is sent straight to the window structure
697 with win->x, win->y, win->w and win->h
698 */
699 RGFW_quit, /*!< the user clicked the quit button */
700 RGFW_dataDrop, /*!< a file has been dropped into the window */
701 RGFW_dataDrag, /*!< the start of a drag and drop event, when the file is being dragged */
702 /* drop data note
703 The x and y coords of the drop are stored in the vector RGFW_x, y
704
705 RGFW_event.drop.count holds how many files were dropped
706
707 This is also the size of the array which stores all the dropped file string,
708 RGFW_event.drop.files
709 */
710 RGFW_windowMaximized, /*!< the window was maximized */
711 RGFW_windowMinimized, /*!< the window was minimized */
712 RGFW_windowRestored, /*!< the window was restored */
713 RGFW_scaleUpdated, /*!< content scale factor changed */
714 RGFW_monitorConnected, /*!< a monitor has been connected */
715 RGFW_monitorDisconnected /*!< a monitor has been disconnected */
716};
717
718/*! @brief flags for toggling wether or not an event should be processed */
719typedef RGFW_ENUM(u32, RGFW_eventFlag) {
720 RGFW_keyPressedFlag = RGFW_BIT(RGFW_keyPressed),
721 RGFW_keyReleasedFlag = RGFW_BIT(RGFW_keyReleased),
722 RGFW_keyCharFlag = RGFW_BIT(RGFW_keyChar),
723 RGFW_mouseScrollFlag = RGFW_BIT(RGFW_mouseScroll),
724 RGFW_mouseButtonPressedFlag = RGFW_BIT(RGFW_mouseButtonPressed),
725 RGFW_mouseButtonReleasedFlag = RGFW_BIT(RGFW_mouseButtonReleased),
726 RGFW_mousePosChangedFlag = RGFW_BIT(RGFW_mousePosChanged),
727 RGFW_mouseEnterFlag = RGFW_BIT(RGFW_mouseEnter),
728 RGFW_mouseLeaveFlag = RGFW_BIT(RGFW_mouseLeave),
729 RGFW_windowMovedFlag = RGFW_BIT(RGFW_windowMoved),
730 RGFW_windowResizedFlag = RGFW_BIT(RGFW_windowResized),
731 RGFW_focusInFlag = RGFW_BIT(RGFW_focusIn),
732 RGFW_focusOutFlag = RGFW_BIT(RGFW_focusOut),
733 RGFW_windowRefreshFlag = RGFW_BIT(RGFW_windowRefresh),
734 RGFW_windowMaximizedFlag = RGFW_BIT(RGFW_windowMaximized),
735 RGFW_windowMinimizedFlag = RGFW_BIT(RGFW_windowMinimized),
736 RGFW_windowRestoredFlag = RGFW_BIT(RGFW_windowRestored),
737 RGFW_scaleUpdatedFlag = RGFW_BIT(RGFW_scaleUpdated),
738 RGFW_quitFlag = RGFW_BIT(RGFW_quit),
739 RGFW_dataDropFlag = RGFW_BIT(RGFW_dataDrop),
740 RGFW_dataDragFlag = RGFW_BIT(RGFW_dataDrag),
741 RGFW_monitorConnectedFlag = RGFW_BIT(RGFW_monitorConnected),
742 RGFW_monitorDisconnectedFlag = RGFW_BIT(RGFW_monitorDisconnected),
743
744 RGFW_keyEventsFlag = RGFW_keyPressedFlag | RGFW_keyReleasedFlag | RGFW_keyCharFlag,
745 RGFW_mouseEventsFlag = RGFW_mouseButtonPressedFlag | RGFW_mouseButtonReleasedFlag | RGFW_mousePosChangedFlag | RGFW_mouseEnterFlag | RGFW_mouseLeaveFlag | RGFW_mouseScrollFlag ,
746 RGFW_windowEventsFlag = RGFW_windowMovedFlag | RGFW_windowResizedFlag | RGFW_windowRefreshFlag | RGFW_windowMaximizedFlag | RGFW_windowMinimizedFlag | RGFW_windowRestoredFlag | RGFW_scaleUpdatedFlag,
747 RGFW_focusEventsFlag = RGFW_focusInFlag | RGFW_focusOutFlag,
748 RGFW_dataDropEventsFlag = RGFW_dataDropFlag | RGFW_dataDragFlag,
749 RGFW_monitorEventsFlag = RGFW_monitorConnectedFlag | RGFW_monitorDisconnectedFlag,
750 RGFW_allEventFlags = RGFW_keyEventsFlag | RGFW_mouseEventsFlag | RGFW_windowEventsFlag | RGFW_focusEventsFlag | RGFW_dataDropEventsFlag | RGFW_quitFlag | RGFW_monitorEventsFlag
751};
752
753/*! Event structure(s) and union for checking/getting events */
754
755/*! @brief common event data across all events */
756typedef struct RGFW_commonEvent {
757 RGFW_eventType type; /*!< which event has been sent?*/
758 RGFW_window* win; /*!< the window this event applies to (for event queue events) */
759} RGFW_commonEvent;
760
761/*! @brief event data for any mouse button event (press/release) */
762typedef struct RGFW_mouseButtonEvent {
763 RGFW_eventType type; /*!< which event has been sent?*/
764 RGFW_window* win; /*!< the window this event applies to (for event queue events) */
765 RGFW_mouseButton value; /* !< which mouse button was pressed */
766} RGFW_mouseButtonEvent;
767
768/*! @brief event data for any mouse scroll event */
769typedef struct RGFW_mouseScrollEvent {
770 RGFW_eventType type; /*!< which event has been sent?*/
771 RGFW_window* win; /*!< the window this event applies to (for event queue events) */
772 float x, y; /*!< the raw mouse scroll value */
773} RGFW_mouseScrollEvent;
774
775/*! @brief event data for any mouse position event (RGFW_mousePosChanged) */
776typedef struct RGFW_mousePosEvent {
777 RGFW_eventType type; /*!< which event has been sent?*/
778 RGFW_window* win; /*!< the window this event applies to (for event queue events) */
779 i32 x, y; /*!< mouse x, y of event (or drop point) */
780 float vecX, vecY; /*!< raw mouse movement */
781} RGFW_mousePosEvent;
782
783/*! @brief event data for a key press/release event */
784typedef struct RGFW_keyEvent {
785 RGFW_eventType type; /*!< which event has been sent?*/
786 RGFW_window* win; /*!< the window this event applies to (for event queue events) */
787 RGFW_key value; /*!< the physical key of the event, refers to where key is physically */
788 RGFW_bool repeat; /*!< key press event repeated (the key is being held) */
789 RGFW_keymod mod;
790} RGFW_keyEvent;
791
792/*! @brief event data for a key character event */
793typedef struct RGFW_keyCharEvent {
794 RGFW_eventType type; /*!< which event has been sent?*/
795 RGFW_window* win; /*!< the window this event applies to (for event queue events) */
796 u32 value; /*!< the unicode value of the key */
797} RGFW_keyCharEvent;
798
799/*! @brief event data for any data drop event */
800typedef struct RGFW_dataDropEvent {
801 RGFW_eventType type; /*!< which event has been sent?*/
802 RGFW_window* win; /*!< the window this event applies to (for event queue events) */
803 /* 260 max paths with a max length of 260 */
804 char** files; /*!< dropped files */
805 size_t count; /*!< how many files were dropped */
806} RGFW_dataDropEvent;
807
808/*! @brief event data for any data drag event */
809typedef struct RGFW_dataDragEvent {
810 RGFW_eventType type; /*!< which event has been sent?*/
811 RGFW_window* win; /*!< the window this event applies to (for event queue events) */
812 i32 x, y; /*!< mouse x, y of event (or drop point) */
813} RGFW_dataDragEvent;
814
815/*! @brief event data for when the window scale (DPI) is updated */
816typedef struct RGFW_scaleUpdatedEvent {
817 RGFW_eventType type; /*!< which event has been sent?*/
818 RGFW_window* win; /*!< the window this event applies to (for event queue events) */
819 float x, y; /*!< DPI scaling */
820} RGFW_scaleUpdatedEvent;
821
822/*! @brief event data for when a monitor is connected, disconnected or updated */
823typedef struct RGFW_monitorEvent {
824 RGFW_eventType type; /*!< which event has been sent?*/
825 RGFW_window* win; /*!< the window this event applies to (for event queue events) */
826 const RGFW_monitor* monitor; /*!< the monitor that this event applies to */
827} RGFW_monitorEvent;
828
829/*! @brief union for all of the event stucture types */
830typedef 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_mouseButtonEvent button; /*!< data for a button press/release */
834 RGFW_mouseScrollEvent scroll; /*!< data for a mouse scroll */
835 RGFW_mousePosEvent mouse; /*!< data for mouse motion events */
836 RGFW_keyEvent key; /*!< data for key press/release/hold events */
837 RGFW_keyCharEvent keyChar; /*!< data for key character events */
838 RGFW_dataDropEvent drop; /*!< dropping a file events */
839 RGFW_dataDragEvent drag; /*!< data for dragging a file events */
840 RGFW_scaleUpdatedEvent scale; /*!< data for dpi scaling update events */
841 RGFW_monitorEvent monitor; /*!< data for monitor events */
842} RGFW_event;
843
844/*!
845 @!brief codes for for RGFW_the code is stupid and C++ waitForEvent
846 waitMS -> Allows the function to keep checking for events even after there are no more events
847 if waitMS == 0, the loop will not wait for events
848 if waitMS > 0, the loop will wait that many miliseconds after there are no more events until it returns
849 if waitMS == -1 or waitMS == the max size of an unsigned 32-bit int, the loop will not return until it gets another event
850*/
851typedef RGFW_ENUM(i32, RGFW_eventWait) {
852 RGFW_eventNoWait = 0,
853 RGFW_eventWaitNext = -1
854};
855
856/*! @brief optional bitwise arguments for making a windows, these can be OR'd together */
857typedef RGFW_ENUM(u32, RGFW_windowFlags) {
858 RGFW_windowNoBorder = RGFW_BIT(0), /*!< the window doesn't have a border */
859 RGFW_windowNoResize = RGFW_BIT(1), /*!< the window cannot be resized by the user */
860 RGFW_windowAllowDND = RGFW_BIT(2), /*!< the window supports drag and drop */
861 RGFW_windowHideMouse = RGFW_BIT(3), /*! the window should hide the mouse (can be toggled later on using `RGFW_window_showMouse`) */
862 RGFW_windowFullscreen = RGFW_BIT(4), /*!< the window is fullscreen by default */
863 RGFW_windowTransparent = RGFW_BIT(5), /*!< the window is transparent (only properly works on X11 and MacOS, although it's meant for for windows) */
864 RGFW_windowCenter = RGFW_BIT(6), /*! center the window on the screen */
865 RGFW_windowRawMouse = RGFW_BIT(7), /*!< use raw mouse mouse on window creation */
866 RGFW_windowScaleToMonitor = RGFW_BIT(8), /*! scale the window to the screen */
867 RGFW_windowHide = RGFW_BIT(9), /*! the window is hidden */
868 RGFW_windowMaximize = RGFW_BIT(10), /*!< maximize the window on creation */
869 RGFW_windowCenterCursor = RGFW_BIT(11), /*!< center the cursor to the window on creation */
870 RGFW_windowFloating = RGFW_BIT(12), /*!< create a floating window */
871 RGFW_windowFocusOnShow = RGFW_BIT(13), /*!< focus the window when it's shown */
872 RGFW_windowMinimize = RGFW_BIT(14), /*!< focus the window when it's shown */
873 RGFW_windowFocus = RGFW_BIT(15), /*!< if the window is in focus */
874 RGFW_windowCaptureMouse = RGFW_BIT(16), /*!< capture the mouse mouse mouse on window creation */
875 RGFW_windowOpenGL = RGFW_BIT(17), /*!< create an OpenGL context (you can also do this manually with RGFW_window_createContext_OpenGL) */
876 RGFW_windowEGL = RGFW_BIT(18), /*!< create an EGL context (you can also do this manually with RGFW_window_createContext_EGL) */
877 RGFW_noDeinitOnClose = RGFW_BIT(19), /*!< do not auto deinit RGFW if the window closes and this is the last window open */
878 RGFW_windowedFullscreen = RGFW_windowNoBorder | RGFW_windowMaximize,
879 RGFW_windowCaptureRawMouse = RGFW_windowCaptureMouse | RGFW_windowRawMouse
880};
881
882/*! @brief the types of icon to set */
883typedef RGFW_ENUM(u8, RGFW_icon) {
884 RGFW_iconTaskbar = RGFW_BIT(0),
885 RGFW_iconWindow = RGFW_BIT(1),
886 RGFW_iconBoth = RGFW_iconTaskbar | RGFW_iconWindow
887};
888
889/*! @brief standard mouse icons */
890typedef RGFW_ENUM(u8, RGFW_mouseIcons) {
891 RGFW_mouseNormal = 0,
892 RGFW_mouseArrow,
893 RGFW_mouseIbeam,
894 RGFW_mouseText = RGFW_mouseIbeam,
895 RGFW_mouseCrosshair,
896 RGFW_mousePointingHand,
897 RGFW_mouseResizeEW,
898 RGFW_mouseResizeNS,
899 RGFW_mouseResizeNWSE,
900 RGFW_mouseResizeNESW,
901 RGFW_mouseResizeNW,
902 RGFW_mouseResizeN,
903 RGFW_mouseResizeNE,
904 RGFW_mouseResizeE,
905 RGFW_mouseResizeSE,
906 RGFW_mouseResizeS,
907 RGFW_mouseResizeSW,
908 RGFW_mouseResizeW,
909 RGFW_mouseResizeAll,
910 RGFW_mouseNotAllowed,
911 RGFW_mouseWait,
912 RGFW_mouseProgress,
913 RGFW_mouseIconCount,
914 RGFW_mouseIconFinal = 16 /* padding for alignment */
915};
916
917/*! @breif flash request type */
918typedef RGFW_ENUM(u8, RGFW_flashRequest) {
919 RGFW_flashCancel = 0,
920 RGFW_flashBriefly,
921 RGFW_flashUntilFocused
922};
923
924/*! @brief the type of debug message */
925typedef RGFW_ENUM(u8, RGFW_debugType) {
926 RGFW_typeError = 0, RGFW_typeWarning, RGFW_typeInfo
927};
928
929/*! @brief error codes for known failure types */
930typedef RGFW_ENUM(u8, RGFW_errorCode) {
931 RGFW_noError = 0, /*!< no error */
932 RGFW_errOutOfMemory,
933 RGFW_errOpenGLContext, RGFW_errEGLContext, /*!< error with the OpenGL context */
934 RGFW_errWayland, RGFW_errX11,
935 RGFW_errDirectXContext,
936 RGFW_errIOKit,
937 RGFW_errClipboard,
938 RGFW_errFailedFuncLoad,
939 RGFW_errBuffer,
940 RGFW_errMetal,
941 RGFW_errPlatform,
942 RGFW_errEventQueue,
943 RGFW_infoWindow, RGFW_infoBuffer, RGFW_infoGlobal, RGFW_infoOpenGL,
944 RGFW_warningWayland, RGFW_warningOpenGL
945};
946
947/*! @brief callback function type for debug messags */
948typedef void (* RGFW_debugfunc)(RGFW_debugType type, RGFW_errorCode err, const char* msg);
949
950/*! @brief RGFW_windowMoved, the window and its new rect value */
951typedef void (* RGFW_windowMovedfunc)(RGFW_window* win, i32 x, i32 y);
952/*! @brief RGFW_windowResized, the window and its new rect value */
953typedef void (* RGFW_windowResizedfunc)(RGFW_window* win, i32 w, i32 h);
954/*! @brief RGFW_windowRestored, the window and its new rect value */
955typedef void (* RGFW_windowRestoredfunc)(RGFW_window* win, i32 x, i32 y, i32 w, i32 h);
956/*! @brief RGFW_windowMaximized, the window and its new rect value */
957typedef void (* RGFW_windowMaximizedfunc)(RGFW_window* win, i32 x, i32 y, i32 w, i32 h);
958/*! @brief RGFW_windowMinimized, the window and its new rect value */
959typedef void (* RGFW_windowMinimizedfunc)(RGFW_window* win);
960/*! @brief RGFW_quit, the window that was closed */
961typedef void (* RGFW_windowQuitfunc)(RGFW_window* win);
962/*! @brief RGFW_focusIn / RGFW_focusOut, the window who's focus has changed and if its in focus */
963typedef void (* RGFW_focusfunc)(RGFW_window* win, RGFW_bool inFocus);
964/*! @brief RGFW_mouseEnter / RGFW_mouseLeave, the window that changed, the point of the mouse (enter only) and if the mouse has entered */
965typedef void (* RGFW_mouseNotifyfunc)(RGFW_window* win, i32 x, i32 y, RGFW_bool status);
966/*! @brief RGFW_mousePosChanged, the window that the move happened on, and the new point of the mouse */
967typedef void (* RGFW_mousePosfunc)(RGFW_window* win, i32 x, i32 y, float vecX, float vecY);
968/*! @brief RGFW_dataDrag, the window, the point of the drop on the windows */
969typedef void (* RGFW_dataDragfunc)(RGFW_window* win, i32 x, i32 y);
970/*! @brief RGFW_windowRefresh, the window that needs to be refreshed */
971typedef void (* RGFW_windowRefreshfunc)(RGFW_window* win);
972/*! @brief RGFW_keyChar, the window that got the event, the unicode key value */
973typedef void (* RGFW_keyCharfunc)(RGFW_window* win, u32 codepoint);
974/*! @brief RGFW_mouseButtonPressed / RGFW_mouseButtonReleased, the window that got the event, the button that was pressed, the scroll value, if it was a press (else it's a release) */
975
976/*! @brief RGFW_keyPressed / RGFW_keyReleased, the window that got the event, the mapped key, the physical key, the string version, the state of the mod keys, if it was a press (else it's a release) */
977typedef void (* RGFW_keyfunc)(RGFW_window* win, u8 key, RGFW_keymod mod, RGFW_bool repeat, RGFW_bool pressed);
978/*! @brief RGFW_mouseButtonPressed / RGFW_mouseButtonReleased, the window that got the event, the button that was pressed, the scroll value, if it was a press (else it's a release) */
979typedef void (* RGFW_mouseButtonfunc)(RGFW_window* win, RGFW_mouseButton button, RGFW_bool pressed);
980/*! @brief RGFW_mouseScroll, the window that got the event, the x scroll value, the y scroll value */
981typedef void (* RGFW_mouseScrollfunc)(RGFW_window* win, float x, float y);
982/*! @brief RGFW_dataDrop the window that had the drop, the drop data and the number of files dropped */
983typedef void (* RGFW_dataDropfunc)(RGFW_window* win, char** files, size_t count);
984/*! @brief RGFW_scaleUpdated, the window the event was sent to, content scaleX, content scaleY */
985typedef void (* RGFW_scaleUpdatedfunc)(RGFW_window* win, float scaleX, float scaleY);
986/*! @brief RGFW_monitorConnected / RGFW_monitorDisconnected, there was a monitor connected/disconnected */
987typedef void (* RGFW_monitorfunc)(RGFW_window* win, const RGFW_monitor* monitor, RGFW_bool connected);
988
989/*! @brief function pointer equivalent of void* */
990typedef void (*RGFW_proc)(void);
991
992#if defined(RGFW_OPENGL)
993
994/*! @brief abstract structure for interfacing with the underlying OpenGL API */
995typedef struct RGFW_glContext RGFW_glContext;
996
997/*! @brief abstract structure for interfacing with the underlying EGL API */
998typedef struct RGFW_eglContext RGFW_eglContext;
999
1000/*! values for the releaseBehavior hint */
1001typedef RGFW_ENUM(i32, RGFW_glReleaseBehavior) {
1002 RGFW_glReleaseFlush = 0, /*!< flush the pipeline will be flushed when the context is release */
1003 RGFW_glReleaseNone /*!< do nothing on release */
1004};
1005
1006/*! values for the profile hint */
1007typedef RGFW_ENUM(i32, RGFW_glProfile) {
1008 RGFW_glCore = 0, /*!< the core OpenGL version, e.g. just support for that version */
1009 RGFW_glForwardCompatibility, /*!< only compatibility for newer versions of OpenGL as well as the requested version */
1010 RGFW_glCompatibility, /*!< allow compatibility for older versions of OpenGL as well as the requested version */
1011 RGFW_glES /*!< use OpenGL ES */
1012};
1013
1014/*! values for the renderer hint */
1015typedef RGFW_ENUM(i32, RGFW_glRenderer) {
1016 RGFW_glAccelerated = 0, /*!< hardware accelerated (GPU) */
1017 RGFW_glSoftware /*!< software rendered (CPU) */
1018};
1019
1020/*! OpenGL initalization hints */
1021typedef struct RGFW_glHints {
1022 i32 stencil; /*!< set stencil buffer bit size (0 by default) */
1023 i32 samples; /*!< set number of sample buffers (0 by default) */
1024 i32 stereo; /*!< hint the context to use stereoscopic frame buffers for 3D (false by default) */
1025 i32 auxBuffers; /*!< number of aux buffers (0 by default) */
1026 i32 doubleBuffer; /*!< request double buffering (true by default) */
1027 i32 red, green, blue, alpha; /*!< set color bit sizes (all 8 by default) */
1028 i32 depth; /*!< set depth buffer bit size (24 by default) */
1029 i32 accumRed, accumGreen, accumBlue, accumAlpha; /*!< set accumulated RGBA bit sizes (all 0 by default) */
1030 RGFW_bool sRGB; /*!< request sRGA format (false by default) */
1031 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 */
1032 RGFW_bool debug; /*!< request OpenGL debugging (false by default). */
1033 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 */
1034 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 */
1035 RGFW_glProfile profile; /*!< set OpenGL API profile (RGFW_glCore by default) */
1036 i32 major, minor; /*!< set the OpenGL API profile version (by default RGFW_glMajor is 1, RGFW_glMinor is 0) */
1037 RGFW_glContext* share; /*!< Share this OpenGL context with newly created OpenGL contexts; defaults to NULL. */
1038 RGFW_eglContext* shareEGL; /*!< Share this EGL context with newly created OpenGL contexts; defaults to NULL. */
1039 RGFW_glRenderer renderer; /*!< renderer to use e.g. accelerated or software defaults to accelerated */
1040} RGFW_glHints;
1041
1042#endif
1043
1044/**!
1045 * @brief Allocates memory using the allocator defined by RGFW_ALLOC at compile time.
1046 * @param size The size (in bytes) of the memory block to allocate.
1047 * @return A pointer to the allocated memory block.
1048*/
1049RGFWDEF void* RGFW_alloc(size_t size);
1050
1051/**!
1052 * @brief Frees memory using the deallocator defined by RGFW_FREE at compile time.
1053 * @param ptr A pointer to the memory block to free.
1054*/
1055RGFWDEF void RGFW_free(void* ptr);
1056
1057/**!
1058 * @brief Returns the size (in bytes) of the RGFW_window structure.
1059 * @return The size of the RGFW_window structure.
1060*/
1061RGFWDEF size_t RGFW_sizeofWindow(void);
1062
1063/**!
1064 * @brief Returns the size (in bytes) of the RGFW_window_src structure.
1065 * @return The size of the RGFW_window_src structure.
1066*/
1067RGFWDEF size_t RGFW_sizeofWindowSrc(void);
1068
1069/**!
1070 * @brief (Unix) Toggles the use of Wayland.
1071 * This is enabled by default when compiled with `RGFW_WAYLAND`.
1072 * If not using `RGFW_WAYLAND`, Wayland functions are not exposed.
1073 * This function can be used to force the use of XWayland.
1074 * @param wayland A boolean value indicating whether to use Wayland (true) or not (false).
1075*/
1076RGFWDEF void RGFW_useWayland(RGFW_bool wayland);
1077
1078/**!
1079 * @brief Checks if Wayland is currently being used.
1080 * @return RGFW_TRUE if using Wayland, RGFW_FALSE otherwise.
1081*/
1082RGFWDEF RGFW_bool RGFW_usingWayland(void);
1083
1084/**!
1085 * @brief Retrieves the current Cocoa layer (macOS only).
1086 * @return A pointer to the Cocoa layer, or NULL if the platform is not in use.
1087*/
1088RGFWDEF void* RGFW_getLayer_OSX(void);
1089
1090/**!
1091 * @brief Retrieves the current X11 display connection.
1092 * @return A pointer to the X11 display, or NULL if the platform is not in use.
1093*/
1094RGFWDEF void* RGFW_getDisplay_X11(void);
1095
1096/**!
1097 * @brief Retrieves the current Wayland display connection.
1098 * @return A pointer to the Wayland display (`struct wl_display*`), or NULL if the platform is not in use.
1099*/
1100RGFWDEF struct wl_display* RGFW_getDisplay_Wayland(void);
1101
1102/**!
1103 * @brief Sets the class name for X11 and WinAPI windows.
1104 * Windows with the same class name will be grouped by the window manager.
1105 * By default, the class name matches the root window’s name.
1106 * @param name The class name to assign.
1107*/
1108RGFWDEF void RGFW_setClassName(const char* name);
1109
1110/**!
1111 * @brief Sets the X11 instance name.
1112 * By default, the window name will be used as the instance name.
1113 * @param name The X11 instance name to set.
1114*/
1115RGFWDEF void RGFW_setXInstName(const char* name);
1116
1117/**!
1118 * @brief (macOS only) Changes the current working directory to the application’s resource folder.
1119*/
1120RGFWDEF void RGFW_moveToMacOSResourceDir(void);
1121
1122/*! copy image to another image, respecting each image's format */
1123RGFWDEF void RGFW_copyImageData(u8* dest_data, i32 w, i32 h, RGFW_format dest_format, u8* src_data, RGFW_format src_format, RGFW_convertImageDataFunc func);
1124
1125/**!
1126 * @brief Returns the size (in bytes) of the RGFW_nativeImage structure.
1127 * @return The size of the RGFW_nativeImage structure.
1128*/
1129RGFWDEF size_t RGFW_sizeofNativeImage(void);
1130
1131/**!
1132 * @brief Returns the size (in bytes) of the RGFW_surface structure.
1133 * @return The size of the RGFW_surface structure.
1134*/
1135RGFWDEF size_t RGFW_sizeofSurface(void);
1136
1137/**!
1138 * @brief Returns the native format type for the system
1139 * @return the native format type for the system as a RGFW_format enum value
1140*/
1141RGFWDEF RGFW_format RGFW_nativeFormat(void);
1142
1143/**!
1144 * @brief Creates a new surface from raw pixel data.
1145 * @param data A pointer to the pixel data buffer.
1146 * @param w The width of the surface in pixels.
1147 * @param h The height of the surface in pixels.
1148 * @param format The pixel format of the data.
1149 * @return A pointer to the newly created RGFW_surface.
1150 *
1151 * NOTE: when you create a surface using RGFW_createSurface / ptr, on X11 it uses the root window's visual
1152 * this means it may fail to render on any other window if the visual does not match
1153 * RGFW_window_createSurface and RGFW_window_createSurfacePtr exist only for X11 to address this issues
1154 * Of course, you can also manually set the root window with RGFW_setRootWindow
1155*/
1156RGFWDEF RGFW_surface* RGFW_createSurface(u8* data, i32 w, i32 h, RGFW_format format);
1157
1158/**!
1159 * @brief Creates a surface using a pre-allocated RGFW_surface structure.
1160 * @param data A pointer to the pixel data buffer.
1161 * @param w The width of the surface in pixels.
1162 * @param h The height of the surface in pixels.
1163 * @param format The pixel format of the data.
1164 * @param surface A pointer to a pre-allocated RGFW_surface structure.
1165 * @return RGFW_TRUE if successful, RGFW_FALSE otherwise.
1166*/
1167RGFWDEF RGFW_bool RGFW_createSurfacePtr(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface);
1168
1169/**!
1170 * @brief Retrieves the native image associated with a surface.
1171 * @param surface A pointer to the RGFW_surface.
1172 * @return A pointer to the native RGFW_nativeImage associated with the surface.
1173*/
1174RGFWDEF RGFW_nativeImage* RGFW_surface_getNativeImage(RGFW_surface* surface);
1175
1176/**!
1177 * @brief Frees the surface pointer and any buffers used for software rendering.
1178 * @param surface A pointer to the RGFW_surface to free.
1179*/
1180RGFWDEF void RGFW_surface_free(RGFW_surface* surface);
1181
1182/**!
1183 * @brief Frees only the internal buffers used for software rendering, leaving the surface struct intact.
1184 * @param surface A pointer to the RGFW_surface whose buffers should be freed.
1185*/
1186RGFWDEF void RGFW_surface_freePtr(RGFW_surface* surface);
1187
1188
1189/**!
1190 * @brief Loads a mouse icon from bitmap data (similar to RGFW_window_setIcon).
1191 * @param data A pointer to the bitmap pixel data.
1192 * @param w The width of the mouse icon in pixels.
1193 * @param h The height of the mouse icon in pixels.
1194 * @param format The pixel format of the data.
1195 * @return A pointer to the newly loaded RGFW_mouse structure.
1196 *
1197 * @note The icon is not resized by default.
1198*/
1199RGFWDEF RGFW_mouse* RGFW_loadMouse(u8* data, i32 w, i32 h, RGFW_format format);
1200
1201/**!
1202 * @brief Frees the data associated with an RGFW_mouse structure.
1203 * @param mouse A pointer to the RGFW_mouse to free.
1204*/
1205RGFWDEF void RGFW_freeMouse(RGFW_mouse* mouse);
1206
1207/**!
1208 * @brief Get an allocated array of the supported modes of a monitor
1209 * @param monitor the source monitor object
1210 * @param count [OUTPUT] the count of the array
1211 * @return the allocated array of supported modes
1212*/
1213RGFWDEF RGFW_monitorMode* RGFW_monitor_getModes(RGFW_monitor* monitor, size_t* count);
1214
1215/**!
1216 * @brief Free RGFW allocated modes array
1217 * @param monitor the source monitor object
1218 * @param modes a pointer to an allocated array of modes
1219*/
1220RGFWDEF void RGFW_freeModes(RGFW_monitorMode* modes);
1221
1222/**!
1223 * @brief Get the supported modes of a monitor using a pre-allocated array
1224 * @param monitor the source monitor object
1225 * @param modes [OUTPUT] a pointer to an allocated array of modes
1226 * @return the number of (possible) modes, if [modes == NULL] the possible nodes *may* be less than the actual modes
1227*/
1228RGFWDEF size_t RGFW_monitor_getModesPtr(RGFW_monitor* monitor, RGFW_monitorMode** modes);
1229
1230/**!
1231 * @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.
1232 * @param monitor the source monitor object
1233 * @param mode user filled mode to use for comparison
1234 * @param modes [OUTPUT] a pointer to be filled with the output closest monitor
1235 * @return returns true if a suitable monitor was found and false if no suitable monitor was found at all
1236*/
1237
1238RGFWDEF RGFW_bool RGFW_monitor_findClosestMode(RGFW_monitor* monitor, RGFW_monitorMode* mode, RGFW_monitorMode* closest);
1239
1240/**!
1241 * @brief Get the allocated gamma ramp
1242 * @param monitor the source monitor object
1243*/
1244RGFWDEF RGFW_gammaRamp* RGFW_monitor_getGammaRamp(RGFW_monitor* monitor);
1245
1246/**!
1247 * @brief Free the gamma ramp allocated by RGFW
1248 * @param allocated gamma ramp
1249*/
1250RGFWDEF void RGFW_freeGammaRamp(RGFW_gammaRamp* ramp);
1251
1252/**!
1253 * @brief Get the monitor's gamma ramp using a pre-allocated struct with allocated data
1254 * @param monitor the source monitor object
1255 * @param ramp [OUTPUT] a pointer to an allocated gamma ramp (can be NULL to just get the count)
1256 * @return the count of the gamma ramp
1257*/
1258RGFWDEF size_t RGFW_monitor_getGammaRampPtr(RGFW_monitor* monitor, RGFW_gammaRamp* ramp);
1259
1260/**!
1261 * @brief Set the monitor's gamma ramp using a pre-allocated struct with allocated data
1262 * @param monitor the source monitor object
1263 * @param ramp a pointer to an allocated gamma ramp
1264 * @return a bool if the function was successful
1265*/
1266RGFWDEF RGFW_bool RGFW_monitor_setGammaRamp(RGFW_monitor* monitor, RGFW_gammaRamp* ramp);
1267
1268/**!
1269 * @brief Create and set the monitor's gamma ramp with a base gamma exponent
1270 * @param monitor the source monitor object
1271 * @param the gamma exponent
1272 * @return a bool if the function was successful
1273*/
1274RGFWDEF RGFW_bool RGFW_monitor_setGamma(RGFW_monitor* monitor, float gamma);
1275
1276/**!
1277 * @brief Create and set the monitor's gamma ramp with a base gamma exponent using a pre-allocated array
1278 * @param monitor the source monitor object
1279 * @param gamma the gamma exponent
1280 * @param pre-allocated gammaramp channel
1281 * @param count the length of the allocated channel array
1282 * @return a bool if the function was successful
1283*/
1284RGFWDEF RGFW_bool RGFW_monitor_setGammaPtr(RGFW_monitor* monitor, float gamma, u16* ptr, size_t count);
1285
1286/**!
1287 * @brief Get the workarea of a monitor, meaning the parts not occupied by OS graphics (i.e. the taskbar)
1288 * @param monitor the source monitor object
1289 * @param x [OUTPUT] the x pos of the workarea
1290 * @param y [OUTPUT] the y pos of the workarea
1291 * @param w [OUTPUT] the width of the workarea
1292 * @param h [OUTPUT] the height of the workarea
1293 * @return a bool if the function was successful
1294*/
1295RGFWDEF RGFW_bool RGFW_monitor_getWorkarea(RGFW_monitor* monitor, i32* x, i32* y, i32* width, i32* height);
1296
1297/**!
1298 * @brief Get the position of a monitor (the same as monitor.x / monitor.y)
1299 * @param x [OUTPUT] the x position of the monitor
1300 * @param y [OUTPUT] the y position of the monitor
1301 * @return a bool if the function was successful
1302*/
1303RGFWDEF RGFW_bool RGFW_monitor_getPosition(RGFW_monitor* monitor, i32* x, i32* y);
1304
1305/**!
1306 * @brief Get the name of a monitor (the same as monitor.name)
1307 * @return the cstring of the monitor's name
1308*/
1309RGFWDEF const char* RGFW_monitor_getName(RGFW_monitor* monitor);
1310
1311/**!
1312 * @brief Get the scale of a monitor (the same as monitor.scaleX / monitor.scaleY)
1313 * @param monitor the source monitor object
1314 * @param x [OUTPUT] the x scale of the monitor
1315 * @param y [OUTPUT] the y scale of the monitor
1316 * @return a bool if the function was successful
1317*/
1318RGFWDEF RGFW_bool RGFW_monitor_getScale(RGFW_monitor* monitor, float* x, float* y);
1319
1320/**!
1321 * @brief Get the physical size of a monitor (the same as monitor.physW / monitor.physH)
1322 * @param monitor the source monitor object
1323 * @param w [OUTPUT] the physical width of the monitor
1324 * @param h [OUTPUT] the physical height of the monitor
1325 * @return a bool if the function was successful
1326*/
1327RGFWDEF RGFW_bool RGFW_monitor_getPhysicalSize(RGFW_monitor* monitor, float* w, float* h);
1328
1329/**!
1330 * @brief Set the user pointer of a monitor (the same as monitor.userPtr = userPtr)
1331 * @param monitor the source monitor object
1332 * @param userPtr the new user pointer for the monitor
1333*/
1334RGFWDEF void RGFW_monitor_setUserPtr(RGFW_monitor* monitor, void* userPtr);
1335
1336/**!
1337 * @brief Get the user pointer of a monitor (the same as monitor.userPtr)
1338 * @param monitor the source monitor object
1339 * @return the user pointer of the monitor
1340*/
1341RGFWDEF void* RGFW_monitor_getUserPtr(RGFW_monitor* monitor);
1342
1343/**!
1344 * @brief Get the mode of a monitor (the same as monitor.mode)
1345 * @param monitor the source monitor object
1346 * @param mode [OUTPUT] current mode the monitor
1347 * @return a bool if the function was successful
1348*/
1349RGFWDEF RGFW_bool RGFW_monitor_getMode(RGFW_monitor* monitor, RGFW_monitorMode* mode);
1350
1351/**!
1352 * @brief Poll and check for monitor updates (this is called internally on monitor update events and RGFW_init)
1353*/
1354RGFWDEF void RGFW_pollMonitors(void);
1355
1356/**!
1357 * @brief Retrieves an array of all available monitors.
1358 * @param len [OUTPUT] A pointer to store the number of monitors found (maximum of RGFW_MAX_MONITORS [6 by default]).
1359 * @return An array of pointers to RGFW_monitor structures.
1360*/
1361RGFWDEF RGFW_monitor** RGFW_getMonitors(size_t* len);
1362
1363/**!
1364 * @brief Retrieves the primary monitor.
1365 * @return A pointer to the RGFW_monitor structure representing the primary monitor.
1366*/
1367RGFWDEF RGFW_monitor* RGFW_getPrimaryMonitor(void);
1368
1369/**!
1370 * @brief Requests the display mode for a monitor (based on what attributes are directly requested).
1371 * @param mon The monitor to apply the mode change to.
1372 * @param mode The desired RGFW_monitorMode.
1373 * @param request The RGFW_modeRequest describing how to handle the mode change.
1374 * @return RGFW_TRUE if the mode was successfully applied, otherwise RGFW_FALSE.
1375*/
1376RGFWDEF RGFW_bool RGFW_monitor_requestMode(RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request);
1377
1378/**!
1379 * @brief Sets a specific display mode for a monitor directly.
1380 * @param mon The monitor to apply the mode change to.
1381 * @param mode The desired RGFW_monitorMode.
1382 * @param request The RGFW_modeRequest describing how to handle the mode change.
1383 * @return RGFW_TRUE if the mode was successfully applied, otherwise RGFW_FALSE.
1384*/
1385RGFWDEF RGFW_bool RGFW_monitor_setMode(RGFW_monitor* mon, RGFW_monitorMode* mode);
1386
1387/**!
1388 * @brief Compares two monitor modes to check if they are equivalent.
1389 * @param mon The first monitor mode.
1390 * @param mon2 The second monitor mode.
1391 * @param request The RGFW_modeRequest that defines the comparison parameters.
1392 * @return RGFW_TRUE if both modes are equivalent, otherwise RGFW_FALSE.
1393*/
1394RGFWDEF RGFW_bool RGFW_monitorModeCompare(RGFW_monitorMode* mon, RGFW_monitorMode* mon2, RGFW_modeRequest request);
1395
1396/**!
1397 * @brief Scales a monitor’s mode to match a window’s size.
1398 * @param mon The monitor to be scaled.
1399 * @param win The window whose size should be used as a reference.
1400 * @return RGFW_TRUE if the scaling was successful, otherwise RGFW_FALSE.
1401*/
1402RGFWDEF RGFW_bool RGFW_monitor_scaleToWindow(RGFW_monitor* mon, struct RGFW_window* win);
1403
1404 /**!
1405 * @brief set (enable or disable) raw mouse mode globally
1406 * @param the boolean state of raw mouse mode
1407 *
1408*/
1409RGFWDEF void RGFW_setRawMouseMode(RGFW_bool state);
1410
1411/**!
1412* @brief sleep until RGFW gets an event or the timer ends (defined by OS)
1413* @param waitMS how long to wait for the next event (in miliseconds)
1414*/
1415RGFWDEF void RGFW_waitForEvent(i32 waitMS);
1416
1417/**!
1418* @brief Set if events should be queued or not (enabled by default if the event queue is checked)
1419* @param queue boolean value if RGFW should queue events or not
1420*/
1421RGFWDEF void RGFW_setQueueEvents(RGFW_bool queue);
1422
1423/**!
1424* @brief check all the events until there are none left and updates window structure attributes
1425*/
1426RGFWDEF void RGFW_pollEvents(void);
1427
1428/**!
1429* @brief check all the events until there are none left and updates window structure attributes
1430* queues events if the queue is checked and/or requested
1431*/
1432RGFWDEF void RGFW_stopCheckEvents(void);
1433
1434/**!
1435 * @brief polls and pops the next event
1436 * @param event [OUTPUT] a pointer to store the retrieved event
1437 * @return RGFW_TRUE if an event was found, RGFW_FALSE otherwise
1438 *
1439 * NOTE: Using this function without a loop may cause event lag.
1440 * For multi-threaded systems, use RGFW_pollEvents combined with RGFW_checkQueuedEvent.
1441 *
1442 * Example:
1443 * RGFW_event event;
1444 * while (RGFW_checkEvent(win, &event)) {
1445 * // handle event
1446 * }
1447*/
1448RGFWDEF RGFW_bool RGFW_checkEvent(RGFW_event* event);
1449
1450/**!
1451 * @brief pops the first queued event
1452 * @param event [OUTPUT] a pointer to store the retrieved event
1453 * @return RGFW_TRUE if an event was found, RGFW_FALSE otherwise
1454*/
1455RGFWDEF RGFW_bool RGFW_checkQueuedEvent(RGFW_event* event);
1456
1457/** * @defgroup Input
1458* @{ */
1459
1460/**!
1461 * @brief returns true if the key is pressed during the current frame
1462 * @param key the key code of the key you want to check
1463 * @return The boolean value if the key is pressed or not
1464*/
1465RGFWDEF RGFW_bool RGFW_isKeyPressed(RGFW_key key);
1466
1467/**!
1468 * @brief returns true if the key was released during the current frame
1469 * @param key the key code of the key you want to check
1470 * @return The boolean value if the key is released or not
1471*/
1472RGFWDEF RGFW_bool RGFW_isKeyReleased(RGFW_key key);
1473
1474/**!
1475 * @brief returns true if the key is down
1476 * @param key the key code of the key you want to check
1477 * @return The boolean value if the key is down or not
1478*/
1479RGFWDEF RGFW_bool RGFW_isKeyDown(RGFW_key key);
1480
1481/**!
1482 * @brief returns true if the mouse button is pressed during the current frame
1483 * @param button the mouse button code of the button you want to check
1484 * @return The boolean value if the button is pressed or not
1485*/
1486RGFWDEF RGFW_bool RGFW_isMousePressed(RGFW_mouseButton button);
1487
1488/**!
1489 * @brief returns true if the mouse button is released during the current frame
1490 * @param button the mouse button code of the button you want to check
1491 * @return The boolean value if the button is released or not
1492*/
1493RGFWDEF RGFW_bool RGFW_isMouseReleased(RGFW_mouseButton button);
1494
1495/**!
1496 * @brief returns true if the mouse button is down
1497 * @param button the mouse button code of the button you want to check
1498 * @return The boolean value if the button is down or not
1499*/
1500RGFWDEF RGFW_bool RGFW_isMouseDown(RGFW_mouseButton button);
1501
1502/**!
1503 * @brief outputs the current x, y position of the mouse
1504 * @param X [OUTPUT] a pointer for the output X value
1505 * @param Y [OUTPUT] a pointer for the output Y value
1506*/
1507RGFWDEF void RGFW_getMouseScroll(float* x, float* y);
1508
1509/**!
1510 * @brief outputs the current x, y movement vector of the mouse
1511 * @param X [OUTPUT] a pointer for the output X vector value
1512 * @param Y [OUTPUT] a pointer for the output Y vector value
1513*/
1514RGFWDEF void RGFW_getMouseVector(float* x, float* y);
1515/** @} */
1516
1517/**!
1518 * @brief creates a new window
1519 * @param name the requested title of the window
1520 * @param x the requested x position of the window
1521 * @param y the requested y position of the window
1522 * @param w the requested width of the window
1523 * @param h the requested height of the window
1524 * @param flags extra arguments ((u32)0 means no flags used)
1525 * @return A pointer to the newly created window structure
1526 *
1527 * NOTE: (windows) if the executable has an icon resource named RGFW_ICON, it will be set as the initial icon for the window
1528*/
1529RGFWDEF RGFW_window* RGFW_createWindow(const char* name, i32 x, i32 y, i32 w, i32 h, RGFW_windowFlags flags);
1530
1531/**!
1532 * @brief creates a new window using a pre-allocated window structure
1533 * @param name the requested title of the window
1534 * @param x the requested x position of the window
1535 * @param y the requested y position of the window
1536 * @param w the requested width of the window
1537 * @param h the requested height of the window
1538 * @param flags extra arguments ((u32)0 means no flags used)
1539 * @param win a pointer the pre-allocated window structure
1540 * @return A pointer to the newly created window structure
1541*/
1542RGFWDEF RGFW_window* RGFW_createWindowPtr(const char* name, i32 x, i32 y, i32 w, i32 h, RGFW_windowFlags flags, RGFW_window* win);
1543
1544/**!
1545 * @brief creates a new surface structure
1546 * @param win the source window of the surface
1547 * @param data a pointer to the raw data of the structure (you allocate this)
1548 * @param w the width the data
1549 * @param h the height of the data
1550 * @return A pointer to the newly created surface structure
1551 *
1552 * NOTE: when you create a surface using RGFW_createSurface / ptr, on X11 it uses the root window's visual
1553 * this means it may fail to render on any other window if the visual does not match
1554 * RGFW_window_createSurface and RGFW_window_createSurfacePtr exist only for X11 to address this issues
1555 * Of course, you can also manually set the root window with RGFW_setRootWindow
1556 */
1557RGFWDEF RGFW_surface* RGFW_window_createSurface(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format);
1558
1559/**!
1560 * @brief creates a new surface structure using a pre-allocated surface structure
1561 * @param win the source window of the surface
1562 * @param data a pointer to the raw data of the structure (you allocate this)
1563 * @param w the width the data
1564 * @param h the height of the data
1565 * @param a pointer to the pre-allocated surface structure
1566 * @return a bool if the creation was successful or not
1567*/
1568RGFWDEF RGFW_bool RGFW_window_createSurfacePtr(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface);
1569
1570/**!
1571 * @brief set the function/callback used for converting surface data between formats
1572 * @param surface a pointer to the surface
1573 * @param a function pointer for the function to use [if NULL the default function is used]
1574*/
1575RGFWDEF void RGFW_surface_setConvertFunc(RGFW_surface* surface, RGFW_convertImageDataFunc func);
1576
1577/**!
1578 * @brief blits a surface stucture to the window
1579 * @param win a pointer the window to blit to
1580 * @param surface a pointer to the surface
1581*/
1582RGFWDEF void RGFW_window_blitSurface(RGFW_window* win, RGFW_surface* surface);
1583
1584/**!
1585 * @brief gets the position of the window | with RGFW_window.x and window.y
1586 * @param x [OUTPUT] the x position of the window
1587 * @param y [OUTPUT] the y position of the window
1588 * @return a bool if the function was successful
1589*/
1590RGFWDEF RGFW_bool RGFW_window_getPosition(RGFW_window* win, i32* x, i32* y); /*!< */
1591
1592/**!
1593 * @brief gets the size of the window | with RGFW_window.w and window.h
1594 * @param win a pointer to the window
1595 * @param w [OUTPUT] the width of the window
1596 * @param h [OUTPUT] the height of the window
1597 * @return a bool if the function was successful
1598*/
1599RGFWDEF RGFW_bool RGFW_window_getSize(RGFW_window* win, i32* w, i32* h);
1600
1601/**!
1602 * @brief gets the size of the window in exact pixels
1603 * @param win a pointer to the window
1604 * @param w [OUTPUT] the width of the window
1605 * @param h [OUTPUT] the height of the window
1606 * @return a bool if the function was successful
1607*/
1608RGFWDEF RGFW_bool RGFW_window_getSizeInPixels(RGFW_window* win, i32* w, i32* h);
1609
1610/**!
1611 * @brief gets the flags of the window | returns RGFW_window._flags
1612 * @param win a pointer to the window
1613 * @return the window flags
1614*/
1615RGFWDEF u32 RGFW_window_getFlags(RGFW_window* win);
1616
1617/**!
1618 * @brief returns the exit key assigned to the window
1619 * @param win a pointer to the target window
1620 * @return The key code assigned as the exit key
1621*/
1622RGFWDEF RGFW_key RGFW_window_getExitKey(RGFW_window* win);
1623
1624/**!
1625 * @brief sets the exit key for the window
1626 * @param win a pointer to the target window
1627 * @param key the key code to assign as the exit key
1628*/
1629RGFWDEF void RGFW_window_setExitKey(RGFW_window* win, RGFW_key key);
1630
1631/**!
1632 * @brief sets the types of events you want the window to receive
1633 * @param win a pointer to the target window
1634 * @param events the event flags to enable (use RGFW_allEventFlags for all)
1635*/
1636RGFWDEF void RGFW_window_setEnabledEvents(RGFW_window* win, RGFW_eventFlag events);
1637
1638/**!
1639 * @brief gets the currently enabled events for the window
1640 * @param win a pointer to the target window
1641 * @return The enabled event flags for the window
1642*/
1643RGFWDEF RGFW_eventFlag RGFW_window_getEnabledEvents(RGFW_window* win);
1644
1645/**!
1646 * @brief enables all events and disables selected ones
1647 * @param win a pointer to the target window
1648 * @param events the event flags to disable
1649*/
1650RGFWDEF void RGFW_window_setDisabledEvents(RGFW_window* win, RGFW_eventFlag events);
1651
1652/**!
1653 * @brief directly enables or disables a specific event or group of events
1654 * @param win a pointer to the target window
1655 * @param event the event flag or group of flags to modify
1656 * @param state RGFW_TRUE to enable, RGFW_FALSE to disable
1657*/
1658RGFWDEF void RGFW_window_setEventState(RGFW_window* win, RGFW_eventFlag event, RGFW_bool state);
1659
1660/**!
1661 * @brief gets the user pointer associated with the window
1662 * @param win a pointer to the target window
1663 * @return The user-defined pointer stored in the window
1664*/
1665RGFWDEF void* RGFW_window_getUserPtr(RGFW_window* win);
1666
1667/**!
1668 * @brief sets a user pointer for the window
1669 * @param win a pointer to the target window
1670 * @param ptr a pointer to associate with the window
1671*/
1672RGFWDEF void RGFW_window_setUserPtr(RGFW_window* win, void* ptr);
1673
1674/**!
1675 * @brief retrieves the platform-specific window source pointer
1676 * @param win a pointer to the target window
1677 * @return A pointer to the internal RGFW_window_src structure
1678*/
1679RGFWDEF RGFW_window_src* RGFW_window_getSrc(RGFW_window* win);
1680
1681/**!
1682 * @brief sets the macOS layer object associated with the window
1683 * @param win a pointer to the target window
1684 * @param layer a pointer to the macOS layer object
1685 * @note Only available on macOS platforms
1686*/
1687RGFWDEF void RGFW_window_setLayer_OSX(RGFW_window* win, void* layer);
1688
1689/**!
1690 * @brief retrieves the macOS view object associated with the window
1691 * @param win a pointer to the target window
1692 * @return A pointer to the macOS view object, or NULL if not on macOS
1693*/
1694RGFWDEF void* RGFW_window_getView_OSX(RGFW_window* win);
1695
1696/**!
1697 * @brief retrieves the macOS window object
1698 * @param win a pointer to the target window
1699 * @return A pointer to the macOS window object, or NULL if not on macOS
1700*/
1701RGFWDEF void* RGFW_window_getWindow_OSX(RGFW_window* win);
1702
1703/**!
1704 * @brief retrieves the HWND handle for the window
1705 * @param win a pointer to the target window
1706 * @return A pointer to the Windows HWND handle, or NULL if not on Windows
1707*/
1708RGFWDEF void* RGFW_window_getHWND(RGFW_window* win);
1709
1710/**!
1711 * @brief retrieves the HDC handle for the window
1712 * @param win a pointer to the target window
1713 * @return A pointer to the Windows HDC handle, or NULL if not on Windows
1714*/
1715RGFWDEF void* RGFW_window_getHDC(RGFW_window* win);
1716
1717/**!
1718 * @brief retrieves the X11 Window handle for the window
1719 * @param win a pointer to the target window
1720 * @return The X11 Window handle, or 0 if not on X11
1721*/
1722RGFWDEF u64 RGFW_window_getWindow_X11(RGFW_window* win);
1723
1724/**!
1725 * @brief retrieves the Wayland surface handle for the window
1726 * @param win a pointer to the target window
1727 * @return A pointer to the Wayland wl_surface, or NULL if not on Wayland
1728*/
1729RGFWDEF struct wl_surface* RGFW_window_getWindow_Wayland(RGFW_window* win);
1730
1731/** * @defgroup Window_management
1732* @{ */
1733
1734/*! set the window flags (will undo flags if they don't match the old ones) */
1735RGFWDEF void RGFW_window_setFlags(RGFW_window* win, RGFW_windowFlags);
1736
1737/**!
1738 * @brief polls and pops the next event with the matching target window in event queue, pushes back events that don't match
1739 * @param win a pointer to the target window
1740 * @param event [OUTPUT] a pointer to store the retrieved event
1741 * @return RGFW_TRUE if an event was found, RGFW_FALSE otherwise
1742 *
1743 * NOTE: Using this function without a loop may cause event lag.
1744 * For multi-threaded systems, use RGFW_pollEvents combined with RGFW_window_checkQueuedEvent.
1745 *
1746 * Example:
1747 * RGFW_event event;
1748 * while (RGFW_window_checkEvent(win, &event)) {
1749 * // handle event
1750 * }
1751*/
1752RGFWDEF RGFW_bool RGFW_window_checkEvent(RGFW_window* win, RGFW_event* event);
1753
1754/**!
1755 * @brief pops the first queued event with the matching target window, pushes back events that don't match
1756 * @param win a pointer to the target window
1757 * @param event [OUTPUT] a pointer to store the retrieved event
1758 * @return RGFW_TRUE if an event was found, RGFW_FALSE otherwise
1759*/
1760RGFWDEF RGFW_bool RGFW_window_checkQueuedEvent(RGFW_window* win, RGFW_event* event);
1761
1762/**!
1763 * @brief checks if a key was pressed while the window is in focus
1764 * @param win a pointer to the target window
1765 * @param key the key code to check
1766 * @return RGFW_TRUE if the key was pressed, RGFW_FALSE otherwise
1767*/
1768RGFWDEF RGFW_bool RGFW_window_isKeyPressed(RGFW_window* win, RGFW_key key);
1769
1770/**!
1771 * @brief checks if a key is currently being held down
1772 * @param win a pointer to the target window
1773 * @param key the key code to check
1774 * @return RGFW_TRUE if the key is held down, RGFW_FALSE otherwise
1775*/
1776RGFWDEF RGFW_bool RGFW_window_isKeyDown(RGFW_window* win, RGFW_key key);
1777
1778/**!
1779 * @brief checks if a key was released
1780 * @param win a pointer to the target window
1781 * @param key the key code to check
1782 * @return RGFW_TRUE if the key was released, RGFW_FALSE otherwise
1783*/
1784RGFWDEF RGFW_bool RGFW_window_isKeyReleased(RGFW_window* win, RGFW_key key);
1785
1786/**!
1787 * @brief checks if a mouse button was pressed
1788 * @param win a pointer to the target window
1789 * @param button the mouse button code to check
1790 * @return RGFW_TRUE if the mouse button was pressed, RGFW_FALSE otherwise
1791*/
1792RGFWDEF RGFW_bool RGFW_window_isMousePressed(RGFW_window* win, RGFW_mouseButton button);
1793
1794/**!
1795 * @brief checks if a mouse button is currently held down
1796 * @param win a pointer to the target window
1797 * @param button the mouse button code to check
1798 * @return RGFW_TRUE if the mouse button is down, RGFW_FALSE otherwise
1799*/
1800RGFWDEF RGFW_bool RGFW_window_isMouseDown(RGFW_window* win, RGFW_mouseButton button);
1801
1802/**!
1803 * @brief checks if a mouse button was released
1804 * @param win a pointer to the target window
1805 * @param button the mouse button code to check
1806 * @return RGFW_TRUE if the mouse button was released, RGFW_FALSE otherwise
1807*/
1808RGFWDEF RGFW_bool RGFW_window_isMouseReleased(RGFW_window* win, RGFW_mouseButton button);
1809
1810/**!
1811 * @brief checks if the mouse left the window (true only for the first frame)
1812 * @param win a pointer to the target window
1813 * @return RGFW_TRUE if the mouse left, RGFW_FALSE otherwise
1814*/
1815RGFWDEF RGFW_bool RGFW_window_didMouseLeave(RGFW_window* win);
1816
1817/**!
1818 * @brief checks if the mouse entered the window (true only for the first frame)
1819 * @param win a pointer to the target window
1820 * @return RGFW_TRUE if the mouse entered, RGFW_FALSE otherwise
1821*/
1822RGFWDEF RGFW_bool RGFW_window_didMouseEnter(RGFW_window* win);
1823
1824/**!
1825 * @brief checks if the mouse is currently inside the window bounds
1826 * @param win a pointer to the target window
1827 * @return RGFW_TRUE if the mouse is inside, RGFW_FALSE otherwise
1828*/
1829RGFWDEF RGFW_bool RGFW_window_isMouseInside(RGFW_window* win);
1830
1831/**!
1832 * @brief checks if there is data being dragged into or within the window
1833 * @param win a pointer to the target window
1834 * @return RGFW_TRUE if data is being dragged, RGFW_FALSE otherwise
1835*/
1836RGFWDEF RGFW_bool RGFW_window_isDataDragging(RGFW_window* win);
1837
1838/**!
1839 * @brief gets the position of a data drag
1840 * @param win a pointer to the target window
1841 * @param x [OUTPUT] pointer to store the x position
1842 * @param y [OUTPUT] pointer to store the y position
1843 * @return RGFW_TRUE if there is an active drag, RGFW_FALSE otherwise
1844*/
1845RGFWDEF RGFW_bool RGFW_window_getDataDrag(RGFW_window* win, i32* x, i32* y);
1846
1847/**!
1848 * @brief checks if a data drop occurred in the window (first frame only)
1849 * @param win a pointer to the target window
1850 * @return RGFW_TRUE if data was dropped, RGFW_FALSE otherwise
1851*/
1852RGFWDEF RGFW_bool RGFW_window_didDataDrop(RGFW_window* win);
1853
1854/**!
1855 * @brief retrieves files from a data drop (drag and drop)
1856 * @param win a pointer to the target window
1857 * @param files [OUTPUT] a pointer to the array of file paths
1858 * @param count [OUTPUT] the number of dropped files
1859 * @return RGFW_TRUE if a data drop occurred, RGFW_FALSE otherwise
1860*/
1861RGFWDEF RGFW_bool RGFW_window_getDataDrop(RGFW_window* win, const char*** files, size_t* count);
1862
1863/**!
1864 * @brief closes the window and frees its associated structure
1865 * @param win a pointer to the target window
1866*/
1867RGFWDEF void RGFW_window_close(RGFW_window* win);
1868
1869/**!
1870 * @brief closes the window without freeing its structure
1871 * @param win a pointer to the target window
1872*/
1873RGFWDEF void RGFW_window_closePtr(RGFW_window* win);
1874
1875/**!
1876 * @brief moves the window to a new position on the screen
1877 * @param win a pointer to the target window
1878 * @param x the new x position
1879 * @param y the new y position
1880*/
1881RGFWDEF void RGFW_window_move(RGFW_window* win, i32 x, i32 y);
1882
1883/**!
1884 * @brief moves the window to a specific monitor
1885 * @param win a pointer to the target window
1886 * @param m the target monitor
1887*/
1888RGFWDEF void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor* m);
1889
1890/**!
1891 * @brief resizes the window to the given dimensions
1892 * @param win a pointer to the target window
1893 * @param w the new width
1894 * @param h the new height
1895*/
1896RGFWDEF void RGFW_window_resize(RGFW_window* win, i32 w, i32 h);
1897
1898/**!
1899 * @brief sets the aspect ratio of the window
1900 * @param win a pointer to the target window
1901 * @param w the width ratio
1902 * @param h the height ratio
1903*/
1904RGFWDEF void RGFW_window_setAspectRatio(RGFW_window* win, i32 w, i32 h);
1905
1906/**!
1907 * @brief sets the minimum size of the window
1908 * @param win a pointer to the target window
1909 * @param w the minimum width
1910 * @param h the minimum height
1911*/
1912RGFWDEF void RGFW_window_setMinSize(RGFW_window* win, i32 w, i32 h);
1913
1914/**!
1915 * @brief sets the maximum size of the window
1916 * @param win a pointer to the target window
1917 * @param w the maximum width
1918 * @param h the maximum height
1919*/
1920RGFWDEF void RGFW_window_setMaxSize(RGFW_window* win, i32 w, i32 h);
1921
1922/**!
1923 * @brief sets focus to the window
1924 * @param win a pointer to the target window
1925*/
1926RGFWDEF void RGFW_window_focus(RGFW_window* win);
1927
1928/**!
1929 * @brief checks if the window is currently in focus
1930 * @param win a pointer to the target window
1931 * @return RGFW_TRUE if the window is in focus, RGFW_FALSE otherwise
1932*/
1933RGFWDEF RGFW_bool RGFW_window_isInFocus(RGFW_window* win);
1934
1935/**!
1936 * @brief raises the window to the top of the stack
1937 * @param win a pointer to the target window
1938*/
1939RGFWDEF void RGFW_window_raise(RGFW_window* win);
1940
1941/**!
1942 * @brief maximizes the window
1943 * @param win a pointer to the target window
1944*/
1945RGFWDEF void RGFW_window_maximize(RGFW_window* win);
1946
1947/**!
1948 * @brief toggles fullscreen mode for the window
1949 * @param win a pointer to the target window
1950 * @param fullscreen RGFW_TRUE to enable fullscreen, RGFW_FALSE to disable
1951*/
1952RGFWDEF void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen);
1953
1954/**!
1955 * @brief centers the window on the screen
1956 * @param win a pointer to the target window
1957*/
1958RGFWDEF void RGFW_window_center(RGFW_window* win);
1959
1960/**!
1961 * @brief minimizes the window
1962 * @param win a pointer to the target window
1963*/
1964RGFWDEF void RGFW_window_minimize(RGFW_window* win);
1965
1966/**!
1967 * @brief restores the window from minimized state
1968 * @param win a pointer to the target window
1969*/
1970RGFWDEF void RGFW_window_restore(RGFW_window* win);
1971
1972/**!
1973 * @brief makes the window a floating window
1974 * @param win a pointer to the target window
1975 * @param floating RGFW_TRUE to float, RGFW_FALSE to disable
1976*/
1977RGFWDEF void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating);
1978
1979/**!
1980 * @brief sets the opacity level of the window
1981 * @param win a pointer to the target window
1982 * @param opacity the opacity level (0–255)
1983*/
1984RGFWDEF void RGFW_window_setOpacity(RGFW_window* win, u8 opacity);
1985
1986/**!
1987 * @brief toggles window borders
1988 * @param win a pointer to the target window
1989 * @param border RGFW_TRUE for bordered, RGFW_FALSE for borderless
1990*/
1991RGFWDEF void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border);
1992
1993/**!
1994 * @brief checks if the window is borderless
1995 * @param win a pointer to the target window
1996 * @return RGFW_TRUE if borderless, RGFW_FALSE otherwise
1997*/
1998RGFWDEF RGFW_bool RGFW_window_borderless(RGFW_window* win);
1999
2000/**!
2001 * @brief toggles drag-and-drop (DND) support for the window
2002 * @param win a pointer to the target window
2003 * @param allow RGFW_TRUE to allow DND, RGFW_FALSE to disable
2004 * @note RGFW_windowAllowDND must still be passed when creating the window
2005*/
2006RGFWDEF void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow);
2007
2008/**!
2009 * @brief checks if drag-and-drop (DND) is allowed
2010 * @param win a pointer to the target window
2011 * @return RGFW_TRUE if DND is enabled, RGFW_FALSE otherwise
2012*/
2013RGFWDEF RGFW_bool RGFW_window_allowsDND(RGFW_window* win);
2014
2015#ifndef RGFW_NO_PASSTHROUGH
2016/**!
2017 * @brief toggles mouse passthrough for the window
2018 * @param win a pointer to the target window
2019 * @param passthrough RGFW_TRUE to enable passthrough, RGFW_FALSE to disable
2020*/
2021RGFWDEF void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough);
2022#endif
2023
2024/**!
2025 * @brief renames the window
2026 * @param win a pointer to the target window
2027 * @param name the new title string for the window
2028*/
2029RGFWDEF void RGFW_window_setName(RGFW_window* win, const char* name);
2030
2031/**!
2032 * @brief sets the icon for the window and taskbar
2033 * @param win a pointer to the target window
2034 * @param data the image data
2035 * @param w the width of the icon
2036 * @param h the height of the icon
2037 * @param format the image format
2038 * @return RGFW_TRUE if successful, RGFW_FALSE otherwise
2039 *
2040 * NOTE: The image may be resized by default.
2041*/
2042RGFWDEF RGFW_bool RGFW_window_setIcon(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format);
2043
2044/**!
2045 * @brief sets the icon for the window and/or taskbar
2046 * @param win a pointer to the target window
2047 * @param data the image data
2048 * @param w the width of the icon
2049 * @param h the height of the icon
2050 * @param format the image format
2051 * @param type the target icon type (taskbar, window, or both)
2052 * @return RGFW_TRUE if successful, RGFW_FALSE otherwise
2053*/
2054RGFWDEF RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_icon type);
2055
2056/**!
2057 * @brief sets the mouse icon for the window using a loaded bitmap
2058 * @param win a pointer to the target window
2059 * @param mouse a pointer to the RGFW_mouse struct containing the icon
2060*/
2061RGFWDEF void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse);
2062
2063/**!
2064 * @brief Sets the mouse to a standard system cursor.
2065 * @param win The target window.
2066 * @param mouse The standard cursor type (see RGFW_MOUSE enum).
2067 * @return True if the standard cursor was successfully applied.
2068*/
2069RGFWDEF RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, RGFW_mouseIcons mouse);
2070
2071/**!
2072 * @brief Sets the mouse to the default cursor icon.
2073 * @param win The target window.
2074 * @return True if the default cursor was successfully set.
2075*/
2076RGFWDEF RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win);
2077
2078/**!
2079 * @brief set (enable or disable) raw mouse mode only for the select window
2080 * @param win The target window.
2081 * @param the boolean state of raw mouse mode
2082 *
2083*/
2084RGFWDEF void RGFW_window_setRawMouseMode(RGFW_window* win, RGFW_bool state);
2085
2086/**!
2087 * @brief lock/unlock the cursor.
2088 * @param win The target window.
2089 * @param the boolean state of the mouse's capture state
2090 *
2091*/
2092RGFWDEF void RGFW_window_captureMouse(RGFW_window* win, RGFW_bool state);
2093
2094/**!
2095 * @brief lock/unlock the cursor and enable raw mpuise mode.
2096 * @param win The target window.
2097 * @param the boolean state of raw mouse mode
2098 *
2099*/
2100RGFWDEF void RGFW_window_captureRawMouse(RGFW_window* win, RGFW_bool state);
2101
2102/**!
2103 * @brief Returns true if the mouse is using raw mouse mode
2104 * @param win The target window.
2105 * @return True if the mouse is using raw mouse input mode.
2106*/
2107RGFWDEF RGFW_bool RGFW_window_isRawMouseMode(RGFW_window* win);
2108
2109
2110/**!
2111 * @brief Returns true if the mouse is captured
2112 * @param win The target window.
2113 * @return True if the mouse is being captured.
2114*/
2115RGFWDEF RGFW_bool RGFW_window_isCaptured(RGFW_window* win);
2116
2117/**!
2118 * @brief Hides the window from view.
2119 * @param win The target window.
2120*/
2121RGFWDEF void RGFW_window_hide(RGFW_window* win);
2122
2123/**!
2124 * @brief Shows the window if it was hidden.
2125 * @param win The target window.
2126*/
2127RGFWDEF void RGFW_window_show(RGFW_window* win);
2128
2129/**!
2130 * @breif request a window flash to get attention from the user
2131 * @param win the target window
2132 * @param request the flash operation requested
2133*/
2134RGFWDEF void RGFW_window_flash(RGFW_window* win, RGFW_flashRequest request);
2135
2136/**!
2137 * @brief Sets whether the window should close.
2138 * @param win The target window.
2139 * @param shouldClose True to signal the window should close, false to keep it open.
2140 *
2141 * This can override or trigger the `RGFW_window_shouldClose` state by modifying window flags.
2142*/
2143RGFWDEF void RGFW_window_setShouldClose(RGFW_window* win, RGFW_bool shouldClose);
2144
2145/**!
2146 * @brief Retrieves the current global mouse position.
2147 * @param x [OUTPUT] Pointer to store the X position of the mouse on the screen.
2148 * @param y [OUTPUT] Pointer to store the Y position of the mouse on the screen.
2149 * @return True if the position was successfully retrieved.
2150*/
2151RGFWDEF RGFW_bool RGFW_getGlobalMouse(i32* x, i32* y);
2152
2153/**!
2154 * @brief Retrieves the mouse position relative to the window.
2155 * @param win The target window.
2156 * @param x [OUTPUT] Pointer to store the X position within the window.
2157 * @param y [OUTPUT] Pointer to store the Y position within the window.
2158 * @return True if the position was successfully retrieved.
2159*/
2160RGFWDEF RGFW_bool RGFW_window_getMouse(RGFW_window* win, i32* x, i32* y);
2161
2162/**!
2163 * @brief Shows or hides the mouse cursor for the window.
2164 * @param win The target window.
2165 * @param show True to show the mouse, false to hide it.
2166*/
2167RGFWDEF void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show);
2168
2169/**!
2170 * @brief Checks if the mouse is currently hidden in the window.
2171 * @param win The target window.
2172 * @return True if the mouse is hidden.
2173*/
2174RGFWDEF RGFW_bool RGFW_window_isMouseHidden(RGFW_window* win);
2175
2176/**!
2177 * @brief Moves the mouse to the specified position within the window.
2178 * @param win The target window.
2179 * @param x The new X position.
2180 * @param y The new Y position.
2181*/
2182RGFWDEF void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y);
2183
2184/**!
2185 * @brief Checks if the window should close.
2186 * @param win The target window.
2187 * @return True if the window should close (for example, if ESC was pressed or a close event occurred).
2188*/
2189RGFWDEF RGFW_bool RGFW_window_shouldClose(RGFW_window* win);
2190
2191/**!
2192 * @brief Checks if the window is currently fullscreen.
2193 * @param win The target window.
2194 * @return True if the window is fullscreen.
2195*/
2196RGFWDEF RGFW_bool RGFW_window_isFullscreen(RGFW_window* win);
2197
2198/**!
2199 * @brief Checks if the window is currently hidden.
2200 * @param win The target window.
2201 * @return True if the window is hidden.
2202*/
2203RGFWDEF RGFW_bool RGFW_window_isHidden(RGFW_window* win);
2204
2205/**!
2206 * @brief Checks if the window is minimized.
2207 * @param win The target window.
2208 * @return True if the window is minimized.
2209*/
2210RGFWDEF RGFW_bool RGFW_window_isMinimized(RGFW_window* win);
2211
2212/**!
2213 * @brief Checks if the window is maximized.
2214 * @param win The target window.
2215 * @return True if the window is maximized.
2216*/
2217RGFWDEF RGFW_bool RGFW_window_isMaximized(RGFW_window* win);
2218
2219/**!
2220 * @brief Checks if the window is floating.
2221 * @param win The target window.
2222 * @return True if the window is floating.
2223*/
2224RGFWDEF RGFW_bool RGFW_window_isFloating(RGFW_window* win);
2225/** @} */
2226
2227/** * @defgroup Monitor
2228* @{ */
2229
2230/**!
2231 * @brief Scales the window to match its monitor’s resolution.
2232 * @param win The target window.
2233 *
2234 * This function is automatically called when the flag `RGFW_scaleToMonitor`
2235 * is used during window creation.
2236*/
2237RGFWDEF void RGFW_window_scaleToMonitor(RGFW_window* win);
2238
2239/**!
2240 * @brief Retrieves the monitor structure associated with the window.
2241 * @param win The target window.
2242 * @return The monitor structure of the window.
2243*/
2244RGFWDEF RGFW_monitor* RGFW_window_getMonitor(RGFW_window* win);
2245
2246/** @} */
2247
2248/** * @defgroup Clipboard
2249* @{ */
2250
2251/**!
2252 * @brief Reads clipboard data.
2253 * @param size [OUTPUT] A pointer that will be filled with the size of the clipboard data.
2254 * @return A pointer to the clipboard data as a string.
2255*/
2256RGFWDEF const char* RGFW_readClipboard(size_t* size);
2257
2258/**!
2259 * @brief Reads clipboard data into a provided buffer, or returns the required length if str is NULL.
2260 * @param str [OUTPUT] A pointer to the buffer that will receive the clipboard data (or NULL to get required size).
2261 * @param strCapacity The capacity of the provided buffer.
2262 * @return The number of bytes read or required length of clipboard data.
2263*/
2264RGFWDEF RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity);
2265
2266/**!
2267 * @brief Writes text to the clipboard.
2268 * @param text The text to be written to the clipboard.
2269 * @param textLen The length of the text being written.
2270*/
2271RGFWDEF void RGFW_writeClipboard(const char* text, u32 textLen);
2272/** @} */
2273
2274
2275
2276/** * @defgroup error handling
2277* @{ */
2278/**!
2279 * @brief Sets the callback function to handle debug messages from RGFW.
2280 * @param func The function pointer to be used as the debug callback.
2281 * @return The previously set debug callback function.
2282*/
2283RGFWDEF RGFW_debugfunc RGFW_setDebugCallback(RGFW_debugfunc func);
2284
2285/**!
2286 * @brief Sends a debug message manually through the currently set debug callback.
2287 * @param type The type of debug message being sent.
2288 * @param err The associated error code.
2289 * @param msg The debug message text.
2290*/
2291RGFWDEF void RGFW_sendDebugInfo(RGFW_debugType type, RGFW_errorCode err, const char* msg);
2292/** @} */
2293
2294/**
2295
2296
2297 event callbacks.
2298 These are completely optional, so you can use the normal
2299 RGFW_checkEvent() method if you prefer that
2300
2301* @defgroup Callbacks
2302* @{
2303*/
2304
2305/**!
2306 * @brief Sets the callback function for window move events.
2307 * @param func The function to be called when the window is moved.
2308 * @return The previously set callback function, if any.
2309*/
2310RGFWDEF RGFW_windowMovedfunc RGFW_setWindowMovedCallback(RGFW_windowMovedfunc func);
2311
2312/**!
2313 * @brief Sets the callback function for window resize events.
2314 * @param func The function to be called when the window is resized.
2315 * @return The previously set callback function, if any.
2316*/
2317RGFWDEF RGFW_windowResizedfunc RGFW_setWindowResizedCallback(RGFW_windowResizedfunc func);
2318
2319/**!
2320 * @brief Sets the callback function for window quit events.
2321 * @param func The function to be called when the window receives a quit signal.
2322 * @return The previously set callback function, if any.
2323*/
2324RGFWDEF RGFW_windowQuitfunc RGFW_setWindowQuitCallback(RGFW_windowQuitfunc func);
2325
2326/**!
2327 * @brief Sets the callback function for mouse move events.
2328 * @param func The function to be called when the mouse moves within the window.
2329 * @return The previously set callback function, if any.
2330*/
2331RGFWDEF RGFW_mousePosfunc RGFW_setMousePosCallback(RGFW_mousePosfunc func);
2332
2333/**!
2334 * @brief Sets the callback function for window refresh events.
2335 * @param func The function to be called when the window needs to be refreshed.
2336 * @return The previously set callback function, if any.
2337*/
2338RGFWDEF RGFW_windowRefreshfunc RGFW_setWindowRefreshCallback(RGFW_windowRefreshfunc func);
2339
2340/**!
2341 * @brief Sets the callback function for focus change events.
2342 * @param func The function to be called when the window gains or loses focus.
2343 * @return The previously set callback function, if any.
2344*/
2345RGFWDEF RGFW_focusfunc RGFW_setFocusCallback(RGFW_focusfunc func);
2346
2347/**!
2348 * @brief Sets the callback function for mouse notification events.
2349 * @param func The function to be called when a mouse notification event occurs.
2350 * @return The previously set callback function, if any.
2351*/
2352RGFWDEF RGFW_mouseNotifyfunc RGFW_setMouseNotifyCallback(RGFW_mouseNotifyfunc func);
2353
2354/**!
2355 * @brief Sets the callback function for data drop events.
2356 * @param func The function to be called when data is dropped into the window.
2357 * @return The previously set callback function, if any.
2358*/
2359RGFWDEF RGFW_dataDropfunc RGFW_setDataDropCallback(RGFW_dataDropfunc func);
2360
2361/**!
2362 * @brief Sets the callback function for the start of a data drag event.
2363 * @param func The function to be called when data dragging begins.
2364 * @return The previously set callback function, if any.
2365*/
2366RGFWDEF RGFW_dataDragfunc RGFW_setDataDragCallback(RGFW_dataDragfunc func);
2367
2368/**!
2369 * @brief Sets the callback function for key press and release events.
2370 * @param func The function to be called when a key is pressed or released.
2371 * @return The previously set callback function, if any.
2372*/
2373RGFWDEF RGFW_keyfunc RGFW_setKeyCallback(RGFW_keyfunc func);
2374
2375/**!
2376 * @brief Sets the callback function for key character events.
2377 * @param func The function to be called when a key is pressed or released.
2378 * @return The previously set callback function, if any.
2379*/
2380RGFWDEF RGFW_keyCharfunc RGFW_setKeyCharCallback(RGFW_keyCharfunc func);
2381
2382/**!
2383 * @brief Sets the callback function for mouse button press and release events.
2384 * @param func The function to be called when a mouse button is pressed or released.
2385 * @return The previously set callback function, if any.
2386*/
2387RGFWDEF RGFW_mouseButtonfunc RGFW_setMouseButtonCallback(RGFW_mouseButtonfunc func);
2388
2389/**!
2390 * @brief Sets the callback function for mouse scroll events.
2391 * @param func The function to be called when the mouse wheel is scrolled.
2392 * @return The previously set callback function, if any.
2393*/
2394RGFWDEF RGFW_mouseScrollfunc RGFW_setMouseScrollCallback(RGFW_mouseScrollfunc func);
2395
2396/**!
2397 * @brief Sets the callback function for window maximize events.
2398 * @param func The function to be called when the window is maximized.
2399 * @return The previously set callback function, if any.
2400*/
2401RGFWDEF RGFW_windowMaximizedfunc RGFW_setWindowMaximizedCallback(RGFW_windowMaximizedfunc func);
2402
2403/**!
2404 * @brief Sets the callback function for window minimize events.
2405 * @param func The function to be called when the window is minimized.
2406 * @return The previously set callback function, if any.
2407*/
2408RGFWDEF RGFW_windowMinimizedfunc RGFW_setWindowMinimizedCallback(RGFW_windowMinimizedfunc func);
2409
2410/**!
2411 * @brief Sets the callback function for window restore events.
2412 * @param func The function to be called when the window is restored from a minimized or maximized state.
2413 * @return The previously set callback function, if any.
2414*/
2415RGFWDEF RGFW_windowRestoredfunc RGFW_setWindowRestoredCallback(RGFW_windowRestoredfunc func);
2416
2417/**!
2418 * @brief Sets the callback function for DPI (scale) update events.
2419 * @param func The function to be called when the window’s DPI or scale changes.
2420 * @return The previously set callback function, if any.
2421*/
2422RGFWDEF RGFW_scaleUpdatedfunc RGFW_setScaleUpdatedCallback(RGFW_scaleUpdatedfunc func);
2423
2424/**!
2425 * @brief Sets the callback function for monitor connected and disconnect events.
2426 * @param func The function to be called when a monitor is connected or disconnected.
2427 * @return The previously set callback function, if any.
2428*/
2429RGFWDEF RGFW_monitorfunc RGFW_setMonitorCallback(RGFW_monitorfunc func);
2430
2431/** @} */
2432
2433/** * @defgroup graphics_API
2434* @{ */
2435
2436/*! native rendering API functions */
2437#if defined(RGFW_OPENGL)
2438/* these are native opengl specific functions and will NOT work with EGL */
2439
2440/*!< make the window the current OpenGL drawing context
2441
2442 NOTE:
2443 if you want to switch the graphics context's thread,
2444 you have to run RGFW_window_makeCurrentContext_OpenGL(NULL); on the old thread
2445 then RGFW_window_makeCurrentContext_OpenGL(valid_window) on the new thread
2446*/
2447
2448/**!
2449 * @brief Sets the global OpenGL hints to the specified pointer.
2450 * @param hints A pointer to the RGFW_glHints structure containing the desired OpenGL settings.
2451*/
2452RGFWDEF void RGFW_setGlobalHints_OpenGL(RGFW_glHints* hints);
2453
2454/**!
2455 * @brief Resets the global OpenGL hints to their default values.
2456*/
2457RGFWDEF void RGFW_resetGlobalHints_OpenGL(void);
2458
2459/**!
2460 * @brief Gets the current global OpenGL hints pointer.
2461 * @return A pointer to the currently active RGFW_glHints structure.
2462*/
2463RGFWDEF RGFW_glHints* RGFW_getGlobalHints_OpenGL(void);
2464
2465/**!
2466 * @brief Creates and allocates an OpenGL context for the specified window.
2467 * @param win A pointer to the target RGFW_window.
2468 * @param hints A pointer to an RGFW_glHints structure defining context creation parameters.
2469 * @return A pointer to the newly created RGFW_glContext.
2470*/
2471RGFWDEF RGFW_glContext* RGFW_window_createContext_OpenGL(RGFW_window* win, RGFW_glHints* hints);
2472
2473/**!
2474 * @brief Creates an OpenGL context for the specified window using a preallocated context structure.
2475 * @param win A pointer to the target RGFW_window.
2476 * @param ctx A pointer to an already allocated RGFW_glContext structure.
2477 * @param hints A pointer to an RGFW_glHints structure defining context creation parameters.
2478 * @return RGFW_TRUE on success, RGFW_FALSE on failure.
2479*/
2480RGFWDEF RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints);
2481
2482/**!
2483 * @brief Retrieves the OpenGL context associated with a window.
2484 * @param win A pointer to the RGFW_window.
2485 * @return A pointer to the associated RGFW_glContext, or NULL if none exists or if the context is EGL-based.
2486*/
2487RGFWDEF RGFW_glContext* RGFW_window_getContext_OpenGL(RGFW_window* win);
2488
2489/**!
2490 * @brief Deletes and frees the OpenGL context.
2491 * @param win A pointer to the RGFW_window.
2492 * @param ctx A pointer to the RGFW_glContext to delete.
2493 *
2494 * @note This is automatically called by RGFW_window_close if the window’s context is not NULL.
2495*/
2496RGFWDEF void RGFW_window_deleteContext_OpenGL(RGFW_window* win, RGFW_glContext* ctx);
2497
2498/**!
2499 * @brief Deletes the OpenGL context without freeing its memory.
2500 * @param win A pointer to the RGFW_window.
2501 * @param ctx A pointer to the RGFW_glContext to delete.
2502 *
2503 * @note This is automatically called by RGFW_window_close if the window’s context is not NULL.
2504*/
2505RGFWDEF void RGFW_window_deleteContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx);
2506
2507/**!
2508 * @brief Retrieves the native source context from an RGFW_glContext.
2509 * @param ctx A pointer to the RGFW_glContext.
2510 * @return A pointer to the native OpenGL context handle.
2511*/
2512RGFWDEF void* RGFW_glContext_getSourceContext(RGFW_glContext* ctx);
2513
2514/**!
2515 * @brief Makes the specified window the current OpenGL rendering target.
2516 * @param win A pointer to the RGFW_window to make current.
2517 *
2518 * @note This is typically called internally by RGFW_window_makeCurrent.
2519*/
2520RGFWDEF void RGFW_window_makeCurrentWindow_OpenGL(RGFW_window* win);
2521
2522/**!
2523 * @brief Makes the OpenGL context of the specified window current.
2524 * @param win A pointer to the RGFW_window whose context should be made current.
2525 *
2526 * @note To move a context between threads, call RGFW_window_makeCurrentContext_OpenGL(NULL)
2527 * on the old thread before making it current on the new one.
2528*/
2529RGFWDEF void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win);
2530
2531/**!
2532 * @brief Swaps the OpenGL buffers for the specified window.
2533 * @param win A pointer to the RGFW_window whose buffers should be swapped.
2534*/
2535RGFWDEF void RGFW_window_swapBuffers_OpenGL(RGFW_window* win);
2536
2537/**!
2538 * @brief Retrieves the current OpenGL context.
2539 * @return A pointer to the currently active OpenGL context (GLX, WGL, Cocoa, or WebGL backend).
2540*/
2541RGFWDEF void* RGFW_getCurrentContext_OpenGL(void);
2542
2543/**!
2544 * @brief Retrieves the current OpenGL window.
2545 * @return A pointer to the RGFW_window currently bound as the OpenGL context target.
2546*/
2547RGFWDEF RGFW_window* RGFW_getCurrentWindow_OpenGL(void);
2548
2549/**!
2550 * @brief Sets the OpenGL swap interval (vsync).
2551 * @param win A pointer to the RGFW_window.
2552 * @param swapInterval The desired swap interval value (0 to disable vsync, 1 to enable).
2553*/
2554RGFWDEF void RGFW_window_swapInterval_OpenGL(RGFW_window* win, i32 swapInterval);
2555
2556/**!
2557 * @brief Retrieves the address of a native OpenGL procedure.
2558 * @param procname The name of the OpenGL function to look up.
2559 * @return A pointer to the function, or NULL if not found.
2560*/
2561RGFWDEF RGFW_proc RGFW_getProcAddress_OpenGL(const char* procname);
2562
2563/**!
2564 * @brief Checks whether a specific OpenGL or OpenGL ES API extension is supported.
2565 * @param extension The name of the extension to check.
2566 * @param len The length of the extension string.
2567 * @return RGFW_TRUE if supported, RGFW_FALSE otherwise.
2568*/
2569RGFWDEF RGFW_bool RGFW_extensionSupported_OpenGL(const char* extension, size_t len);
2570
2571/**!
2572 * @brief Checks whether a specific platform-dependent OpenGL extension is supported.
2573 * @param extension The name of the extension to check.
2574 * @param len The length of the extension string.
2575 * @return RGFW_TRUE if supported, RGFW_FALSE otherwise.
2576*/
2577RGFWDEF RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char* extension, size_t len);
2578
2579/* these are EGL specific functions, they may fallback to OpenGL */
2580#ifdef RGFW_EGL
2581/**!
2582 * @brief Creates and allocates an OpenGL/EGL context for the specified window.
2583 * @param win A pointer to the target RGFW_window.
2584 * @param hints A pointer to an RGFW_glHints structure defining context creation parameters.
2585 * @return A pointer to the newly created RGFW_eglContext.
2586*/
2587RGFWDEF RGFW_eglContext* RGFW_window_createContext_EGL(RGFW_window* win, RGFW_glHints* hints);
2588
2589/**!
2590 * @brief Creates an OpenGL/EGL context for the specified window using a preallocated context structure.
2591 * @param win A pointer to the target RGFW_window.
2592 * @param ctx A pointer to an already allocated RGFW_eglContext structure.
2593 * @param hints A pointer to an RGFW_glHints structure defining context creation parameters.
2594 * @return RGFW_TRUE on success, RGFW_FALSE on failure.
2595*/
2596RGFWDEF RGFW_bool RGFW_window_createContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ctx, RGFW_glHints* hints);
2597
2598/**!
2599 * @brief Frees and deletes an OpenGL/EGL context.
2600 * @param win A pointer to the RGFW_window.
2601 * @param ctx A pointer to the RGFW_eglContext to delete.
2602 *
2603 * @note Automatically called by RGFW_window_close if RGFW owns the context.
2604*/
2605RGFWDEF void RGFW_window_deleteContext_EGL(RGFW_window* win, RGFW_eglContext* ctx);
2606
2607/**!
2608 * @brief Deletes an OpenGL/EGL context without freeing its memory.
2609 * @param win A pointer to the RGFW_window.
2610 * @param ctx A pointer to the RGFW_eglContext to delete.
2611 *
2612 * @note Automatically called by RGFW_window_close if RGFW owns the context.
2613*/
2614RGFWDEF void RGFW_window_deleteContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ctx);
2615
2616/**!
2617 * @brief Retrieves the OpenGL/EGL context associated with a window.
2618 * @param win A pointer to the RGFW_window.
2619 * @return A pointer to the associated RGFW_eglContext, or NULL if none exists or if the context is a native OpenGL context.
2620*/
2621RGFWDEF RGFW_eglContext* RGFW_window_getContext_EGL(RGFW_window* win);
2622
2623/**!
2624 * @brief Retrieves the EGL display handle.
2625 * @return A pointer to the native EGLDisplay.
2626*/
2627RGFWDEF void* RGFW_getDisplay_EGL(void);
2628
2629/**!
2630 * @brief Retrieves the native source context from an RGFW_eglContext.
2631 * @param ctx A pointer to the RGFW_eglContext.
2632 * @return A pointer to the native EGLContext handle.
2633*/
2634RGFWDEF void* RGFW_eglContext_getSourceContext(RGFW_eglContext* ctx);
2635
2636/**!
2637 * @brief Retrieves the EGL surface handle from an RGFW_eglContext.
2638 * @param ctx A pointer to the RGFW_eglContext.
2639 * @return A pointer to the EGLSurface associated with the context.
2640*/
2641RGFWDEF void* RGFW_eglContext_getSurface(RGFW_eglContext* ctx);
2642
2643/**!
2644 * @brief Retrieves the Wayland EGL window handle from an RGFW_eglContext.
2645 * @param ctx A pointer to the RGFW_eglContext.
2646 * @return A pointer to the wl_egl_window associated with the EGL context.
2647*/
2648RGFWDEF struct wl_egl_window* RGFW_eglContext_wlEGLWindow(RGFW_eglContext* ctx);
2649
2650/**!
2651 * @brief Swaps the EGL buffers for the specified window.
2652 * @param win A pointer to the RGFW_window whose buffers should be swapped.
2653 *
2654 * @note Typically called by RGFW_window_swapInterval.
2655*/
2656RGFWDEF void RGFW_window_swapBuffers_EGL(RGFW_window* win);
2657
2658/**!
2659 * @brief Makes the specified window the current EGL rendering target.
2660 * @param win A pointer to the RGFW_window to make current.
2661 *
2662 * @note This is typically called internally by RGFW_window_makeCurrent.
2663*/
2664RGFWDEF void RGFW_window_makeCurrentWindow_EGL(RGFW_window* win);
2665
2666/**!
2667 * @brief Makes the EGL context of the specified window current.
2668 * @param win A pointer to the RGFW_window whose context should be made current.
2669 *
2670 * @note To move a context between threads, call RGFW_window_makeCurrentContext_EGL(NULL)
2671 * on the old thread before making it current on the new one.
2672*/
2673RGFWDEF void RGFW_window_makeCurrentContext_EGL(RGFW_window* win);
2674
2675/**!
2676 * @brief Retrieves the current EGL context.
2677 * @return A pointer to the currently active EGLContext.
2678*/
2679RGFWDEF void* RGFW_getCurrentContext_EGL(void);
2680
2681/**!
2682 * @brief Retrieves the current EGL window.
2683 * @return A pointer to the RGFW_window currently bound as the EGL context target.
2684*/
2685RGFWDEF RGFW_window* RGFW_getCurrentWindow_EGL(void);
2686
2687/**!
2688 * @brief Sets the EGL swap interval (vsync).
2689 * @param win A pointer to the RGFW_window.
2690 * @param swapInterval The desired swap interval value (0 to disable vsync, 1 to enable).
2691*/
2692RGFWDEF void RGFW_window_swapInterval_EGL(RGFW_window* win, i32 swapInterval);
2693
2694/**!
2695 * @brief Retrieves the address of a native OpenGL or OpenGL ES procedure in an EGL context.
2696 * @param procname The name of the OpenGL function to look up.
2697 * @return A pointer to the function, or NULL if not found.
2698*/
2699RGFWDEF RGFW_proc RGFW_getProcAddress_EGL(const char* procname);
2700
2701/**!
2702 * @brief Checks whether a specific OpenGL or OpenGL ES API extension is supported in the current EGL context.
2703 * @param extension The name of the extension to check.
2704 * @param len The length of the extension string.
2705 * @return RGFW_TRUE if supported, RGFW_FALSE otherwise.
2706*/
2707RGFWDEF RGFW_bool RGFW_extensionSupported_EGL(const char* extension, size_t len);
2708
2709/**!
2710 * @brief Checks whether a specific platform-dependent EGL extension is supported in the current context.
2711 * @param extension The name of the extension to check.
2712 * @param len The length of the extension string.
2713 * @return RGFW_TRUE if supported, RGFW_FALSE otherwise.
2714*/
2715RGFWDEF RGFW_bool RGFW_extensionSupportedPlatform_EGL(const char* extension, size_t len);
2716#endif
2717#endif
2718
2719#ifdef RGFW_VULKAN
2720#include <vulkan/vulkan.h>
2721
2722/* if you don't want to use the above macros */
2723
2724/**!
2725 * @brief Retrieves the Vulkan instance extensions required by RGFW.
2726 * @param count [OUTPUT] A pointer that will receive the number of required extensions (typically 2).
2727 * @return A pointer to a static array of required Vulkan instance extension names.
2728*/
2729RGFWDEF const char** RGFW_getRequiredInstanceExtensions_Vulkan(size_t* count);
2730
2731/**!
2732 * @brief Creates a Vulkan surface for the specified window.
2733 * @param win A pointer to the RGFW_window for which to create the Vulkan surface.
2734 * @param instance The Vulkan instance used to create the surface.
2735 * @param surface [OUTPUT] A pointer to a VkSurfaceKHR handle that will receive the created surface.
2736 * @return A VkResult indicating success or failure.
2737*/
2738RGFWDEF VkResult RGFW_window_createSurface_Vulkan(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface);
2739
2740/**!
2741 * @brief Checks whether the specified Vulkan physical device and queue family support presentation for RGFW.
2742 * @param instance The Vulkan instance.
2743 * @param physicalDevice The Vulkan physical device to check.
2744 * @param queueFamilyIndex The index of the queue family to query for presentation support.
2745 * @return RGFW_TRUE if presentation is supported, RGFW_FALSE otherwise.
2746*/
2747RGFWDEF RGFW_bool RGFW_getPresentationSupport_Vulkan(VkPhysicalDevice physicalDevice, u32 queueFamilyIndex);
2748#endif
2749
2750#ifdef RGFW_DIRECTX
2751#ifndef RGFW_WINDOWS
2752 #undef RGFW_DIRECTX
2753#else
2754 #define OEMRESOURCE
2755 #include <dxgi.h>
2756
2757 #ifndef __cplusplus
2758 #define __uuidof(T) IID_##T
2759 #endif
2760/**!
2761 * @brief Creates a DirectX swap chain for the specified RGFW window.
2762 * @param win A pointer to the RGFW_window for which to create the swap chain.
2763 * @param pFactory A pointer to the IDXGIFactory used to create the swap chain.
2764 * @param pDevice A pointer to the DirectX device (e.g., ID3D11Device or ID3D12Device).
2765 * @param swapchain [OUTPUT] A pointer to an IDXGISwapChain pointer that will receive the created swap chain.
2766 * @return An integer result code (0 on success, or a DirectX error code on failure).
2767*/
2768RGFWDEF int RGFW_window_createSwapChain_DirectX(RGFW_window* win, IDXGIFactory* pFactory, IUnknown* pDevice, IDXGISwapChain** swapchain);
2769#endif
2770#endif
2771
2772#ifdef RGFW_WEBGPU
2773 #include <webgpu/webgpu.h>
2774 /**!
2775 * @brief Creates a WebGPU surface for the specified RGFW window.
2776 * @param window A pointer to the RGFW_window for which to create the surface.
2777 * @param instance The WebGPU instance used to create the surface.
2778 * @return The created WGPUSurface handle.
2779 */
2780 RGFWDEF WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance instance);
2781#endif
2782
2783/** @} */
2784
2785/** * @defgroup Supporting
2786* @{ */
2787
2788/**!
2789 * @brief Sets the root (main) RGFW window.
2790 * @param win A pointer to the RGFW_window to set as the root window.
2791*/
2792RGFWDEF void RGFW_setRootWindow(RGFW_window* win);
2793
2794/**!
2795 * @brief Retrieves the current root RGFW window.
2796 * @return A pointer to the current root RGFW_window.
2797*/
2798RGFWDEF RGFW_window* RGFW_getRootWindow(void);
2799
2800/**!
2801 * @brief Pushes an event into the standard RGFW event queue.
2802 * @param event A pointer to the RGFW_event to be added to the queue.
2803*/
2804RGFWDEF void RGFW_eventQueuePush(const RGFW_event* event);
2805
2806/**!
2807 * @brief Clears all events from the RGFW event queue without processing them.
2808*/
2809RGFWDEF void RGFW_eventQueueFlush(void);
2810
2811/**!
2812 * @brief Pops the next event from the RGFW event queue.
2813 * @return A pointer to the popped RGFW_event, or NULL if the queue is empty.
2814*/
2815RGFWDEF RGFW_event* RGFW_eventQueuePop(void);
2816
2817/**!
2818 * @brief Pops the next event from the RGFW event queue that matches the target window, pushes back events that don't matchj.
2819 * @param win A pointer to the target RGFW_window.
2820 * @return A pointer to the popped RGFW_event, or NULL if the queue is empty.
2821*/
2822RGFWDEF RGFW_event* RGFW_window_eventQueuePop(RGFW_window* win);
2823
2824/**!
2825 * @brief Converts an API keycode to the RGFW unmapped (physical) key.
2826 * @param keycode The platform-specific keycode.
2827 * @return The corresponding RGFW keycode.
2828*/
2829RGFWDEF RGFW_key RGFW_apiKeyToRGFW(u32 keycode);
2830
2831/**!
2832 * @brief Converts an RGFW keycode to the unmapped (physical) API key.
2833 * @param keycode The RGFW keycode.
2834 * @return The corresponding platform-specific keycode.
2835*/
2836RGFWDEF u32 RGFW_rgfwToApiKey(RGFW_key keycode);
2837
2838/**!
2839 * @brief Converts an physical RGFW keycode to a mapped RGFW keycode.
2840 * @param keycode the physical RGFW keycode.
2841 * @return The corresponding mapped RGFW keycode.
2842*/
2843RGFWDEF RGFW_key RGFW_physicalToMappedKey(RGFW_key keycode);
2844
2845/**!
2846 * @brief Retrieves the size of the RGFW_info structure.
2847 * @return The size (in bytes) of RGFW_info.
2848*/
2849RGFWDEF size_t RGFW_sizeofInfo(void);
2850
2851/**!
2852 * @brief Initializes the RGFW library.
2853 * @return 0 on success, or a negative error code on failure.
2854 * @note This is automatically called when the first window is created.
2855*/
2856RGFWDEF i32 RGFW_init(void);
2857
2858/**!
2859 * @brief Deinitializes the RGFW library.
2860 * @note This is automatically called when the last open window is closed.
2861*/
2862RGFWDEF void RGFW_deinit(void);
2863
2864/**!
2865 * @brief Initializes RGFW using a user-provided RGFW_info structure.
2866 * @param info A pointer to an RGFW_info structure to be used for initialization.
2867 * @return 0 on success, or a negative error code on failure.
2868*/
2869RGFWDEF i32 RGFW_init_ptr(RGFW_info* info);
2870
2871/**!
2872 * @brief Deinitializes a specific RGFW instance stored in the provided RGFW_info pointer.
2873 * @param info A pointer to the RGFW_info structure representing the instance to deinitialize.
2874*/
2875RGFWDEF void RGFW_deinit_ptr(RGFW_info* info);
2876
2877/**!
2878 * @brief Sets the global RGFW_info structure pointer.
2879 * @param info A pointer to the RGFW_info structure to set.
2880*/
2881RGFWDEF void RGFW_setInfo(RGFW_info* info);
2882
2883/**!
2884 * @brief Retrieves the global RGFW_info structure pointer.
2885 * @return A pointer to the current RGFW_info structure.
2886*/
2887RGFWDEF RGFW_info* RGFW_getInfo(void);
2888
2889/** @} */
2890#endif /* RGFW_HEADER */
2891
2892#if !defined(RGFW_NATIVE_HEADER) && (defined(RGFW_NATIVE) || defined(RGFW_IMPLEMENTATION))
2893#define RGFW_NATIVE_HEADER
2894 #if (defined(RGFW_OPENGL) || defined(RGFW_WEGL)) && defined(_MSC_VER)
2895 #pragma comment(lib, "opengl32")
2896 #endif
2897
2898 #ifdef RGFW_OPENGL
2899 struct RGFW_eglContext {
2900 void* ctx;
2901 void* surface;
2902 struct wl_egl_window* eglWindow;
2903 };
2904
2905 typedef union RGFW_gfxContext {
2906 RGFW_glContext* native;
2907 RGFW_eglContext* egl;
2908 } RGFW_gfxContext;
2909
2910 typedef RGFW_ENUM(u32, RGFW_gfxContextType) {
2911 RGFW_gfxNativeOpenGL = RGFW_BIT(0),
2912 RGFW_gfxEGL = RGFW_BIT(1),
2913 RGFW_gfxOwnedByRGFW = RGFW_BIT(2)
2914 };
2915 #endif
2916
2917 /*! source data for the window (used by the APIs) */
2918 #ifdef RGFW_WINDOWS
2919
2920 #ifndef WIN32_LEAN_AND_MEAN
2921 #define WIN32_LEAN_AND_MEAN
2922 #endif
2923 #ifndef OEMRESOURCE
2924 #define OEMRESOURCE
2925 #endif
2926
2927 #include <windows.h>
2928
2929 struct RGFW_nativeImage {
2930 HBITMAP bitmap;
2931 u8* bitmapBits;
2932 RGFW_format format;
2933 HDC hdcMem;
2934 };
2935
2936 #ifdef RGFW_OPENGL
2937 struct RGFW_glContext { HGLRC ctx; };
2938 #endif
2939
2940 struct RGFW_window_src {
2941 HWND window; /*!< source window */
2942 HDC hdc; /*!< source HDC */
2943 HICON hIconSmall, hIconBig; /*!< source window icons */
2944 i32 maxSizeW, maxSizeH, minSizeW, minSizeH, aspectRatioW, aspectRatioH; /*!< for setting max/min resize (RGFW_WINDOWS) */
2945 RGFW_bool actionFrame; /* frame after a caption button was toggled (e.g. minimize, maximize or close) */
2946 WCHAR highSurrogate;
2947 #ifdef RGFW_OPENGL
2948 RGFW_gfxContext ctx;
2949 RGFW_gfxContextType gfxType;
2950 #endif
2951 };
2952
2953#elif defined(RGFW_UNIX)
2954 #ifdef RGFW_X11
2955 #include <X11/Xlib.h>
2956 #include <X11/Xutil.h>
2957
2958 #ifndef RGFW_NO_XRANDR
2959 #include <X11/extensions/Xrandr.h>
2960 #include <X11/Xresource.h>
2961 #endif
2962 #endif
2963
2964 #ifdef RGFW_WAYLAND
2965 #ifdef RGFW_LIBDECOR
2966 #include <libdecor-0/libdecor.h>
2967 #endif
2968
2969 #include <wayland-client.h>
2970 #include <errno.h>
2971 #endif
2972
2973 struct RGFW_nativeImage {
2974 #ifdef RGFW_X11
2975 XImage* bitmap;
2976 #endif
2977 #ifdef RGFW_WAYLAND
2978 struct wl_buffer* wl_buffer;
2979 i32 fd;
2980 struct wl_shm_pool* pool;
2981 #endif
2982 u8* buffer;
2983 RGFW_format format;
2984 };
2985
2986 #ifdef RGFW_OPENGL
2987 struct RGFW_glContext {
2988 #ifdef RGFW_X11
2989 struct __GLXcontextRec* ctx; /*!< source graphics context */
2990 Window window;
2991 #endif
2992 #ifdef RGFW_WAYLAND
2993 RGFW_eglContext egl;
2994 #endif
2995 };
2996 #endif
2997
2998 struct RGFW_window_src {
2999 i32 x, y, w, h;
3000 #ifdef RGFW_OPENGL
3001 RGFW_gfxContext ctx;
3002 RGFW_gfxContextType gfxType;
3003 #endif
3004#ifdef RGFW_X11
3005 Window window; /*!< source window */
3006 Window parent; /*!< parent window */
3007 GC gc;
3008 XIC ic;
3009 u64 flashEnd;
3010 #ifdef RGFW_ADVANCED_SMOOTH_RESIZE
3011 i64 counter_value;
3012 XID counter;
3013 #endif
3014#endif /* RGFW_X11 */
3015
3016#if defined(RGFW_WAYLAND)
3017 struct wl_surface* surface;
3018 struct xdg_surface* xdg_surface;
3019 struct xdg_toplevel* xdg_toplevel;
3020 struct zxdg_toplevel_decoration_v1* decoration;
3021 struct zwp_locked_pointer_v1 *locked_pointer;
3022 struct xdg_toplevel_icon_v1 *icon;
3023 u32 decoration_mode;
3024 /* State flags to configure the window */
3025 RGFW_bool pending_activated;
3026 RGFW_bool activated;
3027 RGFW_bool resizing;
3028 RGFW_bool pending_maximized;
3029 RGFW_bool maximized;
3030 RGFW_bool minimized;
3031 RGFW_bool configured;
3032
3033 RGFW_bool using_custom_cursor;
3034 struct wl_surface* custom_cursor_surface;
3035
3036 RGFW_monitorNode* active_monitor;
3037
3038 struct wl_data_source *data_source; // offer data to other clients
3039
3040 #ifdef RGFW_LIBDECOR
3041 struct libdecor* decorContext;
3042 #endif
3043#endif /* RGFW_WAYLAND */
3044 };
3045
3046#elif defined(RGFW_MACOS)
3047 #include <CoreVideo/CoreVideo.h>
3048
3049 struct RGFW_nativeImage {
3050 RGFW_format format;
3051 u8* buffer;
3052 void* rep;
3053 };
3054
3055 #ifdef RGFW_OPENGL
3056 struct RGFW_glContext {
3057 void* ctx;
3058 void* format;
3059 };
3060 #endif
3061
3062 struct RGFW_window_src {
3063 void* window;
3064 void* view; /* apple viewpoint thingy */
3065 void* mouse;
3066 void* delegate;
3067 #ifdef RGFW_OPENGL
3068 RGFW_gfxContext ctx;
3069 RGFW_gfxContextType gfxType;
3070 #endif
3071 };
3072
3073#elif defined(RGFW_WASM)
3074
3075 #include <emscripten/html5.h>
3076 #include <emscripten/key_codes.h>
3077
3078 struct RGFW_nativeImage {
3079 RGFW_format format;
3080 };
3081
3082 #ifdef RGFW_OPENGL
3083 struct RGFW_glContext {
3084 EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx;
3085 };
3086 #endif
3087
3088 struct RGFW_window_src {
3089 #ifdef RGFW_OPENGL
3090 RGFW_gfxContext ctx;
3091 RGFW_gfxContextType gfxType;
3092 #endif
3093 };
3094
3095#endif
3096
3097struct RGFW_surface {
3098 u8* data;
3099 i32 w, h;
3100 RGFW_format format;
3101 RGFW_convertImageDataFunc convertFunc;
3102 RGFW_nativeImage native;
3103};
3104
3105/*! internal window data that is not specific to the OS */
3106typedef struct RGFW_windowInternal {
3107 /*! which key RGFW_window_shouldClose checks. Settting this to RGFW_keyNULL disables the feature. */
3108 RGFW_key exitKey;
3109 i32 lastMouseX, lastMouseY; /*!< last cusor point (for raw mouse data) */
3110
3111 RGFW_bool shouldClose;
3112 RGFW_bool rawMouse;
3113 RGFW_bool captureMouse;
3114 RGFW_bool inFocus;
3115 RGFW_bool mouseInside;
3116 RGFW_keymod mod;
3117 RGFW_eventFlag enabledEvents;
3118 u32 flags; /*!< windows flags (for RGFW to check and modify) */
3119 i32 oldX, oldY, oldW, oldH;
3120} RGFW_windowInternal;
3121
3122struct RGFW_window {
3123 RGFW_window_src src; /*!< src window data */
3124 RGFW_windowInternal internal; /*!< internal window data that is not specific to the OS */
3125 void* userPtr; /* ptr for user data */
3126 i32 x, y, w, h; /*!< position and size of the window */
3127}; /*!< window structure for the window */
3128
3129typedef struct RGFW_windowState {
3130 RGFW_bool mouseEnter;
3131 RGFW_bool dataDragging;
3132 RGFW_bool dataDrop;
3133 size_t filesCount;
3134 i32 dropX, dropY;
3135 RGFW_window* win; /*!< it's not possible for one of these events to happen in the frame that the other event happened */
3136
3137 RGFW_bool mouseLeave;
3138 RGFW_window* winLeave; /*!< if a mouse leaves one window and enters the next */
3139} RGFW_windowState;
3140
3141typedef struct {
3142 RGFW_bool current;
3143 RGFW_bool prev;
3144} RGFW_keyState;
3145
3146struct RGFW_monitorNode {
3147 RGFW_monitor mon;
3148 RGFW_bool disconnected;
3149 RGFW_monitorNode* next;
3150#ifdef RGFW_WAYLAND
3151 u32 id; /* Add id so wl_outputs can be removed */
3152 struct wl_output *output;
3153 struct zxdg_output_v1 *xdg_output;
3154 RGFW_monitorMode* modes;
3155 size_t modeCount;
3156#endif
3157#if defined(RGFW_X11) && !defined(RGFW_NO_XRANDR)
3158 i32 screen;
3159 RROutput rrOutput;
3160 RRCrtc crtc;
3161#endif
3162#ifdef RGFW_WINDOWS
3163 HMONITOR hMonitor;
3164 WCHAR adapterName[32];
3165 WCHAR deviceName[32];
3166#endif
3167#ifdef RGFW_MACOS
3168 void* screen;
3169 CGDirectDisplayID display;
3170 u32 uintNum;
3171#endif
3172};
3173
3174typedef struct RGFW_monitorList {
3175 RGFW_monitorNode* head;
3176 RGFW_monitorNode* cur;
3177} RGFW_monitorList;
3178
3179typedef struct RGFW_monitors {
3180 RGFW_monitorList list;
3181 RGFW_monitorList freeList;
3182 size_t count;
3183
3184 RGFW_monitorNode* primary;
3185 RGFW_monitorNode data[RGFW_MAX_MONITORS];
3186} RGFW_monitors;
3187
3188RGFWDEF RGFW_monitorNode* RGFW_monitors_add(const RGFW_monitor* mon);
3189RGFWDEF void RGFW_monitors_remove(RGFW_monitorNode* node, RGFW_monitorNode* prev);
3190
3191struct RGFW_info {
3192 RGFW_window* root;
3193 i32 windowCount;
3194
3195 RGFW_mouse* hiddenMouse;
3196
3197 RGFW_event events[RGFW_MAX_EVENTS]; /* A circular buffer (FIFO), using eventBottom/Len */
3198
3199 i32 eventBottom;
3200 i32 eventLen;
3201 RGFW_bool queueEvents;
3202 RGFW_bool polledEvents;
3203
3204 u32 apiKeycodes[RGFW_keyLast];
3205 #if defined(RGFW_X11) || defined(RGFW_WAYLAND)
3206 RGFW_key keycodes[256];
3207 #elif defined(RGFW_WINDOWS)
3208 RGFW_key keycodes[512];
3209 #elif defined(RGFW_MACOS)
3210 RGFW_key keycodes[128];
3211 #elif defined(RGFW_WASM)
3212 RGFW_key keycodes[256];
3213 #endif
3214
3215 const char* className;
3216 RGFW_bool useWaylandBool;
3217 RGFW_bool stopCheckEvents_bool ;
3218 u64 timerOffset;
3219
3220 char* clipboard_data;
3221 char* clipboard; /* for writing to the clipboard selection */
3222 size_t clipboard_len;
3223 char filesSrc[RGFW_MAX_PATH * RGFW_MAX_DROPS];
3224 char** files;
3225 #ifdef RGFW_X11
3226 Display* display;
3227 XContext context;
3228 Window helperWindow;
3229 const char* instName;
3230 XErrorEvent* x11Error;
3231 i32 xrandrEventBase;
3232 XIM im;
3233 #endif
3234 #ifdef RGFW_WAYLAND
3235 struct wl_display* wl_display;
3236 struct xkb_context *xkb_context;
3237 struct xkb_keymap *keymap;
3238 struct xkb_state *xkb_state;
3239 struct zxdg_decoration_manager_v1 *decoration_manager;
3240 struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
3241 struct zwp_relative_pointer_v1 *relative_pointer;
3242 struct zwp_pointer_constraints_v1 *constraint_manager;
3243 struct xdg_toplevel_icon_manager_v1 *icon_manager;
3244
3245 struct zxdg_output_manager_v1 *xdg_output_manager;
3246
3247 struct wl_data_device_manager *data_device_manager;
3248 struct wl_data_device *data_device; // supports clipboard and DND
3249 struct wp_pointer_warp_v1* wp_pointer_warp;
3250
3251 struct wl_keyboard* wl_keyboard;
3252 struct wl_pointer* wl_pointer;
3253 struct wl_compositor* compositor;
3254 struct xdg_wm_base* xdg_wm_base;
3255 struct wl_shm* shm;
3256 struct wl_seat *seat;
3257 struct wl_registry *registry;
3258 u32 mouse_enter_serial;
3259 struct wl_cursor_theme* wl_cursor_theme;
3260 struct wl_surface* cursor_surface;
3261 struct xkb_compose_state* composeState;
3262
3263 RGFW_window* kbOwner;
3264 RGFW_window* mouseOwner; /* what window has access to the mouse */
3265
3266 #endif
3267
3268 RGFW_monitors monitors;
3269
3270 #ifdef RGFW_UNIX
3271 int eventWait_forceStop[3];
3272 i32 clock;
3273 #endif
3274
3275 #ifdef RGFW_MACOS
3276 void* NSApp;
3277 i64 flash;
3278 void* customViewClasses[2]; /* NSView and NSOpenGLView */
3279 void* customNSAppDelegateClass;
3280 void* customWindowDelegateClass;
3281 void* customNSAppDelegate;
3282 void* tisBundle;
3283 #endif
3284
3285 #ifdef RGFW_OPENGL
3286 RGFW_window* current;
3287 #endif
3288 #ifdef RGFW_EGL
3289 void* EGL_display;
3290 #endif
3291
3292 RGFW_bool rawMouse; /* global raw mouse toggle */
3293
3294 RGFW_windowState windowState; /*! for checking window state events */
3295
3296 RGFW_keyState mouseButtons[RGFW_mouseFinal];
3297 RGFW_keyState keyboard[RGFW_keyLast];
3298 float scrollX, scrollY;
3299 float vectorX, vectorY;
3300};
3301#endif /* RGFW_NATIVE_HEADER */
3302
3303#ifdef RGFW_IMPLEMENTATION
3304
3305#ifndef RGFW_NO_MATH
3306#include <math.h>
3307#endif
3308
3309/* global private API */
3310
3311/* for C++ / C89 */
3312RGFWDEF RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win);
3313RGFWDEF void RGFW_window_closePlatform(RGFW_window* win);
3314
3315RGFWDEF void RGFW_window_setFlagsInternal(RGFW_window* win, RGFW_windowFlags flags, RGFW_windowFlags cmpFlags);
3316
3317RGFWDEF void RGFW_initKeycodes(void);
3318RGFWDEF void RGFW_initKeycodesPlatform(void);
3319RGFWDEF void RGFW_resetPrevState(void);
3320RGFWDEF void RGFW_resetKey(void);
3321RGFWDEF void RGFW_unloadEGL(void);
3322RGFWDEF void RGFW_updateKeyModsEx(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll);
3323RGFWDEF void RGFW_updateKeyMods(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool scroll);
3324RGFWDEF void RGFW_window_showMouseFlags(RGFW_window* win, RGFW_bool show);
3325RGFWDEF void RGFW_updateKeyMod(RGFW_window* win, RGFW_keymod mod, RGFW_bool value);
3326RGFWDEF void RGFW_monitors_refresh(void);
3327
3328RGFWDEF void RGFW_windowMaximizedCallback(RGFW_window* win, i32 x, i32 y, i32 w, i32 h);
3329RGFWDEF void RGFW_windowMinimizedCallback(RGFW_window* win);
3330RGFWDEF void RGFW_windowRestoredCallback(RGFW_window* win, i32 x, i32 y, i32 w, i32 h);
3331RGFWDEF void RGFW_windowMovedCallback(RGFW_window* win, i32 x, i32 y);
3332RGFWDEF void RGFW_windowResizedCallback(RGFW_window* win, i32 w, i32 h);
3333RGFWDEF void RGFW_windowQuitCallback(RGFW_window* win);
3334RGFWDEF void RGFW_mousePosCallback(RGFW_window* win, i32 x, i32 y, float vecX, float vecY);
3335RGFWDEF void RGFW_windowRefreshCallback(RGFW_window* win);
3336RGFWDEF void RGFW_focusCallback(RGFW_window* win, RGFW_bool inFocus);
3337RGFWDEF void RGFW_mouseNotifyCallback(RGFW_window* win, i32 x, i32 y, RGFW_bool status);
3338RGFWDEF void RGFW_dataDropCallback(RGFW_window* win, char** files, size_t count);
3339RGFWDEF void RGFW_dataDragCallback(RGFW_window* win, i32 x, i32 y);
3340RGFWDEF void RGFW_keyCharCallback(RGFW_window* win, u32 codepoint);
3341RGFWDEF void RGFW_keyCallback(RGFW_window* win, RGFW_key key, RGFW_keymod mod, RGFW_bool repeat, RGFW_bool press);
3342RGFWDEF void RGFW_mouseButtonCallback(RGFW_window* win, RGFW_mouseButton button, RGFW_bool press);
3343RGFWDEF void RGFW_mouseScrollCallback(RGFW_window* win, float x, float y);
3344RGFWDEF void RGFW_scaleUpdatedCallback(RGFW_window* win, float scaleX, float scaleY);
3345RGFWDEF void RGFW_monitorCallback(RGFW_window* win, const RGFW_monitor* monitor, RGFW_bool connected);
3346
3347RGFWDEF void RGFW_setBit(u32* var, u32 mask, RGFW_bool set);
3348RGFWDEF void RGFW_splitBPP(u32 bpp, RGFW_monitorMode* mode);
3349
3350RGFWDEF void RGFW_window_captureMousePlatform(RGFW_window* win, RGFW_bool state);
3351RGFWDEF void RGFW_window_setRawMouseModePlatform(RGFW_window *win, RGFW_bool state);
3352
3353RGFWDEF void RGFW_copyImageData64(u8* dest_data, i32 w, i32 h, RGFW_format dest_format,
3354 u8* src_data, RGFW_format src_format, RGFW_bool is64bit, RGFW_convertImageDataFunc func);
3355
3356RGFWDEF RGFW_bool RGFW_loadEGL(void);
3357
3358#ifdef RGFW_OPENGL
3359typedef struct RGFW_attribStack {
3360 i32* attribs;
3361 size_t count;
3362 size_t max;
3363} RGFW_attribStack;
3364RGFWDEF void RGFW_attribStack_init(RGFW_attribStack* stack, i32* attribs, size_t max);
3365RGFWDEF void RGFW_attribStack_pushAttrib(RGFW_attribStack* stack, i32 attrib);
3366RGFWDEF void RGFW_attribStack_pushAttribs(RGFW_attribStack* stack, i32 attrib1, i32 attrib2);
3367
3368RGFWDEF RGFW_bool RGFW_extensionSupportedStr(const char* extensions, const char* ext, size_t len);
3369#endif
3370
3371#ifdef RGFW_X11
3372RGFWDEF void RGFW_XCreateWindow (XVisualInfo visual, const char* name, RGFW_windowFlags flags, RGFW_window* win);
3373#endif
3374#ifdef RGFW_MACOS
3375RGFWDEF void RGFW_osx_initView(RGFW_window* win);
3376#endif
3377/* end of global private API defs */
3378
3379RGFW_info* _RGFW = NULL;
3380void RGFW_setInfo(RGFW_info* info) { _RGFW = info; }
3381RGFW_info* RGFW_getInfo(void) { return _RGFW; }
3382
3383
3384void* RGFW_alloc(size_t size) { return RGFW_ALLOC(size); }
3385void RGFW_free(void* ptr) { RGFW_FREE(ptr); }
3386
3387void RGFW_useWayland(RGFW_bool wayland) { RGFW_init(); _RGFW->useWaylandBool = RGFW_BOOL(wayland); }
3388RGFW_bool RGFW_usingWayland(void) { return _RGFW->useWaylandBool; }
3389
3390void RGFW_setRawMouseMode(RGFW_bool state) {
3391 _RGFW->rawMouse = state;
3392 RGFW_window_setRawMouseModePlatform(_RGFW->root, state);
3393}
3394
3395void RGFW_clipboard_switch(char* newstr);
3396void RGFW_clipboard_switch(char* newstr) {
3397 if (_RGFW->clipboard_data != NULL)
3398 RGFW_FREE(_RGFW->clipboard_data);
3399 _RGFW->clipboard_data = newstr;
3400}
3401
3402#define RGFW_CHECK_CLIPBOARD() \
3403 if (size <= 0 && _RGFW->clipboard_data != NULL) \
3404 return (const char*)_RGFW->clipboard_data; \
3405 else if (size <= 0) \
3406 return "\0";
3407
3408const char* RGFW_readClipboard(size_t* len) {
3409 RGFW_ssize_t size = RGFW_readClipboardPtr(NULL, 0);
3410 RGFW_CHECK_CLIPBOARD();
3411 char* str = (char*)RGFW_ALLOC((size_t)size);
3412 RGFW_ASSERT(str != NULL);
3413 str[0] = '\0';
3414
3415 size = RGFW_readClipboardPtr(str, (size_t)size);
3416
3417 RGFW_CHECK_CLIPBOARD();
3418
3419 if (len != NULL) *len = (size_t)size;
3420
3421 RGFW_clipboard_switch(str);
3422 return (const char*)str;
3423}
3424
3425/*
3426RGFW_IMPLEMENTATION starts with generic RGFW defines
3427
3428This is the start of keycode data
3429*/
3430
3431
3432
3433void RGFW_initKeycodes(void) {
3434 RGFW_MEMSET(_RGFW->keycodes, 0, sizeof(_RGFW->keycodes));
3435 RGFW_initKeycodesPlatform();
3436 size_t i, y;
3437 for (i = 0; i < RGFW_keyLast; i++) {
3438 for (y = 0; y < (sizeof(_RGFW->keycodes) / sizeof(RGFW_key)); y++) {
3439 if (_RGFW->keycodes[y] == i) {
3440 _RGFW->apiKeycodes[i] = (RGFW_key)y;
3441 break;
3442 }
3443 }
3444 }
3445
3446
3447 RGFW_resetKey();
3448}
3449
3450RGFW_key RGFW_apiKeyToRGFW(u32 keycode) {
3451 /* make sure the key isn't out of bounds */
3452 if (keycode > (sizeof(_RGFW->keycodes) / sizeof(RGFW_key)))
3453 return 0;
3454
3455 return _RGFW->keycodes[keycode];
3456}
3457
3458u32 RGFW_rgfwToApiKey(RGFW_key keycode) {
3459 /* make sure the key isn't out of bounds */
3460 return _RGFW->apiKeycodes[keycode];
3461}
3462
3463void RGFW_resetKey(void) { RGFW_MEMSET(_RGFW->keyboard, 0, sizeof(_RGFW->keyboard)); }
3464/*
3465 this is the end of keycode data
3466*/
3467
3468/*
3469 event callback defines start here
3470*/
3471
3472
3473/*
3474 These exist to avoid the
3475 if (func == NULL) check
3476 for (allegedly) better performance
3477
3478 RGFW_EMPTY_DEF exists to prevent the missing-prototypes warning
3479*/
3480#define RGFW_CALLBACK_DEFINE(x, x2) \
3481RGFW_##x##func RGFW_##x##CallbackSrc = NULL; \
3482RGFW_##x##func RGFW_set##x2##Callback(RGFW_##x##func func) { \
3483 RGFW_##x##func prev = RGFW_##x##CallbackSrc; \
3484 RGFW_##x##CallbackSrc = func; \
3485 return prev; \
3486}
3487
3488RGFW_CALLBACK_DEFINE(windowMaximized, WindowMaximized)
3489RGFW_CALLBACK_DEFINE(windowMinimized, WindowMinimized)
3490RGFW_CALLBACK_DEFINE(windowRestored, WindowRestored)
3491RGFW_CALLBACK_DEFINE(windowMoved, WindowMoved)
3492RGFW_CALLBACK_DEFINE(windowResized, WindowResized)
3493RGFW_CALLBACK_DEFINE(windowQuit, WindowQuit)
3494RGFW_CALLBACK_DEFINE(mousePos, MousePos)
3495RGFW_CALLBACK_DEFINE(windowRefresh, WindowRefresh)
3496RGFW_CALLBACK_DEFINE(focus, Focus)
3497RGFW_CALLBACK_DEFINE(mouseNotify, MouseNotify)
3498RGFW_CALLBACK_DEFINE(dataDrop, DataDrop)
3499RGFW_CALLBACK_DEFINE(dataDrag, DataDrag)
3500RGFW_CALLBACK_DEFINE(key, Key)
3501RGFW_CALLBACK_DEFINE(keyChar, KeyChar)
3502RGFW_CALLBACK_DEFINE(mouseButton, MouseButton)
3503RGFW_CALLBACK_DEFINE(mouseScroll, MouseScroll)
3504RGFW_CALLBACK_DEFINE(scaleUpdated, ScaleUpdated)
3505RGFW_CALLBACK_DEFINE(monitor, Monitor)
3506RGFW_CALLBACK_DEFINE(debug, Debug)
3507#define RGFW_debugCallback(type, err, msg) if (RGFW_debugCallbackSrc) RGFW_debugCallbackSrc(type, err, msg);
3508#undef RGFW_CALLBACK_DEFINE
3509
3510void RGFW_windowMaximizedCallback(RGFW_window* win, i32 x, i32 y, i32 w, i32 h) {
3511 win->internal.flags |= RGFW_windowMaximize;
3512
3513 if (!(win->internal.enabledEvents & RGFW_windowMaximizedFlag)) return;
3514
3515 RGFW_event event;
3516 event.type = RGFW_windowMaximized;
3517 event.common.win = win;
3518 RGFW_eventQueuePush(&event);
3519
3520 if (RGFW_windowMaximizedCallbackSrc) RGFW_windowMaximizedCallbackSrc(win, x, y, w, h);
3521}
3522
3523void RGFW_windowMinimizedCallback(RGFW_window* win) {
3524 win->internal.flags |= RGFW_windowMinimize;
3525
3526 if (!(win->internal.enabledEvents & RGFW_windowMinimizedFlag)) return;
3527
3528 RGFW_event event;
3529 event.type = RGFW_windowMinimized;
3530 event.common.win = win;
3531 RGFW_eventQueuePush(&event);
3532
3533 if (RGFW_windowMinimizedCallbackSrc) RGFW_windowMinimizedCallbackSrc(win);
3534}
3535
3536void RGFW_windowRestoredCallback(RGFW_window* win, i32 x, i32 y, i32 w, i32 h) {
3537 win->internal.flags &= ~(u32)RGFW_windowMinimize;
3538 if (RGFW_window_isMaximized(win) == RGFW_FALSE) win->internal.flags &= ~(u32)RGFW_windowMaximize;
3539
3540 if (!(win->internal.enabledEvents & RGFW_windowRestoredFlag)) return;
3541
3542 RGFW_event event;
3543 event.type = RGFW_windowRestored;
3544 event.common.win = win;
3545 RGFW_eventQueuePush(&event);
3546
3547 if (RGFW_windowRestoredCallbackSrc) RGFW_windowRestoredCallbackSrc(win, x, y, w, h);
3548}
3549
3550void RGFW_windowMovedCallback(RGFW_window* win, i32 x, i32 y) {
3551 win->x = x;
3552 win->y = y;
3553 if (!(win->internal.enabledEvents & RGFW_windowMovedFlag)) return;
3554
3555 RGFW_event event;
3556 event.type = RGFW_windowMoved;
3557 event.common.win = win;
3558 RGFW_eventQueuePush(&event);
3559
3560 if (RGFW_windowMovedCallbackSrc) RGFW_windowMovedCallbackSrc(win, x, y);
3561}
3562
3563void RGFW_windowResizedCallback(RGFW_window* win, i32 w, i32 h) {
3564 win->w = w;
3565 win->h = h;
3566
3567 if (!(win->internal.enabledEvents & RGFW_windowResizedFlag)) return;
3568 RGFW_event event;
3569 event.type = RGFW_windowResized;
3570 event.common.win = win;
3571 RGFW_eventQueuePush(&event);
3572
3573 if (RGFW_windowResizedCallbackSrc) RGFW_windowResizedCallbackSrc(win, w, h);
3574}
3575
3576void RGFW_windowQuitCallback(RGFW_window* win) {
3577 win->internal.shouldClose = RGFW_TRUE;
3578
3579 RGFW_event event;
3580 event.type = RGFW_quit;
3581 event.common.win = win;
3582 RGFW_eventQueuePush(&event);
3583
3584 if (RGFW_windowQuitCallbackSrc) RGFW_windowQuitCallbackSrc(win);
3585}
3586
3587void RGFW_mousePosCallback(RGFW_window* win, i32 x, i32 y, float vecX, float vecY) {
3588 win->internal.lastMouseX = x;
3589 win->internal.lastMouseY = y;
3590 _RGFW->vectorX = vecX;
3591 _RGFW->vectorY = vecY;
3592
3593 if (!(win->internal.enabledEvents & RGFW_mousePosChangedFlag)) return;
3594
3595 RGFW_event event;
3596 event.type = RGFW_mousePosChanged;
3597 event.mouse.x = x;
3598 event.mouse.y = y;
3599 event.mouse.vecX = vecX;
3600 event.mouse.vecY = vecY;
3601 event.common.win = win;
3602
3603 RGFW_eventQueuePush(&event);
3604
3605 if (RGFW_mousePosCallbackSrc) RGFW_mousePosCallbackSrc(win, x, y, vecX, vecY);
3606}
3607
3608void RGFW_windowRefreshCallback(RGFW_window* win) {
3609 if (!(win->internal.enabledEvents & RGFW_windowRefreshFlag)) return;
3610 RGFW_event event;
3611 event.type = RGFW_windowRefresh;
3612 event.common.win = win;
3613 RGFW_eventQueuePush(&event);
3614
3615 if (RGFW_windowRefreshCallbackSrc) RGFW_windowRefreshCallbackSrc(win);
3616}
3617
3618void RGFW_focusCallback(RGFW_window* win, RGFW_bool inFocus) {
3619 win->internal.inFocus = inFocus;
3620
3621 if (win->internal.captureMouse) {
3622 RGFW_window_captureMousePlatform(win, inFocus);
3623 }
3624
3625 RGFW_event event;
3626 event.common.win = win;
3627
3628 if (inFocus == RGFW_TRUE) {
3629 if ((win->internal.flags & RGFW_windowFullscreen))
3630 RGFW_window_raise(win);
3631
3632 event.type = RGFW_focusIn;
3633 } else if (inFocus == RGFW_FALSE) {
3634 if ((win->internal.flags & RGFW_windowFullscreen))
3635 RGFW_window_minimize(win);
3636
3637 size_t key;
3638 for (key = 0; key < RGFW_keyLast; key++) {
3639 if (RGFW_isKeyDown((u8)key) == RGFW_FALSE) continue;
3640
3641 _RGFW->keyboard[key].current = RGFW_FALSE;
3642 if ((win->internal.enabledEvents & RGFW_BIT(RGFW_keyReleased))) {
3643 RGFW_keyCallback(win, (u8)key, win->internal.mod, RGFW_FALSE, RGFW_FALSE);
3644 }
3645 }
3646
3647 RGFW_resetKey();
3648 event.type = RGFW_focusOut;
3649 }
3650
3651 event.common.win = win;
3652
3653 RGFW_eventQueuePush(&event);
3654
3655 if (RGFW_focusCallbackSrc) RGFW_focusCallbackSrc(win, inFocus);
3656}
3657
3658void RGFW_mouseNotifyCallback(RGFW_window* win, i32 x, i32 y, RGFW_bool status) {
3659 win->internal.mouseInside = status;
3660 _RGFW->windowState.win = win;
3661
3662 win->internal.lastMouseX = x;
3663 win->internal.lastMouseY = y;
3664
3665 RGFW_event event;
3666 event.common.win = win;
3667 event.mouse.x = x;
3668 event.mouse.y = y;
3669
3670 if (status) {
3671 if (!(win->internal.enabledEvents & RGFW_mouseEnterFlag)) return;
3672 _RGFW->windowState.mouseEnter = RGFW_TRUE;
3673 _RGFW->windowState.win = win;
3674 event.type = RGFW_mouseEnter;
3675 } else {
3676 if (!(win->internal.enabledEvents & RGFW_mouseLeaveFlag)) return;
3677 _RGFW->windowState.winLeave = win;
3678 _RGFW->windowState.mouseLeave = RGFW_TRUE;
3679 event.type = RGFW_mouseLeave;
3680 }
3681
3682 RGFW_eventQueuePush(&event);
3683
3684 if (RGFW_mouseNotifyCallbackSrc) RGFW_mouseNotifyCallbackSrc(win, x, y, status);
3685}
3686
3687void RGFW_dataDropCallback(RGFW_window* win, char** files, size_t count) {
3688 if (!(win->internal.enabledEvents & RGFW_dataDropFlag) || !(win->internal.flags & RGFW_windowAllowDND))
3689 return;
3690
3691 _RGFW->windowState.win = win;
3692 _RGFW->windowState.dataDrop = RGFW_TRUE;
3693 _RGFW->windowState.filesCount = count;
3694
3695 RGFW_event event;
3696 event.type = RGFW_dataDrop;
3697 event.drop.files = files;
3698 event.drop.count = count;
3699 event.common.win = win;
3700 RGFW_eventQueuePush(&event);
3701
3702 if (RGFW_dataDropCallbackSrc) RGFW_dataDropCallbackSrc(win, files, count);
3703}
3704
3705void RGFW_dataDragCallback(RGFW_window* win, i32 x, i32 y) {
3706 _RGFW->windowState.win = win;
3707 _RGFW->windowState.dataDragging = RGFW_TRUE;
3708 _RGFW->windowState.dropX = x;
3709 _RGFW->windowState.dropY = y;
3710
3711 if (win->internal.enabledEvents & RGFW_dataDragFlag) return;
3712
3713 RGFW_event event;
3714 event.type = RGFW_dataDrag;
3715 event.drag.x = x;
3716 event.drag.y = y;
3717 event.common.win = win;
3718 RGFW_eventQueuePush(&event);
3719
3720 if (RGFW_dataDragCallbackSrc) RGFW_dataDragCallbackSrc(win, x, y);
3721}
3722
3723void RGFW_keyCharCallback(RGFW_window* win, u32 codepoint) {
3724 if (!(win->internal.enabledEvents & RGFW_keyCharFlag)) return;
3725
3726 RGFW_event event;
3727 event.type = RGFW_keyChar;
3728 event.keyChar.value = codepoint;
3729 event.common.win = win;
3730 RGFW_eventQueuePush(&event);
3731
3732 if (RGFW_keyCharCallbackSrc) RGFW_keyCharCallbackSrc(win, codepoint);
3733}
3734
3735void RGFW_keyCallback(RGFW_window* win, RGFW_key key, RGFW_keymod mod, RGFW_bool repeat, RGFW_bool press) {
3736 RGFW_event event;
3737
3738 if (press) {
3739 if (!(win->internal.enabledEvents & RGFW_keyPressedFlag)) return;
3740 event.type = RGFW_keyPressed;
3741 } else {
3742 if (!(win->internal.enabledEvents & RGFW_keyReleasedFlag)) return;
3743 event.type = RGFW_keyReleased;
3744 }
3745
3746 _RGFW->keyboard[key].prev = _RGFW->keyboard[key].current;
3747 _RGFW->keyboard[key].current = press;
3748
3749 event.key.value = key;
3750 event.key.mod = repeat;
3751 event.key.mod = mod;
3752 event.common.win = win;
3753 RGFW_eventQueuePush(&event);
3754
3755 if (RGFW_keyCallbackSrc) RGFW_keyCallbackSrc(win, key, mod, repeat, press);
3756}
3757
3758void RGFW_mouseButtonCallback(RGFW_window* win, RGFW_mouseButton button, RGFW_bool press) {
3759 RGFW_event event;
3760 if (press) {
3761 if (!(win->internal.enabledEvents & RGFW_mouseButtonPressedFlag)) return;
3762 event.type = RGFW_mouseButtonPressed;
3763 } else {
3764 if (!(win->internal.enabledEvents & RGFW_mouseButtonReleasedFlag)) return;
3765 event.type = RGFW_mouseButtonReleased;
3766 }
3767
3768 _RGFW->mouseButtons[button].prev = _RGFW->mouseButtons[button].current;
3769 _RGFW->mouseButtons[button].current = press;
3770
3771 event.button.value = button;
3772 event.common.win = win;
3773 RGFW_eventQueuePush(&event);
3774
3775 if (RGFW_mouseButtonCallbackSrc) RGFW_mouseButtonCallbackSrc(win, button, press);
3776}
3777
3778void RGFW_mouseScrollCallback(RGFW_window* win, float x, float y) {
3779 if (!(win->internal.enabledEvents & RGFW_mouseScrollFlag)) return;
3780 _RGFW->scrollX = x;
3781 _RGFW->scrollY = y;
3782
3783 RGFW_event event;
3784 event.type = RGFW_mouseScroll;
3785 event.scroll.x = x;
3786 event.scroll.y = y;
3787 event.common.win = win;
3788 RGFW_eventQueuePush(&event);
3789
3790 if (RGFW_mouseScrollCallbackSrc) RGFW_mouseScrollCallbackSrc(win, x, y);
3791}
3792
3793void RGFW_scaleUpdatedCallback(RGFW_window* win, float scaleX, float scaleY) {
3794 if (win->internal.flags & RGFW_windowScaleToMonitor) RGFW_window_scaleToMonitor(win);
3795 if (!(win->internal.enabledEvents & RGFW_scaleUpdatedFlag)) return;
3796
3797 RGFW_event event;
3798 event.type = RGFW_scaleUpdated;
3799 event.scale.x = scaleX;
3800 event.scale.y = scaleY;
3801 event.common.win = win;
3802 RGFW_eventQueuePush(&event);
3803
3804 if (RGFW_scaleUpdatedCallbackSrc) RGFW_scaleUpdatedCallbackSrc(win, scaleX, scaleY);
3805}
3806
3807void RGFW_monitorCallback(RGFW_window* win, const RGFW_monitor* monitor, RGFW_bool connected) {
3808 if (win) {
3809 if (connected && !(win->internal.enabledEvents & RGFW_monitorConnectedFlag)) return;
3810 if (!connected && !(win->internal.enabledEvents & RGFW_monitorDisconnectedFlag)) return;
3811 }
3812
3813 RGFW_event event;
3814 event.type = (connected) ? (RGFW_monitorConnected) : (RGFW_monitorDisconnected);
3815 event.monitor.monitor = monitor;
3816 event.common.win = win;
3817 RGFW_eventQueuePush(&event);
3818
3819 if (RGFW_monitorCallbackSrc) RGFW_monitorCallbackSrc(win, monitor, connected);
3820}
3821
3822#ifdef RGFW_DEBUG
3823#include <stdio.h>
3824#endif
3825
3826void RGFW_sendDebugInfo(RGFW_debugType type, RGFW_errorCode err, const char* msg) {
3827 RGFW_debugCallback(type, err, msg);
3828
3829 #ifdef RGFW_DEBUG
3830 switch (type) {
3831 case RGFW_typeInfo: RGFW_PRINTF("RGFW INFO (%i %i): %s", type, err, msg); break;
3832 case RGFW_typeError: RGFW_PRINTF("RGFW DEBUG (%i %i): %s", type, err, msg); break;
3833 case RGFW_typeWarning: RGFW_PRINTF("RGFW WARNING (%i %i): %s", type, err, msg); break;
3834 default: break;
3835 }
3836
3837 RGFW_PRINTF("\n");
3838 #endif
3839}
3840
3841void RGFW_window_checkMode(RGFW_window* win);
3842void RGFW_window_checkMode(RGFW_window* win) {
3843 if (RGFW_window_isMinimized(win) && (win->internal.enabledEvents & RGFW_windowMinimizedFlag)) {
3844 RGFW_windowMinimizedCallback(win);
3845 } else if (RGFW_window_isMaximized(win) && (win->internal.enabledEvents & RGFW_windowMaximizedFlag)) {
3846 RGFW_windowMaximizedCallback(win, win->x, win->y, win->w, win->h);
3847 } else if ((((win->internal.flags & RGFW_windowMinimize) && !RGFW_window_isMaximized(win)) ||
3848 (win->internal.flags & RGFW_windowMaximize && !RGFW_window_isMaximized(win))) && (win->internal.enabledEvents & RGFW_windowRestoredFlag)) {
3849 RGFW_windowRestoredCallback(win, win->x, win->y, win->w, win->h);
3850 }
3851}
3852
3853/*
3854no more event call back defines
3855*/
3856
3857size_t RGFW_sizeofInfo(void) { return sizeof(RGFW_info); }
3858size_t RGFW_sizeofNativeImage(void) { return sizeof(RGFW_nativeImage); }
3859size_t RGFW_sizeofSurface(void) { return sizeof(RGFW_surface); }
3860size_t RGFW_sizeofWindow(void) { return sizeof(RGFW_window); }
3861size_t RGFW_sizeofWindowSrc(void) { return sizeof(RGFW_window_src); }
3862
3863RGFW_window_src* RGFW_window_getSrc(RGFW_window* win) { return &win->src; }
3864RGFW_bool RGFW_window_getPosition(RGFW_window* win, i32* x, i32* y) { if (x) *x = win->x; if (y) *y = win->y; return RGFW_TRUE; }
3865RGFW_bool RGFW_window_getSize(RGFW_window* win, i32* w, i32* h) { if (w) *w = win->w; if (h) *h = win->h; return RGFW_TRUE; }
3866u32 RGFW_window_getFlags(RGFW_window* win) { return win->internal.flags; }
3867RGFW_key RGFW_window_getExitKey(RGFW_window* win) { return win->internal.exitKey; }
3868void RGFW_window_setExitKey(RGFW_window* win, RGFW_key key) { win->internal.exitKey = key; }
3869void RGFW_window_setEnabledEvents(RGFW_window* win, RGFW_eventFlag events) { win->internal.enabledEvents = events; }
3870RGFW_eventFlag RGFW_window_getEnabledEvents(RGFW_window* win) { return win->internal.enabledEvents; }
3871void RGFW_window_setDisabledEvents(RGFW_window* win, RGFW_eventFlag events) { RGFW_window_setEnabledEvents(win, (RGFW_allEventFlags) & ~(u32)events); }
3872void RGFW_window_setEventState(RGFW_window* win, RGFW_eventFlag event, RGFW_bool state) { RGFW_setBit(&win->internal.enabledEvents, event, state); }
3873void* RGFW_window_getUserPtr(RGFW_window* win) { return win->userPtr; }
3874void RGFW_window_setUserPtr(RGFW_window* win, void* ptr) { win->userPtr = ptr; }
3875
3876RGFW_bool RGFW_window_getSizeInPixels(RGFW_window* win, i32* w, i32* h) {
3877 RGFW_monitor* mon = RGFW_window_getMonitor(win);
3878 if (mon == NULL) return RGFW_FALSE;
3879
3880 if (w) *w = (i32)((float)win->w * mon->pixelRatio);
3881 if (h) *h = (i32)((float)win->h * mon->pixelRatio);
3882
3883 return RGFW_TRUE;
3884}
3885
3886
3887#if defined(RGFW_USE_XDL) && defined(RGFW_X11)
3888 #define XDL_IMPLEMENTATION
3889 #include "XDL.h"
3890#endif
3891
3892#ifndef RGFW_FORCE_INIT
3893RGFW_info _rgfwGlobal;
3894#endif
3895
3896i32 RGFW_init(void) { return RGFW_init_ptr(&_rgfwGlobal); }
3897void RGFW_deinit(void) { RGFW_deinit_ptr(&_rgfwGlobal); }
3898
3899i32 RGFW_initPlatform(void);
3900void RGFW_deinitPlatform(void);
3901
3902i32 RGFW_init_ptr(RGFW_info* info) {
3903 if (info == _RGFW || info == NULL) return 1;
3904
3905 RGFW_setInfo(info);
3906 RGFW_MEMSET(_RGFW, 0, sizeof(RGFW_info));
3907 _RGFW->queueEvents = RGFW_FALSE;
3908 _RGFW->polledEvents = RGFW_FALSE;
3909#ifdef RGFW_WAYLAND
3910 _RGFW->useWaylandBool = RGFW_TRUE;
3911#endif
3912
3913 _RGFW->files = (char**)(void*)_RGFW->filesSrc;
3914 u32 i;
3915 for (i = 0; i < RGFW_MAX_DROPS; i++)
3916 _RGFW->files[i] = (char*)(_RGFW->filesSrc + RGFW_MAX_DROPS + (i * RGFW_MAX_PATH));
3917
3918 _RGFW->monitors.freeList.head = &_RGFW->monitors.data[0];
3919 _RGFW->monitors.freeList.cur = _RGFW->monitors.freeList.head;
3920
3921 for (i = 1; i < RGFW_MAX_MONITORS; i++) {
3922 RGFW_monitorNode* newNode = &_RGFW->monitors.data[i];
3923 _RGFW->monitors.freeList.cur->next = newNode;
3924 _RGFW->monitors.freeList.cur = _RGFW->monitors.freeList.cur->next;
3925 }
3926
3927 _RGFW->monitors.list.head = NULL;
3928 _RGFW->monitors.list.head = NULL;
3929 RGFW_initKeycodes();
3930 i32 out = RGFW_initPlatform();
3931
3932 RGFW_pollMonitors();
3933
3934 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, "global context initialized");
3935
3936 return out;
3937}
3938
3939#ifndef RGFW_EGL
3940void RGFW_unloadEGL(void) { }
3941#endif
3942
3943void RGFW_deinit_ptr(RGFW_info* info) {
3944 if (info == NULL) return;
3945
3946 RGFW_setInfo(info);
3947 RGFW_unloadEGL();
3948 RGFW_deinitPlatform();
3949
3950 _RGFW->root = NULL;
3951 _RGFW->windowCount = 0;
3952 RGFW_setInfo(NULL);
3953 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, "global context deinitialized");
3954}
3955
3956RGFW_window* RGFW_createWindow(const char* name, i32 x, i32 y, i32 w, i32 h, RGFW_windowFlags flags) {
3957 RGFW_window* win = (RGFW_window*)RGFW_ALLOC(sizeof(RGFW_window));
3958 RGFW_ASSERT(win != NULL);
3959 return RGFW_createWindowPtr(name, x, y, w, h, flags, win);
3960}
3961
3962void RGFW_window_close(RGFW_window* win) {
3963 RGFW_ASSERT(win != NULL);
3964 RGFW_window_closePtr(win);
3965 RGFW_FREE(win);
3966}
3967
3968RGFW_window* RGFW_createWindowPtr(const char* name, i32 x, i32 y, i32 w, i32 h, RGFW_windowFlags flags, RGFW_window* win) {
3969 RGFW_ASSERT(win != NULL);
3970 if (name == NULL) name = "\0";
3971
3972 RGFW_MEMSET(win, 0, sizeof(RGFW_window));
3973
3974 if (_RGFW == NULL) RGFW_init();
3975 _RGFW->windowCount++;
3976
3977 /* rect based the requested flags */
3978 if (_RGFW->root == NULL) {
3979 RGFW_setRootWindow(win);
3980 }
3981
3982 /* set and init the new window's data */
3983 win->x = x;
3984 win->y = y;
3985 win->w = w;
3986 win->h = h;
3987 win->internal.flags = flags;
3988 win->internal.enabledEvents = RGFW_allEventFlags;
3989
3990 RGFW_window* ret = RGFW_createWindowPlatform(name, flags, win);
3991
3992#ifndef RGFW_X11
3993 RGFW_window_setFlagsInternal(win, flags, 0);
3994#endif
3995
3996#ifdef RGFW_OPENGL
3997 win->src.gfxType = 0;
3998 if (flags & RGFW_windowOpenGL)
3999 RGFW_window_createContext_OpenGL(win, RGFW_getGlobalHints_OpenGL());
4000#endif
4001
4002#ifdef RGFW_EGL
4003 if (flags & RGFW_windowEGL)
4004 RGFW_window_createContext_EGL(win, RGFW_getGlobalHints_OpenGL());
4005#endif
4006
4007 /* X11 creates the window after the OpenGL context is created (because of visual garbage),
4008 * so we have to wait to set the flags
4009 * This is required so that way the user can create their own OpenGL context after RGFW_createWindow is used
4010 * if a window is created, CreateContext will delete the window and create a new one
4011 * */
4012#ifdef RGFW_X11
4013 RGFW_window_setFlagsInternal(win, flags, 0);
4014#endif
4015
4016#ifdef RGFW_MACOS
4017 /*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 */
4018 RGFW_osx_initView(win);
4019#endif
4020
4021#ifdef RGFW_WAYLAND
4022 /* recieve all events needed to configure the surface */
4023 /* also gets the wl_outputs */
4024 if (RGFW_usingWayland()) {
4025 wl_display_roundtrip(_RGFW->wl_display);
4026 /* NOTE: this is a hack so that way wayland spawns a window, even if nothing is drawn */
4027 if (!(flags & RGFW_windowOpenGL) && !(flags & RGFW_windowEGL)) {
4028 u8* data = (u8*)RGFW_ALLOC((u32)(win->w * win->h * 3));
4029 RGFW_MEMSET(data, 0, (u32)(win->w * win->h * 3) * sizeof(u8));
4030 RGFW_surface* surface = RGFW_createSurface(data, win->w, win->h, RGFW_formatBGR8);
4031 RGFW_window_blitSurface(win, surface);
4032 RGFW_FREE(data);
4033 RGFW_surface_free(surface);
4034 }
4035 }
4036#endif
4037
4038 if (!(flags & RGFW_windowHideMouse)) {
4039 RGFW_window_setMouseDefault(win);
4040 }
4041
4042 RGFW_window_setName(win, name);
4043 if (!(flags & RGFW_windowHide)) {
4044 flags |= RGFW_windowHide;
4045 RGFW_window_show(win);
4046 }
4047
4048 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, "a new window was created");
4049
4050 return ret;
4051}
4052
4053void RGFW_window_closePtr(RGFW_window* win) {
4054 RGFW_ASSERT(win != NULL);
4055
4056 if (win->internal.captureMouse) {
4057 RGFW_window_captureMouse(win, RGFW_FALSE);
4058 }
4059
4060 #ifdef RGFW_EGL
4061 if ((win->src.gfxType & RGFW_gfxEGL) && win->src.ctx.egl) {
4062 RGFW_window_deleteContext_EGL(win, win->src.ctx.egl);
4063 win->src.ctx.egl = NULL;
4064 }
4065 #endif
4066
4067 #ifdef RGFW_OPENGL
4068 if ((win->src.gfxType & RGFW_gfxNativeOpenGL) && win->src.ctx.native) {
4069 RGFW_window_deleteContext_OpenGL(win, win->src.ctx.native);
4070 win->src.ctx.native = NULL;
4071 }
4072 #endif
4073
4074 RGFW_window_closePlatform(win);
4075
4076 RGFW_clipboard_switch(NULL);
4077
4078 _RGFW->windowCount--;
4079 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, "a window was freed");
4080
4081 if (_RGFW->windowCount == 0 && !(win->internal.flags & RGFW_noDeinitOnClose)) RGFW_deinit();
4082}
4083
4084void RGFW_setQueueEvents(RGFW_bool queue) { _RGFW->queueEvents = RGFW_BOOL(queue); }
4085
4086void RGFW_eventQueueFlush(void) { _RGFW->eventLen = 0; }
4087
4088void RGFW_eventQueuePush(const RGFW_event* event) {
4089 if (_RGFW->queueEvents == RGFW_FALSE) return;
4090 RGFW_ASSERT(_RGFW->eventLen >= 0);
4091
4092 if (_RGFW->eventLen >= RGFW_MAX_EVENTS) {
4093 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errEventQueue, "Event queue limit 'RGFW_MAX_EVENTS' has been reached automatically flushing queue.");
4094 RGFW_eventQueueFlush();
4095 return;
4096 }
4097
4098 i32 eventTop = (_RGFW->eventBottom + _RGFW->eventLen) % RGFW_MAX_EVENTS;
4099 _RGFW->eventLen += 1;
4100 _RGFW->events[eventTop] = *event;
4101}
4102
4103RGFW_event* RGFW_eventQueuePop(void) {
4104 RGFW_ASSERT(_RGFW->eventLen >= 0 && _RGFW->eventLen <= RGFW_MAX_EVENTS);
4105 RGFW_event* ev;
4106
4107 if (_RGFW->eventLen == 0) {
4108 return NULL;
4109 }
4110
4111 ev = &_RGFW->events[_RGFW->eventBottom];
4112 _RGFW->eventLen -= 1;
4113 _RGFW->eventBottom = (_RGFW->eventBottom + 1) % RGFW_MAX_EVENTS;
4114
4115 return ev;
4116}
4117
4118RGFW_bool RGFW_checkEvent(RGFW_event* event) {
4119 if (_RGFW->eventLen == 0 && _RGFW->polledEvents == RGFW_FALSE) {
4120 _RGFW->queueEvents = RGFW_TRUE;
4121 RGFW_pollEvents();
4122 _RGFW->polledEvents = RGFW_TRUE;
4123 }
4124
4125 if (RGFW_checkQueuedEvent(event) == RGFW_FALSE) {
4126 _RGFW->polledEvents = RGFW_FALSE;
4127 return RGFW_FALSE;
4128 }
4129
4130 return RGFW_TRUE;
4131}
4132
4133RGFW_bool RGFW_checkQueuedEvent(RGFW_event* event) {
4134 RGFW_event* ev;
4135 _RGFW->queueEvents = RGFW_TRUE;
4136 /* check queued events */
4137 ev = RGFW_eventQueuePop();
4138 if (ev != NULL) {
4139 *event = *ev;
4140 return RGFW_TRUE;
4141 }
4142
4143 return RGFW_FALSE;
4144}
4145
4146void RGFW_resetPrevState(void) {
4147 size_t i; /*!< reset each previous state */
4148 for (i = 0; i < RGFW_keyLast; i++) _RGFW->keyboard[i].prev = _RGFW->keyboard[i].current;
4149 for (i = 0; i < RGFW_mouseFinal; i++) _RGFW->mouseButtons[i].prev = _RGFW->mouseButtons[i].current;
4150 _RGFW->scrollX = 0.0f;
4151 _RGFW->scrollY = 0.0f;
4152 _RGFW->vectorX = (float)0.0f;
4153 _RGFW->vectorY = (float)0.0f;
4154 RGFW_MEMSET(&_RGFW->windowState, 0, sizeof(_RGFW->windowState));
4155}
4156
4157RGFW_bool RGFW_isKeyPressed(RGFW_key key) {
4158 RGFW_ASSERT(_RGFW != NULL);
4159 return _RGFW->keyboard[key].current && !_RGFW->keyboard[key].prev;
4160}
4161RGFW_bool RGFW_isKeyDown(RGFW_key key) {
4162 RGFW_ASSERT(_RGFW != NULL);
4163 return _RGFW->keyboard[key].current;
4164}
4165RGFW_bool RGFW_isKeyReleased(RGFW_key key) {
4166 RGFW_ASSERT(_RGFW != NULL);
4167 return !_RGFW->keyboard[key].current && _RGFW->keyboard[key].prev;
4168}
4169
4170
4171RGFW_bool RGFW_isMousePressed(RGFW_mouseButton button) {
4172 RGFW_ASSERT(_RGFW != NULL);
4173 return _RGFW->mouseButtons[button].current && !_RGFW->mouseButtons[button].prev;
4174}
4175RGFW_bool RGFW_isMouseDown(RGFW_mouseButton button) {
4176 RGFW_ASSERT(_RGFW != NULL);
4177 return _RGFW->mouseButtons[button].current;
4178}
4179RGFW_bool RGFW_isMouseReleased(RGFW_mouseButton button) {
4180 RGFW_ASSERT(_RGFW != NULL);
4181 return !_RGFW->mouseButtons[button].current && _RGFW->mouseButtons[button].prev;
4182}
4183
4184void RGFW_getMouseScroll(float* x, float* y) {
4185 RGFW_ASSERT(_RGFW != NULL);
4186 if (x) *x = _RGFW->scrollX;
4187 if (y) *y = _RGFW->scrollY;
4188}
4189
4190void RGFW_getMouseVector(float* x, float* y) {
4191 RGFW_ASSERT(_RGFW != NULL);
4192 if (x) *x = _RGFW->vectorX;
4193 if (y) *y = _RGFW->vectorY;
4194}
4195
4196RGFW_bool RGFW_window_didMouseLeave(RGFW_window* win) { return _RGFW->windowState.winLeave == win && _RGFW->windowState.mouseLeave; }
4197RGFW_bool RGFW_window_didMouseEnter(RGFW_window* win) { return _RGFW->windowState.win == win && _RGFW->windowState.mouseEnter; }
4198RGFW_bool RGFW_window_isMouseInside(RGFW_window* win) { return win->internal.mouseInside; }
4199
4200RGFW_bool RGFW_window_isDataDragging(RGFW_window* win) { return RGFW_window_getDataDrag(win, (i32*)NULL, (i32*)NULL); }
4201RGFW_bool RGFW_window_didDataDrop(RGFW_window* win) { return RGFW_window_getDataDrop(win, (const char***)NULL, (size_t*)NULL);}
4202
4203
4204RGFW_bool RGFW_window_getDataDrag(RGFW_window* win, i32* x, i32* y) {
4205 if (_RGFW->windowState.win != win || _RGFW->windowState.dataDragging == RGFW_FALSE) return RGFW_FALSE;
4206 if (x) *x = _RGFW->windowState.dropX;
4207 if (y) *y = _RGFW->windowState.dropY;
4208 return RGFW_TRUE;
4209}
4210RGFW_bool RGFW_window_getDataDrop(RGFW_window* win, const char*** files, size_t* count) {
4211 if (_RGFW->windowState.win != win || _RGFW->windowState.dataDrop == RGFW_FALSE) return RGFW_FALSE;
4212 if (files) *files = (const char**)_RGFW->files;
4213 if (count) *count = _RGFW->windowState.filesCount;
4214 return RGFW_TRUE;
4215}
4216
4217RGFW_bool RGFW_window_checkEvent(RGFW_window* win, RGFW_event* event) {
4218 if (_RGFW->eventLen == 0 && _RGFW->polledEvents == RGFW_FALSE) {
4219 _RGFW->queueEvents = RGFW_TRUE;
4220 RGFW_pollEvents();
4221 _RGFW->polledEvents = RGFW_TRUE;
4222 }
4223
4224 if (RGFW_window_checkQueuedEvent(win, event) == RGFW_FALSE) {
4225 _RGFW->polledEvents = RGFW_FALSE;
4226 return RGFW_FALSE;
4227 }
4228
4229 return RGFW_TRUE;
4230}
4231
4232RGFW_bool RGFW_window_checkQueuedEvent(RGFW_window* win, RGFW_event* event) {
4233 RGFW_event* ev;
4234 RGFW_ASSERT(win != NULL);
4235 _RGFW->queueEvents = RGFW_TRUE;
4236 /* check queued events */
4237 ev = RGFW_window_eventQueuePop(win);
4238 if (ev == NULL) return RGFW_FALSE;
4239
4240 *event = *ev;
4241 return RGFW_TRUE;
4242}
4243
4244RGFW_event* RGFW_window_eventQueuePop(RGFW_window* win) {
4245 RGFW_event* ev = RGFW_eventQueuePop();
4246 if (ev == NULL) return ev;
4247
4248 for (i32 i = 1; i < _RGFW->eventLen && ev->common.win != win && ev->common.win != NULL; i++) {
4249 RGFW_eventQueuePush(ev);
4250 ev = RGFW_eventQueuePop();
4251 }
4252
4253 if (ev->common.win != win && ev->common.win != NULL) {
4254 return NULL;
4255 }
4256
4257 return ev;
4258}
4259
4260void RGFW_setRootWindow(RGFW_window* win) { _RGFW->root = win; }
4261RGFW_window* RGFW_getRootWindow(void) { return _RGFW->root; }
4262
4263#ifndef RGFW_EGL
4264RGFW_bool RGFW_loadEGL(void) { return RGFW_FALSE; }
4265#endif
4266
4267void RGFW_window_setFlagsInternal(RGFW_window* win, RGFW_windowFlags flags, RGFW_windowFlags cmpFlags) {
4268 if (flags & RGFW_windowNoBorder) RGFW_window_setBorder(win, 0);
4269 else if (cmpFlags & RGFW_windowNoBorder) RGFW_window_setBorder(win, 1);
4270 if (flags & RGFW_windowScaleToMonitor) RGFW_window_scaleToMonitor(win);
4271 if (flags & RGFW_windowMaximize) RGFW_window_maximize(win);
4272 else if (cmpFlags & RGFW_windowMaximize) RGFW_window_restore(win);
4273 if (flags & RGFW_windowMinimize) RGFW_window_minimize(win);
4274 else if (cmpFlags & RGFW_windowMinimize) RGFW_window_restore(win);
4275 if (flags & RGFW_windowCenter) RGFW_window_center(win);
4276 if (flags & RGFW_windowCenterCursor) RGFW_window_moveMouse(win, win->x + (win->w / 2), win->y + (win->h / 2));
4277 if (flags & RGFW_windowFullscreen) RGFW_window_setFullscreen(win, RGFW_TRUE);
4278 else if (cmpFlags & RGFW_windowFullscreen) RGFW_window_setFullscreen(win, 0);
4279 if (flags & RGFW_windowHideMouse) RGFW_window_showMouse(win, 0);
4280 else if (cmpFlags & RGFW_windowHideMouse) RGFW_window_showMouse(win, 1);
4281 if (flags & RGFW_windowHide) RGFW_window_hide(win);
4282 else if (cmpFlags & RGFW_windowHide) RGFW_window_show(win);
4283 if (flags & RGFW_windowFloating) RGFW_window_setFloating(win, 1);
4284 else if (cmpFlags & RGFW_windowFloating) RGFW_window_setFloating(win, 0);
4285 if (flags & RGFW_windowRawMouse) RGFW_window_setRawMouseMode(win, RGFW_TRUE);
4286 else if (cmpFlags & RGFW_windowRawMouse) RGFW_window_setRawMouseMode(win, RGFW_FALSE);
4287 if (flags & RGFW_windowCaptureMouse) RGFW_window_captureRawMouse(win, RGFW_TRUE);
4288 else if (cmpFlags & RGFW_windowCaptureMouse) RGFW_window_captureMouse(win, RGFW_FALSE);
4289 if (flags & RGFW_windowFocus) RGFW_window_focus(win);
4290
4291 if (flags & RGFW_windowNoResize) {
4292 RGFW_window_setMaxSize(win, win->w, win->h);
4293 RGFW_window_setMinSize(win, win->w, win->h);
4294 } else if (cmpFlags & RGFW_windowNoResize) {
4295 RGFW_window_setMaxSize(win, 0, 0);
4296 RGFW_window_setMinSize(win, 0, 0);
4297 }
4298
4299 win->internal.flags = flags;
4300}
4301
4302
4303void RGFW_window_setFlags(RGFW_window* win, RGFW_windowFlags flags) { RGFW_window_setFlagsInternal(win, flags, win->internal.flags); }
4304
4305RGFW_bool RGFW_window_isInFocus(RGFW_window* win) {
4306#ifdef RGFW_WASM
4307 return RGFW_TRUE;
4308#else
4309 return RGFW_BOOL(win->internal.inFocus);
4310#endif
4311}
4312
4313void RGFW_setClassName(const char* name) { RGFW_init(); _RGFW->className = name; }
4314
4315#ifndef RGFW_X11
4316void RGFW_setXInstName(const char* name) { RGFW_UNUSED(name); }
4317#endif
4318
4319RGFW_bool RGFW_window_getMouse(RGFW_window* win, i32* x, i32* y) {
4320 RGFW_ASSERT(win != NULL);
4321 if (x) *x = win->internal.lastMouseX;
4322 if (y) *y = win->internal.lastMouseY;
4323 return RGFW_TRUE;
4324}
4325
4326RGFW_bool RGFW_window_isKeyPressed(RGFW_window* win, RGFW_key key) { return RGFW_isKeyPressed(key) && RGFW_window_isInFocus(win); }
4327RGFW_bool RGFW_window_isKeyDown(RGFW_window* win, RGFW_key key) { return RGFW_isKeyDown(key) && RGFW_window_isInFocus(win); }
4328RGFW_bool RGFW_window_isKeyReleased(RGFW_window* win, RGFW_key key) { return RGFW_isKeyReleased(key) && RGFW_window_isInFocus(win); }
4329
4330RGFW_bool RGFW_window_isMousePressed(RGFW_window* win, RGFW_mouseButton button) { return RGFW_isMousePressed(button) && RGFW_window_isInFocus(win); }
4331RGFW_bool RGFW_window_isMouseDown(RGFW_window* win, RGFW_mouseButton button) { return RGFW_isMouseDown(button) && RGFW_window_isInFocus(win); }
4332RGFW_bool RGFW_window_isMouseReleased(RGFW_window* win, RGFW_mouseButton button) { return RGFW_isMouseReleased(button) && RGFW_window_isInFocus(win); }
4333
4334
4335
4336#ifndef RGFW_X11
4337void* RGFW_getDisplay_X11(void) { return NULL; }
4338u64 RGFW_window_getWindow_X11(RGFW_window* win) { RGFW_UNUSED(win); return 0; }
4339#endif
4340
4341#ifndef RGFW_WAYLAND
4342struct wl_display* RGFW_getDisplay_Wayland(void) { return NULL; }
4343struct wl_surface* RGFW_window_getWindow_Wayland(RGFW_window* win) { RGFW_UNUSED(win); return NULL; }
4344#endif
4345
4346#ifndef RGFW_WINDOWS
4347void* RGFW_window_getHWND(RGFW_window* win) { RGFW_UNUSED(win); return NULL; }
4348void* RGFW_window_getHDC(RGFW_window* win) { RGFW_UNUSED(win); return NULL; }
4349#endif
4350
4351#ifndef RGFW_MACOS
4352void* RGFW_window_getView_OSX(RGFW_window* win) { RGFW_UNUSED(win); return NULL; }
4353void RGFW_window_setLayer_OSX(RGFW_window* win, void* layer) { RGFW_UNUSED(win); RGFW_UNUSED(layer); }
4354void* RGFW_getLayer_OSX(void) { return NULL; }
4355void* RGFW_window_getWindow_OSX(RGFW_window* win) { RGFW_UNUSED(win); return NULL; }
4356#endif
4357
4358void RGFW_setBit(u32* var, u32 mask, RGFW_bool set) {
4359 if (set) *var |= mask;
4360 else *var &= ~mask;
4361}
4362
4363void RGFW_window_center(RGFW_window* win) {
4364 RGFW_ASSERT(win != NULL);
4365 RGFW_monitor* mon = RGFW_window_getMonitor(win);
4366 if (mon == NULL) return;
4367
4368 RGFW_window_move(win, (i32)(mon->mode.w - win->w) / 2, (mon->mode.h - win->h) / 2);
4369}
4370
4371RGFW_bool RGFW_monitor_scaleToWindow(RGFW_monitor* mon, RGFW_window* win) {
4372 RGFW_monitorMode mode;
4373 RGFW_ASSERT(win != NULL);
4374
4375 mode.w = win->w;
4376 mode.h = win->h;
4377 RGFW_bool ret = RGFW_monitor_requestMode(mon, &mode, RGFW_monitorScale);
4378
4379
4380 /* move window to monitor origin so it doesn't move to the next monitor */
4381 RGFW_window_move(win, mon->x, mon->y);
4382
4383 return ret;
4384}
4385
4386void RGFW_splitBPP(u32 bpp, RGFW_monitorMode* mode) {
4387 if (bpp == 32) bpp = 24;
4388 mode->red = mode->green = mode->blue = (u8)(bpp / 3);
4389
4390 u32 delta = bpp - (mode->red * 3); /* handle leftovers */
4391 if (delta >= 1) mode->green = mode->green + 1;
4392 if (delta == 2) mode->red = mode->red + 1;
4393}
4394
4395RGFW_bool RGFW_monitorModeCompare(RGFW_monitorMode* mon, RGFW_monitorMode* mon2, RGFW_modeRequest request) {
4396 RGFW_ASSERT(mon);
4397 RGFW_ASSERT(mon2);
4398
4399 return (((mon->w == mon2->w && mon->h == mon2->h) || !(request & RGFW_monitorScale)) &&
4400 ((mon->refreshRate == mon2->refreshRate) || !(request & RGFW_monitorRefresh)) &&
4401 ((mon->red == mon2->red && mon->green == mon2->green && mon->blue == mon2->blue) || !(request & RGFW_monitorRGB)));
4402}
4403
4404RGFW_bool RGFW_window_shouldClose(RGFW_window* win) {
4405 return (win == NULL || win->internal.shouldClose || (win->internal.exitKey && RGFW_window_isKeyDown(win, win->internal.exitKey)));
4406}
4407
4408void RGFW_window_setShouldClose(RGFW_window* win, RGFW_bool shouldClose) {
4409 if (shouldClose) {
4410 RGFW_windowQuitCallback(win);
4411 } else {
4412 win->internal.shouldClose = RGFW_FALSE;
4413 }
4414}
4415
4416void RGFW_window_scaleToMonitor(RGFW_window* win) {
4417 RGFW_monitor* monitor = RGFW_window_getMonitor(win);
4418 if (monitor->scaleX == 0 && monitor->scaleY == 0)
4419 return;
4420
4421 RGFW_window_resize(win, (i32)(monitor->scaleX * (float)win->w), (i32)(monitor->scaleY * (float)win->h));
4422}
4423
4424void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor* m) {
4425 RGFW_window_move(win, m->x + win->x, m->y + win->y);
4426}
4427
4428RGFW_surface* RGFW_createSurface(u8* data, i32 w, i32 h, RGFW_format format) {
4429 RGFW_surface* surface = (RGFW_surface*)RGFW_ALLOC(sizeof(RGFW_surface));
4430 RGFW_MEMSET(surface, 0, sizeof(RGFW_surface));
4431 RGFW_createSurfacePtr(data, w, h, format, surface);
4432 return surface;
4433}
4434
4435void RGFW_surface_setConvertFunc(RGFW_surface* surface, RGFW_convertImageDataFunc func) {
4436 surface->convertFunc = func;
4437}
4438
4439void RGFW_surface_free(RGFW_surface* surface) {
4440 RGFW_surface_freePtr(surface);
4441 RGFW_FREE(surface);
4442}
4443
4444RGFW_nativeImage* RGFW_surface_getNativeImage(RGFW_surface* surface) {
4445 return &surface->native;
4446}
4447
4448RGFW_surface* RGFW_window_createSurface(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format) {
4449 RGFW_surface* surface = (RGFW_surface*)RGFW_ALLOC(sizeof(RGFW_surface));
4450 RGFW_MEMSET(surface, 0, sizeof(RGFW_surface));
4451 RGFW_window_createSurfacePtr(win, data, w, h, format, surface);
4452 return surface;
4453}
4454
4455#ifndef RGFW_X11
4456RGFW_bool RGFW_window_createSurfacePtr(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) {
4457 RGFW_UNUSED(win);
4458 return RGFW_createSurfacePtr(data, w, h, format, surface);
4459}
4460#endif
4461
4462const RGFW_colorLayout RGFW_layouts[RGFW_formatCount] = {
4463 { 0, 1, 2, 3, 3 }, /* RGFW_formatRGB8 */
4464 { 2, 1, 0, 3, 3 }, /* RGFW_formatBGR8 */
4465 { 0, 1, 2, 3, 4 }, /* RGFW_formatRGBA8 */
4466 { 1, 2, 3, 0, 4 }, /* RGFW_formatARGB8 */
4467 { 2, 1, 0, 3, 4 }, /* RGFW_formatBGRA8 */
4468 { 3, 2, 1, 0, 4 }, /* RGFW_formatABGR8 */
4469};
4470
4471
4472void RGFW_copyImageData(u8* dest_data, i32 w, i32 h, RGFW_format dest_format, u8* src_data, RGFW_format src_format, RGFW_convertImageDataFunc func) {
4473 RGFW_copyImageData64(dest_data, w, h, dest_format, src_data, src_format, RGFW_FALSE, func);
4474}
4475
4476RGFWDEF void RGFW_convertImageData64(u8* dest_data, u8* src_data, const RGFW_colorLayout* srcLayout, const RGFW_colorLayout* destLayout, size_t count, RGFW_bool is64bit);
4477void RGFW_convertImageData64(u8* dest_data, u8* src_data, const RGFW_colorLayout* srcLayout, const RGFW_colorLayout* destLayout, size_t count, RGFW_bool is64bit) {
4478 u32 i, i2 = 0;
4479 u8 rgba[4] = {0};
4480
4481 for (i = 0; i < count; i++) {
4482 const u8* src_px = &src_data[i * srcLayout->channels];
4483 u8* dst_px = &dest_data[i2 * destLayout->channels];
4484 rgba[0] = src_px[srcLayout->r];
4485 rgba[1] = src_px[srcLayout->g];
4486 rgba[2] = src_px[srcLayout->b];
4487 rgba[3] = (srcLayout->channels == 4) ? src_px[srcLayout->a] : 255;
4488
4489 dst_px[destLayout->r] = rgba[0];
4490 dst_px[destLayout->g] = rgba[1];
4491 dst_px[destLayout->b] = rgba[2];
4492 if (destLayout->channels == 4)
4493 dst_px[destLayout->a] = rgba[3];
4494
4495 i2 += 1 + is64bit;
4496 }
4497}
4498
4499void 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) {
4500 RGFW_ASSERT(dest_data && src_data);
4501
4502 u32 count = (u32)(dest_w * dest_h);
4503
4504 if (src_format == dest_format) {
4505 u32 channels = (dest_format >= RGFW_formatRGBA8) ? 4 : 3;
4506 RGFW_MEMCPY(dest_data, src_data, count * channels);
4507 return;
4508 }
4509
4510 const RGFW_colorLayout* srcLayout = &RGFW_layouts[src_format];
4511 const RGFW_colorLayout* destLayout = &RGFW_layouts[dest_format];
4512
4513 if (is64bit || func == NULL) {
4514 RGFW_convertImageData64(dest_data, src_data, srcLayout, destLayout, count, is64bit);
4515 } else {
4516 func(dest_data, src_data, srcLayout, destLayout, count);
4517 }
4518}
4519
4520RGFW_monitorNode* RGFW_monitors_add(const RGFW_monitor* mon) {
4521 RGFW_monitorNode* node = NULL;
4522 if (_RGFW->monitors.freeList.head == NULL) return node;
4523
4524 node = _RGFW->monitors.freeList.head;
4525
4526 _RGFW->monitors.freeList.head = node->next;
4527 if (_RGFW->monitors.freeList.head == NULL) {
4528 _RGFW->monitors.freeList.cur = NULL;
4529 }
4530
4531 node->next = NULL;
4532
4533 if (_RGFW->monitors.list.head == NULL) {
4534 _RGFW->monitors.list.head = node;
4535 } else {
4536 _RGFW->monitors.list.cur->next = node;
4537 }
4538
4539 _RGFW->monitors.list.cur = node;
4540
4541 if (mon) node->mon = *mon;
4542 node->mon.node = node;
4543 node->disconnected = RGFW_FALSE;
4544
4545 _RGFW->monitors.count += 1;
4546 return node;
4547}
4548
4549void RGFW_monitors_remove(RGFW_monitorNode* node, RGFW_monitorNode* prev) {
4550 _RGFW->monitors.count -= 1;
4551
4552 /* remove node from the list */
4553 if (prev != node) {
4554 prev->next = node->next;
4555 } else { /* node is the head */
4556 _RGFW->monitors.list.head = NULL;
4557 }
4558
4559 node->next = NULL;
4560
4561 /* move node to the free list */
4562 if (_RGFW->monitors.freeList.head == NULL) {
4563 _RGFW->monitors.freeList.head = node;
4564 } else {
4565 _RGFW->monitors.freeList.cur->next = node;
4566 }
4567
4568 _RGFW->monitors.freeList.cur = node;
4569}
4570
4571void RGFW_monitors_refresh(void) {
4572 RGFW_monitorNode* prev = _RGFW->monitors.list.head;
4573 for (RGFW_monitorNode* node = _RGFW->monitors.list.head; node; node = node->next) {
4574 if (node->disconnected == RGFW_FALSE) continue;
4575
4576 RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_FALSE);
4577 RGFW_monitors_remove(node, prev);
4578 prev = node;
4579 }
4580}
4581
4582RGFW_monitorMode* RGFW_monitor_getModes(RGFW_monitor* monitor, size_t* count) {
4583 size_t num = RGFW_monitor_getModesPtr(monitor, NULL);
4584 RGFW_monitorMode* modes = (RGFW_monitorMode*)RGFW_ALLOC(num * sizeof(RGFW_monitorNode));
4585 num = RGFW_monitor_getModesPtr(monitor, &modes);
4586
4587 if (count) *count = num;
4588 return modes;
4589}
4590
4591void RGFW_freeModes(RGFW_monitorMode* modes) {
4592 RGFW_FREE(modes);
4593}
4594
4595RGFW_bool RGFW_monitor_findClosestMode(RGFW_monitor* monitor, RGFW_monitorMode* mode, RGFW_monitorMode* closest) {
4596 size_t count = RGFW_monitor_getModesPtr(monitor, NULL);
4597 RGFW_monitorMode* modes = (RGFW_monitorMode*)RGFW_ALLOC(count * sizeof(RGFW_monitorNode));
4598 count = RGFW_monitor_getModesPtr(monitor, &modes);
4599
4600 RGFW_monitorMode* chosen = NULL;
4601
4602 u32 topScore = 1;
4603 for (size_t i = 0; i < count; i++) {
4604 RGFW_monitorMode* mode2 = &modes[i];
4605
4606 u32 score = 0;
4607 if (mode->w == mode2->w && mode->h == mode2->h) score += 1000;
4608 if (mode->red == mode2->red && mode->green == mode2->green && mode->blue == mode2->blue) score += 100;
4609 if (mode->refreshRate == mode->refreshRate) score += 10;
4610
4611 if (score > topScore) {
4612 topScore = score;
4613 chosen = mode2;
4614 }
4615 }
4616
4617 if (chosen && closest) *closest = *chosen;
4618
4619
4620 RGFW_FREE(modes);
4621
4622 return (chosen == NULL) ? RGFW_FALSE : RGFW_TRUE;
4623}
4624
4625RGFW_bool RGFW_monitor_getPosition(RGFW_monitor* monitor, i32* x, i32* y) {
4626 if (x) *x = monitor->x;
4627 if (y) *y = monitor->y;
4628 return RGFW_TRUE;
4629}
4630
4631const char* RGFW_monitor_getName(RGFW_monitor* monitor) {
4632 return monitor->name;
4633}
4634
4635RGFW_bool RGFW_monitor_getScale(RGFW_monitor* monitor, float* x, float* y) {
4636 if (x) *x = monitor->scaleX;
4637 if (y) *y = monitor->scaleY;
4638 return RGFW_TRUE;
4639}
4640
4641RGFW_bool RGFW_monitor_getPhysicalSize(RGFW_monitor* monitor, float* w, float* h) {
4642 if (w) *w = monitor->physW;
4643 if (h) *h = monitor->physH;
4644 return RGFW_TRUE;
4645}
4646
4647void RGFW_monitor_setUserPtr(RGFW_monitor* monitor, void* userPtr) {
4648 monitor->userPtr = userPtr;
4649}
4650
4651void* RGFW_monitor_getUserPtr(RGFW_monitor* monitor) {
4652 return monitor->userPtr;
4653}
4654
4655RGFW_bool RGFW_monitor_getMode(RGFW_monitor* monitor, RGFW_monitorMode* mode) {
4656 if (mode) *mode = monitor->mode;
4657 return RGFW_TRUE;
4658}
4659
4660RGFW_gammaRamp* RGFW_monitor_getGammaRamp(RGFW_monitor* monitor) {
4661 RGFW_gammaRamp* ramp = (RGFW_gammaRamp*)RGFW_ALLOC(sizeof(RGFW_gammaRamp));
4662 ramp->count = RGFW_monitor_getGammaRampPtr(monitor, NULL);
4663 ramp->red = (u16*)RGFW_ALLOC(sizeof(u16) * ramp->count);
4664 ramp->green = (u16*)RGFW_ALLOC(sizeof(u16) * ramp->count);
4665 ramp->blue = (u16*)RGFW_ALLOC(sizeof(u16) * ramp->count);
4666 ramp->count = RGFW_monitor_getGammaRampPtr(monitor, ramp);
4667
4668 return ramp;
4669}
4670
4671void RGFW_freeGammaRamp(RGFW_gammaRamp* ramp) {
4672 RGFW_FREE(ramp->red);
4673 RGFW_FREE(ramp->green);
4674 RGFW_FREE(ramp->blue);
4675 RGFW_FREE(ramp);
4676}
4677
4678RGFW_bool RGFW_monitor_setGammaPtr(RGFW_monitor* monitor, float gamma, u16* ptr, size_t count) {
4679 RGFW_ASSERT(monitor);
4680 RGFW_ASSERT(gamma > 0.0f);
4681
4682 size_t i;
4683 for (i = 0; i < count; i++) {
4684 float value = (float)i / (float) (count - 1);
4685 #ifndef RGFW_NO_MATH
4686 value = powf(value, 1.f / gamma) * 65535.f + 0.5f;
4687 #endif
4688 value = RGFW_MIN(value, 65535.f);
4689
4690 ptr[i] = (u16)value;
4691 }
4692
4693 RGFW_gammaRamp ramp;
4694 ramp.red = ptr;
4695 ramp.green = ptr;
4696 ramp.blue = ptr;
4697 ramp.count = count;
4698
4699 return RGFW_monitor_setGammaRamp(monitor, &ramp);
4700}
4701
4702RGFW_bool RGFW_monitor_setGamma(RGFW_monitor* monitor, float gamma) {
4703 size_t count = RGFW_monitor_getGammaRampPtr(monitor, NULL);
4704 u16* ptr = (u16*)RGFW_ALLOC(count * sizeof(u16));
4705
4706 RGFW_bool ret = RGFW_monitor_setGammaPtr(monitor, gamma, ptr, count);
4707 RGFW_FREE(ptr);
4708
4709 return ret;
4710}
4711
4712RGFW_monitor** RGFW_getMonitors(size_t* len) {
4713 static RGFW_monitor* monitors[RGFW_MAX_MONITORS];
4714 RGFW_init();
4715 if (len != NULL) {
4716 *len = _RGFW->monitors.count;
4717 }
4718
4719 u8 i = 0;
4720 RGFW_monitorNode* cur_node = _RGFW->monitors.list.head;
4721 while (cur_node != NULL) {
4722 monitors[i] = &cur_node->mon;
4723 i++;
4724 cur_node = cur_node->next;
4725 }
4726 return monitors;
4727}
4728
4729RGFW_monitor* RGFW_getPrimaryMonitor(void) {
4730 if (_RGFW->monitors.primary == NULL) {
4731 _RGFW->monitors.primary = _RGFW->monitors.list.head;
4732 }
4733
4734 return &_RGFW->monitors.primary->mon;
4735}
4736
4737RGFW_bool RGFW_window_setIcon(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format) {
4738 return RGFW_window_setIconEx(win, data, w, h, format, RGFW_iconBoth);
4739}
4740
4741void RGFW_window_captureMouse(RGFW_window* win, RGFW_bool state) {
4742 win->internal.captureMouse = state;
4743 RGFW_window_captureMousePlatform(win, state);
4744}
4745
4746void RGFW_window_setRawMouseMode(RGFW_window* win, RGFW_bool state) {
4747 win->internal.rawMouse = state;
4748 RGFW_window_setRawMouseModePlatform(win, state);
4749}
4750
4751void RGFW_window_captureRawMouse(RGFW_window* win, RGFW_bool state) {
4752 RGFW_window_captureMouse(win, state);
4753 RGFW_window_setRawMouseMode(win, state);
4754}
4755
4756RGFW_bool RGFW_window_isRawMouseMode(RGFW_window* win) { return RGFW_BOOL(win->internal.rawMouse); }
4757RGFW_bool RGFW_window_isCaptured(RGFW_window* win) { return RGFW_BOOL(win->internal.captureMouse); }
4758
4759void RGFW_updateKeyMod(RGFW_window* win, RGFW_keymod mod, RGFW_bool value) {
4760 if (value) win->internal.mod |= mod;
4761 else win->internal.mod &= ~mod;
4762}
4763
4764void RGFW_updateKeyModsEx(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll) {
4765 RGFW_updateKeyMod(win, RGFW_modCapsLock, capital);
4766 RGFW_updateKeyMod(win, RGFW_modNumLock, numlock);
4767 RGFW_updateKeyMod(win, RGFW_modControl, control);
4768 RGFW_updateKeyMod(win, RGFW_modAlt, alt);
4769 RGFW_updateKeyMod(win, RGFW_modShift, shift);
4770 RGFW_updateKeyMod(win, RGFW_modSuper, super);
4771 RGFW_updateKeyMod(win, RGFW_modScrollLock, scroll);
4772}
4773
4774void RGFW_updateKeyMods(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool scroll) {
4775 RGFW_updateKeyModsEx(win, capital, numlock,
4776 RGFW_window_isKeyDown(win, RGFW_controlL) || RGFW_window_isKeyDown(win, RGFW_controlR),
4777 RGFW_window_isKeyDown(win, RGFW_altL) || RGFW_window_isKeyDown(win, RGFW_altR),
4778 RGFW_window_isKeyDown(win, RGFW_shiftL) || RGFW_window_isKeyDown(win, RGFW_shiftR),
4779 RGFW_window_isKeyDown(win, RGFW_superL) || RGFW_window_isKeyDown(win, RGFW_superR),
4780 scroll);
4781}
4782
4783void RGFW_window_showMouseFlags(RGFW_window* win, RGFW_bool show) {
4784 if (show && (win->internal.flags & RGFW_windowHideMouse))
4785 win->internal.flags ^= RGFW_windowHideMouse;
4786 else if (!show && !(win->internal.flags & RGFW_windowHideMouse))
4787 win->internal.flags |= RGFW_windowHideMouse;
4788}
4789
4790RGFW_bool RGFW_window_isMouseHidden(RGFW_window* win) {
4791 return (RGFW_bool)RGFW_BOOL(((RGFW_window*)win)->internal.flags & RGFW_windowHideMouse);
4792}
4793
4794RGFW_bool RGFW_window_borderless(RGFW_window* win) {
4795 return (RGFW_bool)RGFW_BOOL(win->internal.flags & RGFW_windowNoBorder);
4796}
4797
4798RGFW_bool RGFW_window_isFullscreen(RGFW_window* win){ return RGFW_BOOL(win->internal.flags & RGFW_windowFullscreen); }
4799RGFW_bool RGFW_window_allowsDND(RGFW_window* win) { return RGFW_BOOL(win->internal.flags & RGFW_windowAllowDND); }
4800
4801#ifndef RGFW_WINDOWS
4802void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow) {
4803 RGFW_setBit(&win->internal.flags, RGFW_windowAllowDND, allow);
4804}
4805#endif
4806
4807#if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WASM) || defined(RGFW_WAYLAND)
4808#ifndef __USE_POSIX199309
4809 #define __USE_POSIX199309
4810#endif
4811#include <time.h>
4812struct timespec;
4813#endif
4814
4815#if defined(RGFW_WAYLAND) || defined(RGFW_X11) || defined(RGFW_WINDOWS)
4816void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) {
4817 RGFW_window_showMouseFlags(win, show);
4818 if (show == RGFW_FALSE)
4819 RGFW_window_setMouse(win, _RGFW->hiddenMouse);
4820 else
4821 RGFW_window_setMouseDefault(win);
4822}
4823#endif
4824
4825#ifndef RGFW_MACOS
4826void RGFW_moveToMacOSResourceDir(void) { }
4827#endif
4828
4829RGFWDEF RGFW_bool RGFW_isLatin(const char *string, size_t length);
4830RGFW_bool RGFW_isLatin(const char *string, size_t length) {
4831 for (size_t i = 0; i < length; i++) {
4832 if ((u8)string[i] >= 0x80) {
4833 return RGFW_TRUE;
4834 }
4835 }
4836 return RGFW_FALSE;
4837}
4838
4839RGFWDEF u32 RGFW_decodeUTF8(const char* string, size_t* starting_index);
4840u32 RGFW_decodeUTF8(const char* string, size_t* starting_index) {
4841 static const u32 offsets[] = {
4842 0x00000000u, 0x00003080u, 0x000e2080u,
4843 0x03c82080u, 0xfa082080u, 0x82082080u
4844 };
4845
4846 u32 codepoint = (u8)string[(*starting_index)];
4847 size_t count;
4848 for (count = 1; (string[count + (*starting_index)] & 0xc0) == 0x80; count++) {
4849 codepoint = (codepoint << 6) + (u8)string[count + (*starting_index)];
4850 }
4851
4852 *starting_index += count;
4853
4854 RGFW_ASSERT(count <= 6);
4855 return codepoint - offsets[count - 1];
4856}
4857
4858/*
4859 graphics API specific code (end of generic code)
4860 starts here
4861*/
4862
4863
4864/*
4865 OpenGL defines start here (Normal, EGL, OSMesa)
4866*/
4867
4868#if defined(RGFW_OPENGL)
4869/* EGL, OpenGL */
4870#define RGFW_DEFAULT_GL_HINTS { \
4871 /* Stencil */ 0, \
4872 /* Samples */ 0, \
4873 /* Stereo */ RGFW_FALSE, \
4874 /* AuxBuffers */ 0, \
4875 /* DoubleBuffer */ RGFW_TRUE, \
4876 /* Red */ 8, \
4877 /* Green */ 8, \
4878 /* Blue */ 8, \
4879 /* Alpha */ 8, \
4880 /* Depth */ 24, \
4881 /* AccumRed */ 0, \
4882 /* AccumGreen */ 0, \
4883 /* AccumBlue */ 0, \
4884 /* AccumAlpha */ 0, \
4885 /* SRGB */ RGFW_FALSE, \
4886 /* Robustness */ RGFW_FALSE, \
4887 /* Debug */ RGFW_FALSE, \
4888 /* NoError */ RGFW_FALSE, \
4889 /* ReleaseBehavior */ RGFW_glReleaseNone, \
4890 /* Profile */ RGFW_glCore, \
4891 /* Major */ 1, \
4892 /* Minor */ 0, \
4893 /* Share */ NULL, \
4894 /* Share_EGL */ NULL, \
4895 /* renderer */ RGFW_glAccelerated \
4896}
4897
4898RGFW_glHints RGFW_globalHints_OpenGL_SRC = RGFW_DEFAULT_GL_HINTS;
4899RGFW_glHints* RGFW_globalHints_OpenGL = &RGFW_globalHints_OpenGL_SRC;
4900
4901void RGFW_resetGlobalHints_OpenGL(void) {
4902#if !defined(__cplusplus) || defined(RGFW_MACOS)
4903 RGFW_globalHints_OpenGL_SRC = (RGFW_glHints)RGFW_DEFAULT_GL_HINTS;
4904#else
4905 RGFW_globalHints_OpenGL_SRC = RGFW_DEFAULT_GL_HINTS;
4906#endif
4907}
4908void RGFW_setGlobalHints_OpenGL(RGFW_glHints* hints) { RGFW_globalHints_OpenGL = hints; }
4909RGFW_glHints* RGFW_getGlobalHints_OpenGL(void) { RGFW_init(); return RGFW_globalHints_OpenGL; }
4910
4911
4912void* RGFW_glContext_getSourceContext(RGFW_glContext* ctx) {
4913 RGFW_UNUSED(ctx);
4914
4915#ifdef RGFW_WAYLAND
4916 if (RGFW_usingWayland()) return (void*)ctx->egl.ctx;
4917#endif
4918
4919#if defined(RGFW_X11)
4920 return (void*)ctx->ctx;
4921#else
4922 return NULL;
4923#endif
4924}
4925
4926RGFW_glContext* RGFW_window_createContext_OpenGL(RGFW_window* win, RGFW_glHints* hints) {
4927 #ifdef RGFW_WAYLAND
4928 if (RGFW_usingWayland()) {
4929 return (RGFW_glContext*)RGFW_window_createContext_EGL(win, hints);
4930 }
4931 #endif
4932 RGFW_glContext* ctx = (RGFW_glContext*)RGFW_ALLOC(sizeof(RGFW_glContext));
4933 if (RGFW_window_createContextPtr_OpenGL(win, ctx, hints) == RGFW_FALSE) {
4934 RGFW_FREE(ctx);
4935 win->src.ctx.native = NULL;
4936 return NULL;
4937 }
4938 win->src.gfxType |= RGFW_gfxOwnedByRGFW;
4939 return ctx;
4940}
4941
4942RGFW_glContext* RGFW_window_getContext_OpenGL(RGFW_window* win) {
4943 if (win->src.gfxType & RGFW_windowEGL) return NULL;
4944 return win->src.ctx.native;
4945}
4946
4947void RGFW_window_deleteContext_OpenGL(RGFW_window* win, RGFW_glContext* ctx) {
4948 RGFW_window_deleteContextPtr_OpenGL(win, ctx);
4949 if (win->src.gfxType & RGFW_gfxOwnedByRGFW) RGFW_FREE(ctx);
4950}
4951
4952RGFW_bool RGFW_extensionSupportedStr(const char* extensions, const char* ext, size_t len) {
4953 const char *start = extensions;
4954 const char *where;
4955 const char* terminator;
4956
4957 if (extensions == NULL || ext == NULL) {
4958 return RGFW_FALSE;
4959 }
4960
4961 while (ext[len - 1] == '\0' && len > 3) {
4962 len--;
4963 }
4964
4965 where = RGFW_STRSTR(extensions, ext);
4966 while (where) {
4967 terminator = where + len;
4968 if ((where == start || *(where - 1) == ' ') &&
4969 (*terminator == ' ' || *terminator == '\0')) {
4970 return RGFW_TRUE;
4971 }
4972 where = RGFW_STRSTR(terminator, ext);
4973 }
4974
4975 return RGFW_FALSE;
4976}
4977
4978RGFWDEF RGFW_bool RGFW_extensionSupported_base(const char* extension, size_t len);
4979RGFW_bool RGFW_extensionSupported_base(const char* extension, size_t len) {
4980 #ifdef GL_NUM_EXTENSIONS
4981 if (RGFW_globalHints_OpenGL->major >= 3) {
4982 i32 i;
4983
4984 GLint count = 0;
4985
4986 RGFW_proc RGFW_glGetStringi = RGFW_getProcAddress_OpenGL("glGetStringi");
4987 RGFW_proc RGFW_glGetIntegerv = RGFW_getProcAddress_OpenGL("glGetIntegerv");
4988 if (RGFW_glGetIntegerv)
4989 ((void(*)(GLenum, GLint*))RGFW_glGetIntegerv)(GL_NUM_EXTENSIONS, &count);
4990
4991 for (i = 0; RGFW_glGetStringi && i < count; i++) {
4992 const char* en = ((const char* (*)(u32, u32))RGFW_glGetStringi)(GL_EXTENSIONS, (u32)i);
4993 if (en && RGFW_STRNCMP(en, extension, len) == 0) {
4994 return RGFW_TRUE;
4995 }
4996 }
4997 } else
4998#endif
4999 {
5000 RGFW_proc RGFW_glGetString = RGFW_getProcAddress_OpenGL("glGetString");
5001 #define RGFW_GL_EXTENSIONS 0x1F03
5002 if (RGFW_glGetString) {
5003 const char* extensions = ((const char*(*)(u32))RGFW_glGetString)(RGFW_GL_EXTENSIONS);
5004
5005 if ((extensions != NULL) && RGFW_extensionSupportedStr(extensions, extension, len)) {
5006 return RGFW_TRUE;
5007 }
5008 }
5009 }
5010 return RGFW_FALSE;
5011}
5012
5013RGFW_bool RGFW_extensionSupported_OpenGL(const char* extension, size_t len) {
5014 if (RGFW_extensionSupported_base(extension, len)) return RGFW_TRUE;
5015 return RGFW_extensionSupportedPlatform_OpenGL(extension, len);
5016}
5017
5018void RGFW_window_makeCurrentWindow_OpenGL(RGFW_window* win) {
5019 if (win) {
5020 _RGFW->current = win;
5021 }
5022
5023 RGFW_window_makeCurrentContext_OpenGL(win);
5024}
5025
5026RGFW_window* RGFW_getCurrentWindow_OpenGL(void) { return _RGFW->current; }
5027void RGFW_attribStack_init(RGFW_attribStack* stack, i32* attribs, size_t max) { stack->attribs = attribs; stack->count = 0; stack->max = max; }
5028void RGFW_attribStack_pushAttrib(RGFW_attribStack* stack, i32 attrib) {
5029 RGFW_ASSERT(stack->count < stack->max);
5030 stack->attribs[stack->count] = attrib;
5031 stack->count += 1;
5032}
5033void RGFW_attribStack_pushAttribs(RGFW_attribStack* stack, i32 attrib1, i32 attrib2) {
5034 RGFW_attribStack_pushAttrib(stack, attrib1);
5035 RGFW_attribStack_pushAttrib(stack, attrib2);
5036}
5037
5038/* EGL */
5039#ifdef RGFW_EGL
5040#include <EGL/eglplatform.h>
5041#include <EGL/egl.h>
5042
5043PFNEGLINITIALIZEPROC RGFW_eglInitialize;
5044PFNEGLGETCONFIGSPROC RGFW_eglGetConfigs;
5045PFNEGLCHOOSECONFIGPROC RGFW_eglChooseConfig;
5046PFNEGLCREATEWINDOWSURFACEPROC RGFW_eglCreateWindowSurface;
5047PFNEGLCREATECONTEXTPROC RGFW_eglCreateContext;
5048PFNEGLMAKECURRENTPROC RGFW_eglMakeCurrent;
5049PFNEGLGETDISPLAYPROC RGFW_eglGetDisplay;
5050PFNEGLSWAPBUFFERSPROC RGFW_eglSwapBuffers;
5051PFNEGLSWAPINTERVALPROC RGFW_eglSwapInterval;
5052PFNEGLBINDAPIPROC RGFW_eglBindAPI;
5053PFNEGLDESTROYCONTEXTPROC RGFW_eglDestroyContext;
5054PFNEGLTERMINATEPROC RGFW_eglTerminate;
5055PFNEGLDESTROYSURFACEPROC RGFW_eglDestroySurface;
5056PFNEGLGETCURRENTCONTEXTPROC RGFW_eglGetCurrentContext;
5057PFNEGLGETPROCADDRESSPROC RGFW_eglGetProcAddress = NULL;
5058PFNEGLQUERYSTRINGPROC RGFW_eglQueryString;
5059PFNEGLGETCONFIGATTRIBPROC RGFW_eglGetConfigAttrib;
5060
5061#define EGL_SURFACE_MAJOR_VERSION_KHR 0x3098
5062#define EGL_SURFACE_MINOR_VERSION_KHR 0x30fb
5063
5064#ifdef RGFW_WINDOWS
5065 #include <windows.h>
5066#elif defined(RGFW_MACOS) || defined(RGFW_UNIX)
5067 #include <dlfcn.h>
5068#endif
5069
5070#ifdef RGFW_WAYLAND
5071#include <wayland-egl.h>
5072#endif
5073
5074void* RGFW_eglLibHandle = NULL;
5075
5076void* RGFW_getDisplay_EGL(void) { return _RGFW->EGL_display; }
5077void* RGFW_eglContext_getSourceContext(RGFW_eglContext* ctx) { return ctx->ctx; }
5078void* RGFW_eglContext_getSurface(RGFW_eglContext* ctx) { return ctx->surface; }
5079struct wl_egl_window* RGFW_eglContext_wlEGLWindow(RGFW_eglContext* ctx) { return ctx->eglWindow; }
5080
5081RGFW_bool RGFW_loadEGL(void) {
5082 RGFW_init();
5083 if (RGFW_eglGetProcAddress != NULL) {
5084 return RGFW_TRUE;
5085 }
5086
5087#ifndef RGFW_WASM
5088 #ifdef RGFW_WINDOWS
5089 const char* libNames[] = { "libEGL.dll", "EGL.dll" };
5090 #elif defined(RGFW_MACOS) || defined(RGFW_UNIX)
5091 /* Linux and macOS */
5092 const char* libNames[] = {
5093 "libEGL.so.1", /* most common */
5094 "libEGL.so", /* fallback */
5095 "/System/Library/Frameworks/OpenGL.framework/OpenGL" /* fallback for older macOS EGL-like systems */
5096 };
5097 #endif
5098
5099 for (size_t i = 0; i < sizeof(libNames) / sizeof(libNames[0]); i++) {
5100 #ifdef RGFW_WINDOWS
5101 RGFW_eglLibHandle = (void*)LoadLibraryA(libNames[i]);
5102 if (RGFW_eglLibHandle) {
5103 RGFW_eglGetProcAddress = (PFNEGLGETPROCADDRESSPROC)(RGFW_proc)GetProcAddress((HMODULE)RGFW_eglLibHandle, "eglGetProcAddress");
5104 break;
5105 }
5106 #elif defined(RGFW_MACOS) || defined(RGFW_UNIX)
5107 RGFW_eglLibHandle = dlopen(libNames[i], RTLD_LAZY | RTLD_GLOBAL);
5108 if (RGFW_eglLibHandle) {
5109 void* lib = dlsym(RGFW_eglLibHandle, "eglGetProcAddress");
5110 if (lib != NULL) RGFW_MEMCPY(&RGFW_eglGetProcAddress, &lib, sizeof(PFNEGLGETPROCADDRESSPROC));
5111 break;
5112 }
5113 #endif
5114 }
5115
5116 if (!RGFW_eglLibHandle || !RGFW_eglGetProcAddress) {
5117 return RGFW_FALSE;
5118 }
5119
5120 RGFW_eglInitialize = (PFNEGLINITIALIZEPROC) RGFW_eglGetProcAddress("eglInitialize");
5121 RGFW_eglGetConfigs = (PFNEGLGETCONFIGSPROC) RGFW_eglGetProcAddress("eglGetConfigs");
5122 RGFW_eglChooseConfig = (PFNEGLCHOOSECONFIGPROC) RGFW_eglGetProcAddress("eglChooseConfig");
5123 RGFW_eglCreateWindowSurface = (PFNEGLCREATEWINDOWSURFACEPROC) RGFW_eglGetProcAddress("eglCreateWindowSurface");
5124 RGFW_eglCreateContext = (PFNEGLCREATECONTEXTPROC) RGFW_eglGetProcAddress("eglCreateContext");
5125 RGFW_eglMakeCurrent = (PFNEGLMAKECURRENTPROC) RGFW_eglGetProcAddress("eglMakeCurrent");
5126 RGFW_eglGetDisplay = (PFNEGLGETDISPLAYPROC) RGFW_eglGetProcAddress("eglGetDisplay");
5127 RGFW_eglSwapBuffers = (PFNEGLSWAPBUFFERSPROC) RGFW_eglGetProcAddress("eglSwapBuffers");
5128 RGFW_eglSwapInterval = (PFNEGLSWAPINTERVALPROC) RGFW_eglGetProcAddress("eglSwapInterval");
5129 RGFW_eglBindAPI = (PFNEGLBINDAPIPROC) RGFW_eglGetProcAddress("eglBindAPI");
5130 RGFW_eglDestroyContext = (PFNEGLDESTROYCONTEXTPROC) RGFW_eglGetProcAddress("eglDestroyContext");
5131 RGFW_eglTerminate = (PFNEGLTERMINATEPROC) RGFW_eglGetProcAddress("eglTerminate");
5132 RGFW_eglDestroySurface = (PFNEGLDESTROYSURFACEPROC) RGFW_eglGetProcAddress("eglDestroySurface");
5133 RGFW_eglQueryString = (PFNEGLQUERYSTRINGPROC) RGFW_eglGetProcAddress("eglQueryString");
5134 RGFW_eglGetCurrentContext = (PFNEGLGETCURRENTCONTEXTPROC) RGFW_eglGetProcAddress("eglGetCurrentContext");
5135 RGFW_eglGetConfigAttrib = (PFNEGLGETCONFIGATTRIBPROC) RGFW_eglGetProcAddress("eglGetConfigAttrib");
5136
5137#else
5138 RGFW_eglGetProcAddress = eglGetProcAddress;
5139 RGFW_eglInitialize = (PFNEGLINITIALIZEPROC) eglInitialize;
5140 RGFW_eglGetConfigs = (PFNEGLGETCONFIGSPROC) eglGetConfigs;
5141 RGFW_eglChooseConfig = (PFNEGLCHOOSECONFIGPROC) eglChooseConfig;
5142 RGFW_eglCreateWindowSurface = (PFNEGLCREATEWINDOWSURFACEPROC) eglCreateWindowSurface;
5143 RGFW_eglCreateContext = (PFNEGLCREATECONTEXTPROC) eglCreateContext;
5144 RGFW_eglMakeCurrent = (PFNEGLMAKECURRENTPROC) eglMakeCurrent;
5145 RGFW_eglGetDisplay = (PFNEGLGETDISPLAYPROC) eglGetDisplay;
5146 RGFW_eglSwapBuffers = (PFNEGLSWAPBUFFERSPROC) eglSwapBuffers;
5147 RGFW_eglSwapInterval = (PFNEGLSWAPINTERVALPROC) eglSwapInterval;
5148 RGFW_eglBindAPI = (PFNEGLBINDAPIPROC) eglBindAPI;
5149 RGFW_eglDestroyContext = (PFNEGLDESTROYCONTEXTPROC) eglDestroyContext;
5150 RGFW_eglTerminate = (PFNEGLTERMINATEPROC) eglTerminate;
5151 RGFW_eglDestroySurface = (PFNEGLDESTROYSURFACEPROC) eglDestroySurface;
5152 RGFW_eglQueryString = (PFNEGLQUERYSTRINGPROC) eglQueryString;
5153 RGFW_eglGetCurrentContext = (PFNEGLGETCURRENTCONTEXTPROC) eglGetCurrentContext;
5154 RGFW_eglGetConfigAttrib = (PFNEGLGETCONFIGATTRIBPROC)eglGetConfigAttrib;
5155#endif
5156
5157 RGFW_bool out = RGFW_BOOL(RGFW_eglInitialize!= NULL &&
5158 RGFW_eglGetConfigs!= NULL &&
5159 RGFW_eglChooseConfig!= NULL &&
5160 RGFW_eglCreateWindowSurface!= NULL &&
5161 RGFW_eglCreateContext!= NULL &&
5162 RGFW_eglMakeCurrent!= NULL &&
5163 RGFW_eglGetDisplay!= NULL &&
5164 RGFW_eglSwapBuffers!= NULL &&
5165 RGFW_eglSwapInterval != NULL &&
5166 RGFW_eglBindAPI!= NULL &&
5167 RGFW_eglDestroyContext!= NULL &&
5168 RGFW_eglTerminate!= NULL &&
5169 RGFW_eglDestroySurface!= NULL &&
5170 RGFW_eglQueryString != NULL &&
5171 RGFW_eglGetCurrentContext != NULL &&
5172 RGFW_eglGetConfigAttrib != NULL);
5173
5174 if (out) {
5175 #ifdef RGFW_WINDOWS
5176 HDC dc = GetDC(NULL);
5177 _RGFW->EGL_display = RGFW_eglGetDisplay((EGLNativeDisplayType) dc);
5178 ReleaseDC(NULL, dc);
5179 #elif defined(RGFW_WAYLAND)
5180 if (_RGFW->useWaylandBool)
5181 _RGFW->EGL_display = RGFW_eglGetDisplay((EGLNativeDisplayType) _RGFW->wl_display);
5182 else
5183 #endif
5184 #ifdef RGFW_X11
5185 _RGFW->EGL_display = RGFW_eglGetDisplay((EGLNativeDisplayType) _RGFW->display);
5186 #else
5187 {}
5188 #endif
5189 #if !defined(RGFW_WAYLAND) && !defined(RGFW_WINDOWS) && !defined(RGFW_X11)
5190 _RGFW->EGL_display = RGFW_eglGetDisplay(EGL_DEFAULT_DISPLAY);
5191 #endif
5192 }
5193
5194 RGFW_eglInitialize(_RGFW->EGL_display, NULL, NULL);
5195 return out;
5196}
5197
5198
5199void RGFW_unloadEGL(void) {
5200 if (!RGFW_eglLibHandle) return;
5201 RGFW_eglTerminate(_RGFW->EGL_display);
5202 #ifdef RGFW_WINDOWS
5203 FreeLibrary((HMODULE)RGFW_eglLibHandle);
5204 #elif defined(RGFW_MACOS) || defined(RGFW_UNIX)
5205 dlclose(RGFW_eglLibHandle);
5206 #endif
5207
5208 RGFW_eglLibHandle = NULL;
5209 RGFW_eglGetProcAddress = NULL;
5210}
5211
5212RGFW_bool RGFW_window_createContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ctx, RGFW_glHints* hints) {
5213 if (RGFW_loadEGL() == RGFW_FALSE) return RGFW_FALSE;
5214 win->src.ctx.egl = ctx;
5215 win->src.gfxType = RGFW_gfxEGL;
5216
5217#ifdef RGFW_WAYLAND
5218 if (_RGFW->useWaylandBool)
5219 win->src.ctx.egl->eglWindow = wl_egl_window_create(win->src.surface, win->w, win->h);
5220#endif
5221
5222 #ifndef EGL_OPENGL_ES1_BIT
5223 #define EGL_OPENGL_ES1_BIT 0x1
5224 #endif
5225
5226 EGLint egl_config[24];
5227
5228 {
5229 RGFW_attribStack stack;
5230 RGFW_attribStack_init(&stack, egl_config, 24);
5231
5232 RGFW_attribStack_pushAttribs(&stack, EGL_SURFACE_TYPE, EGL_WINDOW_BIT);
5233 RGFW_attribStack_pushAttrib(&stack, EGL_RENDERABLE_TYPE);
5234
5235 if (hints->profile == RGFW_glES) {
5236 switch (hints->major) {
5237 case 1: RGFW_attribStack_pushAttrib(&stack, EGL_OPENGL_ES1_BIT); break;
5238 case 2: RGFW_attribStack_pushAttrib(&stack, EGL_OPENGL_ES2_BIT); break;
5239 case 3: RGFW_attribStack_pushAttrib(&stack, EGL_OPENGL_ES3_BIT); break;
5240 default: break;
5241 }
5242 } else {
5243 RGFW_attribStack_pushAttrib(&stack, EGL_OPENGL_BIT);
5244 }
5245
5246 RGFW_attribStack_pushAttribs(&stack, EGL_RED_SIZE, hints->red);
5247 RGFW_attribStack_pushAttribs(&stack, EGL_GREEN_SIZE, hints->green);
5248 RGFW_attribStack_pushAttribs(&stack, EGL_BLUE_SIZE, hints->blue);
5249 RGFW_attribStack_pushAttribs(&stack, EGL_ALPHA_SIZE, hints->alpha);
5250 RGFW_attribStack_pushAttribs(&stack, EGL_DEPTH_SIZE, hints->depth);
5251
5252 RGFW_attribStack_pushAttribs(&stack, EGL_STENCIL_SIZE, hints->stencil);
5253 if (hints->samples) {
5254 RGFW_attribStack_pushAttribs(&stack, EGL_SAMPLE_BUFFERS, 1);
5255 RGFW_attribStack_pushAttribs(&stack, EGL_SAMPLES, hints->samples);
5256 }
5257
5258 RGFW_attribStack_pushAttribs(&stack, EGL_NONE, EGL_NONE);
5259 }
5260
5261 EGLint numConfigs, best_config = -1, best_samples = 0;
5262
5263 RGFW_eglChooseConfig(_RGFW->EGL_display, egl_config, NULL, 0, &numConfigs);
5264 EGLConfig* configs = (EGLConfig*)RGFW_ALLOC(sizeof(EGLConfig) * (u32)numConfigs);
5265
5266 RGFW_eglChooseConfig(_RGFW->EGL_display, egl_config, configs, numConfigs, &numConfigs);
5267
5268#ifdef RGFW_X11
5269 RGFW_bool transparent = (win->internal.flags & RGFW_windowTransparent);
5270 EGLint best_depth = 0;
5271#endif
5272
5273 for (EGLint i = 0; i < numConfigs; i++) {
5274 EGLint visual_id = 0;
5275 EGLint samples = 0;
5276
5277 RGFW_eglGetConfigAttrib(_RGFW->EGL_display, configs[i], EGL_NATIVE_VISUAL_ID, &visual_id);
5278 RGFW_eglGetConfigAttrib(_RGFW->EGL_display, configs[i], EGL_SAMPLES, &samples);
5279
5280 if (best_config == -1) best_config = i;
5281
5282#ifdef RGFW_X11
5283 if (_RGFW->useWaylandBool == RGFW_FALSE) {
5284 XVisualInfo vinfo_template;
5285 vinfo_template.visualid = (VisualID)visual_id;
5286
5287 int num_visuals = 0;
5288 XVisualInfo* vi = XGetVisualInfo(_RGFW->display, VisualIDMask, &vinfo_template, &num_visuals);
5289 if (!vi) continue;
5290 if ((!transparent || vi->depth == 32) && best_depth == 0) {
5291 best_config = i;
5292 best_depth = vi->depth;
5293 }
5294
5295 if ((!(transparent) || vi->depth == 32) && (samples <= hints->samples && samples > best_samples)) {
5296 best_depth = vi->depth;
5297 best_config = i;
5298 best_samples = samples;
5299 XFree(vi);
5300 continue;
5301 }
5302 }
5303#endif
5304
5305 if (samples <= hints->samples && samples > best_samples) {
5306 best_config = i;
5307 best_samples = samples;
5308 }
5309 }
5310
5311 EGLConfig config = configs[best_config];
5312 RGFW_FREE(configs);
5313#ifdef RGFW_X11
5314 if (_RGFW->useWaylandBool == RGFW_FALSE) {
5315 /* This is required so that way the user can create their own OpenGL context after RGFW_createWindow is used */
5316 XVisualInfo* result;
5317 XVisualInfo desired;
5318 EGLint visualID = 0, count = 0;
5319
5320 RGFW_eglGetConfigAttrib(_RGFW->EGL_display, config, EGL_NATIVE_VISUAL_ID, &visualID);
5321 if (visualID) {
5322 desired.visualid = (VisualID)visualID;
5323 result = XGetVisualInfo(_RGFW->display, VisualIDMask, &desired, &count);
5324 } else RGFW_sendDebugInfo(RGFW_typeError, RGFW_errEGLContext, "Failed to fetch a valid EGL VisualID");
5325
5326 if (result == NULL || count == 0) {
5327 if (win->src.window == 0) {
5328 /* try to create a EGL context anyway (this will work if you're not using a NVidia driver) */
5329 win->internal.flags &= ~(u32)RGFW_windowEGL;
5330 RGFW_createWindowPlatform("", win->internal.flags, win);
5331 }
5332 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errEGLContext, "Failed to find a valid visual for the EGL config");
5333 } else {
5334 RGFW_bool showWindow = RGFW_FALSE;
5335 if (win->src.window) {
5336 showWindow = (RGFW_window_isMinimized(win) == RGFW_FALSE);
5337 RGFW_window_closePlatform(win);
5338 }
5339
5340 RGFW_XCreateWindow(*result, "", win->internal.flags, win);
5341
5342 if (showWindow) {
5343 RGFW_window_show(win);
5344 }
5345 XFree(result);
5346 }
5347 }
5348#endif
5349
5350 EGLint surf_attribs[9];
5351
5352 {
5353 RGFW_attribStack stack;
5354 RGFW_attribStack_init(&stack, surf_attribs, 9);
5355
5356 const char present_opaque_str[] = "EGL_EXT_present_opaque";
5357 RGFW_bool opaque_extension_Found = RGFW_extensionSupportedPlatform_EGL(present_opaque_str, sizeof(present_opaque_str));
5358
5359 #ifndef EGL_PRESENT_OPAQUE_EXT
5360 #define EGL_PRESENT_OPAQUE_EXT 0x31df
5361 #endif
5362
5363 #ifndef EGL_GL_COLORSPACE_KHR
5364 #define EGL_GL_COLORSPACE_KHR 0x309D
5365 #ifndef EGL_GL_COLORSPACE_SRGB_KHR
5366 #define EGL_GL_COLORSPACE_SRGB_KHR 0x3089
5367 #endif
5368 #endif
5369
5370 const char gl_colorspace_str[] = "EGL_KHR_gl_colorspace";
5371 RGFW_bool gl_colorspace_Found = RGFW_extensionSupportedPlatform_EGL(gl_colorspace_str, sizeof(gl_colorspace_str));
5372
5373 if (hints->sRGB && gl_colorspace_Found) {
5374 RGFW_attribStack_pushAttribs(&stack, EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR);
5375 }
5376
5377 if (!(win->internal.flags & RGFW_windowTransparent) && opaque_extension_Found)
5378 RGFW_attribStack_pushAttribs(&stack, EGL_PRESENT_OPAQUE_EXT, EGL_TRUE);
5379
5380 if (hints->doubleBuffer == 0) {
5381 RGFW_attribStack_pushAttribs(&stack, EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER);
5382 }
5383
5384 RGFW_attribStack_pushAttribs(&stack, EGL_NONE, EGL_NONE);
5385 }
5386 #if defined(RGFW_MACOS)
5387 void* layer = RGFW_getLayer_OSX();
5388
5389 RGFW_window_setLayer_OSX(win, layer);
5390
5391 win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, config, (EGLNativeWindowType) layer, surf_attribs);
5392 #elif defined(RGFW_WINDOWS)
5393 win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, config, (EGLNativeWindowType) win->src.window, surf_attribs);
5394 #elif defined(RGFW_WAYLAND)
5395 if (_RGFW->useWaylandBool)
5396 win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, config, (EGLNativeWindowType) win->src.ctx.egl->eglWindow, surf_attribs);
5397 else
5398 #endif
5399 #ifdef RGFW_X11
5400 win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, config, (EGLNativeWindowType) win->src.window, surf_attribs);
5401 #else
5402 {}
5403 #endif
5404 #ifdef RGFW_WASM
5405 win->src.ctx.egl->surface = eglCreateWindowSurface(_RGFW->EGL_display, config, 0, 0);
5406 #endif
5407
5408 if (win->src.ctx.egl->surface == NULL) {
5409 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errEGLContext, "Failed to create an EGL surface.");
5410 return RGFW_FALSE;
5411 }
5412
5413 EGLint attribs[20];
5414 {
5415 RGFW_attribStack stack;
5416 RGFW_attribStack_init(&stack, attribs, 20);
5417
5418 if (hints->major || hints->minor) {
5419 RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_MAJOR_VERSION, hints->major);
5420 RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_MINOR_VERSION, hints->minor);
5421 }
5422
5423 if (hints->profile == RGFW_glCore) {
5424 RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT);
5425 } else if (hints->profile == RGFW_glCompatibility) {
5426 RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT);
5427 } else if (hints->profile == RGFW_glForwardCompatibility) {
5428 RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE, EGL_TRUE);
5429 }
5430
5431
5432 RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_ROBUST_ACCESS, hints->robustness);
5433 RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_DEBUG, hints->debug);
5434
5435 #ifndef EGL_CONTEXT_RELEASE_BEHAVIOR_KHR
5436 #define EGL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x2097
5437 #endif
5438
5439 #ifndef EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR
5440 #define EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x2098
5441 #endif
5442
5443 if (hints->releaseBehavior == RGFW_glReleaseFlush) {
5444 RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR);
5445 } else {
5446 RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, 0x0000);
5447 }
5448
5449 RGFW_attribStack_pushAttribs(&stack, EGL_NONE, EGL_NONE);
5450 }
5451
5452 if (hints->profile == RGFW_glES)
5453 RGFW_eglBindAPI(EGL_OPENGL_ES_API);
5454 else
5455 RGFW_eglBindAPI(EGL_OPENGL_API);
5456
5457 win->src.ctx.egl->ctx = RGFW_eglCreateContext(_RGFW->EGL_display, config, hints->shareEGL, attribs);
5458
5459 if (win->src.ctx.egl->ctx == NULL) {
5460 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errEGLContext, "Failed to create an EGL context.");
5461 return RGFW_FALSE;
5462 }
5463
5464 RGFW_eglMakeCurrent(_RGFW->EGL_display, win->src.ctx.egl->surface, win->src.ctx.egl->surface, win->src.ctx.egl->ctx);
5465 RGFW_eglSwapBuffers(_RGFW->EGL_display, win->src.ctx.egl->surface);
5466 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "EGL context initalized.");
5467 return RGFW_TRUE;
5468}
5469
5470RGFW_eglContext* RGFW_window_getContext_EGL(RGFW_window* win) {
5471 if (win->src.gfxType == RGFW_windowOpenGL) return NULL;
5472 return win->src.ctx.egl;
5473}
5474
5475void RGFW_window_deleteContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ctx) {
5476 if (_RGFW->EGL_display == NULL) return;
5477
5478 RGFW_eglDestroySurface(_RGFW->EGL_display, ctx->surface);
5479 RGFW_eglDestroyContext(_RGFW->EGL_display, ctx->ctx);
5480 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "EGL context freed");
5481 #ifdef RGFW_WAYLAND
5482 if (_RGFW->useWaylandBool == RGFW_FALSE) return;
5483 wl_egl_window_destroy(win->src.ctx.egl->eglWindow);
5484 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "EGL window context freed");
5485 #endif
5486 win->src.ctx.egl = NULL;
5487}
5488
5489void RGFW_window_makeCurrentContext_EGL(RGFW_window* win) { if (win) RGFW_ASSERT(win->src.ctx.egl);
5490 if (win == NULL)
5491 RGFW_eglMakeCurrent(_RGFW->EGL_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
5492 else {
5493 RGFW_eglMakeCurrent(_RGFW->EGL_display, win->src.ctx.egl->surface, win->src.ctx.egl->surface, win->src.ctx.egl->ctx);
5494 }
5495}
5496
5497void RGFW_window_swapBuffers_EGL(RGFW_window* win) {
5498 if (RGFW_eglSwapBuffers)
5499 RGFW_eglSwapBuffers(_RGFW->EGL_display, win->src.ctx.egl->surface);
5500 else RGFW_window_swapBuffers_OpenGL(win);
5501}
5502
5503void* RGFW_getCurrentContext_EGL(void) {
5504 return RGFW_eglGetCurrentContext();
5505}
5506
5507RGFW_proc RGFW_getProcAddress_EGL(const char* procname) {
5508 #if defined(RGFW_WINDOWS)
5509 RGFW_proc proc = (RGFW_proc) GetProcAddress(RGFW_wgl_dll, procname);
5510
5511 if (proc)
5512 return proc;
5513 #endif
5514
5515 return (RGFW_proc) RGFW_eglGetProcAddress(procname);
5516}
5517
5518RGFW_bool RGFW_extensionSupportedPlatform_EGL(const char* extension, size_t len) {
5519 if (RGFW_loadEGL() == RGFW_FALSE) return RGFW_FALSE;
5520 const char* extensions = RGFW_eglQueryString(_RGFW->EGL_display, EGL_EXTENSIONS);
5521 return extensions != NULL && RGFW_extensionSupportedStr(extensions, extension, len);
5522}
5523
5524void RGFW_window_swapInterval_EGL(RGFW_window* win, i32 swapInterval) {
5525 RGFW_ASSERT(win != NULL);
5526 RGFW_eglSwapInterval(_RGFW->EGL_display, swapInterval);
5527}
5528
5529RGFW_bool RGFW_extensionSupported_EGL(const char* extension, size_t len) {
5530 if (RGFW_extensionSupported_base(extension, len)) return RGFW_TRUE;
5531 return RGFW_extensionSupportedPlatform_EGL(extension, len);
5532}
5533
5534void RGFW_window_makeCurrentWindow_EGL(RGFW_window* win) {
5535 _RGFW->current = win;
5536 RGFW_window_makeCurrentContext_EGL(win);
5537}
5538
5539RGFW_window* RGFW_getCurrentWindow_EGL(void) { return _RGFW->current; }
5540
5541RGFW_eglContext* RGFW_window_createContext_EGL(RGFW_window* win, RGFW_glHints* hints) {
5542 RGFW_eglContext* ctx = (RGFW_eglContext*)RGFW_ALLOC(sizeof(RGFW_eglContext));
5543 if (RGFW_window_createContextPtr_EGL(win, ctx, hints) == RGFW_FALSE) {
5544 RGFW_FREE(ctx);
5545 win->src.ctx.egl = NULL;
5546 return NULL;
5547 }
5548 win->src.gfxType |= RGFW_gfxOwnedByRGFW;
5549 return ctx;
5550}
5551
5552void RGFW_window_deleteContext_EGL(RGFW_window* win, RGFW_eglContext* ctx) {
5553 RGFW_window_deleteContextPtr_EGL(win, ctx);
5554 if (win->src.gfxType & RGFW_gfxOwnedByRGFW) RGFW_FREE(ctx);
5555}
5556
5557#endif /* RGFW_EGL */
5558
5559/*
5560 end of RGFW_EGL defines
5561*/
5562#endif /* end of RGFW_GL (OpenGL, EGL, OSMesa )*/
5563
5564/*
5565 RGFW_VULKAN defines
5566*/
5567#ifdef RGFW_VULKAN
5568#ifdef RGFW_MACOS
5569#include <objc/message.h>
5570#endif
5571
5572const char** RGFW_getRequiredInstanceExtensions_Vulkan(size_t* count) {
5573 static const char* arr[2] = {VK_KHR_SURFACE_EXTENSION_NAME};
5574 arr[1] = RGFW_VK_SURFACE;
5575 if (count != NULL) *count = 2;
5576
5577 return (const char**)arr;
5578}
5579
5580#ifndef RGFW_MACOS
5581VkResult RGFW_window_createSurface_Vulkan(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface) {
5582 RGFW_ASSERT(win != NULL); RGFW_ASSERT(instance);
5583 RGFW_ASSERT(surface != NULL);
5584
5585 *surface = VK_NULL_HANDLE;
5586
5587#ifdef RGFW_X11
5588
5589 VkXlibSurfaceCreateInfoKHR x11 = { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, 0, 0, (Display*) _RGFW->display, (Window) win->src.window };
5590 return vkCreateXlibSurfaceKHR(instance, &x11, NULL, surface);
5591#endif
5592#if defined(RGFW_WAYLAND)
5593
5594 VkWaylandSurfaceCreateInfoKHR wayland = { VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, 0, 0, (struct wl_display*) _RGFW->wl_display, (struct wl_surface*) win->src.surface };
5595 return vkCreateWaylandSurfaceKHR(instance, &wayland, NULL, surface);
5596#elif defined(RGFW_WINDOWS)
5597 VkWin32SurfaceCreateInfoKHR win32 = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, 0, 0, GetModuleHandle(NULL), (HWND)win->src.window };
5598
5599 return vkCreateWin32SurfaceKHR(instance, &win32, NULL, surface);
5600#endif
5601}
5602#endif
5603
5604RGFW_bool RGFW_getPresentationSupport_Vulkan(VkPhysicalDevice physicalDevice, u32 queueFamilyIndex) {
5605 if (_RGFW == NULL) RGFW_init();
5606#ifdef RGFW_X11
5607
5608 Visual* visual = DefaultVisual(_RGFW->display, DefaultScreen(_RGFW->display));
5609 RGFW_bool out = vkGetPhysicalDeviceXlibPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW->display, XVisualIDFromVisual(visual));
5610 return out;
5611#endif
5612#if defined(RGFW_WAYLAND)
5613
5614 RGFW_bool wlout = vkGetPhysicalDeviceWaylandPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW->wl_display);
5615 return wlout;
5616#elif defined(RGFW_WINDOWS)
5617 RGFW_bool out = vkGetPhysicalDeviceWin32PresentationSupportKHR(physicalDevice, queueFamilyIndex);
5618 return out;
5619#elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11)
5620 RGFW_UNUSED(physicalDevice);
5621 RGFW_UNUSED(queueFamilyIndex);
5622 return RGFW_FALSE; /* TODO */
5623#endif
5624}
5625#endif /* end of RGFW_vulkan */
5626
5627/*
5628This is where OS specific stuff starts
5629*/
5630
5631/* start of unix (wayland or X11 (unix) ) defines */
5632
5633#ifdef RGFW_UNIX
5634#include <fcntl.h>
5635#include <poll.h>
5636#include <unistd.h>
5637
5638void RGFW_stopCheckEvents(void) {
5639
5640 _RGFW->eventWait_forceStop[2] = 1;
5641 while (1) {
5642 const char byte = 0;
5643 const ssize_t result = write(_RGFW->eventWait_forceStop[1], &byte, 1);
5644 if (result == 1 || result == -1)
5645 break;
5646 }
5647}
5648
5649RGFWDEF u64 RGFW_linux_getTimeNS(void);
5650u64 RGFW_linux_getTimeNS(void) {
5651 struct timespec ts;
5652 const u64 scale_factor = 1000000000;
5653 clock_gettime(_RGFW->clock, &ts);
5654 return (u64)ts.tv_sec * scale_factor + (u64)ts.tv_nsec;
5655}
5656
5657void RGFW_waitForEvent(i32 waitMS) {
5658 if (waitMS == 0) return;
5659
5660 if (_RGFW->eventWait_forceStop[0] == 0 || _RGFW->eventWait_forceStop[1] == 0) {
5661 if (pipe(_RGFW->eventWait_forceStop) != -1) {
5662 fcntl(_RGFW->eventWait_forceStop[0], F_GETFL, 0);
5663 fcntl(_RGFW->eventWait_forceStop[0], F_GETFD, 0);
5664 fcntl(_RGFW->eventWait_forceStop[1], F_GETFL, 0);
5665 fcntl(_RGFW->eventWait_forceStop[1], F_GETFD, 0);
5666 }
5667 }
5668
5669 struct pollfd fds[2];
5670 fds[0].fd = 0;
5671 fds[0].events = POLLIN;
5672 fds[0].revents = 0;
5673 fds[1].fd = _RGFW->eventWait_forceStop[0];
5674 fds[1].events = POLLIN;
5675 fds[1].revents = 0;
5676
5677
5678 if (RGFW_usingWayland()) {
5679 #ifdef RGFW_WAYLAND
5680 fds[0].fd = wl_display_get_fd(_RGFW->wl_display);
5681
5682 /* empty the queue */
5683 while (wl_display_prepare_read(_RGFW->wl_display) != 0) {
5684 /* error occured when dispatching the queue */
5685 if (wl_display_dispatch_pending(_RGFW->wl_display) == -1) {
5686 return;
5687 }
5688 }
5689
5690 /* send any pending requests to the compositor */
5691 while (wl_display_flush(_RGFW->wl_display) == -1) {
5692
5693 /* queue is full dispatch them */
5694 if (errno == EAGAIN) {
5695 if (wl_display_dispatch_pending(_RGFW->wl_display) == -1) {
5696 return;
5697 }
5698 } else {
5699 return;
5700 }
5701 }
5702 #endif
5703 } else {
5704 #ifdef RGFW_X11
5705 fds[0].fd = ConnectionNumber(_RGFW->display);
5706 #endif
5707 }
5708
5709
5710 u64 start = RGFW_linux_getTimeNS();
5711 if (RGFW_usingWayland()) {
5712 #ifdef RGFW_WAYLAND
5713 while (wl_display_dispatch_pending(_RGFW->wl_display) == 0) {
5714 if (poll(fds, 1, waitMS) <= 0) {
5715 wl_display_cancel_read(_RGFW->wl_display);
5716 break;
5717 } else {
5718 if (wl_display_read_events(_RGFW->wl_display) == -1)
5719 return;
5720 }
5721
5722 if (waitMS != RGFW_eventWaitNext) {
5723 waitMS -= (i32)(RGFW_linux_getTimeNS() - start) / (i32)1e+6;
5724 }
5725 }
5726
5727 /* queue contains events from read, dispatch them */
5728 if (wl_display_dispatch_pending(_RGFW->wl_display) == -1) {
5729 return;
5730 }
5731 #endif
5732 } else {
5733 #ifdef RGFW_X11
5734 while (XPending(_RGFW->display) == 0) {
5735 if (poll(fds, 1, waitMS) <= 0)
5736 break;
5737
5738 if (waitMS != RGFW_eventWaitNext) {
5739 waitMS -= (i32)(RGFW_linux_getTimeNS() - start) / (i32)1e+6;
5740 }
5741 }
5742 #endif
5743 }
5744
5745 /* drain any data in the stop request */
5746 if (_RGFW->eventWait_forceStop[2]) {
5747 char data[64];
5748 RGFW_MEMSET(data, 0, sizeof(data));
5749 (void)!read(_RGFW->eventWait_forceStop[0], data, sizeof(data));
5750
5751 _RGFW->eventWait_forceStop[2] = 0;
5752 }
5753}
5754
5755char* RGFW_strtok(char* str, const char* delimStr);
5756char* RGFW_strtok(char* str, const char* delimStr) {
5757 static char* static_str = NULL;
5758
5759 if (str != NULL)
5760 static_str = str;
5761
5762 if (static_str == NULL) {
5763 return NULL;
5764 }
5765
5766 while (*static_str != '\0') {
5767 RGFW_bool delim = 0;
5768 const char* d;
5769 for (d = delimStr; *d != '\0'; d++) {
5770 if (*static_str == *d) {
5771 delim = 1;
5772 break;
5773 }
5774 }
5775 if (!delim)
5776 break;
5777 static_str++;
5778 }
5779
5780 if (*static_str == '\0')
5781 return NULL;
5782
5783 char* token_start = static_str;
5784 while (*static_str != '\0') {
5785 int delim = 0;
5786 const char* d;
5787 for (d = delimStr; *d != '\0'; d++) {
5788 if (*static_str == *d) {
5789 delim = 1;
5790 break;
5791 }
5792 }
5793
5794 if (delim) {
5795 *static_str = '\0';
5796 static_str++;
5797 break;
5798 }
5799 static_str++;
5800 }
5801
5802 return token_start;
5803}
5804
5805#ifdef RGFW_X11
5806RGFWDEF i32 RGFW_initPlatform_X11(void);
5807RGFWDEF void RGFW_deinitPlatform_X11(void);
5808#endif
5809#ifdef RGFW_WAYLAND
5810RGFWDEF i32 RGFW_initPlatform_Wayland(void);
5811RGFWDEF void RGFW_deinitPlatform_Wayland(void);
5812#endif
5813
5814RGFWDEF void RGFW_load_X11(void);
5815RGFWDEF void RGFW_load_Wayland(void);
5816
5817#if !defined(RGFW_X11) || !defined(RGFW_WAYLAND)
5818void RGFW_load_X11(void) { }
5819void RGFW_load_Wayland(void) { }
5820#endif
5821
5822/*
5823 * Sadly we have to use magic linux keycodes
5824 * We can't use X11 functions, because that breaks Wayland, but they use the same keycodes so there's no use redeffing them
5825 * We can't use linux enums, because the headers don't exist on BSD
5826 */
5827void RGFW_initKeycodesPlatform(void) {
5828 _RGFW->keycodes[49] = RGFW_backtick;
5829 _RGFW->keycodes[19] = RGFW_0;
5830 _RGFW->keycodes[10] = RGFW_1;
5831 _RGFW->keycodes[11] = RGFW_2;
5832 _RGFW->keycodes[12] = RGFW_3;
5833 _RGFW->keycodes[13] = RGFW_4;
5834 _RGFW->keycodes[14] = RGFW_5;
5835 _RGFW->keycodes[15] = RGFW_6;
5836 _RGFW->keycodes[16] = RGFW_7;
5837 _RGFW->keycodes[17] = RGFW_8;
5838 _RGFW->keycodes[18] = RGFW_9;
5839 _RGFW->keycodes[65] = RGFW_space;
5840 _RGFW->keycodes[38] = RGFW_a;
5841 _RGFW->keycodes[56] = RGFW_b;
5842 _RGFW->keycodes[54] = RGFW_c;
5843 _RGFW->keycodes[40] = RGFW_d;
5844 _RGFW->keycodes[26] = RGFW_e;
5845 _RGFW->keycodes[41] = RGFW_f;
5846 _RGFW->keycodes[42] = RGFW_g;
5847 _RGFW->keycodes[43] = RGFW_h;
5848 _RGFW->keycodes[31] = RGFW_i;
5849 _RGFW->keycodes[44] = RGFW_j;
5850 _RGFW->keycodes[45] = RGFW_k;
5851 _RGFW->keycodes[46] = RGFW_l;
5852 _RGFW->keycodes[58] = RGFW_m;
5853 _RGFW->keycodes[57] = RGFW_n;
5854 _RGFW->keycodes[32] = RGFW_o;
5855 _RGFW->keycodes[33] = RGFW_p;
5856 _RGFW->keycodes[24] = RGFW_q;
5857 _RGFW->keycodes[27] = RGFW_r;
5858 _RGFW->keycodes[39] = RGFW_s;
5859 _RGFW->keycodes[28] = RGFW_t;
5860 _RGFW->keycodes[30] = RGFW_u;
5861 _RGFW->keycodes[55] = RGFW_v;
5862 _RGFW->keycodes[25] = RGFW_w;
5863 _RGFW->keycodes[53] = RGFW_x;
5864 _RGFW->keycodes[29] = RGFW_y;
5865 _RGFW->keycodes[52] = RGFW_z;
5866 _RGFW->keycodes[60] = RGFW_period;
5867 _RGFW->keycodes[59] = RGFW_comma;
5868 _RGFW->keycodes[61] = RGFW_slash;
5869 _RGFW->keycodes[34] = RGFW_bracket;
5870 _RGFW->keycodes[35] = RGFW_closeBracket;
5871 _RGFW->keycodes[47] = RGFW_semicolon;
5872 _RGFW->keycodes[48] = RGFW_apostrophe;
5873 _RGFW->keycodes[51] = RGFW_backSlash;
5874 _RGFW->keycodes[36] = RGFW_return;
5875 _RGFW->keycodes[119] = RGFW_delete;
5876 _RGFW->keycodes[77] = RGFW_numLock;
5877 _RGFW->keycodes[106] = RGFW_kpSlash;
5878 _RGFW->keycodes[63] = RGFW_kpMultiply;
5879 _RGFW->keycodes[86] = RGFW_kpPlus;
5880 _RGFW->keycodes[82] = RGFW_kpMinus;
5881 _RGFW->keycodes[87] = RGFW_kp1;
5882 _RGFW->keycodes[88] = RGFW_kp2;
5883 _RGFW->keycodes[89] = RGFW_kp3;
5884 _RGFW->keycodes[83] = RGFW_kp4;
5885 _RGFW->keycodes[84] = RGFW_kp5;
5886 _RGFW->keycodes[85] = RGFW_kp6;
5887 _RGFW->keycodes[81] = RGFW_kp9;
5888 _RGFW->keycodes[90] = RGFW_kp0;
5889 _RGFW->keycodes[91] = RGFW_kpPeriod;
5890 _RGFW->keycodes[104] = RGFW_kpReturn;
5891 _RGFW->keycodes[20] = RGFW_minus;
5892 _RGFW->keycodes[21] = RGFW_equals;
5893 _RGFW->keycodes[22] = RGFW_backSpace;
5894 _RGFW->keycodes[23] = RGFW_tab;
5895 _RGFW->keycodes[66] = RGFW_capsLock;
5896 _RGFW->keycodes[50] = RGFW_shiftL;
5897 _RGFW->keycodes[37] = RGFW_controlL;
5898 _RGFW->keycodes[64] = RGFW_altL;
5899 _RGFW->keycodes[133] = RGFW_superL;
5900 _RGFW->keycodes[105] = RGFW_controlR;
5901 _RGFW->keycodes[134] = RGFW_superR;
5902 _RGFW->keycodes[62] = RGFW_shiftR;
5903 _RGFW->keycodes[108] = RGFW_altR;
5904 _RGFW->keycodes[67] = RGFW_F1;
5905 _RGFW->keycodes[68] = RGFW_F2;
5906 _RGFW->keycodes[69] = RGFW_F3;
5907 _RGFW->keycodes[70] = RGFW_F4;
5908 _RGFW->keycodes[71] = RGFW_F5;
5909 _RGFW->keycodes[72] = RGFW_F6;
5910 _RGFW->keycodes[73] = RGFW_F7;
5911 _RGFW->keycodes[74] = RGFW_F8;
5912 _RGFW->keycodes[75] = RGFW_F9;
5913 _RGFW->keycodes[76] = RGFW_F10;
5914 _RGFW->keycodes[95] = RGFW_F11;
5915 _RGFW->keycodes[96] = RGFW_F12;
5916 _RGFW->keycodes[111] = RGFW_up;
5917 _RGFW->keycodes[116] = RGFW_down;
5918 _RGFW->keycodes[113] = RGFW_left;
5919 _RGFW->keycodes[114] = RGFW_right;
5920 _RGFW->keycodes[118] = RGFW_insert;
5921 _RGFW->keycodes[115] = RGFW_end;
5922 _RGFW->keycodes[112] = RGFW_pageUp;
5923 _RGFW->keycodes[117] = RGFW_pageDown;
5924 _RGFW->keycodes[9] = RGFW_escape;
5925 _RGFW->keycodes[110] = RGFW_home;
5926 _RGFW->keycodes[78] = RGFW_scrollLock;
5927 _RGFW->keycodes[107] = RGFW_printScreen;
5928 _RGFW->keycodes[128] = RGFW_pause;
5929 _RGFW->keycodes[191] = RGFW_F13;
5930 _RGFW->keycodes[192] = RGFW_F14;
5931 _RGFW->keycodes[193] = RGFW_F15;
5932 _RGFW->keycodes[194] = RGFW_F16;
5933 _RGFW->keycodes[195] = RGFW_F17;
5934 _RGFW->keycodes[196] = RGFW_F18;
5935 _RGFW->keycodes[197] = RGFW_F19;
5936 _RGFW->keycodes[198] = RGFW_F20;
5937 _RGFW->keycodes[199] = RGFW_F21;
5938 _RGFW->keycodes[200] = RGFW_F22;
5939 _RGFW->keycodes[201] = RGFW_F23;
5940 _RGFW->keycodes[202] = RGFW_F24;
5941 _RGFW->keycodes[203] = RGFW_F25;
5942 _RGFW->keycodes[142] = RGFW_kpEqual;
5943 _RGFW->keycodes[161] = RGFW_world1; /* non-US key #1 */
5944 _RGFW->keycodes[162] = RGFW_world2; /* non-US key #2 */
5945}
5946
5947i32 RGFW_initPlatform(void) {
5948 #if defined(_POSIX_MONOTONIC_CLOCK)
5949 struct timespec ts;
5950 RGFW_MEMSET(&ts, 0, sizeof(struct timespec));
5951
5952 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
5953 _RGFW->clock = CLOCK_MONOTONIC;
5954 #else
5955 _RGFW->clock = CLOCK_REALTIME;
5956 #endif
5957
5958#ifdef RGFW_WAYLAND
5959 RGFW_load_Wayland();
5960 i32 ret = RGFW_initPlatform_Wayland();
5961 if (ret == 0) {
5962 return 0;
5963 } else {
5964 #ifdef RGFW_X11
5965 RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningWayland, "Falling back to X11");
5966 RGFW_useWayland(0);
5967 #else
5968 return ret;
5969 #endif
5970 }
5971#endif
5972#ifdef RGFW_X11
5973 RGFW_load_X11();
5974 return RGFW_initPlatform_X11();
5975#else
5976 return 0;
5977#endif
5978}
5979
5980
5981void RGFW_deinitPlatform(void) {
5982 if (_RGFW->eventWait_forceStop[0] || _RGFW->eventWait_forceStop[1]){
5983 close(_RGFW->eventWait_forceStop[0]);
5984 close(_RGFW->eventWait_forceStop[1]);
5985 }
5986#ifdef RGFW_WAYLAND
5987 if (_RGFW->useWaylandBool) {
5988 RGFW_deinitPlatform_Wayland();
5989 return;
5990 }
5991#endif
5992#ifdef RGFW_X11
5993 RGFW_deinitPlatform_X11();
5994#endif
5995}
5996
5997RGFWDEF size_t RGFW_unix_stringlen(const char* name);
5998size_t RGFW_unix_stringlen(const char* name) {
5999 size_t i = 0;
6000 while (name[i]) { i++; }
6001 return i;
6002}
6003
6004#endif /* end of wayland or X11 defines */
6005
6006
6007/*
6008
6009
6010Start of Linux / Unix defines
6011
6012
6013*/
6014
6015#ifdef RGFW_X11
6016#ifdef RGFW_WAYLAND
6017#define RGFW_FUNC(func) func##_X11
6018#else
6019#define RGFW_FUNC(func) func
6020#endif
6021
6022#include <dlfcn.h>
6023#include <unistd.h>
6024
6025#include <limits.h> /* for data limits (mainly used in drag and drop functions) */
6026#include <poll.h>
6027
6028void RGFW_setXInstName(const char* name) { _RGFW->instName = name; }
6029#if !defined(RGFW_NO_X11_CURSOR) && defined(RGFW_X11)
6030 #include <X11/Xcursor/Xcursor.h>
6031#endif
6032
6033#include <X11/Xatom.h>
6034#include <X11/keysymdef.h>
6035#include <X11/extensions/sync.h>
6036
6037#include <X11/XKBlib.h> /* for converting keycode to string */
6038#include <X11/cursorfont.h> /* for hiding */
6039#include <X11/extensions/shapeconst.h>
6040#include <X11/extensions/shape.h>
6041#include <X11/extensions/XInput2.h>
6042
6043#ifdef RGFW_OPENGL
6044 #ifndef __gl_h_
6045 #define __gl_h_
6046 #define RGFW_gl_ndef
6047 #define GLubyte unsigned char
6048 #define GLenum unsigned int
6049 #define GLint int
6050 #define GLuint unsigned int
6051 #define GLsizei int
6052 #define GLfloat float
6053 #define GLvoid void
6054 #define GLbitfield unsigned int
6055 #define GLintptr ptrdiff_t
6056 #define GLsizeiptr ptrdiff_t
6057 #define GLboolean unsigned char
6058 #endif
6059
6060 #include <GL/glx.h> /* GLX defs, xlib.h, gl.h */
6061 #ifndef GLX_MESA_swap_control
6062 #define GLX_MESA_swap_control
6063 #endif
6064
6065 #ifdef RGFW_gl_ndef
6066 #undef __gl_h_
6067 #undef GLubyte
6068 #undef GLenum
6069 #undef GLint
6070 #undef GLuint
6071 #undef GLsizei
6072 #undef GLfloat
6073 #undef GLvoid
6074 #undef GLbitfield
6075 #undef GLintptr
6076 #undef GLsizeiptr
6077 #undef GLboolean
6078 #endif
6079 typedef GLXContext(*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
6080#endif
6081
6082/* atoms needed for drag and drop */
6083#if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD)
6084 typedef XcursorImage* (*PFN_XcursorImageCreate)(int, int);
6085 typedef void (*PFN_XcursorImageDestroy)(XcursorImage*);
6086 typedef Cursor(*PFN_XcursorImageLoadCursor)(Display*, const XcursorImage*);
6087#endif
6088
6089#if !defined(RGFW_NO_X11_XI_PRELOAD)
6090 typedef int (* PFN_XISelectEvents)(Display*,Window,XIEventMask*,int);
6091 PFN_XISelectEvents XISelectEventsSRC = NULL;
6092 #define XISelectEvents XISelectEventsSRC
6093
6094 void* X11Xihandle = NULL;
6095#endif
6096
6097#if !defined(RGFW_NO_X11_EXT_PRELOAD)
6098 typedef void (* PFN_XSyncIntToValue)(XSyncValue*, int);
6099 PFN_XSyncIntToValue XSyncIntToValueSRC = NULL;
6100 #define XSyncIntToValue XSyncIntToValueSRC
6101
6102 typedef Status (* PFN_XSyncSetCounter)(Display*, XSyncCounter, XSyncValue);
6103 PFN_XSyncSetCounter XSyncSetCounterSRC = NULL;
6104 #define XSyncSetCounter XSyncSetCounterSRC
6105
6106 typedef XSyncCounter (* PFN_XSyncCreateCounter)(Display*, XSyncValue);
6107 PFN_XSyncCreateCounter XSyncCreateCounterSRC = NULL;
6108 #define XSyncCreateCounter XSyncCreateCounterSRC
6109
6110 typedef void (* PFN_XShapeCombineMask)(Display*,Window,int,int,int,Pixmap,int);
6111 PFN_XShapeCombineMask XShapeCombineMaskSRC;
6112 #define XShapeCombineMask XShapeCombineMaskSRC
6113
6114 typedef void (* PFN_XShapeCombineRegion)(Display*,Window,int,int,int,Region,int);
6115 PFN_XShapeCombineRegion XShapeCombineRegionSRC;
6116 #define XShapeCombineRegion XShapeCombineRegionSRC
6117 void* X11XEXThandle = NULL;
6118#endif
6119
6120#if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD)
6121 PFN_XcursorImageLoadCursor XcursorImageLoadCursorSRC = NULL;
6122 PFN_XcursorImageCreate XcursorImageCreateSRC = NULL;
6123 PFN_XcursorImageDestroy XcursorImageDestroySRC = NULL;
6124
6125 #define XcursorImageLoadCursor XcursorImageLoadCursorSRC
6126 #define XcursorImageCreate XcursorImageCreateSRC
6127 #define XcursorImageDestroy XcursorImageDestroySRC
6128
6129 void* X11Cursorhandle = NULL;
6130#endif
6131
6132RGFWDEF RGFW_bool RGFW_waitForShowEvent_X11(RGFW_window* win);
6133RGFW_bool RGFW_waitForShowEvent_X11(RGFW_window* win) {
6134 XEvent dummy;
6135 while (!XCheckTypedWindowEvent(_RGFW->display, win->src.window, VisibilityNotify, &dummy)) {
6136 RGFW_waitForEvent(100);
6137 }
6138
6139 return RGFW_TRUE;
6140}
6141
6142RGFWDEF void RGFW_x11_icCallback(XIC ic, char* clientData, char* callData);
6143void RGFW_x11_icCallback(XIC ic, char* clientData, char* callData) {
6144 RGFW_UNUSED(ic); RGFW_UNUSED(callData);
6145 RGFW_window* win = (RGFW_window*)(void*)clientData;
6146 win->src.ic = NULL;
6147}
6148
6149RGFWDEF void RGFW_x11_imCallback(XIM im, char* clientData, char* callData);
6150void RGFW_x11_imCallback(XIM im, char* clientData, char* callData) {
6151 RGFW_UNUSED(im); RGFW_UNUSED(clientData); RGFW_UNUSED(callData);
6152 _RGFW->im = NULL;
6153}
6154
6155RGFWDEF void RGFW_x11_imInitCallback(Display* display, XPointer clientData, XPointer callData);
6156void RGFW_x11_imInitCallback(Display* display, XPointer clientData, XPointer callData) {
6157 RGFW_UNUSED(display); RGFW_UNUSED(clientData); RGFW_UNUSED(callData);
6158
6159 if (_RGFW->im) {
6160 return;
6161 }
6162
6163 _RGFW->im = XOpenIM(_RGFW->display, 0, NULL, NULL);
6164 if (_RGFW->im == NULL) {
6165 return;
6166 }
6167
6168 RGFW_bool found = RGFW_FALSE;
6169 XIMStyles* styles = NULL;
6170
6171 if (XGetIMValues(_RGFW->im, XNQueryInputStyle, &styles, NULL) != NULL) {
6172 found = RGFW_FALSE;
6173 } else {
6174 for (unsigned int i = 0; i < styles->count_styles; i++) {
6175 if (styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing)) {
6176 found = RGFW_TRUE;
6177 break;
6178 }
6179 }
6180
6181 XFree(styles);
6182 }
6183
6184 if (found == RGFW_FALSE) {
6185 XCloseIM(_RGFW->im);
6186 _RGFW->im = NULL;
6187 }
6188
6189 XIMCallback callback;
6190 callback.callback = (XIMProc) RGFW_x11_imCallback;
6191 callback.client_data = NULL;
6192 XSetIMValues(_RGFW->im, XNDestroyCallback, &callback, NULL);
6193}
6194
6195void* RGFW_getDisplay_X11(void) { return _RGFW->display; }
6196u64 RGFW_window_getWindow_X11(RGFW_window* win) { return (u64)win->src.window; }
6197
6198RGFWDEF RGFW_format RGFW_XImage_getFormat(XImage* image);
6199RGFW_format RGFW_XImage_getFormat(XImage* image) {
6200 switch (image->bits_per_pixel) {
6201 case 24:
6202 if (image->red_mask == 0xFF0000 && image->green_mask == 0x00FF00 && image->blue_mask == 0x0000FF)
6203 return RGFW_formatRGB8;
6204 if (image->red_mask == 0x0000FF && image->green_mask == 0x00FF00 && image->blue_mask == 0xFF0000)
6205 return RGFW_formatBGR8;
6206 break;
6207 case 32:
6208 if (image->red_mask == 0x00FF0000 && image->green_mask == 0x0000FF00 && image->blue_mask == 0x000000FF)
6209 return RGFW_formatBGRA8;
6210 if (image->red_mask == 0x000000FF && image->green_mask == 0x0000FF00 && image->blue_mask == 0x00FF0000)
6211 return RGFW_formatRGBA8;
6212 if (image->red_mask == 0x0000FF00 && image->green_mask == 0x00FF0000 && image->blue_mask == 0xFF000000)
6213 return RGFW_formatABGR8;
6214 if (image->red_mask == 0x00FF0000 && image->green_mask == 0x0000FF00 && image->blue_mask == 0x000000FF)
6215 return RGFW_formatARGB8; /* ambiguous without alpha */
6216 break;
6217 }
6218 return RGFW_formatARGB8;
6219}
6220
6221
6222RGFW_bool RGFW_window_createSurfacePtr(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) {
6223 RGFW_ASSERT(surface != NULL);
6224 surface->data = data;
6225 surface->w = w;
6226 surface->h = h;
6227 surface->format = format;
6228
6229 XWindowAttributes attrs;
6230 if (XGetWindowAttributes(_RGFW->display, win->src.window, &attrs) == 0) {
6231 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, "Failed to get window attributes.");
6232 return RGFW_FALSE;
6233 }
6234
6235 surface->native.bitmap = XCreateImage(_RGFW->display, attrs.visual, (u32)attrs.depth,
6236 ZPixmap, 0, NULL, (u32)surface->w, (u32)surface->h, 32, 0);
6237
6238 surface->native.buffer = (u8*)RGFW_ALLOC((size_t)(w * h * 4));
6239 surface->native.format = RGFW_XImage_getFormat(surface->native.bitmap);
6240
6241 if (surface->native.bitmap == NULL) {
6242 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, "Failed to create XImage.");
6243 return RGFW_FALSE;
6244 }
6245
6246 surface->native.format = RGFW_formatBGRA8;
6247 return RGFW_TRUE;
6248}
6249
6250RGFW_format RGFW_FUNC(RGFW_nativeFormat)(void) { return RGFW_formatBGRA8; }
6251
6252RGFW_bool RGFW_FUNC(RGFW_createSurfacePtr) (u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) {
6253 return RGFW_window_createSurfacePtr(_RGFW->root, data, w, h, format, surface);
6254}
6255
6256void RGFW_FUNC(RGFW_window_blitSurface) (RGFW_window* win, RGFW_surface* surface) {
6257 RGFW_ASSERT(surface != NULL);
6258 surface->native.bitmap->data = (char*)surface->native.buffer;
6259 RGFW_copyImageData((u8*)surface->native.buffer, surface->w, RGFW_MIN(win->h, surface->h), surface->native.format, surface->data, surface->format, surface->convertFunc);
6260
6261 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));
6262 surface->native.bitmap->data = NULL;
6263 return;
6264}
6265
6266void RGFW_FUNC(RGFW_surface_freePtr) (RGFW_surface* surface) {
6267 RGFW_ASSERT(surface != NULL);
6268 RGFW_FREE(surface->native.buffer);
6269 XDestroyImage(surface->native.bitmap);
6270 return;
6271}
6272
6273#define RGFW_LOAD_ATOM(name) \
6274 static Atom name = 0; \
6275 if (name == 0) name = XInternAtom(_RGFW->display, #name, False);
6276
6277void RGFW_FUNC(RGFW_window_setBorder) (RGFW_window* win, RGFW_bool border) {
6278 RGFW_setBit(&win->internal.flags, RGFW_windowNoBorder, !border);
6279 RGFW_LOAD_ATOM(_MOTIF_WM_HINTS);
6280
6281 struct __x11WindowHints {
6282 unsigned long flags, functions, decorations, status;
6283 long input_mode;
6284 } hints;
6285 hints.flags = 2;
6286 hints.decorations = border;
6287
6288 XChangeProperty(_RGFW->display, win->src.window, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 32, PropModeReplace, (u8*)&hints, 5);
6289
6290 if (RGFW_window_isHidden(win) == 0) {
6291 RGFW_window_hide(win);
6292 RGFW_window_show(win);
6293 }
6294}
6295
6296void RGFW_FUNC(RGFW_window_setRawMouseModePlatform) (RGFW_window* win, RGFW_bool state) {
6297 RGFW_UNUSED(win); RGFW_UNUSED(state);
6298}
6299
6300void RGFW_FUNC(RGFW_window_captureMousePlatform) (RGFW_window* win, RGFW_bool state) {
6301 if (state) {
6302 unsigned int event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask;
6303 XGrabPointer(_RGFW->display, win->src.window, True, event_mask, GrabModeAsync, GrabModeAsync, win->src.window, None, CurrentTime);
6304 } else {
6305 XUngrabPointer(_RGFW->display, CurrentTime);
6306 }
6307}
6308
6309#define RGFW_LOAD_LIBRARY(x, lib) if (x == NULL) x = dlopen(lib, RTLD_LAZY | RTLD_LOCAL)
6310#define RGFW_PROC_DEF(proc, name) if (name##SRC == NULL && proc != NULL) { \
6311 void* ptr = dlsym(proc, #name); \
6312 if (ptr != NULL) RGFW_MEMCPY(&name##SRC, &ptr, sizeof(PFN_##name)); \
6313}
6314
6315RGFWDEF void RGFW_window_getVisual(XVisualInfo* visual, RGFW_bool transparent);
6316void RGFW_window_getVisual(XVisualInfo* visual, RGFW_bool transparent) {
6317 visual->visual = DefaultVisual(_RGFW->display, DefaultScreen(_RGFW->display));
6318 visual->depth = DefaultDepth(_RGFW->display, DefaultScreen(_RGFW->display));
6319 if (transparent) {
6320 XMatchVisualInfo(_RGFW->display, DefaultScreen(_RGFW->display), 32, TrueColor, visual); /*!< for RGBA backgrounds */
6321 if (visual->depth != 32)
6322 RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, "Failed to load a 32-bit depth.");
6323 }
6324}
6325
6326RGFWDEF int RGFW_XErrorHandler(Display* display, XErrorEvent* ev);
6327int RGFW_XErrorHandler(Display* display, XErrorEvent* ev) {
6328 char errorText[512];
6329 XGetErrorText(display, ev->error_code, errorText, sizeof(errorText));
6330
6331 char buf[1024];
6332 RGFW_SNPRINTF(buf, sizeof(buf), "[X Error] %s\n Error code: %d\n Request code: %d\n Minor code: %d\n Serial: %lu\n",
6333 errorText,
6334 ev->error_code, ev->request_code, ev->minor_code, ev->serial);
6335
6336 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errX11, buf);
6337 _RGFW->x11Error = ev;
6338 return 0;
6339}
6340
6341void RGFW_XCreateWindow (XVisualInfo visual, const char* name, RGFW_windowFlags flags, RGFW_window* win) {
6342 i64 event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | FocusChangeMask |
6343 LeaveWindowMask | EnterWindowMask | ExposureMask | VisibilityChangeMask | PropertyChangeMask;
6344
6345 /* make X window attrubutes */
6346 XSetWindowAttributes swa;
6347 RGFW_MEMSET(&swa, 0, sizeof(swa));
6348
6349 win->src.parent = DefaultRootWindow(_RGFW->display);
6350
6351 Colormap cmap;
6352 swa.colormap = cmap = XCreateColormap(_RGFW->display,
6353 win->src.parent,
6354 visual.visual, AllocNone);
6355 swa.event_mask = event_mask;
6356 swa.background_pixmap = None;
6357
6358 /* create the window */
6359 win->src.window = XCreateWindow(_RGFW->display, win->src.parent, win->x, win->y, (u32)win->w, (u32)win->h,
6360 0, visual.depth, InputOutput, visual.visual,
6361 CWBorderPixel | CWColormap | CWEventMask, &swa);
6362
6363 win->src.flashEnd = 0;
6364
6365 XFreeColors(_RGFW->display, cmap, NULL, 0, 0);
6366
6367 XSaveContext(_RGFW->display, win->src.window, _RGFW->context, (XPointer)win);
6368
6369 win->src.gc = XCreateGC(_RGFW->display, win->src.window, 0, NULL);
6370
6371 if (_RGFW->im) {
6372 XIMCallback callback;
6373 callback.callback = (XIMProc) RGFW_x11_icCallback;
6374 callback.client_data = (XPointer) win;
6375
6376 win->src.ic = XCreateIC(_RGFW->im, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, win->src.window, XNFocusWindow, win->src.window, XNDestroyCallback, &callback, NULL);
6377 }
6378
6379
6380 /* In your .desktop app, if you set the property
6381 StartupWMClass=RGFW that will assoicate the launcher icon
6382 with your application - robrohan */
6383 if (_RGFW->className == NULL)
6384 _RGFW->className = (char*)name;
6385
6386 XClassHint hint;
6387 hint.res_class = (char*)_RGFW->className;
6388
6389 if (_RGFW->instName == NULL) hint.res_name = (char*)name;
6390 else hint.res_name = (char*)_RGFW->instName;
6391
6392 XSetClassHint(_RGFW->display, win->src.window, &hint);
6393
6394 XWMHints hints;
6395 hints.flags = StateHint;
6396 hints.initial_state = NormalState;
6397
6398 XSetWMHints(_RGFW->display, win->src.window, &hints);
6399
6400 if (flags & RGFW_windowScaleToMonitor)
6401 RGFW_window_scaleToMonitor(win);
6402
6403 XSelectInput(_RGFW->display, (Drawable) win->src.window, event_mask); /*!< tell X11 what events we want */
6404
6405 /* make it so the user can't close the window until the program does */
6406 RGFW_LOAD_ATOM(WM_DELETE_WINDOW);
6407 XSetWMProtocols(_RGFW->display, (Drawable) win->src.window, &WM_DELETE_WINDOW, 1);
6408 /* set the background */
6409 RGFW_window_setName(win, name);
6410
6411 XMoveWindow(_RGFW->display, (Drawable) win->src.window, win->x, win->y); /*!< move the window to it's proper cords */
6412
6413 if (flags & RGFW_windowAllowDND) { /* init drag and drop atoms and turn on drag and drop for this window */
6414 win->internal.flags |= RGFW_windowAllowDND;
6415
6416 /* actions */
6417 Atom XdndAware = XInternAtom(_RGFW->display, "XdndAware", False);
6418 const u8 version = 5;
6419
6420 XChangeProperty(_RGFW->display, win->src.window,
6421 XdndAware, 4, 32,
6422 PropModeReplace, &version, 1); /*!< turns on drag and drop */
6423 }
6424
6425#ifdef RGFW_ADVANCED_SMOOTH_RESIZE
6426 RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST_COUNTER)
6427 RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST)
6428
6429 Atom protcols[2] = {_NET_WM_SYNC_REQUEST, WM_DELETE_WINDOW};
6430 XSetWMProtocols(_RGFW->display, win->src.window, protcols, 2);
6431
6432 XSyncValue initial_value;
6433 XSyncIntToValue(&initial_value, 0);
6434 win->src.counter = XSyncCreateCounter(_RGFW->display, initial_value);
6435
6436 XChangeProperty(_RGFW->display, win->src.window, _NET_WM_SYNC_REQUEST_COUNTER, XA_CARDINAL, 32, PropModeReplace, (u8*)&win->src.counter, 1);
6437#endif
6438
6439 win->src.x = win->x;
6440 win->src.y = win->y;
6441 win->src.w = win->w;
6442 win->src.h = win->h;
6443
6444 XSetWindowBackground(_RGFW->display, win->src.window, None);
6445 XClearWindow(_RGFW->display, win->src.window);
6446
6447 /* stupid hack to make resizing the window less bad */
6448 XSetWindowBackgroundPixmap(_RGFW->display, win->src.window, None);
6449}
6450
6451RGFW_window* RGFW_FUNC(RGFW_createWindowPlatform) (const char* name, RGFW_windowFlags flags, RGFW_window* win) {
6452 if ((flags & RGFW_windowOpenGL) || (flags & RGFW_windowEGL)) {
6453 win->src.window = 0;
6454 return win;
6455 }
6456
6457 XVisualInfo visual;
6458 RGFW_window_getVisual(&visual, RGFW_BOOL(win->internal.flags & RGFW_windowTransparent));
6459 RGFW_XCreateWindow(visual, name, flags, win);
6460 return win; /*return newly created window */
6461}
6462
6463RGFW_bool RGFW_FUNC(RGFW_getGlobalMouse) (i32* fX, i32* fY) {
6464 RGFW_init();
6465 i32 x, y;
6466 u32 z;
6467 Window window1, window2;
6468 XQueryPointer(_RGFW->display, XDefaultRootWindow(_RGFW->display), &window1, &window2, fX, fY, &x, &y, &z);
6469 return RGFW_TRUE;
6470}
6471
6472RGFWDEF void RGFW_XHandleClipboardSelection(XEvent* event);
6473void RGFW_XHandleClipboardSelection(XEvent* event) { RGFW_UNUSED(event);
6474 RGFW_LOAD_ATOM(ATOM_PAIR);
6475 RGFW_LOAD_ATOM(MULTIPLE);
6476 RGFW_LOAD_ATOM(TARGETS);
6477 RGFW_LOAD_ATOM(SAVE_TARGETS);
6478 RGFW_LOAD_ATOM(UTF8_STRING);
6479
6480 const XSelectionRequestEvent* request = &event->xselectionrequest;
6481 Atom formats[2] = {0};
6482 formats[0] = UTF8_STRING;
6483 formats[1] = XA_STRING;
6484 const int formatCount = sizeof(formats) / sizeof(formats[0]);
6485
6486 if (request->target == TARGETS) {
6487 Atom targets[4] = {0};
6488 targets[0] = TARGETS;
6489 targets[1] = MULTIPLE;
6490 targets[2] = UTF8_STRING;
6491 targets[3] = XA_STRING;
6492
6493 XChangeProperty(_RGFW->display, request->requestor, request->property,
6494 XA_ATOM, 32, PropModeReplace, (u8*) targets, sizeof(targets) / sizeof(Atom));
6495 } else if (request->target == MULTIPLE) {
6496 Atom* targets = NULL;
6497
6498 Atom actualType = 0;
6499 int actualFormat = 0;
6500 unsigned long count = 0, bytesAfter = 0;
6501
6502 XGetWindowProperty(_RGFW->display, request->requestor, request->property, 0, LONG_MAX,
6503 False, ATOM_PAIR, &actualType, &actualFormat, &count, &bytesAfter, (u8**) &targets);
6504
6505 unsigned long i;
6506 for (i = 0; i < (u32)count; i += 2) {
6507 if (targets[i] == UTF8_STRING || targets[i] == XA_STRING)
6508 XChangeProperty(_RGFW->display, request->requestor, targets[i + 1], targets[i],
6509 8, PropModeReplace, (const unsigned char *)_RGFW->clipboard, (i32)_RGFW->clipboard_len);
6510 else
6511 targets[i + 1] = None;
6512 }
6513
6514 XChangeProperty(_RGFW->display,
6515 request->requestor, request->property, ATOM_PAIR, 32,
6516 PropModeReplace, (u8*) targets, (i32)count);
6517
6518 XFlush(_RGFW->display);
6519 XFree(targets);
6520 } else if (request->target == SAVE_TARGETS)
6521 XChangeProperty(_RGFW->display, request->requestor, request->property, 0, 32, PropModeReplace, NULL, 0);
6522 else {
6523 int i;
6524 for (i = 0; i < formatCount; i++) {
6525 if (request->target != formats[i])
6526 continue;
6527 XChangeProperty(_RGFW->display, request->requestor, request->property, request->target,
6528 8, PropModeReplace, (u8*) _RGFW->clipboard, (i32)_RGFW->clipboard_len);
6529 }
6530 }
6531
6532 XEvent reply = { SelectionNotify };
6533 reply.xselection.property = request->property;
6534 reply.xselection.display = request->display;
6535 reply.xselection.requestor = request->requestor;
6536 reply.xselection.selection = request->selection;
6537 reply.xselection.target = request->target;
6538 reply.xselection.time = request->time;
6539
6540 XSendEvent(_RGFW->display, request->requestor, False, 0, &reply);
6541 XFlush(_RGFW->display);
6542}
6543
6544i32 RGFW_XHandleClipboardSelectionHelper(void);
6545
6546RGFW_key RGFW_FUNC(RGFW_physicalToMappedKey) (RGFW_key key) {
6547 KeyCode keycode = (KeyCode)RGFW_rgfwToApiKey(key);
6548 KeySym sym = XkbKeycodeToKeysym(_RGFW->display, keycode, 0, 0);
6549
6550 if (sym < 256) {
6551 return (RGFW_key)sym;
6552 }
6553
6554 switch (sym) {
6555 case XK_F1: return RGFW_F1;
6556 case XK_F2: return RGFW_F2;
6557 case XK_F3: return RGFW_F3;
6558 case XK_F4: return RGFW_F4;
6559 case XK_F5: return RGFW_F5;
6560 case XK_F6: return RGFW_F6;
6561 case XK_F7: return RGFW_F7;
6562 case XK_F8: return RGFW_F8;
6563 case XK_F9: return RGFW_F9;
6564 case XK_F10: return RGFW_F10;
6565 case XK_F11: return RGFW_F11;
6566 case XK_F12: return RGFW_F12;
6567 case XK_F13: return RGFW_F13;
6568 case XK_F14: return RGFW_F14;
6569 case XK_F15: return RGFW_F15;
6570 case XK_F16: return RGFW_F16;
6571 case XK_F17: return RGFW_F17;
6572 case XK_F18: return RGFW_F18;
6573 case XK_F19: return RGFW_F19;
6574 case XK_F20: return RGFW_F20;
6575 case XK_F21: return RGFW_F21;
6576 case XK_F22: return RGFW_F22;
6577 case XK_F23: return RGFW_F23;
6578 case XK_F24: return RGFW_F24;
6579 case XK_F25: return RGFW_F25;
6580 case XK_Shift_L: return RGFW_shiftL;
6581 case XK_Shift_R: return RGFW_shiftR;
6582 case XK_Control_L: return RGFW_controlL;
6583 case XK_Control_R: return RGFW_controlR;
6584 case XK_Alt_L: return RGFW_altL;
6585 case XK_Alt_R: return RGFW_altR;
6586 case XK_Super_L: return RGFW_superL;
6587 case XK_Super_R: return RGFW_superR;
6588 case XK_Caps_Lock: return RGFW_capsLock;
6589 case XK_Num_Lock: return RGFW_numLock;
6590 case XK_Scroll_Lock:return RGFW_scrollLock;
6591 case XK_Up: return RGFW_up;
6592 case XK_Down: return RGFW_down;
6593 case XK_Left: return RGFW_left;
6594 case XK_Right: return RGFW_right;
6595 case XK_Home: return RGFW_home;
6596 case XK_End: return RGFW_end;
6597 case XK_Page_Up: return RGFW_pageUp;
6598 case XK_Page_Down: return RGFW_pageDown;
6599 case XK_Insert: return RGFW_insert;
6600 case XK_Menu: return RGFW_menu;
6601 case XK_KP_Add: return RGFW_kpPlus;
6602 case XK_KP_Subtract: return RGFW_kpMinus;
6603 case XK_KP_Multiply: return RGFW_kpMultiply;
6604 case XK_KP_Divide: return RGFW_kpSlash;
6605 case XK_KP_Equal: return RGFW_kpEqual;
6606 case XK_KP_Enter: return RGFW_kpReturn;
6607 case XK_KP_Decimal: return RGFW_kpPeriod;
6608 case XK_KP_0: return RGFW_kp0;
6609 case XK_KP_1: return RGFW_kp1;
6610 case XK_KP_2: return RGFW_kp2;
6611 case XK_KP_3: return RGFW_kp3;
6612 case XK_KP_4: return RGFW_kp4;
6613 case XK_KP_5: return RGFW_kp5;
6614 case XK_KP_6: return RGFW_kp6;
6615 case XK_KP_7: return RGFW_kp7;
6616 case XK_KP_8: return RGFW_kp8;
6617 case XK_KP_9: return RGFW_kp9;
6618 case XK_Print: return RGFW_printScreen;
6619 case XK_Pause: return RGFW_pause;
6620 default: break;
6621 }
6622
6623 return RGFW_keyNULL;
6624}
6625
6626RGFWDEF void RGFW_XHandleEvent(void);
6627void RGFW_XHandleEvent(void) {
6628 RGFW_LOAD_ATOM(XdndTypeList);
6629 RGFW_LOAD_ATOM(XdndSelection);
6630 RGFW_LOAD_ATOM(XdndEnter);
6631 RGFW_LOAD_ATOM(XdndPosition);
6632 RGFW_LOAD_ATOM(XdndStatus);
6633 RGFW_LOAD_ATOM(XdndLeave);
6634 RGFW_LOAD_ATOM(XdndDrop);
6635 RGFW_LOAD_ATOM(XdndFinished);
6636 RGFW_LOAD_ATOM(XdndActionCopy);
6637 RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST);
6638 RGFW_LOAD_ATOM(WM_PROTOCOLS);
6639 RGFW_LOAD_ATOM(WM_STATE);
6640 RGFW_LOAD_ATOM(_NET_WM_STATE);
6641
6642 /* xdnd data */
6643 static Window source = 0;
6644 static long version = 0;
6645 static i32 format = 0;
6646
6647 static float deltaX = 0.0f;
6648 static float deltaY = 0.0f;
6649
6650 XEvent reply = { ClientMessage };
6651 XEvent E;
6652
6653 XNextEvent(_RGFW->display, &E);
6654
6655 if (E.type != GenericEvent) {
6656 deltaX = 0.0f;
6657 deltaY = 0.0f;
6658 }
6659
6660#ifndef RGFW_NO_XRANDR
6661 if (E.type == _RGFW->xrandrEventBase + RRNotify) {
6662 RGFW_pollMonitors();
6663 return;
6664 }
6665#endif
6666
6667 switch (E.type) {
6668 case SelectionRequest:
6669 RGFW_XHandleClipboardSelection(&E);
6670 return;
6671 case GenericEvent: {
6672 XGetEventData(_RGFW->display, &E.xcookie);
6673 switch (E.xcookie.evtype) {
6674 case XI_RawMotion: {
6675 XIRawEvent* raw = (XIRawEvent *)E.xcookie.data;
6676 if (raw->valuators.mask_len == 0) {
6677 XFreeEventData(_RGFW->display, &E.xcookie);
6678 return;
6679 }
6680
6681 i32 index = 0;
6682 if (XIMaskIsSet(raw->valuators.mask, 0) != 0) {
6683 deltaX += (float)raw->raw_values[index];
6684 index += 1;
6685 }
6686
6687 if (XIMaskIsSet(raw->valuators.mask, 1) != 0)
6688 deltaY += (float)raw->raw_values[index];
6689
6690 _RGFW->vectorX = (float)deltaX;
6691 _RGFW->vectorY = (float)deltaY;
6692 }
6693 default: break;
6694 }
6695
6696 XFreeEventData(_RGFW->display, &E.xcookie);
6697 return;
6698 }
6699 }
6700
6701 RGFW_window* win = NULL;
6702 if (XFindContext(_RGFW->display, E.xany.window, _RGFW->context, (XPointer*) &win) != 0) {
6703 return;
6704 }
6705
6706 if (win->src.flashEnd) {
6707 if ((win->src.flashEnd <= RGFW_linux_getTimeNS()) || RGFW_window_isInFocus(win)) {
6708 RGFW_window_flash(win, RGFW_flashCancel);
6709 }
6710 }
6711
6712
6713 /*
6714 Repeated key presses are sent as a release followed by another press at the same time.
6715 We want to convert that into a single key press event with the repeat flag set
6716 */
6717
6718 RGFW_bool keyRepeat = RGFW_FALSE;
6719
6720 if (E.type == KeyRelease && XEventsQueued(_RGFW->display, QueuedAfterReading)) {
6721 XEvent NE;
6722 XPeekEvent(_RGFW->display, &NE);
6723 if (NE.type == KeyPress && E.xkey.time == NE.xkey.time && E.xkey.keycode == NE.xkey.keycode) {
6724 /* Use the next KeyPress event */
6725 XNextEvent(_RGFW->display, &E);
6726 keyRepeat = RGFW_TRUE;
6727 }
6728 }
6729
6730 switch (E.type) {
6731 case KeyPress: {
6732 if (!(win->internal.enabledEvents & RGFW_keyPressedFlag)) return;
6733 RGFW_key value = (u8)RGFW_apiKeyToRGFW(E.xkey.keycode);
6734
6735 XkbStateRec state;
6736 XkbGetState(_RGFW->display, XkbUseCoreKbd, &state);
6737 RGFW_updateKeyMods(win, (state.locked_mods & LockMask), (state.locked_mods & Mod2Mask), (state.locked_mods & Mod3Mask));
6738
6739 if (win->src.ic && XFilterEvent(&E, None) == False) {
6740 char buffer[100];
6741 char* chars = buffer;
6742
6743 Status status;
6744 size_t count = (size_t)Xutf8LookupString(win->src.ic, &E.xkey, buffer, sizeof(buffer) - 1, NULL, &status);
6745
6746 if (status == XBufferOverflow) {
6747 chars = (char*)RGFW_ALLOC(count + 1);
6748 count = (size_t)Xutf8LookupString(win->src.ic, &E.xkey, chars, (int)count, NULL, &status);
6749 }
6750
6751 if (status == XLookupChars || status == XLookupBoth) {
6752 chars[count] = '\0';
6753 for (size_t index = 0; index < count;
6754 RGFW_keyCharCallback(win, RGFW_decodeUTF8(&chars[index], &index))
6755 );
6756 }
6757
6758 if (chars != buffer)
6759 RGFW_FREE(chars);
6760 } else {
6761 Window root = DefaultRootWindow(_RGFW->display);
6762 Window ret_root, ret_child;
6763 int root_x, root_y, win_x, win_y;
6764 unsigned int mask;
6765 XQueryPointer(_RGFW->display, root, &ret_root, &ret_child, &root_x, &root_y, &win_x, &win_y, &mask);
6766 KeySym sym = (KeySym)XkbKeycodeToKeysym(_RGFW->display, (KeyCode)E.xkey.keycode, 0, (KeyCode)mask & ShiftMask ? 1 : 0);
6767
6768 if ((mask & LockMask) && sym >= XK_a && sym <= XK_z)
6769 sym = (mask & ShiftMask) ? sym + 32 : sym - 32;
6770 if ((u8)sym != (u32)sym)
6771 sym = 0;
6772
6773 RGFW_keyCharCallback(win, (u8)sym);
6774 }
6775
6776 RGFW_keyCallback(win, value, win->internal.mod, keyRepeat, RGFW_TRUE);
6777 break;
6778 }
6779 case KeyRelease: {
6780 if (!(win->internal.enabledEvents & RGFW_keyReleasedFlag)) return;
6781
6782 RGFW_key value = (u8)RGFW_apiKeyToRGFW(E.xkey.keycode);
6783
6784 XkbStateRec state;
6785 XkbGetState(_RGFW->display, XkbUseCoreKbd, &state);
6786 RGFW_updateKeyMods(win, (state.locked_mods & LockMask), (state.locked_mods & Mod2Mask), (state.locked_mods & Mod3Mask));
6787
6788 RGFW_keyCallback(win, value, win->internal.mod, keyRepeat, RGFW_FALSE);
6789 break;
6790 }
6791 case ButtonPress: {
6792 RGFW_bool scroll = RGFW_FALSE;
6793 if (E.xbutton.button >= Button4 && E.xbutton.button <= 7) {
6794 scroll = RGFW_TRUE;
6795 }
6796
6797 float scrollX = 0.0f;
6798 float scrollY = 0.0f;
6799 RGFW_mouseButton value = 0;
6800
6801 switch (E.xbutton.button) {
6802 case Button1: value = RGFW_mouseLeft; break;
6803 case Button2: value = RGFW_mouseMiddle; break;
6804 case Button3: value = RGFW_mouseRight; break;
6805 case Button4: scrollY = 1.0; break;
6806 case Button5: scrollY = -1.0; break;
6807 case 6: scrollX = 1.0f; break;
6808 case 7: scrollX = -1.0f; break;
6809 default:
6810 value = (u8)E.xbutton.button - Button1 - 4;
6811 break;
6812 }
6813
6814 if (scroll) {
6815 RGFW_mouseScrollCallback(win, scrollX, scrollY);
6816 break;
6817 }
6818
6819 RGFW_mouseButtonCallback(win, value, RGFW_TRUE);
6820 break;
6821 }
6822 case ButtonRelease: {
6823 if (E.xbutton.button >= Button4 && E.xbutton.button <= 7) break;
6824
6825 RGFW_mouseButton value = 0;
6826 switch(E.xbutton.button) {
6827 case Button1: value = RGFW_mouseLeft; break;
6828 case Button2: value = RGFW_mouseMiddle; break;
6829 case Button3: value = RGFW_mouseRight; break;
6830 default:
6831 value = (u8)E.xbutton.button - Button1 - 4;
6832 break;
6833 }
6834
6835 RGFW_mouseButtonCallback(win, value, RGFW_FALSE);
6836 break;
6837 }
6838 case MotionNotify:
6839 RGFW_mousePosCallback(win, E.xmotion.x, E.xmotion.y, _RGFW->vectorX, _RGFW->vectorY);
6840 break;
6841
6842 case Expose: {
6843 RGFW_windowRefreshCallback(win);
6844
6845#ifdef RGFW_ADVANCED_SMOOTH_RESIZE
6846 XSyncValue value;
6847 XSyncIntToValue(&value, (i32)win->src.counter_value);
6848 XSyncSetCounter(_RGFW->display, win->src.counter, value);
6849#endif
6850 break;
6851 }
6852
6853 case PropertyNotify:
6854 if (E.xproperty.state != PropertyNewValue) break;
6855
6856 if (E.xproperty.atom == WM_STATE) {
6857 if (RGFW_window_isMinimized(win) && !(win->internal.flags & RGFW_windowMinimized)) {
6858 RGFW_windowMinimizedCallback(win);
6859 break;
6860 }
6861 } else if (E.xproperty.atom == _NET_WM_STATE) {
6862 if (RGFW_window_isMaximized(win) && !(win->internal.flags & RGFW_windowMaximize)) {
6863 RGFW_windowMaximizedCallback(win, win->x, win->y, win->w, win->h);
6864 break;
6865 }
6866 }
6867
6868 RGFW_window_checkMode(win);
6869 break;
6870 case MapNotify: case UnmapNotify: RGFW_window_checkMode(win); break;
6871 case ClientMessage: {
6872 RGFW_LOAD_ATOM(WM_DELETE_WINDOW);
6873 /* if the client closed the window */
6874 if (E.xclient.data.l[0] == (long)WM_DELETE_WINDOW) {
6875 RGFW_windowQuitCallback(win);
6876 break;
6877 }
6878#ifdef RGFW_ADVANCED_SMOOTH_RESIZE
6879 if (E.xclient.message_type == WM_PROTOCOLS && (Atom)E.xclient.data.l[0] == _NET_WM_SYNC_REQUEST) {
6880 RGFW_windowRefreshCallback(win);
6881 win->src.counter_value = 0;
6882 win->src.counter_value |= E.xclient.data.l[2];
6883 win->src.counter_value |= (E.xclient.data.l[3] << 32);
6884
6885 XSyncValue value;
6886 XSyncIntToValue(&value, (i32)win->src.counter_value);
6887 XSyncSetCounter(_RGFW->display, win->src.counter, value);
6888 break;
6889 }
6890#endif
6891 if ((win->internal.flags & RGFW_windowAllowDND) == 0)
6892 return;
6893
6894 i32 dragX = 0;
6895 i32 dragY = 0;
6896
6897 reply.xclient.window = source;
6898 reply.xclient.format = 32;
6899 reply.xclient.data.l[0] = (long)win->src.window;
6900 reply.xclient.data.l[1] = 0;
6901 reply.xclient.data.l[2] = None;
6902
6903 if (E.xclient.message_type == XdndEnter) {
6904 if (version > 5)
6905 break;
6906
6907 unsigned long count;
6908 Atom* formats;
6909 Atom real_formats[6];
6910 Bool list = E.xclient.data.l[1] & 1;
6911
6912 source = (unsigned long int)E.xclient.data.l[0];
6913 version = E.xclient.data.l[1] >> 24;
6914 format = None;
6915 if (list) {
6916 Atom actualType;
6917 i32 actualFormat;
6918 unsigned long bytesAfter;
6919
6920 XGetWindowProperty(
6921 _RGFW->display, source, XdndTypeList,
6922 0, LONG_MAX, False, 4,
6923 &actualType, &actualFormat, &count, &bytesAfter, (u8**)&formats
6924 );
6925 } else {
6926 count = 0;
6927
6928 size_t i;
6929 for (i = 2; i < 5; i++) {
6930 if (E.xclient.data.l[i] != None) {
6931 real_formats[count] = (unsigned long int)E.xclient.data.l[i];
6932 count += 1;
6933 }
6934 }
6935
6936 formats = real_formats;
6937 }
6938
6939 Atom XtextPlain = XInternAtom(_RGFW->display, "text/plain", False);
6940 Atom XtextUriList = XInternAtom(_RGFW->display, "text/uri-list", False);
6941
6942 size_t i;
6943 for (i = 0; i < count; i++) {
6944 if (formats[i] == XtextUriList || formats[i] == XtextPlain) {
6945 format = (int)formats[i];
6946 break;
6947 }
6948 }
6949
6950 if (list) {
6951 XFree(formats);
6952 }
6953
6954 break;
6955 }
6956
6957 if (E.xclient.message_type == XdndPosition) {
6958 const i32 xabs = (E.xclient.data.l[2] >> 16) & 0xffff;
6959 const i32 yabs = (E.xclient.data.l[2]) & 0xffff;
6960 Window dummy;
6961 i32 xpos, ypos;
6962
6963 if (version > 5)
6964 break;
6965
6966 XTranslateCoordinates(
6967 _RGFW->display, XDefaultRootWindow(_RGFW->display), win->src.window,
6968 xabs, yabs, &xpos, &ypos, &dummy
6969 );
6970
6971 dragX = xpos;
6972 dragY = ypos;
6973
6974 reply.xclient.window = source;
6975 reply.xclient.message_type = XdndStatus;
6976
6977 if (format) {
6978 reply.xclient.data.l[1] = 1;
6979 if (version >= 2)
6980 reply.xclient.data.l[4] = (long)XdndActionCopy;
6981 }
6982
6983 XSendEvent(_RGFW->display, source, False, NoEventMask, &reply);
6984 XFlush(_RGFW->display);
6985 break;
6986 }
6987 if (E.xclient.message_type != XdndDrop)
6988 break;
6989
6990 if (version > 5)
6991 break;
6992
6993 if (format) {
6994 Time time = (version >= 1)
6995 ? (Time)E.xclient.data.l[2]
6996 : CurrentTime;
6997
6998 XConvertSelection(
6999 _RGFW->display, XdndSelection, (Atom)format,
7000 XdndSelection, win->src.window, time
7001 );
7002 } else if (version >= 2) {
7003 XEvent new_reply = { ClientMessage };
7004
7005 XSendEvent(_RGFW->display, source, False, NoEventMask, &new_reply);
7006 XFlush(_RGFW->display);
7007 }
7008
7009 RGFW_dataDragCallback(win, dragX, dragY);
7010 } break;
7011 case SelectionNotify: {
7012 /* this is only for checking for xdnd drops */
7013 if (!(win->internal.enabledEvents & RGFW_dataDropFlag) || E.xselection.property != XdndSelection || !(win->internal.flags & RGFW_windowAllowDND))
7014 return;
7015 char* data;
7016 unsigned long result;
7017
7018 Atom actualType;
7019 i32 actualFormat;
7020 unsigned long bytesAfter;
7021
7022 XGetWindowProperty(_RGFW->display, E.xselection.requestor, E.xselection.property, 0, LONG_MAX, False, E.xselection.target, &actualType, &actualFormat, &result, &bytesAfter, (u8**) &data);
7023
7024 if (result == 0)
7025 break;
7026
7027 const char* prefix = (const char*)"file://";
7028
7029 char* line;
7030
7031 size_t count = 0;
7032 char** files = _RGFW->files;
7033
7034 while ((line = (char*)RGFW_strtok(data, "\r\n"))) {
7035 data = NULL;
7036
7037 if (line[0] == '#')
7038 continue;
7039
7040 char* l;
7041 for (l = line; 1; l++) {
7042 if ((l - line) > 7)
7043 break;
7044 else if (*l != prefix[(l - line)])
7045 break;
7046 else if (*l == '\0' && prefix[(l - line)] == '\0') {
7047 line += 7;
7048 while (*line != '/')
7049 line++;
7050 break;
7051 } else if (*l == '\0')
7052 break;
7053 }
7054
7055 count++;
7056
7057 size_t len = RGFW_unix_stringlen(line);
7058 char* path = (char*)RGFW_ALLOC(len + 1);
7059
7060 size_t index = 0;
7061 while (*line) {
7062 if (line[0] == '%' && line[1] && line[2]) {
7063 char digits[3] = {0};
7064 digits[0] = line[1];
7065 digits[1] = line[2];
7066 digits[2] = '\0';
7067 path[index] = (char) RGFW_STRTOL(digits, NULL, 16);
7068 line += 2;
7069 } else {
7070 if (index >= len) {
7071 break;
7072 }
7073
7074 path[index] = *line;
7075 }
7076
7077 index++;
7078 line++;
7079 }
7080
7081 path[len] = '\0';
7082 size_t cnt = RGFW_MIN(len + 1, RGFW_MAX_PATH);
7083 if (cnt == RGFW_MAX_PATH) {
7084 path[cnt] = '\0';
7085 }
7086
7087 RGFW_MEMCPY(files[count - 1], path, cnt);
7088 RGFW_FREE(path);
7089 }
7090
7091 RGFW_dataDropCallback(win, files, count);
7092 if (data)
7093 XFree(data);
7094
7095 if (version >= 2) {
7096 XEvent new_reply = { ClientMessage };
7097 new_reply.xclient.window = source;
7098 new_reply.xclient.message_type = XdndFinished;
7099 new_reply.xclient.format = 32;
7100 new_reply.xclient.data.l[1] = (long int)result;
7101 new_reply.xclient.data.l[2] = (long int)XdndActionCopy;
7102 XSendEvent(_RGFW->display, source, False, NoEventMask, &new_reply);
7103 XFlush(_RGFW->display);
7104 }
7105 break;
7106 }
7107 case FocusIn:
7108 if (win->src.ic) XSetICFocus(win->src.ic);
7109 RGFW_focusCallback(win, 1);
7110 break;
7111 case FocusOut:
7112 if (win->src.ic) XUnsetICFocus(win->src.ic);
7113 RGFW_focusCallback(win, 0);
7114 break;
7115 case EnterNotify: {
7116 RGFW_mouseNotifyCallback(win, E.xcrossing.x, E.xcrossing.y, RGFW_TRUE);
7117 break;
7118 }
7119
7120 case LeaveNotify: {
7121 RGFW_mouseNotifyCallback(win, win->internal.lastMouseX, win->internal.lastMouseY, RGFW_FALSE);
7122 break;
7123 }
7124 case ReparentNotify:
7125 win->src.parent = E.xreparent.parent;
7126 break;
7127 case ConfigureNotify: {
7128 /* detect resize */
7129 if (E.xconfigure.width != win->src.w || E.xconfigure.height != win->src.h) {
7130 RGFW_window_checkMode(win);
7131 win->src.w = E.xconfigure.width;
7132 win->src.h = E.xconfigure.height;
7133 RGFW_windowResizedCallback(win, E.xconfigure.width, E.xconfigure.height);
7134 }
7135
7136 i32 x = E.xconfigure.x;
7137 i32 y = E.xconfigure.y;
7138
7139 /*
7140 if the event came from the server and we're not a direct child of the root window then
7141 we're using local coords which need to be translated into screen coords
7142 */
7143 Window root = DefaultRootWindow(_RGFW->display);
7144 if (E.xany.send_event == 0 && win->src.parent != root) {
7145 Window dummy = 0;
7146 XTranslateCoordinates(_RGFW->display, win->src.parent, root, x, y, &x, &y, &dummy);
7147 }
7148
7149 /* detect move */
7150 if (E.xconfigure.x != win->src.x || E.xconfigure.y != win->src.y) {
7151 win->src.x = E.xconfigure.x;
7152 win->src.y = E.xconfigure.y;
7153 RGFW_windowMovedCallback(win, E.xconfigure.x, E.xconfigure.y);
7154 }
7155 return;
7156 }
7157 default:
7158 break;
7159 }
7160
7161 XFlush(_RGFW->display);
7162}
7163
7164void RGFW_FUNC(RGFW_pollEvents) (void) {
7165 RGFW_resetPrevState();
7166
7167 XPending(_RGFW->display);
7168 /* if there is no unread queued events, get a new one */
7169 while (QLength(_RGFW->display)) {
7170 RGFW_XHandleEvent();
7171 }
7172}
7173
7174void RGFW_FUNC(RGFW_window_move) (RGFW_window* win, i32 x, i32 y) {
7175 RGFW_ASSERT(win != NULL);
7176 win->x = x;
7177 win->y = y;
7178
7179 XMoveWindow(_RGFW->display, win->src.window, x, y);
7180 return;
7181}
7182
7183
7184void RGFW_FUNC(RGFW_window_resize) (RGFW_window* win, i32 w, i32 h) {
7185 RGFW_ASSERT(win != NULL);
7186 win->w = (i32)w;
7187 win->h = (i32)h;
7188
7189 XResizeWindow(_RGFW->display, win->src.window, (u32)w, (u32)h);
7190
7191 if ((win->internal.flags & RGFW_windowNoResize)) {
7192 XSizeHints sh;
7193 sh.flags = (1L << 4) | (1L << 5);
7194 sh.min_width = sh.max_width = (i32)w;
7195 sh.min_height = sh.max_height = (i32)h;
7196
7197 XSetWMSizeHints(_RGFW->display, (Drawable) win->src.window, &sh, XA_WM_NORMAL_HINTS);
7198 }
7199 return;
7200}
7201
7202void RGFW_FUNC(RGFW_window_setAspectRatio) (RGFW_window* win, i32 w, i32 h) {
7203 RGFW_ASSERT(win != NULL);
7204
7205
7206 if (w == 0 && h == 0)
7207 return;
7208 XSizeHints hints;
7209 long flags;
7210
7211 XGetWMNormalHints(_RGFW->display, win->src.window, &hints, &flags);
7212
7213 hints.flags |= PAspect;
7214
7215 hints.min_aspect.x = hints.max_aspect.x = (i32)w;
7216 hints.min_aspect.y = hints.max_aspect.y = (i32)h;
7217
7218 XSetWMNormalHints(_RGFW->display, win->src.window, &hints);
7219 return;
7220}
7221
7222void RGFW_FUNC(RGFW_window_setMinSize) (RGFW_window* win, i32 w, i32 h) {
7223 RGFW_ASSERT(win != NULL);
7224
7225 long flags;
7226 XSizeHints hints;
7227 RGFW_MEMSET(&hints, 0, sizeof(XSizeHints));
7228
7229 XGetWMNormalHints(_RGFW->display, win->src.window, &hints, &flags);
7230
7231 hints.flags |= PMinSize;
7232
7233 hints.min_width = (i32)w;
7234 hints.min_height = (i32)h;
7235
7236 XSetWMNormalHints(_RGFW->display, win->src.window, &hints);
7237 return;
7238}
7239
7240void RGFW_FUNC(RGFW_window_setMaxSize) (RGFW_window* win, i32 w, i32 h) {
7241 RGFW_ASSERT(win != NULL);
7242
7243 long flags;
7244 XSizeHints hints;
7245 RGFW_MEMSET(&hints, 0, sizeof(XSizeHints));
7246
7247 XGetWMNormalHints(_RGFW->display, win->src.window, &hints, &flags);
7248
7249 hints.flags |= PMaxSize;
7250
7251 hints.max_width = (i32)w;
7252 hints.max_height = (i32)h;
7253
7254 XSetWMNormalHints(_RGFW->display, win->src.window, &hints);
7255 return;
7256}
7257
7258void RGFW_toggleXMaximized(RGFW_window* win, RGFW_bool maximized);
7259void RGFW_toggleXMaximized(RGFW_window* win, RGFW_bool maximized) {
7260 RGFW_ASSERT(win != NULL);
7261 RGFW_LOAD_ATOM(_NET_WM_STATE);
7262 RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_VERT);
7263 RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ);
7264
7265 XEvent xev = {0};
7266 xev.type = ClientMessage;
7267 xev.xclient.window = win->src.window;
7268 xev.xclient.message_type = _NET_WM_STATE;
7269 xev.xclient.format = 32;
7270 xev.xclient.data.l[0] = maximized;
7271 xev.xclient.data.l[1] = (long int)_NET_WM_STATE_MAXIMIZED_HORZ;
7272 xev.xclient.data.l[2] = (long int)_NET_WM_STATE_MAXIMIZED_VERT;
7273 xev.xclient.data.l[3] = 0;
7274 xev.xclient.data.l[4] = 0;
7275
7276 XSendEvent(_RGFW->display, DefaultRootWindow(_RGFW->display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
7277}
7278
7279void RGFW_FUNC(RGFW_window_maximize) (RGFW_window* win) {
7280 win->internal.oldX = win->x;
7281 win->internal.oldY = win->y;
7282 win->internal.oldW = win->w;
7283 win->internal.oldH = win->h;
7284
7285 RGFW_toggleXMaximized(win, 1);
7286 return;
7287}
7288
7289void RGFW_FUNC(RGFW_window_focus) (RGFW_window* win) {
7290 RGFW_ASSERT(win);
7291
7292 XWindowAttributes attr;
7293 XGetWindowAttributes(_RGFW->display, win->src.window, &attr);
7294 if (attr.map_state != IsViewable) return;
7295
7296 XSetInputFocus(_RGFW->display, win->src.window, RevertToPointerRoot, CurrentTime);
7297 XFlush(_RGFW->display);
7298}
7299
7300void RGFW_FUNC(RGFW_window_raise) (RGFW_window* win) {
7301 RGFW_ASSERT(win);
7302 XMapRaised(_RGFW->display, win->src.window);
7303 RGFW_window_setFullscreen(win, RGFW_window_isFullscreen(win));
7304}
7305
7306void RGFW_window_setXAtom(RGFW_window* win, Atom netAtom, RGFW_bool fullscreen);
7307void RGFW_window_setXAtom(RGFW_window* win, Atom netAtom, RGFW_bool fullscreen) {
7308 RGFW_ASSERT(win != NULL);
7309 RGFW_LOAD_ATOM(_NET_WM_STATE);
7310
7311 XEvent xev = {0};
7312 xev.xclient.type = ClientMessage;
7313 xev.xclient.serial = 0;
7314 xev.xclient.send_event = True;
7315 xev.xclient.message_type = _NET_WM_STATE;
7316 xev.xclient.window = win->src.window;
7317 xev.xclient.format = 32;
7318 xev.xclient.data.l[0] = fullscreen;
7319 xev.xclient.data.l[1] = (long int)netAtom;
7320 xev.xclient.data.l[2] = 0;
7321
7322 XSendEvent(_RGFW->display, DefaultRootWindow(_RGFW->display), False, SubstructureNotifyMask | SubstructureRedirectMask, &xev);
7323}
7324
7325void RGFW_FUNC(RGFW_window_setFullscreen)(RGFW_window* win, RGFW_bool fullscreen) {
7326 RGFW_ASSERT(win != NULL);
7327
7328 if (fullscreen) {
7329 win->internal.flags |= RGFW_windowFullscreen;
7330 win->internal.oldX = win->x;
7331 win->internal.oldY = win->y;
7332 win->internal.oldW = win->w;
7333 win->internal.oldH = win->h;
7334 }
7335 else win->internal.flags &= ~(u32)RGFW_windowFullscreen;
7336
7337 XRaiseWindow(_RGFW->display, win->src.window);
7338
7339 RGFW_LOAD_ATOM(_NET_WM_STATE_FULLSCREEN);
7340 RGFW_window_setXAtom(win, _NET_WM_STATE_FULLSCREEN, fullscreen);
7341
7342 if (!(win->internal.flags & RGFW_windowTransparent)) {
7343 const unsigned char value = fullscreen;
7344 RGFW_LOAD_ATOM(_NET_WM_BYPASS_COMPOSITOR);
7345 XChangeProperty(
7346 _RGFW->display, win->src.window,
7347 _NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32,
7348 PropModeReplace, &value, 1);
7349 }
7350}
7351
7352void RGFW_FUNC(RGFW_window_setFloating)(RGFW_window* win, RGFW_bool floating) {
7353 RGFW_ASSERT(win != NULL);
7354 RGFW_LOAD_ATOM(_NET_WM_STATE_ABOVE);
7355 RGFW_window_setXAtom(win, _NET_WM_STATE_ABOVE, floating);
7356}
7357
7358void RGFW_FUNC(RGFW_window_setOpacity)(RGFW_window* win, u8 opacity) {
7359 RGFW_ASSERT(win != NULL);
7360 const u32 value = (u32) (0xffffffffu * (double) opacity);
7361 RGFW_LOAD_ATOM(NET_WM_WINDOW_OPACITY);
7362 XChangeProperty(_RGFW->display, win->src.window,
7363 NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32, PropModeReplace, (unsigned char*) &value, 1);
7364}
7365
7366void RGFW_FUNC(RGFW_window_minimize)(RGFW_window* win) {
7367 RGFW_ASSERT(win != NULL);
7368
7369 if (RGFW_window_isMaximized(win)) return;
7370
7371 win->internal.oldX = win->x;
7372 win->internal.oldY = win->y;
7373 win->internal.oldW = win->w;
7374 win->internal.oldH = win->h;
7375 XIconifyWindow(_RGFW->display, win->src.window, DefaultScreen(_RGFW->display));
7376 XFlush(_RGFW->display);
7377}
7378
7379void RGFW_FUNC(RGFW_window_restore)(RGFW_window* win) {
7380 RGFW_ASSERT(win != NULL);
7381 RGFW_toggleXMaximized(win, RGFW_FALSE);
7382 RGFW_window_move(win, win->internal.oldX, win->internal.oldY);
7383 RGFW_window_resize(win, win->internal.oldW, win->internal.oldH);
7384
7385 RGFW_window_show(win);
7386 XFlush(_RGFW->display);
7387}
7388
7389RGFW_bool RGFW_FUNC(RGFW_window_isFloating)(RGFW_window* win) {
7390 RGFW_LOAD_ATOM(_NET_WM_STATE);
7391 RGFW_LOAD_ATOM(_NET_WM_STATE_ABOVE);
7392
7393 Atom actual_type;
7394 int actual_format;
7395 unsigned long nitems, bytes_after;
7396 Atom* prop_return = NULL;
7397
7398 int status = XGetWindowProperty(_RGFW->display, win->src.window, _NET_WM_STATE, 0, (~0L), False, XA_ATOM,
7399 &actual_type, &actual_format, &nitems, &bytes_after,
7400 (unsigned char **)&prop_return);
7401
7402 if (status != Success || actual_type != XA_ATOM)
7403 return RGFW_FALSE;
7404
7405 unsigned long i;
7406 for (i = 0; i < nitems; i++)
7407 if (prop_return[i] == _NET_WM_STATE_ABOVE) return RGFW_TRUE;
7408
7409 if (prop_return)
7410 XFree(prop_return);
7411 return RGFW_FALSE;
7412}
7413
7414void RGFW_FUNC(RGFW_window_setName)(RGFW_window* win, const char* name) {
7415 RGFW_ASSERT(win != NULL);
7416 if (name == NULL) name = "\0";
7417
7418 Xutf8SetWMProperties(_RGFW->display, win->src.window, name, name, NULL, 0, NULL, NULL, NULL);
7419 XStoreName(_RGFW->display, win->src.window, name);
7420
7421 RGFW_LOAD_ATOM(_NET_WM_NAME); RGFW_LOAD_ATOM(UTF8_STRING);
7422
7423 XChangeProperty(
7424 _RGFW->display, win->src.window, _NET_WM_NAME, UTF8_STRING,
7425 8, PropModeReplace, (u8*)name, (int)RGFW_unix_stringlen(name)
7426 );
7427}
7428
7429#ifndef RGFW_NO_PASSTHROUGH
7430void RGFW_FUNC(RGFW_window_setMousePassthrough) (RGFW_window* win, RGFW_bool passthrough) {
7431 RGFW_ASSERT(win != NULL);
7432 if (passthrough) {
7433 Region region = XCreateRegion();
7434 XShapeCombineRegion(_RGFW->display, win->src.window, ShapeInput, 0, 0, region, ShapeSet);
7435 XDestroyRegion(region);
7436
7437 return;
7438 }
7439
7440 XShapeCombineMask(_RGFW->display, win->src.window, ShapeInput, 0, 0, None, ShapeSet);
7441}
7442#endif /* RGFW_NO_PASSTHROUGH */
7443
7444RGFW_bool RGFW_FUNC(RGFW_window_setIconEx) (RGFW_window* win, u8* data_src, i32 w, i32 h, RGFW_format format, RGFW_icon type) {
7445 Atom _NET_WM_ICON = XInternAtom(_RGFW->display, "_NET_WM_ICON", False);
7446 RGFW_ASSERT(win != NULL);
7447 if (data_src == NULL) {
7448 RGFW_bool res = (RGFW_bool)XChangeProperty(
7449 _RGFW->display, win->src.window, _NET_WM_ICON, XA_CARDINAL, 32,
7450 PropModeReplace, (u8*)NULL, 0
7451 );
7452 return res;
7453 }
7454
7455 i32 count = (i32)(2 + (w * h));
7456
7457 unsigned long* data = (unsigned long*) RGFW_ALLOC((u32)count * sizeof(unsigned long));
7458 RGFW_ASSERT(data != NULL);
7459
7460 RGFW_MEMSET(data, 0, (u32)count * sizeof(unsigned long));
7461 data[0] = (unsigned long)w;
7462 data[1] = (unsigned long)h;
7463
7464 RGFW_copyImageData64((u8*)&data[2], w, h, RGFW_formatBGRA8, data_src, format, RGFW_TRUE, NULL);
7465 RGFW_bool res = RGFW_TRUE;
7466 if (type & RGFW_iconTaskbar) {
7467 res = (RGFW_bool)XChangeProperty(
7468 _RGFW->display, win->src.window, _NET_WM_ICON, XA_CARDINAL, 32,
7469 PropModeReplace, (u8*)data, count
7470 );
7471 }
7472
7473 RGFW_copyImageData64((u8*)&data[2], w, h, RGFW_formatBGRA8, data_src, format, RGFW_FALSE, NULL);
7474
7475 if (type & RGFW_iconWindow) {
7476 XWMHints wm_hints;
7477 wm_hints.flags = IconPixmapHint;
7478
7479 i32 depth = DefaultDepth(_RGFW->display, DefaultScreen(_RGFW->display));
7480 XImage *image = XCreateImage(_RGFW->display, DefaultVisual(_RGFW->display, DefaultScreen(_RGFW->display)),
7481 (u32)depth, ZPixmap, 0, (char *)&data[2], (u32)w, (u32)h, 32, 0);
7482
7483 wm_hints.icon_pixmap = XCreatePixmap(_RGFW->display, win->src.window, (u32)w, (u32)h, (u32)depth);
7484 XPutImage(_RGFW->display, wm_hints.icon_pixmap, DefaultGC(_RGFW->display, DefaultScreen(_RGFW->display)), image, 0, 0, 0, 0, (u32)w, (u32)h);
7485 image->data = NULL;
7486 XDestroyImage(image);
7487
7488 XSetWMHints(_RGFW->display, win->src.window, &wm_hints);
7489 }
7490
7491 RGFW_FREE(data);
7492 XFlush(_RGFW->display);
7493 return RGFW_BOOL(res);
7494}
7495
7496RGFW_mouse* RGFW_FUNC(RGFW_loadMouse) (u8* data, i32 w, i32 h, RGFW_format format) {
7497 RGFW_ASSERT(data);
7498#ifndef RGFW_NO_X11_CURSOR
7499 RGFW_init();
7500 XcursorImage* native = XcursorImageCreate((i32)w, (i32)h);
7501 native->xhot = 0;
7502 native->yhot = 0;
7503 RGFW_MEMSET(native->pixels, 0, (u32)(w * h * 4));
7504 RGFW_copyImageData((u8*)native->pixels, w, h, RGFW_formatBGRA8, data, format, NULL);
7505
7506 Cursor cursor = XcursorImageLoadCursor(_RGFW->display, native);
7507 XcursorImageDestroy(native);
7508
7509 return (void*)cursor;
7510#else
7511 RGFW_UNUSED(data); RGFW_UNUSED(w); RGFW_UNUSED(h); RGFW_UNUSED(format);
7512 return NULL;
7513#endif
7514}
7515
7516void RGFW_FUNC(RGFW_window_setMouse)(RGFW_window* win, RGFW_mouse* mouse) {
7517 RGFW_ASSERT(win && mouse);
7518 XDefineCursor(_RGFW->display, win->src.window, (Cursor)mouse);
7519}
7520
7521void RGFW_FUNC(RGFW_freeMouse)(RGFW_mouse* mouse) {
7522 RGFW_ASSERT(mouse);
7523 XFreeCursor(_RGFW->display, (Cursor)mouse);
7524}
7525
7526void RGFW_FUNC(RGFW_window_moveMouse)(RGFW_window* win, i32 x, i32 y) {
7527 RGFW_ASSERT(win != NULL);
7528
7529 XEvent event;
7530 XQueryPointer(_RGFW->display, DefaultRootWindow(_RGFW->display),
7531 &event.xbutton.root, &event.xbutton.window,
7532 &event.xbutton.x_root, &event.xbutton.y_root,
7533 &event.xbutton.x, &event.xbutton.y,
7534 &event.xbutton.state);
7535
7536 win->internal.lastMouseX = x - win->x;
7537 win->internal.lastMouseY = y - win->y;
7538 if (event.xbutton.x == x && event.xbutton.y == y)
7539 return;
7540
7541 XWarpPointer(_RGFW->display, None, win->src.window, 0, 0, 0, 0, (int) x - win->x, (int) y - win->y);
7542}
7543
7544RGFW_bool RGFW_FUNC(RGFW_window_setMouseDefault) (RGFW_window* win) {
7545 return RGFW_window_setMouseStandard(win, RGFW_mouseArrow);
7546}
7547
7548RGFW_bool RGFW_FUNC(RGFW_window_setMouseStandard) (RGFW_window* win, u8 mouse) {
7549 RGFW_ASSERT(win != NULL);
7550
7551 u32 mouseIcon = 0;
7552
7553 switch (mouse) {
7554 case RGFW_mouseNormal: mouseIcon = XC_left_ptr; break;
7555 case RGFW_mouseArrow: mouseIcon = XC_left_ptr; break;
7556 case RGFW_mouseIbeam: mouseIcon = XC_xterm; break;
7557 case RGFW_mouseWait: mouseIcon = XC_watch; break;
7558 case RGFW_mouseCrosshair: mouseIcon = XC_tcross; break;
7559 case RGFW_mouseProgress: mouseIcon = XC_watch; break;
7560 case RGFW_mouseResizeNWSE: mouseIcon = XC_top_left_corner; break;
7561 case RGFW_mouseResizeNESW: mouseIcon = XC_top_right_corner; break;
7562 case RGFW_mouseResizeEW: mouseIcon = XC_sb_h_double_arrow; break;
7563 case RGFW_mouseResizeNS: mouseIcon = XC_sb_v_double_arrow; break;
7564 case RGFW_mouseResizeNW: mouseIcon = XC_top_left_corner; break;
7565 case RGFW_mouseResizeN: mouseIcon = XC_top_side; break;
7566 case RGFW_mouseResizeNE: mouseIcon = XC_top_right_corner; break;
7567 case RGFW_mouseResizeE: mouseIcon = XC_right_side; break;
7568 case RGFW_mouseResizeSE: mouseIcon = XC_bottom_right_corner; break;
7569 case RGFW_mouseResizeS: mouseIcon = XC_bottom_side; break;
7570 case RGFW_mouseResizeSW: mouseIcon = XC_bottom_left_corner; break;
7571 case RGFW_mouseResizeW: mouseIcon = XC_left_side; break;
7572 case RGFW_mouseResizeAll: mouseIcon = XC_fleur; break;
7573 case RGFW_mouseNotAllowed: mouseIcon = XC_pirate; break;
7574 case RGFW_mousePointingHand: mouseIcon = XC_hand2; break;
7575 default: return RGFW_FALSE;
7576 }
7577
7578 Cursor cursor = XCreateFontCursor(_RGFW->display, mouseIcon);
7579 XDefineCursor(_RGFW->display, win->src.window, (Cursor) cursor);
7580 XFreeCursor(_RGFW->display, (Cursor) cursor);
7581 return RGFW_TRUE;
7582}
7583
7584void RGFW_FUNC(RGFW_window_hide)(RGFW_window* win) {
7585 win->internal.flags |= (u32)RGFW_windowHide;
7586 XUnmapWindow(_RGFW->display, win->src.window);
7587
7588 XFlush(_RGFW->display);
7589}
7590
7591void RGFW_FUNC(RGFW_window_show) (RGFW_window* win) {
7592 win->internal.flags &= ~(u32)RGFW_windowHide;
7593 if (win->internal.flags & RGFW_windowFocusOnShow) RGFW_window_focus(win);
7594
7595 if (RGFW_window_isHidden(win) == RGFW_FALSE) {
7596 return;
7597 }
7598
7599 XMapWindow(_RGFW->display, win->src.window);
7600 RGFW_window_move(win, win->x, win->y);
7601
7602 RGFW_waitForShowEvent_X11(win);
7603 RGFW_window_setFullscreen(win, RGFW_window_isFullscreen(win));
7604 return;
7605}
7606
7607void RGFW_FUNC(RGFW_window_flash) (RGFW_window* win, RGFW_flashRequest request) {
7608 if (RGFW_window_isInFocus(win) && request) {
7609 return;
7610 }
7611
7612 XWMHints* wmhints = XGetWMHints(_RGFW->display, win->src.window);
7613 if (wmhints == NULL) return;
7614
7615 if (request) {
7616 wmhints->flags |= XUrgencyHint;
7617 if (request == RGFW_flashBriefly)
7618 win->src.flashEnd = RGFW_linux_getTimeNS() + (u64)1e+9;
7619 if (request == RGFW_flashUntilFocused)
7620 win->src.flashEnd = (u64)-1;
7621 } else {
7622 win->src.flashEnd = 0;
7623 wmhints->flags &= ~XUrgencyHint;
7624 }
7625
7626 XSetWMHints(_RGFW->display, win->src.window, wmhints);
7627 XFree(wmhints);
7628}
7629
7630RGFW_ssize_t RGFW_FUNC(RGFW_readClipboardPtr)(char* str, size_t strCapacity) {
7631 RGFW_init();
7632 RGFW_LOAD_ATOM(XSEL_DATA); RGFW_LOAD_ATOM(UTF8_STRING); RGFW_LOAD_ATOM(CLIPBOARD);
7633 if (XGetSelectionOwner(_RGFW->display, CLIPBOARD) == _RGFW->helperWindow) {
7634 if (str != NULL)
7635 RGFW_STRNCPY(str, _RGFW->clipboard, _RGFW->clipboard_len - 1);
7636 _RGFW->clipboard[_RGFW->clipboard_len - 1] = '\0';
7637 return (RGFW_ssize_t)_RGFW->clipboard_len - 1;
7638 }
7639
7640 XEvent event;
7641 int format;
7642 unsigned long N, sizeN;
7643 char* data;
7644 Atom target;
7645
7646 XConvertSelection(_RGFW->display, CLIPBOARD, UTF8_STRING, XSEL_DATA, _RGFW->helperWindow, CurrentTime);
7647 XSync(_RGFW->display, 0);
7648 while (1) {
7649 XNextEvent(_RGFW->display, &event);
7650 if (event.type != SelectionNotify) continue;
7651
7652 if (event.xselection.selection != CLIPBOARD || event.xselection.property == 0)
7653 return -1;
7654 break;
7655 }
7656
7657 XGetWindowProperty(event.xselection.display, event.xselection.requestor,
7658 event.xselection.property, 0L, (~0L), 0, AnyPropertyType, &target,
7659 &format, &sizeN, &N, (u8**) &data);
7660
7661 RGFW_ssize_t size;
7662 if (sizeN > strCapacity && str != NULL)
7663 size = -1;
7664
7665 if ((target == UTF8_STRING || target == XA_STRING) && str != NULL) {
7666 RGFW_MEMCPY(str, data, sizeN);
7667 str[sizeN] = '\0';
7668 XFree(data);
7669 } else if (str != NULL) size = -1;
7670
7671 XDeleteProperty(event.xselection.display, event.xselection.requestor, event.xselection.property);
7672 size = (RGFW_ssize_t)sizeN;
7673
7674 return size;
7675}
7676
7677i32 RGFW_XHandleClipboardSelectionHelper(void) {
7678 RGFW_LOAD_ATOM(SAVE_TARGETS);
7679
7680 XEvent event;
7681 XPending(_RGFW->display);
7682
7683 if (QLength(_RGFW->display) || XEventsQueued(_RGFW->display, QueuedAlready) + XEventsQueued(_RGFW->display, QueuedAfterReading))
7684 XNextEvent(_RGFW->display, &event);
7685 else
7686 return 0;
7687
7688 switch (event.type) {
7689 case SelectionRequest:
7690 RGFW_XHandleClipboardSelection(&event);
7691 return 0;
7692 case SelectionNotify:
7693 if (event.xselection.target == SAVE_TARGETS)
7694 return 0;
7695 break;
7696 default: break;
7697 }
7698
7699 return 0;
7700}
7701
7702void RGFW_FUNC(RGFW_writeClipboard)(const char* text, u32 textLen) {
7703 RGFW_LOAD_ATOM(SAVE_TARGETS); RGFW_LOAD_ATOM(CLIPBOARD);
7704 RGFW_init();
7705
7706 /* request ownership of the clipboard section and request to convert it, this means its our job to convert it */
7707 XSetSelectionOwner(_RGFW->display, CLIPBOARD, _RGFW->helperWindow, CurrentTime);
7708 if (XGetSelectionOwner(_RGFW->display, CLIPBOARD) != _RGFW->helperWindow) {
7709 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errClipboard, "X11 failed to become owner of clipboard selection");
7710 return;
7711 }
7712
7713 if (_RGFW->clipboard)
7714 RGFW_FREE(_RGFW->clipboard);
7715
7716 _RGFW->clipboard = (char*)RGFW_ALLOC(textLen);
7717 RGFW_ASSERT(_RGFW->clipboard != NULL);
7718
7719 RGFW_STRNCPY(_RGFW->clipboard, text, textLen - 1);
7720 _RGFW->clipboard[textLen - 1] = '\0';
7721 _RGFW->clipboard_len = textLen;
7722 return;
7723}
7724
7725RGFW_bool RGFW_FUNC(RGFW_window_isHidden)(RGFW_window* win) {
7726 RGFW_ASSERT(win != NULL);
7727 XWindowAttributes windowAttributes;
7728 XGetWindowAttributes(_RGFW->display, win->src.window, &windowAttributes);
7729
7730 return (windowAttributes.map_state != IsViewable);
7731}
7732
7733RGFW_bool RGFW_FUNC(RGFW_window_isMinimized)(RGFW_window* win) {
7734 RGFW_ASSERT(win != NULL);
7735 RGFW_LOAD_ATOM(WM_STATE);
7736
7737 Atom actual_type;
7738 i32 actual_format;
7739 unsigned long nitems, bytes_after;
7740 unsigned char* prop_data;
7741
7742 i32 status = XGetWindowProperty(_RGFW->display, win->src.window, WM_STATE, 0, 2, False,
7743 AnyPropertyType, &actual_type, &actual_format,
7744 &nitems, &bytes_after, &prop_data);
7745
7746 if (status == Success && nitems >= 1 && prop_data == (unsigned char*)IconicState) {
7747 XFree(prop_data);
7748 return RGFW_TRUE;
7749 }
7750
7751 if (prop_data != NULL)
7752 XFree(prop_data);
7753
7754 XWindowAttributes windowAttributes;
7755 XGetWindowAttributes(_RGFW->display, win->src.window, &windowAttributes);
7756 return windowAttributes.map_state != IsViewable;
7757}
7758
7759RGFW_bool RGFW_FUNC(RGFW_window_isMaximized)(RGFW_window* win) {
7760 RGFW_ASSERT(win != NULL);
7761 RGFW_LOAD_ATOM(_NET_WM_STATE);
7762 RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_VERT);
7763 RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ);
7764
7765 Atom actual_type;
7766 i32 actual_format;
7767 unsigned long nitems, bytes_after;
7768 unsigned char* prop_data;
7769
7770 i32 status = XGetWindowProperty(_RGFW->display, win->src.window, _NET_WM_STATE, 0, 1024, False,
7771 XA_ATOM, &actual_type, &actual_format,
7772 &nitems, &bytes_after, &prop_data);
7773
7774 if (status != Success) {
7775 if (prop_data != NULL)
7776 XFree(prop_data);
7777
7778 return RGFW_FALSE;
7779 }
7780
7781 u64 i;
7782 for (i = 0; i < nitems; i++) {
7783 if (prop_data[i] == _NET_WM_STATE_MAXIMIZED_VERT ||
7784 prop_data[i] == _NET_WM_STATE_MAXIMIZED_HORZ) {
7785 XFree(prop_data);
7786 return RGFW_TRUE;
7787 }
7788 }
7789
7790 if (prop_data != NULL)
7791 XFree(prop_data);
7792
7793 return RGFW_FALSE;
7794}
7795
7796RGFWDEF void RGFW_XGetSystemContentDPI(float* dpi);
7797void RGFW_XGetSystemContentDPI(float* dpi) {
7798 if (dpi == NULL) return;
7799 float dpiOutput = 96.0f;
7800
7801 #ifndef RGFW_NO_XRANDR
7802 char* rms = XResourceManagerString(_RGFW->display);
7803 if (rms == NULL) return;
7804
7805 XrmDatabase db = XrmGetStringDatabase(rms);
7806 if (db == NULL) return;
7807
7808 XrmValue value;
7809 char* type = NULL;
7810
7811 if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value) && type && RGFW_STRNCMP(type, "String", 7) == 0)
7812 dpiOutput = (float)RGFW_ATOF(value.addr);
7813 XrmDestroyDatabase(db);
7814 #endif
7815
7816 if (dpi) *dpi = dpiOutput;
7817}
7818
7819RGFWDEF XRRModeInfo* RGFW_XGetMode(XRRCrtcInfo* ci, XRRScreenResources* res, RRMode mode, RGFW_monitorMode* foundMode);
7820XRRModeInfo* RGFW_XGetMode(XRRCrtcInfo* ci, XRRScreenResources* res, RRMode mode, RGFW_monitorMode* foundMode) {
7821 XRRModeInfo* mi = None;
7822 for (i32 j = 0; j < res->nmode; j++) {
7823 if (res->modes[j].id == mode)
7824 mi = &res->modes[j];
7825 }
7826
7827 if (mi == None) return NULL;
7828
7829 if ((mi->modeFlags & RR_Interlace) != 0) return NULL;
7830
7831 foundMode->w = (i32)mi->width;
7832 foundMode->h = (i32)mi->height;
7833 if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270) {
7834 foundMode->w = (i32)mi->height;
7835 foundMode->h = (i32)mi->width;
7836 } else {
7837 foundMode->w = (i32)mi->width;
7838 foundMode->h = (i32)mi->height;
7839 }
7840
7841 RGFW_splitBPP((u32)DefaultDepth(_RGFW->display, DefaultScreen(_RGFW->display)), foundMode);
7842
7843 foundMode->src = (void*)mode;
7844
7845 foundMode->refreshRate = 0;
7846 if (mi->hTotal == 0 || mi->vTotal == 0)
7847 return mi;
7848
7849 u32 vTotal = mi->vTotal;
7850
7851 if (mi->modeFlags & RR_DoubleScan) {
7852 vTotal *= 2;
7853 }
7854
7855 if (mi->modeFlags & RR_Interlace) {
7856 vTotal /= 2;
7857 }
7858
7859 i32 numerator = (i32)mi->dotClock;
7860 i32 denominator = (i32)(mi->hTotal * vTotal);
7861 float refreshRate = 0;
7862
7863 if (denominator <= 0) {
7864 denominator = 1;
7865 }
7866
7867 refreshRate = ((float)numerator / (float)denominator);
7868
7869 foundMode->refreshRate = RGFW_ROUNDF((refreshRate * 100)) / 100.0f;
7870 return mi;
7871}
7872
7873void RGFW_FUNC(RGFW_pollMonitors) (void) {
7874 RGFW_init();
7875
7876 Window root = XDefaultRootWindow(_RGFW->display);
7877 XRRScreenResources* res = XRRGetScreenResourcesCurrent(_RGFW->display, root);
7878 if (res == 0) {
7879 return;
7880 }
7881
7882 RROutput primary = XRRGetOutputPrimary(_RGFW->display, root);
7883
7884 for (RGFW_monitorNode* node = _RGFW->monitors.list.head; node; node = node->next) {
7885 node->disconnected = RGFW_TRUE;
7886 }
7887
7888 for (i32 i = 0; i < res->noutput; i++) {
7889 RGFW_monitorNode* node = NULL;
7890 for (node = _RGFW->monitors.list.head; node; node = node->next) {
7891 if (node->rrOutput == res->outputs[i]) {
7892 break;
7893 }
7894 }
7895
7896 if (node) {
7897 node->disconnected = RGFW_FALSE;
7898 if (node->rrOutput == primary) {
7899 _RGFW->monitors.primary = node;
7900 }
7901 continue;
7902 }
7903
7904 RGFW_monitor monitor;
7905
7906 XRROutputInfo* info = XRRGetOutputInfo(_RGFW->display, res, res->outputs[i]);
7907 if (info == NULL || info->connection != RR_Connected || info->crtc == None) {
7908 continue;
7909 }
7910
7911 XRRCrtcInfo* ci = XRRGetCrtcInfo(_RGFW->display, res, info->crtc);
7912
7913 if (ci == NULL) {
7914 continue;
7915 }
7916
7917 float physW = (float)info->mm_width / 25.4f;
7918 float physH = (float)info->mm_height / 25.4f;
7919
7920 RGFW_STRNCPY(monitor.name, info->name, sizeof(monitor.name) - 1);
7921 monitor.name[sizeof(monitor.name) - 1] = '\0';
7922
7923 if (physW > 0.0f && physH > 0.0f) {
7924 monitor.physW = physW;
7925 monitor.physH = physH;
7926 } else {
7927 monitor.physW = (float) ((float)ci->width / 96.f);
7928 monitor.physH = (float) ((float)ci->height / 96.f);
7929 }
7930
7931 monitor.x = ci->x;
7932 monitor.y = ci->y;
7933
7934 float dpi = 96.0f;
7935 RGFW_XGetSystemContentDPI(&dpi);
7936
7937 monitor.scaleX = dpi / 96.0f;
7938 monitor.scaleY = dpi / 96.0f;
7939
7940 monitor.pixelRatio = dpi >= 192.0f ? 2.0f : 1.0f;
7941
7942 XRRModeInfo* mi = RGFW_XGetMode(ci, res, ci->mode, &monitor.mode);
7943
7944 if (mi == NULL) {
7945 break;
7946 }
7947
7948 XRRFreeCrtcInfo(ci);
7949
7950 node = RGFW_monitors_add(&monitor);
7951 if (node == NULL) break;
7952
7953 node->rrOutput = res->outputs[i];
7954 node->crtc = info->crtc;
7955
7956 if (node->rrOutput == primary) {
7957 _RGFW->monitors.primary = node;
7958 }
7959
7960 XRRFreeOutputInfo(info);
7961 info = NULL;
7962
7963 RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_TRUE);
7964 }
7965
7966 XRRFreeScreenResources(res);
7967
7968 RGFW_monitors_refresh();
7969}
7970
7971RGFW_bool RGFW_FUNC(RGFW_monitor_getWorkarea) (RGFW_monitor* monitor, i32* x, i32* y, i32* width, i32* height) {
7972 RGFW_LOAD_ATOM(_NET_WORKAREA);
7973 RGFW_LOAD_ATOM(_NET_CURRENT_DESKTOP);
7974
7975 Window root = DefaultRootWindow(_RGFW->display);
7976
7977 i32 areaX = monitor->x;
7978 i32 areaY = monitor->y;
7979 i32 areaW = monitor->mode.w;
7980 i32 areaH = monitor->mode.h;
7981
7982 if (_NET_WORKAREA && _NET_CURRENT_DESKTOP) {
7983 Atom* extents = NULL;
7984 Atom* desktop = NULL;
7985
7986 Atom actualType = 0;
7987 int actualFormat = 0;
7988 unsigned long extentCount = 0, bytesAfter = 0;
7989 XGetWindowProperty(_RGFW->display, root, _NET_WORKAREA, 0, LONG_MAX, False, XA_CARDINAL, &actualType, &actualFormat, &extentCount, &bytesAfter, (u8**) &extents);
7990
7991 unsigned long count;
7992 XGetWindowProperty(_RGFW->display, root, _NET_CURRENT_DESKTOP, 0, LONG_MAX, False, XA_CARDINAL, &actualType, &actualFormat, &count, &bytesAfter, (u8**) &desktop);
7993
7994 if (count) {
7995 if (extentCount >= 4 && *desktop < extentCount / 4) {
7996 i32 globalX = (i32)extents[*desktop * 4 + 0];
7997 i32 globalY = (i32)extents[*desktop * 4 + 1];
7998 i32 globalW = (i32)extents[*desktop * 4 + 2];
7999 i32 globalH = (i32)extents[*desktop * 4 + 3];
8000
8001 if (areaX < globalX) {
8002 areaW -= globalX - areaX;
8003 areaX = globalX;
8004 }
8005
8006 if (areaY < globalY) {
8007 areaH -= globalY - areaY;
8008 areaY = globalY;
8009 }
8010
8011 if (areaX + areaW > globalX + globalW)
8012 areaW = globalX - areaX + globalW;
8013 if (areaY + areaH > globalY + globalH)
8014 areaH = globalY - areaY + globalH;
8015 }
8016 }
8017
8018 if (extents)
8019 XFree(extents);
8020 if (desktop)
8021 XFree(desktop);
8022 }
8023
8024 if (x) *x = areaX;
8025 if (y) *y = areaY;
8026 if (width) *width = areaW;
8027 if (height) *height = areaH;
8028
8029 return RGFW_TRUE;
8030}
8031
8032size_t RGFW_FUNC(RGFW_monitor_getModesPtr) (RGFW_monitor* monitor, RGFW_monitorMode** modes) {
8033 size_t count = 0;
8034
8035 XRRScreenResources* res = XRRGetScreenResourcesCurrent(_RGFW->display, DefaultRootWindow(_RGFW->display));
8036 if (res == NULL) return 0;
8037
8038 XRRCrtcInfo* ci = XRRGetCrtcInfo(_RGFW->display, res, monitor->node->crtc);
8039 XRROutputInfo* oi = XRRGetOutputInfo(_RGFW->display, res, monitor->node->rrOutput);
8040 count = (size_t)oi->nmode;
8041
8042 int i;
8043 for (i = 0; modes && i < oi->nmode; i++) {
8044 XRRModeInfo* mi = RGFW_XGetMode(ci, res, oi->modes[i], &((*modes)[i]));
8045 RGFW_UNUSED(mi);
8046 }
8047
8048 XRRFreeOutputInfo(oi);
8049 XRRFreeCrtcInfo(ci);
8050 XRRFreeScreenResources(res);
8051
8052 return count;
8053}
8054
8055size_t RGFW_FUNC(RGFW_monitor_getGammaRampPtr) (RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
8056 RGFW_UNUSED(monitor); RGFW_UNUSED(ramp);
8057#ifndef RGFW_NO_XRANDR
8058 size_t size = (size_t)XRRGetCrtcGammaSize(_RGFW->display, monitor->node->crtc);
8059 XRRCrtcGamma* gamma = XRRGetCrtcGamma(_RGFW->display, monitor->node->crtc);
8060
8061 if (ramp) {
8062 RGFW_MEMCPY(ramp->red, gamma->red, size * sizeof(unsigned short));
8063 RGFW_MEMCPY(ramp->green, gamma->green, size * sizeof(unsigned short));
8064 RGFW_MEMCPY(ramp->blue, gamma->blue, size * sizeof(unsigned short));
8065 }
8066
8067 XRRFreeGamma(gamma);
8068 return size;
8069#endif
8070
8071 return 0;
8072}
8073
8074RGFW_bool RGFW_FUNC(RGFW_monitor_setGammaRamp) (RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
8075 RGFW_UNUSED(monitor); RGFW_UNUSED(ramp);
8076
8077#ifndef RGFW_NO_XRANDR
8078 size_t size = (size_t)XRRGetCrtcGammaSize(_RGFW->display, monitor->node->crtc);
8079 if (size != ramp->count) {
8080 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errX11, "X11: Gamma ramp size must match current ramp size");
8081 return RGFW_FALSE;
8082 }
8083
8084 XRRCrtcGamma* gamma = XRRAllocGamma((int)ramp->count);
8085
8086 memcpy(gamma->red, ramp->red, ramp->count * sizeof(unsigned short));
8087 memcpy(gamma->green, ramp->green, ramp->count * sizeof(unsigned short));
8088 memcpy(gamma->blue, ramp->blue, ramp->count * sizeof(unsigned short));
8089
8090 XRRSetCrtcGamma(_RGFW->display, monitor->node->crtc, gamma);
8091 XRRFreeGamma(gamma);
8092
8093 return RGFW_TRUE;
8094#endif
8095 return RGFW_FALSE;
8096}
8097
8098RGFW_bool RGFW_FUNC(RGFW_monitor_setMode)(RGFW_monitor* mon, RGFW_monitorMode* mode) {
8099 RGFW_bool out = RGFW_FALSE;
8100
8101 XRRScreenResources* res = XRRGetScreenResourcesCurrent(_RGFW->display, DefaultRootWindow(_RGFW->display));
8102 XRRCrtcInfo* ci = XRRGetCrtcInfo(_RGFW->display, res, mon->node->crtc);
8103
8104 if (XRRSetCrtcConfig(_RGFW->display, res, mon->node->crtc, CurrentTime, ci->x, ci->y, (RRMode)mode->src, ci->rotation, ci->outputs, ci->noutput) == True) {
8105 out = RGFW_TRUE;
8106 }
8107
8108 XRRFreeCrtcInfo(ci);
8109 XRRFreeScreenResources(res);
8110 return out;
8111}
8112
8113RGFW_bool RGFW_FUNC(RGFW_monitor_requestMode)(RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request) {
8114 #ifndef RGFW_NO_XRANDR
8115 RGFW_init();
8116
8117 RGFW_bool output = RGFW_FALSE;
8118
8119 XRRScreenResources* res = XRRGetScreenResourcesCurrent(_RGFW->display, DefaultRootWindow(_RGFW->display));
8120 if (res == NULL) return RGFW_FALSE;
8121
8122 XRRCrtcInfo* ci = XRRGetCrtcInfo(_RGFW->display, res, mon->node->crtc);
8123 XRROutputInfo* oi = XRRGetOutputInfo(_RGFW->display, res, mon->node->rrOutput);
8124
8125 RRMode native = None;
8126
8127 int i;
8128 for (i = 0; i < oi->nmode; i++) {
8129 RGFW_monitorMode foundMode;
8130 XRRModeInfo* mi = RGFW_XGetMode(ci, res, oi->modes[i], &foundMode);
8131 if (mi == NULL) {
8132 continue;
8133 }
8134
8135 if (RGFW_monitorModeCompare(mode, &foundMode, request)) {
8136 native = mi->id;
8137 output = RGFW_TRUE;
8138 mon->mode = foundMode;
8139 break;
8140 }
8141 }
8142
8143 if (native) {
8144 XRRSetCrtcConfig(_RGFW->display, res, mon->node->crtc, CurrentTime, ci->x, ci->y, native, ci->rotation, ci->outputs, ci->noutput);
8145 }
8146
8147 XRRFreeOutputInfo(oi);
8148 XRRFreeCrtcInfo(ci);
8149 XRRFreeScreenResources(res);
8150 return output;
8151#endif
8152 return RGFW_FALSE;
8153}
8154
8155RGFW_monitor* RGFW_FUNC(RGFW_window_getMonitor) (RGFW_window* win) {
8156 RGFW_ASSERT(win != NULL);
8157
8158 XWindowAttributes attrs;
8159 if (!XGetWindowAttributes(_RGFW->display, win->src.window, &attrs)) {
8160 return NULL;
8161 }
8162
8163 for (RGFW_monitorNode* node = _RGFW->monitors.list.head; node; node = node->next) {
8164 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))
8165 return &node->mon;
8166 }
8167
8168
8169 return &_RGFW->monitors.list.head->mon;
8170}
8171
8172#ifdef RGFW_OPENGL
8173RGFW_bool RGFW_FUNC(RGFW_window_createContextPtr_OpenGL) (RGFW_window* win, RGFW_glContext* context, RGFW_glHints* hints) {
8174 /* for checking extensions later */
8175 const char sRGBARBstr[] = "GLX_ARB_framebuffer_sRGB";
8176 const char sRGBEXTstr[] = "GLX_EXT_framebuffer_sRGB";
8177 const char noErorrStr[] = "GLX_ARB_create_context_no_error";
8178 const char flushStr[] = "GLX_ARB_context_flush_control";
8179 const char robustStr[] = "GLX_ARB_create_context_robustness";
8180
8181 /* basic RGFW int */
8182 win->src.ctx.native = context;
8183 win->src.gfxType = RGFW_gfxNativeOpenGL;
8184
8185 /* This is required so that way the user can create their own OpenGL context after RGFW_createWindow is used */
8186 RGFW_bool showWindow = RGFW_FALSE;
8187 if (win->src.window) {
8188 showWindow = (RGFW_window_isMinimized(win) == RGFW_FALSE);
8189 RGFW_window_closePlatform(win);
8190 }
8191
8192 RGFW_bool transparent = (win->internal.flags & RGFW_windowTransparent);
8193
8194 /* start by creating a GLX config / X11 Viusal */
8195 XVisualInfo visual;
8196 GLXFBConfig bestFbc;
8197
8198 i32 visual_attribs[40];
8199 RGFW_attribStack stack;
8200 RGFW_attribStack_init(&stack, visual_attribs, 40);
8201 RGFW_attribStack_pushAttribs(&stack, GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR);
8202 RGFW_attribStack_pushAttribs(&stack, GLX_X_RENDERABLE, 1);
8203 RGFW_attribStack_pushAttribs(&stack, GLX_RENDER_TYPE, GLX_RGBA_BIT);
8204 RGFW_attribStack_pushAttribs(&stack, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT);
8205 RGFW_attribStack_pushAttribs(&stack, GLX_DOUBLEBUFFER, 1);
8206 RGFW_attribStack_pushAttribs(&stack, GLX_ALPHA_SIZE, hints->alpha);
8207 RGFW_attribStack_pushAttribs(&stack, GLX_DEPTH_SIZE, hints->depth);
8208 RGFW_attribStack_pushAttribs(&stack, GLX_STENCIL_SIZE, hints->stencil);
8209 RGFW_attribStack_pushAttribs(&stack, GLX_STEREO, hints->stereo);
8210 RGFW_attribStack_pushAttribs(&stack, GLX_AUX_BUFFERS, hints->auxBuffers);
8211 RGFW_attribStack_pushAttribs(&stack, GLX_RED_SIZE, hints->red);
8212 RGFW_attribStack_pushAttribs(&stack, GLX_GREEN_SIZE, hints->green);
8213 RGFW_attribStack_pushAttribs(&stack, GLX_BLUE_SIZE, hints->blue);
8214 RGFW_attribStack_pushAttribs(&stack, GLX_ACCUM_RED_SIZE, hints->accumRed);
8215 RGFW_attribStack_pushAttribs(&stack, GLX_ACCUM_GREEN_SIZE, hints->accumGreen);
8216 RGFW_attribStack_pushAttribs(&stack, GLX_ACCUM_BLUE_SIZE, hints->accumBlue);
8217 RGFW_attribStack_pushAttribs(&stack, GLX_ACCUM_ALPHA_SIZE, hints->accumAlpha);
8218
8219 if (hints->sRGB) {
8220 if (RGFW_extensionSupportedPlatform_OpenGL(sRGBARBstr, sizeof(sRGBARBstr)))
8221 RGFW_attribStack_pushAttribs(&stack, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, hints->sRGB);
8222 if (RGFW_extensionSupportedPlatform_OpenGL(sRGBEXTstr, sizeof(sRGBEXTstr)))
8223 RGFW_attribStack_pushAttribs(&stack, GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, hints->sRGB);
8224 }
8225
8226 RGFW_attribStack_pushAttribs(&stack, 0, 0);
8227
8228 /* find the configs */
8229 i32 fbcount;
8230 GLXFBConfig* fbc = glXChooseFBConfig(_RGFW->display, DefaultScreen(_RGFW->display), visual_attribs, &fbcount);
8231
8232 i32 best_fbc = -1;
8233 i32 best_depth = 0;
8234 i32 best_samples = 0;
8235
8236 if (fbcount == 0) {
8237 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to find any valid GLX visual configs.");
8238 return 0;
8239 }
8240
8241 /* search through all found configs to find the best match */
8242 i32 i;
8243 for (i = 0; i < fbcount; i++) {
8244 XVisualInfo* vi = glXGetVisualFromFBConfig(_RGFW->display, fbc[i]);
8245 if (vi == NULL)
8246 continue;
8247
8248 i32 samp_buf, samples;
8249 glXGetFBConfigAttrib(_RGFW->display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf);
8250 glXGetFBConfigAttrib(_RGFW->display, fbc[i], GLX_SAMPLES, &samples);
8251
8252 if (best_fbc == -1) best_fbc = i;
8253 if ((!(transparent) || vi->depth == 32) && best_depth == 0) {
8254 best_fbc = i;
8255 best_depth = vi->depth;
8256 }
8257 if ((!(transparent) || vi->depth == 32) && samples <= hints->samples && samples > best_samples) {
8258 best_fbc = i;
8259 best_depth = vi->depth;
8260 best_samples = samples;
8261 }
8262 XFree(vi);
8263 }
8264
8265 if (best_fbc == -1) {
8266 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to get a valid GLX visual.");
8267 return 0;
8268 }
8269
8270 /* we found a config */
8271 bestFbc = fbc[best_fbc];
8272 XVisualInfo* vi = glXGetVisualFromFBConfig(_RGFW->display, bestFbc);
8273 if (vi->depth != 32 && transparent)
8274 RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, "Failed to to find a matching visual with a 32-bit depth.");
8275
8276 if (best_samples < hints->samples)
8277 RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, "Failed to load a matching sample count.");
8278
8279 XFree(fbc);
8280 visual = *vi;
8281 XFree(vi);
8282
8283 /* use the visual to create a new window */
8284 RGFW_XCreateWindow(visual, "", win->internal.flags, win);
8285
8286 if (showWindow) {
8287 RGFW_window_show(win);
8288 }
8289
8290 /* create the actual OpenGL context */
8291 i32 context_attribs[40];
8292 RGFW_attribStack_init(&stack, context_attribs, 40);
8293
8294 i32 mask = 0;
8295 switch (hints->profile) {
8296 case RGFW_glES: mask |= GLX_CONTEXT_ES_PROFILE_BIT_EXT; break;
8297 case RGFW_glForwardCompatibility: mask |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; break;
8298 case RGFW_glCompatibility: mask |= GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; break;
8299 case RGFW_glCore: mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; break;
8300 default: mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; break;
8301 }
8302
8303 RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_PROFILE_MASK_ARB, mask);
8304
8305 if (hints->minor || hints->major) {
8306 RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_MAJOR_VERSION_ARB, hints->major);
8307 RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_MINOR_VERSION_ARB, hints->minor);
8308 }
8309
8310
8311 if (RGFW_extensionSupportedPlatform_OpenGL(flushStr, sizeof(flushStr))) {
8312 if (hints->releaseBehavior == RGFW_glReleaseFlush) {
8313 RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB);
8314 } else if (hints->releaseBehavior == RGFW_glReleaseNone) {
8315 RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB);
8316 }
8317 }
8318
8319 i32 flags = 0;
8320 if (hints->debug) flags |= GLX_CONTEXT_DEBUG_BIT_ARB;
8321 if (hints->robustness && RGFW_extensionSupportedPlatform_OpenGL(robustStr, sizeof(robustStr))) flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB;
8322 if (flags) {
8323 RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_FLAGS_ARB, flags);
8324 }
8325
8326 if (RGFW_extensionSupportedPlatform_OpenGL(noErorrStr, sizeof(noErorrStr))) {
8327 RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_OPENGL_NO_ERROR_ARB, hints->noError);
8328 }
8329
8330 RGFW_attribStack_pushAttribs(&stack, 0, 0);
8331
8332 /* create the context */
8333 glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
8334 char str[] = "glXCreateContextAttribsARB";
8335 glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)glXGetProcAddressARB((u8*) str);
8336
8337 GLXContext ctx = NULL;
8338 if (hints->share) {
8339 ctx = hints->share->ctx;
8340 }
8341
8342 if (glXCreateContextAttribsARB == NULL) {
8343 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load proc address 'glXCreateContextAttribsARB', loading a generic OpenGL context.");
8344 win->src.ctx.native->ctx = glXCreateContext(_RGFW->display, &visual, ctx, True);
8345 } else {
8346 _RGFW->x11Error = NULL;
8347 win->src.ctx.native->ctx = glXCreateContextAttribsARB(_RGFW->display, bestFbc, ctx, True, context_attribs);
8348 if (_RGFW->x11Error || win->src.ctx.native->ctx == NULL) {
8349 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to create an OpenGL context with AttribsARB, loading a generic OpenGL context.");
8350 win->src.ctx.native->ctx = glXCreateContext(_RGFW->display, &visual, ctx, True);
8351 }
8352 }
8353
8354 #ifndef RGFW_NO_GLXWINDOW
8355 win->src.ctx.native->window = glXCreateWindow(_RGFW->display, bestFbc, win->src.window, NULL);
8356 #else
8357 win->src.ctx.native->window = win->src.window;
8358 #endif
8359
8360 glXMakeCurrent(_RGFW->display, (Drawable)win->src.ctx.native->window, (GLXContext)win->src.ctx.native->ctx);
8361 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized.");
8362
8363 RGFW_window_swapInterval_OpenGL(win, 0);
8364
8365 return RGFW_TRUE;
8366}
8367
8368void RGFW_FUNC(RGFW_window_deleteContextPtr_OpenGL) (RGFW_window* win, RGFW_glContext* ctx) {
8369 #ifndef RGFW_NO_GLXWINDOW
8370 if (win->src.ctx.native->window != win->src.window) {
8371 glXDestroyWindow(_RGFW->display, win->src.ctx.native->window);
8372 }
8373 #endif
8374
8375 glXDestroyContext(_RGFW->display, ctx->ctx);
8376 win->src.ctx.native = NULL;
8377 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context freed.");
8378}
8379
8380RGFW_bool RGFW_FUNC(RGFW_extensionSupportedPlatform_OpenGL)(const char * extension, size_t len) {
8381 RGFW_init();
8382 const char* extensions = glXQueryExtensionsString(_RGFW->display, XDefaultScreen(_RGFW->display));
8383 return (extensions != NULL) && RGFW_extensionSupportedStr(extensions, extension, len);
8384}
8385
8386RGFW_proc RGFW_FUNC(RGFW_getProcAddress_OpenGL)(const char* procname) { return glXGetProcAddress((u8*) procname); }
8387
8388void RGFW_FUNC(RGFW_window_makeCurrentContext_OpenGL) (RGFW_window* win) { if (win) RGFW_ASSERT(win->src.ctx.native);
8389 if (win == NULL)
8390 glXMakeCurrent(NULL, (Drawable)NULL, (GLXContext) NULL);
8391 else
8392 glXMakeCurrent(_RGFW->display, (Drawable)win->src.ctx.native->window, (GLXContext) win->src.ctx.native->ctx);
8393 return;
8394}
8395void* RGFW_FUNC(RGFW_getCurrentContext_OpenGL) (void) { return glXGetCurrentContext(); }
8396void RGFW_FUNC(RGFW_window_swapBuffers_OpenGL) (RGFW_window* win) { RGFW_ASSERT(win->src.ctx.native); glXSwapBuffers(_RGFW->display, win->src.ctx.native->window); }
8397
8398void RGFW_FUNC(RGFW_window_swapInterval_OpenGL) (RGFW_window* win, i32 swapInterval) {
8399 RGFW_ASSERT(win != NULL);
8400 /* cached pfn to avoid calling glXGetProcAddress more than once */
8401 static PFNGLXSWAPINTERVALEXTPROC pfn = NULL;
8402 static int (*pfn2)(int) = NULL;
8403
8404 if (pfn == NULL) {
8405 u8 str[] = "glXSwapIntervalEXT";
8406 pfn = (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddress(str);
8407 if (pfn == NULL) {
8408 pfn = (PFNGLXSWAPINTERVALEXTPROC)1;
8409 const char* array[] = {"GLX_MESA_swap_control", "GLX_SGI_swap_control"};
8410
8411 size_t i;
8412 for (i = 0; i < sizeof(array) / sizeof(char*) && pfn2 == NULL; i++) {
8413 pfn2 = (int(*)(int))glXGetProcAddress((u8*)array[i]);
8414 }
8415
8416 if (pfn2 != NULL) {
8417 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load swap interval function, fallingback to the native swapinterval function");
8418 } else {
8419 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load swap interval function");
8420 }
8421 }
8422 }
8423
8424 if (pfn != (PFNGLXSWAPINTERVALEXTPROC)1) {
8425 pfn(_RGFW->display, win->src.ctx.native->window, swapInterval);
8426 }
8427 else if (pfn2 != NULL) {
8428 pfn2(swapInterval);
8429 }
8430}
8431#endif /* RGFW_OPENGL */
8432
8433i32 RGFW_initPlatform_X11(void) {
8434 #ifdef RGFW_USE_XDL
8435 XDL_init();
8436 #endif
8437
8438 #if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD)
8439 #if defined(__CYGWIN__)
8440 RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor-1.so");
8441 #elif defined(__OpenBSD__) || defined(__NetBSD__)
8442 RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor.so");
8443 #else
8444 RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor.so.1");
8445 #endif
8446 RGFW_PROC_DEF(X11Cursorhandle, XcursorImageCreate);
8447 RGFW_PROC_DEF(X11Cursorhandle, XcursorImageDestroy);
8448 RGFW_PROC_DEF(X11Cursorhandle, XcursorImageLoadCursor);
8449 #endif
8450
8451 #if !defined(RGFW_NO_X11_XI_PRELOAD)
8452 #if defined(__CYGWIN__)
8453 RGFW_LOAD_LIBRARY(X11Xihandle, "libXi-6.so");
8454 #elif defined(__OpenBSD__) || defined(__NetBSD__)
8455 RGFW_LOAD_LIBRARY(X11Xihandle, "libXi.so");
8456 #else
8457 RGFW_LOAD_LIBRARY(X11Xihandle, "libXi.so.6");
8458 #endif
8459 RGFW_PROC_DEF(X11Xihandle, XISelectEvents);
8460 #endif
8461
8462 #if !defined(RGFW_NO_X11_EXT_PRELOAD)
8463 #if defined(__CYGWIN__)
8464 RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext-6.so");
8465 #elif defined(__OpenBSD__) || defined(__NetBSD__)
8466 RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext.so");
8467 #else
8468 RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext.so.6");
8469 #endif
8470 RGFW_PROC_DEF(X11XEXThandle, XSyncCreateCounter);
8471 RGFW_PROC_DEF(X11XEXThandle, XSyncIntToValue);
8472 RGFW_PROC_DEF(X11XEXThandle, XSyncSetCounter);
8473 RGFW_PROC_DEF(X11XEXThandle, XShapeCombineRegion);
8474 RGFW_PROC_DEF(X11XEXThandle, XShapeCombineMask);
8475 #endif
8476
8477 XInitThreads(); /*!< init X11 threading */
8478 _RGFW->display = XOpenDisplay(0);
8479 _RGFW->context = XUniqueContext();
8480
8481 XSetWindowAttributes wa;
8482 RGFW_MEMSET(&wa, 0, sizeof(wa));
8483 wa.event_mask = PropertyChangeMask;
8484 _RGFW->helperWindow = XCreateWindow(_RGFW->display, XDefaultRootWindow(_RGFW->display), 0, 0, 1, 1, 0, 0,
8485 InputOnly, DefaultVisual(_RGFW->display, DefaultScreen(_RGFW->display)), CWEventMask, &wa);
8486
8487 u8 RGFW_blk[] = { 0, 0, 0, 0 };
8488 _RGFW->hiddenMouse = RGFW_loadMouse(RGFW_blk, 1, 1, RGFW_formatRGBA8);
8489 _RGFW->clipboard = NULL;
8490
8491 XkbComponentNamesRec rec;
8492 XkbDescPtr desc = XkbGetMap(_RGFW->display, 0, XkbUseCoreKbd);
8493 XkbDescPtr evdesc;
8494 XSetErrorHandler(RGFW_XErrorHandler);
8495 u8 old[256];
8496
8497 XkbGetNames(_RGFW->display, XkbKeyNamesMask, desc);
8498
8499 RGFW_MEMSET(&rec, 0, sizeof(rec));
8500 char evdev[] = "evdev";
8501 rec.keycodes = evdev;
8502 evdesc = XkbGetKeyboardByName(_RGFW->display, XkbUseCoreKbd, &rec, XkbGBN_KeyNamesMask, XkbGBN_KeyNamesMask, False);
8503 /* memo: RGFW_keycodes[x11 keycode] = rgfw keycode */
8504 if(evdesc != NULL && desc != NULL) {
8505 int i, j;
8506 for(i = 0; i < (int)sizeof(old); i++){
8507 old[i] = _RGFW->keycodes[i];
8508 _RGFW->keycodes[i] = 0;
8509 }
8510 for(i = evdesc->min_key_code; i <= evdesc->max_key_code; i++){
8511 for(j = desc->min_key_code; j <= desc->max_key_code; j++){
8512 if(RGFW_STRNCMP(evdesc->names->keys[i].name, desc->names->keys[j].name, XkbKeyNameLength) == 0){
8513 _RGFW->keycodes[j] = old[i];
8514 break;
8515 }
8516 }
8517 }
8518 XkbFreeKeyboard(desc, 0, True);
8519 XkbFreeKeyboard(evdesc, 0, True);
8520 }
8521
8522 XSetLocaleModifiers("");
8523 XRegisterIMInstantiateCallback(_RGFW->display, NULL, NULL, NULL, RGFW_x11_imInitCallback, NULL);
8524
8525 unsigned char mask[XIMaskLen(XI_RawMotion)];
8526 RGFW_MEMSET(mask, 0, sizeof(mask));
8527 XISetMask(mask, XI_RawMotion);
8528
8529 XIEventMask em;
8530 em.deviceid = XIAllMasterDevices;
8531 em.mask_len = sizeof(mask);
8532 em.mask = mask;
8533
8534 XISelectEvents(_RGFW->display, XDefaultRootWindow(_RGFW->display), &em, 1);
8535
8536#ifndef RGFW_NO_XRANDR
8537 i32 errorBase;
8538 if (XRRQueryExtension(_RGFW->display, &_RGFW->xrandrEventBase, &errorBase)) {
8539 XRRSelectInput(_RGFW->display, RootWindow(_RGFW->display, DefaultScreen(_RGFW->display)), RROutputChangeNotifyMask);
8540 }
8541#endif
8542
8543 return 0;
8544}
8545
8546void RGFW_deinitPlatform_X11(void) {
8547 #define RGFW_FREE_LIBRARY(x) if (x != NULL) dlclose(x); x = NULL;
8548 /* to save the clipboard on the x server after the window is closed */
8549 RGFW_LOAD_ATOM(CLIPBOARD_MANAGER); RGFW_LOAD_ATOM(CLIPBOARD);
8550 RGFW_LOAD_ATOM(SAVE_TARGETS);
8551 if (XGetSelectionOwner(_RGFW->display, CLIPBOARD) == _RGFW->helperWindow) {
8552 XConvertSelection(_RGFW->display, CLIPBOARD_MANAGER, SAVE_TARGETS, None, _RGFW->helperWindow, CurrentTime);
8553 while (RGFW_XHandleClipboardSelectionHelper());
8554 }
8555
8556 XUnregisterIMInstantiateCallback(_RGFW->display, NULL, NULL, NULL, RGFW_x11_imInitCallback, NULL);
8557
8558 if (_RGFW->im) {
8559 XCloseIM(_RGFW->im);
8560 _RGFW->im = NULL;
8561 }
8562
8563 if (_RGFW->clipboard) {
8564 RGFW_FREE(_RGFW->clipboard);
8565 _RGFW->clipboard = NULL;
8566 }
8567
8568 if (_RGFW->hiddenMouse) {
8569 RGFW_freeMouse(_RGFW->hiddenMouse);
8570 _RGFW->hiddenMouse = NULL;
8571 }
8572
8573 XDestroyWindow(_RGFW->display, (Drawable) _RGFW->helperWindow); /*!< close the window */
8574 XCloseDisplay(_RGFW->display); /*!< kill connection to the x server */
8575
8576 #if !defined(RGFW_NO_X11_CURSOR_PRELOAD) && !defined(RGFW_NO_X11_CURSOR)
8577 RGFW_FREE_LIBRARY(X11Cursorhandle);
8578 #endif
8579 #if !defined(RGFW_NO_X11_XI_PRELOAD)
8580 RGFW_FREE_LIBRARY(X11Xihandle);
8581 #endif
8582
8583 #ifdef RGFW_USE_XDL
8584 XDL_close();
8585 #endif
8586
8587 #if !defined(RGFW_NO_X11_EXT_PRELOAD)
8588 RGFW_FREE_LIBRARY(X11XEXThandle);
8589 #endif
8590}
8591
8592void RGFW_FUNC(RGFW_window_closePlatform)(RGFW_window* win) {
8593 if (win->src.ic) {
8594 XDestroyIC(win->src.ic);
8595 win->src.ic = NULL;
8596 }
8597
8598 XFreeGC(_RGFW->display, win->src.gc);
8599 XDeleteContext(_RGFW->display, win->src.window, _RGFW->context);
8600 XDestroyWindow(_RGFW->display, (Drawable) win->src.window); /*!< close the window */
8601 return;
8602}
8603
8604#ifdef RGFW_WEBGPU
8605WGPUSurface RGFW_FUNC(RGFW_window_createSurface_WebGPU) (RGFW_window* window, WGPUInstance instance) {
8606 WGPUSurfaceDescriptor surfaceDesc = {0};
8607 WGPUSurfaceSourceXlibWindow fromXlib = {0};
8608 fromXlib.chain.sType = WGPUSType_SurfaceSourceXlibWindow;
8609 fromXlib.display = _RGFW->display;
8610 fromXlib.window = window->src.window;
8611
8612 surfaceDesc.nextInChain = (WGPUChainedStruct*)&fromXlib.chain;
8613 return wgpuInstanceCreateSurface(instance, &surfaceDesc);
8614}
8615#endif
8616
8617#endif
8618/*
8619 End of X11 linux / wayland / unix defines
8620*/
8621
8622/*
8623
8624 Start of Wayland defayland
8625*/
8626
8627#ifdef RGFW_WAYLAND
8628#ifdef RGFW_X11
8629#undef RGFW_FUNC /* remove previous define */
8630#define RGFW_FUNC(func) func##_Wayland
8631#else
8632#define RGFW_FUNC(func) func
8633#endif
8634
8635/*
8636Wayland TODO: (out of date)
8637- fix RGFW_keyPressed lock state
8638
8639 RGFW_windowMoved, the window was moved (by the user)
8640 RGFW_windowRefresh The window content needs to be refreshed
8641
8642 RGFW_dataDrop a file has been dropped into the window
8643 RGFW_dataDrag
8644
8645- window args:
8646 #define RGFW_windowNoResize the window cannot be resized by the user
8647 #define RGFW_windowAllowDND the window supports drag and drop
8648 #define RGFW_scaleToMonitor scale the window to the screen
8649
8650- other missing functions functions ("TODO wayland") (~30 functions)
8651- fix buffer rendering weird behavior
8652*/
8653#include <errno.h>
8654#include <unistd.h>
8655#include <sys/mman.h>
8656#include <xkbcommon/xkbcommon.h>
8657#include <xkbcommon/xkbcommon-keysyms.h>
8658#include <xkbcommon/xkbcommon-compose.h>
8659#include <dirent.h>
8660#include <linux/kd.h>
8661#include <wayland-cursor.h>
8662#include <fcntl.h>
8663
8664struct wl_display* RGFW_getDisplay_Wayland(void) { return _RGFW->wl_display; }
8665struct wl_surface* RGFW_window_getWindow_Wayland(RGFW_window* win) { return win->src.surface; }
8666
8667
8668/* wayland global garbage (wayland bad, X11 is fine (ish) (not really)) */
8669#include "xdg-shell-client-protocol.h"
8670#include "xdg-toplevel-icon-v1-client-protocol.h"
8671#include "xdg-decoration-unstable-v1-client-protocol.h"
8672#include "relative-pointer-unstable-v1-client-protocol.h"
8673#include "pointer-constraints-unstable-v1-client-protocol.h"
8674#include "xdg-output-unstable-v1-client-protocol.h"
8675#include "pointer-warp-v1-client-protocol.h"
8676
8677void RGFW_toggleWaylandMaximized(RGFW_window* win, RGFW_bool maximized);
8678
8679static void RGFW_wl_setOpaque(RGFW_window* win) {
8680 struct wl_region* wl_region = wl_compositor_create_region(_RGFW->compositor);
8681
8682 if (!wl_region) return; /* return if no region was created */
8683
8684 wl_region_add(wl_region, 0, 0, win->w, win->h);
8685 wl_surface_set_opaque_region(win->src.surface, wl_region);
8686 wl_region_destroy(wl_region);
8687
8688}
8689
8690static void RGFW_wl_xdg_wm_base_ping_handler(void* data, struct xdg_wm_base* wm_base,
8691 u32 serial) {
8692 RGFW_UNUSED(data);
8693 xdg_wm_base_pong(wm_base, serial);
8694}
8695static void RGFW_wl_xdg_surface_configure_handler(void* data, struct xdg_surface* xdg_surface,
8696 u32 serial) {
8697
8698 xdg_surface_ack_configure(xdg_surface, serial);
8699
8700 RGFW_window* win = (RGFW_window*)data;
8701
8702 if (win == NULL) {
8703 win = _RGFW->kbOwner;
8704 if (win == NULL)
8705 return;
8706 }
8707
8708 /* useful for libdecor */
8709 if (win->src.activated != win->src.pending_activated) {
8710 win->src.activated = win->src.pending_activated;
8711 }
8712
8713 if (win->src.maximized != win->src.pending_maximized) {
8714 RGFW_toggleWaylandMaximized(win, win->src.pending_maximized);
8715
8716 RGFW_window_checkMode(win);
8717 }
8718
8719
8720 if (win->src.resizing) {
8721
8722 RGFW_windowResizedCallback(win, win->w, win->h);
8723 RGFW_window_resize(win, win->w, win->h);
8724 if (!(win->internal.flags & RGFW_windowTransparent)) {
8725 RGFW_wl_setOpaque(win);
8726 }
8727 }
8728
8729 win->src.configured = RGFW_TRUE;
8730}
8731
8732static void RGFW_wl_xdg_toplevel_configure_handler(void* data, struct xdg_toplevel* toplevel,
8733 i32 width, i32 height, struct wl_array* states) {
8734
8735 RGFW_UNUSED(toplevel);
8736 RGFW_window* win = (RGFW_window*)data;
8737
8738
8739 win->src.pending_activated = RGFW_FALSE;
8740 win->src.pending_maximized = RGFW_FALSE;
8741 win->src.resizing = RGFW_FALSE;
8742
8743
8744 enum xdg_toplevel_state* state;
8745 wl_array_for_each(state, states) {
8746 switch (*state) {
8747 case XDG_TOPLEVEL_STATE_ACTIVATED:
8748 win->src.pending_activated = RGFW_TRUE;
8749 break;
8750 case XDG_TOPLEVEL_STATE_MAXIMIZED:
8751 win->src.pending_maximized = RGFW_TRUE;
8752 break;
8753 default:
8754 break;
8755 }
8756
8757 }
8758 /* if width and height are not zero and are not the same as the window */
8759 /* the window is resizing so update the values */
8760 if ((width && height) && (win->w != width || win->h != height)) {
8761 win->src.resizing = RGFW_TRUE;
8762 win->src.w = win->w = width;
8763 win->src.h = win->h = height;
8764 }
8765}
8766
8767static void RGFW_wl_xdg_toplevel_close_handler(void* data, struct xdg_toplevel *toplevel) {
8768 RGFW_UNUSED(toplevel);
8769 RGFW_window* win = (RGFW_window*)data;
8770
8771 if (!win->internal.shouldClose) {
8772 RGFW_windowQuitCallback(win);
8773 }
8774}
8775
8776static void RGFW_wl_xdg_decoration_configure_handler(void* data,
8777 struct zxdg_toplevel_decoration_v1* zxdg_toplevel_decoration_v1, u32 mode) {
8778 RGFW_window* win = (RGFW_window*)data; RGFW_UNUSED(zxdg_toplevel_decoration_v1);
8779
8780 /* this is expected to run once */
8781 /* set the decoration mode set by earlier request */
8782 if (mode != win->src.decoration_mode) {
8783 win->src.decoration_mode = mode;
8784 }
8785}
8786
8787static void RGFW_wl_shm_format_handler(void* data, struct wl_shm *shm, u32 format) {
8788 RGFW_UNUSED(data); RGFW_UNUSED(shm); RGFW_UNUSED(format);
8789}
8790
8791static void RGFW_wl_relative_pointer_motion(void *data, struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1,
8792 u32 time_hi, u32 time_lo, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t dx_unaccel, wl_fixed_t dy_unaccel) {
8793
8794 RGFW_UNUSED(zwp_relative_pointer_v1); RGFW_UNUSED(time_hi); RGFW_UNUSED(time_lo);
8795 RGFW_UNUSED(dx_unaccel); RGFW_UNUSED(dy_unaccel);
8796
8797 RGFW_info* RGFW = (RGFW_info*)data;
8798
8799 RGFW_ASSERT(RGFW->mouseOwner != NULL);
8800 RGFW_window* win = RGFW->mouseOwner;
8801
8802 RGFW_ASSERT(win);
8803
8804 float vecX = (float)wl_fixed_to_double(dx);
8805 float vecY = (float)wl_fixed_to_double(dy);
8806 RGFW_mousePosCallback(win, win->internal.lastMouseX, win->internal.lastMouseY, vecX, vecY);
8807}
8808
8809static void RGFW_wl_pointer_locked(void *data, struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1) {
8810 RGFW_UNUSED(zwp_locked_pointer_v1);
8811 RGFW_info* RGFW = (RGFW_info*)data;
8812 wl_pointer_set_cursor(RGFW->wl_pointer, RGFW->mouse_enter_serial, NULL, 0, 0); /* draw no cursor */
8813}
8814
8815static void RGFW_wl_pointer_enter(void* data, struct wl_pointer* pointer, u32 serial,
8816 struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) {
8817 RGFW_info* RGFW = (RGFW_info*)data;
8818 RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
8819
8820 /* save when the pointer is locked or using default cursor */
8821 RGFW->mouse_enter_serial = serial;
8822 win->internal.mouseInside = RGFW_TRUE;
8823 RGFW->windowState.mouseEnter = RGFW_TRUE;
8824
8825 RGFW->mouseOwner = win;
8826
8827 /* set the cursor */
8828 if (win->src.using_custom_cursor) {
8829 wl_pointer_set_cursor(pointer, serial, win->src.custom_cursor_surface, 0, 0);
8830 }
8831 else {
8832 RGFW_window_setMouseDefault(win);
8833 }
8834
8835 i32 x = (i32)wl_fixed_to_double(surface_x);
8836 i32 y = (i32)wl_fixed_to_double(surface_y);
8837 RGFW_mouseNotifyCallback(win, x, y, RGFW_TRUE);
8838}
8839
8840static void RGFW_wl_pointer_leave(void* data, struct wl_pointer *pointer, u32 serial, struct wl_surface *surface) {
8841 RGFW_UNUSED(pointer); RGFW_UNUSED(serial);
8842 RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
8843 RGFW_info* RGFW = (RGFW_info*)data;
8844 if (RGFW->mouseOwner == win)
8845 RGFW->mouseOwner = NULL;
8846
8847 RGFW_mouseNotifyCallback(win, win->internal.lastMouseX, win->internal.lastMouseY, RGFW_FALSE);
8848}
8849
8850static void RGFW_wl_pointer_motion(void* data, struct wl_pointer *pointer, u32 time, wl_fixed_t x, wl_fixed_t y) {
8851 RGFW_UNUSED(pointer); RGFW_UNUSED(time);
8852
8853 RGFW_info* RGFW = (RGFW_info*)data;
8854 RGFW_ASSERT(RGFW->mouseOwner != NULL);
8855
8856 RGFW_window* win = RGFW->mouseOwner;
8857
8858 i32 convertedX = (i32)wl_fixed_to_double(x);
8859 i32 convertedY = (i32)wl_fixed_to_double(y);
8860 float newVecX = (float)(convertedX - win->internal.lastMouseX);
8861 float newVecY = (float)(convertedY - win->internal.lastMouseY);
8862
8863 RGFW_mousePosCallback(win, convertedX, convertedY, newVecX, newVecY);
8864}
8865
8866static void RGFW_wl_pointer_button(void* data, struct wl_pointer *pointer, u32 serial, u32 time, u32 button, u32 state) {
8867 RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(serial);
8868 RGFW_info* RGFW = (RGFW_info*)data;
8869
8870 RGFW_ASSERT(RGFW->mouseOwner != NULL);
8871 RGFW_window* win = RGFW->mouseOwner;
8872
8873 u32 b = (button - 0x110);
8874
8875 /* flip right and middle button codes */
8876 if (b == 1) b = 2;
8877 else if (b == 2) b = 1;
8878
8879 RGFW_mouseButtonCallback(win, (u8)b, RGFW_BOOL(state));
8880}
8881
8882static void RGFW_wl_pointer_axis(void* data, struct wl_pointer *pointer, u32 time, u32 axis, wl_fixed_t value) {
8883 RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(axis);
8884
8885 RGFW_info* RGFW = (RGFW_info*)data;
8886 RGFW_ASSERT(RGFW->mouseOwner != NULL);
8887 RGFW_window* win = RGFW->mouseOwner;
8888
8889 float scrollX = 0.0;
8890 float scrollY = 0.0;
8891
8892 if (!(win->internal.enabledEvents & (RGFW_BIT(RGFW_mouseScroll)))) return;
8893
8894 if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
8895 scrollX = (float)(-wl_fixed_to_double(value) / 10.0);
8896 else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
8897 scrollY = (float)(-wl_fixed_to_double(value) / 10.0);
8898
8899 RGFW_mouseScrollCallback(win, scrollX, scrollY);
8900}
8901
8902
8903static void RGFW_doNothing(void) { }
8904
8905static void RGFW_wl_keyboard_keymap(void* data, struct wl_keyboard *keyboard, u32 format, i32 fd, u32 size) {
8906 RGFW_UNUSED(keyboard); RGFW_UNUSED(format);
8907 RGFW_info* RGFW = (RGFW_info*)data;
8908
8909 char *keymap_string = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0);
8910 xkb_keymap_unref(RGFW->keymap);
8911 RGFW->keymap = xkb_keymap_new_from_string(RGFW->xkb_context, keymap_string, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
8912
8913 munmap(keymap_string, size);
8914 close(fd);
8915 xkb_state_unref(RGFW->xkb_state);
8916 RGFW->xkb_state = xkb_state_new(RGFW->keymap);
8917
8918 const char* locale = getenv("LC_ALL");
8919 if (!locale)
8920 locale = getenv("LC_CTYPE");
8921 if (!locale)
8922 locale = getenv("LANG");
8923 if (!locale)
8924 locale = "C";
8925
8926 struct xkb_compose_table* composeTable = xkb_compose_table_new_from_locale(RGFW->xkb_context, locale, XKB_COMPOSE_COMPILE_NO_FLAGS);
8927 if (composeTable) {
8928 RGFW->composeState = xkb_compose_state_new(composeTable, XKB_COMPOSE_STATE_NO_FLAGS);
8929 xkb_compose_table_unref(composeTable);
8930 }
8931}
8932
8933static void RGFW_wl_keyboard_enter(void* data, struct wl_keyboard *keyboard, u32 serial, struct wl_surface *surface, struct wl_array *keys) {
8934 RGFW_UNUSED(keyboard); RGFW_UNUSED(keys);
8935
8936 RGFW_info* RGFW = (RGFW_info*)data;
8937 RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
8938 RGFW->kbOwner = win;
8939
8940
8941 // this is to prevent race conditions
8942 if (RGFW->data_device != NULL && win->src.data_source != NULL) {
8943 wl_data_device_set_selection(RGFW->data_device, win->src.data_source, serial);
8944 }
8945 /* is set when RGFW_window_minimize is called; if the minimize button is */
8946 /* pressed this flag is not set since there is no event to listen for */
8947 if (win->src.minimized == RGFW_TRUE) win->src.minimized = RGFW_FALSE;
8948
8949 RGFW_focusCallback(win, RGFW_TRUE);
8950}
8951
8952static void RGFW_wl_keyboard_leave(void* data, struct wl_keyboard *keyboard, u32 serial, struct wl_surface *surface) {
8953 RGFW_UNUSED(keyboard); RGFW_UNUSED(serial);
8954
8955 RGFW_info* RGFW = (RGFW_info*)data;
8956 RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
8957 if (RGFW->kbOwner == win)
8958 RGFW->kbOwner = NULL;
8959
8960 RGFW_focusCallback(win, RGFW_FALSE);
8961}
8962
8963static xkb_keysym_t RGFW_wl_composeSymbol(RGFW_info* RGFW, xkb_keysym_t sym) {
8964 if (sym == XKB_KEY_NoSymbol || !RGFW->composeState)
8965 return sym;
8966 if (xkb_compose_state_feed(RGFW->composeState, sym) != XKB_COMPOSE_FEED_ACCEPTED)
8967 return sym;
8968 switch (xkb_compose_state_get_status(RGFW->composeState)) {
8969 case XKB_COMPOSE_COMPOSED:
8970 return xkb_compose_state_get_one_sym(RGFW->composeState);
8971 case XKB_COMPOSE_COMPOSING:
8972 case XKB_COMPOSE_CANCELLED:
8973 return XKB_KEY_NoSymbol;
8974 case XKB_COMPOSE_NOTHING:
8975 default:
8976 return sym;
8977 }
8978}
8979
8980static void RGFW_wl_keyboard_key(void* data, struct wl_keyboard *keyboard, u32 serial, u32 time, u32 key, u32 state) {
8981 RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time);
8982
8983 RGFW_info* RGFW = (RGFW_info*)data;
8984 if (RGFW->kbOwner == NULL) return;
8985
8986 RGFW_window *RGFW_key_win = RGFW->kbOwner;
8987 RGFW_key RGFWkey = RGFW_apiKeyToRGFW(key + 8);
8988
8989 RGFW_updateKeyMods(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")));
8990 RGFW_keyCallback(RGFW_key_win, (u8)RGFWkey, RGFW_key_win->internal.mod, RGFW_window_isKeyDown(RGFW_key_win, (u8)RGFWkey), RGFW_BOOL(state));
8991
8992 const xkb_keysym_t* keysyms;
8993 if (xkb_state_key_get_syms(RGFW->xkb_state, key + 8, &keysyms) == 1) {
8994 xkb_keysym_t keysym = RGFW_wl_composeSymbol(RGFW, keysyms[0]);
8995 u32 codepoint = xkb_keysym_to_utf32(keysym);
8996 if (codepoint != 0) {
8997 RGFW_keyCharCallback(RGFW_key_win, codepoint);
8998 }
8999 }
9000}
9001
9002static void RGFW_wl_keyboard_modifiers(void* data, struct wl_keyboard *keyboard, u32 serial, u32 mods_depressed, u32 mods_latched, u32 mods_locked, u32 group) {
9003 RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time);
9004 RGFW_info* RGFW = (RGFW_info*)data;
9005 xkb_state_update_mask(RGFW->xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
9006}
9007
9008static void RGFW_wl_seat_capabilities(void* data, struct wl_seat *seat, u32 capabilities) {
9009 RGFW_info* RGFW = (RGFW_info*)data;
9010 static struct wl_pointer_listener pointer_listener;
9011 RGFW_MEMSET(&pointer_listener, 0, sizeof(pointer_listener));
9012 pointer_listener.enter = &RGFW_wl_pointer_enter;
9013 pointer_listener.leave = &RGFW_wl_pointer_leave;
9014 pointer_listener.motion = &RGFW_wl_pointer_motion;
9015 pointer_listener.button = &RGFW_wl_pointer_button;
9016 pointer_listener.axis = &RGFW_wl_pointer_axis;
9017
9018 static struct wl_keyboard_listener keyboard_listener;
9019 RGFW_MEMSET(&keyboard_listener, 0, sizeof(keyboard_listener));
9020 keyboard_listener.keymap = &RGFW_wl_keyboard_keymap;
9021 keyboard_listener.enter = &RGFW_wl_keyboard_enter;
9022 keyboard_listener.leave = &RGFW_wl_keyboard_leave;
9023 keyboard_listener.key = &RGFW_wl_keyboard_key;
9024 keyboard_listener.modifiers = &RGFW_wl_keyboard_modifiers;
9025
9026 if ((capabilities & WL_SEAT_CAPABILITY_POINTER) && !RGFW->wl_pointer) {
9027 RGFW->wl_pointer = wl_seat_get_pointer(seat);
9028 wl_pointer_add_listener(RGFW->wl_pointer, &pointer_listener, RGFW);
9029 }
9030 if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && !RGFW->wl_keyboard) {
9031 RGFW->wl_keyboard = wl_seat_get_keyboard(seat);
9032 wl_keyboard_add_listener(RGFW->wl_keyboard, &keyboard_listener, RGFW);
9033 }
9034
9035 if (!(capabilities & WL_SEAT_CAPABILITY_POINTER) && RGFW->wl_pointer) {
9036 wl_pointer_destroy(RGFW->wl_pointer);
9037 }
9038 if (!(capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && RGFW->wl_keyboard) {
9039 wl_keyboard_destroy(RGFW->wl_keyboard);
9040 }
9041}
9042
9043static void RGFW_wl_output_set_geometry(void *data, struct wl_output *wl_output,
9044 i32 x, i32 y, i32 physical_width, i32 physical_height,
9045 i32 subpixel, const char *make, const char *model, i32 transform) {
9046
9047 RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon;
9048 monitor->x = x;
9049 monitor->y = y;
9050
9051 monitor->physW = (float)physical_width / 25.4f;
9052 monitor->physH = (float)physical_height / 25.4f;
9053
9054 RGFW_UNUSED(wl_output);
9055 RGFW_UNUSED(subpixel);
9056 RGFW_UNUSED(make);
9057 RGFW_UNUSED(model);
9058 RGFW_UNUSED(transform);
9059}
9060
9061static void RGFW_wl_output_handle_mode(void *data, struct wl_output *wl_output, u32 flags,
9062 i32 width, i32 height, i32 refresh) {
9063
9064 RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon;
9065
9066 RGFW_monitorMode mode;
9067 mode.w = width;
9068 mode.h = height;
9069 mode.refreshRate = (float)refresh / 1000.0f;
9070 mode.src = wl_output;
9071
9072 monitor->node->modeCount += 1;
9073
9074 RGFW_monitorMode* modes = (RGFW_monitorMode*)RGFW_ALLOC(monitor->node->modeCount * sizeof(RGFW_monitorMode));
9075
9076 if (monitor->node->modeCount > 1) {
9077 RGFW_monitor_getModesPtr(monitor, &modes);
9078 RGFW_FREE(monitor->node->modes);
9079 }
9080
9081 modes[monitor->node->modeCount - 1] = mode;
9082 monitor->node->modes = modes;
9083
9084 if (flags & WL_OUTPUT_MODE_CURRENT) {
9085 monitor->mode = mode;
9086 } else {
9087 }
9088}
9089
9090static void RGFW_wl_output_set_scale(void *data, struct wl_output *wl_output, i32 factor) {
9091 RGFW_UNUSED(wl_output);
9092 RGFW_monitor* mon = &((RGFW_monitorNode*)data)->mon;
9093
9094 mon->scaleX = (float)factor;
9095 mon->scaleY = (float)factor;
9096}
9097
9098static void RGFW_wl_output_set_name(void *data, struct wl_output *wl_output, const char *name) {
9099 RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon;
9100
9101 RGFW_STRNCPY(monitor->name, name, sizeof(monitor->name) - 1);
9102 monitor->name[sizeof(monitor->name) - 1] = '\0';
9103
9104 RGFW_UNUSED(wl_output);
9105
9106}
9107
9108static void RGFW_xdg_output_logical_pos(void *data, struct zxdg_output_v1 *zxdg_output_v1, i32 x, i32 y) {
9109 RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon;
9110 monitor->x = x;
9111 monitor->y = y;
9112 RGFW_UNUSED(zxdg_output_v1);
9113}
9114
9115static void RGFW_xdg_output_logical_size(void *data, struct zxdg_output_v1 *zxdg_output_v1, i32 width, i32 height) {
9116 RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon;
9117
9118 float mon_float_width = (float) monitor->mode.w;
9119 float mon_float_height = (float) monitor->mode.h;
9120
9121 float scaleX = (mon_float_width / (float) width);
9122 float scaleY = (mon_float_height / (float) height);
9123 RGFW_UNUSED(scaleY);
9124
9125 float dpi = scaleX * 96.0f;
9126
9127 monitor->pixelRatio = dpi >= 192.0f ? 2.0f : 1.0f;
9128
9129 /* under xwayland the monitor changes w & h when compositor scales it */
9130 monitor->mode.w = width;
9131 monitor->mode.h = height;
9132 RGFW_UNUSED(zxdg_output_v1);
9133}
9134
9135
9136static void RGFW_wl_output_handle_done(void* data, struct wl_output* output) {
9137 RGFW_UNUSED(output);
9138
9139 RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon;
9140
9141 if (monitor->physW <= 0 || monitor->physH <= 0) {
9142 monitor->physW = (i32) ((float)monitor->mode.w / 96.0f);
9143 monitor->physH = (i32) ((float)monitor->mode.h / 96.0f);
9144 }
9145
9146 if (((RGFW_monitorNode*)data)->disconnected == RGFW_FALSE) {
9147 return;
9148 }
9149
9150 ((RGFW_monitorNode*)data)->disconnected = RGFW_TRUE;
9151
9152 RGFW_monitorCallback(_RGFW->root, monitor, RGFW_TRUE);
9153}
9154
9155static void RGFW_wl_create_outputs(struct wl_registry *const registry, u32 id) {
9156 struct wl_output *output = wl_registry_bind(registry, id, &wl_output_interface, wl_display_get_version(_RGFW->wl_display) < 4 ? 3 : 4);
9157 RGFW_monitorNode* node;
9158 RGFW_monitor mon;
9159
9160 if (!output) return;
9161
9162 char RGFW_mon_default_name[10];
9163
9164 RGFW_SNPRINTF(RGFW_mon_default_name, sizeof(RGFW_mon_default_name), "monitor-%li", _RGFW->monitors.count);
9165 RGFW_STRNCPY(mon.name, RGFW_mon_default_name, sizeof(mon.name) - 1);
9166 mon.name[sizeof(mon.name) - 1] = '\0';
9167
9168 /* set in case compositor does not send one */
9169 /* or no xdg_output support */
9170 mon.scaleY = mon.scaleX = mon.pixelRatio = 1.0f;
9171
9172 node = RGFW_monitors_add(&mon);
9173 if (node == NULL) return;
9174
9175 node->modeCount = 0;
9176 node->disconnected = RGFW_TRUE;
9177 node->id = id;
9178 node->output = output;
9179
9180 static const struct wl_output_listener wl_output_listener = {
9181 .geometry = RGFW_wl_output_set_geometry,
9182 .mode = RGFW_wl_output_handle_mode,
9183 .done = RGFW_wl_output_handle_done,
9184 .scale = RGFW_wl_output_set_scale,
9185 .name = RGFW_wl_output_set_name,
9186 .description = (void (*)(void *, struct wl_output *, const char *))&RGFW_doNothing
9187 };
9188
9189 /* the wl_output will have a reference to the node */
9190 wl_output_set_user_data(output, node);
9191
9192 /* pass the monitor so we can access it in the callback functions */
9193 wl_output_add_listener(output, &wl_output_listener, node);
9194
9195 if (!_RGFW->xdg_output_manager)
9196 return; /* compositor does not support it */
9197
9198 static const struct zxdg_output_v1_listener xdg_output_listener = {
9199 .name = (void (*)(void *,struct zxdg_output_v1 *, const char *))&RGFW_doNothing,
9200 .done = (void (*)(void *,struct zxdg_output_v1 *))&RGFW_doNothing,
9201 .description = (void (*)(void *,struct zxdg_output_v1 *, const char *))&RGFW_doNothing,
9202 .logical_position = RGFW_xdg_output_logical_pos,
9203 .logical_size = RGFW_xdg_output_logical_size
9204 };
9205
9206 node->xdg_output = zxdg_output_manager_v1_get_xdg_output(_RGFW->xdg_output_manager, node->output);
9207 zxdg_output_v1_add_listener(node->xdg_output, &xdg_output_listener, node);
9208}
9209
9210static void RGFW_wl_surface_enter(void *data, struct wl_surface *wl_surface, struct wl_output *output) {
9211 RGFW_UNUSED(wl_surface);
9212
9213 RGFW_window* win = (RGFW_window*)data;
9214 RGFW_monitorNode* node = wl_output_get_user_data(output);
9215 if (node == NULL) return;
9216
9217 win->src.active_monitor = node;
9218
9219 if (win->internal.flags & RGFW_windowScaleToMonitor)
9220 RGFW_window_scaleToMonitor(win);
9221}
9222
9223static void RGFW_wl_data_source_send(void *data, struct wl_data_source *wl_data_source, const char *mime_type, i32 fd) {
9224 RGFW_UNUSED(data); RGFW_UNUSED(wl_data_source);
9225
9226 // a client can accept our clipboard
9227 if (RGFW_STRNCMP(mime_type, "text/plain;charset=utf-8", 25) == 0) {
9228 // do not write \0
9229 write(fd, _RGFW->clipboard, _RGFW->clipboard_len - 1);
9230 }
9231
9232 close(fd);
9233}
9234
9235static void RGFW_wl_data_source_cancelled(void *data, struct wl_data_source *wl_data_source) {
9236
9237 RGFW_info* RGFW = (RGFW_info*)data;
9238
9239 if (RGFW->kbOwner->src.data_source == wl_data_source) {
9240 RGFW->kbOwner->src.data_source = NULL;
9241 }
9242
9243 wl_data_source_destroy(wl_data_source);
9244
9245}
9246
9247static void RGFW_wl_data_device_data_offer(void *data, struct wl_data_device *wl_data_device, struct wl_data_offer *wl_data_offer) {
9248
9249 RGFW_UNUSED(data); RGFW_UNUSED(wl_data_device);
9250 static const struct wl_data_offer_listener wl_data_offer_listener = {
9251 .offer = (void (*)(void *data, struct wl_data_offer *wl_data_offer, const char *))RGFW_doNothing,
9252 .source_actions = (void (*)(void *data, struct wl_data_offer *wl_data_offer, u32 dnd_action))RGFW_doNothing,
9253 .action = (void (*)(void *data, struct wl_data_offer *wl_data_offer, u32 dnd_action))RGFW_doNothing
9254 };
9255 wl_data_offer_add_listener(wl_data_offer, &wl_data_offer_listener, NULL);
9256}
9257
9258static void RGFW_wl_data_device_selection(void *data, struct wl_data_device *wl_data_device, struct wl_data_offer *wl_data_offer) {
9259 RGFW_UNUSED(data); RGFW_UNUSED(wl_data_device);
9260 /* Clipboard is empty */
9261 if (wl_data_offer == NULL) {
9262 return;
9263 }
9264
9265 int pfds[2];
9266 pipe(pfds);
9267
9268 wl_data_offer_receive(wl_data_offer, "text/plain;charset=utf-8", pfds[1]);
9269 close(pfds[1]);
9270
9271 wl_display_roundtrip(_RGFW->wl_display);
9272
9273 char buf[1024];
9274
9275 ssize_t n = read(pfds[0], buf, sizeof(buf));
9276
9277 _RGFW->clipboard = (char*)RGFW_ALLOC((size_t)n);
9278 RGFW_ASSERT(_RGFW->clipboard != NULL);
9279 RGFW_STRNCPY(_RGFW->clipboard, buf, (size_t)n);
9280
9281 _RGFW->clipboard_len = (size_t)n + 1;
9282
9283 close(pfds[0]);
9284
9285 wl_data_offer_destroy(wl_data_offer);
9286
9287}
9288
9289static void RGFW_wl_global_registry_handler(void* data, struct wl_registry *registry, u32 id, const char *interface, u32 version) {
9290
9291 static struct wl_seat_listener seat_listener = {&RGFW_wl_seat_capabilities, (void (*)(void *, struct wl_seat *, const char *))&RGFW_doNothing};
9292 static const struct wl_shm_listener shm_listener = { .format = RGFW_wl_shm_format_handler };
9293
9294 RGFW_info* RGFW = (RGFW_info*)data;
9295 RGFW_UNUSED(version);
9296
9297 if (RGFW_STRNCMP(interface, "wl_compositor", 16) == 0) {
9298 RGFW->compositor = wl_registry_bind(registry, id, &wl_compositor_interface, 4);
9299 } else if (RGFW_STRNCMP(interface, "xdg_wm_base", 12) == 0) {
9300 RGFW->xdg_wm_base = wl_registry_bind(registry, id, &xdg_wm_base_interface, 1);
9301 } else if (RGFW_STRNCMP(interface, zxdg_decoration_manager_v1_interface.name, 255) == 0) {
9302 RGFW->decoration_manager = wl_registry_bind(registry, id, &zxdg_decoration_manager_v1_interface, 1);
9303 } else if (RGFW_STRNCMP(interface, zwp_pointer_constraints_v1_interface.name, 255) == 0) {
9304 RGFW->constraint_manager = wl_registry_bind(registry, id, &zwp_pointer_constraints_v1_interface, 1);
9305 } else if (RGFW_STRNCMP(interface, zwp_relative_pointer_manager_v1_interface.name, 255) == 0) {
9306 RGFW->relative_pointer_manager = wl_registry_bind(registry, id, &zwp_relative_pointer_manager_v1_interface, 1);
9307 } else if (RGFW_STRNCMP(interface, xdg_toplevel_icon_manager_v1_interface.name, 255) == 0) {
9308 RGFW->icon_manager = wl_registry_bind(registry, id, &xdg_toplevel_icon_manager_v1_interface, 1);
9309 } else if (RGFW_STRNCMP(interface, "wl_shm", 7) == 0) {
9310 RGFW->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
9311 wl_shm_add_listener(RGFW->shm, &shm_listener, RGFW);
9312 } else if (RGFW_STRNCMP(interface,"wl_seat", 8) == 0) {
9313 RGFW->seat = wl_registry_bind(registry, id, &wl_seat_interface, 1);
9314 wl_seat_add_listener(RGFW->seat, &seat_listener, RGFW);
9315 } else if (RGFW_STRNCMP(interface, zxdg_output_manager_v1_interface.name, 255) == 0) {
9316 RGFW->xdg_output_manager = wl_registry_bind(registry, id, &zxdg_output_manager_v1_interface, 1);
9317 } else if (RGFW_STRNCMP(interface,"wl_output", 10) == 0) {
9318 RGFW_wl_create_outputs(registry, id);
9319 } else if (RGFW_STRNCMP(interface, wp_pointer_warp_v1_interface.name, 255) == 0) {
9320 RGFW->wp_pointer_warp = wl_registry_bind(registry, id, &wp_pointer_warp_v1_interface, 1);
9321 } else if (RGFW_STRNCMP(interface,"wl_data_device_manager", 23) == 0) {
9322 RGFW->data_device_manager = wl_registry_bind(registry, id, &wl_data_device_manager_interface, 1);
9323 }
9324}
9325
9326static void RGFW_wl_global_registry_remove(void* data, struct wl_registry *registry, u32 id) {
9327 RGFW_UNUSED(data); RGFW_UNUSED(registry);
9328 RGFW_info* RGFW = (RGFW_info*)data;
9329 RGFW_monitorNode* prev = RGFW->monitors.list.head;
9330 RGFW_monitorNode* node = NULL;
9331 if (prev == NULL) return;
9332
9333 if (prev->id != id) {
9334 /* find the first node that has a matching id */
9335 while(prev->next != NULL && prev->next->id != id) {
9336 prev = prev->next;
9337 }
9338
9339 if (prev->next == NULL) return;
9340 node = prev->next;
9341 } else {
9342 node = prev;
9343 }
9344
9345 if (node->output) {
9346 wl_output_destroy(node->output);
9347 }
9348
9349 if (node->xdg_output) {
9350 zxdg_output_v1_destroy(node->xdg_output);
9351 }
9352
9353 if (node->modeCount) {
9354 RGFW_FREE(node->modes);
9355 node->modeCount = 0;
9356 }
9357
9358 RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_FALSE);
9359 RGFW_monitors_remove(node, prev);
9360}
9361
9362static void RGFW_wl_randname(char *buf) {
9363 struct timespec ts;
9364 clock_gettime(CLOCK_REALTIME, &ts);
9365 long r = ts.tv_nsec;
9366
9367 int i;
9368 for (i = 0; i < 6; i++) {
9369 buf[i] = (char)('A'+(r&15)+(r&16)*2);
9370 r >>= 5;
9371 }
9372}
9373
9374static int RGFW_wl_anonymous_shm_open(void) {
9375 char name[] = "/RGFW-wayland-XXXXXX";
9376 int retries = 100;
9377
9378 do {
9379 RGFW_wl_randname(name + RGFW_unix_stringlen(name) - 6);
9380
9381 --retries;
9382 /* shm_open guarantees that O_CLOEXEC is set */
9383 int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
9384 if (fd >= 0) {
9385 shm_unlink(name);
9386 return fd;
9387 }
9388 } while (retries > 0 && errno == EEXIST);
9389
9390 return -1;
9391}
9392
9393static int RGFW_wl_create_shm_file(off_t size) {
9394 int fd = RGFW_wl_anonymous_shm_open();
9395 if (fd < 0) {
9396 return fd;
9397 }
9398
9399 if (ftruncate(fd, size) < 0) {
9400 close(fd);
9401 return -1;
9402 }
9403
9404 return fd;
9405}
9406
9407i32 RGFW_initPlatform_Wayland(void) {
9408 _RGFW->wl_display = wl_display_connect(NULL);
9409 if (_RGFW->wl_display == NULL) {
9410 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errWayland, "Failed to load Wayland display");
9411 return -1;
9412 }
9413
9414 _RGFW->compositor = NULL;
9415 static const struct wl_registry_listener registry_listener = {
9416 .global = RGFW_wl_global_registry_handler,
9417 .global_remove = RGFW_wl_global_registry_remove,
9418 };
9419
9420 _RGFW->registry = wl_display_get_registry(_RGFW->wl_display);
9421 wl_registry_add_listener(_RGFW->registry, &registry_listener, _RGFW);
9422
9423 wl_display_roundtrip(_RGFW->wl_display); /* bind to globals */
9424
9425 if (_RGFW->compositor == NULL) {
9426 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errWayland, "Can't find compositor.");
9427 return 1;
9428 }
9429
9430 if (_RGFW->wl_cursor_theme == NULL) {
9431 _RGFW->wl_cursor_theme = wl_cursor_theme_load(NULL, 24, _RGFW->shm);
9432 _RGFW->cursor_surface = wl_compositor_create_surface(_RGFW->compositor);
9433 }
9434
9435 u8 RGFW_blk[] = { 0, 0, 0, 0 };
9436 _RGFW->hiddenMouse = RGFW_loadMouse(RGFW_blk, 1, 1, RGFW_formatRGBA8);
9437
9438 static const struct xdg_wm_base_listener xdg_wm_base_listener = {
9439 .ping = RGFW_wl_xdg_wm_base_ping_handler,
9440 };
9441
9442 xdg_wm_base_add_listener(_RGFW->xdg_wm_base, &xdg_wm_base_listener, NULL);
9443
9444 _RGFW->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
9445
9446 static const struct wl_data_device_listener wl_data_device_listener = {
9447 .data_offer = RGFW_wl_data_device_data_offer,
9448 .enter = (void (*)(void *, struct wl_data_device *, u32, struct wl_surface*, wl_fixed_t, wl_fixed_t, struct wl_data_offer *))&RGFW_doNothing,
9449 .leave = (void (*)(void *, struct wl_data_device *))&RGFW_doNothing,
9450 .motion = (void (*)(void *, struct wl_data_device *, u32, wl_fixed_t, wl_fixed_t))&RGFW_doNothing,
9451 .drop = (void (*)(void *, struct wl_data_device *))&RGFW_doNothing,
9452 .selection = RGFW_wl_data_device_selection
9453 };
9454
9455 if (_RGFW->seat && _RGFW->data_device_manager) {
9456 _RGFW->data_device = wl_data_device_manager_get_data_device(_RGFW->data_device_manager, _RGFW->seat);
9457 wl_data_device_add_listener(_RGFW->data_device, &wl_data_device_listener, NULL);
9458 }
9459
9460 return 0;
9461}
9462
9463void RGFW_deinitPlatform_Wayland(void) {
9464 if (_RGFW->clipboard) {
9465 RGFW_FREE(_RGFW->clipboard);
9466 _RGFW->clipboard = NULL;
9467 }
9468
9469 if (_RGFW->wl_pointer) {
9470 wl_pointer_destroy(_RGFW->wl_pointer);
9471 }
9472 if (_RGFW->wl_keyboard) {
9473 wl_keyboard_destroy(_RGFW->wl_keyboard);
9474 }
9475
9476 wl_registry_destroy(_RGFW->registry);
9477 if (_RGFW->decoration_manager != NULL)
9478 zxdg_decoration_manager_v1_destroy(_RGFW->decoration_manager);
9479 if (_RGFW->relative_pointer_manager != NULL) {
9480 zwp_relative_pointer_manager_v1_destroy(_RGFW->relative_pointer_manager);
9481 }
9482
9483 if (_RGFW->relative_pointer) {
9484 zwp_relative_pointer_v1_destroy(_RGFW->relative_pointer);
9485 }
9486
9487 if (_RGFW->constraint_manager != NULL) {
9488 zwp_pointer_constraints_v1_destroy(_RGFW->constraint_manager);
9489 }
9490
9491 if (_RGFW->xdg_output_manager != NULL)
9492 if (_RGFW->icon_manager != NULL) {
9493 xdg_toplevel_icon_manager_v1_destroy(_RGFW->icon_manager);
9494 }
9495
9496 if (_RGFW->xdg_output_manager) {
9497 zxdg_output_manager_v1_destroy(_RGFW->xdg_output_manager);
9498 }
9499
9500 if (_RGFW->data_device_manager) {
9501 wl_data_device_manager_destroy(_RGFW->data_device_manager);
9502 }
9503
9504 if (_RGFW->data_device) {
9505 wl_data_device_destroy(_RGFW->data_device);
9506 }
9507
9508 if (_RGFW->wl_cursor_theme != NULL) {
9509 wl_cursor_theme_destroy(_RGFW->wl_cursor_theme);
9510 }
9511
9512 if (_RGFW->wp_pointer_warp != NULL) {
9513 wp_pointer_warp_v1_destroy(_RGFW->wp_pointer_warp);
9514 }
9515
9516 RGFW_freeMouse(_RGFW->hiddenMouse);
9517
9518 RGFW_monitorNode* node = _RGFW->monitors.list.head;
9519
9520 while (node != NULL) {
9521 if (node->output) {
9522 wl_output_destroy(node->output);
9523 }
9524
9525 if (node->xdg_output) {
9526 zxdg_output_v1_destroy(node->xdg_output);
9527 }
9528
9529 _RGFW->monitors.count -= 1;
9530 node = node->next;
9531
9532 }
9533
9534 wl_surface_destroy(_RGFW->cursor_surface);
9535 wl_shm_destroy(_RGFW->shm);
9536 wl_seat_release(_RGFW->seat);
9537 xdg_wm_base_destroy(_RGFW->xdg_wm_base);
9538 wl_compositor_destroy(_RGFW->compositor);
9539 wl_display_disconnect(_RGFW->wl_display);
9540}
9541
9542RGFW_format RGFW_FUNC(RGFW_nativeFormat)(void) { return RGFW_formatBGRA8; }
9543
9544RGFW_bool RGFW_FUNC(RGFW_createSurfacePtr) (u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) {
9545 RGFW_ASSERT(surface != NULL);
9546 surface->data = data;
9547 surface->w = w;
9548 surface->h = h;
9549 surface->format = format;
9550 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoBuffer, "Creating a 4 channel buffer");
9551
9552 u32 size = (u32)(surface->w * surface->h * 4);
9553 int fd = RGFW_wl_create_shm_file(size);
9554 if (fd < 0) {
9555 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, "Failed to create a buffer.");
9556 return RGFW_FALSE;
9557 }
9558
9559 surface->native.pool = wl_shm_create_pool(_RGFW->shm, fd, (i32)size);
9560
9561 surface->native.buffer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
9562 if (surface->native.buffer == MAP_FAILED) {
9563 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, "mmap failed.");
9564 return RGFW_FALSE;
9565 }
9566
9567 surface->native.fd = fd;
9568 surface->native.format = RGFW_formatBGRA8;
9569 return RGFW_TRUE;
9570}
9571
9572void RGFW_FUNC(RGFW_window_blitSurface) (RGFW_window* win, RGFW_surface* surface) {
9573 RGFW_ASSERT(surface != NULL);
9574
9575 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);
9576 RGFW_copyImageData(surface->native.buffer, surface->w, RGFW_MIN(win->h, surface->h), surface->native.format, surface->data, surface->format, surface->convertFunc);
9577
9578 wl_surface_attach(win->src.surface, surface->native.wl_buffer, 0, 0);
9579 wl_surface_damage(win->src.surface, 0, 0, RGFW_MIN(win->w, surface->w), RGFW_MIN(win->h, surface->h));
9580 wl_surface_commit(win->src.surface);
9581
9582 wl_buffer_destroy(surface->native.wl_buffer);
9583}
9584
9585void RGFW_FUNC(RGFW_surface_freePtr) (RGFW_surface* surface) {
9586 RGFW_ASSERT(surface != NULL);
9587
9588 wl_shm_pool_destroy(surface->native.pool);
9589 close(surface->native.fd);
9590
9591 munmap(surface->native.buffer, (size_t)(surface->w * surface->h * 4));
9592}
9593
9594void RGFW_FUNC(RGFW_window_setBorder) (RGFW_window* win, RGFW_bool border) {
9595 RGFW_setBit(&win->internal.flags, RGFW_windowNoBorder, !border);
9596
9597 /* for now just toggle between SSD & CSD depending on the bool */
9598 if (_RGFW->decoration_manager != NULL) {
9599 zxdg_toplevel_decoration_v1_set_mode(win->src.decoration, (border ? ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE : ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE));
9600 }
9601}
9602
9603void RGFW_FUNC(RGFW_window_setRawMouseModePlatform) (RGFW_window* win, RGFW_bool state) {
9604 RGFW_ASSERT(win);
9605 if (_RGFW->relative_pointer_manager == NULL) return;
9606
9607 if (state == RGFW_FALSE) {
9608 if (_RGFW->relative_pointer != NULL)
9609 zwp_relative_pointer_v1_destroy(_RGFW->relative_pointer);
9610 _RGFW->relative_pointer = NULL;
9611 return;
9612 }
9613
9614 if (_RGFW->relative_pointer != NULL) return;
9615
9616 _RGFW->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(_RGFW->relative_pointer_manager, _RGFW->wl_pointer);
9617
9618 static const struct zwp_relative_pointer_v1_listener relative_motion_listener = {
9619 .relative_motion = RGFW_wl_relative_pointer_motion
9620 };
9621
9622 zwp_relative_pointer_v1_add_listener(_RGFW->relative_pointer, &relative_motion_listener, _RGFW);
9623}
9624
9625void RGFW_FUNC(RGFW_window_captureMousePlatform) (RGFW_window* win, RGFW_bool state) {
9626 RGFW_ASSERT(win);
9627
9628 /* compositor has no support or window already is locked do nothing */
9629 if (_RGFW->constraint_manager == NULL) return;
9630
9631 if (state == RGFW_FALSE) {
9632 if (win->src.locked_pointer != NULL)
9633 zwp_locked_pointer_v1_destroy(win->src.locked_pointer);
9634 win->src.locked_pointer = NULL;
9635 return;
9636 }
9637
9638
9639 if (win->src.locked_pointer != NULL) return;
9640 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);
9641
9642 static const struct zwp_locked_pointer_v1_listener locked_listener = {
9643 .locked = RGFW_wl_pointer_locked,
9644 .unlocked = (void (*)(void *, struct zwp_locked_pointer_v1 *))RGFW_doNothing
9645 };
9646
9647 zwp_locked_pointer_v1_add_listener(win->src.locked_pointer, &locked_listener, _RGFW);
9648}
9649
9650RGFW_window* RGFW_FUNC(RGFW_createWindowPlatform) (const char* name, RGFW_windowFlags flags, RGFW_window* win) {
9651 RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningWayland, "RGFW Wayland support is experimental");
9652
9653 static const struct xdg_surface_listener xdg_surface_listener = {
9654 .configure = RGFW_wl_xdg_surface_configure_handler,
9655 };
9656
9657 static const struct wl_surface_listener wl_surface_listener = {
9658 .enter = RGFW_wl_surface_enter,
9659 .leave = (void (*)(void *, struct wl_surface *, struct wl_output *))&RGFW_doNothing,
9660 .preferred_buffer_scale = (void (*)(void *, struct wl_surface *, i32))&RGFW_doNothing,
9661 .preferred_buffer_transform = (void (*)(void *, struct wl_surface *, u32))&RGFW_doNothing
9662 };
9663
9664 win->src.surface = wl_compositor_create_surface(_RGFW->compositor);
9665 wl_surface_add_listener(win->src.surface, &wl_surface_listener, win);
9666
9667 /* create a surface for a custom cursor */
9668 win->src.custom_cursor_surface = wl_compositor_create_surface(_RGFW->compositor);
9669
9670 win->src.xdg_surface = xdg_wm_base_get_xdg_surface(_RGFW->xdg_wm_base, win->src.surface);
9671 xdg_surface_add_listener(win->src.xdg_surface, &xdg_surface_listener, win);
9672
9673 xdg_wm_base_set_user_data(_RGFW->xdg_wm_base, win);
9674
9675 win->src.xdg_toplevel = xdg_surface_get_toplevel(win->src.xdg_surface);
9676
9677 if (_RGFW->className == NULL)
9678 _RGFW->className = (char*)name;
9679
9680 xdg_toplevel_set_app_id(win->src.xdg_toplevel, name);
9681
9682 xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->w, win->h);
9683
9684 if (!(win->internal.flags & RGFW_windowTransparent)) { /* no transparency */
9685 RGFW_wl_setOpaque(win);
9686 }
9687
9688 static const struct xdg_toplevel_listener xdg_toplevel_listener = {
9689 .configure = RGFW_wl_xdg_toplevel_configure_handler,
9690 .close = RGFW_wl_xdg_toplevel_close_handler,
9691 };
9692
9693 xdg_toplevel_add_listener(win->src.xdg_toplevel, &xdg_toplevel_listener, win);
9694
9695 /* compositor supports both SSD & CSD
9696 So choose accordingly
9697 */
9698 if (_RGFW->decoration_manager) {
9699 u32 decoration_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE;
9700 win->src.decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(
9701 _RGFW->decoration_manager, win->src.xdg_toplevel);
9702
9703 static const struct zxdg_toplevel_decoration_v1_listener xdg_decoration_listener = {
9704 .configure = RGFW_wl_xdg_decoration_configure_handler
9705 };
9706
9707 zxdg_toplevel_decoration_v1_add_listener(win->src.decoration, &xdg_decoration_listener, win);
9708
9709 /* we want no decorations */
9710 if ((flags & RGFW_windowNoBorder)) {
9711 decoration_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
9712 }
9713
9714 zxdg_toplevel_decoration_v1_set_mode(win->src.decoration, decoration_mode);
9715
9716 /* no xdg_decoration support */
9717 } else if (!(flags & RGFW_windowNoBorder)) {
9718 /* TODO, some fallback */
9719 #ifdef RGFW_LIBDECOR
9720 static struct libdecor_interface interface = {
9721 .error = NULL,
9722 };
9723
9724 static struct libdecor_frame_interface frameInterface = {0}; /*= {
9725 RGFW_wl_handle_configure,
9726 RGFW_wl_handle_close,
9727 RGFW_wl_handle_commit,
9728 RGFW_wl_handle_dismiss_popup,
9729 };*/
9730
9731 win->src.decorContext = libdecor_new(_RGFW->wl_display, &interface);
9732 if (win->src.decorContext) {
9733 struct libdecor_frame *frame = libdecor_decorate(win->src.decorContext, win->src.surface, &frameInterface, win);
9734 if (!frame) {
9735 libdecor_unref(win->src.decorContext);
9736 win->src.decorContext = NULL;
9737 } else {
9738 libdecor_frame_set_app_id(frame, "my-libdecor-app");
9739 libdecor_frame_set_title(frame, "My Libdecor Window");
9740 }
9741 }
9742 #endif
9743 }
9744
9745 if (_RGFW->icon_manager != NULL) {
9746 /* set the default wayland icon */
9747 xdg_toplevel_icon_manager_v1_set_icon(_RGFW->icon_manager, win->src.xdg_toplevel, NULL);
9748 }
9749
9750 wl_surface_commit(win->src.surface);
9751
9752 while (win->src.configured == RGFW_FALSE) {
9753 wl_display_dispatch(_RGFW->wl_display);
9754 }
9755
9756 RGFW_UNUSED(name);
9757
9758 return win;
9759}
9760
9761RGFW_bool RGFW_FUNC(RGFW_getGlobalMouse) (i32* x, i32* y) {
9762 RGFW_init();
9763 if (x) *x = 0;
9764 if (y) *y = 0;
9765 return RGFW_FALSE;
9766}
9767
9768RGFW_key RGFW_FUNC(RGFW_physicalToMappedKey)(RGFW_key key) {
9769 u32 keycode = RGFW_rgfwToApiKey(key);
9770 xkb_keycode_t kc = keycode + 8;
9771 xkb_keysym_t sym = xkb_state_key_get_one_sym(_RGFW->xkb_state, kc);
9772 if (sym < 256) {
9773 return (RGFW_key)sym;
9774 }
9775
9776 switch (sym) {
9777 case XKB_KEY_F1: return RGFW_F1;
9778 case XKB_KEY_F2: return RGFW_F2;
9779 case XKB_KEY_F3: return RGFW_F3;
9780 case XKB_KEY_F4: return RGFW_F4;
9781 case XKB_KEY_F5: return RGFW_F5;
9782 case XKB_KEY_F6: return RGFW_F6;
9783 case XKB_KEY_F7: return RGFW_F7;
9784 case XKB_KEY_F8: return RGFW_F8;
9785 case XKB_KEY_F9: return RGFW_F9;
9786 case XKB_KEY_F10: return RGFW_F10;
9787 case XKB_KEY_F11: return RGFW_F11;
9788 case XKB_KEY_F12: return RGFW_F12;
9789 case XKB_KEY_F13: return RGFW_F13;
9790 case XKB_KEY_F14: return RGFW_F14;
9791 case XKB_KEY_F15: return RGFW_F15;
9792 case XKB_KEY_F16: return RGFW_F16;
9793 case XKB_KEY_F17: return RGFW_F17;
9794 case XKB_KEY_F18: return RGFW_F18;
9795 case XKB_KEY_F19: return RGFW_F19;
9796 case XKB_KEY_F20: return RGFW_F20;
9797 case XKB_KEY_F21: return RGFW_F21;
9798 case XKB_KEY_F22: return RGFW_F22;
9799 case XKB_KEY_F23: return RGFW_F23;
9800 case XKB_KEY_F24: return RGFW_F24;
9801 case XKB_KEY_F25: return RGFW_F25;
9802 case XKB_KEY_Shift_L: return RGFW_shiftL;
9803 case XKB_KEY_Shift_R: return RGFW_shiftR;
9804 case XKB_KEY_Control_L: return RGFW_controlL;
9805 case XKB_KEY_Control_R: return RGFW_controlR;
9806 case XKB_KEY_Alt_L: return RGFW_altL;
9807 case XKB_KEY_Alt_R: return RGFW_altR;
9808 case XKB_KEY_Super_L: return RGFW_superL;
9809 case XKB_KEY_Super_R: return RGFW_superR;
9810 case XKB_KEY_Caps_Lock: return RGFW_capsLock;
9811 case XKB_KEY_Num_Lock: return RGFW_numLock;
9812 case XKB_KEY_Scroll_Lock:return RGFW_scrollLock;
9813 case XKB_KEY_Up: return RGFW_up;
9814 case XKB_KEY_Down: return RGFW_down;
9815 case XKB_KEY_Left: return RGFW_left;
9816 case XKB_KEY_Right: return RGFW_right;
9817 case XKB_KEY_Home: return RGFW_home;
9818 case XKB_KEY_End: return RGFW_end;
9819 case XKB_KEY_Page_Up: return RGFW_pageUp;
9820 case XKB_KEY_Page_Down: return RGFW_pageDown;
9821 case XKB_KEY_Insert: return RGFW_insert;
9822 case XKB_KEY_Menu: return RGFW_menu;
9823 case XKB_KEY_KP_Add: return RGFW_kpPlus;
9824 case XKB_KEY_KP_Subtract: return RGFW_kpMinus;
9825 case XKB_KEY_KP_Multiply: return RGFW_kpMultiply;
9826 case XKB_KEY_KP_Divide: return RGFW_kpSlash;
9827 case XKB_KEY_KP_Equal: return RGFW_kpEqual;
9828 case XKB_KEY_KP_Enter: return RGFW_kpReturn;
9829 case XKB_KEY_KP_Decimal: return RGFW_kpPeriod;
9830 case XKB_KEY_KP_0: return RGFW_kp0;
9831 case XKB_KEY_KP_1: return RGFW_kp1;
9832 case XKB_KEY_KP_2: return RGFW_kp2;
9833 case XKB_KEY_KP_3: return RGFW_kp3;
9834 case XKB_KEY_KP_4: return RGFW_kp4;
9835 case XKB_KEY_KP_5: return RGFW_kp5;
9836 case XKB_KEY_KP_6: return RGFW_kp6;
9837 case XKB_KEY_KP_7: return RGFW_kp7;
9838 case XKB_KEY_KP_8: return RGFW_kp8;
9839 case XKB_KEY_KP_9: return RGFW_kp9;
9840 case XKB_KEY_Print: return RGFW_printScreen;
9841 case XKB_KEY_Pause: return RGFW_pause;
9842 default: break;
9843 }
9844
9845 return RGFW_keyNULL;
9846}
9847
9848void RGFW_FUNC(RGFW_pollEvents) (void) {
9849 RGFW_resetPrevState();
9850
9851 /* send buffered requests to compositor */
9852 while (wl_display_flush(_RGFW->wl_display) == -1) {
9853 /* compositor not responding to new requests */
9854 /* so let's dispatch some events so the compositor responds */
9855 if (errno == EAGAIN) {
9856 if (wl_display_dispatch_pending(_RGFW->wl_display) == -1) {
9857 return;
9858 }
9859 } else {
9860 return;
9861 }
9862 }
9863
9864 /* read the events; if empty this reads from the */
9865 /* wayland file descriptor */
9866 if (wl_display_dispatch(_RGFW->wl_display) == -1) {
9867 return;
9868 }
9869
9870}
9871
9872void RGFW_FUNC(RGFW_window_move) (RGFW_window* win, i32 x, i32 y) {
9873 RGFW_ASSERT(win != NULL);
9874 win->x = x;
9875 win->y = y;
9876}
9877
9878
9879void RGFW_FUNC(RGFW_window_resize) (RGFW_window* win, i32 w, i32 h) {
9880 RGFW_ASSERT(win != NULL);
9881 win->w = w;
9882 win->h = h;
9883 if (_RGFW->compositor) {
9884 xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->w, win->h);
9885 #ifdef RGFW_OPENGL
9886 if (win->src.ctx.egl)
9887 wl_egl_window_resize(win->src.ctx.egl->eglWindow, (i32)w, (i32)h, 0, 0);
9888 #endif
9889 }
9890}
9891
9892void RGFW_FUNC(RGFW_window_setAspectRatio) (RGFW_window* win, i32 w, i32 h) {
9893 RGFW_ASSERT(win != NULL);
9894
9895 if (w == 0 && h == 0)
9896 return;
9897 xdg_toplevel_set_max_size(win->src.xdg_toplevel, (i32)w, (i32)h);
9898}
9899
9900void RGFW_FUNC(RGFW_window_setMinSize) (RGFW_window* win, i32 w, i32 h) {
9901 RGFW_ASSERT(win != NULL);
9902 xdg_toplevel_set_min_size(win->src.xdg_toplevel, w, h);
9903}
9904
9905void RGFW_FUNC(RGFW_window_setMaxSize) (RGFW_window* win, i32 w, i32 h) {
9906 RGFW_ASSERT(win != NULL);
9907 xdg_toplevel_set_max_size(win->src.xdg_toplevel, w, h);
9908}
9909
9910void RGFW_toggleWaylandMaximized(RGFW_window* win, RGFW_bool maximized) {
9911 win->src.maximized = maximized;
9912 if (maximized) {
9913 xdg_toplevel_set_maximized(win->src.xdg_toplevel);
9914 } else {
9915 xdg_toplevel_unset_maximized(win->src.xdg_toplevel);
9916 }
9917}
9918
9919void RGFW_FUNC(RGFW_window_maximize) (RGFW_window* win) {
9920 win->internal.oldX = win->x;
9921 win->internal.oldY = win->y;
9922 win->internal.oldW = win->w;
9923 win->internal.oldH = win->h;
9924 RGFW_toggleWaylandMaximized(win, 1);
9925 return;
9926}
9927
9928void RGFW_FUNC(RGFW_window_focus)(RGFW_window* win) {
9929 RGFW_ASSERT(win);
9930}
9931
9932void RGFW_FUNC(RGFW_window_raise)(RGFW_window* win) {
9933 RGFW_ASSERT(win);
9934}
9935
9936void RGFW_FUNC(RGFW_window_setFullscreen)(RGFW_window* win, RGFW_bool fullscreen) {
9937 RGFW_ASSERT(win != NULL);
9938 if (fullscreen) {
9939
9940 win->internal.flags |= RGFW_windowFullscreen;
9941 win->internal.oldX = win->x;
9942 win->internal.oldY = win->y;
9943 win->internal.oldW = win->w;
9944 win->internal.oldH = win->h;
9945 xdg_toplevel_set_fullscreen(win->src.xdg_toplevel, NULL); /* let the compositor decide */
9946 } else {
9947 win->internal.flags &= ~(u32)RGFW_windowFullscreen;
9948 xdg_toplevel_unset_fullscreen(win->src.xdg_toplevel);
9949 }
9950
9951}
9952
9953void RGFW_FUNC(RGFW_window_setFloating) (RGFW_window* win, RGFW_bool floating) {
9954 RGFW_ASSERT(win != NULL);
9955 RGFW_UNUSED(floating);
9956}
9957
9958void RGFW_FUNC(RGFW_window_setOpacity) (RGFW_window* win, u8 opacity) {
9959 RGFW_ASSERT(win != NULL);
9960 RGFW_UNUSED(opacity);
9961}
9962
9963void RGFW_FUNC(RGFW_window_minimize)(RGFW_window* win) {
9964 RGFW_ASSERT(win != NULL);
9965 if (RGFW_window_isMaximized(win)) return;
9966 win->internal.oldX = win->x;
9967 win->internal.oldY = win->y;
9968 win->internal.oldW = win->w;
9969 win->internal.oldH = win->h;
9970 win->src.minimized = RGFW_TRUE;
9971 xdg_toplevel_set_minimized(win->src.xdg_toplevel);
9972}
9973
9974void RGFW_FUNC(RGFW_window_restore)(RGFW_window* win) {
9975 RGFW_ASSERT(win != NULL);
9976 RGFW_toggleWaylandMaximized(win, RGFW_FALSE);
9977
9978 RGFW_window_move(win, win->internal.oldX, win->internal.oldY);
9979 RGFW_window_resize(win, win->internal.oldW, win->internal.oldH);
9980
9981 RGFW_window_show(win);
9982 RGFW_window_move(win, win->internal.oldX, win->internal.oldY);
9983 RGFW_window_resize(win, win->internal.oldW, win->internal.oldH);
9984
9985 RGFW_window_show(win);
9986}
9987
9988RGFW_bool RGFW_FUNC(RGFW_window_isFloating)(RGFW_window* win) {
9989 return (!RGFW_window_isFullscreen(win) && !RGFW_window_isMaximized(win));
9990}
9991
9992void RGFW_FUNC(RGFW_window_setName) (RGFW_window* win, const char* name) {
9993 RGFW_ASSERT(win != NULL);
9994 if (name == NULL) name = "\0";
9995
9996 if (_RGFW->compositor)
9997 xdg_toplevel_set_title(win->src.xdg_toplevel, name);
9998}
9999
10000#ifndef RGFW_NO_PASSTHROUGH
10001void RGFW_FUNC(RGFW_window_setMousePassthrough) (RGFW_window* win, RGFW_bool passthrough) {
10002 RGFW_ASSERT(win != NULL);
10003 RGFW_UNUSED(passthrough);
10004}
10005#endif /* RGFW_NO_PASSTHROUGH */
10006
10007RGFW_bool RGFW_FUNC(RGFW_window_setIconEx) (RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_icon type) {
10008 RGFW_ASSERT(win != NULL);
10009 RGFW_UNUSED(type);
10010
10011 if (_RGFW->icon_manager == NULL || w != h) return RGFW_FALSE;
10012
10013 if (win->src.icon) {
10014 xdg_toplevel_icon_v1_destroy(win->src.icon);
10015 win->src.icon= NULL;
10016 }
10017
10018 RGFW_surface* surface = RGFW_createSurface(data, w, h, format);
10019
10020 if (surface == NULL) return RGFW_FALSE;
10021
10022 RGFW_copyImageData(surface->native.buffer, RGFW_MIN(w, surface->w), RGFW_MIN(h, surface->h), surface->native.format, surface->data, surface->format, NULL);
10023
10024 win->src.icon = xdg_toplevel_icon_manager_v1_create_icon(_RGFW->icon_manager);
10025 xdg_toplevel_icon_v1_add_buffer(win->src.icon, surface->native.wl_buffer, 1);
10026 xdg_toplevel_icon_manager_v1_set_icon(_RGFW->icon_manager, win->src.xdg_toplevel, win->src.icon);
10027
10028 RGFW_surface_free(surface);
10029 return RGFW_TRUE;
10030}
10031
10032RGFW_mouse* RGFW_FUNC(RGFW_loadMouse)(u8* data, i32 w, i32 h, RGFW_format format) {
10033
10034 RGFW_surface *mouse_surface = RGFW_createSurface(data, w, h, format);
10035
10036 if (mouse_surface == NULL) return NULL;
10037
10038 RGFW_copyImageData(mouse_surface->native.buffer, RGFW_MIN(w, mouse_surface->w), RGFW_MIN(h, mouse_surface->h), mouse_surface->native.format, mouse_surface->data, mouse_surface->format, NULL);
10039
10040 return (void*) mouse_surface;
10041}
10042
10043void RGFW_FUNC(RGFW_window_setMouse)(RGFW_window* win, RGFW_mouse* mouse) {
10044 RGFW_ASSERT(win); RGFW_ASSERT(mouse);
10045 RGFW_surface *mouse_surface = (RGFW_surface*)mouse;
10046
10047 win->src.using_custom_cursor = RGFW_TRUE;
10048
10049 struct wl_buffer *mouse_buffer = mouse_surface->native.wl_buffer;
10050
10051 wl_surface_attach(win->src.custom_cursor_surface, mouse_buffer, 0, 0);
10052 wl_surface_damage(win->src.custom_cursor_surface, 0, 0, mouse_surface->w, mouse_surface->h);
10053 wl_surface_commit(win->src.custom_cursor_surface);
10054
10055}
10056
10057void RGFW_FUNC(RGFW_freeMouse)(RGFW_mouse* mouse) {
10058 if (mouse != NULL) {
10059 RGFW_surface_free((RGFW_surface*)mouse);
10060 }
10061}
10062
10063void RGFW_FUNC(RGFW_window_moveMouse)(RGFW_window* win, i32 x, i32 y) {
10064 if (_RGFW->wp_pointer_warp != NULL) {
10065 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);
10066 }
10067}
10068
10069RGFW_bool RGFW_FUNC(RGFW_window_setMouseDefault)(RGFW_window* win) {
10070 return RGFW_window_setMouseStandard(win, RGFW_mouseArrow);
10071}
10072
10073RGFW_bool RGFW_FUNC(RGFW_window_setMouseStandard)(RGFW_window* win, u8 mouse) {
10074 RGFW_ASSERT(win != NULL);
10075
10076 char* cursorName = NULL;
10077 switch (mouse) {
10078 case RGFW_mouseNormal: cursorName = (char*)"left_ptr"; break;
10079 case RGFW_mouseArrow: cursorName = (char*)"left_ptr"; break;
10080 case RGFW_mouseIbeam: cursorName = (char*)"xterm"; break;
10081 case RGFW_mouseCrosshair: cursorName = (char*)"crosshair"; break;
10082 case RGFW_mousePointingHand: cursorName = (char*)"hand2"; break;
10083 case RGFW_mouseResizeEW: cursorName = (char*)"sb_h_double_arrow"; break;
10084 case RGFW_mouseResizeNS: cursorName = (char*)"sb_v_double_arrow"; break;
10085 case RGFW_mouseResizeNWSE: cursorName = (char*)"top_left_corner"; break; /* or fd_double_arrow */
10086 case RGFW_mouseResizeNESW: cursorName = (char*)"top_right_corner"; break; /* or bd_double_arrow */
10087 case RGFW_mouseResizeNW: cursorName = (char*)"top_left_corner"; break;
10088 case RGFW_mouseResizeN: cursorName = (char*)"top_side"; break;
10089 case RGFW_mouseResizeNE: cursorName = (char*)"top_right_corner"; break;
10090 case RGFW_mouseResizeE: cursorName = (char*)"right_side"; break;
10091 case RGFW_mouseResizeSE: cursorName = (char*)"bottom_right_corner"; break;
10092 case RGFW_mouseResizeS: cursorName = (char*)"bottom_side"; break;
10093 case RGFW_mouseResizeSW: cursorName = (char*)"bottom_left_corner"; break;
10094 case RGFW_mouseResizeW: cursorName = (char*)"left_side"; break;
10095 case RGFW_mouseResizeAll: cursorName = (char*)"fleur"; break;
10096 case RGFW_mouseNotAllowed: cursorName = (char*)"not-allowed"; break;
10097 case RGFW_mouseWait: cursorName = (char*)"watch"; break;
10098 case RGFW_mouseProgress: cursorName = (char*)"watch"; break;
10099 default: return RGFW_FALSE;
10100 }
10101
10102 win->src.using_custom_cursor = RGFW_FALSE;
10103
10104 struct wl_cursor* wlcursor = wl_cursor_theme_get_cursor(_RGFW->wl_cursor_theme, cursorName);
10105 if (wlcursor == NULL)
10106 return RGFW_FALSE;
10107 struct wl_cursor_image* cursor_image = wlcursor->images[0];
10108 struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(cursor_image);
10109 wl_pointer_set_cursor(_RGFW->wl_pointer, _RGFW->mouse_enter_serial, _RGFW->cursor_surface, (i32)cursor_image->hotspot_x, (i32)cursor_image->hotspot_y);
10110 wl_surface_attach(_RGFW->cursor_surface, cursor_buffer, 0, 0);
10111 wl_surface_damage(_RGFW->cursor_surface, 0, 0, (i32)cursor_image->width, (i32)cursor_image->height);
10112 wl_surface_commit(_RGFW->cursor_surface);
10113 return RGFW_TRUE;
10114}
10115
10116void RGFW_FUNC(RGFW_window_hide) (RGFW_window* win) {
10117 wl_surface_attach(win->src.surface, NULL, 0, 0);
10118 wl_surface_commit(win->src.surface);
10119 win->internal.flags |= RGFW_windowHide;
10120}
10121
10122void RGFW_FUNC(RGFW_window_show) (RGFW_window* win) {
10123 win->internal.flags &= ~(u32)RGFW_windowHide;
10124 if (win->internal.flags & RGFW_windowFocusOnShow) RGFW_window_focus(win);
10125 /* wl_surface_attach(win->src.surface, win->x, win->y, win->w, win->h, 0, 0); */
10126 wl_surface_commit(win->src.surface);
10127}
10128
10129void RGFW_FUNC(RGFW_window_flash) (RGFW_window* win, RGFW_flashRequest request) {
10130 if (RGFW_window_isInFocus(win) && request) {
10131 return;
10132 }
10133}
10134
10135RGFW_ssize_t RGFW_FUNC(RGFW_readClipboardPtr) (char* str, size_t strCapacity) {
10136 RGFW_UNUSED(strCapacity);
10137
10138 if (str != NULL)
10139 RGFW_STRNCPY(str, _RGFW->clipboard, _RGFW->clipboard_len - 1);
10140 _RGFW->clipboard[_RGFW->clipboard_len - 1] = '\0';
10141 return (RGFW_ssize_t)_RGFW->clipboard_len - 1;
10142}
10143
10144void RGFW_FUNC(RGFW_writeClipboard) (const char* text, u32 textLen) {
10145
10146 // compositor does not support wl_data_device_manager
10147 // clients cannot read rgfw's clipboard
10148 if (_RGFW->data_device_manager == NULL) return;
10149 // clear the clipboard
10150 if (_RGFW->clipboard)
10151 RGFW_FREE(_RGFW->clipboard);
10152
10153 // set the contents
10154 _RGFW->clipboard = (char*)RGFW_ALLOC(textLen);
10155 RGFW_ASSERT(_RGFW->clipboard != NULL);
10156 RGFW_STRNCPY(_RGFW->clipboard, text, textLen - 1);
10157 _RGFW->clipboard[textLen - 1] = '\0';
10158 _RGFW->clipboard_len = textLen;
10159
10160 // means we already wrote to the clipboard
10161 // so destroy it to create a new one
10162 RGFW_window* win = _RGFW->kbOwner;
10163
10164 if (win->src.data_source != NULL) {
10165 wl_data_source_destroy(win->src.data_source);
10166 win->src.data_source = NULL;
10167 }
10168
10169 // advertise to other clients that we offer text
10170 win->src.data_source = wl_data_device_manager_create_data_source(_RGFW->data_device_manager);
10171
10172 // basic error checking
10173 if (win->src.data_source == NULL) {
10174 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errClipboard, "Could not create clipboard data source");
10175 return;
10176 }
10177 wl_data_source_offer(win->src.data_source , "text/plain;charset=utf-8");
10178
10179 // needed RGFW_doNothing because wayland will call the functions
10180 // if not set they are random data that lead to a crash
10181 static const struct wl_data_source_listener data_source_listener = {
10182 .target = (void (*)(void *, struct wl_data_source *, const char *))&RGFW_doNothing,
10183 .action = (void (*)(void *, struct wl_data_source *, u32))&RGFW_doNothing,
10184 .dnd_drop_performed = (void (*)(void *, struct wl_data_source *))&RGFW_doNothing,
10185 .dnd_finished = (void (*)(void *, struct wl_data_source *))&RGFW_doNothing,
10186 .send = RGFW_wl_data_source_send,
10187 .cancelled = RGFW_wl_data_source_cancelled
10188 };
10189
10190 wl_data_source_add_listener(win->src.data_source, &data_source_listener, _RGFW);
10191
10192}
10193
10194RGFW_bool RGFW_FUNC(RGFW_window_isHidden) (RGFW_window* win) {
10195 RGFW_ASSERT(win != NULL);
10196 return RGFW_FALSE;
10197}
10198
10199RGFW_bool RGFW_FUNC(RGFW_window_isMinimized) (RGFW_window* win) {
10200 RGFW_ASSERT(win != NULL);
10201 return win->src.minimized;
10202}
10203
10204RGFW_bool RGFW_FUNC(RGFW_window_isMaximized) (RGFW_window* win) {
10205 RGFW_ASSERT(win != NULL);
10206 return win->src.maximized;
10207}
10208
10209void RGFW_FUNC(RGFW_pollMonitors) (void) {
10210 _RGFW->monitors.primary = _RGFW->monitors.list.head;
10211}
10212
10213
10214RGFW_bool RGFW_FUNC(RGFW_monitor_getWorkarea) (RGFW_monitor* monitor, i32* x, i32* y, i32* width, i32* height) {
10215 /* NOTE: Wayland has no way to get the actual workarea as far as I'm aware :( */
10216 if (x) *x = monitor->x;
10217 if (y) *y = monitor->y;
10218 if (width) *width = monitor->mode.w;
10219 if (height) *height = monitor->mode.h;
10220 return RGFW_TRUE;
10221}
10222
10223size_t RGFW_FUNC(RGFW_monitor_getModesPtr) (RGFW_monitor* monitor, RGFW_monitorMode** modes) {
10224 if (modes) {
10225 RGFW_MEMCPY((*modes), monitor->node->modes, monitor->node->modeCount * sizeof(RGFW_monitorMode));
10226 }
10227
10228 return monitor->node->modeCount;
10229}
10230
10231size_t RGFW_FUNC(RGFW_monitor_getGammaRampPtr) (RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
10232 RGFW_UNUSED(monitor); RGFW_UNUSED(ramp);
10233 return 0;
10234}
10235
10236RGFW_bool RGFW_FUNC(RGFW_monitor_setGammaRamp) (RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
10237 RGFW_UNUSED(monitor); RGFW_UNUSED(ramp);
10238 return RGFW_FALSE;
10239}
10240
10241RGFW_bool RGFW_FUNC(RGFW_monitor_requestMode) (RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request) {
10242 for (size_t i = 0; i < mon->node->modeCount; i++) {
10243 if (RGFW_monitorModeCompare(mode, &mon->node->modes[i], request) == RGFW_FALSE) {
10244 continue;
10245 }
10246
10247 RGFW_monitor_setMode(mon, &mon->node->modes[i]);
10248 return RGFW_TRUE;
10249 }
10250
10251 return RGFW_FALSE;
10252}
10253
10254RGFW_bool RGFW_FUNC(RGFW_monitor_setMode) (RGFW_monitor* mon, RGFW_monitorMode* mode) {
10255 RGFW_UNUSED(mon); RGFW_UNUSED(mode);
10256 return RGFW_FALSE;
10257}
10258
10259RGFW_monitor* RGFW_FUNC(RGFW_window_getMonitor) (RGFW_window* win) {
10260 RGFW_ASSERT(win);
10261 if (win->src.active_monitor == NULL) {
10262 /* TODO: fix race condition [probably a problem with wayland] */
10263 return RGFW_getPrimaryMonitor();
10264 }
10265
10266 return &win->src.active_monitor->mon;
10267}
10268
10269#ifdef RGFW_OPENGL
10270RGFW_bool RGFW_FUNC(RGFW_extensionSupportedPlatform_OpenGL) (const char * extension, size_t len) { return RGFW_extensionSupportedPlatform_EGL(extension, len); }
10271RGFW_proc RGFW_FUNC(RGFW_getProcAddress_OpenGL) (const char* procname) { return RGFW_getProcAddress_EGL(procname); }
10272
10273
10274RGFW_bool RGFW_FUNC(RGFW_window_createContextPtr_OpenGL)(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints) {
10275 RGFW_bool out = RGFW_window_createContextPtr_EGL(win, &ctx->egl, hints);
10276 win->src.gfxType = RGFW_gfxNativeOpenGL;
10277
10278 RGFW_window_swapInterval_OpenGL(win, 0);
10279 return out;
10280}
10281void RGFW_FUNC(RGFW_window_deleteContextPtr_OpenGL) (RGFW_window* win, RGFW_glContext* ctx) { RGFW_window_deleteContextPtr_EGL(win, &ctx->egl); win->src.ctx.native = NULL; }
10282
10283void RGFW_FUNC(RGFW_window_makeCurrentContext_OpenGL) (RGFW_window* win) { RGFW_window_makeCurrentContext_EGL(win); }
10284void* RGFW_FUNC(RGFW_getCurrentContext_OpenGL) (void) { return RGFW_getCurrentContext_EGL(); }
10285void RGFW_FUNC(RGFW_window_swapBuffers_OpenGL) (RGFW_window* win) { RGFW_window_swapBuffers_EGL(win); }
10286void RGFW_FUNC(RGFW_window_swapInterval_OpenGL) (RGFW_window* win, i32 swapInterval) { RGFW_window_swapInterval_EGL(win, swapInterval); }
10287#endif /* RGFW_OPENGL */
10288
10289void RGFW_FUNC(RGFW_window_closePlatform)(RGFW_window* win) {
10290 RGFW_ASSERT(win != NULL);
10291 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, "a window was freed");
10292 #ifdef RGFW_LIBDECOR
10293 if (win->src.decorContext)
10294 libdecor_unref(win->src.decorContext);
10295 #endif
10296
10297 if (win->src.decoration) {
10298 zxdg_toplevel_decoration_v1_destroy(win->src.decoration);
10299 }
10300
10301 if (win->src.xdg_toplevel) {
10302 xdg_toplevel_destroy(win->src.xdg_toplevel);
10303 }
10304
10305 wl_surface_destroy(win->src.custom_cursor_surface);
10306
10307 if (win->src.locked_pointer) {
10308 zwp_locked_pointer_v1_destroy(win->src.locked_pointer);
10309 }
10310
10311 if (win->src.icon) {
10312 xdg_toplevel_icon_v1_destroy(win->src.icon);
10313 }
10314
10315 xdg_surface_destroy(win->src.xdg_surface);
10316 wl_surface_destroy(win->src.surface);
10317}
10318
10319#ifdef RGFW_WEBGPU
10320WGPUSurface RGFW_FUNC(RGFW_window_createSurface_WebGPU) (RGFW_window* window, WGPUInstance instance) {
10321 WGPUSurfaceDescriptor surfaceDesc = {0};
10322 WGPUSurfaceSourceWaylandSurface fromWl = {0};
10323 fromWl.chain.sType = WGPUSType_SurfaceSourceWaylandSurface;
10324 fromWl.display = _RGFW->wl_display;
10325 fromWl.surface = window->src.surface;
10326
10327 surfaceDesc.nextInChain = (WGPUChainedStruct*)&fromWl.chain;
10328 return wgpuInstanceCreateSurface(instance, &surfaceDesc);
10329}
10330#endif
10331
10332
10333
10334#endif /* RGFW_WAYLAND */
10335/*
10336 End of Wayland defines
10337*/
10338
10339/*
10340
10341 Start of Windows defines
10342
10343
10344*/
10345
10346#ifdef RGFW_WINDOWS
10347#ifndef WIN32_LEAN_AND_MEAN
10348 #define WIN32_LEAN_AND_MEAN
10349#endif
10350
10351#ifndef OEMRESOURCE
10352 #define OEMRESOURCE
10353#endif
10354
10355#include <windows.h>
10356
10357#ifndef OCR_NORMAL
10358#define OCR_NORMAL 32512
10359#define OCR_IBEAM 32513
10360#define OCR_WAIT 32514
10361#define OCR_CROSS 32515
10362#define OCR_UP 32516
10363#define OCR_SIZENWSE 32642
10364#define OCR_SIZENESW 32643
10365#define OCR_SIZEWE 32644
10366#define OCR_SIZENS 32645
10367#define OCR_SIZEALL 32646
10368#define OCR_NO 32648
10369#define OCR_HAND 32649
10370#define OCR_APPSTARTING 32650
10371#endif
10372
10373#include <windowsx.h>
10374#include <shellapi.h>
10375#include <shellscalingapi.h>
10376#include <wchar.h>
10377#include <locale.h>
10378#include <winuser.h>
10379
10380#ifndef WM_DPICHANGED
10381#define WM_DPICHANGED 0x02E0
10382#endif
10383
10384RGFWDEF DWORD RGFW_winapi_window_getStyle(RGFW_window* win, RGFW_windowFlags flags);
10385DWORD RGFW_winapi_window_getStyle(RGFW_window* win, RGFW_windowFlags flags) {
10386 RGFW_UNUSED(win);
10387 DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
10388
10389 if ((flags & RGFW_windowFullscreen)) {
10390 style |= WS_POPUP;
10391 } else {
10392 style |= WS_SYSMENU | WS_MINIMIZEBOX;
10393
10394 if (!(flags & RGFW_windowNoBorder)) {
10395 style |= WS_CAPTION;
10396
10397 if (!(flags & RGFW_windowNoResize))
10398 style |= WS_MAXIMIZEBOX | WS_THICKFRAME;
10399 }
10400 else
10401 style |= WS_POPUP;
10402 }
10403
10404 return style;
10405}
10406
10407RGFWDEF DWORD RGFW_winapi_window_getExStyle(RGFW_window* win, RGFW_windowFlags flags);
10408DWORD RGFW_winapi_window_getExStyle(RGFW_window* win, RGFW_windowFlags flags) {
10409 DWORD style = WS_EX_APPWINDOW;
10410 if (flags & RGFW_windowFullscreen || (flags & RGFW_windowFloating || RGFW_window_isFloating(win))) {
10411 style |= WS_EX_TOPMOST;
10412 }
10413
10414 return style;
10415}
10416
10417RGFW_bool RGFW_createUTF8FromWideStringWin32(const WCHAR* source, char* out, size_t max);
10418
10419#define GL_FRONT 0x0404
10420#define GL_BACK 0x0405
10421#define GL_LEFT 0x0406
10422#define GL_RIGHT 0x0407
10423
10424typedef int (*PFN_wglGetSwapIntervalEXT)(void);
10425PFN_wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc = NULL;
10426#define wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc
10427
10428/* these two wgl functions need to be preloaded */
10429typedef HGLRC (WINAPI *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC hdc, HGLRC hglrc, const int *attribList);
10430PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL;
10431
10432HMODULE RGFW_wgl_dll = NULL;
10433
10434#ifndef RGFW_NO_LOAD_WGL
10435 typedef HGLRC(WINAPI* PFN_wglCreateContext)(HDC);
10436 typedef BOOL(WINAPI* PFN_wglDeleteContext)(HGLRC);
10437 typedef PROC(WINAPI* PFN_wglGetProcAddress)(LPCSTR);
10438 typedef BOOL(WINAPI* PFN_wglMakeCurrent)(HDC, HGLRC);
10439 typedef HDC(WINAPI* PFN_wglGetCurrentDC)(void);
10440 typedef HGLRC(WINAPI* PFN_wglGetCurrentContext)(void);
10441 typedef BOOL(WINAPI* PFN_wglShareLists)(HGLRC, HGLRC);
10442
10443 PFN_wglCreateContext wglCreateContextSRC;
10444 PFN_wglDeleteContext wglDeleteContextSRC;
10445 PFN_wglGetProcAddress wglGetProcAddressSRC;
10446 PFN_wglMakeCurrent wglMakeCurrentSRC;
10447 PFN_wglGetCurrentDC wglGetCurrentDCSRC;
10448 PFN_wglGetCurrentContext wglGetCurrentContextSRC;
10449 PFN_wglShareLists wglShareListsSRC;
10450
10451 #define wglCreateContext wglCreateContextSRC
10452 #define wglDeleteContext wglDeleteContextSRC
10453 #define wglGetProcAddress wglGetProcAddressSRC
10454 #define wglMakeCurrent wglMakeCurrentSRC
10455 #define wglGetCurrentDC wglGetCurrentDCSRC
10456 #define wglGetCurrentContext wglGetCurrentContextSRC
10457 #define wglShareLists wglShareListsSRC
10458#endif
10459
10460void* RGFW_window_getHWND(RGFW_window* win) { return win->src.window; }
10461void* RGFW_window_getHDC(RGFW_window* win) { return win->src.hdc; }
10462
10463#ifdef RGFW_OPENGL
10464RGFWDEF void RGFW_win32_loadOpenGLFuncs(HWND dummyWin);
10465
10466typedef HRESULT (APIENTRY* PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats);
10467PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL;
10468
10469typedef BOOL(APIENTRY* PFNWGLSWAPINTERVALEXTPROC)(int interval);
10470PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
10471#endif
10472
10473#ifndef RGFW_NO_DWM
10474HMODULE RGFW_dwm_dll = NULL;
10475#ifndef _DWMAPI_H_
10476typedef struct { DWORD dwFlags; int fEnable; HRGN hRgnBlur; int fTransitionOnMaximized;} DWM_BLURBEHIND;
10477#endif
10478typedef HRESULT (WINAPI * PFN_DwmEnableBlurBehindWindow)(HWND, const DWM_BLURBEHIND*);
10479PFN_DwmEnableBlurBehindWindow DwmEnableBlurBehindWindowSRC = NULL;
10480
10481typedef HRESULT (WINAPI * PFN_DwmSetWindowAttribute)(HWND, DWORD, LPCVOID, DWORD);
10482PFN_DwmSetWindowAttribute DwmSetWindowAttributeSRC = NULL;
10483#endif
10484void RGFW_win32_makeWindowTransparent(RGFW_window* win);
10485void RGFW_win32_makeWindowTransparent(RGFW_window* win) {
10486 if (!(win->internal.flags & RGFW_windowTransparent)) return;
10487
10488 #ifndef RGFW_NO_DWM
10489 if (DwmEnableBlurBehindWindowSRC != NULL) {
10490 DWM_BLURBEHIND bb = {0, 0, 0, 0};
10491 bb.dwFlags = 0x1;
10492 bb.fEnable = TRUE;
10493 bb.hRgnBlur = NULL;
10494 DwmEnableBlurBehindWindowSRC(win->src.window, &bb);
10495
10496 } else
10497 #endif
10498 {
10499 SetWindowLong(win->src.window, GWL_EXSTYLE, WS_EX_LAYERED);
10500 SetLayeredWindowAttributes(win->src.window, 0, 128, LWA_ALPHA);
10501 }
10502}
10503
10504RGFWDEF RGFW_bool RGFW_win32_getDarkModeState(void);
10505RGFW_bool RGFW_win32_getDarkModeState(void) {
10506 u32 lightMode = 1;
10507 DWORD len = sizeof(lightMode);
10508
10509 RegGetValueW(
10510 HKEY_CURRENT_USER,
10511 L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
10512 L"AppsUseLightTheme", RRF_RT_REG_DWORD, NULL, &lightMode, &len
10513 );
10514
10515 return (lightMode == 0);
10516}
10517
10518RGFWDEF void RGFW_win32_makeWindowDarkMode(RGFW_window* win, RGFW_bool state);
10519void RGFW_win32_makeWindowDarkMode(RGFW_window* win, RGFW_bool state) {
10520 BOOL value = (state == RGFW_TRUE) ? TRUE : FALSE;
10521 DwmSetWindowAttributeSRC(win->src.window, 20 /* DWMWA_USE_IMMERSIVE_DARK_MODE */, &value, sizeof(value));
10522}
10523
10524LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
10525LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
10526 RGFW_window* win = (RGFW_window*)GetPropW(hWnd, L"RGFW");
10527 if (win == NULL) return DefWindowProcW(hWnd, message, wParam, lParam);
10528
10529 static BYTE keyboardState[256];
10530 GetKeyboardState(keyboardState);
10531
10532 RECT frame;
10533 ZeroMemory(&frame, sizeof(frame));
10534 DWORD style = RGFW_winapi_window_getStyle(win, win->internal.flags);
10535 DWORD exStyle = RGFW_winapi_window_getExStyle(win, win->internal.flags);
10536 AdjustWindowRectEx(&frame, style, FALSE, exStyle);
10537
10538 switch (message) {
10539 case WM_DISPLAYCHANGE:
10540 RGFW_pollMonitors();
10541 break;
10542 case WM_CLOSE:
10543 case WM_QUIT:
10544 RGFW_windowQuitCallback(win);
10545 return 0;
10546 case WM_ACTIVATE: {
10547 RGFW_bool inFocus = RGFW_BOOL(LOWORD(wParam) != WA_INACTIVE);
10548 RGFW_focusCallback(win, inFocus);
10549
10550 return DefWindowProcW(hWnd, message, wParam, lParam);
10551 }
10552 case WM_MOVE:
10553 if (win->internal.captureMouse) {
10554 RGFW_window_captureMousePlatform(win, RGFW_TRUE);
10555 }
10556
10557 RGFW_windowMovedCallback(win, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
10558 return DefWindowProcW(hWnd, message, wParam, lParam);
10559 case WM_SIZE: {
10560 if (win->internal.captureMouse) {
10561 RGFW_window_captureMousePlatform(win, RGFW_TRUE);
10562 }
10563
10564 RGFW_windowResizedCallback(win, LOWORD(lParam), HIWORD(lParam));
10565 RGFW_window_checkMode(win);
10566 return DefWindowProcW(hWnd, message, wParam, lParam);
10567 }
10568 case WM_MOUSEACTIVATE: {
10569 if (HIWORD(lParam) == WM_LBUTTONDOWN) {
10570 if (LOWORD(lParam) != HTCLIENT)
10571 win->src.actionFrame = RGFW_TRUE;
10572 }
10573
10574 break;
10575 }
10576 case WM_CAPTURECHANGED: {
10577 if (lParam == 0 && win->src.actionFrame) {
10578 RGFW_window_captureMousePlatform(win, win->internal.captureMouse);
10579 win->src.actionFrame = RGFW_FALSE;
10580 }
10581
10582 break;
10583 }
10584 #ifndef RGFW_NO_DPI
10585 case WM_DPICHANGED: {
10586 const float scaleX = HIWORD(wParam) / (float) 96;
10587 const float scaleY = LOWORD(wParam) / (float) 96;
10588
10589 RGFW_scaleUpdatedCallback(win, scaleX, scaleY);
10590 return DefWindowProcW(hWnd, message, wParam, lParam);
10591 }
10592 #endif
10593 case WM_SIZING: {
10594 if (win->src.aspectRatioW == 0 && win->src.aspectRatioH == 0) {
10595 break;
10596 }
10597
10598 RECT* area = (RECT*)lParam;
10599 i32 edge = (i32)wParam;
10600
10601 double ratio = (double)win->src.aspectRatioW / (double) win->src.aspectRatioH;
10602
10603 if (edge == WMSZ_LEFT || edge == WMSZ_BOTTOMLEFT || edge == WMSZ_RIGHT || edge == WMSZ_BOTTOMRIGHT) {
10604 area->bottom = area->top + (frame.bottom - frame.top) + (i32) (((area->right - area->left) - (frame.right - frame.left)) / ratio);
10605 } else if (edge == WMSZ_TOPLEFT || edge == WMSZ_TOPRIGHT) {
10606 area->top = area->bottom - (frame.bottom - frame.top) - (i32) (((area->right - area->left) - (frame.right - frame.left)) / ratio);
10607 } else if (edge == WMSZ_TOP || edge == WMSZ_BOTTOM) {
10608 area->right = area->left + (frame.right - frame.left) + (i32) (((area->bottom - area->top) - (frame.bottom - frame.top)) * ratio);
10609 }
10610
10611 return TRUE;
10612 }
10613 case WM_GETMINMAXINFO: {
10614 MINMAXINFO* mmi = (MINMAXINFO*) lParam;
10615 RGFW_bool resize = ((win->src.minSizeW == win->src.maxSizeW) && (win->src.minSizeH == win->src.maxSizeH));
10616 RGFW_setBit(&win->internal.flags, RGFW_windowNoResize, resize);
10617
10618 mmi->ptMinTrackSize.x = (LONG)(win->src.minSizeW + (frame.right - frame.left));
10619 mmi->ptMinTrackSize.y = (LONG)(win->src.minSizeH + (frame.bottom - frame.top));
10620 if (win->src.maxSizeW == 0 && win->src.maxSizeH == 0)
10621 return DefWindowProcW(hWnd, message, wParam, lParam);
10622
10623 mmi->ptMaxTrackSize.x = (LONG)(win->src.maxSizeW + (frame.right - frame.left));
10624 mmi->ptMaxTrackSize.y = (LONG)(win->src.maxSizeH + (frame.bottom - frame.top));
10625 return DefWindowProcW(hWnd, message, wParam, lParam);
10626 }
10627 case WM_PAINT: {
10628 PAINTSTRUCT ps;
10629 BeginPaint(hWnd, &ps);
10630 RGFW_windowRefreshCallback(win);
10631 EndPaint(hWnd, &ps);
10632
10633 return DefWindowProcW(hWnd, message, wParam, lParam);
10634 }
10635 #if(_WIN32_WINNT >= 0x0600)
10636 case WM_DWMCOMPOSITIONCHANGED:
10637 case WM_DWMCOLORIZATIONCOLORCHANGED:
10638 RGFW_win32_makeWindowTransparent(win);
10639 break;
10640 #endif
10641
10642 case WM_ENTERSIZEMOVE: {
10643 if (win->src.actionFrame)
10644 RGFW_window_captureMousePlatform(win, win->internal.captureMouse);
10645
10646 #ifdef RGFW_ADVANCED_SMOOTH_RESIZE
10647 SetTimer(win->src.window, 1, USER_TIMER_MINIMUM, NULL); break;
10648 #endif
10649 break;
10650 }
10651 case WM_EXITSIZEMOVE: {
10652 if (win->src.actionFrame)
10653 RGFW_window_captureMousePlatform(win, win->internal.captureMouse);
10654
10655 #ifdef RGFW_ADVANCED_SMOOTH_RESIZE
10656 KillTimer(win->src.window, 1); break;
10657 #endif
10658 break;
10659 }
10660 case WM_TIMER:
10661 RGFW_windowRefreshCallback(win);
10662 break;
10663
10664 case WM_NCLBUTTONDOWN: {
10665 /* workaround for half-second pause when starting to move window
10666 see: https://gamedev.net/forums/topic/672094-keeping-things-moving-during-win32-moveresize-events/5254386/
10667 */
10668 POINT point = { 0, 0 };
10669 if (SendMessage(win->src.window, WM_NCHITTEST, wParam, lParam) != HTCAPTION || GetCursorPos(&point) == FALSE)
10670 break;
10671
10672 ScreenToClient(win->src.window, &point);
10673 PostMessage(win->src.window, WM_MOUSEMOVE, 0, (u32)(point.x)|((u32)(point.y) << 16));
10674 break;
10675 }
10676 case WM_MOUSELEAVE:
10677 RGFW_mouseNotifyCallback(win, win->internal.lastMouseX, win->internal.lastMouseY, RGFW_FALSE);
10678 break;
10679
10680 case WM_CHAR:
10681 case WM_SYSCHAR: {
10682 if (wParam >= 0xd800 && wParam <= 0xdbff)
10683 win->src.highSurrogate = (WCHAR) wParam;
10684 else {
10685 u32 codepoint = 0;
10686
10687 if (wParam >= 0xdc00 && wParam <= 0xdfff) {
10688 if (win->src.highSurrogate) {
10689 codepoint += (u32)((win->src.highSurrogate - 0xd800) << 10);
10690 codepoint += (u32)((WCHAR) wParam - 0xdc00);
10691 codepoint += 0x10000;
10692 }
10693 }
10694 else
10695 codepoint = (WCHAR) wParam;
10696
10697 win->src.highSurrogate = 0;
10698 RGFW_keyCharCallback(win, (u32)codepoint);
10699 }
10700
10701 return 0;
10702 }
10703
10704 case WM_UNICHAR: {
10705 if (wParam == UNICODE_NOCHAR) {
10706 return TRUE;
10707 }
10708
10709 RGFW_keyCharCallback(win, (u32)wParam);
10710 return 0;
10711 }
10712 case WM_SYSKEYUP: case WM_KEYUP: {
10713 if (!(win->internal.enabledEvents & RGFW_keyReleasedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam);
10714 i32 scancode = (HIWORD(lParam) & (KF_EXTENDED | 0xff));
10715 if (scancode == 0)
10716 scancode = (i32)MapVirtualKeyW((UINT)wParam, MAPVK_VK_TO_VSC);
10717
10718 switch (scancode) {
10719 case 0x54: scancode = 0x137; break; /* Alt+PrtS */
10720 case 0x146: scancode = 0x45; break; /* Ctrl+Pause */
10721 case 0x136: scancode = 0x36; break; /* CJK IME sets the extended bit for right Shift */
10722 default: break;
10723 }
10724
10725 RGFW_key value = (u8)RGFW_apiKeyToRGFW((u32) scancode);
10726
10727 if (wParam == VK_CONTROL) {
10728 if (HIWORD(lParam) & KF_EXTENDED)
10729 value = RGFW_controlR;
10730 else value = RGFW_controlL;
10731 }
10732
10733 RGFW_bool repeat = ((lParam & 0x40000000) != 0) || RGFW_window_isKeyDown(win, value);
10734
10735 RGFW_updateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001), (GetKeyState(VK_SCROLL) & 0x0001));
10736 RGFW_keyCallback(win, value, win->internal.mod, repeat, RGFW_FALSE);
10737 break;
10738 }
10739 case WM_SYSKEYDOWN: case WM_KEYDOWN: {
10740 if (!(win->internal.enabledEvents & RGFW_keyPressedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam);
10741 i32 scancode = (HIWORD(lParam) & (KF_EXTENDED | 0xff));
10742 if (scancode == 0)
10743 scancode = (i32)MapVirtualKeyW((u32)wParam, MAPVK_VK_TO_VSC);
10744
10745 switch (scancode) {
10746 case 0x54: scancode = 0x137; break; /* Alt+PrtS */
10747 case 0x146: scancode = 0x45; break; /* Ctrl+Pause */
10748 case 0x136: scancode = 0x36; break; /* CJK IME sets the extended bit for right Shift */
10749 default: break;
10750 }
10751
10752 RGFW_key value = (u8)RGFW_apiKeyToRGFW((u32) scancode);
10753 if (wParam == VK_CONTROL) {
10754 if (HIWORD(lParam) & KF_EXTENDED)
10755 value = RGFW_controlR;
10756 else value = RGFW_controlL;
10757 }
10758
10759 RGFW_bool repeat = ((lParam & 0x40000000) != 0) || RGFW_window_isKeyDown(win, value);
10760
10761 RGFW_updateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001), (GetKeyState(VK_SCROLL) & 0x0001));
10762 RGFW_keyCallback(win, value, win->internal.mod, repeat, 1);
10763 break;
10764 }
10765 case WM_MOUSEMOVE: {
10766 if (win->internal.mouseInside == RGFW_FALSE) {
10767 RGFW_mouseNotifyCallback(win, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), RGFW_TRUE);
10768 }
10769
10770 if ((win->internal.rawMouse) || _RGFW->rawMouse) {
10771 return DefWindowProcW(hWnd, message, wParam, lParam);
10772 }
10773
10774 RGFW_mousePosCallback(win, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), _RGFW->vectorX, _RGFW->vectorY);
10775 break;
10776 }
10777 case WM_INPUT: {
10778 if (!(win->internal.rawMouse || _RGFW->rawMouse)) return DefWindowProcW(hWnd, message, wParam, lParam);
10779 unsigned size = sizeof(RAWINPUT);
10780 static RAWINPUT raw;
10781
10782 GetRawInputData((HRAWINPUT)lParam, RID_INPUT, &raw, &size, sizeof(RAWINPUTHEADER));
10783
10784 if (raw.header.dwType != RIM_TYPEMOUSE || (raw.data.mouse.lLastX == 0 && raw.data.mouse.lLastY == 0) )
10785 break;
10786
10787 float vecX = 0.0f;
10788 float vecY = 0.0f;
10789
10790 if (raw.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) {
10791 POINT pos = {0, 0};
10792 int width, height;
10793
10794 if (raw.data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP) {
10795 pos.x += GetSystemMetrics(SM_XVIRTUALSCREEN);
10796 pos.y += GetSystemMetrics(SM_YVIRTUALSCREEN);
10797 width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
10798 height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
10799 }
10800 else {
10801 width = GetSystemMetrics(SM_CXSCREEN);
10802 height = GetSystemMetrics(SM_CYSCREEN);
10803 }
10804
10805 pos.x += (int) (((float)raw.data.mouse.lLastX / 65535.f) * (float)width);
10806 pos.y += (int) (((float)raw.data.mouse.lLastY / 65535.f) * (float)height);
10807 ScreenToClient(win->src.window, &pos);
10808
10809 vecX = (float)(pos.x - win->internal.lastMouseX);
10810 vecY = (float)(pos.y - win->internal.lastMouseY);
10811 } else {
10812 vecX = (float)(raw.data.mouse.lLastX);
10813 vecY = (float)(raw.data.mouse.lLastY);
10814 }
10815
10816 RGFW_mousePosCallback(win, win->internal.lastMouseX, win->internal.lastMouseY, vecX, vecY);
10817 break;
10818 }
10819 case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: case WM_XBUTTONDOWN: {
10820 RGFW_mouseButton value = 0;
10821 if (message == WM_XBUTTONDOWN)
10822 value = RGFW_mouseMisc1 + (GET_XBUTTON_WPARAM(wParam) == XBUTTON2);
10823 else value = (message == WM_LBUTTONDOWN) ? (u8)RGFW_mouseLeft :
10824 (message == WM_RBUTTONDOWN) ? (u8)RGFW_mouseRight : (u8)RGFW_mouseMiddle;
10825
10826 RGFW_mouseButtonCallback(win, value, 1);
10827 break;
10828 }
10829 case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MBUTTONUP: case WM_XBUTTONUP: {
10830 RGFW_mouseButton value = 0;
10831 if (message == WM_XBUTTONUP)
10832 value = RGFW_mouseMisc1 + (GET_XBUTTON_WPARAM(wParam) == XBUTTON2);
10833 else value = (message == WM_LBUTTONUP) ? (u8)RGFW_mouseLeft :
10834 (message == WM_RBUTTONUP) ? (u8)RGFW_mouseRight : (u8)RGFW_mouseMiddle;
10835
10836 RGFW_mouseButtonCallback(win, value, 0);
10837 break;
10838 }
10839 case WM_MOUSEWHEEL: {
10840 float scrollY = (float)((i16) HIWORD(wParam) / (double) WHEEL_DELTA);
10841 RGFW_mouseScrollCallback(win, 0.0f, scrollY);
10842 break;
10843 }
10844 case 0x020E: {/* WM_MOUSEHWHEEL */
10845 float scrollX = -(float)((i16) HIWORD(wParam) / (double) WHEEL_DELTA);
10846 RGFW_mouseScrollCallback(win, scrollX, 0.0f);
10847 break;
10848 }
10849 case WM_DROPFILES: {
10850 HDROP drop = (HDROP) wParam;
10851 POINT pt;
10852
10853 /* Move the mouse to the position of the drop */
10854 DragQueryPoint(drop, &pt);
10855 RGFW_dataDragCallback(win, pt.x, pt.y);
10856
10857 if (!(win->internal.enabledEvents & RGFW_dataDrop)) return DefWindowProcW(hWnd, message, wParam, lParam);
10858 char** files = _RGFW->files;
10859 size_t count = DragQueryFileW(drop, 0xffffffff, NULL, 0);
10860
10861 u32 i;
10862 for (i = 0; i < count; i++) {
10863 UINT length = DragQueryFileW(drop, i, NULL, 0);
10864 if (length == 0)
10865 continue;
10866
10867 WCHAR buffer[RGFW_MAX_PATH * 2];
10868 if (length > (RGFW_MAX_PATH * 2) - 1)
10869 length = RGFW_MAX_PATH * 2;
10870
10871 DragQueryFileW(drop, i, buffer, length + 1);
10872
10873 RGFW_createUTF8FromWideStringWin32(buffer, files[i], RGFW_MAX_PATH);
10874
10875 files[i][RGFW_MAX_PATH - 1] = '\0';
10876 }
10877
10878 DragFinish(drop);
10879
10880 RGFW_dataDropCallback(win, files, count);
10881 break;
10882 }
10883 default: break;
10884 }
10885
10886 return DefWindowProcW(hWnd, message, wParam, lParam);
10887}
10888
10889#ifndef RGFW_NO_DPI
10890 HMODULE RGFW_Shcore_dll = NULL;
10891 typedef HRESULT (WINAPI *PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*,UINT*);
10892 PFN_GetDpiForMonitor GetDpiForMonitorSRC = NULL;
10893 #define GetDpiForMonitor GetDpiForMonitorSRC
10894#endif
10895
10896#if !defined(RGFW_NO_LOAD_WINMM) && !defined(RGFW_NO_WINMM)
10897 HMODULE RGFW_winmm_dll = NULL;
10898 typedef u32 (WINAPI * PFN_timeBeginPeriod)(u32);
10899 typedef PFN_timeBeginPeriod PFN_timeEndPeriod;
10900 PFN_timeBeginPeriod timeBeginPeriodSRC, timeEndPeriodSRC;
10901 #define timeBeginPeriod timeBeginPeriodSRC
10902 #define timeEndPeriod timeEndPeriodSRC
10903#elif !defined(RGFW_NO_WINMM)
10904 __declspec(dllimport) u32 __stdcall timeBeginPeriod(u32 uPeriod);
10905 __declspec(dllimport) u32 __stdcall timeEndPeriod(u32 uPeriod);
10906#endif
10907#define RGFW_PROC_DEF(proc, name) if (name##SRC == NULL && proc != NULL) { \
10908 name##SRC = (PFN_##name)(RGFW_proc)GetProcAddress((proc), (#name)); \
10909 RGFW_ASSERT(name##SRC != NULL); \
10910 }
10911
10912RGFW_format RGFW_nativeFormat(void) { return RGFW_formatBGRA8; }
10913
10914RGFW_bool RGFW_createSurfacePtr(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) {
10915 RGFW_ASSERT(surface != NULL);
10916 surface->data = data;
10917 surface->w = w;
10918 surface->h = h;
10919 surface->format = format;
10920
10921 BITMAPV5HEADER bi;
10922 ZeroMemory(&bi, sizeof(bi));
10923 bi.bV5Size = sizeof(bi);
10924 bi.bV5Width = (i32)w;
10925 bi.bV5Height = -((LONG) h);
10926 bi.bV5Planes = 1;
10927 bi.bV5BitCount = (format >= RGFW_formatRGBA8) ? 32 : 24;
10928 bi.bV5Compression = BI_RGB;
10929
10930 surface->native.bitmap = CreateDIBSection(_RGFW->root->src.hdc,
10931 (BITMAPINFO*) &bi, DIB_RGB_COLORS,
10932 (void**) &surface->native.bitmapBits,
10933 NULL, (DWORD) 0);
10934
10935 surface->native.format = (format >= RGFW_formatRGBA8) ? RGFW_formatBGRA8 : RGFW_formatBGR8;
10936
10937 if (surface->native.bitmap == NULL) {
10938 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, "Failed to create DIB section.");
10939 return RGFW_FALSE;
10940 }
10941
10942 surface->native.hdcMem = CreateCompatibleDC(_RGFW->root->src.hdc);
10943 SelectObject(surface->native.hdcMem, surface->native.bitmap);
10944
10945 return RGFW_TRUE;
10946}
10947
10948void RGFW_surface_freePtr(RGFW_surface* surface) {
10949 RGFW_ASSERT(surface != NULL);
10950
10951 DeleteDC(surface->native.hdcMem);
10952 DeleteObject(surface->native.bitmap);
10953}
10954
10955void RGFW_window_blitSurface(RGFW_window* win, RGFW_surface* surface) {
10956 RGFW_copyImageData(surface->native.bitmapBits, surface->w, RGFW_MIN(win->h, surface->h), surface->native.format, surface->data, surface->format, surface->convertFunc);
10957 BitBlt(win->src.hdc, 0, 0, RGFW_MIN(win->w, surface->w), RGFW_MIN(win->h, surface->h), surface->native.hdcMem, 0, 0, SRCCOPY);
10958}
10959
10960void RGFW_window_setRawMouseModePlatform(RGFW_window* win, RGFW_bool state) {
10961 RGFW_UNUSED(win);
10962 RAWINPUTDEVICE id = { 0x01, 0x02, 0, win->src.window };
10963 id.dwFlags = (state == RGFW_TRUE) ? 0 : RIDEV_REMOVE;
10964
10965 RegisterRawInputDevices(&id, 1, sizeof(id));
10966}
10967
10968void RGFW_window_captureMousePlatform(RGFW_window* win, RGFW_bool state) {
10969 if (state == RGFW_FALSE) {
10970 ClipCursor(NULL);
10971 return;
10972 }
10973
10974 RECT clipRect;
10975 GetClientRect(win->src.window, &clipRect);
10976 ClientToScreen(win->src.window, (POINT*) &clipRect.left);
10977 ClientToScreen(win->src.window, (POINT*) &clipRect.right);
10978 ClipCursor(&clipRect);
10979}
10980
10981#define RGFW_LOAD_LIBRARY(x, lib) if (x == NULL) { x = LoadLibraryA(lib); RGFW_ASSERT(x != NULL); }
10982
10983#ifdef RGFW_DIRECTX
10984int RGFW_window_createSwapChain_DirectX(RGFW_window* win, IDXGIFactory* pFactory, IUnknown* pDevice, IDXGISwapChain** swapchain) {
10985 RGFW_ASSERT(win && pFactory && pDevice && swapchain);
10986
10987 static DXGI_SWAP_CHAIN_DESC swapChainDesc;
10988 RGFW_MEMSET(&swapChainDesc, 0, sizeof(swapChainDesc));
10989 swapChainDesc.BufferCount = 2;
10990 swapChainDesc.BufferDesc.Width = win->w;
10991 swapChainDesc.BufferDesc.Height = win->h;
10992 swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
10993 swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
10994 swapChainDesc.OutputWindow = (HWND)win->src.window;
10995 swapChainDesc.SampleDesc.Count = 1;
10996 swapChainDesc.SampleDesc.Quality = 0;
10997 swapChainDesc.Windowed = TRUE;
10998 swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
10999
11000 HRESULT hr = pFactory->lpVtbl->CreateSwapChain(pFactory, (IUnknown*)pDevice, &swapChainDesc, swapchain);
11001 if (FAILED(hr)) {
11002 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errDirectXContext, "Failed to create DirectX swap chain!");
11003 return -2;
11004 }
11005
11006 return 0;
11007}
11008#endif
11009
11010/* we're doing it with magic numbers because some keys are missing */
11011void RGFW_initKeycodesPlatform(void) {
11012 _RGFW->keycodes[0x00B] = RGFW_0;
11013 _RGFW->keycodes[0x002] = RGFW_1;
11014 _RGFW->keycodes[0x003] = RGFW_2;
11015 _RGFW->keycodes[0x004] = RGFW_3;
11016 _RGFW->keycodes[0x005] = RGFW_4;
11017 _RGFW->keycodes[0x006] = RGFW_5;
11018 _RGFW->keycodes[0x007] = RGFW_6;
11019 _RGFW->keycodes[0x008] = RGFW_7;
11020 _RGFW->keycodes[0x009] = RGFW_8;
11021 _RGFW->keycodes[0x00A] = RGFW_9;
11022 _RGFW->keycodes[0x01E] = RGFW_a;
11023 _RGFW->keycodes[0x030] = RGFW_b;
11024 _RGFW->keycodes[0x02E] = RGFW_c;
11025 _RGFW->keycodes[0x020] = RGFW_d;
11026 _RGFW->keycodes[0x012] = RGFW_e;
11027 _RGFW->keycodes[0x021] = RGFW_f;
11028 _RGFW->keycodes[0x022] = RGFW_g;
11029 _RGFW->keycodes[0x023] = RGFW_h;
11030 _RGFW->keycodes[0x017] = RGFW_i;
11031 _RGFW->keycodes[0x024] = RGFW_j;
11032 _RGFW->keycodes[0x025] = RGFW_k;
11033 _RGFW->keycodes[0x026] = RGFW_l;
11034 _RGFW->keycodes[0x032] = RGFW_m;
11035 _RGFW->keycodes[0x031] = RGFW_n;
11036 _RGFW->keycodes[0x018] = RGFW_o;
11037 _RGFW->keycodes[0x019] = RGFW_p;
11038 _RGFW->keycodes[0x010] = RGFW_q;
11039 _RGFW->keycodes[0x013] = RGFW_r;
11040 _RGFW->keycodes[0x01F] = RGFW_s;
11041 _RGFW->keycodes[0x014] = RGFW_t;
11042 _RGFW->keycodes[0x016] = RGFW_u;
11043 _RGFW->keycodes[0x02F] = RGFW_v;
11044 _RGFW->keycodes[0x011] = RGFW_w;
11045 _RGFW->keycodes[0x02D] = RGFW_x;
11046 _RGFW->keycodes[0x015] = RGFW_y;
11047 _RGFW->keycodes[0x02C] = RGFW_z;
11048 _RGFW->keycodes[0x028] = RGFW_apostrophe;
11049 _RGFW->keycodes[0x02B] = RGFW_backSlash;
11050 _RGFW->keycodes[0x033] = RGFW_comma;
11051 _RGFW->keycodes[0x00D] = RGFW_equals;
11052 _RGFW->keycodes[0x029] = RGFW_backtick;
11053 _RGFW->keycodes[0x01A] = RGFW_bracket;
11054 _RGFW->keycodes[0x00C] = RGFW_minus;
11055 _RGFW->keycodes[0x034] = RGFW_period;
11056 _RGFW->keycodes[0x01B] = RGFW_closeBracket;
11057 _RGFW->keycodes[0x027] = RGFW_semicolon;
11058 _RGFW->keycodes[0x035] = RGFW_slash;
11059 _RGFW->keycodes[0x056] = RGFW_world2;
11060 _RGFW->keycodes[0x00E] = RGFW_backSpace;
11061 _RGFW->keycodes[0x153] = RGFW_delete;
11062 _RGFW->keycodes[0x14F] = RGFW_end;
11063 _RGFW->keycodes[0x01C] = RGFW_enter;
11064 _RGFW->keycodes[0x001] = RGFW_escape;
11065 _RGFW->keycodes[0x147] = RGFW_home;
11066 _RGFW->keycodes[0x152] = RGFW_insert;
11067 _RGFW->keycodes[0x15D] = RGFW_menu;
11068 _RGFW->keycodes[0x151] = RGFW_pageDown;
11069 _RGFW->keycodes[0x149] = RGFW_pageUp;
11070 _RGFW->keycodes[0x045] = RGFW_pause;
11071 _RGFW->keycodes[0x039] = RGFW_space;
11072 _RGFW->keycodes[0x00F] = RGFW_tab;
11073 _RGFW->keycodes[0x03A] = RGFW_capsLock;
11074 _RGFW->keycodes[0x145] = RGFW_numLock;
11075 _RGFW->keycodes[0x046] = RGFW_scrollLock;
11076 _RGFW->keycodes[0x03B] = RGFW_F1;
11077 _RGFW->keycodes[0x03C] = RGFW_F2;
11078 _RGFW->keycodes[0x03D] = RGFW_F3;
11079 _RGFW->keycodes[0x03E] = RGFW_F4;
11080 _RGFW->keycodes[0x03F] = RGFW_F5;
11081 _RGFW->keycodes[0x040] = RGFW_F6;
11082 _RGFW->keycodes[0x041] = RGFW_F7;
11083 _RGFW->keycodes[0x042] = RGFW_F8;
11084 _RGFW->keycodes[0x043] = RGFW_F9;
11085 _RGFW->keycodes[0x044] = RGFW_F10;
11086 _RGFW->keycodes[0x057] = RGFW_F11;
11087 _RGFW->keycodes[0x058] = RGFW_F12;
11088 _RGFW->keycodes[0x064] = RGFW_F13;
11089 _RGFW->keycodes[0x065] = RGFW_F14;
11090 _RGFW->keycodes[0x066] = RGFW_F15;
11091 _RGFW->keycodes[0x067] = RGFW_F16;
11092 _RGFW->keycodes[0x068] = RGFW_F17;
11093 _RGFW->keycodes[0x069] = RGFW_F18;
11094 _RGFW->keycodes[0x06A] = RGFW_F19;
11095 _RGFW->keycodes[0x06B] = RGFW_F20;
11096 _RGFW->keycodes[0x06C] = RGFW_F21;
11097 _RGFW->keycodes[0x06D] = RGFW_F22;
11098 _RGFW->keycodes[0x06E] = RGFW_F23;
11099 _RGFW->keycodes[0x076] = RGFW_F24;
11100 _RGFW->keycodes[0x038] = RGFW_altL;
11101 _RGFW->keycodes[0x01D] = RGFW_controlL;
11102 _RGFW->keycodes[0x02A] = RGFW_shiftL;
11103 _RGFW->keycodes[0x15B] = RGFW_superL;
11104 _RGFW->keycodes[0x137] = RGFW_printScreen;
11105 _RGFW->keycodes[0x138] = RGFW_altR;
11106 _RGFW->keycodes[0x11D] = RGFW_controlR;
11107 _RGFW->keycodes[0x036] = RGFW_shiftR;
11108 _RGFW->keycodes[0x15C] = RGFW_superR;
11109 _RGFW->keycodes[0x150] = RGFW_down;
11110 _RGFW->keycodes[0x14B] = RGFW_left;
11111 _RGFW->keycodes[0x14D] = RGFW_right;
11112 _RGFW->keycodes[0x148] = RGFW_up;
11113 _RGFW->keycodes[0x052] = RGFW_kp0;
11114 _RGFW->keycodes[0x04F] = RGFW_kp1;
11115 _RGFW->keycodes[0x050] = RGFW_kp2;
11116 _RGFW->keycodes[0x051] = RGFW_kp3;
11117 _RGFW->keycodes[0x04B] = RGFW_kp4;
11118 _RGFW->keycodes[0x04C] = RGFW_kp5;
11119 _RGFW->keycodes[0x04D] = RGFW_kp6;
11120 _RGFW->keycodes[0x047] = RGFW_kp7;
11121 _RGFW->keycodes[0x048] = RGFW_kp8;
11122 _RGFW->keycodes[0x049] = RGFW_kp9;
11123 _RGFW->keycodes[0x04E] = RGFW_kpPlus;
11124 _RGFW->keycodes[0x053] = RGFW_kpPeriod;
11125 _RGFW->keycodes[0x135] = RGFW_kpSlash;
11126 _RGFW->keycodes[0x11C] = RGFW_kpReturn;
11127 _RGFW->keycodes[0x059] = RGFW_kpEqual;
11128 _RGFW->keycodes[0x037] = RGFW_kpMultiply;
11129 _RGFW->keycodes[0x04A] = RGFW_kpMinus;
11130}
11131
11132
11133i32 RGFW_initPlatform(void) {
11134#ifndef RGFW_NO_DPI
11135 #if (_WIN32_WINNT >= 0x0600)
11136 SetProcessDPIAware();
11137 #endif
11138#endif
11139
11140 #ifndef RGFW_NO_WINMM
11141 #ifndef RGFW_NO_LOAD_WINMM
11142 RGFW_LOAD_LIBRARY(RGFW_winmm_dll, "winmm.dll");
11143 RGFW_PROC_DEF(RGFW_winmm_dll, timeBeginPeriod);
11144 RGFW_PROC_DEF(RGFW_winmm_dll, timeEndPeriod);
11145 #endif
11146 timeBeginPeriod(1);
11147 #endif
11148
11149 #ifndef RGFW_NO_DWM
11150 RGFW_LOAD_LIBRARY(RGFW_dwm_dll, "dwmapi.dll");
11151 RGFW_PROC_DEF(RGFW_dwm_dll, DwmEnableBlurBehindWindow);
11152 RGFW_PROC_DEF(RGFW_dwm_dll, DwmSetWindowAttribute);
11153 #endif
11154
11155 RGFW_LOAD_LIBRARY(RGFW_wgl_dll, "opengl32.dll");
11156 #ifndef RGFW_NO_LOAD_WGL
11157 RGFW_PROC_DEF(RGFW_wgl_dll, wglCreateContext);
11158 RGFW_PROC_DEF(RGFW_wgl_dll, wglDeleteContext);
11159 RGFW_PROC_DEF(RGFW_wgl_dll, wglGetProcAddress);
11160 RGFW_PROC_DEF(RGFW_wgl_dll, wglMakeCurrent);
11161 RGFW_PROC_DEF(RGFW_wgl_dll, wglGetCurrentDC);
11162 RGFW_PROC_DEF(RGFW_wgl_dll, wglGetCurrentContext);
11163 RGFW_PROC_DEF(RGFW_wgl_dll, wglShareLists);
11164 #endif
11165
11166 u8 RGFW_blk[] = { 0, 0, 0, 0 };
11167 _RGFW->hiddenMouse = RGFW_loadMouse(RGFW_blk, 1, 1, RGFW_formatRGBA8);
11168 return 1;
11169}
11170
11171RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win) {
11172 if (name[0] == 0) name = (char*) " ";
11173 win->src.hIconSmall = win->src.hIconBig = NULL;
11174 win->src.maxSizeW = 0;
11175 win->src.maxSizeH = 0;
11176 win->src.minSizeW = 0;
11177 win->src.minSizeH = 0;
11178 win->src.aspectRatioW = 0;
11179 win->src.aspectRatioH = 0;
11180
11181 HINSTANCE inh = GetModuleHandleA(NULL);
11182
11183 #ifndef __cplusplus
11184 WNDCLASSW Class = {0}; /*!< Setup the Window class. */
11185 #else
11186 WNDCLASSW Class = {};
11187 #endif
11188
11189 if (_RGFW->className == NULL)
11190 _RGFW->className = (char*)name;
11191
11192 wchar_t wide_class[256];
11193 MultiByteToWideChar(CP_UTF8, 0, _RGFW->className, -1, wide_class, 255);
11194
11195 Class.lpszClassName = wide_class;
11196 Class.hInstance = inh;
11197 Class.hCursor = LoadCursor(NULL, IDC_ARROW);
11198 Class.lpfnWndProc = WndProcW;
11199 Class.cbClsExtra = sizeof(RGFW_window*);
11200
11201 Class.hIcon = (HICON)LoadImageA(GetModuleHandleW(NULL), "RGFW_ICON", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
11202 if (Class.hIcon == NULL)
11203 Class.hIcon = (HICON)LoadImageA(NULL, (LPCSTR)IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
11204
11205 RegisterClassW(&Class);
11206
11207 DWORD window_style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
11208
11209 RECT windowRect, clientRect;
11210
11211 if (!(flags & RGFW_windowNoBorder)) {
11212 window_style |= WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX;
11213
11214 if (!(flags & RGFW_windowNoResize))
11215 window_style |= WS_SIZEBOX | WS_MAXIMIZEBOX;
11216 } else
11217 window_style |= WS_POPUP | WS_VISIBLE | WS_SYSMENU;
11218
11219 wchar_t wide_name[256];
11220 MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_name, 255);
11221 HWND dummyWin = CreateWindowW(Class.lpszClassName, (wchar_t*)wide_name, window_style, win->x, win->y, win->w, win->h, 0, 0, inh, 0);
11222
11223 GetWindowRect(dummyWin, &windowRect);
11224 GetClientRect(dummyWin, &clientRect);
11225
11226#ifdef RGFW_OPENGL
11227 RGFW_win32_loadOpenGLFuncs(dummyWin);
11228#endif
11229
11230 DestroyWindow(dummyWin);
11231
11232 RECT rect = { 0, 0, win->w, win->h};
11233 DWORD style = RGFW_winapi_window_getStyle(win, flags);
11234 DWORD exStyle = RGFW_winapi_window_getExStyle(win, flags);
11235 AdjustWindowRectEx(&rect, style, FALSE, exStyle);
11236
11237 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);
11238 SetPropW(win->src.window, L"RGFW", win);
11239 RGFW_window_resize(win, win->w, win->h); /* so WM_GETMINMAXINFO gets called again */
11240
11241 if (flags & RGFW_windowAllowDND) {
11242 win->internal.flags |= RGFW_windowAllowDND;
11243 RGFW_window_setDND(win, 1);
11244 }
11245 win->src.hdc = GetDC(win->src.window);
11246
11247 RGFW_win32_makeWindowDarkMode(win, RGFW_win32_getDarkModeState());
11248 RGFW_win32_makeWindowTransparent(win);
11249 return win;
11250}
11251
11252void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) {
11253 RGFW_setBit(&win->internal.flags, RGFW_windowNoBorder, !border);
11254 LONG style = GetWindowLong(win->src.window, GWL_STYLE);
11255
11256 if (border == 0) {
11257 SetWindowLong(win->src.window, GWL_STYLE, style & ~WS_OVERLAPPEDWINDOW);
11258 SetWindowPos(
11259 win->src.window, HWND_TOP, 0, 0, 0, 0,
11260 SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE
11261 );
11262 }
11263 else {
11264 if (win->internal.flags & RGFW_windowNoResize) style &= ~WS_MAXIMIZEBOX;
11265 SetWindowLong(win->src.window, GWL_STYLE, style | WS_OVERLAPPEDWINDOW);
11266 SetWindowPos(
11267 win->src.window, HWND_TOP, 0, 0, 0, 0,
11268 SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE
11269 );
11270 }
11271}
11272
11273void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow) {
11274 RGFW_setBit(&win->internal.flags, RGFW_windowAllowDND, allow);
11275 DragAcceptFiles(win->src.window, allow);
11276}
11277
11278RGFW_bool RGFW_getGlobalMouse(i32* x, i32* y) {
11279 POINT p;
11280 GetCursorPos(&p);
11281 if (x) *x = p.x;
11282 if (y) *y = p.y;
11283 return RGFW_TRUE;
11284}
11285
11286void RGFW_window_setAspectRatio(RGFW_window* win, i32 w, i32 h) {
11287 RGFW_ASSERT(win != NULL);
11288 win->src.aspectRatioW = w;
11289 win->src.aspectRatioH = h;
11290}
11291
11292void RGFW_window_setMinSize(RGFW_window* win, i32 w, i32 h) {
11293 RGFW_ASSERT(win != NULL);
11294 win->src.minSizeW = w;
11295 win->src.minSizeH = h;
11296}
11297
11298void RGFW_window_setMaxSize(RGFW_window* win, i32 w, i32 h) {
11299 RGFW_ASSERT(win != NULL);
11300 win->src.maxSizeW = w;
11301 win->src.maxSizeH = h;
11302}
11303
11304void RGFW_window_focus(RGFW_window* win) {
11305 RGFW_ASSERT(win);
11306 SetForegroundWindow(win->src.window);
11307 SetFocus(win->src.window);
11308}
11309
11310void RGFW_window_raise(RGFW_window* win) {
11311 RGFW_ASSERT(win);
11312 BringWindowToTop(win->src.window);
11313 SetWindowPos(win->src.window, HWND_TOP, win->x, win->y, win->w, win->h, SWP_NOSIZE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
11314}
11315
11316void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) {
11317 RGFW_ASSERT(win != NULL);
11318
11319 if (fullscreen == RGFW_FALSE) {
11320 RGFW_window_setBorder(win, 1);
11321
11322 RECT rect = { 0, 0, win->internal.oldW, win->internal.oldH};
11323 DWORD style = RGFW_winapi_window_getStyle(win, win->internal.flags);
11324 DWORD exStyle = RGFW_winapi_window_getExStyle(win, win->internal.flags);
11325 AdjustWindowRectEx(&rect, style, FALSE, exStyle);
11326 SetWindowPos(win->src.window, HWND_TOP, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER);
11327
11328
11329 win->internal.flags &= ~(u32)RGFW_windowFullscreen;
11330 win->x = win->internal.oldX;
11331 win->y = win->internal.oldY;
11332 win->w = win->internal.oldW;
11333 win->h = win->internal.oldH;
11334 return;
11335 }
11336
11337 win->internal.oldX = win->x;
11338 win->internal.oldY = win->y;
11339 win->internal.oldW = win->w;
11340 win->internal.oldH = win->h;
11341 win->internal.flags |= RGFW_windowFullscreen;
11342
11343 RGFW_monitor* mon = RGFW_window_getMonitor(win);
11344
11345 RGFW_window_setBorder(win, 0);
11346 RGFW_monitor_scaleToWindow(mon, win);
11347
11348 SetWindowPos(win->src.window, HWND_TOPMOST, (i32)mon->x, (i32)mon->y, (i32)mon->mode.w, (i32)mon->mode.h, SWP_NOOWNERZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW);
11349
11350 win->x = mon->x;
11351 win->y = mon->y;
11352 win->w = mon->mode.w;
11353 win->h = mon->mode.h;
11354}
11355
11356void RGFW_window_maximize(RGFW_window* win) {
11357 RGFW_ASSERT(win != NULL);
11358 RGFW_window_hide(win);
11359 ShowWindow(win->src.window, SW_MAXIMIZE);
11360}
11361
11362void RGFW_window_minimize(RGFW_window* win) {
11363 RGFW_ASSERT(win != NULL);
11364 ShowWindow(win->src.window, SW_MINIMIZE);
11365}
11366
11367void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) {
11368 RGFW_ASSERT(win != NULL);
11369 if (floating) SetWindowPos(win->src.window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
11370 else SetWindowPos(win->src.window, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
11371}
11372
11373void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) {
11374 SetWindowLong(win->src.window, GWL_EXSTYLE, WS_EX_LAYERED);
11375 SetLayeredWindowAttributes(win->src.window, 0, opacity, LWA_ALPHA);
11376}
11377
11378void RGFW_window_restore(RGFW_window* win) { RGFW_window_show(win); }
11379
11380RGFW_bool RGFW_window_isFloating(RGFW_window* win) {
11381 return (GetWindowLongPtr(win->src.window, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
11382}
11383
11384void RGFW_stopCheckEvents(void) {
11385 PostMessageW(_RGFW->root->src.window, WM_NULL, 0, 0);
11386}
11387
11388void RGFW_waitForEvent(i32 waitMS) {
11389 MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD)waitMS, QS_ALLINPUT);
11390}
11391
11392RGFW_key RGFW_physicalToMappedKey(RGFW_key key) {
11393 UINT vsc = RGFW_rgfwToApiKey(key);
11394 BYTE keyboardState[256] = {0};
11395
11396 if (!GetKeyboardState(keyboardState))
11397 return key;
11398
11399 UINT vk = MapVirtualKeyW(vsc, MAPVK_VSC_TO_VK);
11400 HKL layout = GetKeyboardLayout(0);
11401
11402 wchar_t charBuffer[4] = {0};
11403 int result = ToUnicodeEx(vk, vsc, keyboardState, charBuffer, 1, 0, layout);
11404
11405 if (result == 1 && charBuffer[0] < 256) {
11406 return (RGFW_key)charBuffer[0];
11407 }
11408
11409 switch (vk) {
11410 case VK_F1: return RGFW_F1;
11411 case VK_F2: return RGFW_F2;
11412 case VK_F3: return RGFW_F3;
11413 case VK_F4: return RGFW_F4;
11414 case VK_F5: return RGFW_F5;
11415 case VK_F6: return RGFW_F6;
11416 case VK_F7: return RGFW_F7;
11417 case VK_F8: return RGFW_F8;
11418 case VK_F9: return RGFW_F9;
11419 case VK_F10: return RGFW_F10;
11420 case VK_F11: return RGFW_F11;
11421 case VK_F12: return RGFW_F12;
11422 case VK_F13: return RGFW_F13;
11423 case VK_F14: return RGFW_F14;
11424 case VK_F15: return RGFW_F15;
11425 case VK_F16: return RGFW_F16;
11426 case VK_F17: return RGFW_F17;
11427 case VK_F18: return RGFW_F18;
11428 case VK_F19: return RGFW_F19;
11429 case VK_F20: return RGFW_F20;
11430 case VK_F21: return RGFW_F21;
11431 case VK_F22: return RGFW_F22;
11432 case VK_F23: return RGFW_F23;
11433 case VK_F24: return RGFW_F24;
11434 case VK_LSHIFT: return RGFW_shiftL;
11435 case VK_RSHIFT: return RGFW_shiftR;
11436 case VK_LCONTROL: return RGFW_controlL;
11437 case VK_RCONTROL: return RGFW_controlR;
11438 case VK_LMENU: return RGFW_altL;
11439 case VK_RMENU: return RGFW_altR;
11440 case VK_LWIN: return RGFW_superL;
11441 case VK_RWIN: return RGFW_superR;
11442 case VK_CAPITAL: return RGFW_capsLock;
11443 case VK_NUMLOCK: return RGFW_numLock;
11444 case VK_SCROLL: return RGFW_scrollLock;
11445 case VK_UP: return RGFW_up;
11446 case VK_DOWN: return RGFW_down;
11447 case VK_LEFT: return RGFW_left;
11448 case VK_RIGHT: return RGFW_right;
11449 case VK_HOME: return RGFW_home;
11450 case VK_END: return RGFW_end;
11451 case VK_PRIOR: return RGFW_pageUp;
11452 case VK_NEXT: return RGFW_pageDown;
11453 case VK_INSERT: return RGFW_insert;
11454 case VK_APPS: return RGFW_menu;
11455 case VK_ADD: return RGFW_kpPlus;
11456 case VK_SUBTRACT: return RGFW_kpMinus;
11457 case VK_MULTIPLY: return RGFW_kpMultiply;
11458 case VK_DIVIDE: return RGFW_kpSlash;
11459 case VK_RETURN: return RGFW_kpReturn;
11460 case VK_DECIMAL: return RGFW_kpPeriod;
11461 case VK_NUMPAD0: return RGFW_kp0;
11462 case VK_NUMPAD1: return RGFW_kp1;
11463 case VK_NUMPAD2: return RGFW_kp2;
11464 case VK_NUMPAD3: return RGFW_kp3;
11465 case VK_NUMPAD4: return RGFW_kp4;
11466 case VK_NUMPAD5: return RGFW_kp5;
11467 case VK_NUMPAD6: return RGFW_kp6;
11468 case VK_NUMPAD7: return RGFW_kp7;
11469 case VK_NUMPAD8: return RGFW_kp8;
11470 case VK_NUMPAD9: return RGFW_kp9;
11471 case VK_SNAPSHOT: return RGFW_printScreen;
11472 case VK_PAUSE: return RGFW_pause;
11473 default: return RGFW_keyNULL;
11474 }
11475
11476 return RGFW_keyNULL;
11477}
11478
11479void RGFW_pollEvents(void) {
11480 RGFW_resetPrevState();
11481 MSG msg;
11482 while (PeekMessageA(&msg, NULL, 0u, 0u, PM_REMOVE)) {
11483 TranslateMessage(&msg);
11484 DispatchMessageA(&msg);
11485 }
11486}
11487
11488RGFW_bool RGFW_window_isHidden(RGFW_window* win) {
11489 RGFW_ASSERT(win != NULL);
11490 return IsWindowVisible(win->src.window) == 0 && !RGFW_window_isMinimized(win);
11491}
11492
11493RGFW_bool RGFW_window_isMinimized(RGFW_window* win) {
11494 RGFW_ASSERT(win != NULL);
11495
11496 #ifndef __cplusplus
11497 WINDOWPLACEMENT placement = {0};
11498 #else
11499 WINDOWPLACEMENT placement = {};
11500 #endif
11501 GetWindowPlacement(win->src.window, &placement);
11502 return placement.showCmd == SW_SHOWMINIMIZED;
11503}
11504
11505RGFW_bool RGFW_window_isMaximized(RGFW_window* win) {
11506 RGFW_ASSERT(win != NULL);
11507
11508 #ifndef __cplusplus
11509 WINDOWPLACEMENT placement = {0};
11510 #else
11511 WINDOWPLACEMENT placement = {};
11512 #endif
11513 GetWindowPlacement(win->src.window, &placement);
11514 return placement.showCmd == SW_SHOWMAXIMIZED || IsZoomed(win->src.window);
11515}
11516
11517RGFW_bool RGFW_monitor_getWorkarea(RGFW_monitor* monitor, i32* x, i32* y, i32* width, i32* height) {
11518 MONITORINFOEX mi;
11519 mi.cbSize = sizeof(MONITORINFOEX);
11520 GetMonitorInfoA(monitor->node->hMonitor, (LPMONITORINFO)&mi);
11521
11522 if (x) *x = mi.rcWork.left;
11523 if (y) *y = mi.rcWork.top;
11524 if (width) *width = mi.rcWork.right - mi.rcWork.left;
11525 if (height) *height = mi.rcWork.bottom - mi.rcWork.top;
11526
11527 return RGFW_TRUE;
11528}
11529
11530size_t RGFW_monitor_getGammaRampPtr(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
11531 WORD values[3][256];
11532
11533 HDC dc = CreateDCW(L"DISPLAY", monitor->node->adapterName, NULL, NULL);
11534 GetDeviceGammaRamp(dc, values);
11535 DeleteDC(dc);
11536
11537 if (ramp) {
11538 memcpy(ramp->red, values[0], sizeof(values[0]));
11539 memcpy(ramp->green, values[1], sizeof(values[1]));
11540 memcpy(ramp->blue, values[2], sizeof(values[2]));
11541 }
11542
11543 return sizeof(values[0]) / sizeof(WORD);
11544}
11545
11546RGFW_bool RGFW_monitor_setGammaRamp(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
11547 WORD values[3][256];
11548 if (ramp->count != 256) {
11549 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errX11, "Win32: Gamma ramp size must be 256");
11550 return RGFW_FALSE;
11551 }
11552
11553 memcpy(values[0], ramp->red, sizeof(values[0]));
11554 memcpy(values[1], ramp->green, sizeof(values[1]));
11555 memcpy(values[2], ramp->blue, sizeof(values[2]));
11556
11557 HDC dc = CreateDCW(L"DISPLAY", monitor->node->adapterName, NULL, NULL);
11558 SetDeviceGammaRamp(dc, values);
11559 DeleteDC(dc);
11560 return RGFW_TRUE;
11561}
11562
11563BOOL CALLBACK RGFW_win32_getMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData);
11564BOOL CALLBACK RGFW_win32_getMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
11565 RGFW_UNUSED(hMonitor);
11566 RGFW_UNUSED(hdcMonitor);
11567 RGFW_UNUSED(lprcMonitor);
11568 RGFW_UNUSED(dwData);
11569
11570 MONITORINFOEXW mi;
11571 ZeroMemory(&mi, sizeof(mi));
11572 mi.cbSize = sizeof(mi);
11573
11574 if (GetMonitorInfoW(hMonitor, (MONITORINFO*) &mi)) {
11575 RGFW_monitorNode* node = (RGFW_monitorNode*)dwData;
11576 if (wcscmp(mi.szDevice, node->adapterName) == 0) {
11577 node->hMonitor = hMonitor;
11578 }
11579 }
11580
11581 return TRUE;
11582}
11583
11584RGFWDEF void RGFW_win32_getMode(DEVMODEW* dm, RGFW_monitorMode* mode);
11585void RGFW_win32_getMode(DEVMODEW* dm, RGFW_monitorMode* mode) {
11586 mode->w = (i32)dm->dmPelsWidth;
11587 mode->h = (i32)dm->dmPelsHeight;
11588 RGFW_splitBPP(dm->dmBitsPerPel, mode);
11589
11590 switch (dm->dmDisplayFrequency) {
11591 case 119:
11592 case 59:
11593 case 29:
11594 mode->refreshRate = ((float)(dm->dmDisplayFrequency + 1) * 1000.0f) / 1001.f;
11595 break;
11596 default:
11597 mode->refreshRate = (float)dm->dmDisplayFrequency;
11598 break;
11599 }
11600}
11601
11602size_t RGFW_monitor_getModesPtr(RGFW_monitor* monitor, RGFW_monitorMode** modes){
11603 size_t count = 0;
11604 DWORD modeIndex = 0;
11605
11606 for (;;) {
11607 DEVMODEW dm;
11608 ZeroMemory(&dm, sizeof(dm));
11609 dm.dmSize = sizeof(dm);
11610
11611 if (!EnumDisplaySettingsW(monitor->node->adapterName, modeIndex, &dm))
11612 break;
11613
11614 modeIndex++;
11615
11616 if (dm.dmBitsPerPel < 15)
11617 continue;
11618
11619 if (modes) {
11620 RGFW_monitorMode mode;
11621 RGFW_win32_getMode(&dm, &mode);
11622
11623 size_t i;
11624 for (i = 0; i < count; i++) {
11625 if (RGFW_monitorModeCompare(&(*modes)[i], &mode, RGFW_monitorAll) == RGFW_TRUE) {
11626 break;
11627 }
11628 }
11629
11630 if (i < count) {
11631 continue;
11632 }
11633
11634 (*modes)[count] = mode;
11635 }
11636
11637 count += 1;
11638 }
11639
11640 return count;
11641}
11642
11643RGFWDEF void RGFW_win32_createMonitor(DISPLAY_DEVICEW* adapter, DISPLAY_DEVICEW* dd);
11644void RGFW_win32_createMonitor(DISPLAY_DEVICEW* adapter, DISPLAY_DEVICEW* dd) {
11645 DEVMODEW dm;
11646 ZeroMemory(&dm, sizeof(dm));
11647 dm.dmSize = sizeof(dm);
11648
11649 if (!EnumDisplaySettingsW(adapter->DeviceName, ENUM_CURRENT_SETTINGS, &dm)) {
11650 return;
11651 }
11652
11653 RGFW_monitorNode* node = RGFW_monitors_add(NULL);
11654
11655 wcscpy(node->adapterName, adapter->DeviceName);
11656 wcscpy(node->deviceName, dd->DeviceName);
11657
11658 RGFW_createUTF8FromWideStringWin32(dd->DeviceString, node->mon.name, sizeof(node->mon.name));
11659 node->mon.name[sizeof(node->mon.name) - 1] = '\0';
11660
11661 RECT rect;
11662 rect.left = (LONG)dm.dmPosition.x;
11663 rect.top = (LONG)dm.dmPosition.y;
11664 rect.right = (LONG)((LONG)dm.dmPosition.x + (LONG)dm.dmPelsWidth);
11665 rect.bottom = (LONG)((long)dm.dmPosition.y + (LONG)dm.dmPelsHeight);
11666 EnumDisplayMonitors(NULL, &rect, RGFW_win32_getMonitorHandle, (LPARAM)node);
11667
11668 RGFW_win32_getMode(&dm, &node->mon.mode);
11669
11670 MONITORINFOEXW monitorInfo;
11671 monitorInfo.cbSize = sizeof(MONITORINFOEXW);
11672 GetMonitorInfoW(node->hMonitor, (LPMONITORINFO)&monitorInfo);
11673
11674 node->mon.x = monitorInfo.rcMonitor.left;
11675 node->mon.y = monitorInfo.rcMonitor.top;
11676
11677 HDC hdc = CreateDCW(monitorInfo.szDevice, NULL, NULL, NULL);
11678 /* get pixels per inch */
11679 float dpiX = (float)GetDeviceCaps(hdc, LOGPIXELSX);
11680 float dpiY = (float)GetDeviceCaps(hdc, LOGPIXELSX);
11681
11682 node->mon.scaleX = dpiX / 96.0f;
11683 node->mon.scaleY = dpiY / 96.0f;
11684 node->mon.pixelRatio = dpiX >= 192.0f ? 2.0f : 1.0f;
11685
11686 node->mon.physW = (float)GetDeviceCaps(hdc, HORZSIZE) / 25.4f;
11687 node->mon.physH = (float)GetDeviceCaps(hdc, VERTSIZE) / 25.4f;
11688 DeleteDC(hdc);
11689
11690#ifndef RGFW_NO_DPI
11691 RGFW_LOAD_LIBRARY(RGFW_Shcore_dll, "shcore.dll");
11692 RGFW_PROC_DEF(RGFW_Shcore_dll, GetDpiForMonitor);
11693
11694 if (GetDpiForMonitor != NULL) {
11695 u32 x, y;
11696 GetDpiForMonitor(node->hMonitor, MDT_EFFECTIVE_DPI, &x, &y);
11697 node->mon.scaleX = (float) (x) / (float) 96.0f;
11698 node->mon.scaleY = (float) (y) / (float) 96.0f;
11699 node->mon.pixelRatio = dpiX >= 192.0f ? 2.0f : 1.0f;
11700 }
11701#endif
11702
11703 if (monitorInfo.dwFlags & MONITORINFOF_PRIMARY) {
11704 _RGFW->monitors.primary = node;
11705 }
11706
11707 RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_TRUE);
11708}
11709
11710void RGFW_pollMonitors(void) {
11711 for (RGFW_monitorNode* node = _RGFW->monitors.list.head; node; node = node->next) {
11712 node->disconnected = RGFW_TRUE;
11713 }
11714
11715 /* loop through display adapters (GPU) */
11716 DISPLAY_DEVICEW adapter;
11717 DWORD adapterNum;
11718 for (adapterNum = 0; ; adapterNum++) {
11719 ZeroMemory(&adapter, sizeof(adapter));
11720 adapter.cb = sizeof(adapter);
11721
11722 if (!EnumDisplayDevicesW(NULL, adapterNum, &adapter, 0))
11723 break;
11724
11725 if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE))
11726 continue;
11727
11728 DISPLAY_DEVICEW dd;
11729 dd.cb = sizeof(dd);
11730
11731 /* loop through display devices (monitors) */
11732 DWORD deviceNum;
11733 for (deviceNum = 0; ; deviceNum++) {
11734 ZeroMemory(&dd, sizeof(dd));
11735 dd.cb = sizeof(dd);
11736
11737 if (!EnumDisplayDevicesW(adapter.DeviceName, deviceNum, &dd, 0))
11738 break;
11739
11740 if (!(dd.StateFlags & DISPLAY_DEVICE_ACTIVE))
11741 continue;
11742
11743 RGFW_monitorNode* node;
11744 for (node = _RGFW->monitors.list.head; node; node = node->next) {
11745 if (node->disconnected == RGFW_TRUE && wcscmp(node->deviceName, dd.DeviceName) == 0) {
11746 node->disconnected = RGFW_FALSE;
11747 EnumDisplayMonitors(NULL, NULL, RGFW_win32_getMonitorHandle, (LPARAM) &node->mon);
11748 break;
11749 }
11750 }
11751
11752 if (node) {
11753 continue;
11754 }
11755
11756 RGFW_win32_createMonitor(&adapter, &dd);
11757 }
11758
11759 /* if there are no display devices, just use the monitor directly (hack borrowed from GLFW (I'm not giving it back)) */
11760 if (deviceNum == 0) {
11761 RGFW_monitorNode* node;
11762 for (node = _RGFW->monitors.list.head; node; node = node->next) {
11763 if (node->disconnected == RGFW_TRUE && wcscmp(node->adapterName, adapter.DeviceName) == 0) {
11764 node->disconnected = RGFW_FALSE;
11765 break;
11766 }
11767 }
11768
11769 if (node) {
11770 continue;
11771 }
11772
11773 RGFW_win32_createMonitor(&adapter, NULL);
11774 }
11775 }
11776
11777 RGFW_monitors_refresh();
11778}
11779
11780RGFW_monitor* RGFW_window_getMonitor(RGFW_window* win) {
11781 HMONITOR src = MonitorFromWindow(win->src.window, MONITOR_DEFAULTTOPRIMARY);
11782 RGFW_monitorNode* node = _RGFW->monitors.list.head;
11783
11784 for (node = _RGFW->monitors.list.head; node; node = node->next) {
11785 if (node->hMonitor == src) {
11786 return &node->mon;
11787 }
11788 }
11789
11790 return RGFW_getPrimaryMonitor();
11791}
11792
11793RGFW_bool RGFW_monitor_setMode(RGFW_monitor* mon, RGFW_monitorMode* mode) {
11794 DEVMODEW dm;
11795 ZeroMemory(&dm, sizeof(dm));
11796 dm.dmSize = sizeof(dm);
11797
11798 dm.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT;
11799 dm.dmPelsWidth = (u32)mode->w;
11800 dm.dmPelsHeight = (u32)mode->h;
11801
11802 dm.dmFields |= DM_DISPLAYFREQUENCY;
11803 dm.dmDisplayFrequency = (DWORD)mode->refreshRate;
11804
11805 dm.dmFields |= DM_BITSPERPEL;
11806 dm.dmBitsPerPel = (DWORD)(mode->red + mode->green + mode->blue);
11807
11808 if (ChangeDisplaySettingsExW(mon->node->adapterName, &dm, NULL, CDS_TEST, NULL) == DISP_CHANGE_SUCCESSFUL) {
11809 if (ChangeDisplaySettingsExW(mon->node->adapterName, &dm, NULL, CDS_UPDATEREGISTRY, NULL) == DISP_CHANGE_SUCCESSFUL)
11810 return RGFW_TRUE;
11811 return RGFW_FALSE;
11812 } else return RGFW_FALSE;
11813}
11814
11815RGFW_bool RGFW_monitor_requestMode(RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request) {
11816 HMONITOR src = mon->node->hMonitor;
11817
11818 MONITORINFOEX monitorInfo;
11819 monitorInfo.cbSize = sizeof(MONITORINFOEX);
11820 GetMonitorInfoA(src, (LPMONITORINFO)&monitorInfo);
11821
11822 DEVMODEW dm;
11823 ZeroMemory(&dm, sizeof(dm));
11824 dm.dmSize = sizeof(dm);
11825
11826 if (EnumDisplaySettingsW(mon->node->adapterName, ENUM_CURRENT_SETTINGS, &dm)) {
11827 if (request & RGFW_monitorScale) {
11828 dm.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT;
11829 dm.dmPelsWidth = (u32)mode->w;
11830 dm.dmPelsHeight = (u32)mode->h;
11831 }
11832
11833 if (request & RGFW_monitorRefresh) {
11834 dm.dmFields |= DM_DISPLAYFREQUENCY;
11835 dm.dmDisplayFrequency = (DWORD)mode->refreshRate;
11836 }
11837
11838 if (request & RGFW_monitorRGB) {
11839 dm.dmFields |= DM_BITSPERPEL;
11840 dm.dmBitsPerPel = (DWORD)(mode->red + mode->green + mode->blue);
11841 }
11842
11843 if (ChangeDisplaySettingsExW(mon->node->adapterName, &dm, NULL, CDS_TEST, NULL) == DISP_CHANGE_SUCCESSFUL) {
11844 if (ChangeDisplaySettingsExW(mon->node->adapterName, &dm, NULL, CDS_UPDATEREGISTRY, NULL) == DISP_CHANGE_SUCCESSFUL) {
11845 RGFW_win32_getMode(&dm, &mon->mode);
11846 return RGFW_TRUE;
11847 }
11848 return RGFW_FALSE;
11849 } else return RGFW_FALSE;
11850 }
11851
11852 return RGFW_FALSE;
11853}
11854
11855HICON RGFW_loadHandleImage(u8* data, i32 w, i32 h, RGFW_format format, BOOL icon);
11856HICON RGFW_loadHandleImage(u8* data, i32 w, i32 h, RGFW_format format, BOOL icon) {
11857 BITMAPV5HEADER bi;
11858 ZeroMemory(&bi, sizeof(bi));
11859 bi.bV5Size = sizeof(bi);
11860 bi.bV5Width = (i32)w;
11861 bi.bV5Height = -((LONG) h);
11862 bi.bV5Planes = 1;
11863 bi.bV5BitCount = (WORD)32;
11864 bi.bV5Compression = BI_RGB;
11865 HDC dc = GetDC(NULL);
11866 u8* target = NULL;
11867
11868 HBITMAP color = CreateDIBSection(dc,
11869 (BITMAPINFO*) &bi, DIB_RGB_COLORS, (void**) &target,
11870 NULL, (DWORD) 0);
11871
11872 RGFW_copyImageData(target, w, h, RGFW_formatBGRA8, data, format, NULL);
11873 ReleaseDC(NULL, dc);
11874
11875 HBITMAP mask = CreateBitmap((i32)w, (i32)h, 1, 1, NULL);
11876
11877 ICONINFO ii;
11878 ZeroMemory(&ii, sizeof(ii));
11879 ii.fIcon = icon;
11880 ii.xHotspot = (u32)w / 2;
11881 ii.yHotspot = (u32)h / 2;
11882 ii.hbmMask = mask;
11883 ii.hbmColor = color;
11884
11885 HICON handle = CreateIconIndirect(&ii);
11886
11887 DeleteObject(color);
11888 DeleteObject(mask);
11889
11890 return handle;
11891}
11892RGFW_mouse* RGFW_loadMouse(u8* data, i32 w, i32 h, RGFW_format format) {
11893 HCURSOR cursor = (HCURSOR) RGFW_loadHandleImage(data, w, h, format, FALSE);
11894 return cursor;
11895}
11896
11897void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) {
11898 RGFW_ASSERT(win && mouse);
11899 SetClassLongPtrA(win->src.window, GCLP_HCURSOR, (LPARAM) mouse);
11900 SetCursor((HCURSOR)mouse);
11901}
11902
11903void RGFW_freeMouse(RGFW_mouse* mouse) {
11904 RGFW_ASSERT(mouse);
11905 DestroyCursor((HCURSOR)mouse);
11906}
11907
11908RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) {
11909 return RGFW_window_setMouseStandard(win, RGFW_mouseArrow);
11910}
11911
11912RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) {
11913 RGFW_ASSERT(win != NULL);
11914
11915 u32 mouseIcon = 0;
11916
11917 switch (mouse) {
11918 case RGFW_mouseNormal: mouseIcon = OCR_NORMAL; break;
11919 case RGFW_mouseArrow: mouseIcon = OCR_NORMAL; break;
11920 case RGFW_mouseIbeam: mouseIcon = OCR_IBEAM; break;
11921 case RGFW_mouseWait: mouseIcon = OCR_WAIT; break;
11922 case RGFW_mouseCrosshair: mouseIcon = OCR_CROSS; break;
11923 case RGFW_mouseProgress: mouseIcon = OCR_APPSTARTING; break;
11924 case RGFW_mouseResizeNWSE: mouseIcon = OCR_SIZENWSE; break;
11925 case RGFW_mouseResizeNESW: mouseIcon = OCR_SIZENESW; break;
11926 case RGFW_mouseResizeEW: mouseIcon = OCR_SIZEWE; break;
11927 case RGFW_mouseResizeNS: mouseIcon = OCR_SIZENS; break;
11928 case RGFW_mouseResizeAll: mouseIcon = OCR_SIZEALL; break;
11929 case RGFW_mouseNotAllowed: mouseIcon = OCR_NO; break;
11930 case RGFW_mousePointingHand: mouseIcon = OCR_HAND; break;
11931 case RGFW_mouseResizeNW: mouseIcon = OCR_SIZENWSE; break;
11932 case RGFW_mouseResizeN: mouseIcon = OCR_SIZENS; break;
11933 case RGFW_mouseResizeNE: mouseIcon = OCR_SIZENESW; break;
11934 case RGFW_mouseResizeE: mouseIcon = OCR_SIZEWE; break;
11935 case RGFW_mouseResizeSE: mouseIcon = OCR_SIZENWSE; break;
11936 case RGFW_mouseResizeS: mouseIcon = OCR_SIZENS; break;
11937 case RGFW_mouseResizeSW: mouseIcon = OCR_SIZENESW; break;
11938 case RGFW_mouseResizeW: mouseIcon = OCR_SIZEWE; break;
11939 default: return RGFW_FALSE;
11940 }
11941
11942 char* icon = MAKEINTRESOURCEA(mouseIcon);
11943
11944 SetClassLongPtrA(win->src.window, GCLP_HCURSOR, (LPARAM) LoadCursorA(NULL, icon));
11945 SetCursor(LoadCursorA(NULL, icon));
11946 return RGFW_TRUE;
11947}
11948
11949void RGFW_window_hide(RGFW_window* win) {
11950 ShowWindow(win->src.window, SW_HIDE);
11951}
11952
11953void RGFW_window_show(RGFW_window* win) {
11954 if (win->internal.flags & RGFW_windowFocusOnShow) RGFW_window_focus(win);
11955 ShowWindow(win->src.window, SW_RESTORE);
11956}
11957
11958void RGFW_window_flash(RGFW_window* win, RGFW_flashRequest request) {
11959 if (RGFW_window_isInFocus(win) && request) {
11960 return;
11961 }
11962
11963 FLASHWINFO desc;
11964 RGFW_MEMSET(&desc, 0, sizeof(desc));
11965
11966 desc.cbSize = sizeof(desc);
11967 desc.hwnd = win->src.window;
11968
11969 switch (request) {
11970 case RGFW_flashCancel:
11971 desc.dwFlags = FLASHW_STOP;
11972 break;
11973 case RGFW_flashBriefly:
11974 desc.dwFlags = FLASHW_TRAY;
11975 desc.uCount = 1;
11976 break;
11977 case RGFW_flashUntilFocused:
11978 desc.dwFlags = (FLASHW_TRAY | FLASHW_TIMERNOFG);
11979 break;
11980 default: break;
11981 }
11982
11983 FlashWindowEx(&desc);
11984}
11985
11986#define RGFW_FREE_LIBRARY(x) if (x != NULL) FreeLibrary(x); x = NULL;
11987void RGFW_deinitPlatform(void) {
11988 #ifndef RGFW_NO_DPI
11989 RGFW_FREE_LIBRARY(RGFW_Shcore_dll);
11990 #endif
11991
11992 #ifndef RGFW_NO_WINMM
11993 timeEndPeriod(1);
11994 #ifndef RGFW_NO_LOAD_WINMM
11995 RGFW_FREE_LIBRARY(RGFW_winmm_dll);
11996 #endif
11997 #endif
11998
11999 RGFW_FREE_LIBRARY(RGFW_wgl_dll);
12000
12001 RGFW_freeMouse(_RGFW->hiddenMouse);
12002}
12003
12004
12005void RGFW_window_closePlatform(RGFW_window* win) {
12006 RemovePropW(win->src.window, L"RGFW");
12007 ReleaseDC(win->src.window, win->src.hdc); /*!< delete device context */
12008 DestroyWindow(win->src.window); /*!< delete window */
12009
12010 if (win->src.hIconSmall) DestroyIcon(win->src.hIconSmall);
12011 if (win->src.hIconBig) DestroyIcon(win->src.hIconBig);
12012}
12013
12014void RGFW_window_move(RGFW_window* win, i32 x, i32 y) {
12015 RGFW_ASSERT(win != NULL);
12016
12017 win->x = x;
12018 win->y = y;
12019 SetWindowPos(win->src.window, HWND_TOP, win->x, win->y, 0, 0, SWP_NOSIZE);
12020}
12021
12022void RGFW_window_resize(RGFW_window* win, i32 w, i32 h) {
12023 RGFW_ASSERT(win != NULL);
12024
12025 win->w = w;
12026 win->h = h;
12027
12028 RECT rect = { 0, 0, w, h};
12029 DWORD style = RGFW_winapi_window_getStyle(win, win->internal.flags);
12030 DWORD exStyle = RGFW_winapi_window_getExStyle(win, win->internal.flags);
12031 AdjustWindowRectEx(&rect, style, FALSE, exStyle);
12032
12033 SetWindowPos(win->src.window, HWND_TOP, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER);
12034}
12035
12036void RGFW_window_setName(RGFW_window* win, const char* name) {
12037 RGFW_ASSERT(win != NULL);
12038 if (name == NULL) name = "\0";
12039
12040 wchar_t wide_name[256];
12041 MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_name, 256);
12042 SetWindowTextW(win->src.window, wide_name);
12043}
12044
12045#ifndef RGFW_NO_PASSTHROUGH
12046void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) {
12047 RGFW_ASSERT(win != NULL);
12048 COLORREF key = 0;
12049 BYTE alpha = 0;
12050 DWORD flags = 0;
12051 i32 exStyle = GetWindowLongW(win->src.window, GWL_EXSTYLE);
12052
12053 if (exStyle & WS_EX_LAYERED)
12054 GetLayeredWindowAttributes(win->src.window, &key, &alpha, &flags);
12055
12056 if (passthrough)
12057 exStyle |= (WS_EX_TRANSPARENT | WS_EX_LAYERED);
12058 else {
12059 exStyle &= ~WS_EX_TRANSPARENT;
12060 if (exStyle & WS_EX_LAYERED && !(flags & LWA_ALPHA))
12061 exStyle &= ~WS_EX_LAYERED;
12062 }
12063
12064 SetWindowLongW(win->src.window, GWL_EXSTYLE, exStyle);
12065
12066 if (passthrough)
12067 SetLayeredWindowAttributes(win->src.window, key, alpha, flags);
12068}
12069#endif
12070
12071RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_icon type) {
12072 RGFW_ASSERT(win != NULL);
12073 #ifndef RGFW_WIN95
12074 if (win->src.hIconSmall && (type & RGFW_iconWindow)) DestroyIcon(win->src.hIconSmall);
12075 if (win->src.hIconBig && (type & RGFW_iconTaskbar)) DestroyIcon(win->src.hIconBig);
12076
12077 if (data == NULL) {
12078 HICON defaultIcon = LoadIcon(NULL, IDI_APPLICATION);
12079 if (type & RGFW_iconWindow)
12080 SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)defaultIcon);
12081 if (type & RGFW_iconTaskbar)
12082 SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)defaultIcon);
12083 return RGFW_TRUE;
12084 }
12085
12086 if (type & RGFW_iconWindow) {
12087 win->src.hIconSmall = RGFW_loadHandleImage(data, w, h, format, TRUE);
12088 SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)win->src.hIconSmall);
12089 }
12090 if (type & RGFW_iconTaskbar) {
12091 win->src.hIconBig = RGFW_loadHandleImage(data, w, h, format, TRUE);
12092 SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)win->src.hIconBig);
12093 }
12094 return RGFW_TRUE;
12095 #else
12096 RGFW_UNUSED(img);
12097 RGFW_UNUSED(type);
12098 return RGFW_FALSE;
12099 #endif
12100}
12101
12102RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) {
12103 /* Open the clipboard */
12104 if (OpenClipboard(NULL) == 0)
12105 return -1;
12106
12107 /* Get the clipboard data as a Unicode string */
12108 HANDLE hData = GetClipboardData(CF_UNICODETEXT);
12109 if (hData == NULL) {
12110 CloseClipboard();
12111 return -1;
12112 }
12113
12114 wchar_t* wstr = (wchar_t*) GlobalLock(hData);
12115
12116 RGFW_ssize_t textLen = 0;
12117
12118 {
12119 setlocale(LC_ALL, "en_US.UTF-8");
12120
12121 textLen = (RGFW_ssize_t)wcstombs(NULL, wstr, 0) + 1;
12122 if (str != NULL && (RGFW_ssize_t)strCapacity <= textLen - 1)
12123 textLen = 0;
12124
12125 if (str != NULL && textLen) {
12126 if (textLen > 1)
12127 wcstombs(str, wstr, (size_t)(textLen));
12128
12129 str[textLen - 1] = '\0';
12130 }
12131 }
12132
12133 /* Release the clipboard data */
12134 GlobalUnlock(hData);
12135 CloseClipboard();
12136
12137 return textLen;
12138}
12139
12140void RGFW_writeClipboard(const char* text, u32 textLen) {
12141 HANDLE object;
12142 WCHAR* buffer;
12143
12144 object = GlobalAlloc(GMEM_MOVEABLE, (1 + textLen) * sizeof(WCHAR));
12145 if (!object)
12146 return;
12147
12148 buffer = (WCHAR*) GlobalLock(object);
12149 if (!buffer) {
12150 GlobalFree(object);
12151 return;
12152 }
12153
12154 MultiByteToWideChar(CP_UTF8, 0, text, -1, buffer, (i32)textLen);
12155 GlobalUnlock(object);
12156
12157 if (!OpenClipboard(_RGFW->root->src.window)) {
12158 GlobalFree(object);
12159 return;
12160 }
12161
12162 EmptyClipboard();
12163 SetClipboardData(CF_UNICODETEXT, object);
12164 CloseClipboard();
12165}
12166
12167void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y) {
12168 RGFW_ASSERT(win != NULL);
12169 win->internal.lastMouseX = x - win->x;
12170 win->internal.lastMouseY = y - win->y;
12171 SetCursorPos(x, y);
12172}
12173
12174#ifdef RGFW_OPENGL
12175RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char * extension, size_t len) {
12176 const char* extensions = NULL;
12177
12178 RGFW_proc proc = RGFW_getProcAddress_OpenGL("wglGetExtensionsStringARB");
12179 RGFW_proc proc2 = RGFW_getProcAddress_OpenGL("wglGetExtensionsStringEXT");
12180
12181 if (proc)
12182 extensions = ((const char* (*)(HDC))proc)(wglGetCurrentDC());
12183 else if (proc2)
12184 extensions = ((const char*(*)(void))proc2)();
12185 return extensions != NULL && RGFW_extensionSupportedStr(extensions, extension, len);
12186}
12187
12188RGFW_proc RGFW_getProcAddress_OpenGL(const char* procname) {
12189 RGFW_proc proc = (RGFW_proc)wglGetProcAddress(procname);
12190 if (proc)
12191 return proc;
12192
12193 return (RGFW_proc) GetProcAddress(RGFW_wgl_dll, procname);
12194}
12195
12196void RGFW_win32_loadOpenGLFuncs(HWND dummyWin) {
12197 if (wglSwapIntervalEXT != NULL && wglChoosePixelFormatARB != NULL && wglChoosePixelFormatARB != NULL)
12198 return;
12199
12200 HDC dummy_dc = GetDC(dummyWin);
12201 u32 pfd_flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
12202
12203 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};
12204
12205 int dummy_pixel_format = ChoosePixelFormat(dummy_dc, &pfd);
12206 SetPixelFormat(dummy_dc, dummy_pixel_format, &pfd);
12207
12208 HGLRC dummy_context = wglCreateContext(dummy_dc);
12209
12210 HGLRC cur = wglGetCurrentContext();
12211 wglMakeCurrent(dummy_dc, dummy_context);
12212
12213 wglCreateContextAttribsARB = ((PFNWGLCREATECONTEXTATTRIBSARBPROC(WINAPI *)(const char*)) wglGetProcAddress)("wglCreateContextAttribsARB");
12214 wglChoosePixelFormatARB = ((PFNWGLCHOOSEPIXELFORMATARBPROC(WINAPI *)(const char*)) wglGetProcAddress)("wglChoosePixelFormatARB");
12215
12216 wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)(RGFW_proc)wglGetProcAddress("wglSwapIntervalEXT");
12217 if (wglSwapIntervalEXT == NULL) {
12218 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load swap interval function");
12219 }
12220
12221 wglMakeCurrent(dummy_dc, cur);
12222 wglDeleteContext(dummy_context);
12223 ReleaseDC(dummyWin, dummy_dc);
12224}
12225
12226#define WGL_ACCELERATION_ARB 0x2003
12227#define WGL_FULL_ACCELERATION_ARB 0x2027
12228#define WGL_DRAW_TO_WINDOW_ARB 0x2001
12229#define WGL_PIXEL_TYPE_ARB 0x2013
12230#define WGL_TYPE_RGBA_ARB 0x202b
12231#define WGL_SUPPORT_OPENGL_ARB 0x2010
12232#define WGL_COLOR_BITS_ARB 0x2014
12233#define WGL_DOUBLE_BUFFER_ARB 0x2011
12234#define WGL_ALPHA_BITS_ARB 0x201b
12235#define WGL_DEPTH_BITS_ARB 0x2022
12236#define WGL_STENCIL_BITS_ARB 0x2023
12237#define WGL_STEREO_ARB 0x2012
12238#define WGL_AUX_BUFFERS_ARB 0x2024
12239#define WGL_RED_BITS_ARB 0x2015
12240#define WGL_GREEN_BITS_ARB 0x2017
12241#define WGL_BLUE_BITS_ARB 0x2019
12242#define WGL_ACCUM_RED_BITS_ARB 0x201e
12243#define WGL_ACCUM_GREEN_BITS_ARB 0x201f
12244#define WGL_ACCUM_BLUE_BITS_ARB 0x2020
12245#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021
12246#define WGL_COLORSPACE_SRGB_EXT 0x3089
12247#define WGL_CONTEXT_OPENGL_NO_ERROR_ARB 0x31b3
12248#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
12249#define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0x0000
12250#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
12251#define WGL_CONTEXT_FLAGS_ARB 0x2094
12252#define WGL_ACCESS_READ_WRITE_NV 0x00000001
12253#define WGL_COVERAGE_SAMPLES_NV 0x2042
12254#define WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004
12255#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
12256#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
12257#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
12258#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
12259#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
12260#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
12261#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9
12262#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
12263#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001
12264#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
12265
12266RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints) {
12267 const char flushControl[] = "WGL_ARB_context_flush_control";
12268 const char noError[] = "WGL_ARB_create_context_no_error";
12269 const char robustness[] = "WGL_ARB_create_context_robustness";
12270
12271 win->src.ctx.native = ctx;
12272 win->src.gfxType = RGFW_gfxNativeOpenGL;
12273
12274 PIXELFORMATDESCRIPTOR pfd;
12275 pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
12276 pfd.nVersion = 1;
12277 pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
12278 pfd.iPixelType = PFD_TYPE_RGBA;
12279 pfd.iLayerType = PFD_MAIN_PLANE;
12280 pfd.cColorBits = 32;
12281 pfd.cAlphaBits = 8;
12282 pfd.cDepthBits = 24;
12283 pfd.cStencilBits = (BYTE)hints->stencil;
12284 pfd.cAuxBuffers = (BYTE)hints->auxBuffers;
12285 if (hints->stereo) pfd.dwFlags |= PFD_STEREO;
12286
12287 /* try to create the pixel format we want for OpenGL and then try to create an OpenGL context for the specified version */
12288 if (hints->renderer == RGFW_glSoftware)
12289 pfd.dwFlags |= PFD_GENERIC_FORMAT | PFD_GENERIC_ACCELERATED;
12290
12291 /* get pixel format, default to a basic pixel format */
12292 int pixel_format = ChoosePixelFormat(win->src.hdc, &pfd);
12293 if (wglChoosePixelFormatARB != NULL) {
12294 i32 pixel_format_attribs[50];
12295 RGFW_attribStack stack;
12296 RGFW_attribStack_init(&stack, pixel_format_attribs, 50);
12297
12298 RGFW_attribStack_pushAttribs(&stack, WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB);
12299 RGFW_attribStack_pushAttribs(&stack, WGL_DRAW_TO_WINDOW_ARB, 1);
12300 RGFW_attribStack_pushAttribs(&stack, WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB);
12301 RGFW_attribStack_pushAttribs(&stack, WGL_SUPPORT_OPENGL_ARB, 1);
12302 RGFW_attribStack_pushAttribs(&stack, WGL_COLOR_BITS_ARB, 32);
12303 RGFW_attribStack_pushAttribs(&stack, WGL_DOUBLE_BUFFER_ARB, 1);
12304 RGFW_attribStack_pushAttribs(&stack, WGL_ALPHA_BITS_ARB, hints->alpha);
12305 RGFW_attribStack_pushAttribs(&stack, WGL_DEPTH_BITS_ARB, hints->depth);
12306 RGFW_attribStack_pushAttribs(&stack, WGL_STENCIL_BITS_ARB, hints->stencil);
12307 RGFW_attribStack_pushAttribs(&stack, WGL_STEREO_ARB, hints->stereo);
12308 RGFW_attribStack_pushAttribs(&stack, WGL_AUX_BUFFERS_ARB, hints->auxBuffers);
12309 RGFW_attribStack_pushAttribs(&stack, WGL_RED_BITS_ARB, hints->red);
12310 RGFW_attribStack_pushAttribs(&stack, WGL_GREEN_BITS_ARB, hints->blue);
12311 RGFW_attribStack_pushAttribs(&stack, WGL_BLUE_BITS_ARB, hints->green);
12312 RGFW_attribStack_pushAttribs(&stack, WGL_ACCUM_RED_BITS_ARB, hints->accumRed);
12313 RGFW_attribStack_pushAttribs(&stack, WGL_ACCUM_GREEN_BITS_ARB, hints->accumGreen);
12314 RGFW_attribStack_pushAttribs(&stack, WGL_ACCUM_BLUE_BITS_ARB, hints->accumBlue);
12315 RGFW_attribStack_pushAttribs(&stack, WGL_ACCUM_ALPHA_BITS_ARB, hints->accumAlpha);
12316
12317 if(hints->sRGB) {
12318 if (hints->profile != RGFW_glES)
12319 RGFW_attribStack_pushAttribs(&stack, WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, 1);
12320 else
12321 RGFW_attribStack_pushAttribs(&stack, WGL_COLORSPACE_SRGB_EXT, hints->sRGB);
12322 }
12323
12324 RGFW_attribStack_pushAttribs(&stack, WGL_COVERAGE_SAMPLES_NV, hints->samples);
12325
12326 RGFW_attribStack_pushAttribs(&stack, 0, 0);
12327
12328 int new_pixel_format;
12329 UINT num_formats;
12330 wglChoosePixelFormatARB(win->src.hdc, pixel_format_attribs, 0, 1, &new_pixel_format, &num_formats);
12331 if (!num_formats)
12332 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to create a pixel format for WGL");
12333 else pixel_format = new_pixel_format;
12334 }
12335
12336 PIXELFORMATDESCRIPTOR suggested;
12337 if (!DescribePixelFormat(win->src.hdc, pixel_format, sizeof(suggested), &suggested) ||
12338 !SetPixelFormat(win->src.hdc, pixel_format, &pfd))
12339 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to set the WGL pixel format");
12340
12341 if (wglCreateContextAttribsARB != NULL) {
12342 /* create OpenGL/WGL context for the specified version */
12343 i32 attribs[40];
12344 RGFW_attribStack stack;
12345 RGFW_attribStack_init(&stack, attribs, 50);
12346
12347
12348 i32 mask = 0;
12349 switch (hints->profile) {
12350 case RGFW_glES: mask |= WGL_CONTEXT_ES_PROFILE_BIT_EXT; break;
12351 case RGFW_glCompatibility: mask |= WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; break;
12352 case RGFW_glForwardCompatibility: mask |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; break;
12353 case RGFW_glCore: mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB; break;
12354 default: mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB; break;
12355 }
12356
12357 RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_PROFILE_MASK_ARB, mask);
12358
12359 if (hints->minor || hints->major) {
12360 RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_MAJOR_VERSION_ARB, hints->major);
12361 RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_MINOR_VERSION_ARB, hints->minor);
12362 }
12363
12364 if (RGFW_extensionSupportedPlatform_OpenGL(noError, sizeof(noError)))
12365 RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_OPENGL_NO_ERROR_ARB, hints->noError);
12366
12367 if (RGFW_extensionSupportedPlatform_OpenGL(flushControl, sizeof(flushControl))) {
12368 if (hints->releaseBehavior == RGFW_glReleaseFlush) {
12369 RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); /* WGL_CONTEXT_RELEASE_BEHAVIOR_ARB */
12370 } else if (hints->releaseBehavior == RGFW_glReleaseNone) {
12371 RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB);
12372 }
12373 }
12374
12375 i32 flags = 0;
12376 if (hints->debug) flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
12377 if (hints->robustness && RGFW_extensionSupportedPlatform_OpenGL(robustness, sizeof(robustness))) flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB;
12378 if (flags) {
12379 RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_FLAGS_ARB, flags);
12380 }
12381
12382
12383 RGFW_attribStack_pushAttribs(&stack, 0, 0);
12384
12385 win->src.ctx.native->ctx = (HGLRC)wglCreateContextAttribsARB(win->src.hdc, NULL, attribs);
12386 }
12387
12388 if (wglCreateContextAttribsARB == NULL || win->src.ctx.native->ctx == NULL) { /* fall back to a default context (probably OpenGL 2 or something) */
12389 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to create an accelerated OpenGL Context.");
12390 win->src.ctx.native->ctx = wglCreateContext(win->src.hdc);
12391 }
12392
12393 ReleaseDC(win->src.window, win->src.hdc);
12394 win->src.hdc = GetDC(win->src.window);
12395
12396 if (hints->share) {
12397 wglShareLists((HGLRC)RGFW_getCurrentContext_OpenGL(), hints->share->ctx);
12398 }
12399
12400 wglMakeCurrent(win->src.hdc, win->src.ctx.native->ctx);
12401 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized.");
12402 return RGFW_TRUE;
12403}
12404
12405void RGFW_window_deleteContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx) {
12406 wglDeleteContext((HGLRC) ctx->ctx); /*!< delete OpenGL context */
12407 win->src.ctx.native->ctx = NULL;
12408 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context freed.");
12409}
12410
12411void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win) {
12412 if (win == NULL)
12413 wglMakeCurrent(NULL, NULL);
12414 else
12415 wglMakeCurrent(win->src.hdc, (HGLRC) win->src.ctx.native->ctx);
12416}
12417void* RGFW_getCurrentContext_OpenGL(void) {
12418 return wglGetCurrentContext();
12419}
12420void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) {
12421 RGFW_ASSERT(win->src.ctx.native);
12422 SwapBuffers(win->src.hdc);
12423}
12424
12425void RGFW_window_swapInterval_OpenGL(RGFW_window* win, i32 swapInterval) {
12426 RGFW_ASSERT(win != NULL);
12427 if (wglSwapIntervalEXT == NULL || wglSwapIntervalEXT(swapInterval) == FALSE)
12428 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to set swap interval");
12429}
12430#endif
12431
12432RGFW_bool RGFW_createUTF8FromWideStringWin32(const WCHAR* source, char* output, size_t max) {
12433 i32 size = 0;
12434 if (source == NULL) {
12435 return RGFW_FALSE;
12436 }
12437 size = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL);
12438 if (!size) {
12439 return RGFW_FALSE;
12440 }
12441
12442 if (size > (i32)max)
12443 size = (i32)max;
12444
12445 if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, output, size, NULL, NULL)) {
12446 return RGFW_FALSE;
12447 }
12448
12449 output[size] = 0;
12450 return RGFW_TRUE;
12451}
12452
12453#ifdef RGFW_WEBGPU
12454WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance instance) {
12455 WGPUSurfaceDescriptor surfaceDesc = {0};
12456 WGPUSurfaceSourceWindowsHWND fromHwnd = {0};
12457 fromHwnd.chain.sType = WGPUSType_SurfaceSourceWindowsHWND;
12458 fromHwnd.hwnd = window->src.window;
12459
12460 fromHwnd.hinstance = GetModuleHandle(NULL);
12461
12462 surfaceDesc.nextInChain = (WGPUChainedStruct*)&fromHwnd.chain;
12463 return wgpuInstanceCreateSurface(instance, &surfaceDesc);
12464}
12465#endif
12466
12467#endif /* RGFW_WINDOWS */
12468
12469/*
12470 End of Windows defines
12471*/
12472
12473
12474
12475/*
12476
12477 Start of MacOS defines
12478
12479
12480*/
12481
12482#if defined(RGFW_MACOS)
12483/*
12484 based on silicon.h
12485 start of cocoa wrapper
12486*/
12487
12488#include <CoreGraphics/CoreGraphics.h>
12489#include <ApplicationServices/ApplicationServices.h>
12490#include <objc/runtime.h>
12491#include <objc/message.h>
12492#include <mach/mach_time.h>
12493
12494#include <Carbon/Carbon.h>
12495
12496typedef TISInputSourceRef (*PFN_TISCopyCurrentKeyboardLayoutInputSource)(void);
12497PFN_TISCopyCurrentKeyboardLayoutInputSource TISCopyCurrentKeyboardLayoutInputSourceSrc;
12498#define TISCopyCurrentKeyboardLayoutInputSource TISCopyCurrentKeyboardLayoutInputSourceSrc
12499
12500typedef CFDataRef (*PFN_TISGetInputSourceProperty)(TISInputSourceRef, CFStringRef);
12501PFN_TISGetInputSourceProperty TISGetInputSourcePropertySrc;
12502#define TISGetInputSourceProperty TISGetInputSourcePropertySrc
12503
12504typedef u8 (*PFN_LMGetKbdType)(void);
12505PFN_LMGetKbdType LMGetKbdTypeSrc;
12506#define LMGetKbdType LMGetKbdTypeSrc
12507
12508CFStringRef kTISPropertyUnicodeKeyLayoutDataSrc;
12509
12510#ifndef __OBJC__
12511typedef CGRect NSRect;
12512typedef CGPoint NSPoint;
12513typedef CGSize NSSize;
12514
12515typedef const char* NSPasteboardType;
12516typedef unsigned long NSUInteger;
12517typedef long NSInteger;
12518typedef NSInteger NSModalResponse;
12519
12520typedef enum NSRequestUserAttentionType {
12521 NSCriticalRequest = 0,
12522 NSInformationalRequest = 10
12523} NSRequestUserAttentionType;
12524
12525typedef enum NSApplicationActivationPolicy {
12526 NSApplicationActivationPolicyRegular,
12527 NSApplicationActivationPolicyAccessory,
12528 NSApplicationActivationPolicyProhibited
12529} NSApplicationActivationPolicy;
12530
12531typedef RGFW_ENUM(u32, NSBackingStoreType) {
12532 NSBackingStoreRetained = 0,
12533 NSBackingStoreNonretained = 1,
12534 NSBackingStoreBuffered = 2
12535};
12536
12537typedef RGFW_ENUM(u32, NSWindowStyleMask) {
12538 NSWindowStyleMaskBorderless = 0,
12539 NSWindowStyleMaskTitled = 1 << 0,
12540 NSWindowStyleMaskClosable = 1 << 1,
12541 NSWindowStyleMaskMiniaturizable = 1 << 2,
12542 NSWindowStyleMaskResizable = 1 << 3,
12543 NSWindowStyleMaskTexturedBackground = 1 << 8, /* deprecated */
12544 NSWindowStyleMaskUnifiedTitleAndToolbar = 1 << 12,
12545 NSWindowStyleMaskFullScreen = 1 << 14,
12546 NSWindowStyleMaskFullSizeContentView = 1 << 15,
12547 NSWindowStyleMaskUtilityWindow = 1 << 4,
12548 NSWindowStyleMaskDocModalWindow = 1 << 6,
12549 NSWindowStyleMaskNonactivatingpanel = 1 << 7,
12550 NSWindowStyleMaskHUDWindow = 1 << 13
12551};
12552
12553#define NSPasteboardTypeString "public.utf8-plain-text"
12554
12555typedef RGFW_ENUM(i32, NSDragOperation) {
12556 NSDragOperationNone = 0,
12557 NSDragOperationCopy = 1,
12558 NSDragOperationLink = 2,
12559 NSDragOperationGeneric = 4,
12560 NSDragOperationPrivate = 8,
12561 NSDragOperationMove = 16,
12562 NSDragOperationDelete = 32,
12563 NSDragOperationEvery = (int)ULONG_MAX
12564};
12565
12566typedef RGFW_ENUM(NSInteger, NSOpenGLContextParameter) {
12567 NSOpenGLContextParameterSwapInterval = 222, /* 1 param. 0 -> Don't sync, 1 -> Sync to vertical retrace */
12568 NSOpenGLContextParametectxaceOrder = 235, /* 1 param. 1 -> Above Window (default), -1 -> Below Window */
12569 NSOpenGLContextParametectxaceOpacity = 236, /* 1 param. 1-> Surface is opaque (default), 0 -> non-opaque */
12570 NSOpenGLContextParametectxaceBackingSize = 304, /* 2 params. Width/height of surface backing size */
12571 NSOpenGLContextParameterReclaimResources = 308, /* 0 params. */
12572 NSOpenGLContextParameterCurrentRendererID = 309, /* 1 param. Retrieves the current renderer ID */
12573 NSOpenGLContextParameterGPUVertexProcessing = 310, /* 1 param. Currently processing vertices with GPU (get) */
12574 NSOpenGLContextParameterGPUFragmentProcessing = 311, /* 1 param. Currently processing fragments with GPU (get) */
12575 NSOpenGLContextParameterHasDrawable = 314, /* 1 param. Boolean returned if drawable is attached */
12576 NSOpenGLContextParameterMPSwapsInFlight = 315, /* 1 param. Max number of swaps queued by the MP GL engine */
12577
12578 NSOpenGLContextParameterSwapRectangle API_DEPRECATED("", macos(10.0, 10.14)) = 200, /* 4 params. Set or get the swap rectangle {x, y, w, h} */
12579 NSOpenGLContextParameterSwapRectangleEnable API_DEPRECATED("", macos(10.0, 10.14)) = 201, /* Enable or disable the swap rectangle */
12580 NSOpenGLContextParameterRasterizationEnable API_DEPRECATED("", macos(10.0, 10.14)) = 221, /* Enable or disable all rasterization */
12581 NSOpenGLContextParameterStateValidation API_DEPRECATED("", macos(10.0, 10.14)) = 301, /* Validate state for multi-screen functionality */
12582 NSOpenGLContextParametectxaceSurfaceVolatile API_DEPRECATED("", macos(10.0, 10.14)) = 306, /* 1 param. Surface volatile state */
12583};
12584
12585typedef RGFW_ENUM(NSInteger, NSWindowButton) {
12586 NSWindowCloseButton = 0,
12587 NSWindowMiniaturizeButton = 1,
12588 NSWindowZoomButton = 2,
12589 NSWindowToolbarButton = 3,
12590 NSWindowDocumentIconButton = 4,
12591 NSWindowDocumentVersionsButton = 6,
12592 NSWindowFullScreenButton = 7,
12593};
12594
12595#define NSPasteboardTypeURL "public.url"
12596#define NSPasteboardTypeFileURL "public.file-url"
12597#define NSTrackingMouseEnteredAndExited 0x01
12598#define NSTrackingMouseMoved 0x02
12599#define NSTrackingCursorUpdate 0x04
12600#define NSTrackingActiveWhenFirstResponder 0x10
12601#define NSTrackingActiveInKeyWindow 0x20
12602#define NSTrackingActiveInActiveApp 0x40
12603#define NSTrackingActiveAlways 0x80
12604#define NSTrackingAssumeInside 0x100
12605#define NSTrackingInVisibleRect 0x200
12606#define NSTrackingEnabledDuringMouseDrag 0x400
12607enum {
12608 NSOpenGLPFAAllRenderers = 1, /* choose from all available renderers */
12609 NSOpenGLPFATripleBuffer = 3, /* choose a triple buffered pixel format */
12610 NSOpenGLPFADoubleBuffer = 5, /* choose a double buffered pixel format */
12611 NSOpenGLPFAAuxBuffers = 7, /* number of aux buffers */
12612 NSOpenGLPFAColorSize = 8, /* number of color buffer bits */
12613 NSOpenGLPFAAlphaSize = 11, /* number of alpha component bits */
12614 NSOpenGLPFADepthSize = 12, /* number of depth buffer bits */
12615 NSOpenGLPFAStencilSize = 13, /* number of stencil buffer bits */
12616 NSOpenGLPFAAccumSize = 14, /* number of accum buffer bits */
12617 NSOpenGLPFAMinimumPolicy = 51, /* never choose smaller buffers than requested */
12618 NSOpenGLPFAMaximumPolicy = 52, /* choose largest buffers of type requested */
12619 NSOpenGLPFASampleBuffers = 55, /* number of multi sample buffers */
12620 NSOpenGLPFASamples = 56, /* number of samples per multi sample buffer */
12621 NSOpenGLPFAAuxDepthStencil = 57, /* each aux buffer has its own depth stencil */
12622 NSOpenGLPFAColorFloat = 58, /* color buffers store floating point pixels */
12623 NSOpenGLPFAMultisample = 59, /* choose multisampling */
12624 NSOpenGLPFASupersample = 60, /* choose supersampling */
12625 NSOpenGLPFASampleAlpha = 61, /* request alpha filtering */
12626 NSOpenGLPFARendererID = 70, /* request renderer by ID */
12627 NSOpenGLPFANoRecovery = 72, /* disable all failure recovery systems */
12628 NSOpenGLPFAAccelerated = 73, /* choose a hardware accelerated renderer */
12629 NSOpenGLPFAClosestPolicy = 74, /* choose the closest color buffer to request */
12630 NSOpenGLPFABackingStore = 76, /* back buffer contents are valid after swap */
12631 NSOpenGLPFAScreenMask = 84, /* bit mask of supported physical screens */
12632 NSOpenGLPFAAllowOfflineRenderers = 96, /* allow use of offline renderers */
12633 NSOpenGLPFAAcceleratedCompute = 97, /* choose a hardware accelerated compute device */
12634 NSOpenGLPFAOpenGLProfile = 99, /* specify an OpenGL Profile to use */
12635 NSOpenGLProfileVersionLegacy = 0x1000, /* The requested profile is a legacy (pre-OpenGL 3.0) profile. */
12636 NSOpenGLProfileVersion3_2Core = 0x3200, /* The 3.2 Profile of OpenGL */
12637 NSOpenGLProfileVersion4_1Core = 0x3200, /* The 4.1 profile of OpenGL */
12638 NSOpenGLPFAVirtualScreenCount = 128, /* number of virtual screens in this format */
12639 NSOpenGLPFAStereo = 6,
12640 NSOpenGLPFAOffScreen = 53,
12641 NSOpenGLPFAFullScreen = 54,
12642 NSOpenGLPFASingleRenderer = 71,
12643 NSOpenGLPFARobust = 75,
12644 NSOpenGLPFAMPSafe = 78,
12645 NSOpenGLPFAWindow = 80,
12646 NSOpenGLPFAMultiScreen = 81,
12647 NSOpenGLPFACompliant = 83,
12648 NSOpenGLPFAPixelBuffer = 90,
12649 NSOpenGLPFARemotePixelBuffer = 91,
12650};
12651
12652typedef RGFW_ENUM(u32, NSEventType) { /* various types of events */
12653 NSEventTypeApplicationDefined = 15,
12654};
12655typedef unsigned long long NSEventMask;
12656
12657typedef enum NSEventModifierFlags {
12658 NSEventModifierFlagCapsLock = 1 << 16,
12659 NSEventModifierFlagShift = 1 << 17,
12660 NSEventModifierFlagControl = 1 << 18,
12661 NSEventModifierFlagOption = 1 << 19,
12662 NSEventModifierFlagCommand = 1 << 20,
12663 NSEventModifierFlagNumericPad = 1 << 21
12664} NSEventModifierFlags;
12665
12666typedef RGFW_ENUM(NSUInteger, NSBitmapFormat) {
12667 NSBitmapFormatAlphaFirst = 1 << 0, /* 0 means is alpha last (RGBA, CMYKA, etc.) */
12668 NSBitmapFormatAlphaNonpremultiplied = 1 << 1, /* 0 means is premultiplied */
12669 NSBitmapFormatFloatingpointSamples = 1 << 2, /* 0 is integer */
12670
12671 NSBitmapFormatSixteenBitLittleEndian = (1 << 8),
12672 NSBitmapFormatThirtyTwoBitLittleEndian = (1 << 9),
12673 NSBitmapFormatSixteenBitBigEndian = (1 << 10),
12674 NSBitmapFormatThirtyTwoBitBigEndian = (1 << 11)
12675};
12676
12677#else
12678#import <AppKit/AppKit.h>
12679#include <Foundation/Foundation.h>
12680#endif /* notdef __OBJC__ */
12681
12682#ifdef __arm64__
12683 /* ARM just uses objc_msgSend */
12684#define abi_objc_msgSend_stret objc_msgSend
12685#define abi_objc_msgSend_fpret objc_msgSend
12686#else /* __i386__ */
12687 /* x86 just uses abi_objc_msgSend_fpret and (NSColor *)objc_msgSend_id respectively */
12688#define abi_objc_msgSend_stret objc_msgSend_stret
12689#define abi_objc_msgSend_fpret objc_msgSend_fpret
12690#endif
12691
12692#define NSAlloc(nsclass) objc_msgSend_id((id)nsclass, sel_registerName("alloc"))
12693#define objc_msgSend_bool(x, y) ((BOOL (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
12694#define objc_msgSend_void(x, y) ((void (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
12695#define objc_msgSend_void_id(x, y, z) ((void (*)(id, SEL, id))objc_msgSend) ((id)x, (SEL)y, (id)z)
12696#define objc_msgSend_uint(x, y) ((NSUInteger (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
12697#define objc_msgSend_void_bool(x, y, z) ((void (*)(id, SEL, BOOL))objc_msgSend) ((id)(x), (SEL)y, (BOOL)z)
12698#define objc_msgSend_bool_void(x, y) ((BOOL (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
12699#define objc_msgSend_void_SEL(x, y, z) ((void (*)(id, SEL, SEL))objc_msgSend) ((id)(x), (SEL)y, (SEL)z)
12700#define objc_msgSend_id(x, y) ((id (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
12701#define objc_msgSend_id_id(x, y, z) ((id (*)(id, SEL, id))objc_msgSend) ((id)(x), (SEL)y, (id)z)
12702#define objc_msgSend_id_bool(x, y, z) ((BOOL (*)(id, SEL, id))objc_msgSend) ((id)(x), (SEL)y, (id)z)
12703#define objc_msgSend_int(x, y, z) ((id (*)(id, SEL, int))objc_msgSend) ((id)(x), (SEL)y, (int)z)
12704#define objc_msgSend_arr(x, y, z) ((id (*)(id, SEL, int))objc_msgSend) ((id)(x), (SEL)y, (int)z)
12705#define objc_msgSend_ptr(x, y, z) ((id (*)(id, SEL, void*))objc_msgSend) ((id)(x), (SEL)y, (void*)z)
12706#define objc_msgSend_class(x, y) ((id (*)(Class, SEL))objc_msgSend) ((Class)(x), (SEL)y)
12707#define objc_msgSend_class_char(x, y, z) ((id (*)(Class, SEL, char*))objc_msgSend) ((Class)(x), (SEL)y, (char*)z)
12708
12709#define NSRelease(obj) objc_msgSend_void((id)obj, sel_registerName("release"))
12710RGFWDEF id NSString_stringWithUTF8String(const char* str);
12711id NSString_stringWithUTF8String(const char* str) {
12712 return ((id(*)(id, SEL, const char*))objc_msgSend) ((id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), str);
12713}
12714
12715RGFWDEF float RGFW_cocoaYTransform(float y);
12716float RGFW_cocoaYTransform(float y) { return (float)(CGDisplayBounds(CGMainDisplayID()).size.height - (double)y - (double)1.0f); }
12717
12718const char* NSString_to_char(id str);
12719const char* NSString_to_char(id str) {
12720 return ((const char* (*)(id, SEL)) objc_msgSend) ((id)(id)str, sel_registerName("UTF8String"));
12721}
12722
12723unsigned char* NSBitmapImageRep_bitmapData(id imageRep);
12724unsigned char* NSBitmapImageRep_bitmapData(id imageRep) {
12725 return ((unsigned char* (*)(id, SEL))objc_msgSend) ((id)imageRep, sel_registerName("bitmapData"));
12726}
12727
12728id 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);
12729id 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) {
12730 SEL func = sel_registerName("initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bitmapFormat:bytesPerRow:bitsPerPixel:");
12731
12732 return (id) ((id(*)(id, SEL, unsigned char**, NSInteger, NSInteger, NSInteger, NSInteger, bool, bool, id, NSBitmapFormat, NSInteger, NSInteger))objc_msgSend)
12733 (NSAlloc((id)objc_getClass("NSBitmapImageRep")), func, planes, width, height, bps, spp, alpha, isPlanar, NSString_stringWithUTF8String(colorSpaceName), bitmapFormat, rowBytes, pixelBits);
12734}
12735
12736id NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha);
12737id NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha) {
12738 Class nsclass = objc_getClass("NSColor");
12739 SEL func = sel_registerName("colorWithSRGBRed:green:blue:alpha:");
12740 return ((id(*)(id, SEL, CGFloat, CGFloat, CGFloat, CGFloat))objc_msgSend)
12741 ((id)nsclass, func, red, green, blue, alpha);
12742}
12743
12744id NSPasteboard_generalPasteboard(void);
12745id NSPasteboard_generalPasteboard(void) {
12746 return (id) objc_msgSend_id((id)objc_getClass("NSPasteboard"), sel_registerName("generalPasteboard"));
12747}
12748
12749id* cstrToNSStringArray(char** strs, size_t len);
12750id* cstrToNSStringArray(char** strs, size_t len) {
12751 static id nstrs[6];
12752 size_t i;
12753 for (i = 0; i < len; i++)
12754 nstrs[i] = NSString_stringWithUTF8String(strs[i]);
12755
12756 return nstrs;
12757}
12758
12759const char* NSPasteboard_stringForType(id pasteboard, NSPasteboardType dataType, size_t* len);
12760const char* NSPasteboard_stringForType(id pasteboard, NSPasteboardType dataType, size_t* len) {
12761 SEL func = sel_registerName("stringForType:");
12762 id nsstr = NSString_stringWithUTF8String((const char*)dataType);
12763 id nsString = ((id(*)(id, SEL, id))objc_msgSend)(pasteboard, func, nsstr);
12764 const char* str = NSString_to_char(nsString);
12765 if (len != NULL)
12766 *len = (size_t)((NSUInteger(*)(id, SEL, int))objc_msgSend)(nsString, sel_registerName("maximumLengthOfBytesUsingEncoding:"), 4);
12767 return str;
12768}
12769
12770id c_array_to_NSArray(void* array, size_t len);
12771id c_array_to_NSArray(void* array, size_t len) {
12772 return ((id (*)(id, SEL, void*, NSUInteger))objc_msgSend) (NSAlloc(objc_getClass("NSArray")), sel_registerName("initWithObjects:count:"), array, len);
12773}
12774
12775
12776void NSregisterForDraggedTypes(id view, NSPasteboardType* newTypes, size_t len);
12777void NSregisterForDraggedTypes(id view, NSPasteboardType* newTypes, size_t len) {
12778 id* ntypes = cstrToNSStringArray((char**)newTypes, len);
12779
12780 id array = c_array_to_NSArray(ntypes, len);
12781 objc_msgSend_void_id(view, sel_registerName("registerForDraggedTypes:"), array);
12782 NSRelease(array);
12783}
12784
12785NSInteger NSPasteBoard_declareTypes(id pasteboard, NSPasteboardType* newTypes, size_t len, void* owner);
12786NSInteger NSPasteBoard_declareTypes(id pasteboard, NSPasteboardType* newTypes, size_t len, void* owner) {
12787 id* ntypes = cstrToNSStringArray((char**)newTypes, len);
12788
12789 SEL func = sel_registerName("declareTypes:owner:");
12790
12791 id array = c_array_to_NSArray(ntypes, len);
12792
12793 NSInteger output = ((NSInteger(*)(id, SEL, id, void*))objc_msgSend)
12794 (pasteboard, func, array, owner);
12795 NSRelease(array);
12796
12797 return output;
12798}
12799
12800#define NSRetain(obj) objc_msgSend_void((id)obj, sel_registerName("retain"))
12801
12802/*
12803 End of cocoa wrapper
12804*/
12805
12806static id RGFW__osxCustomInitWithRGFWWindow(id self, SEL _cmd, RGFW_window* win) {
12807 RGFW_UNUSED(_cmd);
12808 struct objc_super s = { self, class_getSuperclass(object_getClass(self)) };
12809 self = ((id (*)(struct objc_super*, SEL))objc_msgSendSuper)(&s, sel_registerName("init"));
12810
12811 if (self != nil) {
12812 object_setInstanceVariable(self, "RGFW_window", win);
12813 object_setInstanceVariable(self, "trackingArea", nil);
12814
12815 object_setInstanceVariable(
12816 self, "markedText",
12817 ((id (*)(id, SEL))objc_msgSend)(
12818 ((id (*)(Class, SEL))objc_msgSend)(objc_getClass("NSMutableAttributedString"), sel_registerName("alloc")),
12819 sel_registerName("init")
12820 )
12821 );
12822
12823 ((void (*)(id, SEL))objc_msgSend)(self, sel_registerName("updateTrackingAreas"));
12824
12825 ((void (*)(id, SEL, id))objc_msgSend)(
12826 self, sel_registerName("registerForDraggedTypes:"),
12827 ((id (*)(Class, SEL, id))objc_msgSend)(
12828 objc_getClass("NSArray"),
12829 sel_registerName("arrayWithObject:"),
12830 ((id (*)(Class, SEL, const char*))objc_msgSend)(
12831 objc_getClass("NSString"),
12832 sel_registerName("stringWithUTF8String:"),
12833 "public.url"
12834 )
12835 )
12836 );
12837 }
12838
12839 return self;
12840}
12841
12842static u32 RGFW_OnClose(id self) {
12843 RGFW_window* win = NULL;
12844 object_getInstanceVariable(self, (const char*)"RGFW_window", (void**)&win);
12845 if (win == NULL) return true;
12846
12847 RGFW_windowQuitCallback(win);
12848 return false;
12849}
12850
12851/* NOTE(EimaMei): Fixes the constant clicking when the app is running under a terminal. */
12852static bool RGFW__osxAcceptsFirstResponder(void) { return true; }
12853static bool RGFW__osxPerformKeyEquivalent(id event) { RGFW_UNUSED(event); return true; }
12854
12855static NSDragOperation RGFW__osxDraggingEntered(id self, SEL sel, id sender) {
12856 RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel);
12857
12858 return NSDragOperationCopy;
12859}
12860static NSDragOperation RGFW__osxDraggingUpdated(id self, SEL sel, id sender) {
12861 RGFW_UNUSED(sel);
12862
12863 RGFW_window* win = NULL;
12864
12865 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
12866 if (win == NULL)
12867 return 0;
12868 if (!(win->internal.enabledEvents & RGFW_dataDragFlag)) return NSDragOperationCopy;
12869
12870 NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation"));
12871 RGFW_dataDragCallback(win, (i32) p.x, (i32) (win->h - p.y));
12872 return NSDragOperationCopy;
12873}
12874static bool RGFW__osxPrepareForDragOperation(id self) {
12875 RGFW_window* win = NULL;
12876 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
12877 if (win == NULL || (!(win->internal.enabledEvents & RGFW_dataDropFlag)))
12878 return true;
12879
12880 if (!(win->internal.flags & RGFW_windowAllowDND)) {
12881 return false;
12882 }
12883
12884 return true;
12885}
12886
12887void RGFW__osxDraggingEnded(id self, SEL sel, id sender);
12888void RGFW__osxDraggingEnded(id self, SEL sel, id sender) { RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel); return; }
12889
12890static bool RGFW__osxPerformDragOperation(id self, SEL sel, id sender) {
12891 RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel);
12892
12893 RGFW_window* win = NULL;
12894 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
12895 if (win == NULL || (!(win->internal.enabledEvents & RGFW_dataDropFlag)))
12896 return false;
12897
12898 /* id pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard")); */
12899
12900 id pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard"));
12901
12902 /* Get the types of data available on the pasteboard */
12903 id types = objc_msgSend_id(pasteBoard, sel_registerName("types"));
12904
12905 /* Get the string type for file URLs */
12906 id fileURLsType = objc_msgSend_class_char(objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "NSFilenamesPboardType");
12907
12908 /* Check if the pasteboard contains file URLs */
12909 if (objc_msgSend_id_bool(types, sel_registerName("containsObject:"), fileURLsType) == 0) {
12910 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errClipboard, "No files found on the pasteboard.");
12911 return 0;
12912 }
12913
12914 id fileURLs = objc_msgSend_id_id(pasteBoard, sel_registerName("propertyListForType:"), fileURLsType);
12915 int count = ((int (*)(id, SEL))objc_msgSend)(fileURLs, sel_registerName("count"));
12916
12917 if (count == 0)
12918 return 0;
12919
12920 char** files = (char**)(void*)_RGFW->files;
12921
12922 u32 i;
12923 for (i = 0; i < (u32)count; i++) {
12924 id fileURL = objc_msgSend_arr(fileURLs, sel_registerName("objectAtIndex:"), i);
12925 const char *filePath = ((const char* (*)(id, SEL))objc_msgSend)(fileURL, sel_registerName("UTF8String"));
12926 RGFW_STRNCPY(files[i], filePath, RGFW_MAX_PATH - 1);
12927 files[i][RGFW_MAX_PATH - 1] = '\0';
12928 }
12929
12930 RGFW_dataDropCallback(win, files, (size_t)count);
12931
12932 return false;
12933}
12934
12935#ifndef RGFW_NO_IOKIT
12936#include <IOKit/IOKitLib.h>
12937
12938float RGFW_osx_getFallbackRefreshRate(CGDirectDisplayID displayID);
12939float RGFW_osx_getFallbackRefreshRate(CGDirectDisplayID displayID) {
12940 float refreshRate = 0;
12941 io_iterator_t it;
12942 io_service_t service;
12943 CFNumberRef indexRef, clockRef, countRef;
12944 u32 clock, count;
12945
12946#ifdef kIOMainPortDefault
12947 if (IOServiceGetMatchingServices(kIOMainPortDefault, IOServiceMatching("IOFramebuffer"), &it) != 0)
12948#elif defined(kIOMasterPortDefault)
12949 if (IOServiceGetMatchingServices(kIOMainPortDefault, IOServiceMatching("IOFramebuffer"), &it) != 0)
12950#endif
12951 return RGFW_FALSE;
12952
12953 while ((service = IOIteratorNext(it)) != 0) {
12954 u32 index;
12955 indexRef = (CFNumberRef)IORegistryEntryCreateCFProperty(service, CFSTR("IOFramebufferOpenGLIndex"), kCFAllocatorDefault, kNilOptions);
12956 if (indexRef == 0) continue;
12957
12958 if (CFNumberGetValue(indexRef, kCFNumberIntType, &index) && CGOpenGLDisplayMaskToDisplayID(1 << index) == displayID) {
12959 CFRelease(indexRef);
12960 break;
12961 }
12962
12963 CFRelease(indexRef);
12964 }
12965
12966 if (service) {
12967 clockRef = (CFNumberRef)IORegistryEntryCreateCFProperty(service, CFSTR("IOFBCurrentPixelClock"), kCFAllocatorDefault, kNilOptions);
12968 if (clockRef) {
12969 if (CFNumberGetValue(clockRef, kCFNumberIntType, &clock) && clock) {
12970 countRef = (CFNumberRef)IORegistryEntryCreateCFProperty(service, CFSTR("IOFBCurrentPixelCount"), kCFAllocatorDefault, kNilOptions);
12971 if (countRef && CFNumberGetValue(countRef, kCFNumberIntType, &count) && count) {
12972 refreshRate = (float)((double)clock / (double) count);
12973 CFRelease(countRef);
12974 }
12975 }
12976 CFRelease(clockRef);
12977 }
12978 }
12979
12980 IOObjectRelease(it);
12981 return refreshRate;
12982}
12983#endif
12984
12985void RGFW_moveToMacOSResourceDir(void) {
12986 char resourcesPath[256];
12987
12988 CFBundleRef bundle = CFBundleGetMainBundle();
12989 if (!bundle)
12990 return;
12991
12992 CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle);
12993 CFStringRef last = CFURLCopyLastPathComponent(resourcesURL);
12994
12995 if (
12996 CFStringCompare(CFSTR("Resources"), last, 0) != kCFCompareEqualTo ||
12997 CFURLGetFileSystemRepresentation(resourcesURL, true, (u8*) resourcesPath, 255) == 0
12998 ) {
12999 CFRelease(last);
13000 CFRelease(resourcesURL);
13001 return;
13002 }
13003
13004 CFRelease(last);
13005 CFRelease(resourcesURL);
13006
13007 chdir(resourcesPath);
13008}
13009
13010static void RGFW__osxDidChangeScreenParameters(id self, SEL _cmd, id notification) {
13011 RGFW_UNUSED(self); RGFW_UNUSED(_cmd); RGFW_UNUSED(notification);
13012 RGFW_pollMonitors();
13013}
13014
13015static void RGFW__osxWindowDeminiaturize(id self, SEL sel) {
13016 RGFW_UNUSED(sel);
13017 RGFW_window* win = NULL;
13018 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13019 if (win == NULL) return;
13020
13021 RGFW_windowRestoredCallback(win, win->x, win->y, win->w, win->h);
13022
13023}
13024static void RGFW__osxWindowMiniaturize(id self, SEL sel) {
13025 RGFW_UNUSED(sel);
13026 RGFW_window* win = NULL;
13027 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13028 if (win == NULL) return;
13029
13030 RGFW_windowMinimizedCallback(win);
13031
13032}
13033
13034static void RGFW__osxWindowBecameKey(id self, SEL sel) {
13035 RGFW_UNUSED(sel);
13036 RGFW_window* win = NULL;
13037 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13038 if (win == NULL) return;
13039
13040 RGFW_focusCallback(win, RGFW_TRUE);
13041}
13042
13043static void RGFW__osxWindowResignKey(id self, SEL sel) {
13044 RGFW_UNUSED(sel);
13045 RGFW_window* win = NULL;
13046 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13047 if (win == NULL) return;
13048
13049 RGFW_focusCallback(win, RGFW_FALSE);
13050}
13051
13052static void RGFW__osxDidWindowResize(id self, SEL _cmd, id notification) {
13053 RGFW_UNUSED(_cmd); RGFW_UNUSED(notification);
13054 RGFW_window* win = NULL;
13055 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13056 if (win == NULL) return;
13057
13058 NSRect frame;
13059 if (win->src.view) frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame"));
13060 else return;
13061
13062 if (frame.size.width == 0 || frame.size.height == 0) return;
13063 win->w = (i32)frame.size.width;
13064 win->h = (i32)frame.size.height;
13065
13066 RGFW_monitor* mon = RGFW_window_getMonitor(win);
13067 if (mon == NULL) return;
13068
13069 if ((i32)mon->mode.w == win->w && (i32)mon->mode.h - 102 <= win->h) {
13070 RGFW_windowMaximizedCallback(win, 0, 0, win->w, win->h);
13071 } else if (win->internal.flags & RGFW_windowMaximize) {
13072 RGFW_windowRestoredCallback(win, win->x, win->y, win->w, win->h);
13073 }
13074
13075 RGFW_windowResizedCallback(win, win->w, win->h);
13076}
13077
13078static void RGFW__osxWindowMove(id self, SEL sel) {
13079 RGFW_UNUSED(sel);
13080 RGFW_window* win = NULL;
13081 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13082 if (win == NULL) return;
13083
13084 NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame"));
13085 NSRect content = ((NSRect(*)(id, SEL, NSRect))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("contentRectForFrameRect:"), frame);
13086
13087 float y = RGFW_cocoaYTransform((float)(content.origin.y + content.size.height - 1));
13088
13089 RGFW_windowMovedCallback(win, (i32)content.origin.x, (i32)y);
13090}
13091
13092static void RGFW__osxViewDidChangeBackingProperties(id self, SEL _cmd) {
13093 RGFW_UNUSED(_cmd);
13094 RGFW_window* win = NULL;
13095 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13096 if (win == NULL) return;
13097
13098 RGFW_monitor* mon = RGFW_window_getMonitor(win);
13099 if (mon == NULL) return;
13100
13101 RGFW_scaleUpdatedCallback(win, mon->scaleX, mon->scaleY);
13102}
13103
13104static BOOL RGFW__osxWantsUpdateLayer(id self, SEL _cmd) { RGFW_UNUSED(self); RGFW_UNUSED(_cmd); return YES; }
13105
13106static void RGFW__osxUpdateLayer(id self, SEL _cmd) {
13107 RGFW_UNUSED(self); RGFW_UNUSED(_cmd);
13108 RGFW_window* win = NULL;
13109 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13110 if (win == NULL) return;
13111 RGFW_windowRefreshCallback(win);
13112}
13113
13114static void RGFW__osxDrawRect(id self, SEL _cmd, CGRect rect) {
13115 RGFW_UNUSED(rect); RGFW_UNUSED(_cmd);
13116 RGFW_window* win = NULL;
13117 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13118 if (win == NULL) return;
13119
13120 RGFW_windowRefreshCallback(win);
13121}
13122
13123static void RGFW__osxMouseEntered(id self, SEL _cmd, id event) {
13124 RGFW_UNUSED(_cmd);
13125 RGFW_window* win = NULL;
13126 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13127 if (win == NULL) return;
13128
13129 NSPoint p = ((NSPoint(*)(id, SEL))objc_msgSend)(event, sel_registerName("locationInWindow"));
13130 RGFW_mouseNotifyCallback(win, (i32)p.x, (i32)(win->h - p.y), 1);
13131}
13132
13133static void RGFW__osxMouseExited(id self, SEL _cmd, id event) {
13134 RGFW_UNUSED(_cmd); RGFW_UNUSED(event);
13135 RGFW_window* win = NULL;
13136 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13137 if (win == NULL) return;
13138
13139 RGFW_mouseNotifyCallback(win, win->internal.lastMouseX, win->internal.lastMouseY, RGFW_FALSE);
13140}
13141
13142static void RGFW__osxKeyDown(id self, SEL _cmd, id event) {
13143 RGFW_UNUSED(_cmd);
13144 RGFW_window* win = NULL;
13145 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13146 if (win == NULL || !(win->internal.enabledEvents & RGFW_keyPressedFlag)) return;
13147
13148 u32 key = (u16)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("keyCode"));
13149
13150 RGFW_key value = (u8)RGFW_apiKeyToRGFW(key);
13151 RGFW_bool repeat = RGFW_window_isKeyPressed(win, value);
13152
13153 RGFW_keyCallback(win, value, win->internal.mod, repeat, 1);
13154
13155 id nsstring = ((id(*)(id, SEL))objc_msgSend)(event, sel_registerName("charactersIgnoringModifiers"));
13156 const char* string = NSString_to_char(nsstring);
13157 size_t count = (size_t)((int (*)(id, SEL))objc_msgSend)(nsstring, sel_registerName("length"));
13158
13159 for (size_t index = 0; index < count;
13160 RGFW_keyCharCallback(win, RGFW_decodeUTF8(&string[index], &index))
13161 );
13162}
13163
13164static void RGFW__osxKeyUp(id self, SEL _cmd, id event) {
13165 RGFW_UNUSED(_cmd);
13166 RGFW_window* win = NULL;
13167 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13168 if (win == NULL || !(win->internal.enabledEvents & RGFW_keyReleasedFlag)) return;
13169
13170 u32 key = (u16)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("keyCode"));
13171
13172 RGFW_key value = (u8)RGFW_apiKeyToRGFW(key);
13173 RGFW_bool repeat = RGFW_window_isKeyDown(win, (u8)value);
13174
13175 RGFW_keyCallback(win, value, win->internal.mod, repeat, 0);
13176}
13177
13178static void RGFW__osxFlagsChanged(id self, SEL _cmd, id event) {
13179 RGFW_UNUSED(_cmd);
13180 RGFW_window* win = NULL;
13181 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13182 if (win == NULL) return;
13183
13184 RGFW_key value = 0;
13185 RGFW_bool pressed = RGFW_FALSE;
13186
13187 u32 flags = (u32)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("modifierFlags"));
13188 RGFW_updateKeyModsEx(win,
13189 ((u32)(flags & NSEventModifierFlagCapsLock) % 255),
13190 ((flags & NSEventModifierFlagNumericPad) % 255),
13191 ((flags & NSEventModifierFlagControl) % 255),
13192 ((flags & NSEventModifierFlagOption) % 255),
13193 ((flags & NSEventModifierFlagShift) % 255),
13194 ((flags & NSEventModifierFlagCommand) % 255), 0);
13195 u8 i;
13196 for (i = 0; i < 9; i++)
13197 _RGFW->keyboard[i + RGFW_capsLock].prev = _RGFW->keyboard[i + RGFW_capsLock].current;
13198
13199 for (i = 0; i < 5; i++) {
13200 u32 shift = (1 << (i + 16));
13201 RGFW_key key = i + RGFW_capsLock;
13202 if ((flags & shift) && !RGFW_window_isKeyDown(win, (u8)key)) {
13203 pressed = RGFW_TRUE;
13204 value = (u8)key;
13205 break;
13206 }
13207 if (!(flags & shift) && RGFW_window_isKeyDown(win, (u8)key)) {
13208 pressed = RGFW_FALSE;
13209 value = (u8)key;
13210 break;
13211 }
13212 }
13213
13214 RGFW_bool repeat = RGFW_window_isKeyDown(win, (u8)value);
13215 RGFW_keyCallback(win, value, win->internal.mod, repeat, pressed);
13216
13217 if (value != RGFW_capsLock) {
13218 RGFW_keyCallback(win, value + 4, win->internal.mod, repeat, pressed);
13219 }
13220
13221}
13222
13223static void RGFW__osxMouseMoved(id self, SEL _cmd, id event) {
13224 RGFW_UNUSED(_cmd);
13225 RGFW_window* win = NULL;
13226 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13227 if (win == NULL) return;
13228
13229 NSPoint p = ((NSPoint(*)(id, SEL))objc_msgSend)(event, sel_registerName("locationInWindow"));
13230
13231 CGFloat vecX = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(event, sel_registerName("deltaX"));
13232 CGFloat vecY = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(event, sel_registerName("deltaY"));
13233
13234 RGFW_mousePosCallback(win, (i32)p.x, (i32)(win->h - p.y), (float)vecX, (float)vecY);
13235}
13236
13237static void RGFW__osxMouseDown(id self, SEL _cmd, id event) {
13238 RGFW_UNUSED(_cmd);
13239 RGFW_window* win = NULL;
13240 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13241 if (win == NULL) return;
13242
13243 u32 buttonNumber = (u32)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("buttonNumber"));
13244
13245 RGFW_mouseButton value = 0;
13246 switch (buttonNumber) {
13247 case 0: value = RGFW_mouseLeft; break;
13248 case 1: value = RGFW_mouseRight; break;
13249 case 2: value = RGFW_mouseMiddle; break;
13250 default: value = (u8)buttonNumber;
13251 }
13252
13253 RGFW_mouseButtonCallback(win, value, 1);
13254}
13255
13256static void RGFW__osxMouseUp(id self, SEL _cmd, id event) {
13257 RGFW_UNUSED(_cmd);
13258 RGFW_window* win = NULL;
13259 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13260 if (win == NULL) return;
13261
13262 u32 buttonNumber = (u32)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("buttonNumber"));
13263
13264 RGFW_mouseButton value = 0;
13265 switch (buttonNumber) {
13266 case 0: value = RGFW_mouseLeft; break;
13267 case 1: value = RGFW_mouseRight; break;
13268 case 2: value = RGFW_mouseMiddle; break;
13269 default: value = (u8)buttonNumber;
13270 }
13271
13272 RGFW_mouseButtonCallback(win, value, 0);
13273}
13274
13275static void RGFW__osxScrollWheel(id self, SEL _cmd, id event) {
13276 RGFW_UNUSED(_cmd);
13277 RGFW_window* win = NULL;
13278 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
13279 if (win == NULL) return;
13280
13281 float deltaX = (float)((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(event, sel_registerName("deltaX"));
13282 float deltaY = (float)((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(event, sel_registerName("deltaY"));
13283
13284 RGFW_mouseScrollCallback(win, deltaX, deltaY);
13285}
13286
13287RGFW_format RGFW_nativeFormat(void) { return RGFW_formatRGBA8; }
13288
13289RGFW_bool RGFW_createSurfacePtr(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) {
13290 surface->data = data;
13291 surface->w = w;
13292 surface->h = h;
13293 surface->format = format;
13294 surface->native.format = RGFW_formatRGBA8;
13295
13296 surface->native.buffer = (u8*)RGFW_ALLOC((size_t)(w * h * 4));
13297 return RGFW_TRUE;
13298}
13299
13300void RGFW_surface_freePtr(RGFW_surface* surface) {
13301 RGFW_FREE(surface->native.buffer);
13302}
13303
13304void RGFW_window_blitSurface(RGFW_window* win, RGFW_surface* surface) {
13305 id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
13306 pool = objc_msgSend_id(pool, sel_registerName("init"));
13307
13308 int minW = RGFW_MIN(win->w, surface->w);
13309 int minH = RGFW_MIN(win->h, surface->h);
13310
13311 RGFW_monitor* mon = RGFW_window_getMonitor(win);
13312 if (mon == NULL) return;
13313
13314 minW = (i32)((float)minW * mon->pixelRatio);
13315 minH = (i32)((float)minH * mon->pixelRatio);
13316
13317 surface->native.rep = (void*)NSBitmapImageRep_initWithBitmapData(&surface->native.buffer, minW, minH, 8, 4, true, false, "NSDeviceRGBColorSpace", 1 << 1, (u32)surface->w * 4, 32);
13318
13319 id image = ((id (*)(Class, SEL))objc_msgSend)(objc_getClass("NSImage"), sel_getUid("alloc"));
13320 NSSize size = (NSSize){(double)minW, (double)minH};
13321 image = ((id (*)(id, SEL, NSSize))objc_msgSend)((id)image, sel_getUid("initWithSize:"), size);
13322
13323 RGFW_copyImageData(NSBitmapImageRep_bitmapData((id)surface->native.rep), surface->w, minH, RGFW_formatRGBA8, surface->data, surface->native.format, surface->convertFunc);
13324 ((void (*)(id, SEL, id))objc_msgSend)((id)image, sel_getUid("addRepresentation:"), (id)surface->native.rep);
13325
13326 id layer = ((id (*)(id, SEL))objc_msgSend)((id)win->src.view, sel_getUid("layer"));
13327 ((void (*)(id, SEL, id))objc_msgSend)(layer, sel_getUid("setContents:"), (id)image);
13328
13329 NSRelease(image);
13330 NSRelease(surface->native.rep);
13331
13332 objc_msgSend_bool_void(pool, sel_registerName("drain"));
13333}
13334
13335void* RGFW_window_getView_OSX(RGFW_window* win) { return win->src.view; }
13336
13337void RGFW_window_setLayer_OSX(RGFW_window* win, void* layer) {
13338 objc_msgSend_void_id((id)win->src.view, sel_registerName("setLayer:"), (id)layer);
13339}
13340
13341void* RGFW_getLayer_OSX(void) {
13342 return objc_msgSend_class((id)objc_getClass("CAMetalLayer"), (SEL)sel_registerName("layer"));
13343}
13344void* RGFW_window_getWindow_OSX(RGFW_window* win) { return win->src.window; }
13345
13346void RGFW_initKeycodesPlatform(void) {
13347 _RGFW->keycodes[0x1D] = RGFW_0;
13348 _RGFW->keycodes[0x12] = RGFW_1;
13349 _RGFW->keycodes[0x13] = RGFW_2;
13350 _RGFW->keycodes[0x14] = RGFW_3;
13351 _RGFW->keycodes[0x15] = RGFW_4;
13352 _RGFW->keycodes[0x17] = RGFW_5;
13353 _RGFW->keycodes[0x16] = RGFW_6;
13354 _RGFW->keycodes[0x1A] = RGFW_7;
13355 _RGFW->keycodes[0x1C] = RGFW_8;
13356 _RGFW->keycodes[0x19] = RGFW_9;
13357 _RGFW->keycodes[0x00] = RGFW_a;
13358 _RGFW->keycodes[0x0B] = RGFW_b;
13359 _RGFW->keycodes[0x08] = RGFW_c;
13360 _RGFW->keycodes[0x02] = RGFW_d;
13361 _RGFW->keycodes[0x0E] = RGFW_e;
13362 _RGFW->keycodes[0x03] = RGFW_f;
13363 _RGFW->keycodes[0x05] = RGFW_g;
13364 _RGFW->keycodes[0x04] = RGFW_h;
13365 _RGFW->keycodes[0x22] = RGFW_i;
13366 _RGFW->keycodes[0x26] = RGFW_j;
13367 _RGFW->keycodes[0x28] = RGFW_k;
13368 _RGFW->keycodes[0x25] = RGFW_l;
13369 _RGFW->keycodes[0x2E] = RGFW_m;
13370 _RGFW->keycodes[0x2D] = RGFW_n;
13371 _RGFW->keycodes[0x1F] = RGFW_o;
13372 _RGFW->keycodes[0x23] = RGFW_p;
13373 _RGFW->keycodes[0x0C] = RGFW_q;
13374 _RGFW->keycodes[0x0F] = RGFW_r;
13375 _RGFW->keycodes[0x01] = RGFW_s;
13376 _RGFW->keycodes[0x11] = RGFW_t;
13377 _RGFW->keycodes[0x20] = RGFW_u;
13378 _RGFW->keycodes[0x09] = RGFW_v;
13379 _RGFW->keycodes[0x0D] = RGFW_w;
13380 _RGFW->keycodes[0x07] = RGFW_x;
13381 _RGFW->keycodes[0x10] = RGFW_y;
13382 _RGFW->keycodes[0x06] = RGFW_z;
13383 _RGFW->keycodes[0x27] = RGFW_apostrophe;
13384 _RGFW->keycodes[0x2A] = RGFW_backSlash;
13385 _RGFW->keycodes[0x2B] = RGFW_comma;
13386 _RGFW->keycodes[0x18] = RGFW_equals;
13387 _RGFW->keycodes[0x32] = RGFW_backtick;
13388 _RGFW->keycodes[0x21] = RGFW_bracket;
13389 _RGFW->keycodes[0x1B] = RGFW_minus;
13390 _RGFW->keycodes[0x2F] = RGFW_period;
13391 _RGFW->keycodes[0x1E] = RGFW_closeBracket;
13392 _RGFW->keycodes[0x29] = RGFW_semicolon;
13393 _RGFW->keycodes[0x2C] = RGFW_slash;
13394 _RGFW->keycodes[0x0A] = RGFW_world1;
13395 _RGFW->keycodes[0x33] = RGFW_backSpace;
13396 _RGFW->keycodes[0x39] = RGFW_capsLock;
13397 _RGFW->keycodes[0x75] = RGFW_delete;
13398 _RGFW->keycodes[0x7D] = RGFW_down;
13399 _RGFW->keycodes[0x77] = RGFW_end;
13400 _RGFW->keycodes[0x24] = RGFW_enter;
13401 _RGFW->keycodes[0x35] = RGFW_escape;
13402 _RGFW->keycodes[0x7A] = RGFW_F1;
13403 _RGFW->keycodes[0x78] = RGFW_F2;
13404 _RGFW->keycodes[0x63] = RGFW_F3;
13405 _RGFW->keycodes[0x76] = RGFW_F4;
13406 _RGFW->keycodes[0x60] = RGFW_F5;
13407 _RGFW->keycodes[0x61] = RGFW_F6;
13408 _RGFW->keycodes[0x62] = RGFW_F7;
13409 _RGFW->keycodes[0x64] = RGFW_F8;
13410 _RGFW->keycodes[0x65] = RGFW_F9;
13411 _RGFW->keycodes[0x6D] = RGFW_F10;
13412 _RGFW->keycodes[0x67] = RGFW_F11;
13413 _RGFW->keycodes[0x6F] = RGFW_F12;
13414 _RGFW->keycodes[0x69] = RGFW_printScreen;
13415 _RGFW->keycodes[0x6B] = RGFW_F14;
13416 _RGFW->keycodes[0x71] = RGFW_F15;
13417 _RGFW->keycodes[0x6A] = RGFW_F16;
13418 _RGFW->keycodes[0x40] = RGFW_F17;
13419 _RGFW->keycodes[0x4F] = RGFW_F18;
13420 _RGFW->keycodes[0x50] = RGFW_F19;
13421 _RGFW->keycodes[0x5A] = RGFW_F20;
13422 _RGFW->keycodes[0x73] = RGFW_home;
13423 _RGFW->keycodes[0x72] = RGFW_insert;
13424 _RGFW->keycodes[0x7B] = RGFW_left;
13425 _RGFW->keycodes[0x3A] = RGFW_altL;
13426 _RGFW->keycodes[0x3B] = RGFW_controlL;
13427 _RGFW->keycodes[0x38] = RGFW_shiftL;
13428 _RGFW->keycodes[0x37] = RGFW_superL;
13429 _RGFW->keycodes[0x6E] = RGFW_menu;
13430 _RGFW->keycodes[0x47] = RGFW_numLock;
13431 _RGFW->keycodes[0x79] = RGFW_pageDown;
13432 _RGFW->keycodes[0x74] = RGFW_pageUp;
13433 _RGFW->keycodes[0x7C] = RGFW_right;
13434 _RGFW->keycodes[0x3D] = RGFW_altR;
13435 _RGFW->keycodes[0x3E] = RGFW_controlR;
13436 _RGFW->keycodes[0x3C] = RGFW_shiftR;
13437 _RGFW->keycodes[0x36] = RGFW_superR;
13438 _RGFW->keycodes[0x31] = RGFW_space;
13439 _RGFW->keycodes[0x30] = RGFW_tab;
13440 _RGFW->keycodes[0x7E] = RGFW_up;
13441 _RGFW->keycodes[0x52] = RGFW_kp0;
13442 _RGFW->keycodes[0x53] = RGFW_kp1;
13443 _RGFW->keycodes[0x54] = RGFW_kp2;
13444 _RGFW->keycodes[0x55] = RGFW_kp3;
13445 _RGFW->keycodes[0x56] = RGFW_kp4;
13446 _RGFW->keycodes[0x57] = RGFW_kp5;
13447 _RGFW->keycodes[0x58] = RGFW_kp6;
13448 _RGFW->keycodes[0x59] = RGFW_kp7;
13449 _RGFW->keycodes[0x5B] = RGFW_kp8;
13450 _RGFW->keycodes[0x5C] = RGFW_kp9;
13451 _RGFW->keycodes[0x45] = RGFW_kpSlash;
13452 _RGFW->keycodes[0x41] = RGFW_kpPeriod;
13453 _RGFW->keycodes[0x4B] = RGFW_kpSlash;
13454 _RGFW->keycodes[0x4C] = RGFW_kpReturn;
13455 _RGFW->keycodes[0x51] = RGFW_kpEqual;
13456 _RGFW->keycodes[0x43] = RGFW_kpMultiply;
13457 _RGFW->keycodes[0x4E] = RGFW_kpMinus;
13458}
13459
13460i32 RGFW_initPlatform(void) {
13461 _RGFW->tisBundle = (void*)CFBundleGetBundleWithIdentifier(CFSTR("com.apple.HIToolbox"));
13462
13463 TISGetInputSourcePropertySrc = (PFN_TISGetInputSourceProperty)CFBundleGetFunctionPointerForName((CFBundleRef)_RGFW->tisBundle, CFSTR("TISGetInputSourceProperty"));
13464 TISCopyCurrentKeyboardLayoutInputSourceSrc = (PFN_TISCopyCurrentKeyboardLayoutInputSource)CFBundleGetFunctionPointerForName((CFBundleRef)_RGFW->tisBundle, CFSTR("TISCopyCurrentKeyboardLayoutInputSource"));
13465 LMGetKbdTypeSrc = (PFN_LMGetKbdType)CFBundleGetFunctionPointerForName((CFBundleRef)_RGFW->tisBundle, CFSTR("LMGetKbdType"));
13466
13467 CFStringRef* cfStr = (CFStringRef*)CFBundleGetDataPointerForName((CFBundleRef)_RGFW->tisBundle, CFSTR("kTISPropertyUnicodeKeyLayoutData"));;
13468 if (cfStr) kTISPropertyUnicodeKeyLayoutDataSrc = *cfStr;
13469
13470 class_addMethod(objc_getClass("NSObject"), sel_registerName("windowShouldClose:"), (IMP)(void*)RGFW_OnClose, 0);
13471
13472 /* NOTE(EimaMei): Fixes the 'Boop' sfx from constantly playing each time you click a key. Only a problem when running in the terminal. */
13473 class_addMethod(objc_getClass("NSWindowClass"), sel_registerName("acceptsFirstResponder:"), (IMP)(void*)RGFW__osxAcceptsFirstResponder, 0);
13474 class_addMethod(objc_getClass("NSWindowClass"), sel_registerName("performKeyEquivalent:"), (IMP)(void*)RGFW__osxPerformKeyEquivalent, 0);
13475
13476 _RGFW->NSApp = objc_msgSend_id(objc_getClass("NSApplication"), sel_registerName("sharedApplication"));
13477
13478 NSRetain(_RGFW->NSApp);
13479
13480 _RGFW->customNSAppDelegateClass = objc_allocateClassPair(objc_getClass("NSObject"), "RGFWNSAppDelegate", 0);
13481 class_addMethod((Class)_RGFW->customNSAppDelegateClass, sel_registerName("applicationDidChangeScreenParameters:"), (IMP)RGFW__osxDidChangeScreenParameters, "v@:@");
13482 objc_registerClassPair((Class)_RGFW->customNSAppDelegateClass);
13483 _RGFW->customNSAppDelegate = objc_msgSend_id(NSAlloc(_RGFW->customNSAppDelegateClass), sel_registerName("init"));
13484
13485 objc_msgSend_void_id(_RGFW->NSApp, sel_registerName("setDelegate:"), _RGFW->customNSAppDelegate);
13486
13487 ((void (*)(id, SEL, NSUInteger))objc_msgSend) ((id)_RGFW->NSApp, sel_registerName("setActivationPolicy:"), NSApplicationActivationPolicyRegular);
13488
13489 _RGFW->customViewClasses[0] = objc_allocateClassPair(objc_getClass("NSView"), "RGFWCustomView", 0);
13490 _RGFW->customViewClasses[1] = objc_allocateClassPair(objc_getClass("NSOpenGLView"), "RGFWOpenGLCustomView", 0);
13491 for (size_t i = 0; i < 2; i++) {
13492 class_addIvar((Class)_RGFW->customViewClasses[i], "RGFW_window", sizeof(RGFW_window*), sizeof(RGFW_window*), "L");
13493 class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("drawRect:"), (IMP)RGFW__osxDrawRect, "v@:{CGRect=ffff}");
13494 class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("viewDidChangeBackingProperties"), (IMP)RGFW__osxViewDidChangeBackingProperties, "v@:");
13495 class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseDown:"), (IMP)RGFW__osxMouseDown, "v@:@");
13496 class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("rightMouseDown:"), (IMP)RGFW__osxMouseDown, "v@:@");
13497 class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("otherMouseDown:"), (IMP)RGFW__osxMouseDown, "v@:@");
13498 class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseUp:"), (IMP)RGFW__osxMouseUp, "v@:@");
13499 class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("rightMouseUp:"), (IMP)RGFW__osxMouseUp, "v@:@");
13500 class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("otherMouseUp:"), (IMP)RGFW__osxMouseUp, "v@:@");
13501 class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("scrollWheel:"), (IMP)RGFW__osxScrollWheel, "v@:@");
13502 class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseDragged:"), (IMP)RGFW__osxMouseMoved, "v@:@");
13503 class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("rightMouseDragged:"), (IMP)RGFW__osxMouseMoved, "v@:@");
13504 class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("otherMouseDragged:"), (IMP)RGFW__osxMouseMoved, "v@:@");
13505 class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("keyDown:"), (IMP)RGFW__osxKeyDown, "v@:@");
13506 class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("keyUp:"), (IMP)RGFW__osxKeyUp, "v@:@");
13507 class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseMoved:"), (IMP)RGFW__osxMouseMoved, "v@:@");
13508 class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseEntered:"), (IMP)RGFW__osxMouseEntered, "v@:@");
13509 class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseExited:"), (IMP)RGFW__osxMouseExited, "v@:@");
13510 class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("flagsChanged:"), (IMP)RGFW__osxFlagsChanged, "v@:@");
13511 class_addMethod((Class)_RGFW->customViewClasses[i], sel_getUid("acceptsFirstResponder"), (IMP)RGFW__osxAcceptsFirstResponder, "B@:");
13512 class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("initWithRGFWWindow:"), (IMP)RGFW__osxCustomInitWithRGFWWindow, "@@:{CGRect={CGPoint=dd}{CGSize=dd}}");
13513 class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("wantsUpdateLayer"), (IMP)RGFW__osxWantsUpdateLayer, "B@:");
13514 class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("updateLayer"), (IMP)RGFW__osxUpdateLayer, "v@:");
13515 objc_registerClassPair((Class)_RGFW->customViewClasses[i]);
13516 }
13517
13518 _RGFW->customWindowDelegateClass = objc_allocateClassPair(objc_getClass("NSObject"), "RGFWWindowDelegate", 0);
13519 class_addIvar((Class)_RGFW->customWindowDelegateClass, "RGFW_window", sizeof(RGFW_window*), sizeof(RGFW_window*), "L");
13520 class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidResize:"), (IMP)RGFW__osxDidWindowResize, "v@:@");
13521 class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidMove:"), (IMP) RGFW__osxWindowMove, "");
13522 class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidMiniaturize:"), (IMP) RGFW__osxWindowMiniaturize, "");
13523 class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidDeminiaturize:"), (IMP) RGFW__osxWindowDeminiaturize, "");
13524 class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidBecomeKey:"), (IMP) RGFW__osxWindowBecameKey, "");
13525 class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidResignKey:"), (IMP) RGFW__osxWindowResignKey, "");
13526 class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("draggingEntered:"), (IMP)RGFW__osxDraggingEntered, "l@:@");
13527 class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("draggingUpdated:"), (IMP)RGFW__osxDraggingUpdated, "l@:@");
13528 class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("draggingExited:"), (IMP)RGFW__osxDraggingEnded, "v@:@");
13529 class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("draggingEnded:"), (IMP)RGFW__osxDraggingEnded, "v@:@");
13530 class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("prepareForDragOperation:"), (IMP)RGFW__osxPrepareForDragOperation, "B@:@");
13531 class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("performDragOperation:"), (IMP)RGFW__osxPerformDragOperation, "B@:@");
13532 objc_registerClassPair((Class)_RGFW->customWindowDelegateClass);
13533 return 0;
13534}
13535
13536void RGFW_osx_initView(RGFW_window* win) {
13537 NSRect contentRect;
13538 contentRect.origin.x = 0;
13539 contentRect.origin.y = 0;
13540 contentRect.size.width = (double)win->w;
13541 contentRect.size.height = (double)win->h;
13542 ((void(*)(id, SEL, CGRect))objc_msgSend)((id)win->src.view, sel_registerName("setFrame:"), contentRect);
13543
13544
13545 if (RGFW_COCOA_FRAME_NAME)
13546 objc_msgSend_ptr(win->src.view, sel_registerName("setFrameAutosaveName:"), RGFW_COCOA_FRAME_NAME);
13547
13548 object_setInstanceVariable((id)win->src.view, "RGFW_window", win);
13549 objc_msgSend_void_id((id)win->src.window, sel_registerName("setContentView:"), win->src.view);
13550 objc_msgSend_void_bool(win->src.view, sel_registerName("setWantsLayer:"), true);
13551 objc_msgSend_int((id)win->src.view, sel_registerName("setLayerContentsPlacement:"), 4);
13552
13553 id trackingArea = objc_msgSend_id(objc_getClass("NSTrackingArea"), sel_registerName("alloc"));
13554 trackingArea = ((id (*)(id, SEL, NSRect, NSUInteger, id, id))objc_msgSend)(
13555 trackingArea,
13556 sel_registerName("initWithRect:options:owner:userInfo:"),
13557 contentRect,
13558 NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingInVisibleRect,
13559 (id)win->src.view,
13560 nil
13561 );
13562
13563 ((void (*)(id, SEL, id))objc_msgSend)((id)win->src.view, sel_registerName("addTrackingArea:"), trackingArea);
13564 ((void (*)(id, SEL))objc_msgSend)(trackingArea, sel_registerName("release"));
13565}
13566
13567RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win) {
13568 /* RR Create an autorelease pool */
13569 id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
13570 pool = objc_msgSend_id(pool, sel_registerName("init"));
13571
13572 RGFW_window_setMouseDefault(win);
13573
13574 NSRect windowRect;
13575 windowRect.origin.x = (double)win->x;
13576 windowRect.origin.y = (double)RGFW_cocoaYTransform((float)(win->y + win->h - 1));
13577 windowRect.size.width = (double)win->w;
13578 windowRect.size.height = (double)win->h;
13579 NSBackingStoreType macArgs = (NSBackingStoreType)(NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSBackingStoreBuffered | NSWindowStyleMaskTitled);
13580
13581 if (!(flags & RGFW_windowNoResize))
13582 macArgs = (NSBackingStoreType)(macArgs | (NSBackingStoreType)NSWindowStyleMaskResizable);
13583 if (!(flags & RGFW_windowNoBorder))
13584 macArgs = (NSBackingStoreType)(macArgs | (NSBackingStoreType)NSWindowStyleMaskTitled);
13585 {
13586 void* nsclass = objc_getClass("NSWindow");
13587 SEL func = sel_registerName("initWithContentRect:styleMask:backing:defer:");
13588
13589 win->src.window = ((id(*)(id, SEL, NSRect, NSWindowStyleMask, NSBackingStoreType, bool))objc_msgSend)
13590 (NSAlloc(nsclass), func, windowRect, (NSWindowStyleMask)macArgs, macArgs, false);
13591 }
13592
13593 id str = NSString_stringWithUTF8String(name);
13594 objc_msgSend_void_id((id)win->src.window, sel_registerName("setTitle:"), str);
13595
13596 win->src.delegate = (void*)objc_msgSend_id(NSAlloc((Class)_RGFW->customWindowDelegateClass), sel_registerName("init"));
13597 object_setInstanceVariable((id)win->src.delegate, "RGFW_window", win);
13598
13599 objc_msgSend_void_id((id)win->src.window, sel_registerName("setDelegate:"), (id)win->src.delegate);
13600
13601 if (flags & RGFW_windowAllowDND) {
13602 win->internal.flags |= RGFW_windowAllowDND;
13603
13604 NSPasteboardType types[] = {NSPasteboardTypeURL, NSPasteboardTypeFileURL, NSPasteboardTypeString};
13605 NSregisterForDraggedTypes((id)win->src.window, types, 3);
13606 }
13607
13608 objc_msgSend_void_bool((id)win->src.window, sel_registerName("setAcceptsMouseMovedEvents:"), true);
13609
13610 if (flags & RGFW_windowTransparent) {
13611 objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), false);
13612
13613 objc_msgSend_void_id((id)win->src.window, sel_registerName("setBackgroundColor:"),
13614 NSColor_colorWithSRGB(0, 0, 0, 0));
13615 }
13616
13617 /* Show the window */
13618 objc_msgSend_void_bool((id)_RGFW->NSApp, sel_registerName("activateIgnoringOtherApps:"), true);
13619
13620 if (_RGFW->root == NULL) {
13621 objc_msgSend_void(win->src.window, sel_registerName("makeMainWindow"));
13622 }
13623
13624 objc_msgSend_void(win->src.window, sel_registerName("makeKeyWindow"));
13625
13626 NSRetain(win->src.window);
13627
13628 win->src.view = ((id(*)(id, SEL, RGFW_window*))objc_msgSend) (NSAlloc((Class)_RGFW->customViewClasses[0]), sel_registerName("initWithRGFWWindow:"), win);
13629 return win;
13630}
13631
13632void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) {
13633 NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame"));
13634 NSRect content = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame"));
13635 double offset = 0;
13636
13637 RGFW_setBit(&win->internal.flags, RGFW_windowNoBorder, !border);
13638 NSBackingStoreType storeType = (NSBackingStoreType)(NSWindowStyleMaskBorderless | NSWindowStyleMaskFullSizeContentView);
13639 if (border)
13640 storeType = (NSBackingStoreType)(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable);
13641 if (!(win->internal.flags & RGFW_windowNoResize)) {
13642 storeType = (NSBackingStoreType)(storeType | (NSBackingStoreType)NSWindowStyleMaskResizable);
13643 }
13644
13645 ((void (*)(id, SEL, NSBackingStoreType))objc_msgSend)((id)win->src.window, sel_registerName("setStyleMask:"), storeType);
13646
13647 if (!border) {
13648 id miniaturizeButton = objc_msgSend_int((id)win->src.window, sel_registerName("standardWindowButton:"), NSWindowMiniaturizeButton);
13649 id titleBarView = objc_msgSend_id(miniaturizeButton, sel_registerName("superview"));
13650 objc_msgSend_void_bool(titleBarView, sel_registerName("setHidden:"), true);
13651
13652 offset = (double)(frame.size.height - content.size.height);
13653 }
13654
13655 RGFW_window_resize(win, win->w, win->h + (i32)offset);
13656 win->h -= (i32)offset;
13657}
13658
13659RGFW_bool RGFW_getGlobalMouse(i32* x, i32* y) {
13660 RGFW_ASSERT(_RGFW->root != NULL);
13661
13662 CGEventRef e = CGEventCreate(NULL);
13663 CGPoint point = CGEventGetLocation(e);
13664 CFRelease(e);
13665
13666 if (x) *x = (i32)point.x;
13667 if (y) *y = (i32)point.y;
13668 return RGFW_TRUE;
13669}
13670
13671void RGFW_stopCheckEvents(void) {
13672 id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
13673 eventPool = objc_msgSend_id(eventPool, sel_registerName("init"));
13674
13675 id e = (id) ((id(*)(Class, SEL, NSEventType, NSPoint, NSEventModifierFlags, void*, NSInteger, void**, short, NSInteger, NSInteger))objc_msgSend)
13676 (objc_getClass("NSEvent"), sel_registerName("otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:"),
13677 NSEventTypeApplicationDefined, (NSPoint){0, 0}, (NSEventModifierFlags)0, NULL, (NSInteger)0, NULL, 0, 0, 0);
13678
13679 ((void (*)(id, SEL, id, bool))objc_msgSend)
13680 ((id)_RGFW->NSApp, sel_registerName("postEvent:atStart:"), e, 1);
13681
13682 objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
13683}
13684
13685void RGFW_waitForEvent(i32 waitMS) {
13686 id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
13687 eventPool = objc_msgSend_id(eventPool, sel_registerName("init"));
13688
13689 void* date = (void*) ((id(*)(Class, SEL, double))objc_msgSend)
13690 (objc_getClass("NSDate"), sel_registerName("dateWithTimeIntervalSinceNow:"), waitMS);
13691
13692 SEL eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:");
13693 id e = (id) ((id(*)(id, SEL, NSEventMask, void*, id, bool))objc_msgSend)
13694 ((id)_RGFW->NSApp, eventFunc,
13695 ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true);
13696
13697 if (e) {
13698 ((void (*)(id, SEL, id, bool))objc_msgSend)
13699 ((id)_RGFW->NSApp, sel_registerName("postEvent:atStart:"), e, 1);
13700 }
13701
13702 objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
13703}
13704
13705RGFW_key RGFW_physicalToMappedKey(RGFW_key key) {
13706 u16 keycode = (u16)RGFW_rgfwToApiKey(key);
13707 TISInputSourceRef source = TISCopyCurrentKeyboardLayoutInputSource();
13708 if (source == NULL)
13709 return key;
13710
13711 CFDataRef layoutData = TISGetInputSourceProperty(source, kTISPropertyUnicodeKeyLayoutDataSrc);
13712
13713 if (layoutData == NULL) {
13714 CFRelease(source);
13715 return key;
13716 }
13717
13718 UCKeyboardLayout *layout = (UCKeyboardLayout*)(void*)CFDataGetBytePtr(layoutData);
13719
13720 UInt32 deadKeyState = 0;
13721 UniChar chars[4];
13722 UniCharCount len = 0;
13723 u32 type = LMGetKbdType();
13724 OSStatus status = UCKeyTranslate(layout, keycode, kUCKeyActionDown, 0, type, kUCKeyTranslateNoDeadKeysBit, &deadKeyState, 4, &len, chars );
13725
13726 CFRelease(source);
13727
13728 if (status == noErr && len == 1 && chars[0] < 256) {
13729 return (RGFW_key)chars[0];
13730 }
13731
13732 return key;
13733}
13734
13735void RGFW_pollEvents(void) {
13736 RGFW_resetPrevState();
13737
13738 id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
13739 eventPool = objc_msgSend_id(eventPool, sel_registerName("init"));
13740 SEL eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:");
13741
13742 while (1) {
13743 void* date = NULL;
13744 id e = (id) ((id(*)(id, SEL, NSEventMask, void*, id, bool))objc_msgSend)
13745 ((id)_RGFW->NSApp, eventFunc, ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true);
13746
13747 if (e == NULL) {
13748 break;
13749 }
13750
13751 objc_msgSend_void_id((id)_RGFW->NSApp, sel_registerName("sendEvent:"), e);
13752 }
13753
13754 objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
13755}
13756
13757
13758void RGFW_window_move(RGFW_window* win, i32 x, i32 y) {
13759 RGFW_ASSERT(win != NULL);
13760
13761 NSRect content = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame"));
13762
13763 win->x = x;
13764 win->y = (i32)RGFW_cocoaYTransform((float)y + (float)content.size.height - 1.0f);
13765
13766 ((void(*)(id,SEL,NSPoint))objc_msgSend)((id)win->src.window, sel_registerName("setFrameOrigin:"), (NSPoint){(double)x, (double)y});
13767}
13768
13769void RGFW_window_resize(RGFW_window* win, i32 w, i32 h) {
13770 RGFW_ASSERT(win != NULL);
13771
13772 NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame"));
13773 NSRect content = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame"));
13774 float offset = (float)(frame.size.height - content.size.height);
13775
13776 win->w = w;
13777 win->h = h;
13778
13779
13780 ((void(*)(id, SEL, CGRect))objc_msgSend)((id)win->src.view, sel_registerName("setFrame:"), (NSRect){{0, 0}, {(double)win->w, (double)win->h}});
13781 ((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend)
13782 ((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);
13783}
13784
13785void RGFW_window_focus(RGFW_window* win) {
13786 RGFW_ASSERT(win);
13787 objc_msgSend_void_bool((id)_RGFW->NSApp, sel_registerName("activateIgnoringOtherApps:"), true);
13788 ((void (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_registerName("makeKeyWindow"));
13789}
13790
13791void RGFW_window_raise(RGFW_window* win) {
13792 RGFW_ASSERT(win != NULL);
13793 ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("orderFront:"), (SEL)NULL);
13794 objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGNormalWindowLevelKey);
13795}
13796
13797void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) {
13798 RGFW_ASSERT(win != NULL);
13799 if (fullscreen && (win->internal.flags & RGFW_windowFullscreen)) return;
13800 if (!fullscreen && !(win->internal.flags & RGFW_windowFullscreen)) return;
13801
13802 if (fullscreen) {
13803 win->internal.oldX = win->x;
13804 win->internal.oldY = win->y;
13805 win->internal.oldW = win->w;
13806 win->internal.oldH = win->h;
13807
13808 win->internal.flags |= RGFW_windowFullscreen;
13809
13810 RGFW_monitor* mon = RGFW_window_getMonitor(win);
13811 RGFW_monitor_scaleToWindow(mon, win);
13812
13813 RGFW_window_setBorder(win, RGFW_FALSE);
13814
13815 if (mon != NULL) {
13816 win->x = mon->x;
13817 win->y = mon->y;
13818 win->w = mon->mode.w;
13819 win->h = mon->mode.h;
13820 RGFW_window_resize(win, mon->mode.w, mon->mode.h);
13821 RGFW_window_move(win, mon->x, mon->y);
13822 }
13823
13824 ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("orderFront:"), (SEL)NULL);
13825 objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), 25);
13826 }
13827
13828 objc_msgSend_void_SEL(win->src.window, sel_registerName("toggleFullScreen:"), NULL);
13829
13830 if (!fullscreen) {
13831 win->x = win->internal.oldX;
13832 win->y = win->internal.oldY;
13833 win->w = win->internal.oldW;
13834 win->h = win->internal.oldH;
13835 win->internal.flags &= ~(u32)RGFW_windowFullscreen;
13836
13837 RGFW_window_resize(win, win->w, win->h);
13838 RGFW_window_move(win, win->x, win->y);
13839 }
13840}
13841
13842void RGFW_window_maximize(RGFW_window* win) {
13843 RGFW_ASSERT(win != NULL);
13844 if (RGFW_window_isMaximized(win)) return;
13845
13846 win->internal.flags |= RGFW_windowMaximize;
13847 objc_msgSend_void_SEL(win->src.window, sel_registerName("zoom:"), NULL);
13848}
13849
13850void RGFW_window_minimize(RGFW_window* win) {
13851 RGFW_ASSERT(win != NULL);
13852 objc_msgSend_void_SEL(win->src.window, sel_registerName("performMiniaturize:"), NULL);
13853}
13854
13855void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) {
13856 RGFW_ASSERT(win != NULL);
13857 if (floating) objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGFloatingWindowLevelKey);
13858 else objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGNormalWindowLevelKey);
13859}
13860
13861void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) {
13862 objc_msgSend_int(win->src.window, sel_registerName("setAlphaValue:"), opacity);
13863 objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), (opacity < (u8)255));
13864
13865 if (opacity)
13866 objc_msgSend_void_id((id)win->src.window, sel_registerName("setBackgroundColor:"), NSColor_colorWithSRGB(0, 0, 0, opacity));
13867
13868}
13869
13870void RGFW_window_restore(RGFW_window* win) {
13871 RGFW_ASSERT(win != NULL);
13872
13873 if (RGFW_window_isMaximized(win))
13874 objc_msgSend_void_SEL(win->src.window, sel_registerName("zoom:"), NULL);
13875
13876 objc_msgSend_void_SEL(win->src.window, sel_registerName("deminiaturize:"), NULL);
13877 RGFW_window_show(win);
13878}
13879
13880RGFW_bool RGFW_window_isFloating(RGFW_window* win) {
13881 RGFW_ASSERT(win != NULL);
13882 int level = ((int (*)(id, SEL))objc_msgSend) ((id)(win->src.window), (SEL)sel_registerName("level"));
13883 return level > kCGNormalWindowLevelKey;
13884}
13885
13886void RGFW_window_setName(RGFW_window* win, const char* name) {
13887 RGFW_ASSERT(win != NULL);
13888 if (name == NULL) name = "\0";
13889
13890 id str = NSString_stringWithUTF8String(name);
13891 objc_msgSend_void_id((id)win->src.window, sel_registerName("setTitle:"), str);
13892}
13893
13894#ifndef RGFW_NO_PASSTHROUGH
13895void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) {
13896 objc_msgSend_void_bool(win->src.window, sel_registerName("setIgnoresMouseEvents:"), passthrough);
13897}
13898#endif
13899
13900void RGFW_window_setAspectRatio(RGFW_window* win, i32 w, i32 h) {
13901 if (w == 0 && h == 0) { w = 1; h = 1; };
13902
13903 ((void (*)(id, SEL, NSSize))objc_msgSend)
13904 ((id)win->src.window, sel_registerName("setContentAspectRatio:"), (NSSize){(CGFloat)w, (CGFloat)h});
13905}
13906
13907void RGFW_window_setMinSize(RGFW_window* win, i32 w, i32 h) {
13908 ((void (*)(id, SEL, NSSize))objc_msgSend) ((id)win->src.window, sel_registerName("setMinSize:"), (NSSize){(CGFloat)w, (CGFloat)h});
13909}
13910
13911void RGFW_window_setMaxSize(RGFW_window* win, i32 w, i32 h) {
13912 if (w == 0 && h == 0) {
13913 RGFW_monitor* mon = RGFW_window_getMonitor(win);
13914 if (mon != NULL) {
13915 w = mon->mode.w;
13916 h = mon->mode.h;
13917 }
13918 }
13919
13920 ((void (*)(id, SEL, NSSize))objc_msgSend)
13921 ((id)win->src.window, sel_registerName("setMaxSize:"), (NSSize){(CGFloat)w, (CGFloat)h});
13922}
13923
13924RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_icon type) {
13925 RGFW_ASSERT(win != NULL);
13926 RGFW_UNUSED(type);
13927
13928 id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
13929 pool = objc_msgSend_id(pool, sel_registerName("init"));
13930
13931 if (data == NULL) {
13932 objc_msgSend_void_id((id)_RGFW->NSApp, sel_registerName("setApplicationIconImage:"), NULL);
13933 objc_msgSend_bool_void(pool, sel_registerName("drain"));
13934 return RGFW_TRUE;
13935 }
13936
13937 id representation = NSBitmapImageRep_initWithBitmapData(NULL, w, h, 8, (NSInteger)4, true, false, "NSCalibratedRGBColorSpace", 1 << 1, w * 4, 32);
13938 RGFW_copyImageData(NSBitmapImageRep_bitmapData(representation), w, h, RGFW_formatRGBA8, data, format, NULL);
13939
13940 id dock_image = ((id(*)(id, SEL, NSSize))objc_msgSend) (NSAlloc((id)objc_getClass("NSImage")), sel_registerName("initWithSize:"), ((NSSize){(CGFloat)w, (CGFloat)h}));
13941
13942 objc_msgSend_void_id(dock_image, sel_registerName("addRepresentation:"), representation);
13943
13944 objc_msgSend_void_id((id)_RGFW->NSApp, sel_registerName("setApplicationIconImage:"), dock_image);
13945
13946 NSRelease(dock_image);
13947 NSRelease(representation);
13948
13949 objc_msgSend_bool_void(pool, sel_registerName("drain"));
13950
13951 return RGFW_TRUE;
13952}
13953
13954id NSCursor_arrowStr(const char* str);
13955id NSCursor_arrowStr(const char* str) {
13956 void* nclass = objc_getClass("NSCursor");
13957 SEL func = sel_registerName(str);
13958 return (id) objc_msgSend_id(nclass, func);
13959}
13960
13961RGFW_mouse* RGFW_loadMouse(u8* data, i32 w, i32 h, RGFW_format format) {
13962 id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
13963 pool = objc_msgSend_id(pool, sel_registerName("init"));
13964
13965 if (data == NULL) {
13966 objc_msgSend_void(NSCursor_arrowStr("arrowCursor"), sel_registerName("set"));
13967
13968 objc_msgSend_bool_void(pool, sel_registerName("drain"));
13969 return NULL;
13970 }
13971
13972 id representation = (id)NSBitmapImageRep_initWithBitmapData(NULL, w, h, 8, (NSInteger)4, true, false, "NSCalibratedRGBColorSpace", 1 << 1, w * 4, 32);
13973 RGFW_copyImageData(NSBitmapImageRep_bitmapData(representation), w, h, RGFW_formatRGBA8, data, format, NULL);
13974
13975 id cursor_image = ((id(*)(id, SEL, NSSize))objc_msgSend) (NSAlloc((id)objc_getClass("NSImage")), sel_registerName("initWithSize:"), ((NSSize){(CGFloat)w, (CGFloat)h}));
13976
13977 objc_msgSend_void_id(cursor_image, sel_registerName("addRepresentation:"), representation);
13978
13979 id cursor = (id) ((id(*)(id, SEL, id, NSPoint))objc_msgSend)
13980 (NSAlloc(objc_getClass("NSCursor")), sel_registerName("initWithImage:hotSpot:"), cursor_image, (NSPoint){0.0, 0.0});
13981
13982 NSRelease(cursor_image);
13983 NSRelease(representation);
13984
13985 objc_msgSend_bool_void(pool, sel_registerName("drain"));
13986
13987 return (void*)cursor;
13988}
13989
13990void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) {
13991 RGFW_ASSERT(win != NULL); RGFW_ASSERT(mouse);
13992 CGDisplayShowCursor(kCGDirectMainDisplay);
13993 objc_msgSend_void((id)mouse, sel_registerName("set"));
13994 win->src.mouse = mouse;
13995}
13996
13997void RGFW_freeMouse(RGFW_mouse* mouse) {
13998 RGFW_ASSERT(mouse);
13999 NSRelease((id)mouse);
14000}
14001
14002RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) {
14003 return RGFW_window_setMouseStandard(win, RGFW_mouseArrow);
14004}
14005
14006void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) {
14007 RGFW_window_showMouseFlags(win, show);
14008 if (show) CGDisplayShowCursor(kCGDirectMainDisplay);
14009 else CGDisplayHideCursor(kCGDirectMainDisplay);
14010}
14011
14012RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 stdMouse) {
14013 const char* cursorSelectorStr;
14014 switch (stdMouse) {
14015 case RGFW_mouseNormal: cursorSelectorStr = "arrowCursor"; break;
14016 case RGFW_mouseArrow: cursorSelectorStr = "arrowCursor"; break;
14017 case RGFW_mouseIbeam: cursorSelectorStr = "IBeamCursor"; break;
14018 case RGFW_mouseCrosshair: cursorSelectorStr = "crosshairCursor"; break;
14019 case RGFW_mousePointingHand: cursorSelectorStr = "pointingHandCursor"; break;
14020 case RGFW_mouseResizeEW: cursorSelectorStr = "resizeLeftRightCursor"; break;
14021 case RGFW_mouseResizeE: cursorSelectorStr = "resizeLeftRightCursor"; break;
14022 case RGFW_mouseResizeW: cursorSelectorStr = "resizeLeftRightCursor"; break;
14023 case RGFW_mouseResizeNS: cursorSelectorStr = "resizeUpDownCursor"; break;
14024 case RGFW_mouseResizeN: cursorSelectorStr = "resizeUpDownCursor"; break;
14025 case RGFW_mouseResizeS: cursorSelectorStr = "resizeUpDownCursor"; break;
14026 case RGFW_mouseResizeNWSE: cursorSelectorStr = "_windowResizeNorthWestSouthEastCursor"; break;
14027 case RGFW_mouseResizeNW: cursorSelectorStr = "_windowResizeNorthWestSouthEastCursor"; break;
14028 case RGFW_mouseResizeSE: cursorSelectorStr = "_windowResizeNorthWestSouthEastCursor"; break;
14029 case RGFW_mouseResizeNESW: cursorSelectorStr = "_windowResizeNorthEastSouthWestCursor"; break;
14030 case RGFW_mouseResizeNE: cursorSelectorStr = "_windowResizeNorthEastSouthWestCursor"; break;
14031 case RGFW_mouseResizeSW: cursorSelectorStr = "_windowResizeNorthEastSouthWestCursor"; break;
14032 case RGFW_mouseResizeAll: cursorSelectorStr = "openHandCursor"; break;
14033 case RGFW_mouseNotAllowed: cursorSelectorStr = "operationNotAllowedCursor"; break;
14034 case RGFW_mouseWait: cursorSelectorStr = "arrowCursor"; break;
14035 case RGFW_mouseProgress: cursorSelectorStr = "arrowCursor"; break;
14036 default:
14037 return RGFW_FALSE;
14038 }
14039
14040 id mouse = NSCursor_arrowStr(cursorSelectorStr);
14041
14042 if (mouse == NULL)
14043 return RGFW_FALSE;
14044
14045 RGFW_UNUSED(win);
14046 CGDisplayShowCursor(kCGDirectMainDisplay);
14047 objc_msgSend_void(mouse, sel_registerName("set"));
14048 win->src.mouse = mouse;
14049
14050 return RGFW_TRUE;
14051}
14052
14053void RGFW_window_setRawMouseModePlatform(RGFW_window* win, RGFW_bool state) {
14054 RGFW_UNUSED(win); RGFW_UNUSED(state);
14055}
14056
14057void RGFW_window_captureMousePlatform(RGFW_window* win, RGFW_bool state) {
14058 RGFW_UNUSED(win);
14059 CGAssociateMouseAndMouseCursorPosition(!(state == RGFW_TRUE));
14060}
14061
14062void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y) {
14063 RGFW_UNUSED(win);
14064
14065 win->internal.lastMouseX = x - win->x;
14066 win->internal.lastMouseY = y - win->y;
14067 CGWarpMouseCursorPosition((CGPoint){(CGFloat)x, (CGFloat)y});
14068}
14069
14070
14071void RGFW_window_hide(RGFW_window* win) {
14072 objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), false);
14073}
14074
14075void RGFW_window_show(RGFW_window* win) {
14076 if (win->internal.flags & RGFW_windowFocusOnShow)
14077 ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("makeKeyAndOrderFront:"), NULL);
14078
14079 ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("orderFront:"), NULL);
14080 objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), true);
14081}
14082
14083void RGFW_window_flash(RGFW_window* win, RGFW_flashRequest request) {
14084 if (RGFW_window_isInFocus(win) && request) {
14085 return;
14086 }
14087
14088 id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
14089 pool = objc_msgSend_id(pool, sel_registerName("init"));
14090
14091 if (_RGFW->flash) {
14092 ((void (*)(id, SEL, NSInteger))objc_msgSend) ((id)_RGFW->NSApp, sel_registerName("cancelUserAttentionRequest:"), _RGFW->flash);
14093 }
14094
14095 switch (request) {
14096 case RGFW_flashBriefly:
14097 _RGFW->flash = ((NSInteger (*)(id, SEL, NSInteger))objc_msgSend) ((id)_RGFW->NSApp, sel_registerName("requestUserAttention:"), NSInformationalRequest);
14098 break;
14099 case RGFW_flashUntilFocused:
14100 _RGFW->flash = ((NSInteger (*)(id, SEL, NSInteger))objc_msgSend) ((id)_RGFW->NSApp, sel_registerName("requestUserAttention:"), NSCriticalRequest);
14101 break;
14102 default: break;
14103 }
14104
14105 objc_msgSend_bool_void(pool, sel_registerName("drain"));
14106}
14107
14108RGFW_bool RGFW_window_isHidden(RGFW_window* win) {
14109 RGFW_ASSERT(win != NULL);
14110
14111 bool visible = objc_msgSend_bool(win->src.window, sel_registerName("isVisible"));
14112 return visible == NO && !RGFW_window_isMinimized(win);
14113}
14114
14115RGFW_bool RGFW_window_isMinimized(RGFW_window* win) {
14116 RGFW_ASSERT(win != NULL);
14117
14118 return objc_msgSend_bool(win->src.window, sel_registerName("isMiniaturized")) == YES;
14119}
14120
14121RGFW_bool RGFW_window_isMaximized(RGFW_window* win) {
14122 RGFW_ASSERT(win != NULL);
14123 RGFW_bool b = (RGFW_bool)objc_msgSend_bool(win->src.window, sel_registerName("isZoomed"));
14124 return b;
14125}
14126
14127RGFWDEF id RGFW_getNSScreenForDisplayUInt(u32 uintNum);
14128id RGFW_getNSScreenForDisplayUInt(u32 uintNum) {
14129 Class NSScreenClass = objc_getClass("NSScreen");
14130
14131 id screens = objc_msgSend_id(NSScreenClass, sel_registerName("screens"));
14132
14133 NSUInteger count = (NSUInteger)objc_msgSend_uint(screens, sel_registerName("count"));
14134 NSUInteger i;
14135 for (i = 0; i < count; i++) {
14136 id screen = ((id (*)(id, SEL, int))objc_msgSend) (screens, sel_registerName("objectAtIndex:"), (int)i);
14137 id description = objc_msgSend_id(screen, sel_registerName("deviceDescription"));
14138 id screenNumberKey = NSString_stringWithUTF8String("NSScreenNumber");
14139 id screenNumber = objc_msgSend_id_id(description, sel_registerName("objectForKey:"), screenNumberKey);
14140
14141 if (CGDisplayUnitNumber((CGDirectDisplayID)objc_msgSend_uint(screenNumber, sel_registerName("unsignedIntValue"))) == uintNum) {
14142 return screen;
14143 }
14144 }
14145
14146 return NULL;
14147}
14148
14149float RGFW_osx_getRefreshRate(CGDirectDisplayID display, CGDisplayModeRef mode);
14150float RGFW_osx_getRefreshRate(CGDirectDisplayID display, CGDisplayModeRef mode) {
14151 if (mode) {
14152 float refreshRate = (float)CGDisplayModeGetRefreshRate(mode);
14153 if (refreshRate != 0) return refreshRate;
14154 }
14155
14156#ifndef RGFW_NO_IOKIT
14157 float res = RGFW_osx_getFallbackRefreshRate(display);
14158 if (res != 0) return res;
14159#else
14160 RGFW_UNUSED(display);
14161#endif
14162 return 60;
14163}
14164
14165void RGFW_pollMonitors(void) {
14166 static CGDirectDisplayID displays[RGFW_MAX_MONITORS];
14167 u32 count;
14168
14169 if (CGGetActiveDisplayList(RGFW_MAX_MONITORS, displays, &count) != kCGErrorSuccess) {
14170 return;
14171 }
14172
14173 if (count > RGFW_MAX_MONITORS) count = RGFW_MAX_MONITORS;
14174
14175 for (RGFW_monitorNode* node = _RGFW->monitors.list.head; node; node = node->next) {
14176 node->disconnected = RGFW_TRUE;
14177 }
14178
14179 CGDirectDisplayID primary = CGMainDisplayID();
14180
14181 u32 i;
14182 for (i = 0; i < count; i++) {
14183 RGFW_monitor monitor;
14184
14185 u32 uintNum = CGDisplayUnitNumber(displays[i]);
14186 id screen = RGFW_getNSScreenForDisplayUInt(uintNum);
14187
14188 RGFW_monitorNode* node;
14189 for (node = _RGFW->monitors.list.head; node; node = node->next) {
14190 if (node->uintNum == uintNum) break;
14191 }
14192
14193 if (node) {
14194 node->screen = (void*)screen;
14195 node->display = displays[i];
14196 node->disconnected = RGFW_FALSE;
14197 if (displays[i] == primary) {
14198 _RGFW->monitors.primary = node;
14199 }
14200 continue;
14201 }
14202
14203 const char name[] = "MacOS\0";
14204 RGFW_MEMCPY(monitor.name, name, 6);
14205
14206 CGRect bounds = CGDisplayBounds(displays[i]);
14207 monitor.x = (i32)bounds.origin.x;
14208 monitor.y = (i32)RGFW_cocoaYTransform((float)(bounds.origin.y + bounds.size.height - 1));
14209
14210 CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displays[i]);
14211 monitor.mode.w = (i32)CGDisplayModeGetWidth(mode);
14212 monitor.mode.h = (i32)CGDisplayModeGetHeight(mode);
14213 monitor.mode.src = (void*)mode;
14214 monitor.mode.red = 8; monitor.mode.green = 8; monitor.mode.blue = 8;
14215
14216 monitor.mode.refreshRate = RGFW_osx_getRefreshRate(displays[i], mode);
14217 CFRelease(mode);
14218
14219 CGSize screenSizeMM = CGDisplayScreenSize(displays[i]);
14220 monitor.physW = (float)screenSizeMM.width / 25.4f;
14221 monitor.physH = (float)screenSizeMM.height / 25.4f;
14222
14223 float ppi_width = ((float)monitor.mode.w / monitor.physW);
14224 float ppi_height = ((float)monitor.mode.h / monitor.physH);
14225
14226 monitor.pixelRatio = (float)((CGFloat (*)(id, SEL))abi_objc_msgSend_fpret) (screen, sel_registerName("backingScaleFactor"));
14227 float dpi = 96.0f * monitor.pixelRatio;
14228
14229 monitor.scaleX = ((((float) (ppi_width) / dpi) * 10.0f)) / 10.0f;
14230 monitor.scaleY = ((((float) (ppi_height) / dpi) * 10.0f)) / 10.0f;
14231
14232 node = RGFW_monitors_add(&monitor);
14233
14234 node->screen = (void*)screen;
14235 node->uintNum = uintNum;
14236 node->display = displays[i];
14237
14238 if (displays[i] == primary) {
14239 _RGFW->monitors.primary = node;
14240 }
14241
14242 RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_TRUE);
14243 }
14244
14245 RGFW_monitors_refresh();
14246}
14247
14248RGFW_bool RGFW_monitor_getWorkarea(RGFW_monitor* monitor, i32* x, i32* y, i32* width, i32* height) {
14249 NSRect frameRect = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)monitor->node->screen, sel_registerName("visibleFrame"));
14250
14251 if (x) *x = (i32)frameRect.origin.x;
14252 if (y) *y = (i32)RGFW_cocoaYTransform((float)(frameRect.origin.y + frameRect.size.height - (double)1.0f));
14253 if (width) *width = (i32)frameRect.size.width;
14254 if (height) *height = (i32)frameRect.size.height;
14255
14256 return RGFW_TRUE;
14257}
14258
14259size_t RGFW_monitor_getGammaRampPtr(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
14260 id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
14261 pool = objc_msgSend_id(pool, sel_registerName("init"));
14262
14263 u32 size = CGDisplayGammaTableCapacity(monitor->node->display);
14264 CGGammaValue* values = (CGGammaValue*)RGFW_ALLOC(size * 3 * sizeof(CGGammaValue));
14265
14266 CGGetDisplayTransferByTable(monitor->node->display, size, values, values + size, values + size * 2, &size);
14267
14268 for (u32 i = 0; ramp && i < size; i++) {
14269 ramp->red[i] = (u16) (values[i] * 65535);
14270 ramp->green[i] = (u16) (values[i + size] * 65535);
14271 ramp->blue[i] = (u16) (values[i + size * 2] * 65535);
14272 }
14273
14274 RGFW_FREE(values);
14275
14276 objc_msgSend_bool_void(pool, sel_registerName("drain"));
14277 return size;
14278}
14279
14280RGFW_bool RGFW_monitor_setGammaRamp(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
14281 id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
14282 pool = objc_msgSend_id(pool, sel_registerName("init"));
14283
14284 CGGammaValue* values = (CGGammaValue*)RGFW_ALLOC(ramp->count * 3 * sizeof(CGGammaValue));
14285
14286 for (u32 i = 0; i < ramp->count; i++) {
14287 values[i] = ramp->red[i] / 65535.f;
14288 values[i + ramp->count] = ramp->green[i] / 65535.f;
14289 values[i + ramp->count * 2] = ramp->blue[i] / 65535.f;
14290 }
14291
14292 CGSetDisplayTransferByTable(monitor->node->display, (u32)ramp->count, values, values + ramp->count, values + ramp->count * 2);
14293
14294 RGFW_FREE(values);
14295
14296 objc_msgSend_bool_void(pool, sel_registerName("drain"));
14297
14298 return RGFW_TRUE;
14299}
14300
14301size_t RGFW_monitor_getModesPtr(RGFW_monitor* mon, RGFW_monitorMode** modes) {
14302 CGDirectDisplayID display = mon->node->display;
14303 CFArrayRef allModes = CGDisplayCopyAllDisplayModes(display, NULL);
14304
14305 if (allModes == NULL) {
14306 return RGFW_FALSE;
14307 }
14308
14309 size_t count = (size_t)CFArrayGetCount(allModes);
14310
14311 CFIndex i;
14312 for (i = 0; i < (CFIndex)count && modes; i++) {
14313 CGDisplayModeRef cmode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, i);
14314
14315 RGFW_monitorMode foundMode;
14316 foundMode.w = (i32)CGDisplayModeGetWidth(cmode);
14317 foundMode.h = (i32)CGDisplayModeGetHeight(cmode);
14318 foundMode.refreshRate = RGFW_osx_getRefreshRate(display, cmode);
14319 foundMode.red = 8; foundMode.green = 8; foundMode.blue = 8;
14320 foundMode.src = (void*)cmode;
14321 (*modes)[i] = foundMode;
14322 }
14323
14324 CFRelease(allModes);
14325 return count;
14326}
14327
14328RGFW_bool RGFW_monitor_setMode(RGFW_monitor* mon, RGFW_monitorMode* mode) {
14329 if (CGDisplaySetDisplayMode(mon->node->display, (CGDisplayModeRef)mode->src, NULL) == kCGErrorSuccess) {
14330 return RGFW_TRUE;
14331 }
14332
14333 return RGFW_FALSE;
14334}
14335
14336RGFW_bool RGFW_monitor_requestMode(RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request) {
14337 CGDirectDisplayID display = mon->node->display;
14338 CFArrayRef allModes = CGDisplayCopyAllDisplayModes(display, NULL);
14339
14340 if (allModes == NULL) {
14341 return RGFW_FALSE;
14342 }
14343
14344 CGDisplayModeRef native = NULL;
14345
14346 CFIndex i;
14347 for (i = 0; i < CFArrayGetCount(allModes); i++) {
14348 CGDisplayModeRef cmode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, i);
14349
14350 RGFW_monitorMode foundMode;
14351 foundMode.w = (i32)CGDisplayModeGetWidth(cmode);
14352 foundMode.h = (i32)CGDisplayModeGetHeight(cmode);
14353 foundMode.refreshRate = RGFW_osx_getRefreshRate(display, cmode);
14354 foundMode.red = 8; foundMode.green = 8; foundMode.blue = 8;
14355 foundMode.src = (void*)cmode;
14356
14357 if (RGFW_monitorModeCompare(mode, &foundMode, request)) {
14358 native = cmode;
14359 mon->mode = foundMode;
14360 break;
14361 }
14362 }
14363
14364 CFRelease(allModes);
14365
14366 if (native) {
14367 if (CGDisplaySetDisplayMode(display, native, NULL) == kCGErrorSuccess) {
14368 return RGFW_TRUE;
14369 }
14370 }
14371
14372 return RGFW_FALSE;
14373}
14374
14375RGFW_monitor* RGFW_window_getMonitor(RGFW_window* win) {
14376 id screen = objc_msgSend_id(win->src.window, sel_registerName("screen"));
14377 id description = objc_msgSend_id(screen, sel_registerName("deviceDescription"));
14378 id screenNumberKey = NSString_stringWithUTF8String("NSScreenNumber");
14379 id screenNumber = objc_msgSend_id_id(description, sel_registerName("objectForKey:"), screenNumberKey);
14380
14381 CGDirectDisplayID display = (CGDirectDisplayID)objc_msgSend_uint(screenNumber, sel_registerName("unsignedIntValue"));
14382
14383 RGFW_monitorNode* node = _RGFW->monitors.list.head;
14384 for (node = _RGFW->monitors.list.head; node; node = node->next) {
14385 if (node->display == display && (id)node->screen == screen) {
14386 break;
14387 }
14388 }
14389
14390 return &node->mon;
14391}
14392
14393RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) {
14394 size_t clip_len;
14395 char* clip = (char*)NSPasteboard_stringForType(NSPasteboard_generalPasteboard(), NSPasteboardTypeString, &clip_len);
14396 if (clip == NULL) return -1;
14397
14398 if (str != NULL) {
14399 if (strCapacity < clip_len)
14400 return 0;
14401
14402 RGFW_MEMCPY(str, clip, clip_len);
14403
14404 str[clip_len] = '\0';
14405 }
14406
14407 return (RGFW_ssize_t)clip_len;
14408}
14409
14410void RGFW_writeClipboard(const char* text, u32 textLen) {
14411 RGFW_UNUSED(textLen);
14412
14413 NSPasteboardType array[] = { NSPasteboardTypeString, NULL };
14414 NSPasteBoard_declareTypes(NSPasteboard_generalPasteboard(), array, 1, NULL);
14415
14416 SEL func = sel_registerName("setString:forType:");
14417 ((bool (*)(id, SEL, id, id))objc_msgSend)
14418 (NSPasteboard_generalPasteboard(), func, NSString_stringWithUTF8String(text), NSString_stringWithUTF8String((const char*)NSPasteboardTypeString));
14419}
14420
14421#ifdef RGFW_OPENGL
14422void NSOpenGLContext_setValues(id context, const int* vals, NSOpenGLContextParameter param);
14423void NSOpenGLContext_setValues(id context, const int* vals, NSOpenGLContextParameter param) {
14424 ((void (*)(id, SEL, const int*, NSOpenGLContextParameter))objc_msgSend)
14425 (context, sel_registerName("setValues:forParameter:"), vals, param);
14426}
14427
14428
14429/* MacOS OpenGL API spares us yet again (there are no extensions) */
14430RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char * extension, size_t len) { RGFW_UNUSED(extension); RGFW_UNUSED(len); return RGFW_FALSE; }
14431
14432RGFW_proc RGFW_getProcAddress_OpenGL(const char* procname) {
14433 static CFBundleRef RGFWnsglFramework = NULL;
14434 if (RGFWnsglFramework == NULL)
14435 RGFWnsglFramework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
14436
14437 CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault, procname, kCFStringEncodingASCII);
14438
14439 RGFW_proc symbol = (RGFW_proc)CFBundleGetFunctionPointerForName(RGFWnsglFramework, symbolName);
14440
14441 CFRelease(symbolName);
14442
14443 return symbol;
14444}
14445
14446RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints) {
14447 win->src.ctx.native = ctx;
14448 win->src.gfxType = RGFW_gfxNativeOpenGL;
14449
14450 i32 attribs[40];
14451 size_t render_type_index = 0;
14452 {
14453 RGFW_attribStack stack;
14454 RGFW_attribStack_init(&stack, attribs, 40);
14455
14456 i32 colorBits = (i32)(hints->red + hints->green + hints->blue + hints->alpha) / 4;
14457 RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAColorSize, colorBits);
14458
14459 RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAAlphaSize, hints->alpha);
14460 RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFADepthSize, hints->depth);
14461 RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAStencilSize, hints->stencil);
14462 RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAAuxBuffers, hints->auxBuffers);
14463 RGFW_attribStack_pushAttrib(&stack, NSOpenGLPFAClosestPolicy);
14464 if (hints->samples) {
14465 RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFASampleBuffers, 1);
14466 RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFASamples, hints->samples);
14467 } else RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFASampleBuffers, 0);
14468
14469 if (hints->doubleBuffer)
14470 RGFW_attribStack_pushAttrib(&stack, NSOpenGLPFADoubleBuffer);
14471
14472 #ifdef RGFW_COCOA_GRAPHICS_SWITCHING
14473 RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAAllowOfflineRenderers, kCGLPFASupportsAutomaticGraphicsSwitching);
14474 #endif
14475 #if MAC_OS_X_VERSION_MAX_ALLOWED < 101200
14476 if (hints->stereo) RGFW_attribStack_pushAttrib(&stack, NSOpenGLPFAStereo);
14477 #endif
14478
14479 /* 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? */
14480 RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAOpenGLProfile,
14481 (hints->major >= 4) ? NSOpenGLProfileVersion4_1Core : (hints->major >= 3) ?
14482 NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy);
14483
14484 if (hints->major <= 2) {
14485 i32 accumSize = (i32)(hints->accumRed + hints->accumGreen + hints->accumBlue + hints->accumAlpha) / 4;
14486 RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAAccumSize, accumSize);
14487 }
14488
14489 if (hints->renderer == RGFW_glSoftware) {
14490 RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFARendererID, kCGLRendererGenericFloatID);
14491 } else {
14492 RGFW_attribStack_pushAttrib(&stack, NSOpenGLPFAAccelerated);
14493 }
14494 render_type_index = stack.count - 1;
14495
14496 RGFW_attribStack_pushAttribs(&stack, 0, 0);
14497 }
14498
14499 void* format = (void*) ((id(*)(id, SEL, const u32*))objc_msgSend) (NSAlloc((id)objc_getClass("NSOpenGLPixelFormat")), sel_registerName("initWithAttributes:"), (u32*)attribs);
14500 if (format == NULL) {
14501 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load pixel format for OpenGL");
14502
14503 assert(render_type_index + 3 < (sizeof(attribs) / sizeof(attribs[0])));
14504 attribs[render_type_index] = NSOpenGLPFARendererID;
14505 attribs[render_type_index + 1] = kCGLRendererGenericFloatID;
14506 attribs[render_type_index + 3] = 0;
14507
14508 format = (void*) ((id(*)(id, SEL, const u32*))objc_msgSend) (NSAlloc((id)objc_getClass("NSOpenGLPixelFormat")), sel_registerName("initWithAttributes:"), (u32*)attribs);
14509 if (format == NULL)
14510 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "and loading software rendering OpenGL failed");
14511 else
14512 RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, "Switching to software rendering");
14513 }
14514
14515 /* the pixel format can be passed directly to OpenGL context creation to create a context
14516 this is because the format also includes information about the OpenGL version (which may be a bad thing) */
14517
14518 if (win->src.view)
14519 NSRelease(win->src.view);
14520 win->src.view = (id) ((id(*)(id, SEL, NSRect, u32*))objc_msgSend) (NSAlloc(_RGFW->customViewClasses[1]),
14521 sel_registerName("initWithFrame:pixelFormat:"), (NSRect){{0, 0}, {(double)win->w, (double)win->h}}, (u32*)format);
14522
14523 id share = NULL;
14524 if (hints->share) {
14525 share = (id)hints->share->ctx;
14526 }
14527
14528 win->src.ctx.native->ctx = ((id (*)(id, SEL, id, id))objc_msgSend)(NSAlloc(objc_getClass("NSOpenGLContext")),
14529 sel_registerName("initWithFormat:shareContext:"),
14530 (id)format, share);
14531
14532 win->src.ctx.native->format = format;
14533
14534 objc_msgSend_void_id(win->src.view, sel_registerName("setOpenGLContext:"), win->src.ctx.native->ctx);
14535 if (win->internal.flags & RGFW_windowTransparent) {
14536 i32 opacity = 0;
14537 #define NSOpenGLCPSurfaceOpacity 236
14538 NSOpenGLContext_setValues((id)win->src.ctx.native->ctx, &opacity, (NSOpenGLContextParameter)NSOpenGLCPSurfaceOpacity);
14539
14540 }
14541
14542 objc_msgSend_void(win->src.ctx.native->ctx, sel_registerName("makeCurrentContext"));
14543
14544 objc_msgSend_void_id((id)win->src.window, sel_registerName("setContentView:"), win->src.view);
14545 objc_msgSend_void_bool(win->src.view, sel_registerName("setWantsLayer:"), true);
14546 objc_msgSend_int((id)win->src.view, sel_registerName("setLayerContentsPlacement:"), 4);
14547
14548 RGFW_window_swapInterval_OpenGL(win, 0);
14549
14550 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized.");
14551 return RGFW_TRUE;
14552}
14553
14554void RGFW_window_deleteContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx) {
14555 objc_msgSend_void(ctx->format, sel_registerName("release"));
14556 win->src.ctx.native->format = NULL;
14557
14558 objc_msgSend_void(ctx->ctx, sel_registerName("release"));
14559 win->src.ctx.native->ctx = NULL;
14560 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context freed.");
14561}
14562
14563void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win) {
14564 if (win) RGFW_ASSERT(win->src.ctx.native);
14565 if (win != NULL)
14566 objc_msgSend_void(win->src.ctx.native->ctx, sel_registerName("makeCurrentContext"));
14567 else
14568 objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("clearCurrentContext"));
14569}
14570void* RGFW_getCurrentContext_OpenGL(void) {
14571 return objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("currentContext"));
14572}
14573
14574void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) {
14575 RGFW_ASSERT(win && win->src.ctx.native);
14576 objc_msgSend_void(win->src.ctx.native->ctx, sel_registerName("flushBuffer"));
14577}
14578void RGFW_window_swapInterval_OpenGL(RGFW_window* win, i32 swapInterval) {
14579 RGFW_ASSERT(win != NULL && win->src.ctx.native != NULL);
14580 NSOpenGLContext_setValues((id)win->src.ctx.native->ctx, &swapInterval, (NSOpenGLContextParameter)222);
14581}
14582#endif
14583
14584void RGFW_deinitPlatform(void) {
14585 objc_msgSend_void_id(_RGFW->NSApp, sel_registerName("setDelegate:"), NULL);
14586
14587 objc_msgSend_void_id(_RGFW->NSApp, sel_registerName("stop:"), NULL);
14588 NSRelease(_RGFW->NSApp);
14589 _RGFW->NSApp = NULL;
14590
14591 NSRelease(_RGFW->customNSAppDelegate);
14592
14593 _RGFW->customNSAppDelegate = NULL;
14594
14595 objc_disposeClassPair((Class)_RGFW->customViewClasses[0]);
14596 objc_disposeClassPair((Class)_RGFW->customViewClasses[1]);
14597 objc_disposeClassPair((Class)_RGFW->customWindowDelegateClass);
14598 objc_disposeClassPair((Class)_RGFW->customNSAppDelegateClass);
14599}
14600
14601void RGFW_window_closePlatform(RGFW_window* win) {
14602 objc_msgSend_void_id((id)win->src.window, sel_registerName("setDelegate:"), NULL);
14603 NSRelease((id)win->src.delegate);
14604 NSRelease(win->src.view);
14605
14606 objc_msgSend_id(win->src.window, sel_registerName("close"));
14607 NSRelease(win->src.window);
14608}
14609
14610#ifdef RGFW_VULKAN
14611VkResult RGFW_window_createSurface_Vulkan(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface) {
14612 RGFW_ASSERT(win != NULL); RGFW_ASSERT(instance);
14613 RGFW_ASSERT(surface != NULL);
14614
14615 *surface = VK_NULL_HANDLE;
14616 id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
14617 pool = objc_msgSend_id(pool, sel_registerName("init"));
14618
14619 id nsView = (id)win->src.view;
14620 if (!nsView) {
14621 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errMetal, "NSView is NULL for macOS window");
14622 return -1;
14623 }
14624
14625
14626 id layer = ((id (*)(id, SEL))objc_msgSend)(nsView, sel_registerName("layer"));
14627
14628 void* metalLayer = RGFW_getLayer_OSX();
14629 if (metalLayer == NULL) {
14630 return -1;
14631 }
14632 ((void (*)(id, SEL, id))objc_msgSend)((id)nsView, sel_registerName("setLayer:"), metalLayer);
14633 ((void (*)(id, SEL, BOOL))objc_msgSend)(nsView, sel_registerName("setWantsLayer:"), YES);
14634
14635 VkResult result;
14636/*
14637 VkMetalSurfaceCreateInfoEXT macos;
14638 macos.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
14639 macos.slayer = metalLayer;
14640 RGFW_MEMSET(&macos, 0, sizeof(macos));
14641 result = vkCreateMacOSSurfaceMVK(instance, &macos, NULL, surface);
14642*/
14643
14644 VkMacOSSurfaceCreateInfoMVK macos;
14645 RGFW_MEMSET(&macos, 0, sizeof(macos));
14646 macos.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
14647 macos.pView = nsView;
14648
14649 result = vkCreateMacOSSurfaceMVK(instance, &macos, NULL, surface);
14650
14651 objc_msgSend_bool_void(pool, sel_registerName("drain"));
14652
14653 return result;
14654}
14655#endif
14656
14657#ifdef RGFW_WEBGPU
14658WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance instance) {
14659 WGPUSurfaceDescriptor surfaceDesc = {0};
14660 id* nsView = (id*)window->src.view;
14661 if (!nsView) {
14662 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errMetal, "NSView is NULL for macOS window");
14663 return NULL;
14664 }
14665
14666 ((void (*)(id, SEL, BOOL))objc_msgSend)(nsView, sel_registerName("setWantsLayer:"), YES);
14667 id layer = ((id (*)(id, SEL))objc_msgSend)(nsView, sel_registerName("layer"));
14668
14669 void* metalLayer = RGFW_getLayer_OSX();
14670 if (metalLayer == NULL) {
14671 return NULL;
14672 }
14673 ((void (*)(id, SEL, id))objc_msgSend)((id)nsView, sel_registerName("setLayer:"), metalLayer);
14674 layer = metalLayer;
14675
14676 WGPUSurfaceSourceMetalLayer fromMetal = {0};
14677 fromMetal.chain.sType = WGPUSType_SurfaceSourceMetalLayer;
14678#ifdef __OBJC__
14679 fromMetal.layer = (__bridge CAMetalLayer*)layer; /* Use __bridge for ARC compatibility if mixing C/Obj-C */
14680#else
14681 fromMetal.layer = layer;
14682#endif
14683
14684 surfaceDesc.nextInChain = (WGPUChainedStruct*)&fromMetal.chain;
14685 return wgpuInstanceCreateSurface(instance, &surfaceDesc);
14686}
14687#endif
14688
14689#endif /* RGFW_MACOS */
14690
14691/*
14692 End of MaOS defines
14693*/
14694
14695/*
14696 WASM defines
14697*/
14698
14699#ifdef RGFW_WASM
14700EM_BOOL Emscripten_on_resize(int eventType, const EmscriptenUiEvent* E, void* userData) {
14701 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
14702 RGFW_windowResizedCallback(_RGFW->root, E->windowInnerWidth, E->windowInnerHeight);
14703 return EM_TRUE;
14704}
14705
14706EM_BOOL Emscripten_on_fullscreenchange(int eventType, const EmscriptenFullscreenChangeEvent* E, void* userData) {
14707 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
14708
14709 if (!(_RGFW->root->internal.enabledEvents & RGFW_windowResizedFlag)) return EM_TRUE;
14710
14711 static u8 fullscreen = RGFW_FALSE;
14712 static i32 originalW, originalH;
14713
14714 if (fullscreen == RGFW_FALSE) {
14715 originalW = _RGFW->root->w;
14716 originalH = _RGFW->root->h;
14717 }
14718
14719 fullscreen = !fullscreen;
14720 _RGFW->root->w = E->screenWidth;
14721 _RGFW->root->h = E->screenHeight;
14722
14723 EM_ASM("Module.canvas.focus();");
14724
14725 if (fullscreen == RGFW_FALSE) {
14726 _RGFW->root->w = originalW;
14727 _RGFW->root->h = originalH;
14728 } else {
14729 #if __EMSCRIPTEN_major__ >= 1 && __EMSCRIPTEN_minor__ >= 29 && __EMSCRIPTEN_tiny__ >= 0
14730 EmscriptenFullscreenStrategy FSStrat = {0};
14731 FSStrat.scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH;
14732 FSStrat.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF;
14733 FSStrat.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT;
14734 emscripten_request_fullscreen_strategy("#canvas", 1, &FSStrat);
14735 #else
14736 emscripten_request_fullscreen("#canvas", 1);
14737 #endif
14738 }
14739
14740 emscripten_set_canvas_element_size("#canvas", _RGFW->root->w, _RGFW->root->h);
14741 RGFW_windowResizedCallback(_RGFW->root, _RGFW->root->w, _RGFW->root->h);
14742 return EM_TRUE;
14743}
14744
14745EM_BOOL Emscripten_on_focusin(int eventType, const EmscriptenFocusEvent* E, void* userData) {
14746 RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(E);
14747
14748 RGFW_focusCallback(_RGFW->root, 1);
14749 return EM_TRUE;
14750}
14751
14752EM_BOOL Emscripten_on_focusout(int eventType, const EmscriptenFocusEvent* E, void* userData) {
14753 RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(E);
14754
14755 RGFW_focusCallback(_RGFW->root, 0);
14756 return EM_TRUE;
14757}
14758
14759EM_BOOL Emscripten_on_mousemove(int eventType, const EmscriptenMouseEvent* E, void* userData) {
14760 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
14761 RGFW_mousePosCallback(_RGFW->root, E->targetX, E->targetY, E->movementX, E->movementY);
14762 return EM_TRUE;
14763}
14764
14765EM_BOOL Emscripten_on_mousedown(int eventType, const EmscriptenMouseEvent* E, void* userData) {
14766 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
14767
14768 int button = E->button;
14769 if (button > 2)
14770 button += 2;
14771
14772 RGFW_mouseButtonCallback(_RGFW->root, button, 1);
14773 return EM_TRUE;
14774}
14775
14776EM_BOOL Emscripten_on_mouseup(int eventType, const EmscriptenMouseEvent* E, void* userData) {
14777 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
14778
14779 int button = E->button;
14780 if (button > 2)
14781 button += 2;
14782
14783 RGFW_mouseButtonCallback(_RGFW->root, button, 0);
14784 return EM_TRUE;
14785}
14786
14787EM_BOOL Emscripten_on_wheel(int eventType, const EmscriptenWheelEvent* E, void* userData) {
14788 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
14789
14790 RGFW_mouseScrollCallback(_RGFW->root, E->deltaX, E->deltaY);
14791
14792 return EM_TRUE;
14793}
14794
14795EM_BOOL Emscripten_on_touchstart(int eventType, const EmscriptenTouchEvent* E, void* userData) {
14796 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
14797
14798 if (!(_RGFW->root->internal.enabledEvents & RGFW_mouseButtonPressedFlag)) return EM_TRUE;
14799
14800 size_t i;
14801 for (i = 0; i < (size_t)E->numTouches; i++) {
14802 RGFW_mousePosCallback(_RGFW->root, E->touches[i].targetX, E->touches[i].targetY, 0, 0);
14803 RGFW_mouseButtonCallback(_RGFW->root, RGFW_mouseLeft, 1);
14804 }
14805
14806 return EM_TRUE;
14807}
14808
14809EM_BOOL Emscripten_on_touchmove(int eventType, const EmscriptenTouchEvent* E, void* userData) {
14810 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
14811
14812 if (!(_RGFW->root->internal.enabledEvents & RGFW_mousePosChangedFlag)) return EM_TRUE;
14813
14814 size_t i;
14815 for (i = 0; i < (size_t)E->numTouches; i++) {
14816 RGFW_mousePosCallback(_RGFW->root, E->touches[i].targetX, E->touches[i].targetY, 0, 0);
14817 }
14818 return EM_TRUE;
14819}
14820
14821EM_BOOL Emscripten_on_touchend(int eventType, const EmscriptenTouchEvent* E, void* userData) {
14822 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
14823
14824 if (!(_RGFW->root->internal.enabledEvents & RGFW_mouseButtonReleasedFlag)) return EM_TRUE;
14825
14826 size_t i;
14827 for (i = 0; i < (size_t)E->numTouches; i++) {
14828 RGFW_mousePosCallback(_RGFW->root, E->touches[i].targetX, E->touches[i].targetY, 0, 0);
14829 RGFW_mouseButtonCallback(_RGFW->root, RGFW_mouseLeft, 0);
14830 }
14831 return EM_TRUE;
14832}
14833
14834EM_BOOL Emscripten_on_touchcancel(int eventType, const EmscriptenTouchEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); return EM_TRUE; }
14835
14836RGFW_key RGFW_WASMPhysicalToRGFW(u32 hash);
14837
14838void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyEvent(char* code, u32 codepoint, RGFW_bool press) {
14839 const char* iCode = code;
14840
14841 u32 hash = 0;
14842 while(*iCode) hash = ((hash ^ 0x7E057D79U) << 3) ^ (unsigned int)*iCode++;
14843
14844 u32 physicalKey = RGFW_WASMPhysicalToRGFW(hash);
14845
14846 RGFW_keyCallback(_RGFW->root, physicalKey, _RGFW->root->internal.mod, RGFW_window_isKeyDown(_RGFW->root, (u8)physicalKey), press);
14847 if (press) {
14848; RGFW_keyCharCallback(_RGFW->root, codepoint);
14849 }
14850}
14851
14852void 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) {
14853 RGFW_updateKeyModsEx(_RGFW->root, capital, numlock, control, alt, shift, super, scroll);
14854}
14855
14856void EMSCRIPTEN_KEEPALIVE Emscripten_onDrop(size_t count) {
14857 RGFW_dataDropCallback(_RGFW->root, _RGFW->files, count);
14858}
14859
14860void RGFW_stopCheckEvents(void) {
14861 _RGFW->stopCheckEvents_bool = RGFW_TRUE;
14862}
14863
14864RGFW_bool RGFW_createSurfacePtr(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) {
14865 surface->data = data;
14866 surface->w = w;
14867 surface->h = h;
14868 surface->format = format;
14869 return RGFW_TRUE;
14870}
14871
14872void RGFW_window_blitSurface(RGFW_window* win, RGFW_surface* surface) {
14873 /* TODO: Needs fixing. */
14874 RGFW_copyImageData(surface->data, surface->w, RGFW_MIN(win->h, surface->h), RGFW_formatRGBA8, surface->data, surface->format, surface->convertFunc);
14875 EM_ASM_({
14876 var data = Module.HEAPU8.slice($0, $0 + $1 * $2 * 4);
14877 let context = document.getElementById("canvas").getContext("2d");
14878 let image = context.getImageData(0, 0, $1, $2);
14879 image.data.set(data);
14880 context.putImageData(image, 0, $4 - $2);
14881 }, surface->data, surface->w, surface->h, RGFW_MIN(win->h, surface->w), RGFW_MIN(win->h, surface->h));
14882}
14883
14884void RGFW_surface_freePtr(RGFW_surface* surface) { }
14885
14886void EMSCRIPTEN_KEEPALIVE RGFW_makeSetValue(size_t index, char* file) {
14887 /* This seems like a terrible idea, don't replicate this unless you hate yourself or the OS */
14888 /* TODO: find a better way to do this
14889 */
14890 RGFW_STRNCPY((char*)_RGFW->files[index], file, RGFW_MAX_PATH - 1);
14891 _RGFW->files[index][RGFW_MAX_PATH - 1] = '\0';
14892}
14893
14894#include <sys/stat.h>
14895#include <sys/types.h>
14896#include <errno.h>
14897#include <stdio.h>
14898
14899void EMSCRIPTEN_KEEPALIVE RGFW_mkdir(char* name) { mkdir(name, 0755); }
14900
14901void EMSCRIPTEN_KEEPALIVE RGFW_writeFile(const char *path, const char *data, size_t len) {
14902 FILE* file = fopen(path, "w+");
14903 if (file == NULL)
14904 return;
14905
14906 fwrite(data, sizeof(char), len, file);
14907 fclose(file);
14908}
14909
14910void RGFW_initKeycodesPlatform(void) {
14911 _RGFW->keycodes[DOM_VK_BACK_QUOTE] = RGFW_backtick;
14912 _RGFW->keycodes[DOM_VK_0] = RGFW_0;
14913 _RGFW->keycodes[DOM_VK_1] = RGFW_1;
14914 _RGFW->keycodes[DOM_VK_2] = RGFW_2;
14915 _RGFW->keycodes[DOM_VK_3] = RGFW_3;
14916 _RGFW->keycodes[DOM_VK_4] = RGFW_4;
14917 _RGFW->keycodes[DOM_VK_5] = RGFW_5;
14918 _RGFW->keycodes[DOM_VK_6] = RGFW_6;
14919 _RGFW->keycodes[DOM_VK_7] = RGFW_7;
14920 _RGFW->keycodes[DOM_VK_8] = RGFW_8;
14921 _RGFW->keycodes[DOM_VK_9] = RGFW_9;
14922 _RGFW->keycodes[DOM_VK_SPACE] = RGFW_space;
14923 _RGFW->keycodes[DOM_VK_A] = RGFW_a;
14924 _RGFW->keycodes[DOM_VK_B] = RGFW_b;
14925 _RGFW->keycodes[DOM_VK_C] = RGFW_c;
14926 _RGFW->keycodes[DOM_VK_D] = RGFW_d;
14927 _RGFW->keycodes[DOM_VK_E] = RGFW_e;
14928 _RGFW->keycodes[DOM_VK_F] = RGFW_f;
14929 _RGFW->keycodes[DOM_VK_G] = RGFW_g;
14930 _RGFW->keycodes[DOM_VK_H] = RGFW_h;
14931 _RGFW->keycodes[DOM_VK_I] = RGFW_i;
14932 _RGFW->keycodes[DOM_VK_J] = RGFW_j;
14933 _RGFW->keycodes[DOM_VK_K] = RGFW_k;
14934 _RGFW->keycodes[DOM_VK_L] = RGFW_l;
14935 _RGFW->keycodes[DOM_VK_M] = RGFW_m;
14936 _RGFW->keycodes[DOM_VK_N] = RGFW_n;
14937 _RGFW->keycodes[DOM_VK_O] = RGFW_o;
14938 _RGFW->keycodes[DOM_VK_P] = RGFW_p;
14939 _RGFW->keycodes[DOM_VK_Q] = RGFW_q;
14940 _RGFW->keycodes[DOM_VK_R] = RGFW_r;
14941 _RGFW->keycodes[DOM_VK_S] = RGFW_s;
14942 _RGFW->keycodes[DOM_VK_T] = RGFW_t;
14943 _RGFW->keycodes[DOM_VK_U] = RGFW_u;
14944 _RGFW->keycodes[DOM_VK_V] = RGFW_v;
14945 _RGFW->keycodes[DOM_VK_W] = RGFW_w;
14946 _RGFW->keycodes[DOM_VK_X] = RGFW_x;
14947 _RGFW->keycodes[DOM_VK_Y] = RGFW_y;
14948 _RGFW->keycodes[DOM_VK_Z] = RGFW_z;
14949 _RGFW->keycodes[DOM_VK_PERIOD] = RGFW_period;
14950 _RGFW->keycodes[DOM_VK_COMMA] = RGFW_comma;
14951 _RGFW->keycodes[DOM_VK_SLASH] = RGFW_slash;
14952 _RGFW->keycodes[DOM_VK_OPEN_BRACKET] = RGFW_bracket;
14953 _RGFW->keycodes[DOM_VK_CLOSE_BRACKET] = RGFW_closeBracket;
14954 _RGFW->keycodes[DOM_VK_SEMICOLON] = RGFW_semicolon;
14955 _RGFW->keycodes[DOM_VK_QUOTE] = RGFW_apostrophe;
14956 _RGFW->keycodes[DOM_VK_BACK_SLASH] = RGFW_backSlash;
14957 _RGFW->keycodes[DOM_VK_RETURN] = RGFW_return;
14958 _RGFW->keycodes[DOM_VK_DELETE] = RGFW_delete;
14959 _RGFW->keycodes[DOM_VK_NUM_LOCK] = RGFW_numLock;
14960 _RGFW->keycodes[DOM_VK_DIVIDE] = RGFW_kpSlash;
14961 _RGFW->keycodes[DOM_VK_MULTIPLY] = RGFW_kpMultiply;
14962 _RGFW->keycodes[DOM_VK_SUBTRACT] = RGFW_kpMinus;
14963 _RGFW->keycodes[DOM_VK_NUMPAD1] = RGFW_kp1;
14964 _RGFW->keycodes[DOM_VK_NUMPAD2] = RGFW_kp2;
14965 _RGFW->keycodes[DOM_VK_NUMPAD3] = RGFW_kp3;
14966 _RGFW->keycodes[DOM_VK_NUMPAD4] = RGFW_kp4;
14967 _RGFW->keycodes[DOM_VK_NUMPAD5] = RGFW_kp5;
14968 _RGFW->keycodes[DOM_VK_NUMPAD6] = RGFW_kp6;
14969 _RGFW->keycodes[DOM_VK_NUMPAD9] = RGFW_kp9;
14970 _RGFW->keycodes[DOM_VK_NUMPAD0] = RGFW_kp0;
14971 _RGFW->keycodes[DOM_VK_DECIMAL] = RGFW_kpPeriod;
14972 _RGFW->keycodes[DOM_VK_RETURN] = RGFW_kpReturn;
14973 _RGFW->keycodes[DOM_VK_HYPHEN_MINUS] = RGFW_minus;
14974 _RGFW->keycodes[DOM_VK_EQUALS] = RGFW_equals;
14975 _RGFW->keycodes[DOM_VK_BACK_SPACE] = RGFW_backSpace;
14976 _RGFW->keycodes[DOM_VK_TAB] = RGFW_tab;
14977 _RGFW->keycodes[DOM_VK_CAPS_LOCK] = RGFW_capsLock;
14978 _RGFW->keycodes[DOM_VK_SHIFT] = RGFW_shiftL;
14979 _RGFW->keycodes[DOM_VK_CONTROL] = RGFW_controlL;
14980 _RGFW->keycodes[DOM_VK_ALT] = RGFW_altL;
14981 _RGFW->keycodes[DOM_VK_META] = RGFW_superL;
14982 _RGFW->keycodes[DOM_VK_F1] = RGFW_F1;
14983 _RGFW->keycodes[DOM_VK_F2] = RGFW_F2;
14984 _RGFW->keycodes[DOM_VK_F3] = RGFW_F3;
14985 _RGFW->keycodes[DOM_VK_F4] = RGFW_F4;
14986 _RGFW->keycodes[DOM_VK_F5] = RGFW_F5;
14987 _RGFW->keycodes[DOM_VK_F6] = RGFW_F6;
14988 _RGFW->keycodes[DOM_VK_F7] = RGFW_F7;
14989 _RGFW->keycodes[DOM_VK_F8] = RGFW_F8;
14990 _RGFW->keycodes[DOM_VK_F9] = RGFW_F9;
14991 _RGFW->keycodes[DOM_VK_F10] = RGFW_F10;
14992 _RGFW->keycodes[DOM_VK_F11] = RGFW_F11;
14993 _RGFW->keycodes[DOM_VK_F12] = RGFW_F12;
14994 _RGFW->keycodes[DOM_VK_UP] = RGFW_up;
14995 _RGFW->keycodes[DOM_VK_DOWN] = RGFW_down;
14996 _RGFW->keycodes[DOM_VK_LEFT] = RGFW_left;
14997 _RGFW->keycodes[DOM_VK_RIGHT] = RGFW_right;
14998 _RGFW->keycodes[DOM_VK_INSERT] = RGFW_insert;
14999 _RGFW->keycodes[DOM_VK_END] = RGFW_end;
15000 _RGFW->keycodes[DOM_VK_PAGE_UP] = RGFW_pageUp;
15001 _RGFW->keycodes[DOM_VK_PAGE_DOWN] = RGFW_pageDown;
15002 _RGFW->keycodes[DOM_VK_ESCAPE] = RGFW_escape;
15003 _RGFW->keycodes[DOM_VK_HOME] = RGFW_home;
15004 _RGFW->keycodes[DOM_VK_SCROLL_LOCK] = RGFW_scrollLock;
15005 _RGFW->keycodes[DOM_VK_PRINTSCREEN] = RGFW_printScreen;
15006 _RGFW->keycodes[DOM_VK_PAUSE] = RGFW_pause;
15007 _RGFW->keycodes[DOM_VK_F13] = RGFW_F13;
15008 _RGFW->keycodes[DOM_VK_F14] = RGFW_F14;
15009 _RGFW->keycodes[DOM_VK_F15] = RGFW_F15;
15010 _RGFW->keycodes[DOM_VK_F16] = RGFW_F16;
15011 _RGFW->keycodes[DOM_VK_F17] = RGFW_F17;
15012 _RGFW->keycodes[DOM_VK_F18] = RGFW_F18;
15013 _RGFW->keycodes[DOM_VK_F19] = RGFW_F19;
15014 _RGFW->keycodes[DOM_VK_F20] = RGFW_F20;
15015 _RGFW->keycodes[DOM_VK_F21] = RGFW_F21;
15016 _RGFW->keycodes[DOM_VK_F22] = RGFW_F22;
15017 _RGFW->keycodes[DOM_VK_F23] = RGFW_F23;
15018 _RGFW->keycodes[DOM_VK_F24] = RGFW_F24;
15019}
15020
15021i32 RGFW_initPlatform(void) { return 0; }
15022
15023RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win) {
15024 emscripten_set_canvas_element_size("#canvas", win->w, win->h);
15025 emscripten_set_window_title(name);
15026
15027 /* load callbacks */
15028 emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_resize);
15029 emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, NULL, EM_FALSE, Emscripten_on_fullscreenchange);
15030 emscripten_set_mousemove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousemove);
15031 emscripten_set_touchstart_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchstart);
15032 emscripten_set_touchend_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchend);
15033 emscripten_set_touchmove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchmove);
15034 emscripten_set_touchcancel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchcancel);
15035 emscripten_set_mousedown_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousedown);
15036 emscripten_set_mouseup_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mouseup);
15037 emscripten_set_wheel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_wheel);
15038 emscripten_set_focusin_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusin);
15039 emscripten_set_focusout_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusout);
15040
15041 if (flags & RGFW_windowAllowDND) {
15042 win->internal.flags |= RGFW_windowAllowDND;
15043 }
15044
15045 EM_ASM({
15046 window.addEventListener("keydown",
15047 (event) => {
15048 var code = stringToNewUTF8(event.code);
15049 Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta"), event.getModifierState("ScrollLock"));
15050
15051 var codepoint = event.key.charCodeAt(0);
15052 if(codepoint < 0x7f && event.key.length > 1) {
15053 codepoint = 0;
15054 }
15055
15056 Module._RGFW_handleKeyEvent(code, codepoint, 1);
15057 _free(code);
15058 },
15059 true);
15060 window.addEventListener("keyup",
15061 (event) => {
15062 var code = stringToNewUTF8(event.code);
15063 Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta"), event.getModifierState("ScrollLock"));
15064 Module._RGFW_handleKeyEvent(code, 0, 0);
15065 _free(code);
15066 },
15067 true);
15068 });
15069
15070 EM_ASM({
15071 var canvas = document.getElementById('canvas');
15072 canvas.addEventListener('drop', function(e) {
15073 e.preventDefault();
15074 if (e.dataTransfer.file < 0)
15075 return;
15076
15077 var filenamesArray = [];
15078 var count = e.dataTransfer.files.length;
15079
15080 /* Read and save the files to emscripten's files */
15081 var drop_dir = '.rgfw_dropped_files';
15082 Module._RGFW_mkdir(drop_dir);
15083
15084 for (var i = 0; i < count; i++) {
15085 var file = e.dataTransfer.files[i];
15086
15087 var path = '/' + drop_dir + '/' + file.name.replace("//", '_');
15088 var reader = new FileReader();
15089
15090 reader.onloadend = (e) => {
15091 if (reader.readyState != 2) {
15092 out('failed to read dropped file: '+file.name+': '+reader.error);
15093 }
15094 else {
15095 var data = e.target.result;
15096
15097 Module._RGFW_writeFile(path, new Uint8Array(data), file.size);
15098 }
15099 };
15100
15101 reader.readAsArrayBuffer(file);
15102 /* This works weird on modern OpenGL */
15103 var filename = stringToNewUTF8(path);
15104
15105 filenamesArray.push(filename);
15106
15107 Module._RGFW_makeSetValue(i, filename);
15108 }
15109
15110 Module._Emscripten_onDrop(count);
15111
15112 for (var i = 0; i < count; i++) {
15113 _free(filenamesArray[i]);
15114 }
15115 }, true);
15116
15117 canvas.addEventListener('dragover', function(e) { e.preventDefault(); return false; }, true);
15118 });
15119
15120 return win;
15121}
15122
15123RGFW_key RGFW_physicalToMappedKey(RGFW_key key) {
15124 return key;
15125}
15126
15127void RGFW_pollEvents(void) {
15128 RGFW_resetPrevState();
15129 emscripten_sleep(0);
15130}
15131
15132void RGFW_window_resize(RGFW_window* win, i32 w, i32 h) {
15133 RGFW_UNUSED(win);
15134 emscripten_set_canvas_element_size("#canvas", w, h);
15135}
15136
15137/* NOTE: I don't know if this is possible */
15138void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y) { RGFW_UNUSED(win); RGFW_UNUSED(x); RGFW_UNUSED(y); }
15139/* this one might be possible but it looks iffy */
15140RGFW_mouse* RGFW_loadMouse(u8* data, i32 w, i32 h, RGFW_format format) { RGFW_UNUSED(data); RGFW_UNUSED(w); RGFW_UNUSED(h); RGFW_UNUSED(format); return NULL; }
15141
15142void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) { RGFW_UNUSED(win); RGFW_UNUSED(mouse); }
15143void RGFW_freeMouse(RGFW_mouse* mouse) { RGFW_UNUSED(mouse); }
15144
15145RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) {
15146 RGFW_UNUSED(win);
15147 char* cursorName = NULL;
15148
15149 switch (mouse) {
15150 case RGFW_mouseNormal: cursorName = (char*)"default"; break;
15151 case RGFW_mouseArrow: cursorName = (char*)"default"; break;
15152 case RGFW_mouseIbeam: cursorName = (char*)"text"; break;
15153 case RGFW_mouseCrosshair: cursorName = (char*)"crosshair"; break;
15154 case RGFW_mousePointingHand: cursorName = (char*)"pointer"; break;
15155 case RGFW_mouseResizeEW: cursorName = (char*)"ew-resize"; break;
15156 case RGFW_mouseResizeNS: cursorName = (char*)"ns-resize"; break;
15157 case RGFW_mouseResizeNWSE: cursorName = (char*)"nwse-resize"; break;
15158 case RGFW_mouseResizeNESW: cursorName = (char*)"nesw-resize"; break;
15159 case RGFW_mouseResizeNW: cursorName = (char*)"nw-resize"; break;
15160 case RGFW_mouseResizeN: cursorName = (char*)"n-resize"; break;
15161 case RGFW_mouseResizeNE: cursorName = (char*)"ne-resize"; break;
15162 case RGFW_mouseResizeE: cursorName = (char*)"e-resize"; break;
15163 case RGFW_mouseResizeSE: cursorName = (char*)"se-resize"; break;
15164 case RGFW_mouseResizeS: cursorName = (char*)"s-resize"; break;
15165 case RGFW_mouseResizeSW: cursorName = (char*)"sw-resize"; break;
15166 case RGFW_mouseResizeW: cursorName = (char*)"w-resize"; break;
15167 case RGFW_mouseResizeAll: cursorName = (char*)"move"; break;
15168 case RGFW_mouseNotAllowed: cursorName = (char*)"not-allowed"; break;
15169 case RGFW_mouseWait: cursorName = (char*)"wait"; break;
15170 case RGFW_mouseProgress: cursorName = (char*)"progress"; break;
15171 default: return RGFW_FALSE;
15172 }
15173
15174 EM_ASM( { document.getElementById("canvas").style.cursor = UTF8ToString($0); }, cursorName);
15175 return RGFW_TRUE;
15176}
15177
15178RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) {
15179 return RGFW_window_setMouseStandard(win, RGFW_mouseNormal);
15180}
15181
15182void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) {
15183 RGFW_window_showMouseFlags(win, show);
15184 if (show)
15185 RGFW_window_setMouseDefault(win);
15186 else
15187 EM_ASM(document.getElementById('canvas').style.cursor = 'none';);
15188}
15189
15190RGFW_bool RGFW_getGlobalMouse(i32* x, i32* y) {
15191 if(x) *x = EM_ASM_INT({
15192 return window.mouseX || 0;
15193 });
15194 if (y) *y = EM_ASM_INT({
15195 return window.mouseY || 0;
15196 });
15197 return RGFW_TRUE;
15198}
15199
15200void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) {
15201 RGFW_UNUSED(win);
15202
15203 EM_ASM_({
15204 var canvas = document.getElementById('canvas');
15205 if ($0) {
15206 canvas.style.pointerEvents = 'none';
15207 } else {
15208 canvas.style.pointerEvents = 'auto';
15209 }
15210 }, passthrough);
15211}
15212
15213void RGFW_writeClipboard(const char* text, u32 textLen) {
15214 RGFW_UNUSED(textLen);
15215 EM_ASM({ navigator.clipboard.writeText(UTF8ToString($0)); }, text);
15216}
15217
15218
15219RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) {
15220 RGFW_UNUSED(str); RGFW_UNUSED(strCapacity);
15221 /*
15222 placeholder code for later
15223 I'm not sure if this is possible do the the async stuff
15224 */
15225 return 0;
15226}
15227
15228#ifdef RGFW_OPENGL
15229RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints) {
15230 win->src.ctx.native = ctx;
15231 win->src.gfxType = RGFW_gfxNativeOpenGL;
15232
15233 EmscriptenWebGLContextAttributes attrs;
15234 attrs.alpha = hints->alpha;
15235 attrs.depth = hints->depth;
15236 attrs.stencil = hints->stencil;
15237 attrs.antialias = hints->samples;
15238 attrs.premultipliedAlpha = EM_TRUE;
15239 attrs.preserveDrawingBuffer = EM_FALSE;
15240
15241 if (hints->doubleBuffer == 0)
15242 attrs.renderViaOffscreenBackBuffer = 0;
15243 else
15244 attrs.renderViaOffscreenBackBuffer = hints->auxBuffers;
15245
15246 attrs.failIfMajorPerformanceCaveat = EM_FALSE;
15247 attrs.majorVersion = (hints->major == 0) ? 1 : hints->major;
15248 attrs.minorVersion = hints->minor;
15249
15250 attrs.enableExtensionsByDefault = EM_TRUE;
15251 attrs.explicitSwapControl = EM_TRUE;
15252
15253 emscripten_webgl_init_context_attributes(&attrs);
15254 win->src.ctx.native->ctx = emscripten_webgl_create_context("#canvas", &attrs);
15255 emscripten_webgl_make_context_current(win->src.ctx.native->ctx);
15256
15257 #ifdef LEGACY_GL_EMULATION
15258 EM_ASM("Module.useWebGL = true; GLImmediate.init();");
15259 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized.");
15260 #endif
15261
15262 RGFW_window_swapInterval_OpenGL(win, 0);
15263
15264 return RGFW_TRUE;
15265}
15266
15267void RGFW_window_deleteContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx) {
15268 emscripten_webgl_destroy_context(ctx->ctx);
15269 win->src.ctx.native->ctx = 0;
15270 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context freed.");
15271}
15272
15273void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win) {
15274 if (win) RGFW_ASSERT(win->src.ctx.native);
15275 if (win == NULL)
15276 emscripten_webgl_make_context_current(0);
15277 else
15278 emscripten_webgl_make_context_current(win->src.ctx.native->ctx);
15279}
15280
15281void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) {
15282 RGFW_ASSERT(win && win->src.ctx.native);
15283 emscripten_webgl_commit_frame();
15284}
15285void* RGFW_getCurrentContext_OpenGL(void) { return (void*)emscripten_webgl_get_current_context(); }
15286
15287RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char* extension, size_t len) {
15288 return EM_ASM_INT({
15289 var ext = UTF8ToString($0, $1);
15290 var canvas = document.querySelector('canvas');
15291 var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
15292 if (!gl) return 0;
15293
15294 var supported = gl.getSupportedExtensions();
15295 return supported && supported.includes(ext) ? 1 : 0;
15296 }, extension, len);
15297 return RGFW_FALSE;
15298}
15299
15300RGFW_proc RGFW_getProcAddress_OpenGL(const char* procname) {
15301 return (RGFW_proc)emscripten_webgl_get_proc_address(procname);
15302 return NULL;
15303}
15304
15305#endif
15306
15307void RGFW_window_swapInterval_OpenGL(RGFW_window* win, i32 swapInterval) { RGFW_UNUSED(win); RGFW_UNUSED(swapInterval); }
15308
15309void RGFW_deinitPlatform(void) { }
15310
15311void RGFW_window_closePlatform(RGFW_window* win) { }
15312
15313int RGFW_innerWidth(void) { return EM_ASM_INT({ return window.innerWidth; }); }
15314int RGFW_innerHeight(void) { return EM_ASM_INT({ return window.innerHeight; }); }
15315
15316void RGFW_window_setRawMouseModePlatform(RGFW_window* win, RGFW_bool state) {
15317 RGFW_UNUSED(win); RGFW_UNUSED(state);
15318}
15319
15320void RGFW_window_captureMousePlatform(RGFW_window* win, RGFW_bool state) {
15321 RGFW_UNUSED(win);
15322 if (state) {
15323 emscripten_request_pointerlock("#canvas", 1);
15324 } else {
15325 emscripten_exit_pointerlock();
15326 }
15327}
15328
15329void RGFW_window_setName(RGFW_window* win, const char* name) {
15330 RGFW_UNUSED(win);
15331 if (name == NULL) name = "\0";
15332
15333 emscripten_set_window_title(name);
15334}
15335
15336void RGFW_window_maximize(RGFW_window* win) {
15337 RGFW_ASSERT(win != NULL);
15338
15339 RGFW_monitor* mon = RGFW_window_getMonitor(win);
15340 if (mon != NULL) {
15341 RGFW_window_resize(win, mon->mode.w, mon->mode.h);
15342 }
15343
15344 RGFW_window_move(win, 0, 0);
15345}
15346
15347void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) {
15348 RGFW_ASSERT(win != NULL);
15349 if (fullscreen) {
15350 win->internal.flags |= RGFW_windowFullscreen;
15351 EM_ASM( Module.requestFullscreen(false, true); );
15352 return;
15353 }
15354 win->internal.flags &= ~(u32)RGFW_windowFullscreen;
15355 EM_ASM( Module.exitFullscreen(false, true); );
15356}
15357
15358void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) {
15359 RGFW_UNUSED(win);
15360 EM_ASM({
15361 var element = document.getElementById("canvas");
15362 if (element)
15363 element.style.opacity = $1;
15364 }, "elementId", opacity);
15365}
15366
15367#ifdef RGFW_WEBGPU
15368WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance instance) {
15369 WGPUSurfaceDescriptor surfaceDesc = {0};
15370 WGPUEmscriptenSurfaceSourceCanvasHTMLSelector canvasDesc = {0};
15371 canvasDesc.chain.sType = WGPUSType_EmscriptenSurfaceSourceCanvasHTMLSelector;
15372 canvasDesc.selector = (WGPUStringView){.data = "#canvas", .length = 7};
15373
15374 surfaceDesc.nextInChain = &canvasDesc.chain;
15375 return wgpuInstanceCreateSurface(instance, &surfaceDesc);
15376}
15377#endif
15378
15379RGFW_key RGFW_WASMPhysicalToRGFW(u32 hash) {
15380 switch(hash) { /* 0x0000 */
15381 case 0x67243A2DU /* Escape */: return RGFW_escape; /* 0x0001 */
15382 case 0x67251058U /* Digit0 */: return RGFW_0; /* 0x0002 */
15383 case 0x67251059U /* Digit1 */: return RGFW_1; /* 0x0003 */
15384 case 0x6725105AU /* Digit2 */: return RGFW_2; /* 0x0004 */
15385 case 0x6725105BU /* Digit3 */: return RGFW_3; /* 0x0005 */
15386 case 0x6725105CU /* Digit4 */: return RGFW_4; /* 0x0006 */
15387 case 0x6725105DU /* Digit5 */: return RGFW_5; /* 0x0007 */
15388 case 0x6725105EU /* Digit6 */: return RGFW_6; /* 0x0008 */
15389 case 0x6725105FU /* Digit7 */: return RGFW_7; /* 0x0009 */
15390 case 0x67251050U /* Digit8 */: return RGFW_8; /* 0x000A */
15391 case 0x67251051U /* Digit9 */: return RGFW_9; /* 0x000B */
15392 case 0x92E14DD3U /* Minus */: return RGFW_minus; /* 0x000C */
15393 case 0x92E1FBACU /* Equal */: return RGFW_equals; /* 0x000D */
15394 case 0x36BF1CB5U /* Backspace */: return RGFW_backSpace; /* 0x000E */
15395 case 0x7B8E51E2U /* Tab */: return RGFW_tab; /* 0x000F */
15396 case 0x2C595B51U /* KeyQ */: return RGFW_q; /* 0x0010 */
15397 case 0x2C595B57U /* KeyW */: return RGFW_w; /* 0x0011 */
15398 case 0x2C595B45U /* KeyE */: return RGFW_e; /* 0x0012 */
15399 case 0x2C595B52U /* KeyR */: return RGFW_r; /* 0x0013 */
15400 case 0x2C595B54U /* KeyT */: return RGFW_t; /* 0x0014 */
15401 case 0x2C595B59U /* KeyY */: return RGFW_y; /* 0x0015 */
15402 case 0x2C595B55U /* KeyU */: return RGFW_u; /* 0x0016 */
15403 case 0x2C595B4FU /* KeyO */: return RGFW_o; /* 0x0018 */
15404 case 0x2C595B50U /* KeyP */: return RGFW_p; /* 0x0019 */
15405 case 0x45D8158CU /* BracketLeft */: return RGFW_closeBracket; /* 0x001A */
15406 case 0xDEEABF7CU /* BracketRight */: return RGFW_bracket; /* 0x001B */
15407 case 0x92E1C5D2U /* Enter */: return RGFW_return; /* 0x001C */
15408 case 0xE058958CU /* ControlLeft */: return RGFW_controlL; /* 0x001D */
15409 case 0x2C595B41U /* KeyA */: return RGFW_a; /* 0x001E */
15410 case 0x2C595B53U /* KeyS */: return RGFW_s; /* 0x001F */
15411 case 0x2C595B44U /* KeyD */: return RGFW_d; /* 0x0020 */
15412 case 0x2C595B46U /* KeyF */: return RGFW_f; /* 0x0021 */
15413 case 0x2C595B47U /* KeyG */: return RGFW_g; /* 0x0022 */
15414 case 0x2C595B48U /* KeyH */: return RGFW_h; /* 0x0023 */
15415 case 0x2C595B4AU /* KeyJ */: return RGFW_j; /* 0x0024 */
15416 case 0x2C595B4BU /* KeyK */: return RGFW_k; /* 0x0025 */
15417 case 0x2C595B4CU /* KeyL */: return RGFW_l; /* 0x0026 */
15418 case 0x2707219EU /* Semicolon */: return RGFW_semicolon; /* 0x0027 */
15419 case 0x92E0B58DU /* Quote */: return RGFW_apostrophe; /* 0x0028 */
15420 case 0x36BF358DU /* Backquote */: return RGFW_backtick; /* 0x0029 */
15421 case 0x26B1958CU /* ShiftLeft */: return RGFW_shiftL; /* 0x002A */
15422 case 0x36BF2438U /* Backslash */: return RGFW_backSlash; /* 0x002B */
15423 case 0x2C595B5AU /* KeyZ */: return RGFW_z; /* 0x002C */
15424 case 0x2C595B58U /* KeyX */: return RGFW_x; /* 0x002D */
15425 case 0x2C595B43U /* KeyC */: return RGFW_c; /* 0x002E */
15426 case 0x2C595B56U /* KeyV */: return RGFW_v; /* 0x002F */
15427 case 0x2C595B42U /* KeyB */: return RGFW_b; /* 0x0030 */
15428 case 0x2C595B4EU /* KeyN */: return RGFW_n; /* 0x0031 */
15429 case 0x2C595B4DU /* KeyM */: return RGFW_m; /* 0x0032 */
15430 case 0x92E1A1C1U /* Comma */: return RGFW_comma; /* 0x0033 */
15431 case 0x672FFAD4U /* Period */: return RGFW_period; /* 0x0034 */
15432 case 0x92E0A438U /* Slash */: return RGFW_slash; /* 0x0035 */
15433 case 0xC5A6BF7CU /* ShiftRight */: return RGFW_shiftR;
15434 case 0x5D64DA91U /* NumpadMultiply */: return RGFW_kpMultiply;
15435 case 0xC914958CU /* AltLeft */: return RGFW_altL; /* 0x0038 */
15436 case 0x92E09CB5U /* Space */: return RGFW_space; /* 0x0039 */
15437 case 0xB8FAE73BU /* CapsLock */: return RGFW_capsLock; /* 0x003A */
15438 case 0x7174B789U /* F1 */: return RGFW_F1; /* 0x003B */
15439 case 0x7174B78AU /* F2 */: return RGFW_F2; /* 0x003C */
15440 case 0x7174B78BU /* F3 */: return RGFW_F3; /* 0x003D */
15441 case 0x7174B78CU /* F4 */: return RGFW_F4; /* 0x003E */
15442 case 0x7174B78DU /* F5 */: return RGFW_F5; /* 0x003F */
15443 case 0x7174B78EU /* F6 */: return RGFW_F6; /* 0x0040 */
15444 case 0x7174B78FU /* F7 */: return RGFW_F7; /* 0x0041 */
15445 case 0x7174B780U /* F8 */: return RGFW_F8; /* 0x0042 */
15446 case 0x7174B781U /* F9 */: return RGFW_F9; /* 0x0043 */
15447 case 0x7B8E57B0U /* F10 */: return RGFW_F10; /* 0x0044 */
15448 case 0xC925FCDFU /* Numpad7 */: return RGFW_kpMultiply; /* 0x0047 */
15449 case 0xC925FCD0U /* Numpad8 */: return RGFW_kp8; /* 0x0048 */
15450 case 0xC925FCD1U /* Numpad9 */: return RGFW_kp9; /* 0x0049 */
15451 case 0x5EA3E8A4U /* NumpadSubtract */: return RGFW_minus; /* 0x004A */
15452 case 0xC925FCDCU /* Numpad4 */: return RGFW_kp4; /* 0x004B */
15453 case 0xC925FCDDU /* Numpad5 */: return RGFW_kp5; /* 0x004C */
15454 case 0xC925FCDEU /* Numpad6 */: return RGFW_kp6; /* 0x004D */
15455 case 0xC925FCD9U /* Numpad1 */: return RGFW_kp1; /* 0x004F */
15456 case 0xC925FCDAU /* Numpad2 */: return RGFW_kp2; /* 0x0050 */
15457 case 0xC925FCDBU /* Numpad3 */: return RGFW_kp3; /* 0x0051 */
15458 case 0xC925FCD8U /* Numpad0 */: return RGFW_kp0; /* 0x0052 */
15459 case 0x95852DACU /* NumpadDecimal */: return RGFW_period; /* 0x0053 */
15460 case 0x7B8E57B1U /* F11 */: return RGFW_F11; /* 0x0057 */
15461 case 0x7B8E57B2U /* F12 */: return RGFW_F12; /* 0x0058 */
15462 case 0x7B8E57B3U /* F13 */: return DOM_PK_F13; /* 0x0064 */
15463 case 0x7B8E57B4U /* F14 */: return DOM_PK_F14; /* 0x0065 */
15464 case 0x7B8E57B5U /* F15 */: return DOM_PK_F15; /* 0x0066 */
15465 case 0x7B8E57B6U /* F16 */: return DOM_PK_F16; /* 0x0067 */
15466 case 0x7B8E57B7U /* F17 */: return DOM_PK_F17; /* 0x0068 */
15467 case 0x7B8E57B8U /* F18 */: return DOM_PK_F18; /* 0x0069 */
15468 case 0x7B8E57B9U /* F19 */: return DOM_PK_F19; /* 0x006A */
15469 case 0x7B8E57A8U /* F20 */: return DOM_PK_F20; /* 0x006B */
15470 case 0x7B8E57A9U /* F21 */: return DOM_PK_F21; /* 0x006C */
15471 case 0x7B8E57AAU /* F22 */: return DOM_PK_F22; /* 0x006D */
15472 case 0x7B8E57ABU /* F23 */: return DOM_PK_F23; /* 0x006E */
15473 case 0x7393FBACU /* NumpadEqual */: return RGFW_kpReturn;
15474 case 0xB88EBF7CU /* AltRight */: return RGFW_altR; /* 0xE038 */
15475 case 0xC925873BU /* NumLock */: return RGFW_numLock; /* 0xE045 */
15476 case 0x2C595F45U /* Home */: return RGFW_home; /* 0xE047 */
15477 case 0xC91BB690U /* ArrowUp */: return RGFW_up; /* 0xE048 */
15478 case 0x672F9210U /* PageUp */: return RGFW_pageUp; /* 0xE049 */
15479 case 0x3799258CU /* ArrowLeft */: return RGFW_left; /* 0xE04B */
15480 case 0x4CE33F7CU /* ArrowRight */: return RGFW_right; /* 0xE04D */
15481 case 0x7B8E55DCU /* End */: return RGFW_end; /* 0xE04F */
15482 case 0x3799379EU /* ArrowDown */: return RGFW_down; /* 0xE050 */
15483 case 0xBA90179EU /* PageDown */: return RGFW_pageDown; /* 0xE051 */
15484 case 0x6723CB2CU /* Insert */: return RGFW_insert; /* 0xE052 */
15485 case 0x6725C50DU /* Delete */: return RGFW_delete; /* 0xE053 */
15486 case 0x6723658CU /* OSLeft */: return RGFW_superL; /* 0xE05B */
15487 case 0x39643F7CU /* MetaRight */: return RGFW_superR; /* 0xE05C */
15488 case 0x380B9C8CU /* NumpadAdd */: return DOM_PK_NUMPAD_ADD; /* 0x004E */
15489 default: return DOM_PK_UNKNOWN;
15490 }
15491
15492 return 0;
15493}
15494
15495/* unsupported functions */
15496void RGFW_window_focus(RGFW_window* win) { RGFW_UNUSED(win); }
15497void RGFW_window_raise(RGFW_window* win) { RGFW_UNUSED(win); }
15498RGFW_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; }
15499RGFW_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; }
15500size_t RGFW_monitor_getGammaRampPtr(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) { RGFW_UNUSED(monitor); RGFW_UNUSED(ramp); return 0; }
15501RGFW_bool RGFW_monitor_setGammaRamp(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) { RGFW_UNUSED(monitor); RGFW_UNUSED(ramp); return RGFW_FALSE; }
15502size_t RGFW_monitor_getModesPtr(RGFW_monitor* mon, RGFW_monitorMode** modes) { RGFW_UNUSED(mon); RGFW_UNUSED(modes); return 0; }
15503RGFW_bool RGFW_monitor_setMode(RGFW_monitor* mon, RGFW_monitorMode* mode) { RGFW_UNUSED(mon); RGFW_UNUSED(mode); return RGFW_FALSE; }
15504void RGFW_pollMonitors(void) { }
15505void RGFW_window_move(RGFW_window* win, i32 x, i32 y) { RGFW_UNUSED(win); RGFW_UNUSED(x); RGFW_UNUSED(y); }
15506void RGFW_window_setAspectRatio(RGFW_window* win, i32 w, i32 h) { RGFW_UNUSED(win); RGFW_UNUSED(w); RGFW_UNUSED(h); }
15507void RGFW_window_setMinSize(RGFW_window* win, i32 w, i32 h) { RGFW_UNUSED(win); RGFW_UNUSED(w); RGFW_UNUSED(h); }
15508void RGFW_window_setMaxSize(RGFW_window* win, i32 w, i32 h) { RGFW_UNUSED(win); RGFW_UNUSED(w); RGFW_UNUSED(h); }
15509void RGFW_window_minimize(RGFW_window* win) { RGFW_UNUSED(win); }
15510void RGFW_window_restore(RGFW_window* win) { RGFW_UNUSED(win); }
15511void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) { RGFW_UNUSED(win); RGFW_UNUSED(floating); }
15512void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { RGFW_UNUSED(win); RGFW_UNUSED(border); }
15513RGFW_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; }
15514void RGFW_window_hide(RGFW_window* win) { RGFW_UNUSED(win); }
15515void RGFW_window_show(RGFW_window* win) {RGFW_UNUSED(win); }
15516void RGFW_window_flash(RGFW_window* win, RGFW_flashRequest request) { RGFW_UNUSED(win); RGFW_UNUSED(request); }
15517RGFW_bool RGFW_window_isHidden(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; }
15518RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; }
15519RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; }
15520RGFW_bool RGFW_window_isFloating(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; }
15521RGFW_monitor* RGFW_window_getMonitor(RGFW_window* win) { RGFW_UNUSED(win); return NULL; }
15522void RGFW_waitForEvent(i32 waitMS) { RGFW_UNUSED(waitMS); }
15523#endif
15524
15525/* end of web asm defines */
15526
15527/*
15528 * RGFW function pointer backend, made to allow you to compile for Wayland but fallback to X11
15529*/
15530#ifdef RGFW_DYNAMIC
15531typedef RGFW_window* (*RGFW_createWindowPlatform_ptr)(const char* name, RGFW_windowFlags flags, RGFW_window* win);
15532typedef RGFW_bool (*RGFW_getMouse_ptr)(i32* x, i32* y);
15533typedef RGFW_key (*RGFW_physicalToMappedKey_ptr)(RGFW_key key);
15534typedef void (*RGFW_pollEvents_ptr)(void);
15535typedef void (*RGFW_pollMonitors_ptr)(void);
15536typedef void (*RGFW_window_move_ptr)(RGFW_window* win, i32 x, i32 y);
15537typedef void (*RGFW_window_resize_ptr)(RGFW_window* win, i32 w, i32 h);
15538typedef void (*RGFW_window_setAspectRatio_ptr)(RGFW_window* win, i32 w, i32 h);
15539typedef void (*RGFW_window_setMinSize_ptr)(RGFW_window* win, i32 w, i32 h);
15540typedef void (*RGFW_window_setMaxSize_ptr)(RGFW_window* win, i32 w, i32 h);
15541typedef void (*RGFW_window_maximize_ptr)(RGFW_window* win);
15542typedef void (*RGFW_window_focus_ptr)(RGFW_window* win);
15543typedef void (*RGFW_window_raise_ptr)(RGFW_window* win);
15544typedef void (*RGFW_window_setFullscreen_ptr)(RGFW_window* win, RGFW_bool fullscreen);
15545typedef void (*RGFW_window_setFloating_ptr)(RGFW_window* win, RGFW_bool floating);
15546typedef void (*RGFW_window_setOpacity_ptr)(RGFW_window* win, u8 opacity);
15547typedef void (*RGFW_window_minimize_ptr)(RGFW_window* win);
15548typedef void (*RGFW_window_restore_ptr)(RGFW_window* win);
15549typedef RGFW_bool (*RGFW_window_isFloating_ptr)(RGFW_window* win);
15550typedef void (*RGFW_window_setName_ptr)(RGFW_window* win, const char* name);
15551typedef void (*RGFW_window_setMousePassthrough_ptr)(RGFW_window* win, RGFW_bool passthrough);
15552typedef RGFW_bool (*RGFW_window_setIconEx_ptr)(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, u8 type);
15553typedef RGFW_mouse* (*RGFW_loadMouse_ptr)(u8* data, i32 w, i32 h, RGFW_format format);
15554typedef void (*RGFW_window_setMouse_ptr)(RGFW_window* win, RGFW_mouse* mouse);
15555typedef void (*RGFW_window_moveMouse_ptr)(RGFW_window* win, i32 x, i32 y);
15556typedef RGFW_bool (*RGFW_window_setMouseDefault_ptr)(RGFW_window* win);
15557typedef RGFW_bool (*RGFW_window_setMouseStandard_ptr)(RGFW_window* win, u8 mouse);
15558typedef void (*RGFW_window_hide_ptr)(RGFW_window* win);
15559typedef void (*RGFW_window_show_ptr)(RGFW_window* win);
15560typedef void (*RGFW_window_flash_ptr)(RGFW_window* win, RGFW_flashRequest request);
15561typedef RGFW_ssize_t (*RGFW_readClipboardPtr_ptr)(char* str, size_t strCapacity);
15562typedef void (*RGFW_writeClipboard_ptr)(const char* text, u32 textLen);
15563typedef RGFW_bool (*RGFW_window_isHidden_ptr)(RGFW_window* win);
15564typedef RGFW_bool (*RGFW_window_isMinimized_ptr)(RGFW_window* win);
15565typedef RGFW_bool (*RGFW_window_isMaximized_ptr)(RGFW_window* win);
15566typedef RGFW_bool (*RGFW_monitor_requestMode_ptr)(RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request);
15567typedef RGFW_bool (*RGFW_monitor_getWorkarea_ptr)(RGFW_monitor* mon, i32* x, i32* y, i32* w, i32* h);
15568typedef size_t (*RGFW_monitor_getModesPtr_ptr)(RGFW_monitor* mon, RGFW_monitorMode** modes);
15569typedef size_t (*RGFW_monitor_getGammaRampPtr_ptr) (RGFW_monitor* monitor, RGFW_gammaRamp* ramp);
15570typedef RGFW_bool (*RGFW_monitor_setGammaRamp_ptr) (RGFW_monitor* monitor, RGFW_gammaRamp* ramp);
15571typedef RGFW_bool (*RGFW_monitor_setMode_ptr)(RGFW_monitor* mon, RGFW_monitorMode* mode);
15572typedef RGFW_monitor* (*RGFW_window_getMonitor_ptr)(RGFW_window* win);
15573typedef void (*RGFW_window_closePlatform_ptr)(RGFW_window* win);
15574typedef RGFW_format (*RGFW_nativeFormat_ptr)(void);
15575typedef RGFW_bool (*RGFW_createSurfacePtr_ptr)(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface);
15576typedef void (*RGFW_window_blitSurface_ptr)(RGFW_window* win, RGFW_surface* surface);
15577typedef void (*RGFW_surface_freePtr_ptr)(RGFW_surface* surface);
15578typedef void (*RGFW_freeMouse_ptr)(RGFW_mouse* mouse);
15579typedef void (*RGFW_window_setBorder_ptr)(RGFW_window* win, RGFW_bool border);
15580typedef void (*RGFW_window_captureMousePlatform_ptr)(RGFW_window* win, RGFW_bool state);
15581typedef void (*RGFW_window_setRawMouseModePlatform_ptr)(RGFW_window* win, RGFW_bool state);
15582#ifdef RGFW_OPENGL
15583typedef void (*RGFW_window_makeCurrentContext_OpenGL_ptr)(RGFW_window* win);
15584typedef void* (*RGFW_getCurrentContext_OpenGL_ptr)(void);
15585typedef void (*RGFW_window_swapBuffers_OpenGL_ptr)(RGFW_window* win);
15586typedef void (*RGFW_window_swapInterval_OpenGL_ptr)(RGFW_window* win, i32 swapInterval);
15587typedef RGFW_bool (*RGFW_extensionSupportedPlatform_OpenGL_ptr)(const char* extension, size_t len);
15588typedef RGFW_proc (*RGFW_getProcAddress_OpenGL_ptr)(const char* procname);
15589typedef RGFW_bool (*RGFW_window_createContextPtr_OpenGL_ptr)(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints);
15590typedef void (*RGFW_window_deleteContextPtr_OpenGL_ptr)(RGFW_window* win, RGFW_glContext* ctx);
15591#endif
15592#ifdef RGFW_WEBGPU
15593typedef WGPUSurface (*RGFW_window_createSurface_WebGPU_ptr)(RGFW_window* window, WGPUInstance instance);
15594#endif
15595
15596/* Structure to hold all function pointers */
15597typedef struct RGFW_FunctionPointers {
15598 RGFW_nativeFormat_ptr nativeFormat;
15599 RGFW_createSurfacePtr_ptr createSurfacePtr;
15600 RGFW_window_blitSurface_ptr window_blitSurface;
15601 RGFW_surface_freePtr_ptr surface_freePtr;
15602 RGFW_freeMouse_ptr freeMouse;
15603 RGFW_window_setBorder_ptr window_setBorder;
15604 RGFW_window_captureMousePlatform_ptr window_captureMousePlatform;
15605 RGFW_window_setRawMouseModePlatform_ptr window_setRawMouseModePlatform;
15606 RGFW_createWindowPlatform_ptr createWindowPlatform;
15607 RGFW_getMouse_ptr getGlobalMouse;
15608 RGFW_physicalToMappedKey_ptr physicalToMappedKey;
15609 RGFW_pollEvents_ptr pollEvents;
15610 RGFW_pollMonitors_ptr pollMonitors;
15611 RGFW_window_move_ptr window_move;
15612 RGFW_window_resize_ptr window_resize;
15613 RGFW_window_setAspectRatio_ptr window_setAspectRatio;
15614 RGFW_window_setMinSize_ptr window_setMinSize;
15615 RGFW_window_setMaxSize_ptr window_setMaxSize;
15616 RGFW_window_maximize_ptr window_maximize;
15617 RGFW_window_focus_ptr window_focus;
15618 RGFW_window_raise_ptr window_raise;
15619 RGFW_window_setFullscreen_ptr window_setFullscreen;
15620 RGFW_window_setFloating_ptr window_setFloating;
15621 RGFW_window_setOpacity_ptr window_setOpacity;
15622 RGFW_window_minimize_ptr window_minimize;
15623 RGFW_window_restore_ptr window_restore;
15624 RGFW_window_isFloating_ptr window_isFloating;
15625 RGFW_window_setName_ptr window_setName;
15626 RGFW_window_setMousePassthrough_ptr window_setMousePassthrough;
15627 RGFW_window_setIconEx_ptr window_setIconEx;
15628 RGFW_loadMouse_ptr loadMouse;
15629 RGFW_window_setMouse_ptr window_setMouse;
15630 RGFW_window_moveMouse_ptr window_moveMouse;
15631 RGFW_window_setMouseDefault_ptr window_setMouseDefault;
15632 RGFW_window_setMouseStandard_ptr window_setMouseStandard;
15633 RGFW_window_hide_ptr window_hide;
15634 RGFW_window_show_ptr window_show;
15635 RGFW_window_flash_ptr window_flash;
15636 RGFW_readClipboardPtr_ptr readClipboardPtr;
15637 RGFW_writeClipboard_ptr writeClipboard;
15638 RGFW_window_isHidden_ptr window_isHidden;
15639 RGFW_window_isMinimized_ptr window_isMinimized;
15640 RGFW_window_isMaximized_ptr window_isMaximized;
15641 RGFW_monitor_requestMode_ptr monitor_requestMode;
15642 RGFW_monitor_getWorkarea_ptr monitor_getWorkarea;
15643 RGFW_monitor_getModesPtr_ptr monitor_getModesPtr;
15644 RGFW_monitor_getGammaRampPtr_ptr monitor_getGammaRampPtr;
15645 RGFW_monitor_setGammaRamp_ptr monitor_setGammaRamp;
15646 RGFW_monitor_setMode_ptr monitor_setMode;
15647 RGFW_window_getMonitor_ptr window_getMonitor;
15648 RGFW_window_closePlatform_ptr window_closePlatform;
15649#ifdef RGFW_OPENGL
15650 RGFW_extensionSupportedPlatform_OpenGL_ptr extensionSupportedPlatform_OpenGL;
15651 RGFW_getProcAddress_OpenGL_ptr getProcAddress_OpenGL;
15652 RGFW_window_createContextPtr_OpenGL_ptr window_createContextPtr_OpenGL;
15653 RGFW_window_deleteContextPtr_OpenGL_ptr window_deleteContextPtr_OpenGL;
15654 RGFW_window_makeCurrentContext_OpenGL_ptr window_makeCurrentContext_OpenGL;
15655 RGFW_getCurrentContext_OpenGL_ptr getCurrentContext_OpenGL;
15656 RGFW_window_swapBuffers_OpenGL_ptr window_swapBuffers_OpenGL;
15657 RGFW_window_swapInterval_OpenGL_ptr window_swapInterval_OpenGL;
15658#endif
15659#ifdef RGFW_WEBGPU
15660 RGFW_window_createSurface_WebGPU_ptr window_createSurface_WebGPU;
15661#endif
15662} RGFW_functionPointers;
15663
15664RGFW_functionPointers RGFW_api;
15665
15666RGFW_format RGFW_nativeFormat(void) { return RGFW_api.nativeFormat(); }
15667RGFW_bool RGFW_createSurfacePtr(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) { return RGFW_api.createSurfacePtr(data, w, h, format, surface); }
15668void RGFW_surface_freePtr(RGFW_surface* surface) { RGFW_api.surface_freePtr(surface); }
15669void RGFW_freeMouse(RGFW_mouse* mouse) { RGFW_api.freeMouse(mouse); }
15670void RGFW_window_blitSurface(RGFW_window* win, RGFW_surface* surface) { RGFW_api.window_blitSurface(win, surface); }
15671void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { RGFW_api.window_setBorder(win, border); }
15672void RGFW_window_captureMousePlatform(RGFW_window* win, RGFW_bool state) { RGFW_api.window_captureMousePlatform(win, state); }
15673void RGFW_window_setRawMouseModePlatform(RGFW_window* win, RGFW_bool state) { RGFW_api.window_setRawMouseModePlatform(win, state); }
15674RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win) { RGFW_init(); return RGFW_api.createWindowPlatform(name, flags, win); }
15675RGFW_bool RGFW_getGlobalMouse(i32* x, i32* y) { return RGFW_api.getGlobalMouse(x, y); }
15676RGFW_key RGFW_physicalToMappedKey(RGFW_key key) { return RGFW_api.physicalToMappedKey(key); }
15677void RGFW_pollEvents(void) { RGFW_api.pollEvents(); }
15678void RGFW_pollMonitors(void) { RGFW_api.pollMonitors(); }
15679void RGFW_window_move(RGFW_window* win, i32 x, i32 y) { RGFW_api.window_move(win, x, y); }
15680void RGFW_window_resize(RGFW_window* win, i32 w, i32 h) { RGFW_api.window_resize(win, w, h); }
15681void RGFW_window_setAspectRatio(RGFW_window* win, i32 w, i32 h) { RGFW_api.window_setAspectRatio(win, w, h); }
15682void RGFW_window_setMinSize(RGFW_window* win, i32 w, i32 h) { RGFW_api.window_setMinSize(win, w, h); }
15683void RGFW_window_setMaxSize(RGFW_window* win, i32 w, i32 h) { RGFW_api.window_setMaxSize(win, w, h); }
15684void RGFW_window_maximize(RGFW_window* win) { RGFW_api.window_maximize(win); }
15685void RGFW_window_focus(RGFW_window* win) { RGFW_api.window_focus(win); }
15686void RGFW_window_raise(RGFW_window* win) { RGFW_api.window_raise(win); }
15687void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) { RGFW_api.window_setFullscreen(win, fullscreen); }
15688void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) { RGFW_api.window_setFloating(win, floating); }
15689void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) { RGFW_api.window_setOpacity(win, opacity); }
15690void RGFW_window_minimize(RGFW_window* win) { RGFW_api.window_minimize(win); }
15691void RGFW_window_restore(RGFW_window* win) { RGFW_api.window_restore(win); }
15692RGFW_bool RGFW_window_isFloating(RGFW_window* win) { return RGFW_api.window_isFloating(win); }
15693void RGFW_window_setName(RGFW_window* win, const char* name) { RGFW_api.window_setName(win, name); }
15694
15695#ifndef RGFW_NO_PASSTHROUGH
15696void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) { RGFW_api.window_setMousePassthrough(win, passthrough); }
15697#endif
15698
15699RGFW_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); }
15700RGFW_mouse* RGFW_loadMouse(u8* data, i32 w, i32 h, RGFW_format format) { return RGFW_api.loadMouse(data, w, h, format); }
15701void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) { RGFW_api.window_setMouse(win, mouse); }
15702void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y) { RGFW_api.window_moveMouse(win, x, y); }
15703RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) { return RGFW_api.window_setMouseDefault(win); }
15704RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) { return RGFW_api.window_setMouseStandard(win, mouse); }
15705void RGFW_window_hide(RGFW_window* win) { RGFW_api.window_hide(win); }
15706void RGFW_window_show(RGFW_window* win) { RGFW_api.window_show(win); }
15707void RGFW_window_flash(RGFW_window* win, RGFW_flashRequest request) { RGFW_api.window_flash(win, request); }
15708RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) { return RGFW_api.readClipboardPtr(str, strCapacity); }
15709void RGFW_writeClipboard(const char* text, u32 textLen) { RGFW_api.writeClipboard(text, textLen); }
15710RGFW_bool RGFW_window_isHidden(RGFW_window* win) { return RGFW_api.window_isHidden(win); }
15711RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { return RGFW_api.window_isMinimized(win); }
15712RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { return RGFW_api.window_isMaximized(win); }
15713RGFW_bool RGFW_monitor_requestMode(RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request) { return RGFW_api.monitor_requestMode(mon, mode, request); }
15714RGFW_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); }
15715size_t RGFW_monitor_getGammaRampPtr(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) { return RGFW_api.monitor_getGammaRampPtr(monitor, ramp); }
15716RGFW_bool RGFW_monitor_setGammaRamp(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) { return RGFW_api.monitor_setGammaRamp(monitor, ramp); }
15717size_t RGFW_monitor_getModesPtr(RGFW_monitor* mon, RGFW_monitorMode** modes) { return RGFW_api.monitor_getModesPtr(mon, modes); }
15718RGFW_bool RGFW_monitor_setMode(RGFW_monitor* mon, RGFW_monitorMode* mode) { return RGFW_api.monitor_setMode(mon, mode); }
15719RGFW_monitor* RGFW_window_getMonitor(RGFW_window* win) { return RGFW_api.window_getMonitor(win); }
15720void RGFW_window_closePlatform(RGFW_window* win) { RGFW_api.window_closePlatform(win); }
15721
15722#ifdef RGFW_OPENGL
15723RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char* extension, size_t len) { return RGFW_api.extensionSupportedPlatform_OpenGL(extension, len); }
15724RGFW_proc RGFW_getProcAddress_OpenGL(const char* procname) { return RGFW_api.getProcAddress_OpenGL(procname); }
15725RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints) { return RGFW_api.window_createContextPtr_OpenGL(win, ctx, hints); }
15726void RGFW_window_deleteContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx) { RGFW_api.window_deleteContextPtr_OpenGL(win, ctx); }
15727void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win) { RGFW_api.window_makeCurrentContext_OpenGL(win); }
15728void* RGFW_getCurrentContext_OpenGL(void) { return RGFW_api.getCurrentContext_OpenGL(); }
15729void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { RGFW_api.window_swapBuffers_OpenGL(win); }
15730void RGFW_window_swapInterval_OpenGL(RGFW_window* win, i32 swapInterval) { RGFW_api.window_swapInterval_OpenGL(win, swapInterval); }
15731#endif
15732
15733#ifdef RGFW_WEBGPU
15734WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance instance) { return RGFW_api.window_createSurface_WebGPU(window, instance); }
15735#endif
15736#endif /* RGFW_DYNAMIC */
15737
15738/*
15739 * start of X11 AND wayland defines
15740 * this allows a single executable to support x11 AND wayland
15741 * falling back to x11 if wayland fails to initalize
15742*/
15743#if defined(RGFW_WAYLAND) && defined(RGFW_X11)
15744void RGFW_load_X11(void) {
15745 RGFW_api.nativeFormat = RGFW_nativeFormat_X11;
15746 RGFW_api.createSurfacePtr = RGFW_createSurfacePtr_X11;
15747 RGFW_api.window_blitSurface = RGFW_window_blitSurface_X11;
15748 RGFW_api.surface_freePtr = RGFW_surface_freePtr_X11;
15749 RGFW_api.freeMouse = RGFW_freeMouse_X11;
15750 RGFW_api.window_setBorder = RGFW_window_setBorder_X11;
15751 RGFW_api.window_captureMousePlatform = RGFW_window_captureMousePlatform_X11;
15752 RGFW_api.window_setRawMouseModePlatform = RGFW_window_setRawMouseModePlatform_X11;
15753 RGFW_api.createWindowPlatform = RGFW_createWindowPlatform_X11;
15754 RGFW_api.getGlobalMouse = RGFW_getGlobalMouse_X11;
15755 RGFW_api.physicalToMappedKey = RGFW_physicalToMappedKey_X11;
15756 RGFW_api.pollEvents = RGFW_pollEvents_X11;
15757 RGFW_api.pollMonitors = RGFW_pollMonitors_X11;
15758 RGFW_api.window_move = RGFW_window_move_X11;
15759 RGFW_api.window_resize = RGFW_window_resize_X11;
15760 RGFW_api.window_setAspectRatio = RGFW_window_setAspectRatio_X11;
15761 RGFW_api.window_setMinSize = RGFW_window_setMinSize_X11;
15762 RGFW_api.window_setMaxSize = RGFW_window_setMaxSize_X11;
15763 RGFW_api.window_maximize = RGFW_window_maximize_X11;
15764 RGFW_api.window_focus = RGFW_window_focus_X11;
15765 RGFW_api.window_raise = RGFW_window_raise_X11;
15766 RGFW_api.window_setFullscreen = RGFW_window_setFullscreen_X11;
15767 RGFW_api.window_setFloating = RGFW_window_setFloating_X11;
15768 RGFW_api.window_setOpacity = RGFW_window_setOpacity_X11;
15769 RGFW_api.window_minimize = RGFW_window_minimize_X11;
15770 RGFW_api.window_restore = RGFW_window_restore_X11;
15771 RGFW_api.window_isFloating = RGFW_window_isFloating_X11;
15772 RGFW_api.window_setName = RGFW_window_setName_X11;
15773#ifndef RGFW_NO_PASSTHROUGH
15774 RGFW_api.window_setMousePassthrough = RGFW_window_setMousePassthrough_X11;
15775#endif
15776 RGFW_api.window_setIconEx = RGFW_window_setIconEx_X11;
15777 RGFW_api.loadMouse = RGFW_loadMouse_X11;
15778 RGFW_api.window_setMouse = RGFW_window_setMouse_X11;
15779 RGFW_api.window_moveMouse = RGFW_window_moveMouse_X11;
15780 RGFW_api.window_setMouseDefault = RGFW_window_setMouseDefault_X11;
15781 RGFW_api.window_setMouseStandard = RGFW_window_setMouseStandard_X11;
15782 RGFW_api.window_hide = RGFW_window_hide_X11;
15783 RGFW_api.window_show = RGFW_window_show_X11;
15784 RGFW_api.window_flash = RGFW_window_flash_X11;
15785 RGFW_api.readClipboardPtr = RGFW_readClipboardPtr_X11;
15786 RGFW_api.writeClipboard = RGFW_writeClipboard_X11;
15787 RGFW_api.window_isHidden = RGFW_window_isHidden_X11;
15788 RGFW_api.window_isMinimized = RGFW_window_isMinimized_X11;
15789 RGFW_api.window_isMaximized = RGFW_window_isMaximized_X11;
15790 RGFW_api.monitor_requestMode = RGFW_monitor_requestMode_X11;
15791 RGFW_api.monitor_getModesPtr = RGFW_monitor_getModesPtr_X11;
15792 RGFW_api.monitor_setGammaRamp = RGFW_monitor_setGammaRamp_X11;
15793 RGFW_api.monitor_getGammaRampPtr = RGFW_monitor_getGammaRampPtr_X11;
15794 RGFW_api.monitor_setMode = RGFW_monitor_setMode_X11;
15795 RGFW_api.window_getMonitor = RGFW_window_getMonitor_X11;
15796 RGFW_api.window_closePlatform = RGFW_window_closePlatform_X11;
15797#ifdef RGFW_OPENGL
15798 RGFW_api.extensionSupportedPlatform_OpenGL = RGFW_extensionSupportedPlatform_OpenGL_X11;
15799 RGFW_api.getProcAddress_OpenGL = RGFW_getProcAddress_OpenGL_X11;
15800 RGFW_api.window_createContextPtr_OpenGL = RGFW_window_createContextPtr_OpenGL_X11;
15801 RGFW_api.window_deleteContextPtr_OpenGL = RGFW_window_deleteContextPtr_OpenGL_X11;
15802 RGFW_api.window_makeCurrentContext_OpenGL = RGFW_window_makeCurrentContext_OpenGL_X11;
15803 RGFW_api.getCurrentContext_OpenGL = RGFW_getCurrentContext_OpenGL_X11;
15804 RGFW_api.window_swapBuffers_OpenGL = RGFW_window_swapBuffers_OpenGL_X11;
15805 RGFW_api.window_swapInterval_OpenGL = RGFW_window_swapInterval_OpenGL_X11;
15806#endif
15807#ifdef RGFW_WEBGPU
15808 RGFW_api.window_createSurface_WebGPU = RGFW_window_createSurface_WebGPU_X11;
15809#endif
15810}
15811
15812void RGFW_load_Wayland(void) {
15813 RGFW_api.nativeFormat = RGFW_nativeFormat_Wayland;
15814 RGFW_api.createSurfacePtr = RGFW_createSurfacePtr_Wayland;
15815 RGFW_api.window_blitSurface = RGFW_window_blitSurface_Wayland;
15816 RGFW_api.surface_freePtr = RGFW_surface_freePtr_Wayland;
15817 RGFW_api.freeMouse = RGFW_freeMouse_Wayland;
15818 RGFW_api.window_setBorder = RGFW_window_setBorder_Wayland;
15819 RGFW_api.window_captureMousePlatform = RGFW_window_captureMousePlatform_Wayland;
15820 RGFW_api.window_setRawMouseModePlatform = RGFW_window_setRawMouseModePlatform_Wayland;
15821 RGFW_api.createWindowPlatform = RGFW_createWindowPlatform_Wayland;
15822 RGFW_api.getGlobalMouse = RGFW_getGlobalMouse_Wayland;
15823 RGFW_api.physicalToMappedKey = RGFW_physicalToMappedKey_Wayland;
15824 RGFW_api.pollEvents = RGFW_pollEvents_Wayland;
15825 RGFW_api.pollMonitors = RGFW_pollMonitors_Wayland;
15826 RGFW_api.window_move = RGFW_window_move_Wayland;
15827 RGFW_api.window_resize = RGFW_window_resize_Wayland;
15828 RGFW_api.window_setAspectRatio = RGFW_window_setAspectRatio_Wayland;
15829 RGFW_api.window_setMinSize = RGFW_window_setMinSize_Wayland;
15830 RGFW_api.window_setMaxSize = RGFW_window_setMaxSize_Wayland;
15831 RGFW_api.window_maximize = RGFW_window_maximize_Wayland;
15832 RGFW_api.window_focus = RGFW_window_focus_Wayland;
15833 RGFW_api.window_raise = RGFW_window_raise_Wayland;
15834 RGFW_api.window_setFullscreen = RGFW_window_setFullscreen_Wayland;
15835 RGFW_api.window_setFloating = RGFW_window_setFloating_Wayland;
15836 RGFW_api.window_setOpacity = RGFW_window_setOpacity_Wayland;
15837 RGFW_api.window_minimize = RGFW_window_minimize_Wayland;
15838 RGFW_api.window_restore = RGFW_window_restore_Wayland;
15839 RGFW_api.window_isFloating = RGFW_window_isFloating_Wayland;
15840 RGFW_api.window_setName = RGFW_window_setName_Wayland;
15841#ifndef RGFW_NO_PASSTHROUGH
15842 RGFW_api.window_setMousePassthrough = RGFW_window_setMousePassthrough_Wayland;
15843#endif
15844 RGFW_api.window_setIconEx = RGFW_window_setIconEx_Wayland;
15845 RGFW_api.loadMouse = RGFW_loadMouse_Wayland;
15846 RGFW_api.window_setMouse = RGFW_window_setMouse_Wayland;
15847 RGFW_api.window_moveMouse = RGFW_window_moveMouse_Wayland;
15848 RGFW_api.window_setMouseDefault = RGFW_window_setMouseDefault_Wayland;
15849 RGFW_api.window_setMouseStandard = RGFW_window_setMouseStandard_Wayland;
15850 RGFW_api.window_hide = RGFW_window_hide_Wayland;
15851 RGFW_api.window_show = RGFW_window_show_Wayland;
15852 RGFW_api.window_flash = RGFW_window_flash_X11;
15853 RGFW_api.readClipboardPtr = RGFW_readClipboardPtr_Wayland;
15854 RGFW_api.writeClipboard = RGFW_writeClipboard_Wayland;
15855 RGFW_api.window_isHidden = RGFW_window_isHidden_Wayland;
15856 RGFW_api.window_isMinimized = RGFW_window_isMinimized_Wayland;
15857 RGFW_api.window_isMaximized = RGFW_window_isMaximized_Wayland;
15858 RGFW_api.monitor_requestMode = RGFW_monitor_requestMode_Wayland;
15859 RGFW_api.monitor_getModesPtr = RGFW_monitor_getModesPtr_Wayland;
15860 RGFW_api.monitor_setGammaRamp = RGFW_monitor_setGammaRamp_Wayland;
15861 RGFW_api.monitor_getGammaRampPtr = RGFW_monitor_getGammaRampPtr_Wayland;
15862 RGFW_api.monitor_setMode = RGFW_monitor_setMode_Wayland;
15863 RGFW_api.window_getMonitor = RGFW_window_getMonitor_Wayland;
15864 RGFW_api.window_closePlatform = RGFW_window_closePlatform_Wayland;
15865#ifdef RGFW_OPENGL
15866 RGFW_api.extensionSupportedPlatform_OpenGL = RGFW_extensionSupportedPlatform_OpenGL_Wayland;
15867 RGFW_api.getProcAddress_OpenGL = RGFW_getProcAddress_OpenGL_Wayland;
15868 RGFW_api.window_createContextPtr_OpenGL = RGFW_window_createContextPtr_OpenGL_Wayland;
15869 RGFW_api.window_deleteContextPtr_OpenGL = RGFW_window_deleteContextPtr_OpenGL_Wayland;
15870 RGFW_api.window_makeCurrentContext_OpenGL = RGFW_window_makeCurrentContext_OpenGL_Wayland;
15871 RGFW_api.getCurrentContext_OpenGL = RGFW_getCurrentContext_OpenGL_Wayland;
15872 RGFW_api.window_swapBuffers_OpenGL = RGFW_window_swapBuffers_OpenGL_Wayland;
15873 RGFW_api.window_swapInterval_OpenGL = RGFW_window_swapInterval_OpenGL_Wayland;
15874#endif
15875#ifdef RGFW_WEBGPU
15876 RGFW_api.window_createSurface_WebGPU = RGFW_window_createSurface_WebGPU_Wayland;
15877#endif
15878}
15879#endif /* wayland AND x11 */
15880/* end of X11 AND wayland defines */
15881
15882#endif /* RGFW_IMPLEMENTATION */
15883
15884#if defined(__cplusplus) && !defined(__EMSCRIPTEN__)
15885}
15886#endif
15887
15888#if _MSC_VER
15889 #pragma warning( pop )
15890#endif
15891
Copyright 2026  E766CB298A6D1E64 | Git-Thing heavily inspired by cgit