0/*
1*
2* RGFW 2.0.0-dev
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.
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*/
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*/
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
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
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)
66 #define RGFW_EXPORT - use when building RGFW
67 #define RGFW_IMPORT - use when linking with RGFW (not as a single-header)
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*/
73/*
74Example to get you started :
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
80#define RGFW_IMPLEMENTATION
81#include "RGFW.h"
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};
85int main() {
86 RGFW_window* win = RGFW_createWindow("name", 100, 100, 500, 500, (u64)0);
87 RGFW_event event;
89 RGFW_window_setExitKey(win, RGFW_escape);
90 RGFW_window_setIcon(win, icon, 3, 3, RGFW_formatRGBA8);
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 }
99 RGFW_window_close(win);
100}
102 compiling :
104 if you wish to compile the library all you have to do is create a new file with this in it
106 rgfw.c
107 #define RGFW_IMPLEMENTATION
108 #include "RGFW.h"
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
115 then you can use gcc (or whatever compile you wish to use) to compile the library into object file
117 ex. gcc -c RGFW.c -fPIC
119 after you compile the library into an object file, you can also turn the object file into an static or shared library
121 (commands ar and gcc can be replaced with whatever equivalent your system uses)
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*/
135/*
136 Credits :
137 EimaMei/Sacode : Code review, helped with X11, MacOS and Windows support, Silicon, siliapp.h -> referencing
139 stb : This project is heavily inspired by the stb single header files
141 SDL, GLFW and other online resources : reference implementations
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*/
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
190#if defined(RGFW_EGL) && !defined(RGFW_OPENGL)
191 #define RGFW_OPENGL
192#endif
194/* these OS macros look better & are standardized */
195/* plus it helps with cross-compiling */
197#ifdef __EMSCRIPTEN__
198 #define RGFW_WASM
199#endif
201#if defined(RGFW_X11) && defined(__APPLE__) && !defined(RGFW_CUSTOM_BACKEND)
202 #define RGFW_MACOS_X11
203 #define RGFW_UNIX
204#endif
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
227#ifndef RGFW_ASSERT
228 #include <assert.h>
229 #define RGFW_ASSERT assert
230#endif
232#if !defined(__STDC_VERSION__)
233 #define RGFW_C89
234#endif
236#if !defined(RGFW_SNPRINTF) && (defined(RGFW_X11) || defined(RGFW_WAYLAND))
238 /* required for X11 errors */
239 #include <stdio.h>
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
258#ifndef RGFW_USERPTR
259 #define RGFW_USERPTR NULL
260#endif
262#ifndef RGFW_UNUSED
263 #define RGFW_UNUSED(x) (void)(x)
264#endif
266#ifndef RGFW_ROUND
267 #define RGFW_ROUND(x) (i32)((x) >= 0 ? (x) + 0.5f : (x) - 0.5f)
268#endif
270#ifndef RGFW_ROUNDF
271 #define RGFW_ROUNDF(x) (float)((i32)((x) + ((x) < 0.0f ? -0.5f : 0.5f)))
272#endif
274#ifndef RGFW_MIN
275 #define RGFW_MIN(x, y) ((x < y) ? x : y)
276#endif
278#ifndef RGFW_ALLOC
279 #include <stdlib.h>
280 #define RGFW_ALLOC malloc
281 #define RGFW_FREE free
282#endif
284#if !defined(RGFW_MEMCPY) || !defined(RGFW_STRNCMP) || !defined(RGFW_STRNCPY) || !defined(RGFW_MEMSET)
285 #include <string.h>
286#endif
288#ifndef RGFW_MEMSET
289 #define RGFW_MEMSET(ptr, value, num) memset(ptr, value, num)
290#endif
292#ifndef RGFW_MEMCPY
293 #define RGFW_MEMCPY(dist, src, len) memcpy(dist, src, len)
294#endif
296#ifndef RGFW_STRNCMP
297 #define RGFW_STRNCMP(s1, s2, max) strncmp(s1, s2, max)
298#endif
300#ifndef RGFW_STRNCPY
301 #define RGFW_STRNCPY(dist, src, len) strncpy(dist, src, len)
302#endif
304#ifndef RGFW_STRSTR
305 #define RGFW_STRSTR(str, substr) strstr(str, substr)
306#endif
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
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
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
328#ifndef RGFW_MAX_EVENTS
329 #define RGFW_MAX_EVENTS 32
330#endif
332#ifndef RGFW_MAX_MONITORS
333 #define RGFW_MAX_MONITORS 6
334#endif
336#ifndef RGFW_COCOA_FRAME_NAME
337 #define RGFW_COCOA_FRAME_NAME NULL
338#endif
340#ifdef RGFW_WIN95 /* for windows 95 testing (not that it really works) */
341 #define RGFW_NO_PASSTHROUGH
342#endif
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
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
365#ifndef RGFWDEF
366 #ifdef RGFW_C89
367 #define RGFWDEF __inline
368 #else
369 #define RGFWDEF inline
370 #endif
371#endif
373#if defined(__cplusplus) && !defined(__EMSCRIPTEN__)
374 extern "C" {
375#endif
377/* makes sure the header file part is only defined once by default */
378#ifndef RGFW_HEADER
380#define RGFW_HEADER
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>
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
408typedef ptrdiff_t RGFW_ssize_t;
410#ifndef RGFW_BOOL_DEFINED
411 #define RGFW_BOOL_DEFINED
412 typedef u8 RGFW_bool;
413#endif
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
419#define RGFW_ENUM(type, name) type name; enum
420#define RGFW_BIT(x) (1 << (x))
422#ifdef RGFW_VULKAN
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
446#endif
449/*! @brief The stucture that contains information about the current RGFW instance */
450typedef struct RGFW_info RGFW_info;
452/*! @brief The window stucture for interfacing with the window */
453typedef struct RGFW_window RGFW_window;
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;
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};
469/*! @brief layout struct for mapping out format types */
470typedef struct RGFW_colorLayout { i32 r, g, b, a; u32 channels; } RGFW_colorLayout;
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);
475/*! @brief a stucture for interfacing with the underlying native image (e.g. XImage, HBITMAP, etc) */
476typedef struct RGFW_nativeImage RGFW_nativeImage;
478/*! @brief a stucture for interfacing with pixel data as a renderable surface */
479typedef struct RGFW_surface RGFW_surface;
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;
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;
497/*! @brief structure for monitor node and source monitor data */
498typedef struct RGFW_monitorNode RGFW_monitorNode;
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;
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};
520/*! a raw pointer to the underlying mouse handle for setting and creating custom mouse icons */
521typedef void RGFW_mouse;
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};
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};
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};
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
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 */
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
705 RGFW_event.drop.count holds how many files were dropped
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};
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),
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};
753/*! Event structure(s) and union for checking/getting events */
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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};
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};
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};
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};
917/*! @breif flash request type */
918typedef RGFW_ENUM(u8, RGFW_flashRequest) {
919 RGFW_flashCancel = 0,
920 RGFW_flashBriefly,
921 RGFW_flashUntilFocused
922};
924/*! @brief the type of debug message */
925typedef RGFW_ENUM(u8, RGFW_debugType) {
926 RGFW_typeError = 0, RGFW_typeWarning, RGFW_typeInfo
927};
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};
947/*! @brief callback function type for debug messags */
948typedef void (* RGFW_debugfunc)(RGFW_debugType type, RGFW_errorCode err, const char* msg);
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) */
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);
989/*! @brief function pointer equivalent of void* */
990typedef void (*RGFW_proc)(void);
992#if defined(RGFW_OPENGL)
994/*! @brief abstract structure for interfacing with the underlying OpenGL API */
995typedef struct RGFW_glContext RGFW_glContext;
997/*! @brief abstract structure for interfacing with the underlying EGL API */
998typedef struct RGFW_eglContext RGFW_eglContext;
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};
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};
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};
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;
1042#endif
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
1117/**!
1118 * @brief (macOS only) Changes the current working directory to the application’s resource folder.
1119*/
1120RGFWDEF void RGFW_moveToMacOSResourceDir(void);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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*/
1238RGFWDEF RGFW_bool RGFW_monitor_findClosestMode(RGFW_monitor* monitor, RGFW_monitorMode* mode, RGFW_monitorMode* closest);
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);
1246/**!
1247 * @brief Free the gamma ramp allocated by RGFW
1248 * @param allocated gamma ramp
1249*/
1250RGFWDEF void RGFW_freeGammaRamp(RGFW_gammaRamp* ramp);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
1423/**!
1424* @brief check all the events until there are none left and updates window structure attributes
1425*/
1426RGFWDEF void RGFW_pollEvents(void);
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);
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);
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);
1457/** * @defgroup Input
1458* @{ */
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);
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);
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);
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);
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);
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);
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);
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/** @} */
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);
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);
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);
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);
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);
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);
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); /*!< */
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
1731/** * @defgroup Window_management
1732* @{ */
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
1941/**!
1942 * @brief maximizes the window
1943 * @param win a pointer to the target window
1944*/
1945RGFWDEF void RGFW_window_maximize(RGFW_window* win);
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);
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);
1960/**!
1961 * @brief minimizes the window
1962 * @param win a pointer to the target window
1963*/
1964RGFWDEF void RGFW_window_minimize(RGFW_window* win);
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);
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);
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);
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);
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);
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);
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);
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
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
2117/**!
2118 * @brief Hides the window from view.
2119 * @param win The target window.
2120*/
2121RGFWDEF void RGFW_window_hide(RGFW_window* win);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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/** @} */
2227/** * @defgroup Monitor
2228* @{ */
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);
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);
2246/** @} */
2248/** * @defgroup Clipboard
2249* @{ */
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);
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);
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/** @} */
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);
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/** @} */
2294/**
2297 event callbacks.
2298 These are completely optional, so you can use the normal
2299 RGFW_checkEvent() method if you prefer that
2301* @defgroup Callbacks
2302* @{
2303*/
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
2431/** @} */
2433/** * @defgroup graphics_API
2434* @{ */
2436/*! native rendering API functions */
2437#if defined(RGFW_OPENGL)
2438/* these are native opengl specific functions and will NOT work with EGL */
2440/*!< make the window the current OpenGL drawing context
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*/
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);
2454/**!
2455 * @brief Resets the global OpenGL hints to their default values.
2456*/
2457RGFWDEF void RGFW_resetGlobalHints_OpenGL(void);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
2623/**!
2624 * @brief Retrieves the EGL display handle.
2625 * @return A pointer to the native EGLDisplay.
2626*/
2627RGFWDEF void* RGFW_getDisplay_EGL(void);
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);
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);
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);
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);
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);
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);
2675/**!
2676 * @brief Retrieves the current EGL context.
2677 * @return A pointer to the currently active EGLContext.
2678*/
2679RGFWDEF void* RGFW_getCurrentContext_EGL(void);
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);
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);
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);
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);
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
2719#ifdef RGFW_VULKAN
2720#include <vulkan/vulkan.h>
2722/* if you don't want to use the above macros */
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);
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);
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
2750#ifdef RGFW_DIRECTX
2751#ifndef RGFW_WINDOWS
2752 #undef RGFW_DIRECTX
2753#else
2754 #define OEMRESOURCE
2755 #include <dxgi.h>
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
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
2783/** @} */
2785/** * @defgroup Supporting
2786* @{ */
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);
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);
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);
2806/**!
2807 * @brief Clears all events from the RGFW event queue without processing them.
2808*/
2809RGFWDEF void RGFW_eventQueueFlush(void);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
2889/** @} */
2890#endif /* RGFW_HEADER */
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
2898 #ifdef RGFW_OPENGL
2899 struct RGFW_eglContext {
2900 void* ctx;
2901 void* surface;
2902 struct wl_egl_window* eglWindow;
2903 };
2905 typedef union RGFW_gfxContext {
2906 RGFW_glContext* native;
2907 RGFW_eglContext* egl;
2908 } RGFW_gfxContext;
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
2917 /*! source data for the window (used by the APIs) */
2918 #ifdef RGFW_WINDOWS
2920 #ifndef WIN32_LEAN_AND_MEAN
2921 #define WIN32_LEAN_AND_MEAN
2922 #endif
2923 #ifndef OEMRESOURCE
2924 #define OEMRESOURCE
2925 #endif
2927 #include <windows.h>
2929 struct RGFW_nativeImage {
2930 HBITMAP bitmap;
2931 u8* bitmapBits;
2932 RGFW_format format;
2933 HDC hdcMem;
2934 };
2936 #ifdef RGFW_OPENGL
2937 struct RGFW_glContext { HGLRC ctx; };
2938 #endif
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 };
2953#elif defined(RGFW_UNIX)
2954 #ifdef RGFW_X11
2955 #include <X11/Xlib.h>
2956 #include <X11/Xutil.h>
2958 #ifndef RGFW_NO_XRANDR
2959 #include <X11/extensions/Xrandr.h>
2960 #include <X11/Xresource.h>
2961 #endif
2962 #endif
2964 #ifdef RGFW_WAYLAND
2965 #ifdef RGFW_LIBDECOR
2966 #include <libdecor-0/libdecor.h>
2967 #endif
2969 #include <wayland-client.h>
2970 #include <errno.h>
2971 #endif
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 };
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
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 */
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;
3033 RGFW_bool using_custom_cursor;
3034 struct wl_surface* custom_cursor_surface;
3036 RGFW_monitorNode* active_monitor;
3038 struct wl_data_source *data_source; // offer data to other clients
3040 #ifdef RGFW_LIBDECOR
3041 struct libdecor* decorContext;
3042 #endif
3043#endif /* RGFW_WAYLAND */
3044 };
3046#elif defined(RGFW_MACOS)
3047 #include <CoreVideo/CoreVideo.h>
3049 struct RGFW_nativeImage {
3050 RGFW_format format;
3051 u8* buffer;
3052 void* rep;
3053 };
3055 #ifdef RGFW_OPENGL
3056 struct RGFW_glContext {
3057 void* ctx;
3058 void* format;
3059 };
3060 #endif
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 };
3073#elif defined(RGFW_WASM)
3075 #include <emscripten/html5.h>
3076 #include <emscripten/key_codes.h>
3078 struct RGFW_nativeImage {
3079 RGFW_format format;
3080 };
3082 #ifdef RGFW_OPENGL
3083 struct RGFW_glContext {
3084 EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx;
3085 };
3086 #endif
3088 struct RGFW_window_src {
3089 #ifdef RGFW_OPENGL
3090 RGFW_gfxContext ctx;
3091 RGFW_gfxContextType gfxType;
3092 #endif
3093 };
3095#endif
3097struct RGFW_surface {
3098 u8* data;
3099 i32 w, h;
3100 RGFW_format format;
3101 RGFW_convertImageDataFunc convertFunc;
3102 RGFW_nativeImage native;
3103};
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) */
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;
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 */
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 */
3137 RGFW_bool mouseLeave;
3138 RGFW_window* winLeave; /*!< if a mouse leaves one window and enters the next */
3139} RGFW_windowState;
3141typedef struct {
3142 RGFW_bool current;
3143 RGFW_bool prev;
3144} RGFW_keyState;
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};
3174typedef struct RGFW_monitorList {
3175 RGFW_monitorNode* head;
3176 RGFW_monitorNode* cur;
3177} RGFW_monitorList;
3179typedef struct RGFW_monitors {
3180 RGFW_monitorList list;
3181 RGFW_monitorList freeList;
3182 size_t count;
3184 RGFW_monitorNode* primary;
3185 RGFW_monitorNode data[RGFW_MAX_MONITORS];
3186} RGFW_monitors;
3188RGFWDEF RGFW_monitorNode* RGFW_monitors_add(const RGFW_monitor* mon);
3189RGFWDEF void RGFW_monitors_remove(RGFW_monitorNode* node, RGFW_monitorNode* prev);
3191struct RGFW_info {
3192 RGFW_window* root;
3193 i32 windowCount;
3195 RGFW_mouse* hiddenMouse;
3197 RGFW_event events[RGFW_MAX_EVENTS]; /* A circular buffer (FIFO), using eventBottom/Len */
3199 i32 eventBottom;
3200 i32 eventLen;
3201 RGFW_bool queueEvents;
3202 RGFW_bool polledEvents;
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
3215 const char* className;
3216 RGFW_bool useWaylandBool;
3217 RGFW_bool stopCheckEvents_bool ;
3218 u64 timerOffset;
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;
3245 struct zxdg_output_manager_v1 *xdg_output_manager;
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;
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;
3263 RGFW_window* kbOwner;
3264 RGFW_window* mouseOwner; /* what window has access to the mouse */
3266 #endif
3268 RGFW_monitors monitors;
3270 #ifdef RGFW_UNIX
3271 int eventWait_forceStop[3];
3272 i32 clock;
3273 #endif
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
3285 #ifdef RGFW_OPENGL
3286 RGFW_window* current;
3287 #endif
3288 #ifdef RGFW_EGL
3289 void* EGL_display;
3290 #endif
3292 RGFW_bool rawMouse; /* global raw mouse toggle */
3294 RGFW_windowState windowState; /*! for checking window state events */
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 */
3303#ifdef RGFW_IMPLEMENTATION
3305#ifndef RGFW_NO_MATH
3306#include <math.h>
3307#endif
3309/* global private API */
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);
3315RGFWDEF void RGFW_window_setFlagsInternal(RGFW_window* win, RGFW_windowFlags flags, RGFW_windowFlags cmpFlags);
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);
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);
3347RGFWDEF void RGFW_setBit(u32* var, u32 mask, RGFW_bool set);
3348RGFWDEF void RGFW_splitBPP(u32 bpp, RGFW_monitorMode* mode);
3350RGFWDEF void RGFW_window_captureMousePlatform(RGFW_window* win, RGFW_bool state);
3351RGFWDEF void RGFW_window_setRawMouseModePlatform(RGFW_window *win, RGFW_bool state);
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);
3356RGFWDEF RGFW_bool RGFW_loadEGL(void);
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);
3368RGFWDEF RGFW_bool RGFW_extensionSupportedStr(const char* extensions, const char* ext, size_t len);
3369#endif
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 */
3379RGFW_info* _RGFW = NULL;
3380void RGFW_setInfo(RGFW_info* info) { _RGFW = info; }
3381RGFW_info* RGFW_getInfo(void) { return _RGFW; }
3384void* RGFW_alloc(size_t size) { return RGFW_ALLOC(size); }
3385void RGFW_free(void* ptr) { RGFW_FREE(ptr); }
3387void RGFW_useWayland(RGFW_bool wayland) { RGFW_init(); _RGFW->useWaylandBool = RGFW_BOOL(wayland); }
3388RGFW_bool RGFW_usingWayland(void) { return _RGFW->useWaylandBool; }
3390void RGFW_setRawMouseMode(RGFW_bool state) {
3391 _RGFW->rawMouse = state;
3392 RGFW_window_setRawMouseModePlatform(_RGFW->root, state);
3393}
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}
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";
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';
3415 size = RGFW_readClipboardPtr(str, (size_t)size);
3417 RGFW_CHECK_CLIPBOARD();
3419 if (len != NULL) *len = (size_t)size;
3421 RGFW_clipboard_switch(str);
3422 return (const char*)str;
3423}
3425/*
3426RGFW_IMPLEMENTATION starts with generic RGFW defines
3428This is the start of keycode data
3429*/
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 }
3447 RGFW_resetKey();
3448}
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;
3455 return _RGFW->keycodes[keycode];
3456}
3458u32 RGFW_rgfwToApiKey(RGFW_key keycode) {
3459 /* make sure the key isn't out of bounds */
3460 return _RGFW->apiKeycodes[keycode];
3461}
3463void RGFW_resetKey(void) { RGFW_MEMSET(_RGFW->keyboard, 0, sizeof(_RGFW->keyboard)); }
3464/*
3465 this is the end of keycode data
3466*/
3468/*
3469 event callback defines start here
3470*/
3473/*
3474 These exist to avoid the
3475 if (func == NULL) check
3476 for (allegedly) better performance
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}
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
3510void RGFW_windowMaximizedCallback(RGFW_window* win, i32 x, i32 y, i32 w, i32 h) {
3511 win->internal.flags |= RGFW_windowMaximize;
3513 if (!(win->internal.enabledEvents & RGFW_windowMaximizedFlag)) return;
3515 RGFW_event event;
3516 event.type = RGFW_windowMaximized;
3517 event.common.win = win;
3518 RGFW_eventQueuePush(&event);
3520 if (RGFW_windowMaximizedCallbackSrc) RGFW_windowMaximizedCallbackSrc(win, x, y, w, h);
3521}
3523void RGFW_windowMinimizedCallback(RGFW_window* win) {
3524 win->internal.flags |= RGFW_windowMinimize;
3526 if (!(win->internal.enabledEvents & RGFW_windowMinimizedFlag)) return;
3528 RGFW_event event;
3529 event.type = RGFW_windowMinimized;
3530 event.common.win = win;
3531 RGFW_eventQueuePush(&event);
3533 if (RGFW_windowMinimizedCallbackSrc) RGFW_windowMinimizedCallbackSrc(win);
3534}
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;
3540 if (!(win->internal.enabledEvents & RGFW_windowRestoredFlag)) return;
3542 RGFW_event event;
3543 event.type = RGFW_windowRestored;
3544 event.common.win = win;
3545 RGFW_eventQueuePush(&event);
3547 if (RGFW_windowRestoredCallbackSrc) RGFW_windowRestoredCallbackSrc(win, x, y, w, h);
3548}
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;
3555 RGFW_event event;
3556 event.type = RGFW_windowMoved;
3557 event.common.win = win;
3558 RGFW_eventQueuePush(&event);
3560 if (RGFW_windowMovedCallbackSrc) RGFW_windowMovedCallbackSrc(win, x, y);
3561}
3563void RGFW_windowResizedCallback(RGFW_window* win, i32 w, i32 h) {
3564 win->w = w;
3565 win->h = h;
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);
3573 if (RGFW_windowResizedCallbackSrc) RGFW_windowResizedCallbackSrc(win, w, h);
3574}
3576void RGFW_windowQuitCallback(RGFW_window* win) {
3577 win->internal.shouldClose = RGFW_TRUE;
3579 RGFW_event event;
3580 event.type = RGFW_quit;
3581 event.common.win = win;
3582 RGFW_eventQueuePush(&event);
3584 if (RGFW_windowQuitCallbackSrc) RGFW_windowQuitCallbackSrc(win);
3585}
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;
3593 if (!(win->internal.enabledEvents & RGFW_mousePosChangedFlag)) return;
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;
3603 RGFW_eventQueuePush(&event);
3605 if (RGFW_mousePosCallbackSrc) RGFW_mousePosCallbackSrc(win, x, y, vecX, vecY);
3606}
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);
3615 if (RGFW_windowRefreshCallbackSrc) RGFW_windowRefreshCallbackSrc(win);
3616}
3618void RGFW_focusCallback(RGFW_window* win, RGFW_bool inFocus) {
3619 win->internal.inFocus = inFocus;
3621 if (win->internal.captureMouse) {
3622 RGFW_window_captureMousePlatform(win, inFocus);
3623 }
3625 RGFW_event event;
3626 event.common.win = win;
3628 if (inFocus == RGFW_TRUE) {
3629 if ((win->internal.flags & RGFW_windowFullscreen))
3630 RGFW_window_raise(win);
3632 event.type = RGFW_focusIn;
3633 } else if (inFocus == RGFW_FALSE) {
3634 if ((win->internal.flags & RGFW_windowFullscreen))
3635 RGFW_window_minimize(win);
3637 size_t key;
3638 for (key = 0; key < RGFW_keyLast; key++) {
3639 if (RGFW_isKeyDown((u8)key) == RGFW_FALSE) continue;
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 }
3647 RGFW_resetKey();
3648 event.type = RGFW_focusOut;
3649 }
3651 event.common.win = win;
3653 RGFW_eventQueuePush(&event);
3655 if (RGFW_focusCallbackSrc) RGFW_focusCallbackSrc(win, inFocus);
3656}
3658void RGFW_mouseNotifyCallback(RGFW_window* win, i32 x, i32 y, RGFW_bool status) {
3659 win->internal.mouseInside = status;
3660 _RGFW->windowState.win = win;
3662 win->internal.lastMouseX = x;
3663 win->internal.lastMouseY = y;
3665 RGFW_event event;
3666 event.common.win = win;
3667 event.mouse.x = x;
3668 event.mouse.y = y;
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 }
3682 RGFW_eventQueuePush(&event);
3684 if (RGFW_mouseNotifyCallbackSrc) RGFW_mouseNotifyCallbackSrc(win, x, y, status);
3685}
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;
3691 _RGFW->windowState.win = win;
3692 _RGFW->windowState.dataDrop = RGFW_TRUE;
3693 _RGFW->windowState.filesCount = count;
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);
3702 if (RGFW_dataDropCallbackSrc) RGFW_dataDropCallbackSrc(win, files, count);
3703}
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;
3711 if (win->internal.enabledEvents & RGFW_dataDragFlag) return;
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);
3720 if (RGFW_dataDragCallbackSrc) RGFW_dataDragCallbackSrc(win, x, y);
3721}
3723void RGFW_keyCharCallback(RGFW_window* win, u32 codepoint) {
3724 if (!(win->internal.enabledEvents & RGFW_keyCharFlag)) return;
3726 RGFW_event event;
3727 event.type = RGFW_keyChar;
3728 event.keyChar.value = codepoint;
3729 event.common.win = win;
3730 RGFW_eventQueuePush(&event);
3732 if (RGFW_keyCharCallbackSrc) RGFW_keyCharCallbackSrc(win, codepoint);
3733}
3735void RGFW_keyCallback(RGFW_window* win, RGFW_key key, RGFW_keymod mod, RGFW_bool repeat, RGFW_bool press) {
3736 RGFW_event event;
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 }
3746 _RGFW->keyboard[key].prev = _RGFW->keyboard[key].current;
3747 _RGFW->keyboard[key].current = press;
3749 event.key.value = key;
3750 event.key.mod = repeat;
3751 event.key.mod = mod;
3752 event.common.win = win;
3753 RGFW_eventQueuePush(&event);
3755 if (RGFW_keyCallbackSrc) RGFW_keyCallbackSrc(win, key, mod, repeat, press);
3756}
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 }
3768 _RGFW->mouseButtons[button].prev = _RGFW->mouseButtons[button].current;
3769 _RGFW->mouseButtons[button].current = press;
3771 event.button.value = button;
3772 event.common.win = win;
3773 RGFW_eventQueuePush(&event);
3775 if (RGFW_mouseButtonCallbackSrc) RGFW_mouseButtonCallbackSrc(win, button, press);
3776}
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;
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);
3790 if (RGFW_mouseScrollCallbackSrc) RGFW_mouseScrollCallbackSrc(win, x, y);
3791}
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;
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);
3804 if (RGFW_scaleUpdatedCallbackSrc) RGFW_scaleUpdatedCallbackSrc(win, scaleX, scaleY);
3805}
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 }
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);
3819 if (RGFW_monitorCallbackSrc) RGFW_monitorCallbackSrc(win, monitor, connected);
3820}
3822#ifdef RGFW_DEBUG
3823#include <stdio.h>
3824#endif
3826void RGFW_sendDebugInfo(RGFW_debugType type, RGFW_errorCode err, const char* msg) {
3827 RGFW_debugCallback(type, err, msg);
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 }
3837 RGFW_PRINTF("\n");
3838 #endif
3839}
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}
3853/*
3854no more event call back defines
3855*/
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); }
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; }
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;
3880 if (w) *w = (i32)((float)win->w * mon->pixelRatio);
3881 if (h) *h = (i32)((float)win->h * mon->pixelRatio);
3883 return RGFW_TRUE;
3884}
3887#if defined(RGFW_USE_XDL) && defined(RGFW_X11)
3888 #define XDL_IMPLEMENTATION
3889 #include "XDL.h"
3890#endif
3892#ifndef RGFW_FORCE_INIT
3893RGFW_info _rgfwGlobal;
3894#endif
3896i32 RGFW_init(void) { return RGFW_init_ptr(&_rgfwGlobal); }
3897void RGFW_deinit(void) { RGFW_deinit_ptr(&_rgfwGlobal); }
3899i32 RGFW_initPlatform(void);
3900void RGFW_deinitPlatform(void);
3902i32 RGFW_init_ptr(RGFW_info* info) {
3903 if (info == _RGFW || info == NULL) return 1;
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
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));
3918 _RGFW->monitors.freeList.head = &_RGFW->monitors.data[0];
3919 _RGFW->monitors.freeList.cur = _RGFW->monitors.freeList.head;
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 }
3927 _RGFW->monitors.list.head = NULL;
3928 _RGFW->monitors.list.head = NULL;
3929 RGFW_initKeycodes();
3930 i32 out = RGFW_initPlatform();
3932 RGFW_pollMonitors();
3934 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, "global context initialized");
3936 return out;
3937}
3939#ifndef RGFW_EGL
3940void RGFW_unloadEGL(void) { }
3941#endif
3943void RGFW_deinit_ptr(RGFW_info* info) {
3944 if (info == NULL) return;
3946 RGFW_setInfo(info);
3947 RGFW_unloadEGL();
3948 RGFW_deinitPlatform();
3950 _RGFW->root = NULL;
3951 _RGFW->windowCount = 0;
3952 RGFW_setInfo(NULL);
3953 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, "global context deinitialized");
3954}
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}
3962void RGFW_window_close(RGFW_window* win) {
3963 RGFW_ASSERT(win != NULL);
3964 RGFW_window_closePtr(win);
3965 RGFW_FREE(win);
3966}
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";
3972 RGFW_MEMSET(win, 0, sizeof(RGFW_window));
3974 if (_RGFW == NULL) RGFW_init();
3975 _RGFW->windowCount++;
3977 /* rect based the requested flags */
3978 if (_RGFW->root == NULL) {
3979 RGFW_setRootWindow(win);
3980 }
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;
3990 RGFW_window* ret = RGFW_createWindowPlatform(name, flags, win);
3992#ifndef RGFW_X11
3993 RGFW_window_setFlagsInternal(win, flags, 0);
3994#endif
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
4002#ifdef RGFW_EGL
4003 if (flags & RGFW_windowEGL)
4004 RGFW_window_createContext_EGL(win, RGFW_getGlobalHints_OpenGL());
4005#endif
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
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
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
4038 if (!(flags & RGFW_windowHideMouse)) {
4039 RGFW_window_setMouseDefault(win);
4040 }
4042 RGFW_window_setName(win, name);
4043 if (!(flags & RGFW_windowHide)) {
4044 flags |= RGFW_windowHide;
4045 RGFW_window_show(win);
4046 }
4048 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, "a new window was created");
4050 return ret;
4051}
4053void RGFW_window_closePtr(RGFW_window* win) {
4054 RGFW_ASSERT(win != NULL);
4056 if (win->internal.captureMouse) {
4057 RGFW_window_captureMouse(win, RGFW_FALSE);
4058 }
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
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
4074 RGFW_window_closePlatform(win);
4076 RGFW_clipboard_switch(NULL);
4078 _RGFW->windowCount--;
4079 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, "a window was freed");
4081 if (_RGFW->windowCount == 0 && !(win->internal.flags & RGFW_noDeinitOnClose)) RGFW_deinit();
4082}
4084void RGFW_setQueueEvents(RGFW_bool queue) { _RGFW->queueEvents = RGFW_BOOL(queue); }
4086void RGFW_eventQueueFlush(void) { _RGFW->eventLen = 0; }
4088void RGFW_eventQueuePush(const RGFW_event* event) {
4089 if (_RGFW->queueEvents == RGFW_FALSE) return;
4090 RGFW_ASSERT(_RGFW->eventLen >= 0);
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 }
4098 i32 eventTop = (_RGFW->eventBottom + _RGFW->eventLen) % RGFW_MAX_EVENTS;
4099 _RGFW->eventLen += 1;
4100 _RGFW->events[eventTop] = *event;
4101}
4103RGFW_event* RGFW_eventQueuePop(void) {
4104 RGFW_ASSERT(_RGFW->eventLen >= 0 && _RGFW->eventLen <= RGFW_MAX_EVENTS);
4105 RGFW_event* ev;
4107 if (_RGFW->eventLen == 0) {
4108 return NULL;
4109 }
4111 ev = &_RGFW->events[_RGFW->eventBottom];
4112 _RGFW->eventLen -= 1;
4113 _RGFW->eventBottom = (_RGFW->eventBottom + 1) % RGFW_MAX_EVENTS;
4115 return ev;
4116}
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 }
4125 if (RGFW_checkQueuedEvent(event) == RGFW_FALSE) {
4126 _RGFW->polledEvents = RGFW_FALSE;
4127 return RGFW_FALSE;
4128 }
4130 return RGFW_TRUE;
4131}
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 }
4143 return RGFW_FALSE;
4144}
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}
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}
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}
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}
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}
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; }
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);}
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}
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 }
4224 if (RGFW_window_checkQueuedEvent(win, event) == RGFW_FALSE) {
4225 _RGFW->polledEvents = RGFW_FALSE;
4226 return RGFW_FALSE;
4227 }
4229 return RGFW_TRUE;
4230}
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;
4240 *event = *ev;
4241 return RGFW_TRUE;
4242}
4244RGFW_event* RGFW_window_eventQueuePop(RGFW_window* win) {
4245 RGFW_event* ev = RGFW_eventQueuePop();
4246 if (ev == NULL) return ev;
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 }
4253 if (ev->common.win != win && ev->common.win != NULL) {
4254 return NULL;
4255 }
4257 return ev;
4258}
4260void RGFW_setRootWindow(RGFW_window* win) { _RGFW->root = win; }
4261RGFW_window* RGFW_getRootWindow(void) { return _RGFW->root; }
4263#ifndef RGFW_EGL
4264RGFW_bool RGFW_loadEGL(void) { return RGFW_FALSE; }
4265#endif
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);
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 }
4299 win->internal.flags = flags;
4300}
4303void RGFW_window_setFlags(RGFW_window* win, RGFW_windowFlags flags) { RGFW_window_setFlagsInternal(win, flags, win->internal.flags); }
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}
4313void RGFW_setClassName(const char* name) { RGFW_init(); _RGFW->className = name; }
4315#ifndef RGFW_X11
4316void RGFW_setXInstName(const char* name) { RGFW_UNUSED(name); }
4317#endif
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}
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); }
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); }
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
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
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
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
4358void RGFW_setBit(u32* var, u32 mask, RGFW_bool set) {
4359 if (set) *var |= mask;
4360 else *var &= ~mask;
4361}
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;
4368 RGFW_window_move(win, (i32)(mon->mode.w - win->w) / 2, (mon->mode.h - win->h) / 2);
4369}
4371RGFW_bool RGFW_monitor_scaleToWindow(RGFW_monitor* mon, RGFW_window* win) {
4372 RGFW_monitorMode mode;
4373 RGFW_ASSERT(win != NULL);
4375 mode.w = win->w;
4376 mode.h = win->h;
4377 RGFW_bool ret = RGFW_monitor_requestMode(mon, &mode, RGFW_monitorScale);
4380 /* move window to monitor origin so it doesn't move to the next monitor */
4381 RGFW_window_move(win, mon->x, mon->y);
4383 return ret;
4384}
4386void RGFW_splitBPP(u32 bpp, RGFW_monitorMode* mode) {
4387 if (bpp == 32) bpp = 24;
4388 mode->red = mode->green = mode->blue = (u8)(bpp / 3);
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}
4395RGFW_bool RGFW_monitorModeCompare(RGFW_monitorMode* mon, RGFW_monitorMode* mon2, RGFW_modeRequest request) {
4396 RGFW_ASSERT(mon);
4397 RGFW_ASSERT(mon2);
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}
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}
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}
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;
4421 RGFW_window_resize(win, (i32)(monitor->scaleX * (float)win->w), (i32)(monitor->scaleY * (float)win->h));
4422}
4424void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor* m) {
4425 RGFW_window_move(win, m->x + win->x, m->y + win->y);
4426}
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}
4435void RGFW_surface_setConvertFunc(RGFW_surface* surface, RGFW_convertImageDataFunc func) {
4436 surface->convertFunc = func;
4437}
4439void RGFW_surface_free(RGFW_surface* surface) {
4440 RGFW_surface_freePtr(surface);
4441 RGFW_FREE(surface);
4442}
4444RGFW_nativeImage* RGFW_surface_getNativeImage(RGFW_surface* surface) {
4445 return &surface->native;
4446}
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}
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
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};
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}
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};
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;
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];
4495 i2 += 1 + is64bit;
4496 }
4497}
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);
4502 u32 count = (u32)(dest_w * dest_h);
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 }
4510 const RGFW_colorLayout* srcLayout = &RGFW_layouts[src_format];
4511 const RGFW_colorLayout* destLayout = &RGFW_layouts[dest_format];
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}
4520RGFW_monitorNode* RGFW_monitors_add(const RGFW_monitor* mon) {
4521 RGFW_monitorNode* node = NULL;
4522 if (_RGFW->monitors.freeList.head == NULL) return node;
4524 node = _RGFW->monitors.freeList.head;
4526 _RGFW->monitors.freeList.head = node->next;
4527 if (_RGFW->monitors.freeList.head == NULL) {
4528 _RGFW->monitors.freeList.cur = NULL;
4529 }
4531 node->next = NULL;
4533 if (_RGFW->monitors.list.head == NULL) {
4534 _RGFW->monitors.list.head = node;
4535 } else {
4536 _RGFW->monitors.list.cur->next = node;
4537 }
4539 _RGFW->monitors.list.cur = node;
4541 if (mon) node->mon = *mon;
4542 node->mon.node = node;
4543 node->disconnected = RGFW_FALSE;
4545 _RGFW->monitors.count += 1;
4546 return node;
4547}
4549void RGFW_monitors_remove(RGFW_monitorNode* node, RGFW_monitorNode* prev) {
4550 _RGFW->monitors.count -= 1;
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 }
4559 node->next = NULL;
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 }
4568 _RGFW->monitors.freeList.cur = node;
4569}
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;
4576 RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_FALSE);
4577 RGFW_monitors_remove(node, prev);
4578 prev = node;
4579 }
4580}
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);
4587 if (count) *count = num;
4588 return modes;
4589}
4591void RGFW_freeModes(RGFW_monitorMode* modes) {
4592 RGFW_FREE(modes);
4593}
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);
4600 RGFW_monitorMode* chosen = NULL;
4602 u32 topScore = 1;
4603 for (size_t i = 0; i < count; i++) {
4604 RGFW_monitorMode* mode2 = &modes[i];
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;
4611 if (score > topScore) {
4612 topScore = score;
4613 chosen = mode2;
4614 }
4615 }
4617 if (chosen && closest) *closest = *chosen;
4620 RGFW_FREE(modes);
4622 return (chosen == NULL) ? RGFW_FALSE : RGFW_TRUE;
4623}
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}
4631const char* RGFW_monitor_getName(RGFW_monitor* monitor) {
4632 return monitor->name;
4633}
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}
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}
4647void RGFW_monitor_setUserPtr(RGFW_monitor* monitor, void* userPtr) {
4648 monitor->userPtr = userPtr;
4649}
4651void* RGFW_monitor_getUserPtr(RGFW_monitor* monitor) {
4652 return monitor->userPtr;
4653}
4655RGFW_bool RGFW_monitor_getMode(RGFW_monitor* monitor, RGFW_monitorMode* mode) {
4656 if (mode) *mode = monitor->mode;
4657 return RGFW_TRUE;
4658}
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);
4668 return ramp;
4669}
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}
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);
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);
4690 ptr[i] = (u16)value;
4691 }
4693 RGFW_gammaRamp ramp;
4694 ramp.red = ptr;
4695 ramp.green = ptr;
4696 ramp.blue = ptr;
4697 ramp.count = count;
4699 return RGFW_monitor_setGammaRamp(monitor, &ramp);
4700}
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));
4706 RGFW_bool ret = RGFW_monitor_setGammaPtr(monitor, gamma, ptr, count);
4707 RGFW_FREE(ptr);
4709 return ret;
4710}
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 }
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}
4729RGFW_monitor* RGFW_getPrimaryMonitor(void) {
4730 if (_RGFW->monitors.primary == NULL) {
4731 _RGFW->monitors.primary = _RGFW->monitors.list.head;
4732 }
4734 return &_RGFW->monitors.primary->mon;
4735}
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}
4741void RGFW_window_captureMouse(RGFW_window* win, RGFW_bool state) {
4742 win->internal.captureMouse = state;
4743 RGFW_window_captureMousePlatform(win, state);
4744}
4746void RGFW_window_setRawMouseMode(RGFW_window* win, RGFW_bool state) {
4747 win->internal.rawMouse = state;
4748 RGFW_window_setRawMouseModePlatform(win, state);
4749}
4751void RGFW_window_captureRawMouse(RGFW_window* win, RGFW_bool state) {
4752 RGFW_window_captureMouse(win, state);
4753 RGFW_window_setRawMouseMode(win, state);
4754}
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); }
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}
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}
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}
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}
4790RGFW_bool RGFW_window_isMouseHidden(RGFW_window* win) {
4791 return (RGFW_bool)RGFW_BOOL(((RGFW_window*)win)->internal.flags & RGFW_windowHideMouse);
4792}
4794RGFW_bool RGFW_window_borderless(RGFW_window* win) {
4795 return (RGFW_bool)RGFW_BOOL(win->internal.flags & RGFW_windowNoBorder);
4796}
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); }
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
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
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
4825#ifndef RGFW_MACOS
4826void RGFW_moveToMacOSResourceDir(void) { }
4827#endif
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}
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 };
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 }
4852 *starting_index += count;
4854 RGFW_ASSERT(count <= 6);
4855 return codepoint - offsets[count - 1];
4856}
4858/*
4859 graphics API specific code (end of generic code)
4860 starts here
4861*/
4864/*
4865 OpenGL defines start here (Normal, EGL, OSMesa)
4866*/
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}
4898RGFW_glHints RGFW_globalHints_OpenGL_SRC = RGFW_DEFAULT_GL_HINTS;
4899RGFW_glHints* RGFW_globalHints_OpenGL = &RGFW_globalHints_OpenGL_SRC;
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; }
4912void* RGFW_glContext_getSourceContext(RGFW_glContext* ctx) {
4913 RGFW_UNUSED(ctx);
4915#ifdef RGFW_WAYLAND
4916 if (RGFW_usingWayland()) return (void*)ctx->egl.ctx;
4917#endif
4919#if defined(RGFW_X11)
4920 return (void*)ctx->ctx;
4921#else
4922 return NULL;
4923#endif
4924}
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}
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}
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}
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;
4957 if (extensions == NULL || ext == NULL) {
4958 return RGFW_FALSE;
4959 }
4961 while (ext[len - 1] == '\0' && len > 3) {
4962 len--;
4963 }
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 }
4975 return RGFW_FALSE;
4976}
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;
4984 GLint count = 0;
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);
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);
5005 if ((extensions != NULL) && RGFW_extensionSupportedStr(extensions, extension, len)) {
5006 return RGFW_TRUE;
5007 }
5008 }
5009 }
5010 return RGFW_FALSE;
5011}
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}
5018void RGFW_window_makeCurrentWindow_OpenGL(RGFW_window* win) {
5019 if (win) {
5020 _RGFW->current = win;
5021 }
5023 RGFW_window_makeCurrentContext_OpenGL(win);
5024}
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}
5038/* EGL */
5039#ifdef RGFW_EGL
5040#include <EGL/eglplatform.h>
5041#include <EGL/egl.h>
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;
5061#define EGL_SURFACE_MAJOR_VERSION_KHR 0x3098
5062#define EGL_SURFACE_MINOR_VERSION_KHR 0x30fb
5064#ifdef RGFW_WINDOWS
5065 #include <windows.h>
5066#elif defined(RGFW_MACOS) || defined(RGFW_UNIX)
5067 #include <dlfcn.h>
5068#endif
5070#ifdef RGFW_WAYLAND
5071#include <wayland-egl.h>
5072#endif
5074void* RGFW_eglLibHandle = NULL;
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; }
5081RGFW_bool RGFW_loadEGL(void) {
5082 RGFW_init();
5083 if (RGFW_eglGetProcAddress != NULL) {
5084 return RGFW_TRUE;
5085 }
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
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 }
5116 if (!RGFW_eglLibHandle || !RGFW_eglGetProcAddress) {
5117 return RGFW_FALSE;
5118 }
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");
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
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);
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 }
5194 RGFW_eglInitialize(_RGFW->EGL_display, NULL, NULL);
5195 return out;
5196}
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
5208 RGFW_eglLibHandle = NULL;
5209 RGFW_eglGetProcAddress = NULL;
5210}
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;
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
5222 #ifndef EGL_OPENGL_ES1_BIT
5223 #define EGL_OPENGL_ES1_BIT 0x1
5224 #endif
5226 EGLint egl_config[24];
5228 {
5229 RGFW_attribStack stack;
5230 RGFW_attribStack_init(&stack, egl_config, 24);
5232 RGFW_attribStack_pushAttribs(&stack, EGL_SURFACE_TYPE, EGL_WINDOW_BIT);
5233 RGFW_attribStack_pushAttrib(&stack, EGL_RENDERABLE_TYPE);
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 }
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);
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 }
5258 RGFW_attribStack_pushAttribs(&stack, EGL_NONE, EGL_NONE);
5259 }
5261 EGLint numConfigs, best_config = -1, best_samples = 0;
5263 RGFW_eglChooseConfig(_RGFW->EGL_display, egl_config, NULL, 0, &numConfigs);
5264 EGLConfig* configs = (EGLConfig*)RGFW_ALLOC(sizeof(EGLConfig) * (u32)numConfigs);
5266 RGFW_eglChooseConfig(_RGFW->EGL_display, egl_config, configs, numConfigs, &numConfigs);
5268#ifdef RGFW_X11
5269 RGFW_bool transparent = (win->internal.flags & RGFW_windowTransparent);
5270 EGLint best_depth = 0;
5271#endif
5273 for (EGLint i = 0; i < numConfigs; i++) {
5274 EGLint visual_id = 0;
5275 EGLint samples = 0;
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);
5280 if (best_config == -1) best_config = i;
5282#ifdef RGFW_X11
5283 if (_RGFW->useWaylandBool == RGFW_FALSE) {
5284 XVisualInfo vinfo_template;
5285 vinfo_template.visualid = (VisualID)visual_id;
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 }
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
5305 if (samples <= hints->samples && samples > best_samples) {
5306 best_config = i;
5307 best_samples = samples;
5308 }
5309 }
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;
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");
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 }
5340 RGFW_XCreateWindow(*result, "", win->internal.flags, win);
5342 if (showWindow) {
5343 RGFW_window_show(win);
5344 }
5345 XFree(result);
5346 }
5347 }
5348#endif
5350 EGLint surf_attribs[9];
5352 {
5353 RGFW_attribStack stack;
5354 RGFW_attribStack_init(&stack, surf_attribs, 9);
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));
5359 #ifndef EGL_PRESENT_OPAQUE_EXT
5360 #define EGL_PRESENT_OPAQUE_EXT 0x31df
5361 #endif
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
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));
5373 if (hints->sRGB && gl_colorspace_Found) {
5374 RGFW_attribStack_pushAttribs(&stack, EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR);
5375 }
5377 if (!(win->internal.flags & RGFW_windowTransparent) && opaque_extension_Found)
5378 RGFW_attribStack_pushAttribs(&stack, EGL_PRESENT_OPAQUE_EXT, EGL_TRUE);
5380 if (hints->doubleBuffer == 0) {
5381 RGFW_attribStack_pushAttribs(&stack, EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER);
5382 }
5384 RGFW_attribStack_pushAttribs(&stack, EGL_NONE, EGL_NONE);
5385 }
5386 #if defined(RGFW_MACOS)
5387 void* layer = RGFW_getLayer_OSX();
5389 RGFW_window_setLayer_OSX(win, layer);
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
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 }
5413 EGLint attribs[20];
5414 {
5415 RGFW_attribStack stack;
5416 RGFW_attribStack_init(&stack, attribs, 20);
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 }
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 }
5432 RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_ROBUST_ACCESS, hints->robustness);
5433 RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_DEBUG, hints->debug);
5435 #ifndef EGL_CONTEXT_RELEASE_BEHAVIOR_KHR
5436 #define EGL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x2097
5437 #endif
5439 #ifndef EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR
5440 #define EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x2098
5441 #endif
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 }
5449 RGFW_attribStack_pushAttribs(&stack, EGL_NONE, EGL_NONE);
5450 }
5452 if (hints->profile == RGFW_glES)
5453 RGFW_eglBindAPI(EGL_OPENGL_ES_API);
5454 else
5455 RGFW_eglBindAPI(EGL_OPENGL_API);
5457 win->src.ctx.egl->ctx = RGFW_eglCreateContext(_RGFW->EGL_display, config, hints->shareEGL, attribs);
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 }
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}
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}
5475void RGFW_window_deleteContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ctx) {
5476 if (_RGFW->EGL_display == NULL) return;
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}
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}
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}
5503void* RGFW_getCurrentContext_EGL(void) {
5504 return RGFW_eglGetCurrentContext();
5505}
5507RGFW_proc RGFW_getProcAddress_EGL(const char* procname) {
5508 #if defined(RGFW_WINDOWS)
5509 RGFW_proc proc = (RGFW_proc) GetProcAddress(RGFW_wgl_dll, procname);
5511 if (proc)
5512 return proc;
5513 #endif
5515 return (RGFW_proc) RGFW_eglGetProcAddress(procname);
5516}
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}
5524void RGFW_window_swapInterval_EGL(RGFW_window* win, i32 swapInterval) {
5525 RGFW_ASSERT(win != NULL);
5526 RGFW_eglSwapInterval(_RGFW->EGL_display, swapInterval);
5527}
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}
5534void RGFW_window_makeCurrentWindow_EGL(RGFW_window* win) {
5535 _RGFW->current = win;
5536 RGFW_window_makeCurrentContext_EGL(win);
5537}
5539RGFW_window* RGFW_getCurrentWindow_EGL(void) { return _RGFW->current; }
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}
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}
5557#endif /* RGFW_EGL */
5559/*
5560 end of RGFW_EGL defines
5561*/
5562#endif /* end of RGFW_GL (OpenGL, EGL, OSMesa )*/
5564/*
5565 RGFW_VULKAN defines
5566*/
5567#ifdef RGFW_VULKAN
5568#ifdef RGFW_MACOS
5569#include <objc/message.h>
5570#endif
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;
5577 return (const char**)arr;
5578}
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);
5585 *surface = VK_NULL_HANDLE;
5587#ifdef RGFW_X11
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)
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 };
5599 return vkCreateWin32SurfaceKHR(instance, &win32, NULL, surface);
5600#endif
5601}
5602#endif
5604RGFW_bool RGFW_getPresentationSupport_Vulkan(VkPhysicalDevice physicalDevice, u32 queueFamilyIndex) {
5605 if (_RGFW == NULL) RGFW_init();
5606#ifdef RGFW_X11
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)
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 */
5627/*
5628This is where OS specific stuff starts
5629*/
5631/* start of unix (wayland or X11 (unix) ) defines */
5633#ifdef RGFW_UNIX
5634#include <fcntl.h>
5635#include <poll.h>
5636#include <unistd.h>
5638void RGFW_stopCheckEvents(void) {
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}
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}
5657void RGFW_waitForEvent(i32 waitMS) {
5658 if (waitMS == 0) return;
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 }
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;
5678 if (RGFW_usingWayland()) {
5679 #ifdef RGFW_WAYLAND
5680 fds[0].fd = wl_display_get_fd(_RGFW->wl_display);
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 }
5690 /* send any pending requests to the compositor */
5691 while (wl_display_flush(_RGFW->wl_display) == -1) {
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 }
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 }
5722 if (waitMS != RGFW_eventWaitNext) {
5723 waitMS -= (i32)(RGFW_linux_getTimeNS() - start) / (i32)1e+6;
5724 }
5725 }
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;
5738 if (waitMS != RGFW_eventWaitNext) {
5739 waitMS -= (i32)(RGFW_linux_getTimeNS() - start) / (i32)1e+6;
5740 }
5741 }
5742 #endif
5743 }
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));
5751 _RGFW->eventWait_forceStop[2] = 0;
5752 }
5753}
5755char* RGFW_strtok(char* str, const char* delimStr);
5756char* RGFW_strtok(char* str, const char* delimStr) {
5757 static char* static_str = NULL;
5759 if (str != NULL)
5760 static_str = str;
5762 if (static_str == NULL) {
5763 return NULL;
5764 }
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 }
5780 if (*static_str == '\0')
5781 return NULL;
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 }
5794 if (delim) {
5795 *static_str = '\0';
5796 static_str++;
5797 break;
5798 }
5799 static_str++;
5800 }
5802 return token_start;
5803}
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
5814RGFWDEF void RGFW_load_X11(void);
5815RGFWDEF void RGFW_load_Wayland(void);
5817#if !defined(RGFW_X11) || !defined(RGFW_WAYLAND)
5818void RGFW_load_X11(void) { }
5819void RGFW_load_Wayland(void) { }
5820#endif
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}
5947i32 RGFW_initPlatform(void) {
5948 #if defined(_POSIX_MONOTONIC_CLOCK)
5949 struct timespec ts;
5950 RGFW_MEMSET(&ts, 0, sizeof(struct timespec));
5952 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
5953 _RGFW->clock = CLOCK_MONOTONIC;
5954 #else
5955 _RGFW->clock = CLOCK_REALTIME;
5956 #endif
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}
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}
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}
6004#endif /* end of wayland or X11 defines */
6007/*
6010Start of Linux / Unix defines
6013*/
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
6022#include <dlfcn.h>
6023#include <unistd.h>
6025#include <limits.h> /* for data limits (mainly used in drag and drop functions) */
6026#include <poll.h>
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
6033#include <X11/Xatom.h>
6034#include <X11/keysymdef.h>
6035#include <X11/extensions/sync.h>
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>
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
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
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
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
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
6094 void* X11Xihandle = NULL;
6095#endif
6097#if !defined(RGFW_NO_X11_EXT_PRELOAD)
6098 typedef void (* PFN_XSyncIntToValue)(XSyncValue*, int);
6099 PFN_XSyncIntToValue XSyncIntToValueSRC = NULL;
6100 #define XSyncIntToValue XSyncIntToValueSRC
6102 typedef Status (* PFN_XSyncSetCounter)(Display*, XSyncCounter, XSyncValue);
6103 PFN_XSyncSetCounter XSyncSetCounterSRC = NULL;
6104 #define XSyncSetCounter XSyncSetCounterSRC
6106 typedef XSyncCounter (* PFN_XSyncCreateCounter)(Display*, XSyncValue);
6107 PFN_XSyncCreateCounter XSyncCreateCounterSRC = NULL;
6108 #define XSyncCreateCounter XSyncCreateCounterSRC
6110 typedef void (* PFN_XShapeCombineMask)(Display*,Window,int,int,int,Pixmap,int);
6111 PFN_XShapeCombineMask XShapeCombineMaskSRC;
6112 #define XShapeCombineMask XShapeCombineMaskSRC
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
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;
6125 #define XcursorImageLoadCursor XcursorImageLoadCursorSRC
6126 #define XcursorImageCreate XcursorImageCreateSRC
6127 #define XcursorImageDestroy XcursorImageDestroySRC
6129 void* X11Cursorhandle = NULL;
6130#endif
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 }
6139 return RGFW_TRUE;
6140}
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}
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}
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);
6159 if (_RGFW->im) {
6160 return;
6161 }
6163 _RGFW->im = XOpenIM(_RGFW->display, 0, NULL, NULL);
6164 if (_RGFW->im == NULL) {
6165 return;
6166 }
6168 RGFW_bool found = RGFW_FALSE;
6169 XIMStyles* styles = NULL;
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 }
6181 XFree(styles);
6182 }
6184 if (found == RGFW_FALSE) {
6185 XCloseIM(_RGFW->im);
6186 _RGFW->im = NULL;
6187 }
6189 XIMCallback callback;
6190 callback.callback = (XIMProc) RGFW_x11_imCallback;
6191 callback.client_data = NULL;
6192 XSetIMValues(_RGFW->im, XNDestroyCallback, &callback, NULL);
6193}
6195void* RGFW_getDisplay_X11(void) { return _RGFW->display; }
6196u64 RGFW_window_getWindow_X11(RGFW_window* win) { return (u64)win->src.window; }
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}
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;
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 }
6235 surface->native.bitmap = XCreateImage(_RGFW->display, attrs.visual, (u32)attrs.depth,
6236 ZPixmap, 0, NULL, (u32)surface->w, (u32)surface->h, 32, 0);
6238 surface->native.buffer = (u8*)RGFW_ALLOC((size_t)(w * h * 4));
6239 surface->native.format = RGFW_XImage_getFormat(surface->native.bitmap);
6241 if (surface->native.bitmap == NULL) {
6242 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, "Failed to create XImage.");
6243 return RGFW_FALSE;
6244 }
6246 surface->native.format = RGFW_formatBGRA8;
6247 return RGFW_TRUE;
6248}
6250RGFW_format RGFW_FUNC(RGFW_nativeFormat)(void) { return RGFW_formatBGRA8; }
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}
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);
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}
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}
6273#define RGFW_LOAD_ATOM(name) \
6274 static Atom name = 0; \
6275 if (name == 0) name = XInternAtom(_RGFW->display, #name, False);
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);
6281 struct __x11WindowHints {
6282 unsigned long flags, functions, decorations, status;
6283 long input_mode;
6284 } hints;
6285 hints.flags = 2;
6286 hints.decorations = border;
6288 XChangeProperty(_RGFW->display, win->src.window, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 32, PropModeReplace, (u8*)&hints, 5);
6290 if (RGFW_window_isHidden(win) == 0) {
6291 RGFW_window_hide(win);
6292 RGFW_window_show(win);
6293 }
6294}
6296void RGFW_FUNC(RGFW_window_setRawMouseModePlatform) (RGFW_window* win, RGFW_bool state) {
6297 RGFW_UNUSED(win); RGFW_UNUSED(state);
6298}
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}
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}
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}
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));
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);
6336 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errX11, buf);
6337 _RGFW->x11Error = ev;
6338 return 0;
6339}
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;
6345 /* make X window attrubutes */
6346 XSetWindowAttributes swa;
6347 RGFW_MEMSET(&swa, 0, sizeof(swa));
6349 win->src.parent = DefaultRootWindow(_RGFW->display);
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;
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);
6363 win->src.flashEnd = 0;
6365 XFreeColors(_RGFW->display, cmap, NULL, 0, 0);
6367 XSaveContext(_RGFW->display, win->src.window, _RGFW->context, (XPointer)win);
6369 win->src.gc = XCreateGC(_RGFW->display, win->src.window, 0, NULL);
6371 if (_RGFW->im) {
6372 XIMCallback callback;
6373 callback.callback = (XIMProc) RGFW_x11_icCallback;
6374 callback.client_data = (XPointer) win;
6376 win->src.ic = XCreateIC(_RGFW->im, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, win->src.window, XNFocusWindow, win->src.window, XNDestroyCallback, &callback, NULL);
6377 }
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;
6386 XClassHint hint;
6387 hint.res_class = (char*)_RGFW->className;
6389 if (_RGFW->instName == NULL) hint.res_name = (char*)name;
6390 else hint.res_name = (char*)_RGFW->instName;
6392 XSetClassHint(_RGFW->display, win->src.window, &hint);
6394 XWMHints hints;
6395 hints.flags = StateHint;
6396 hints.initial_state = NormalState;
6398 XSetWMHints(_RGFW->display, win->src.window, &hints);
6400 if (flags & RGFW_windowScaleToMonitor)
6401 RGFW_window_scaleToMonitor(win);
6403 XSelectInput(_RGFW->display, (Drawable) win->src.window, event_mask); /*!< tell X11 what events we want */
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);
6411 XMoveWindow(_RGFW->display, (Drawable) win->src.window, win->x, win->y); /*!< move the window to it's proper cords */
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;
6416 /* actions */
6417 Atom XdndAware = XInternAtom(_RGFW->display, "XdndAware", False);
6418 const u8 version = 5;
6420 XChangeProperty(_RGFW->display, win->src.window,
6421 XdndAware, 4, 32,
6422 PropModeReplace, &version, 1); /*!< turns on drag and drop */
6423 }
6425#ifdef RGFW_ADVANCED_SMOOTH_RESIZE
6426 RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST_COUNTER)
6427 RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST)
6429 Atom protcols[2] = {_NET_WM_SYNC_REQUEST, WM_DELETE_WINDOW};
6430 XSetWMProtocols(_RGFW->display, win->src.window, protcols, 2);
6432 XSyncValue initial_value;
6433 XSyncIntToValue(&initial_value, 0);
6434 win->src.counter = XSyncCreateCounter(_RGFW->display, initial_value);
6436 XChangeProperty(_RGFW->display, win->src.window, _NET_WM_SYNC_REQUEST_COUNTER, XA_CARDINAL, 32, PropModeReplace, (u8*)&win->src.counter, 1);
6437#endif
6439 win->src.x = win->x;
6440 win->src.y = win->y;
6441 win->src.w = win->w;
6442 win->src.h = win->h;
6444 XSetWindowBackground(_RGFW->display, win->src.window, None);
6445 XClearWindow(_RGFW->display, win->src.window);
6447 /* stupid hack to make resizing the window less bad */
6448 XSetWindowBackgroundPixmap(_RGFW->display, win->src.window, None);
6449}
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 }
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}
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}
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);
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]);
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;
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;
6498 Atom actualType = 0;
6499 int actualFormat = 0;
6500 unsigned long count = 0, bytesAfter = 0;
6502 XGetWindowProperty(_RGFW->display, request->requestor, request->property, 0, LONG_MAX,
6503 False, ATOM_PAIR, &actualType, &actualFormat, &count, &bytesAfter, (u8**) &targets);
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 }
6514 XChangeProperty(_RGFW->display,
6515 request->requestor, request->property, ATOM_PAIR, 32,
6516 PropModeReplace, (u8*) targets, (i32)count);
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 }
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;
6540 XSendEvent(_RGFW->display, request->requestor, False, 0, &reply);
6541 XFlush(_RGFW->display);
6542}
6544i32 RGFW_XHandleClipboardSelectionHelper(void);
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);
6550 if (sym < 256) {
6551 return (RGFW_key)sym;
6552 }
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 }
6623 return RGFW_keyNULL;
6624}
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);
6642 /* xdnd data */
6643 static Window source = 0;
6644 static long version = 0;
6645 static i32 format = 0;
6647 static float deltaX = 0.0f;
6648 static float deltaY = 0.0f;
6650 XEvent reply = { ClientMessage };
6651 XEvent E;
6653 XNextEvent(_RGFW->display, &E);
6655 if (E.type != GenericEvent) {
6656 deltaX = 0.0f;
6657 deltaY = 0.0f;
6658 }
6660#ifndef RGFW_NO_XRANDR
6661 if (E.type == _RGFW->xrandrEventBase + RRNotify) {
6662 RGFW_pollMonitors();
6663 return;
6664 }
6665#endif
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 }
6681 i32 index = 0;
6682 if (XIMaskIsSet(raw->valuators.mask, 0) != 0) {
6683 deltaX += (float)raw->raw_values[index];
6684 index += 1;
6685 }
6687 if (XIMaskIsSet(raw->valuators.mask, 1) != 0)
6688 deltaY += (float)raw->raw_values[index];
6690 _RGFW->vectorX = (float)deltaX;
6691 _RGFW->vectorY = (float)deltaY;
6692 }
6693 default: break;
6694 }
6696 XFreeEventData(_RGFW->display, &E.xcookie);
6697 return;
6698 }
6699 }
6701 RGFW_window* win = NULL;
6702 if (XFindContext(_RGFW->display, E.xany.window, _RGFW->context, (XPointer*) &win) != 0) {
6703 return;
6704 }
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 }
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 */
6718 RGFW_bool keyRepeat = RGFW_FALSE;
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 }
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);
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));
6739 if (win->src.ic && XFilterEvent(&E, None) == False) {
6740 char buffer[100];
6741 char* chars = buffer;
6743 Status status;
6744 size_t count = (size_t)Xutf8LookupString(win->src.ic, &E.xkey, buffer, sizeof(buffer) - 1, NULL, &status);
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 }
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 }
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);
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;
6773 RGFW_keyCharCallback(win, (u8)sym);
6774 }
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;
6782 RGFW_key value = (u8)RGFW_apiKeyToRGFW(E.xkey.keycode);
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));
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 }
6797 float scrollX = 0.0f;
6798 float scrollY = 0.0f;
6799 RGFW_mouseButton value = 0;
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 }
6814 if (scroll) {
6815 RGFW_mouseScrollCallback(win, scrollX, scrollY);
6816 break;
6817 }
6819 RGFW_mouseButtonCallback(win, value, RGFW_TRUE);
6820 break;
6821 }
6822 case ButtonRelease: {
6823 if (E.xbutton.button >= Button4 && E.xbutton.button <= 7) break;
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 }
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;
6842 case Expose: {
6843 RGFW_windowRefreshCallback(win);
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 }
6853 case PropertyNotify:
6854 if (E.xproperty.state != PropertyNewValue) break;
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 }
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);
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;
6894 i32 dragX = 0;
6895 i32 dragY = 0;
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;
6903 if (E.xclient.message_type == XdndEnter) {
6904 if (version > 5)
6905 break;
6907 unsigned long count;
6908 Atom* formats;
6909 Atom real_formats[6];
6910 Bool list = E.xclient.data.l[1] & 1;
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;
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;
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 }
6936 formats = real_formats;
6937 }
6939 Atom XtextPlain = XInternAtom(_RGFW->display, "text/plain", False);
6940 Atom XtextUriList = XInternAtom(_RGFW->display, "text/uri-list", False);
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 }
6950 if (list) {
6951 XFree(formats);
6952 }
6954 break;
6955 }
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;
6963 if (version > 5)
6964 break;
6966 XTranslateCoordinates(
6967 _RGFW->display, XDefaultRootWindow(_RGFW->display), win->src.window,
6968 xabs, yabs, &xpos, &ypos, &dummy
6969 );
6971 dragX = xpos;
6972 dragY = ypos;
6974 reply.xclient.window = source;
6975 reply.xclient.message_type = XdndStatus;
6977 if (format) {
6978 reply.xclient.data.l[1] = 1;
6979 if (version >= 2)
6980 reply.xclient.data.l[4] = (long)XdndActionCopy;
6981 }
6983 XSendEvent(_RGFW->display, source, False, NoEventMask, &reply);
6984 XFlush(_RGFW->display);
6985 break;
6986 }
6987 if (E.xclient.message_type != XdndDrop)
6988 break;
6990 if (version > 5)
6991 break;
6993 if (format) {
6994 Time time = (version >= 1)
6995 ? (Time)E.xclient.data.l[2]
6996 : CurrentTime;
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 };
7005 XSendEvent(_RGFW->display, source, False, NoEventMask, &new_reply);
7006 XFlush(_RGFW->display);
7007 }
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;
7018 Atom actualType;
7019 i32 actualFormat;
7020 unsigned long bytesAfter;
7022 XGetWindowProperty(_RGFW->display, E.xselection.requestor, E.xselection.property, 0, LONG_MAX, False, E.xselection.target, &actualType, &actualFormat, &result, &bytesAfter, (u8**) &data);
7024 if (result == 0)
7025 break;
7027 const char* prefix = (const char*)"file://";
7029 char* line;
7031 size_t count = 0;
7032 char** files = _RGFW->files;
7034 while ((line = (char*)RGFW_strtok(data, "\r\n"))) {
7035 data = NULL;
7037 if (line[0] == '#')
7038 continue;
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 }
7055 count++;
7057 size_t len = RGFW_unix_stringlen(line);
7058 char* path = (char*)RGFW_ALLOC(len + 1);
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 }
7074 path[index] = *line;
7075 }
7077 index++;
7078 line++;
7079 }
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 }
7087 RGFW_MEMCPY(files[count - 1], path, cnt);
7088 RGFW_FREE(path);
7089 }
7091 RGFW_dataDropCallback(win, files, count);
7092 if (data)
7093 XFree(data);
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 }
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 }
7136 i32 x = E.xconfigure.x;
7137 i32 y = E.xconfigure.y;
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 }
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 }
7161 XFlush(_RGFW->display);
7162}
7164void RGFW_FUNC(RGFW_pollEvents) (void) {
7165 RGFW_resetPrevState();
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}
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;
7179 XMoveWindow(_RGFW->display, win->src.window, x, y);
7180 return;
7181}
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;
7189 XResizeWindow(_RGFW->display, win->src.window, (u32)w, (u32)h);
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;
7197 XSetWMSizeHints(_RGFW->display, (Drawable) win->src.window, &sh, XA_WM_NORMAL_HINTS);
7198 }
7199 return;
7200}
7202void RGFW_FUNC(RGFW_window_setAspectRatio) (RGFW_window* win, i32 w, i32 h) {
7203 RGFW_ASSERT(win != NULL);
7206 if (w == 0 && h == 0)
7207 return;
7208 XSizeHints hints;
7209 long flags;
7211 XGetWMNormalHints(_RGFW->display, win->src.window, &hints, &flags);
7213 hints.flags |= PAspect;
7215 hints.min_aspect.x = hints.max_aspect.x = (i32)w;
7216 hints.min_aspect.y = hints.max_aspect.y = (i32)h;
7218 XSetWMNormalHints(_RGFW->display, win->src.window, &hints);
7219 return;
7220}
7222void RGFW_FUNC(RGFW_window_setMinSize) (RGFW_window* win, i32 w, i32 h) {
7223 RGFW_ASSERT(win != NULL);
7225 long flags;
7226 XSizeHints hints;
7227 RGFW_MEMSET(&hints, 0, sizeof(XSizeHints));
7229 XGetWMNormalHints(_RGFW->display, win->src.window, &hints, &flags);
7231 hints.flags |= PMinSize;
7233 hints.min_width = (i32)w;
7234 hints.min_height = (i32)h;
7236 XSetWMNormalHints(_RGFW->display, win->src.window, &hints);
7237 return;
7238}
7240void RGFW_FUNC(RGFW_window_setMaxSize) (RGFW_window* win, i32 w, i32 h) {
7241 RGFW_ASSERT(win != NULL);
7243 long flags;
7244 XSizeHints hints;
7245 RGFW_MEMSET(&hints, 0, sizeof(XSizeHints));
7247 XGetWMNormalHints(_RGFW->display, win->src.window, &hints, &flags);
7249 hints.flags |= PMaxSize;
7251 hints.max_width = (i32)w;
7252 hints.max_height = (i32)h;
7254 XSetWMNormalHints(_RGFW->display, win->src.window, &hints);
7255 return;
7256}
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);
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;
7276 XSendEvent(_RGFW->display, DefaultRootWindow(_RGFW->display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
7277}
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;
7285 RGFW_toggleXMaximized(win, 1);
7286 return;
7287}
7289void RGFW_FUNC(RGFW_window_focus) (RGFW_window* win) {
7290 RGFW_ASSERT(win);
7292 XWindowAttributes attr;
7293 XGetWindowAttributes(_RGFW->display, win->src.window, &attr);
7294 if (attr.map_state != IsViewable) return;
7296 XSetInputFocus(_RGFW->display, win->src.window, RevertToPointerRoot, CurrentTime);
7297 XFlush(_RGFW->display);
7298}
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}
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);
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;
7322 XSendEvent(_RGFW->display, DefaultRootWindow(_RGFW->display), False, SubstructureNotifyMask | SubstructureRedirectMask, &xev);
7323}
7325void RGFW_FUNC(RGFW_window_setFullscreen)(RGFW_window* win, RGFW_bool fullscreen) {
7326 RGFW_ASSERT(win != NULL);
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;
7337 XRaiseWindow(_RGFW->display, win->src.window);
7339 RGFW_LOAD_ATOM(_NET_WM_STATE_FULLSCREEN);
7340 RGFW_window_setXAtom(win, _NET_WM_STATE_FULLSCREEN, fullscreen);
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}
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}
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}
7366void RGFW_FUNC(RGFW_window_minimize)(RGFW_window* win) {
7367 RGFW_ASSERT(win != NULL);
7369 if (RGFW_window_isMaximized(win)) return;
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}
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);
7385 RGFW_window_show(win);
7386 XFlush(_RGFW->display);
7387}
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);
7393 Atom actual_type;
7394 int actual_format;
7395 unsigned long nitems, bytes_after;
7396 Atom* prop_return = NULL;
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);
7402 if (status != Success || actual_type != XA_ATOM)
7403 return RGFW_FALSE;
7405 unsigned long i;
7406 for (i = 0; i < nitems; i++)
7407 if (prop_return[i] == _NET_WM_STATE_ABOVE) return RGFW_TRUE;
7409 if (prop_return)
7410 XFree(prop_return);
7411 return RGFW_FALSE;
7412}
7414void RGFW_FUNC(RGFW_window_setName)(RGFW_window* win, const char* name) {
7415 RGFW_ASSERT(win != NULL);
7416 if (name == NULL) name = "\0";
7418 Xutf8SetWMProperties(_RGFW->display, win->src.window, name, name, NULL, 0, NULL, NULL, NULL);
7419 XStoreName(_RGFW->display, win->src.window, name);
7421 RGFW_LOAD_ATOM(_NET_WM_NAME); RGFW_LOAD_ATOM(UTF8_STRING);
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}
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);
7437 return;
7438 }
7440 XShapeCombineMask(_RGFW->display, win->src.window, ShapeInput, 0, 0, None, ShapeSet);
7441}
7442#endif /* RGFW_NO_PASSTHROUGH */
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 }
7455 i32 count = (i32)(2 + (w * h));
7457 unsigned long* data = (unsigned long*) RGFW_ALLOC((u32)count * sizeof(unsigned long));
7458 RGFW_ASSERT(data != NULL);
7460 RGFW_MEMSET(data, 0, (u32)count * sizeof(unsigned long));
7461 data[0] = (unsigned long)w;
7462 data[1] = (unsigned long)h;
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 }
7473 RGFW_copyImageData64((u8*)&data[2], w, h, RGFW_formatBGRA8, data_src, format, RGFW_FALSE, NULL);
7475 if (type & RGFW_iconWindow) {
7476 XWMHints wm_hints;
7477 wm_hints.flags = IconPixmapHint;
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);
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);
7488 XSetWMHints(_RGFW->display, win->src.window, &wm_hints);
7489 }
7491 RGFW_FREE(data);
7492 XFlush(_RGFW->display);
7493 return RGFW_BOOL(res);
7494}
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);
7506 Cursor cursor = XcursorImageLoadCursor(_RGFW->display, native);
7507 XcursorImageDestroy(native);
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}
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}
7521void RGFW_FUNC(RGFW_freeMouse)(RGFW_mouse* mouse) {
7522 RGFW_ASSERT(mouse);
7523 XFreeCursor(_RGFW->display, (Cursor)mouse);
7524}
7526void RGFW_FUNC(RGFW_window_moveMouse)(RGFW_window* win, i32 x, i32 y) {
7527 RGFW_ASSERT(win != NULL);
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);
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;
7541 XWarpPointer(_RGFW->display, None, win->src.window, 0, 0, 0, 0, (int) x - win->x, (int) y - win->y);
7542}
7544RGFW_bool RGFW_FUNC(RGFW_window_setMouseDefault) (RGFW_window* win) {
7545 return RGFW_window_setMouseStandard(win, RGFW_mouseArrow);
7546}
7548RGFW_bool RGFW_FUNC(RGFW_window_setMouseStandard) (RGFW_window* win, u8 mouse) {
7549 RGFW_ASSERT(win != NULL);
7551 u32 mouseIcon = 0;
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 }
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}
7584void RGFW_FUNC(RGFW_window_hide)(RGFW_window* win) {
7585 win->internal.flags |= (u32)RGFW_windowHide;
7586 XUnmapWindow(_RGFW->display, win->src.window);
7588 XFlush(_RGFW->display);
7589}
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);
7595 if (RGFW_window_isHidden(win) == RGFW_FALSE) {
7596 return;
7597 }
7599 XMapWindow(_RGFW->display, win->src.window);
7600 RGFW_window_move(win, win->x, win->y);
7602 RGFW_waitForShowEvent_X11(win);
7603 RGFW_window_setFullscreen(win, RGFW_window_isFullscreen(win));
7604 return;
7605}
7607void RGFW_FUNC(RGFW_window_flash) (RGFW_window* win, RGFW_flashRequest request) {
7608 if (RGFW_window_isInFocus(win) && request) {
7609 return;
7610 }
7612 XWMHints* wmhints = XGetWMHints(_RGFW->display, win->src.window);
7613 if (wmhints == NULL) return;
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 }
7626 XSetWMHints(_RGFW->display, win->src.window, wmhints);
7627 XFree(wmhints);
7628}
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 }
7640 XEvent event;
7641 int format;
7642 unsigned long N, sizeN;
7643 char* data;
7644 Atom target;
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;
7652 if (event.xselection.selection != CLIPBOARD || event.xselection.property == 0)
7653 return -1;
7654 break;
7655 }
7657 XGetWindowProperty(event.xselection.display, event.xselection.requestor,
7658 event.xselection.property, 0L, (~0L), 0, AnyPropertyType, &target,
7659 &format, &sizeN, &N, (u8**) &data);
7661 RGFW_ssize_t size;
7662 if (sizeN > strCapacity && str != NULL)
7663 size = -1;
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;
7671 XDeleteProperty(event.xselection.display, event.xselection.requestor, event.xselection.property);
7672 size = (RGFW_ssize_t)sizeN;
7674 return size;
7675}
7677i32 RGFW_XHandleClipboardSelectionHelper(void) {
7678 RGFW_LOAD_ATOM(SAVE_TARGETS);
7680 XEvent event;
7681 XPending(_RGFW->display);
7683 if (QLength(_RGFW->display) || XEventsQueued(_RGFW->display, QueuedAlready) + XEventsQueued(_RGFW->display, QueuedAfterReading))
7684 XNextEvent(_RGFW->display, &event);
7685 else
7686 return 0;
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 }
7699 return 0;
7700}
7702void RGFW_FUNC(RGFW_writeClipboard)(const char* text, u32 textLen) {
7703 RGFW_LOAD_ATOM(SAVE_TARGETS); RGFW_LOAD_ATOM(CLIPBOARD);
7704 RGFW_init();
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 }
7713 if (_RGFW->clipboard)
7714 RGFW_FREE(_RGFW->clipboard);
7716 _RGFW->clipboard = (char*)RGFW_ALLOC(textLen);
7717 RGFW_ASSERT(_RGFW->clipboard != NULL);
7719 RGFW_STRNCPY(_RGFW->clipboard, text, textLen - 1);
7720 _RGFW->clipboard[textLen - 1] = '\0';
7721 _RGFW->clipboard_len = textLen;
7722 return;
7723}
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);
7730 return (windowAttributes.map_state != IsViewable);
7731}
7733RGFW_bool RGFW_FUNC(RGFW_window_isMinimized)(RGFW_window* win) {
7734 RGFW_ASSERT(win != NULL);
7735 RGFW_LOAD_ATOM(WM_STATE);
7737 Atom actual_type;
7738 i32 actual_format;
7739 unsigned long nitems, bytes_after;
7740 unsigned char* prop_data;
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);
7746 if (status == Success && nitems >= 1 && prop_data == (unsigned char*)IconicState) {
7747 XFree(prop_data);
7748 return RGFW_TRUE;
7749 }
7751 if (prop_data != NULL)
7752 XFree(prop_data);
7754 XWindowAttributes windowAttributes;
7755 XGetWindowAttributes(_RGFW->display, win->src.window, &windowAttributes);
7756 return windowAttributes.map_state != IsViewable;
7757}
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);
7765 Atom actual_type;
7766 i32 actual_format;
7767 unsigned long nitems, bytes_after;
7768 unsigned char* prop_data;
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);
7774 if (status != Success) {
7775 if (prop_data != NULL)
7776 XFree(prop_data);
7778 return RGFW_FALSE;
7779 }
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 }
7790 if (prop_data != NULL)
7791 XFree(prop_data);
7793 return RGFW_FALSE;
7794}
7796RGFWDEF void RGFW_XGetSystemContentDPI(float* dpi);
7797void RGFW_XGetSystemContentDPI(float* dpi) {
7798 if (dpi == NULL) return;
7799 float dpiOutput = 96.0f;
7801 #ifndef RGFW_NO_XRANDR
7802 char* rms = XResourceManagerString(_RGFW->display);
7803 if (rms == NULL) return;
7805 XrmDatabase db = XrmGetStringDatabase(rms);
7806 if (db == NULL) return;
7808 XrmValue value;
7809 char* type = NULL;
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
7816 if (dpi) *dpi = dpiOutput;
7817}
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 }
7827 if (mi == None) return NULL;
7829 if ((mi->modeFlags & RR_Interlace) != 0) return NULL;
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 }
7841 RGFW_splitBPP((u32)DefaultDepth(_RGFW->display, DefaultScreen(_RGFW->display)), foundMode);
7843 foundMode->src = (void*)mode;
7845 foundMode->refreshRate = 0;
7846 if (mi->hTotal == 0 || mi->vTotal == 0)
7847 return mi;
7849 u32 vTotal = mi->vTotal;
7851 if (mi->modeFlags & RR_DoubleScan) {
7852 vTotal *= 2;
7853 }
7855 if (mi->modeFlags & RR_Interlace) {
7856 vTotal /= 2;
7857 }
7859 i32 numerator = (i32)mi->dotClock;
7860 i32 denominator = (i32)(mi->hTotal * vTotal);
7861 float refreshRate = 0;
7863 if (denominator <= 0) {
7864 denominator = 1;
7865 }
7867 refreshRate = ((float)numerator / (float)denominator);
7869 foundMode->refreshRate = RGFW_ROUNDF((refreshRate * 100)) / 100.0f;
7870 return mi;
7871}
7873void RGFW_FUNC(RGFW_pollMonitors) (void) {
7874 RGFW_init();
7876 Window root = XDefaultRootWindow(_RGFW->display);
7877 XRRScreenResources* res = XRRGetScreenResourcesCurrent(_RGFW->display, root);
7878 if (res == 0) {
7879 return;
7880 }
7882 RROutput primary = XRRGetOutputPrimary(_RGFW->display, root);
7884 for (RGFW_monitorNode* node = _RGFW->monitors.list.head; node; node = node->next) {
7885 node->disconnected = RGFW_TRUE;
7886 }
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 }
7896 if (node) {
7897 node->disconnected = RGFW_FALSE;
7898 if (node->rrOutput == primary) {
7899 _RGFW->monitors.primary = node;
7900 }
7901 continue;
7902 }
7904 RGFW_monitor monitor;
7906 XRROutputInfo* info = XRRGetOutputInfo(_RGFW->display, res, res->outputs[i]);
7907 if (info == NULL || info->connection != RR_Connected || info->crtc == None) {
7908 continue;
7909 }
7911 XRRCrtcInfo* ci = XRRGetCrtcInfo(_RGFW->display, res, info->crtc);
7913 if (ci == NULL) {
7914 continue;
7915 }
7917 float physW = (float)info->mm_width / 25.4f;
7918 float physH = (float)info->mm_height / 25.4f;
7920 RGFW_STRNCPY(monitor.name, info->name, sizeof(monitor.name) - 1);
7921 monitor.name[sizeof(monitor.name) - 1] = '\0';
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 }
7931 monitor.x = ci->x;
7932 monitor.y = ci->y;
7934 float dpi = 96.0f;
7935 RGFW_XGetSystemContentDPI(&dpi);
7937 monitor.scaleX = dpi / 96.0f;
7938 monitor.scaleY = dpi / 96.0f;
7940 monitor.pixelRatio = dpi >= 192.0f ? 2.0f : 1.0f;
7942 XRRModeInfo* mi = RGFW_XGetMode(ci, res, ci->mode, &monitor.mode);
7944 if (mi == NULL) {
7945 break;
7946 }
7948 XRRFreeCrtcInfo(ci);
7950 node = RGFW_monitors_add(&monitor);
7951 if (node == NULL) break;
7953 node->rrOutput = res->outputs[i];
7954 node->crtc = info->crtc;
7956 if (node->rrOutput == primary) {
7957 _RGFW->monitors.primary = node;
7958 }
7960 XRRFreeOutputInfo(info);
7961 info = NULL;
7963 RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_TRUE);
7964 }
7966 XRRFreeScreenResources(res);
7968 RGFW_monitors_refresh();
7969}
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);
7975 Window root = DefaultRootWindow(_RGFW->display);
7977 i32 areaX = monitor->x;
7978 i32 areaY = monitor->y;
7979 i32 areaW = monitor->mode.w;
7980 i32 areaH = monitor->mode.h;
7982 if (_NET_WORKAREA && _NET_CURRENT_DESKTOP) {
7983 Atom* extents = NULL;
7984 Atom* desktop = NULL;
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);
7991 unsigned long count;
7992 XGetWindowProperty(_RGFW->display, root, _NET_CURRENT_DESKTOP, 0, LONG_MAX, False, XA_CARDINAL, &actualType, &actualFormat, &count, &bytesAfter, (u8**) &desktop);
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];
8001 if (areaX < globalX) {
8002 areaW -= globalX - areaX;
8003 areaX = globalX;
8004 }
8006 if (areaY < globalY) {
8007 areaH -= globalY - areaY;
8008 areaY = globalY;
8009 }
8011 if (areaX + areaW > globalX + globalW)
8012 areaW = globalX - areaX + globalW;
8013 if (areaY + areaH > globalY + globalH)
8014 areaH = globalY - areaY + globalH;
8015 }
8016 }
8018 if (extents)
8019 XFree(extents);
8020 if (desktop)
8021 XFree(desktop);
8022 }
8024 if (x) *x = areaX;
8025 if (y) *y = areaY;
8026 if (width) *width = areaW;
8027 if (height) *height = areaH;
8029 return RGFW_TRUE;
8030}
8032size_t RGFW_FUNC(RGFW_monitor_getModesPtr) (RGFW_monitor* monitor, RGFW_monitorMode** modes) {
8033 size_t count = 0;
8035 XRRScreenResources* res = XRRGetScreenResourcesCurrent(_RGFW->display, DefaultRootWindow(_RGFW->display));
8036 if (res == NULL) return 0;
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;
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 }
8048 XRRFreeOutputInfo(oi);
8049 XRRFreeCrtcInfo(ci);
8050 XRRFreeScreenResources(res);
8052 return count;
8053}
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);
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 }
8067 XRRFreeGamma(gamma);
8068 return size;
8069#endif
8071 return 0;
8072}
8074RGFW_bool RGFW_FUNC(RGFW_monitor_setGammaRamp) (RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
8075 RGFW_UNUSED(monitor); RGFW_UNUSED(ramp);
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 }
8084 XRRCrtcGamma* gamma = XRRAllocGamma((int)ramp->count);
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));
8090 XRRSetCrtcGamma(_RGFW->display, monitor->node->crtc, gamma);
8091 XRRFreeGamma(gamma);
8093 return RGFW_TRUE;
8094#endif
8095 return RGFW_FALSE;
8096}
8098RGFW_bool RGFW_FUNC(RGFW_monitor_setMode)(RGFW_monitor* mon, RGFW_monitorMode* mode) {
8099 RGFW_bool out = RGFW_FALSE;
8101 XRRScreenResources* res = XRRGetScreenResourcesCurrent(_RGFW->display, DefaultRootWindow(_RGFW->display));
8102 XRRCrtcInfo* ci = XRRGetCrtcInfo(_RGFW->display, res, mon->node->crtc);
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 }
8108 XRRFreeCrtcInfo(ci);
8109 XRRFreeScreenResources(res);
8110 return out;
8111}
8113RGFW_bool RGFW_FUNC(RGFW_monitor_requestMode)(RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request) {
8114 #ifndef RGFW_NO_XRANDR
8115 RGFW_init();
8117 RGFW_bool output = RGFW_FALSE;
8119 XRRScreenResources* res = XRRGetScreenResourcesCurrent(_RGFW->display, DefaultRootWindow(_RGFW->display));
8120 if (res == NULL) return RGFW_FALSE;
8122 XRRCrtcInfo* ci = XRRGetCrtcInfo(_RGFW->display, res, mon->node->crtc);
8123 XRROutputInfo* oi = XRRGetOutputInfo(_RGFW->display, res, mon->node->rrOutput);
8125 RRMode native = None;
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 }
8135 if (RGFW_monitorModeCompare(mode, &foundMode, request)) {
8136 native = mi->id;
8137 output = RGFW_TRUE;
8138 mon->mode = foundMode;
8139 break;
8140 }
8141 }
8143 if (native) {
8144 XRRSetCrtcConfig(_RGFW->display, res, mon->node->crtc, CurrentTime, ci->x, ci->y, native, ci->rotation, ci->outputs, ci->noutput);
8145 }
8147 XRRFreeOutputInfo(oi);
8148 XRRFreeCrtcInfo(ci);
8149 XRRFreeScreenResources(res);
8150 return output;
8151#endif
8152 return RGFW_FALSE;
8153}
8155RGFW_monitor* RGFW_FUNC(RGFW_window_getMonitor) (RGFW_window* win) {
8156 RGFW_ASSERT(win != NULL);
8158 XWindowAttributes attrs;
8159 if (!XGetWindowAttributes(_RGFW->display, win->src.window, &attrs)) {
8160 return NULL;
8161 }
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 }
8169 return &_RGFW->monitors.list.head->mon;
8170}
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";
8181 /* basic RGFW int */
8182 win->src.ctx.native = context;
8183 win->src.gfxType = RGFW_gfxNativeOpenGL;
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 }
8192 RGFW_bool transparent = (win->internal.flags & RGFW_windowTransparent);
8194 /* start by creating a GLX config / X11 Viusal */
8195 XVisualInfo visual;
8196 GLXFBConfig bestFbc;
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);
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 }
8226 RGFW_attribStack_pushAttribs(&stack, 0, 0);
8228 /* find the configs */
8229 i32 fbcount;
8230 GLXFBConfig* fbc = glXChooseFBConfig(_RGFW->display, DefaultScreen(_RGFW->display), visual_attribs, &fbcount);
8232 i32 best_fbc = -1;
8233 i32 best_depth = 0;
8234 i32 best_samples = 0;
8236 if (fbcount == 0) {
8237 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to find any valid GLX visual configs.");
8238 return 0;
8239 }
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;
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);
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 }
8265 if (best_fbc == -1) {
8266 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to get a valid GLX visual.");
8267 return 0;
8268 }
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.");
8276 if (best_samples < hints->samples)
8277 RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, "Failed to load a matching sample count.");
8279 XFree(fbc);
8280 visual = *vi;
8281 XFree(vi);
8283 /* use the visual to create a new window */
8284 RGFW_XCreateWindow(visual, "", win->internal.flags, win);
8286 if (showWindow) {
8287 RGFW_window_show(win);
8288 }
8290 /* create the actual OpenGL context */
8291 i32 context_attribs[40];
8292 RGFW_attribStack_init(&stack, context_attribs, 40);
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 }
8303 RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_PROFILE_MASK_ARB, mask);
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 }
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 }
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 }
8326 if (RGFW_extensionSupportedPlatform_OpenGL(noErorrStr, sizeof(noErorrStr))) {
8327 RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_OPENGL_NO_ERROR_ARB, hints->noError);
8328 }
8330 RGFW_attribStack_pushAttribs(&stack, 0, 0);
8332 /* create the context */
8333 glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
8334 char str[] = "glXCreateContextAttribsARB";
8335 glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)glXGetProcAddressARB((u8*) str);
8337 GLXContext ctx = NULL;
8338 if (hints->share) {
8339 ctx = hints->share->ctx;
8340 }
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 }
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
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.");
8363 RGFW_window_swapInterval_OpenGL(win, 0);
8365 return RGFW_TRUE;
8366}
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
8375 glXDestroyContext(_RGFW->display, ctx->ctx);
8376 win->src.ctx.native = NULL;
8377 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context freed.");
8378}
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}
8386RGFW_proc RGFW_FUNC(RGFW_getProcAddress_OpenGL)(const char* procname) { return glXGetProcAddress((u8*) procname); }
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); }
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;
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"};
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 }
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 }
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 */
8433i32 RGFW_initPlatform_X11(void) {
8434 #ifdef RGFW_USE_XDL
8435 XDL_init();
8436 #endif
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
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
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
8477 XInitThreads(); /*!< init X11 threading */
8478 _RGFW->display = XOpenDisplay(0);
8479 _RGFW->context = XUniqueContext();
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);
8487 u8 RGFW_blk[] = { 0, 0, 0, 0 };
8488 _RGFW->hiddenMouse = RGFW_loadMouse(RGFW_blk, 1, 1, RGFW_formatRGBA8);
8489 _RGFW->clipboard = NULL;
8491 XkbComponentNamesRec rec;
8492 XkbDescPtr desc = XkbGetMap(_RGFW->display, 0, XkbUseCoreKbd);
8493 XkbDescPtr evdesc;
8494 XSetErrorHandler(RGFW_XErrorHandler);
8495 u8 old[256];
8497 XkbGetNames(_RGFW->display, XkbKeyNamesMask, desc);
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 }
8522 XSetLocaleModifiers("");
8523 XRegisterIMInstantiateCallback(_RGFW->display, NULL, NULL, NULL, RGFW_x11_imInitCallback, NULL);
8525 unsigned char mask[XIMaskLen(XI_RawMotion)];
8526 RGFW_MEMSET(mask, 0, sizeof(mask));
8527 XISetMask(mask, XI_RawMotion);
8529 XIEventMask em;
8530 em.deviceid = XIAllMasterDevices;
8531 em.mask_len = sizeof(mask);
8532 em.mask = mask;
8534 XISelectEvents(_RGFW->display, XDefaultRootWindow(_RGFW->display), &em, 1);
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
8543 return 0;
8544}
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 }
8556 XUnregisterIMInstantiateCallback(_RGFW->display, NULL, NULL, NULL, RGFW_x11_imInitCallback, NULL);
8558 if (_RGFW->im) {
8559 XCloseIM(_RGFW->im);
8560 _RGFW->im = NULL;
8561 }
8563 if (_RGFW->clipboard) {
8564 RGFW_FREE(_RGFW->clipboard);
8565 _RGFW->clipboard = NULL;
8566 }
8568 if (_RGFW->hiddenMouse) {
8569 RGFW_freeMouse(_RGFW->hiddenMouse);
8570 _RGFW->hiddenMouse = NULL;
8571 }
8573 XDestroyWindow(_RGFW->display, (Drawable) _RGFW->helperWindow); /*!< close the window */
8574 XCloseDisplay(_RGFW->display); /*!< kill connection to the x server */
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
8583 #ifdef RGFW_USE_XDL
8584 XDL_close();
8585 #endif
8587 #if !defined(RGFW_NO_X11_EXT_PRELOAD)
8588 RGFW_FREE_LIBRARY(X11XEXThandle);
8589 #endif
8590}
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 }
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}
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;
8612 surfaceDesc.nextInChain = (WGPUChainedStruct*)&fromXlib.chain;
8613 return wgpuInstanceCreateSurface(instance, &surfaceDesc);
8614}
8615#endif
8617#endif
8618/*
8619 End of X11 linux / wayland / unix defines
8620*/
8622/*
8624 Start of Wayland defayland
8625*/
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
8635/*
8636Wayland TODO: (out of date)
8637- fix RGFW_keyPressed lock state
8639 RGFW_windowMoved, the window was moved (by the user)
8640 RGFW_windowRefresh The window content needs to be refreshed
8642 RGFW_dataDrop a file has been dropped into the window
8643 RGFW_dataDrag
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
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>
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; }
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"
8677void RGFW_toggleWaylandMaximized(RGFW_window* win, RGFW_bool maximized);
8679static void RGFW_wl_setOpaque(RGFW_window* win) {
8680 struct wl_region* wl_region = wl_compositor_create_region(_RGFW->compositor);
8682 if (!wl_region) return; /* return if no region was created */
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);
8688}
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) {
8698 xdg_surface_ack_configure(xdg_surface, serial);
8700 RGFW_window* win = (RGFW_window*)data;
8702 if (win == NULL) {
8703 win = _RGFW->kbOwner;
8704 if (win == NULL)
8705 return;
8706 }
8708 /* useful for libdecor */
8709 if (win->src.activated != win->src.pending_activated) {
8710 win->src.activated = win->src.pending_activated;
8711 }
8713 if (win->src.maximized != win->src.pending_maximized) {
8714 RGFW_toggleWaylandMaximized(win, win->src.pending_maximized);
8716 RGFW_window_checkMode(win);
8717 }
8720 if (win->src.resizing) {
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 }
8729 win->src.configured = RGFW_TRUE;
8730}
8732static void RGFW_wl_xdg_toplevel_configure_handler(void* data, struct xdg_toplevel* toplevel,
8733 i32 width, i32 height, struct wl_array* states) {
8735 RGFW_UNUSED(toplevel);
8736 RGFW_window* win = (RGFW_window*)data;
8739 win->src.pending_activated = RGFW_FALSE;
8740 win->src.pending_maximized = RGFW_FALSE;
8741 win->src.resizing = RGFW_FALSE;
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 }
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}
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;
8771 if (!win->internal.shouldClose) {
8772 RGFW_windowQuitCallback(win);
8773 }
8774}
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);
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}
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}
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) {
8794 RGFW_UNUSED(zwp_relative_pointer_v1); RGFW_UNUSED(time_hi); RGFW_UNUSED(time_lo);
8795 RGFW_UNUSED(dx_unaccel); RGFW_UNUSED(dy_unaccel);
8797 RGFW_info* RGFW = (RGFW_info*)data;
8799 RGFW_ASSERT(RGFW->mouseOwner != NULL);
8800 RGFW_window* win = RGFW->mouseOwner;
8802 RGFW_ASSERT(win);
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}
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}
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);
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;
8825 RGFW->mouseOwner = win;
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 }
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}
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;
8847 RGFW_mouseNotifyCallback(win, win->internal.lastMouseX, win->internal.lastMouseY, RGFW_FALSE);
8848}
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);
8853 RGFW_info* RGFW = (RGFW_info*)data;
8854 RGFW_ASSERT(RGFW->mouseOwner != NULL);
8856 RGFW_window* win = RGFW->mouseOwner;
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);
8863 RGFW_mousePosCallback(win, convertedX, convertedY, newVecX, newVecY);
8864}
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;
8870 RGFW_ASSERT(RGFW->mouseOwner != NULL);
8871 RGFW_window* win = RGFW->mouseOwner;
8873 u32 b = (button - 0x110);
8875 /* flip right and middle button codes */
8876 if (b == 1) b = 2;
8877 else if (b == 2) b = 1;
8879 RGFW_mouseButtonCallback(win, (u8)b, RGFW_BOOL(state));
8880}
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);
8885 RGFW_info* RGFW = (RGFW_info*)data;
8886 RGFW_ASSERT(RGFW->mouseOwner != NULL);
8887 RGFW_window* win = RGFW->mouseOwner;
8889 float scrollX = 0.0;
8890 float scrollY = 0.0;
8892 if (!(win->internal.enabledEvents & (RGFW_BIT(RGFW_mouseScroll)))) return;
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);
8899 RGFW_mouseScrollCallback(win, scrollX, scrollY);
8900}
8903static void RGFW_doNothing(void) { }
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;
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);
8913 munmap(keymap_string, size);
8914 close(fd);
8915 xkb_state_unref(RGFW->xkb_state);
8916 RGFW->xkb_state = xkb_state_new(RGFW->keymap);
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";
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}
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);
8936 RGFW_info* RGFW = (RGFW_info*)data;
8937 RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
8938 RGFW->kbOwner = win;
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;
8949 RGFW_focusCallback(win, RGFW_TRUE);
8950}
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);
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;
8960 RGFW_focusCallback(win, RGFW_FALSE);
8961}
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}
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);
8983 RGFW_info* RGFW = (RGFW_info*)data;
8984 if (RGFW->kbOwner == NULL) return;
8986 RGFW_window *RGFW_key_win = RGFW->kbOwner;
8987 RGFW_key RGFWkey = RGFW_apiKeyToRGFW(key + 8);
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));
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}
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}
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;
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;
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 }
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}
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) {
9047 RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon;
9048 monitor->x = x;
9049 monitor->y = y;
9051 monitor->physW = (float)physical_width / 25.4f;
9052 monitor->physH = (float)physical_height / 25.4f;
9054 RGFW_UNUSED(wl_output);
9055 RGFW_UNUSED(subpixel);
9056 RGFW_UNUSED(make);
9057 RGFW_UNUSED(model);
9058 RGFW_UNUSED(transform);
9059}
9061static void RGFW_wl_output_handle_mode(void *data, struct wl_output *wl_output, u32 flags,
9062 i32 width, i32 height, i32 refresh) {
9064 RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon;
9066 RGFW_monitorMode mode;
9067 mode.w = width;
9068 mode.h = height;
9069 mode.refreshRate = (float)refresh / 1000.0f;
9070 mode.src = wl_output;
9072 monitor->node->modeCount += 1;
9074 RGFW_monitorMode* modes = (RGFW_monitorMode*)RGFW_ALLOC(monitor->node->modeCount * sizeof(RGFW_monitorMode));
9076 if (monitor->node->modeCount > 1) {
9077 RGFW_monitor_getModesPtr(monitor, &modes);
9078 RGFW_FREE(monitor->node->modes);
9079 }
9081 modes[monitor->node->modeCount - 1] = mode;
9082 monitor->node->modes = modes;
9084 if (flags & WL_OUTPUT_MODE_CURRENT) {
9085 monitor->mode = mode;
9086 } else {
9087 }
9088}
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;
9094 mon->scaleX = (float)factor;
9095 mon->scaleY = (float)factor;
9096}
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;
9101 RGFW_STRNCPY(monitor->name, name, sizeof(monitor->name) - 1);
9102 monitor->name[sizeof(monitor->name) - 1] = '\0';
9104 RGFW_UNUSED(wl_output);
9106}
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}
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;
9118 float mon_float_width = (float) monitor->mode.w;
9119 float mon_float_height = (float) monitor->mode.h;
9121 float scaleX = (mon_float_width / (float) width);
9122 float scaleY = (mon_float_height / (float) height);
9123 RGFW_UNUSED(scaleY);
9125 float dpi = scaleX * 96.0f;
9127 monitor->pixelRatio = dpi >= 192.0f ? 2.0f : 1.0f;
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}
9136static void RGFW_wl_output_handle_done(void* data, struct wl_output* output) {
9137 RGFW_UNUSED(output);
9139 RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon;
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 }
9146 if (((RGFW_monitorNode*)data)->disconnected == RGFW_FALSE) {
9147 return;
9148 }
9150 ((RGFW_monitorNode*)data)->disconnected = RGFW_TRUE;
9152 RGFW_monitorCallback(_RGFW->root, monitor, RGFW_TRUE);
9153}
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;
9160 if (!output) return;
9162 char RGFW_mon_default_name[10];
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';
9168 /* set in case compositor does not send one */
9169 /* or no xdg_output support */
9170 mon.scaleY = mon.scaleX = mon.pixelRatio = 1.0f;
9172 node = RGFW_monitors_add(&mon);
9173 if (node == NULL) return;
9175 node->modeCount = 0;
9176 node->disconnected = RGFW_TRUE;
9177 node->id = id;
9178 node->output = output;
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 };
9189 /* the wl_output will have a reference to the node */
9190 wl_output_set_user_data(output, node);
9192 /* pass the monitor so we can access it in the callback functions */
9193 wl_output_add_listener(output, &wl_output_listener, node);
9195 if (!_RGFW->xdg_output_manager)
9196 return; /* compositor does not support it */
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 };
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}
9210static void RGFW_wl_surface_enter(void *data, struct wl_surface *wl_surface, struct wl_output *output) {
9211 RGFW_UNUSED(wl_surface);
9213 RGFW_window* win = (RGFW_window*)data;
9214 RGFW_monitorNode* node = wl_output_get_user_data(output);
9215 if (node == NULL) return;
9217 win->src.active_monitor = node;
9219 if (win->internal.flags & RGFW_windowScaleToMonitor)
9220 RGFW_window_scaleToMonitor(win);
9221}
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);
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 }
9232 close(fd);
9233}
9235static void RGFW_wl_data_source_cancelled(void *data, struct wl_data_source *wl_data_source) {
9237 RGFW_info* RGFW = (RGFW_info*)data;
9239 if (RGFW->kbOwner->src.data_source == wl_data_source) {
9240 RGFW->kbOwner->src.data_source = NULL;
9241 }
9243 wl_data_source_destroy(wl_data_source);
9245}
9247static void RGFW_wl_data_device_data_offer(void *data, struct wl_data_device *wl_data_device, struct wl_data_offer *wl_data_offer) {
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}
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 }
9265 int pfds[2];
9266 pipe(pfds);
9268 wl_data_offer_receive(wl_data_offer, "text/plain;charset=utf-8", pfds[1]);
9269 close(pfds[1]);
9271 wl_display_roundtrip(_RGFW->wl_display);
9273 char buf[1024];
9275 ssize_t n = read(pfds[0], buf, sizeof(buf));
9277 _RGFW->clipboard = (char*)RGFW_ALLOC((size_t)n);
9278 RGFW_ASSERT(_RGFW->clipboard != NULL);
9279 RGFW_STRNCPY(_RGFW->clipboard, buf, (size_t)n);
9281 _RGFW->clipboard_len = (size_t)n + 1;
9283 close(pfds[0]);
9285 wl_data_offer_destroy(wl_data_offer);
9287}
9289static void RGFW_wl_global_registry_handler(void* data, struct wl_registry *registry, u32 id, const char *interface, u32 version) {
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 };
9294 RGFW_info* RGFW = (RGFW_info*)data;
9295 RGFW_UNUSED(version);
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}
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;
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 }
9339 if (prev->next == NULL) return;
9340 node = prev->next;
9341 } else {
9342 node = prev;
9343 }
9345 if (node->output) {
9346 wl_output_destroy(node->output);
9347 }
9349 if (node->xdg_output) {
9350 zxdg_output_v1_destroy(node->xdg_output);
9351 }
9353 if (node->modeCount) {
9354 RGFW_FREE(node->modes);
9355 node->modeCount = 0;
9356 }
9358 RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_FALSE);
9359 RGFW_monitors_remove(node, prev);
9360}
9362static void RGFW_wl_randname(char *buf) {
9363 struct timespec ts;
9364 clock_gettime(CLOCK_REALTIME, &ts);
9365 long r = ts.tv_nsec;
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}
9374static int RGFW_wl_anonymous_shm_open(void) {
9375 char name[] = "/RGFW-wayland-XXXXXX";
9376 int retries = 100;
9378 do {
9379 RGFW_wl_randname(name + RGFW_unix_stringlen(name) - 6);
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);
9390 return -1;
9391}
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 }
9399 if (ftruncate(fd, size) < 0) {
9400 close(fd);
9401 return -1;
9402 }
9404 return fd;
9405}
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 }
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 };
9420 _RGFW->registry = wl_display_get_registry(_RGFW->wl_display);
9421 wl_registry_add_listener(_RGFW->registry, ®istry_listener, _RGFW);
9423 wl_display_roundtrip(_RGFW->wl_display); /* bind to globals */
9425 if (_RGFW->compositor == NULL) {
9426 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errWayland, "Can't find compositor.");
9427 return 1;
9428 }
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 }
9435 u8 RGFW_blk[] = { 0, 0, 0, 0 };
9436 _RGFW->hiddenMouse = RGFW_loadMouse(RGFW_blk, 1, 1, RGFW_formatRGBA8);
9438 static const struct xdg_wm_base_listener xdg_wm_base_listener = {
9439 .ping = RGFW_wl_xdg_wm_base_ping_handler,
9440 };
9442 xdg_wm_base_add_listener(_RGFW->xdg_wm_base, &xdg_wm_base_listener, NULL);
9444 _RGFW->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
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 };
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 }
9460 return 0;
9461}
9463void RGFW_deinitPlatform_Wayland(void) {
9464 if (_RGFW->clipboard) {
9465 RGFW_FREE(_RGFW->clipboard);
9466 _RGFW->clipboard = NULL;
9467 }
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 }
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 }
9483 if (_RGFW->relative_pointer) {
9484 zwp_relative_pointer_v1_destroy(_RGFW->relative_pointer);
9485 }
9487 if (_RGFW->constraint_manager != NULL) {
9488 zwp_pointer_constraints_v1_destroy(_RGFW->constraint_manager);
9489 }
9491 if (_RGFW->xdg_output_manager != NULL)
9492 if (_RGFW->icon_manager != NULL) {
9493 xdg_toplevel_icon_manager_v1_destroy(_RGFW->icon_manager);
9494 }
9496 if (_RGFW->xdg_output_manager) {
9497 zxdg_output_manager_v1_destroy(_RGFW->xdg_output_manager);
9498 }
9500 if (_RGFW->data_device_manager) {
9501 wl_data_device_manager_destroy(_RGFW->data_device_manager);
9502 }
9504 if (_RGFW->data_device) {
9505 wl_data_device_destroy(_RGFW->data_device);
9506 }
9508 if (_RGFW->wl_cursor_theme != NULL) {
9509 wl_cursor_theme_destroy(_RGFW->wl_cursor_theme);
9510 }
9512 if (_RGFW->wp_pointer_warp != NULL) {
9513 wp_pointer_warp_v1_destroy(_RGFW->wp_pointer_warp);
9514 }
9516 RGFW_freeMouse(_RGFW->hiddenMouse);
9518 RGFW_monitorNode* node = _RGFW->monitors.list.head;
9520 while (node != NULL) {
9521 if (node->output) {
9522 wl_output_destroy(node->output);
9523 }
9525 if (node->xdg_output) {
9526 zxdg_output_v1_destroy(node->xdg_output);
9527 }
9529 _RGFW->monitors.count -= 1;
9530 node = node->next;
9532 }
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}
9542RGFW_format RGFW_FUNC(RGFW_nativeFormat)(void) { return RGFW_formatBGRA8; }
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");
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 }
9559 surface->native.pool = wl_shm_create_pool(_RGFW->shm, fd, (i32)size);
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 }
9567 surface->native.fd = fd;
9568 surface->native.format = RGFW_formatBGRA8;
9569 return RGFW_TRUE;
9570}
9572void RGFW_FUNC(RGFW_window_blitSurface) (RGFW_window* win, RGFW_surface* surface) {
9573 RGFW_ASSERT(surface != NULL);
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);
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);
9582 wl_buffer_destroy(surface->native.wl_buffer);
9583}
9585void RGFW_FUNC(RGFW_surface_freePtr) (RGFW_surface* surface) {
9586 RGFW_ASSERT(surface != NULL);
9588 wl_shm_pool_destroy(surface->native.pool);
9589 close(surface->native.fd);
9591 munmap(surface->native.buffer, (size_t)(surface->w * surface->h * 4));
9592}
9594void RGFW_FUNC(RGFW_window_setBorder) (RGFW_window* win, RGFW_bool border) {
9595 RGFW_setBit(&win->internal.flags, RGFW_windowNoBorder, !border);
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}
9603void RGFW_FUNC(RGFW_window_setRawMouseModePlatform) (RGFW_window* win, RGFW_bool state) {
9604 RGFW_ASSERT(win);
9605 if (_RGFW->relative_pointer_manager == NULL) return;
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 }
9614 if (_RGFW->relative_pointer != NULL) return;
9616 _RGFW->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(_RGFW->relative_pointer_manager, _RGFW->wl_pointer);
9618 static const struct zwp_relative_pointer_v1_listener relative_motion_listener = {
9619 .relative_motion = RGFW_wl_relative_pointer_motion
9620 };
9622 zwp_relative_pointer_v1_add_listener(_RGFW->relative_pointer, &relative_motion_listener, _RGFW);
9623}
9625void RGFW_FUNC(RGFW_window_captureMousePlatform) (RGFW_window* win, RGFW_bool state) {
9626 RGFW_ASSERT(win);
9628 /* compositor has no support or window already is locked do nothing */
9629 if (_RGFW->constraint_manager == NULL) return;
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 }
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);
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 };
9647 zwp_locked_pointer_v1_add_listener(win->src.locked_pointer, &locked_listener, _RGFW);
9648}
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");
9653 static const struct xdg_surface_listener xdg_surface_listener = {
9654 .configure = RGFW_wl_xdg_surface_configure_handler,
9655 };
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 };
9664 win->src.surface = wl_compositor_create_surface(_RGFW->compositor);
9665 wl_surface_add_listener(win->src.surface, &wl_surface_listener, win);
9667 /* create a surface for a custom cursor */
9668 win->src.custom_cursor_surface = wl_compositor_create_surface(_RGFW->compositor);
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);
9673 xdg_wm_base_set_user_data(_RGFW->xdg_wm_base, win);
9675 win->src.xdg_toplevel = xdg_surface_get_toplevel(win->src.xdg_surface);
9677 if (_RGFW->className == NULL)
9678 _RGFW->className = (char*)name;
9680 xdg_toplevel_set_app_id(win->src.xdg_toplevel, name);
9682 xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->w, win->h);
9684 if (!(win->internal.flags & RGFW_windowTransparent)) { /* no transparency */
9685 RGFW_wl_setOpaque(win);
9686 }
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 };
9693 xdg_toplevel_add_listener(win->src.xdg_toplevel, &xdg_toplevel_listener, win);
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);
9703 static const struct zxdg_toplevel_decoration_v1_listener xdg_decoration_listener = {
9704 .configure = RGFW_wl_xdg_decoration_configure_handler
9705 };
9707 zxdg_toplevel_decoration_v1_add_listener(win->src.decoration, &xdg_decoration_listener, win);
9709 /* we want no decorations */
9710 if ((flags & RGFW_windowNoBorder)) {
9711 decoration_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
9712 }
9714 zxdg_toplevel_decoration_v1_set_mode(win->src.decoration, decoration_mode);
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 };
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 };*/
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 }
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 }
9750 wl_surface_commit(win->src.surface);
9752 while (win->src.configured == RGFW_FALSE) {
9753 wl_display_dispatch(_RGFW->wl_display);
9754 }
9756 RGFW_UNUSED(name);
9758 return win;
9759}
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}
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 }
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 }
9845 return RGFW_keyNULL;
9846}
9848void RGFW_FUNC(RGFW_pollEvents) (void) {
9849 RGFW_resetPrevState();
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 }
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 }
9870}
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}
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}
9892void RGFW_FUNC(RGFW_window_setAspectRatio) (RGFW_window* win, i32 w, i32 h) {
9893 RGFW_ASSERT(win != NULL);
9895 if (w == 0 && h == 0)
9896 return;
9897 xdg_toplevel_set_max_size(win->src.xdg_toplevel, (i32)w, (i32)h);
9898}
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}
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}
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}
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}
9928void RGFW_FUNC(RGFW_window_focus)(RGFW_window* win) {
9929 RGFW_ASSERT(win);
9930}
9932void RGFW_FUNC(RGFW_window_raise)(RGFW_window* win) {
9933 RGFW_ASSERT(win);
9934}
9936void RGFW_FUNC(RGFW_window_setFullscreen)(RGFW_window* win, RGFW_bool fullscreen) {
9937 RGFW_ASSERT(win != NULL);
9938 if (fullscreen) {
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 }
9951}
9953void RGFW_FUNC(RGFW_window_setFloating) (RGFW_window* win, RGFW_bool floating) {
9954 RGFW_ASSERT(win != NULL);
9955 RGFW_UNUSED(floating);
9956}
9958void RGFW_FUNC(RGFW_window_setOpacity) (RGFW_window* win, u8 opacity) {
9959 RGFW_ASSERT(win != NULL);
9960 RGFW_UNUSED(opacity);
9961}
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}
9974void RGFW_FUNC(RGFW_window_restore)(RGFW_window* win) {
9975 RGFW_ASSERT(win != NULL);
9976 RGFW_toggleWaylandMaximized(win, RGFW_FALSE);
9978 RGFW_window_move(win, win->internal.oldX, win->internal.oldY);
9979 RGFW_window_resize(win, win->internal.oldW, win->internal.oldH);
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);
9985 RGFW_window_show(win);
9986}
9988RGFW_bool RGFW_FUNC(RGFW_window_isFloating)(RGFW_window* win) {
9989 return (!RGFW_window_isFullscreen(win) && !RGFW_window_isMaximized(win));
9990}
9992void RGFW_FUNC(RGFW_window_setName) (RGFW_window* win, const char* name) {
9993 RGFW_ASSERT(win != NULL);
9994 if (name == NULL) name = "\0";
9996 if (_RGFW->compositor)
9997 xdg_toplevel_set_title(win->src.xdg_toplevel, name);
9998}
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);
10005#endif /* RGFW_NO_PASSTHROUGH */
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);
10011 if (_RGFW->icon_manager == NULL || w != h) return RGFW_FALSE;
10013 if (win->src.icon) {
10014 xdg_toplevel_icon_v1_destroy(win->src.icon);
10015 win->src.icon= NULL;
10016 }
10018 RGFW_surface* surface = RGFW_createSurface(data, w, h, format);
10020 if (surface == NULL) return RGFW_FALSE;
10022 RGFW_copyImageData(surface->native.buffer, RGFW_MIN(w, surface->w), RGFW_MIN(h, surface->h), surface->native.format, surface->data, surface->format, NULL);
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);
10028 RGFW_surface_free(surface);
10029 return RGFW_TRUE;
10032RGFW_mouse* RGFW_FUNC(RGFW_loadMouse)(u8* data, i32 w, i32 h, RGFW_format format) {
10034 RGFW_surface *mouse_surface = RGFW_createSurface(data, w, h, format);
10036 if (mouse_surface == NULL) return NULL;
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);
10040 return (void*) mouse_surface;
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;
10047 win->src.using_custom_cursor = RGFW_TRUE;
10049 struct wl_buffer *mouse_buffer = mouse_surface->native.wl_buffer;
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);
10057void RGFW_FUNC(RGFW_freeMouse)(RGFW_mouse* mouse) {
10058 if (mouse != NULL) {
10059 RGFW_surface_free((RGFW_surface*)mouse);
10060 }
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 }
10069RGFW_bool RGFW_FUNC(RGFW_window_setMouseDefault)(RGFW_window* win) {
10070 return RGFW_window_setMouseStandard(win, RGFW_mouseArrow);
10073RGFW_bool RGFW_FUNC(RGFW_window_setMouseStandard)(RGFW_window* win, u8 mouse) {
10074 RGFW_ASSERT(win != NULL);
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 }
10102 win->src.using_custom_cursor = RGFW_FALSE;
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;
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;
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);
10129void RGFW_FUNC(RGFW_window_flash) (RGFW_window* win, RGFW_flashRequest request) {
10130 if (RGFW_window_isInFocus(win) && request) {
10131 return;
10132 }
10135RGFW_ssize_t RGFW_FUNC(RGFW_readClipboardPtr) (char* str, size_t strCapacity) {
10136 RGFW_UNUSED(strCapacity);
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;
10144void RGFW_FUNC(RGFW_writeClipboard) (const char* text, u32 textLen) {
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);
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;
10160 // means we already wrote to the clipboard
10161 // so destroy it to create a new one
10162 RGFW_window* win = _RGFW->kbOwner;
10164 if (win->src.data_source != NULL) {
10165 wl_data_source_destroy(win->src.data_source);
10166 win->src.data_source = NULL;
10167 }
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);
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");
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 };
10190 wl_data_source_add_listener(win->src.data_source, &data_source_listener, _RGFW);
10194RGFW_bool RGFW_FUNC(RGFW_window_isHidden) (RGFW_window* win) {
10195 RGFW_ASSERT(win != NULL);
10196 return RGFW_FALSE;
10199RGFW_bool RGFW_FUNC(RGFW_window_isMinimized) (RGFW_window* win) {
10200 RGFW_ASSERT(win != NULL);
10201 return win->src.minimized;
10204RGFW_bool RGFW_FUNC(RGFW_window_isMaximized) (RGFW_window* win) {
10205 RGFW_ASSERT(win != NULL);
10206 return win->src.maximized;
10209void RGFW_FUNC(RGFW_pollMonitors) (void) {
10210 _RGFW->monitors.primary = _RGFW->monitors.list.head;
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;
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 }
10228 return monitor->node->modeCount;
10231size_t RGFW_FUNC(RGFW_monitor_getGammaRampPtr) (RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
10232 RGFW_UNUSED(monitor); RGFW_UNUSED(ramp);
10233 return 0;
10236RGFW_bool RGFW_FUNC(RGFW_monitor_setGammaRamp) (RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
10237 RGFW_UNUSED(monitor); RGFW_UNUSED(ramp);
10238 return RGFW_FALSE;
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 }
10247 RGFW_monitor_setMode(mon, &mon->node->modes[i]);
10248 return RGFW_TRUE;
10249 }
10251 return RGFW_FALSE;
10254RGFW_bool RGFW_FUNC(RGFW_monitor_setMode) (RGFW_monitor* mon, RGFW_monitorMode* mode) {
10255 RGFW_UNUSED(mon); RGFW_UNUSED(mode);
10256 return RGFW_FALSE;
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 }
10266 return &win->src.active_monitor->mon;
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); }
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;
10278 RGFW_window_swapInterval_OpenGL(win, 0);
10279 return out;
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; }
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 */
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
10297 if (win->src.decoration) {
10298 zxdg_toplevel_decoration_v1_destroy(win->src.decoration);
10299 }
10301 if (win->src.xdg_toplevel) {
10302 xdg_toplevel_destroy(win->src.xdg_toplevel);
10303 }
10305 wl_surface_destroy(win->src.custom_cursor_surface);
10307 if (win->src.locked_pointer) {
10308 zwp_locked_pointer_v1_destroy(win->src.locked_pointer);
10309 }
10311 if (win->src.icon) {
10312 xdg_toplevel_icon_v1_destroy(win->src.icon);
10313 }
10315 xdg_surface_destroy(win->src.xdg_surface);
10316 wl_surface_destroy(win->src.surface);
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;
10327 surfaceDesc.nextInChain = (WGPUChainedStruct*)&fromWl.chain;
10328 return wgpuInstanceCreateSurface(instance, &surfaceDesc);
10330#endif
10334#endif /* RGFW_WAYLAND */
10335/*
10336 End of Wayland defines
10337*/
10339/*
10341 Start of Windows defines
10344*/
10346#ifdef RGFW_WINDOWS
10347#ifndef WIN32_LEAN_AND_MEAN
10348 #define WIN32_LEAN_AND_MEAN
10349#endif
10351#ifndef OEMRESOURCE
10352 #define OEMRESOURCE
10353#endif
10355#include <windows.h>
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
10373#include <windowsx.h>
10374#include <shellapi.h>
10375#include <shellscalingapi.h>
10376#include <wchar.h>
10377#include <locale.h>
10378#include <winuser.h>
10380#ifndef WM_DPICHANGED
10381#define WM_DPICHANGED 0x02E0
10382#endif
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;
10389 if ((flags & RGFW_windowFullscreen)) {
10390 style |= WS_POPUP;
10391 } else {
10392 style |= WS_SYSMENU | WS_MINIMIZEBOX;
10394 if (!(flags & RGFW_windowNoBorder)) {
10395 style |= WS_CAPTION;
10397 if (!(flags & RGFW_windowNoResize))
10398 style |= WS_MAXIMIZEBOX | WS_THICKFRAME;
10399 }
10400 else
10401 style |= WS_POPUP;
10402 }
10404 return style;
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 }
10414 return style;
10417RGFW_bool RGFW_createUTF8FromWideStringWin32(const WCHAR* source, char* out, size_t max);
10419#define GL_FRONT 0x0404
10420#define GL_BACK 0x0405
10421#define GL_LEFT 0x0406
10422#define GL_RIGHT 0x0407
10424typedef int (*PFN_wglGetSwapIntervalEXT)(void);
10425PFN_wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc = NULL;
10426#define wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc
10428/* these two wgl functions need to be preloaded */
10429typedef HGLRC (WINAPI *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC hdc, HGLRC hglrc, const int *attribList);
10430PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL;
10432HMODULE RGFW_wgl_dll = NULL;
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);
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;
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
10460void* RGFW_window_getHWND(RGFW_window* win) { return win->src.window; }
10461void* RGFW_window_getHDC(RGFW_window* win) { return win->src.hdc; }
10463#ifdef RGFW_OPENGL
10464RGFWDEF void RGFW_win32_loadOpenGLFuncs(HWND dummyWin);
10466typedef HRESULT (APIENTRY* PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats);
10467PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL;
10469typedef BOOL(APIENTRY* PFNWGLSWAPINTERVALEXTPROC)(int interval);
10470PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
10471#endif
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;
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;
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);
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 }
10504RGFWDEF RGFW_bool RGFW_win32_getDarkModeState(void);
10505RGFW_bool RGFW_win32_getDarkModeState(void) {
10506 u32 lightMode = 1;
10507 DWORD len = sizeof(lightMode);
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 );
10515 return (lightMode == 0);
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));
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);
10529 static BYTE keyboardState[256];
10530 GetKeyboardState(keyboardState);
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);
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);
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 }
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 }
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 }
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 }
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;
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 }
10598 RECT* area = (RECT*)lParam;
10599 i32 edge = (i32)wParam;
10601 double ratio = (double)win->src.aspectRatioW / (double) win->src.aspectRatioH;
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 }
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);
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);
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);
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
10642 case WM_ENTERSIZEMOVE: {
10643 if (win->src.actionFrame)
10644 RGFW_window_captureMousePlatform(win, win->internal.captureMouse);
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);
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;
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;
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;
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;
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;
10697 win->src.highSurrogate = 0;
10698 RGFW_keyCharCallback(win, (u32)codepoint);
10699 }
10701 return 0;
10702 }
10704 case WM_UNICHAR: {
10705 if (wParam == UNICODE_NOCHAR) {
10706 return TRUE;
10707 }
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);
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 }
10725 RGFW_key value = (u8)RGFW_apiKeyToRGFW((u32) scancode);
10727 if (wParam == VK_CONTROL) {
10728 if (HIWORD(lParam) & KF_EXTENDED)
10729 value = RGFW_controlR;
10730 else value = RGFW_controlL;
10731 }
10733 RGFW_bool repeat = ((lParam & 0x40000000) != 0) || RGFW_window_isKeyDown(win, value);
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);
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 }
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 }
10759 RGFW_bool repeat = ((lParam & 0x40000000) != 0) || RGFW_window_isKeyDown(win, value);
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 }
10770 if ((win->internal.rawMouse) || _RGFW->rawMouse) {
10771 return DefWindowProcW(hWnd, message, wParam, lParam);
10772 }
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;
10782 GetRawInputData((HRAWINPUT)lParam, RID_INPUT, &raw, &size, sizeof(RAWINPUTHEADER));
10784 if (raw.header.dwType != RIM_TYPEMOUSE || (raw.data.mouse.lLastX == 0 && raw.data.mouse.lLastY == 0) )
10785 break;
10787 float vecX = 0.0f;
10788 float vecY = 0.0f;
10790 if (raw.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) {
10791 POINT pos = {0, 0};
10792 int width, height;
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 }
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);
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 }
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;
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;
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;
10853 /* Move the mouse to the position of the drop */
10854 DragQueryPoint(drop, &pt);
10855 RGFW_dataDragCallback(win, pt.x, pt.y);
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);
10861 u32 i;
10862 for (i = 0; i < count; i++) {
10863 UINT length = DragQueryFileW(drop, i, NULL, 0);
10864 if (length == 0)
10865 continue;
10867 WCHAR buffer[RGFW_MAX_PATH * 2];
10868 if (length > (RGFW_MAX_PATH * 2) - 1)
10869 length = RGFW_MAX_PATH * 2;
10871 DragQueryFileW(drop, i, buffer, length + 1);
10873 RGFW_createUTF8FromWideStringWin32(buffer, files[i], RGFW_MAX_PATH);
10875 files[i][RGFW_MAX_PATH - 1] = '\0';
10876 }
10878 DragFinish(drop);
10880 RGFW_dataDropCallback(win, files, count);
10881 break;
10882 }
10883 default: break;
10884 }
10886 return DefWindowProcW(hWnd, message, wParam, lParam);
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
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 }
10912RGFW_format RGFW_nativeFormat(void) { return RGFW_formatBGRA8; }
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;
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;
10930 surface->native.bitmap = CreateDIBSection(_RGFW->root->src.hdc,
10931 (BITMAPINFO*) &bi, DIB_RGB_COLORS,
10932 (void**) &surface->native.bitmapBits,
10933 NULL, (DWORD) 0);
10935 surface->native.format = (format >= RGFW_formatRGBA8) ? RGFW_formatBGRA8 : RGFW_formatBGR8;
10937 if (surface->native.bitmap == NULL) {
10938 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, "Failed to create DIB section.");
10939 return RGFW_FALSE;
10940 }
10942 surface->native.hdcMem = CreateCompatibleDC(_RGFW->root->src.hdc);
10943 SelectObject(surface->native.hdcMem, surface->native.bitmap);
10945 return RGFW_TRUE;
10948void RGFW_surface_freePtr(RGFW_surface* surface) {
10949 RGFW_ASSERT(surface != NULL);
10951 DeleteDC(surface->native.hdcMem);
10952 DeleteObject(surface->native.bitmap);
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);
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;
10965 RegisterRawInputDevices(&id, 1, sizeof(id));
10968void RGFW_window_captureMousePlatform(RGFW_window* win, RGFW_bool state) {
10969 if (state == RGFW_FALSE) {
10970 ClipCursor(NULL);
10971 return;
10972 }
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);
10981#define RGFW_LOAD_LIBRARY(x, lib) if (x == NULL) { x = LoadLibraryA(lib); RGFW_ASSERT(x != NULL); }
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);
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;
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 }
11006 return 0;
11008#endif
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;
11133i32 RGFW_initPlatform(void) {
11134#ifndef RGFW_NO_DPI
11135 #if (_WIN32_WINNT >= 0x0600)
11136 SetProcessDPIAware();
11137 #endif
11138#endif
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
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
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
11166 u8 RGFW_blk[] = { 0, 0, 0, 0 };
11167 _RGFW->hiddenMouse = RGFW_loadMouse(RGFW_blk, 1, 1, RGFW_formatRGBA8);
11168 return 1;
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;
11181 HINSTANCE inh = GetModuleHandleA(NULL);
11183 #ifndef __cplusplus
11184 WNDCLASSW Class = {0}; /*!< Setup the Window class. */
11185 #else
11186 WNDCLASSW Class = {};
11187 #endif
11189 if (_RGFW->className == NULL)
11190 _RGFW->className = (char*)name;
11192 wchar_t wide_class[256];
11193 MultiByteToWideChar(CP_UTF8, 0, _RGFW->className, -1, wide_class, 255);
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*);
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);
11205 RegisterClassW(&Class);
11207 DWORD window_style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
11209 RECT windowRect, clientRect;
11211 if (!(flags & RGFW_windowNoBorder)) {
11212 window_style |= WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX;
11214 if (!(flags & RGFW_windowNoResize))
11215 window_style |= WS_SIZEBOX | WS_MAXIMIZEBOX;
11216 } else
11217 window_style |= WS_POPUP | WS_VISIBLE | WS_SYSMENU;
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);
11223 GetWindowRect(dummyWin, &windowRect);
11224 GetClientRect(dummyWin, &clientRect);
11226#ifdef RGFW_OPENGL
11227 RGFW_win32_loadOpenGLFuncs(dummyWin);
11228#endif
11230 DestroyWindow(dummyWin);
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);
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 */
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);
11247 RGFW_win32_makeWindowDarkMode(win, RGFW_win32_getDarkModeState());
11248 RGFW_win32_makeWindowTransparent(win);
11249 return win;
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);
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 }
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);
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;
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;
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;
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;
11304void RGFW_window_focus(RGFW_window* win) {
11305 RGFW_ASSERT(win);
11306 SetForegroundWindow(win->src.window);
11307 SetFocus(win->src.window);
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);
11316void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) {
11317 RGFW_ASSERT(win != NULL);
11319 if (fullscreen == RGFW_FALSE) {
11320 RGFW_window_setBorder(win, 1);
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);
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 }
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;
11343 RGFW_monitor* mon = RGFW_window_getMonitor(win);
11345 RGFW_window_setBorder(win, 0);
11346 RGFW_monitor_scaleToWindow(mon, win);
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);
11350 win->x = mon->x;
11351 win->y = mon->y;
11352 win->w = mon->mode.w;
11353 win->h = mon->mode.h;
11356void RGFW_window_maximize(RGFW_window* win) {
11357 RGFW_ASSERT(win != NULL);
11358 RGFW_window_hide(win);
11359 ShowWindow(win->src.window, SW_MAXIMIZE);
11362void RGFW_window_minimize(RGFW_window* win) {
11363 RGFW_ASSERT(win != NULL);
11364 ShowWindow(win->src.window, SW_MINIMIZE);
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);
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);
11378void RGFW_window_restore(RGFW_window* win) { RGFW_window_show(win); }
11380RGFW_bool RGFW_window_isFloating(RGFW_window* win) {
11381 return (GetWindowLongPtr(win->src.window, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
11384void RGFW_stopCheckEvents(void) {
11385 PostMessageW(_RGFW->root->src.window, WM_NULL, 0, 0);
11388void RGFW_waitForEvent(i32 waitMS) {
11389 MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD)waitMS, QS_ALLINPUT);
11392RGFW_key RGFW_physicalToMappedKey(RGFW_key key) {
11393 UINT vsc = RGFW_rgfwToApiKey(key);
11394 BYTE keyboardState[256] = {0};
11396 if (!GetKeyboardState(keyboardState))
11397 return key;
11399 UINT vk = MapVirtualKeyW(vsc, MAPVK_VSC_TO_VK);
11400 HKL layout = GetKeyboardLayout(0);
11402 wchar_t charBuffer[4] = {0};
11403 int result = ToUnicodeEx(vk, vsc, keyboardState, charBuffer, 1, 0, layout);
11405 if (result == 1 && charBuffer[0] < 256) {
11406 return (RGFW_key)charBuffer[0];
11407 }
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 }
11476 return RGFW_keyNULL;
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 }
11488RGFW_bool RGFW_window_isHidden(RGFW_window* win) {
11489 RGFW_ASSERT(win != NULL);
11490 return IsWindowVisible(win->src.window) == 0 && !RGFW_window_isMinimized(win);
11493RGFW_bool RGFW_window_isMinimized(RGFW_window* win) {
11494 RGFW_ASSERT(win != NULL);
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;
11505RGFW_bool RGFW_window_isMaximized(RGFW_window* win) {
11506 RGFW_ASSERT(win != NULL);
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);
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);
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;
11527 return RGFW_TRUE;
11530size_t RGFW_monitor_getGammaRampPtr(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
11531 WORD values[3][256];
11533 HDC dc = CreateDCW(L"DISPLAY", monitor->node->adapterName, NULL, NULL);
11534 GetDeviceGammaRamp(dc, values);
11535 DeleteDC(dc);
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 }
11543 return sizeof(values[0]) / sizeof(WORD);
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 }
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]));
11557 HDC dc = CreateDCW(L"DISPLAY", monitor->node->adapterName, NULL, NULL);
11558 SetDeviceGammaRamp(dc, values);
11559 DeleteDC(dc);
11560 return RGFW_TRUE;
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);
11570 MONITORINFOEXW mi;
11571 ZeroMemory(&mi, sizeof(mi));
11572 mi.cbSize = sizeof(mi);
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 }
11581 return TRUE;
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);
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 }
11602size_t RGFW_monitor_getModesPtr(RGFW_monitor* monitor, RGFW_monitorMode** modes){
11603 size_t count = 0;
11604 DWORD modeIndex = 0;
11606 for (;;) {
11607 DEVMODEW dm;
11608 ZeroMemory(&dm, sizeof(dm));
11609 dm.dmSize = sizeof(dm);
11611 if (!EnumDisplaySettingsW(monitor->node->adapterName, modeIndex, &dm))
11612 break;
11614 modeIndex++;
11616 if (dm.dmBitsPerPel < 15)
11617 continue;
11619 if (modes) {
11620 RGFW_monitorMode mode;
11621 RGFW_win32_getMode(&dm, &mode);
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 }
11630 if (i < count) {
11631 continue;
11632 }
11634 (*modes)[count] = mode;
11635 }
11637 count += 1;
11638 }
11640 return count;
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);
11649 if (!EnumDisplaySettingsW(adapter->DeviceName, ENUM_CURRENT_SETTINGS, &dm)) {
11650 return;
11651 }
11653 RGFW_monitorNode* node = RGFW_monitors_add(NULL);
11655 wcscpy(node->adapterName, adapter->DeviceName);
11656 wcscpy(node->deviceName, dd->DeviceName);
11658 RGFW_createUTF8FromWideStringWin32(dd->DeviceString, node->mon.name, sizeof(node->mon.name));
11659 node->mon.name[sizeof(node->mon.name) - 1] = '\0';
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);
11668 RGFW_win32_getMode(&dm, &node->mon.mode);
11670 MONITORINFOEXW monitorInfo;
11671 monitorInfo.cbSize = sizeof(MONITORINFOEXW);
11672 GetMonitorInfoW(node->hMonitor, (LPMONITORINFO)&monitorInfo);
11674 node->mon.x = monitorInfo.rcMonitor.left;
11675 node->mon.y = monitorInfo.rcMonitor.top;
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);
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;
11686 node->mon.physW = (float)GetDeviceCaps(hdc, HORZSIZE) / 25.4f;
11687 node->mon.physH = (float)GetDeviceCaps(hdc, VERTSIZE) / 25.4f;
11688 DeleteDC(hdc);
11690#ifndef RGFW_NO_DPI
11691 RGFW_LOAD_LIBRARY(RGFW_Shcore_dll, "shcore.dll");
11692 RGFW_PROC_DEF(RGFW_Shcore_dll, GetDpiForMonitor);
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
11703 if (monitorInfo.dwFlags & MONITORINFOF_PRIMARY) {
11704 _RGFW->monitors.primary = node;
11705 }
11707 RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_TRUE);
11710void RGFW_pollMonitors(void) {
11711 for (RGFW_monitorNode* node = _RGFW->monitors.list.head; node; node = node->next) {
11712 node->disconnected = RGFW_TRUE;
11713 }
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);
11722 if (!EnumDisplayDevicesW(NULL, adapterNum, &adapter, 0))
11723 break;
11725 if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE))
11726 continue;
11728 DISPLAY_DEVICEW dd;
11729 dd.cb = sizeof(dd);
11731 /* loop through display devices (monitors) */
11732 DWORD deviceNum;
11733 for (deviceNum = 0; ; deviceNum++) {
11734 ZeroMemory(&dd, sizeof(dd));
11735 dd.cb = sizeof(dd);
11737 if (!EnumDisplayDevicesW(adapter.DeviceName, deviceNum, &dd, 0))
11738 break;
11740 if (!(dd.StateFlags & DISPLAY_DEVICE_ACTIVE))
11741 continue;
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 }
11752 if (node) {
11753 continue;
11754 }
11756 RGFW_win32_createMonitor(&adapter, &dd);
11757 }
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 }
11769 if (node) {
11770 continue;
11771 }
11773 RGFW_win32_createMonitor(&adapter, NULL);
11774 }
11775 }
11777 RGFW_monitors_refresh();
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;
11784 for (node = _RGFW->monitors.list.head; node; node = node->next) {
11785 if (node->hMonitor == src) {
11786 return &node->mon;
11787 }
11788 }
11790 return RGFW_getPrimaryMonitor();
11793RGFW_bool RGFW_monitor_setMode(RGFW_monitor* mon, RGFW_monitorMode* mode) {
11794 DEVMODEW dm;
11795 ZeroMemory(&dm, sizeof(dm));
11796 dm.dmSize = sizeof(dm);
11798 dm.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT;
11799 dm.dmPelsWidth = (u32)mode->w;
11800 dm.dmPelsHeight = (u32)mode->h;
11802 dm.dmFields |= DM_DISPLAYFREQUENCY;
11803 dm.dmDisplayFrequency = (DWORD)mode->refreshRate;
11805 dm.dmFields |= DM_BITSPERPEL;
11806 dm.dmBitsPerPel = (DWORD)(mode->red + mode->green + mode->blue);
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;
11815RGFW_bool RGFW_monitor_requestMode(RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request) {
11816 HMONITOR src = mon->node->hMonitor;
11818 MONITORINFOEX monitorInfo;
11819 monitorInfo.cbSize = sizeof(MONITORINFOEX);
11820 GetMonitorInfoA(src, (LPMONITORINFO)&monitorInfo);
11822 DEVMODEW dm;
11823 ZeroMemory(&dm, sizeof(dm));
11824 dm.dmSize = sizeof(dm);
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 }
11833 if (request & RGFW_monitorRefresh) {
11834 dm.dmFields |= DM_DISPLAYFREQUENCY;
11835 dm.dmDisplayFrequency = (DWORD)mode->refreshRate;
11836 }
11838 if (request & RGFW_monitorRGB) {
11839 dm.dmFields |= DM_BITSPERPEL;
11840 dm.dmBitsPerPel = (DWORD)(mode->red + mode->green + mode->blue);
11841 }
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 }
11852 return RGFW_FALSE;
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;
11868 HBITMAP color = CreateDIBSection(dc,
11869 (BITMAPINFO*) &bi, DIB_RGB_COLORS, (void**) &target,
11870 NULL, (DWORD) 0);
11872 RGFW_copyImageData(target, w, h, RGFW_formatBGRA8, data, format, NULL);
11873 ReleaseDC(NULL, dc);
11875 HBITMAP mask = CreateBitmap((i32)w, (i32)h, 1, 1, NULL);
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;
11885 HICON handle = CreateIconIndirect(&ii);
11887 DeleteObject(color);
11888 DeleteObject(mask);
11890 return handle;
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;
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);
11903void RGFW_freeMouse(RGFW_mouse* mouse) {
11904 RGFW_ASSERT(mouse);
11905 DestroyCursor((HCURSOR)mouse);
11908RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) {
11909 return RGFW_window_setMouseStandard(win, RGFW_mouseArrow);
11912RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) {
11913 RGFW_ASSERT(win != NULL);
11915 u32 mouseIcon = 0;
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 }
11942 char* icon = MAKEINTRESOURCEA(mouseIcon);
11944 SetClassLongPtrA(win->src.window, GCLP_HCURSOR, (LPARAM) LoadCursorA(NULL, icon));
11945 SetCursor(LoadCursorA(NULL, icon));
11946 return RGFW_TRUE;
11949void RGFW_window_hide(RGFW_window* win) {
11950 ShowWindow(win->src.window, SW_HIDE);
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);
11958void RGFW_window_flash(RGFW_window* win, RGFW_flashRequest request) {
11959 if (RGFW_window_isInFocus(win) && request) {
11960 return;
11961 }
11963 FLASHWINFO desc;
11964 RGFW_MEMSET(&desc, 0, sizeof(desc));
11966 desc.cbSize = sizeof(desc);
11967 desc.hwnd = win->src.window;
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 }
11983 FlashWindowEx(&desc);
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
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
11999 RGFW_FREE_LIBRARY(RGFW_wgl_dll);
12001 RGFW_freeMouse(_RGFW->hiddenMouse);
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 */
12010 if (win->src.hIconSmall) DestroyIcon(win->src.hIconSmall);
12011 if (win->src.hIconBig) DestroyIcon(win->src.hIconBig);
12014void RGFW_window_move(RGFW_window* win, i32 x, i32 y) {
12015 RGFW_ASSERT(win != NULL);
12017 win->x = x;
12018 win->y = y;
12019 SetWindowPos(win->src.window, HWND_TOP, win->x, win->y, 0, 0, SWP_NOSIZE);
12022void RGFW_window_resize(RGFW_window* win, i32 w, i32 h) {
12023 RGFW_ASSERT(win != NULL);
12025 win->w = w;
12026 win->h = h;
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);
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);
12036void RGFW_window_setName(RGFW_window* win, const char* name) {
12037 RGFW_ASSERT(win != NULL);
12038 if (name == NULL) name = "\0";
12040 wchar_t wide_name[256];
12041 MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_name, 256);
12042 SetWindowTextW(win->src.window, wide_name);
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);
12053 if (exStyle & WS_EX_LAYERED)
12054 GetLayeredWindowAttributes(win->src.window, &key, &alpha, &flags);
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 }
12064 SetWindowLongW(win->src.window, GWL_EXSTYLE, exStyle);
12066 if (passthrough)
12067 SetLayeredWindowAttributes(win->src.window, key, alpha, flags);
12069#endif
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);
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 }
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
12102RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) {
12103 /* Open the clipboard */
12104 if (OpenClipboard(NULL) == 0)
12105 return -1;
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 }
12114 wchar_t* wstr = (wchar_t*) GlobalLock(hData);
12116 RGFW_ssize_t textLen = 0;
12118 {
12119 setlocale(LC_ALL, "en_US.UTF-8");
12121 textLen = (RGFW_ssize_t)wcstombs(NULL, wstr, 0) + 1;
12122 if (str != NULL && (RGFW_ssize_t)strCapacity <= textLen - 1)
12123 textLen = 0;
12125 if (str != NULL && textLen) {
12126 if (textLen > 1)
12127 wcstombs(str, wstr, (size_t)(textLen));
12129 str[textLen - 1] = '\0';
12130 }
12131 }
12133 /* Release the clipboard data */
12134 GlobalUnlock(hData);
12135 CloseClipboard();
12137 return textLen;
12140void RGFW_writeClipboard(const char* text, u32 textLen) {
12141 HANDLE object;
12142 WCHAR* buffer;
12144 object = GlobalAlloc(GMEM_MOVEABLE, (1 + textLen) * sizeof(WCHAR));
12145 if (!object)
12146 return;
12148 buffer = (WCHAR*) GlobalLock(object);
12149 if (!buffer) {
12150 GlobalFree(object);
12151 return;
12152 }
12154 MultiByteToWideChar(CP_UTF8, 0, text, -1, buffer, (i32)textLen);
12155 GlobalUnlock(object);
12157 if (!OpenClipboard(_RGFW->root->src.window)) {
12158 GlobalFree(object);
12159 return;
12160 }
12162 EmptyClipboard();
12163 SetClipboardData(CF_UNICODETEXT, object);
12164 CloseClipboard();
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);
12174#ifdef RGFW_OPENGL
12175RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char * extension, size_t len) {
12176 const char* extensions = NULL;
12178 RGFW_proc proc = RGFW_getProcAddress_OpenGL("wglGetExtensionsStringARB");
12179 RGFW_proc proc2 = RGFW_getProcAddress_OpenGL("wglGetExtensionsStringEXT");
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);
12188RGFW_proc RGFW_getProcAddress_OpenGL(const char* procname) {
12189 RGFW_proc proc = (RGFW_proc)wglGetProcAddress(procname);
12190 if (proc)
12191 return proc;
12193 return (RGFW_proc) GetProcAddress(RGFW_wgl_dll, procname);
12196void RGFW_win32_loadOpenGLFuncs(HWND dummyWin) {
12197 if (wglSwapIntervalEXT != NULL && wglChoosePixelFormatARB != NULL && wglChoosePixelFormatARB != NULL)
12198 return;
12200 HDC dummy_dc = GetDC(dummyWin);
12201 u32 pfd_flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
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};
12205 int dummy_pixel_format = ChoosePixelFormat(dummy_dc, &pfd);
12206 SetPixelFormat(dummy_dc, dummy_pixel_format, &pfd);
12208 HGLRC dummy_context = wglCreateContext(dummy_dc);
12210 HGLRC cur = wglGetCurrentContext();
12211 wglMakeCurrent(dummy_dc, dummy_context);
12213 wglCreateContextAttribsARB = ((PFNWGLCREATECONTEXTATTRIBSARBPROC(WINAPI *)(const char*)) wglGetProcAddress)("wglCreateContextAttribsARB");
12214 wglChoosePixelFormatARB = ((PFNWGLCHOOSEPIXELFORMATARBPROC(WINAPI *)(const char*)) wglGetProcAddress)("wglChoosePixelFormatARB");
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 }
12221 wglMakeCurrent(dummy_dc, cur);
12222 wglDeleteContext(dummy_context);
12223 ReleaseDC(dummyWin, dummy_dc);
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
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";
12271 win->src.ctx.native = ctx;
12272 win->src.gfxType = RGFW_gfxNativeOpenGL;
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;
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;
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);
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);
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 }
12324 RGFW_attribStack_pushAttribs(&stack, WGL_COVERAGE_SAMPLES_NV, hints->samples);
12326 RGFW_attribStack_pushAttribs(&stack, 0, 0);
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 }
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");
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);
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 }
12357 RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_PROFILE_MASK_ARB, mask);
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 }
12364 if (RGFW_extensionSupportedPlatform_OpenGL(noError, sizeof(noError)))
12365 RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_OPENGL_NO_ERROR_ARB, hints->noError);
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 }
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 }
12383 RGFW_attribStack_pushAttribs(&stack, 0, 0);
12385 win->src.ctx.native->ctx = (HGLRC)wglCreateContextAttribsARB(win->src.hdc, NULL, attribs);
12386 }
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 }
12393 ReleaseDC(win->src.window, win->src.hdc);
12394 win->src.hdc = GetDC(win->src.window);
12396 if (hints->share) {
12397 wglShareLists((HGLRC)RGFW_getCurrentContext_OpenGL(), hints->share->ctx);
12398 }
12400 wglMakeCurrent(win->src.hdc, win->src.ctx.native->ctx);
12401 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized.");
12402 return RGFW_TRUE;
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.");
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);
12417void* RGFW_getCurrentContext_OpenGL(void) {
12418 return wglGetCurrentContext();
12420void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) {
12421 RGFW_ASSERT(win->src.ctx.native);
12422 SwapBuffers(win->src.hdc);
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");
12430#endif
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 }
12442 if (size > (i32)max)
12443 size = (i32)max;
12445 if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, output, size, NULL, NULL)) {
12446 return RGFW_FALSE;
12447 }
12449 output[size] = 0;
12450 return RGFW_TRUE;
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;
12460 fromHwnd.hinstance = GetModuleHandle(NULL);
12462 surfaceDesc.nextInChain = (WGPUChainedStruct*)&fromHwnd.chain;
12463 return wgpuInstanceCreateSurface(instance, &surfaceDesc);
12465#endif
12467#endif /* RGFW_WINDOWS */
12469/*
12470 End of Windows defines
12471*/
12475/*
12477 Start of MacOS defines
12480*/
12482#if defined(RGFW_MACOS)
12483/*
12484 based on silicon.h
12485 start of cocoa wrapper
12486*/
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>
12494#include <Carbon/Carbon.h>
12496typedef TISInputSourceRef (*PFN_TISCopyCurrentKeyboardLayoutInputSource)(void);
12497PFN_TISCopyCurrentKeyboardLayoutInputSource TISCopyCurrentKeyboardLayoutInputSourceSrc;
12498#define TISCopyCurrentKeyboardLayoutInputSource TISCopyCurrentKeyboardLayoutInputSourceSrc
12500typedef CFDataRef (*PFN_TISGetInputSourceProperty)(TISInputSourceRef, CFStringRef);
12501PFN_TISGetInputSourceProperty TISGetInputSourcePropertySrc;
12502#define TISGetInputSourceProperty TISGetInputSourcePropertySrc
12504typedef u8 (*PFN_LMGetKbdType)(void);
12505PFN_LMGetKbdType LMGetKbdTypeSrc;
12506#define LMGetKbdType LMGetKbdTypeSrc
12508CFStringRef kTISPropertyUnicodeKeyLayoutDataSrc;
12510#ifndef __OBJC__
12511typedef CGRect NSRect;
12512typedef CGPoint NSPoint;
12513typedef CGSize NSSize;
12515typedef const char* NSPasteboardType;
12516typedef unsigned long NSUInteger;
12517typedef long NSInteger;
12518typedef NSInteger NSModalResponse;
12520typedef enum NSRequestUserAttentionType {
12521 NSCriticalRequest = 0,
12522 NSInformationalRequest = 10
12523} NSRequestUserAttentionType;
12525typedef enum NSApplicationActivationPolicy {
12526 NSApplicationActivationPolicyRegular,
12527 NSApplicationActivationPolicyAccessory,
12528 NSApplicationActivationPolicyProhibited
12529} NSApplicationActivationPolicy;
12531typedef RGFW_ENUM(u32, NSBackingStoreType) {
12532 NSBackingStoreRetained = 0,
12533 NSBackingStoreNonretained = 1,
12534 NSBackingStoreBuffered = 2
12535};
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};
12553#define NSPasteboardTypeString "public.utf8-plain-text"
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};
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 */
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};
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};
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};
12652typedef RGFW_ENUM(u32, NSEventType) { /* various types of events */
12653 NSEventTypeApplicationDefined = 15,
12654};
12655typedef unsigned long long NSEventMask;
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;
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 */
12671 NSBitmapFormatSixteenBitLittleEndian = (1 << 8),
12672 NSBitmapFormatThirtyTwoBitLittleEndian = (1 << 9),
12673 NSBitmapFormatSixteenBitBigEndian = (1 << 10),
12674 NSBitmapFormatThirtyTwoBitBigEndian = (1 << 11)
12675};
12677#else
12678#import <AppKit/AppKit.h>
12679#include <Foundation/Foundation.h>
12680#endif /* notdef __OBJC__ */
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
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)
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);
12715RGFWDEF float RGFW_cocoaYTransform(float y);
12716float RGFW_cocoaYTransform(float y) { return (float)(CGDisplayBounds(CGMainDisplayID()).size.height - (double)y - (double)1.0f); }
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"));
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"));
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:");
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);
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);
12744id NSPasteboard_generalPasteboard(void);
12745id NSPasteboard_generalPasteboard(void) {
12746 return (id) objc_msgSend_id((id)objc_getClass("NSPasteboard"), sel_registerName("generalPasteboard"));
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]);
12756 return nstrs;
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;
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);
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);
12780 id array = c_array_to_NSArray(ntypes, len);
12781 objc_msgSend_void_id(view, sel_registerName("registerForDraggedTypes:"), array);
12782 NSRelease(array);
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);
12789 SEL func = sel_registerName("declareTypes:owner:");
12791 id array = c_array_to_NSArray(ntypes, len);
12793 NSInteger output = ((NSInteger(*)(id, SEL, id, void*))objc_msgSend)
12794 (pasteboard, func, array, owner);
12795 NSRelease(array);
12797 return output;
12800#define NSRetain(obj) objc_msgSend_void((id)obj, sel_registerName("retain"))
12802/*
12803 End of cocoa wrapper
12804*/
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"));
12811 if (self != nil) {
12812 object_setInstanceVariable(self, "RGFW_window", win);
12813 object_setInstanceVariable(self, "trackingArea", nil);
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 );
12823 ((void (*)(id, SEL))objc_msgSend)(self, sel_registerName("updateTrackingAreas"));
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 }
12839 return self;
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;
12847 RGFW_windowQuitCallback(win);
12848 return false;
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; }
12855static NSDragOperation RGFW__osxDraggingEntered(id self, SEL sel, id sender) {
12856 RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel);
12858 return NSDragOperationCopy;
12860static NSDragOperation RGFW__osxDraggingUpdated(id self, SEL sel, id sender) {
12861 RGFW_UNUSED(sel);
12863 RGFW_window* win = NULL;
12865 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
12866 if (win == NULL)
12867 return 0;
12868 if (!(win->internal.enabledEvents & RGFW_dataDragFlag)) return NSDragOperationCopy;
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;
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;
12880 if (!(win->internal.flags & RGFW_windowAllowDND)) {
12881 return false;
12882 }
12884 return true;
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; }
12890static bool RGFW__osxPerformDragOperation(id self, SEL sel, id sender) {
12891 RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel);
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;
12898 /* id pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard")); */
12900 id pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard"));
12902 /* Get the types of data available on the pasteboard */
12903 id types = objc_msgSend_id(pasteBoard, sel_registerName("types"));
12905 /* Get the string type for file URLs */
12906 id fileURLsType = objc_msgSend_class_char(objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "NSFilenamesPboardType");
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 }
12914 id fileURLs = objc_msgSend_id_id(pasteBoard, sel_registerName("propertyListForType:"), fileURLsType);
12915 int count = ((int (*)(id, SEL))objc_msgSend)(fileURLs, sel_registerName("count"));
12917 if (count == 0)
12918 return 0;
12920 char** files = (char**)(void*)_RGFW->files;
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 }
12930 RGFW_dataDropCallback(win, files, (size_t)count);
12932 return false;
12935#ifndef RGFW_NO_IOKIT
12936#include <IOKit/IOKitLib.h>
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;
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;
12953 while ((service = IOIteratorNext(it)) != 0) {
12954 u32 index;
12955 indexRef = (CFNumberRef)IORegistryEntryCreateCFProperty(service, CFSTR("IOFramebufferOpenGLIndex"), kCFAllocatorDefault, kNilOptions);
12956 if (indexRef == 0) continue;
12958 if (CFNumberGetValue(indexRef, kCFNumberIntType, &index) && CGOpenGLDisplayMaskToDisplayID(1 << index) == displayID) {
12959 CFRelease(indexRef);
12960 break;
12961 }
12963 CFRelease(indexRef);
12964 }
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 }
12980 IOObjectRelease(it);
12981 return refreshRate;
12983#endif
12985void RGFW_moveToMacOSResourceDir(void) {
12986 char resourcesPath[256];
12988 CFBundleRef bundle = CFBundleGetMainBundle();
12989 if (!bundle)
12990 return;
12992 CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle);
12993 CFStringRef last = CFURLCopyLastPathComponent(resourcesURL);
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 }
13004 CFRelease(last);
13005 CFRelease(resourcesURL);
13007 chdir(resourcesPath);
13010static void RGFW__osxDidChangeScreenParameters(id self, SEL _cmd, id notification) {
13011 RGFW_UNUSED(self); RGFW_UNUSED(_cmd); RGFW_UNUSED(notification);
13012 RGFW_pollMonitors();
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;
13021 RGFW_windowRestoredCallback(win, win->x, win->y, win->w, win->h);
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;
13030 RGFW_windowMinimizedCallback(win);
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;
13040 RGFW_focusCallback(win, RGFW_TRUE);
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;
13049 RGFW_focusCallback(win, RGFW_FALSE);
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;
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;
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;
13066 RGFW_monitor* mon = RGFW_window_getMonitor(win);
13067 if (mon == NULL) return;
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 }
13075 RGFW_windowResizedCallback(win, win->w, win->h);
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;
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);
13087 float y = RGFW_cocoaYTransform((float)(content.origin.y + content.size.height - 1));
13089 RGFW_windowMovedCallback(win, (i32)content.origin.x, (i32)y);
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;
13098 RGFW_monitor* mon = RGFW_window_getMonitor(win);
13099 if (mon == NULL) return;
13101 RGFW_scaleUpdatedCallback(win, mon->scaleX, mon->scaleY);
13104static BOOL RGFW__osxWantsUpdateLayer(id self, SEL _cmd) { RGFW_UNUSED(self); RGFW_UNUSED(_cmd); return YES; }
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);
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;
13120 RGFW_windowRefreshCallback(win);
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;
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);
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;
13139 RGFW_mouseNotifyCallback(win, win->internal.lastMouseX, win->internal.lastMouseY, RGFW_FALSE);
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;
13148 u32 key = (u16)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("keyCode"));
13150 RGFW_key value = (u8)RGFW_apiKeyToRGFW(key);
13151 RGFW_bool repeat = RGFW_window_isKeyPressed(win, value);
13153 RGFW_keyCallback(win, value, win->internal.mod, repeat, 1);
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"));
13159 for (size_t index = 0; index < count;
13160 RGFW_keyCharCallback(win, RGFW_decodeUTF8(&string[index], &index))
13161 );
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;
13170 u32 key = (u16)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("keyCode"));
13172 RGFW_key value = (u8)RGFW_apiKeyToRGFW(key);
13173 RGFW_bool repeat = RGFW_window_isKeyDown(win, (u8)value);
13175 RGFW_keyCallback(win, value, win->internal.mod, repeat, 0);
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;
13184 RGFW_key value = 0;
13185 RGFW_bool pressed = RGFW_FALSE;
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;
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 }
13214 RGFW_bool repeat = RGFW_window_isKeyDown(win, (u8)value);
13215 RGFW_keyCallback(win, value, win->internal.mod, repeat, pressed);
13217 if (value != RGFW_capsLock) {
13218 RGFW_keyCallback(win, value + 4, win->internal.mod, repeat, pressed);
13219 }
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;
13229 NSPoint p = ((NSPoint(*)(id, SEL))objc_msgSend)(event, sel_registerName("locationInWindow"));
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"));
13234 RGFW_mousePosCallback(win, (i32)p.x, (i32)(win->h - p.y), (float)vecX, (float)vecY);
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;
13243 u32 buttonNumber = (u32)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("buttonNumber"));
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 }
13253 RGFW_mouseButtonCallback(win, value, 1);
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;
13262 u32 buttonNumber = (u32)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("buttonNumber"));
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 }
13272 RGFW_mouseButtonCallback(win, value, 0);
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;
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"));
13284 RGFW_mouseScrollCallback(win, deltaX, deltaY);
13287RGFW_format RGFW_nativeFormat(void) { return RGFW_formatRGBA8; }
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;
13296 surface->native.buffer = (u8*)RGFW_ALLOC((size_t)(w * h * 4));
13297 return RGFW_TRUE;
13300void RGFW_surface_freePtr(RGFW_surface* surface) {
13301 RGFW_FREE(surface->native.buffer);
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"));
13308 int minW = RGFW_MIN(win->w, surface->w);
13309 int minH = RGFW_MIN(win->h, surface->h);
13311 RGFW_monitor* mon = RGFW_window_getMonitor(win);
13312 if (mon == NULL) return;
13314 minW = (i32)((float)minW * mon->pixelRatio);
13315 minH = (i32)((float)minH * mon->pixelRatio);
13317 surface->native.rep = (void*)NSBitmapImageRep_initWithBitmapData(&surface->native.buffer, minW, minH, 8, 4, true, false, "NSDeviceRGBColorSpace", 1 << 1, (u32)surface->w * 4, 32);
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);
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);
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);
13329 NSRelease(image);
13330 NSRelease(surface->native.rep);
13332 objc_msgSend_bool_void(pool, sel_registerName("drain"));
13335void* RGFW_window_getView_OSX(RGFW_window* win) { return win->src.view; }
13337void RGFW_window_setLayer_OSX(RGFW_window* win, void* layer) {
13338 objc_msgSend_void_id((id)win->src.view, sel_registerName("setLayer:"), (id)layer);
13341void* RGFW_getLayer_OSX(void) {
13342 return objc_msgSend_class((id)objc_getClass("CAMetalLayer"), (SEL)sel_registerName("layer"));
13344void* RGFW_window_getWindow_OSX(RGFW_window* win) { return win->src.window; }
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;
13460i32 RGFW_initPlatform(void) {
13461 _RGFW->tisBundle = (void*)CFBundleGetBundleWithIdentifier(CFSTR("com.apple.HIToolbox"));
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"));
13467 CFStringRef* cfStr = (CFStringRef*)CFBundleGetDataPointerForName((CFBundleRef)_RGFW->tisBundle, CFSTR("kTISPropertyUnicodeKeyLayoutData"));;
13468 if (cfStr) kTISPropertyUnicodeKeyLayoutDataSrc = *cfStr;
13470 class_addMethod(objc_getClass("NSObject"), sel_registerName("windowShouldClose:"), (IMP)(void*)RGFW_OnClose, 0);
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);
13476 _RGFW->NSApp = objc_msgSend_id(objc_getClass("NSApplication"), sel_registerName("sharedApplication"));
13478 NSRetain(_RGFW->NSApp);
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"));
13485 objc_msgSend_void_id(_RGFW->NSApp, sel_registerName("setDelegate:"), _RGFW->customNSAppDelegate);
13487 ((void (*)(id, SEL, NSUInteger))objc_msgSend) ((id)_RGFW->NSApp, sel_registerName("setActivationPolicy:"), NSApplicationActivationPolicyRegular);
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 }
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;
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);
13545 if (RGFW_COCOA_FRAME_NAME)
13546 objc_msgSend_ptr(win->src.view, sel_registerName("setFrameAutosaveName:"), RGFW_COCOA_FRAME_NAME);
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);
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 );
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"));
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"));
13572 RGFW_window_setMouseDefault(win);
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);
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:");
13589 win->src.window = ((id(*)(id, SEL, NSRect, NSWindowStyleMask, NSBackingStoreType, bool))objc_msgSend)
13590 (NSAlloc(nsclass), func, windowRect, (NSWindowStyleMask)macArgs, macArgs, false);
13591 }
13593 id str = NSString_stringWithUTF8String(name);
13594 objc_msgSend_void_id((id)win->src.window, sel_registerName("setTitle:"), str);
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);
13599 objc_msgSend_void_id((id)win->src.window, sel_registerName("setDelegate:"), (id)win->src.delegate);
13601 if (flags & RGFW_windowAllowDND) {
13602 win->internal.flags |= RGFW_windowAllowDND;
13604 NSPasteboardType types[] = {NSPasteboardTypeURL, NSPasteboardTypeFileURL, NSPasteboardTypeString};
13605 NSregisterForDraggedTypes((id)win->src.window, types, 3);
13606 }
13608 objc_msgSend_void_bool((id)win->src.window, sel_registerName("setAcceptsMouseMovedEvents:"), true);
13610 if (flags & RGFW_windowTransparent) {
13611 objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), false);
13613 objc_msgSend_void_id((id)win->src.window, sel_registerName("setBackgroundColor:"),
13614 NSColor_colorWithSRGB(0, 0, 0, 0));
13615 }
13617 /* Show the window */
13618 objc_msgSend_void_bool((id)_RGFW->NSApp, sel_registerName("activateIgnoringOtherApps:"), true);
13620 if (_RGFW->root == NULL) {
13621 objc_msgSend_void(win->src.window, sel_registerName("makeMainWindow"));
13622 }
13624 objc_msgSend_void(win->src.window, sel_registerName("makeKeyWindow"));
13626 NSRetain(win->src.window);
13628 win->src.view = ((id(*)(id, SEL, RGFW_window*))objc_msgSend) (NSAlloc((Class)_RGFW->customViewClasses[0]), sel_registerName("initWithRGFWWindow:"), win);
13629 return win;
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;
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 }
13645 ((void (*)(id, SEL, NSBackingStoreType))objc_msgSend)((id)win->src.window, sel_registerName("setStyleMask:"), storeType);
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);
13652 offset = (double)(frame.size.height - content.size.height);
13653 }
13655 RGFW_window_resize(win, win->w, win->h + (i32)offset);
13656 win->h -= (i32)offset;
13659RGFW_bool RGFW_getGlobalMouse(i32* x, i32* y) {
13660 RGFW_ASSERT(_RGFW->root != NULL);
13662 CGEventRef e = CGEventCreate(NULL);
13663 CGPoint point = CGEventGetLocation(e);
13664 CFRelease(e);
13666 if (x) *x = (i32)point.x;
13667 if (y) *y = (i32)point.y;
13668 return RGFW_TRUE;
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"));
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);
13679 ((void (*)(id, SEL, id, bool))objc_msgSend)
13680 ((id)_RGFW->NSApp, sel_registerName("postEvent:atStart:"), e, 1);
13682 objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
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"));
13689 void* date = (void*) ((id(*)(Class, SEL, double))objc_msgSend)
13690 (objc_getClass("NSDate"), sel_registerName("dateWithTimeIntervalSinceNow:"), waitMS);
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);
13697 if (e) {
13698 ((void (*)(id, SEL, id, bool))objc_msgSend)
13699 ((id)_RGFW->NSApp, sel_registerName("postEvent:atStart:"), e, 1);
13700 }
13702 objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
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;
13711 CFDataRef layoutData = TISGetInputSourceProperty(source, kTISPropertyUnicodeKeyLayoutDataSrc);
13713 if (layoutData == NULL) {
13714 CFRelease(source);
13715 return key;
13716 }
13718 UCKeyboardLayout *layout = (UCKeyboardLayout*)(void*)CFDataGetBytePtr(layoutData);
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 );
13726 CFRelease(source);
13728 if (status == noErr && len == 1 && chars[0] < 256) {
13729 return (RGFW_key)chars[0];
13730 }
13732 return key;
13735void RGFW_pollEvents(void) {
13736 RGFW_resetPrevState();
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:");
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);
13747 if (e == NULL) {
13748 break;
13749 }
13751 objc_msgSend_void_id((id)_RGFW->NSApp, sel_registerName("sendEvent:"), e);
13752 }
13754 objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
13758void RGFW_window_move(RGFW_window* win, i32 x, i32 y) {
13759 RGFW_ASSERT(win != NULL);
13761 NSRect content = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame"));
13763 win->x = x;
13764 win->y = (i32)RGFW_cocoaYTransform((float)y + (float)content.size.height - 1.0f);
13766 ((void(*)(id,SEL,NSPoint))objc_msgSend)((id)win->src.window, sel_registerName("setFrameOrigin:"), (NSPoint){(double)x, (double)y});
13769void RGFW_window_resize(RGFW_window* win, i32 w, i32 h) {
13770 RGFW_ASSERT(win != NULL);
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);
13776 win->w = w;
13777 win->h = h;
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);
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"));
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);
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;
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;
13808 win->internal.flags |= RGFW_windowFullscreen;
13810 RGFW_monitor* mon = RGFW_window_getMonitor(win);
13811 RGFW_monitor_scaleToWindow(mon, win);
13813 RGFW_window_setBorder(win, RGFW_FALSE);
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 }
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 }
13828 objc_msgSend_void_SEL(win->src.window, sel_registerName("toggleFullScreen:"), NULL);
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;
13837 RGFW_window_resize(win, win->w, win->h);
13838 RGFW_window_move(win, win->x, win->y);
13839 }
13842void RGFW_window_maximize(RGFW_window* win) {
13843 RGFW_ASSERT(win != NULL);
13844 if (RGFW_window_isMaximized(win)) return;
13846 win->internal.flags |= RGFW_windowMaximize;
13847 objc_msgSend_void_SEL(win->src.window, sel_registerName("zoom:"), NULL);
13850void RGFW_window_minimize(RGFW_window* win) {
13851 RGFW_ASSERT(win != NULL);
13852 objc_msgSend_void_SEL(win->src.window, sel_registerName("performMiniaturize:"), NULL);
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);
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));
13865 if (opacity)
13866 objc_msgSend_void_id((id)win->src.window, sel_registerName("setBackgroundColor:"), NSColor_colorWithSRGB(0, 0, 0, opacity));
13870void RGFW_window_restore(RGFW_window* win) {
13871 RGFW_ASSERT(win != NULL);
13873 if (RGFW_window_isMaximized(win))
13874 objc_msgSend_void_SEL(win->src.window, sel_registerName("zoom:"), NULL);
13876 objc_msgSend_void_SEL(win->src.window, sel_registerName("deminiaturize:"), NULL);
13877 RGFW_window_show(win);
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;
13886void RGFW_window_setName(RGFW_window* win, const char* name) {
13887 RGFW_ASSERT(win != NULL);
13888 if (name == NULL) name = "\0";
13890 id str = NSString_stringWithUTF8String(name);
13891 objc_msgSend_void_id((id)win->src.window, sel_registerName("setTitle:"), str);
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);
13898#endif
13900void RGFW_window_setAspectRatio(RGFW_window* win, i32 w, i32 h) {
13901 if (w == 0 && h == 0) { w = 1; h = 1; };
13903 ((void (*)(id, SEL, NSSize))objc_msgSend)
13904 ((id)win->src.window, sel_registerName("setContentAspectRatio:"), (NSSize){(CGFloat)w, (CGFloat)h});
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});
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 }
13920 ((void (*)(id, SEL, NSSize))objc_msgSend)
13921 ((id)win->src.window, sel_registerName("setMaxSize:"), (NSSize){(CGFloat)w, (CGFloat)h});
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);
13928 id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
13929 pool = objc_msgSend_id(pool, sel_registerName("init"));
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 }
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);
13940 id dock_image = ((id(*)(id, SEL, NSSize))objc_msgSend) (NSAlloc((id)objc_getClass("NSImage")), sel_registerName("initWithSize:"), ((NSSize){(CGFloat)w, (CGFloat)h}));
13942 objc_msgSend_void_id(dock_image, sel_registerName("addRepresentation:"), representation);
13944 objc_msgSend_void_id((id)_RGFW->NSApp, sel_registerName("setApplicationIconImage:"), dock_image);
13946 NSRelease(dock_image);
13947 NSRelease(representation);
13949 objc_msgSend_bool_void(pool, sel_registerName("drain"));
13951 return RGFW_TRUE;
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);
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"));
13965 if (data == NULL) {
13966 objc_msgSend_void(NSCursor_arrowStr("arrowCursor"), sel_registerName("set"));
13968 objc_msgSend_bool_void(pool, sel_registerName("drain"));
13969 return NULL;
13970 }
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);
13975 id cursor_image = ((id(*)(id, SEL, NSSize))objc_msgSend) (NSAlloc((id)objc_getClass("NSImage")), sel_registerName("initWithSize:"), ((NSSize){(CGFloat)w, (CGFloat)h}));
13977 objc_msgSend_void_id(cursor_image, sel_registerName("addRepresentation:"), representation);
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});
13982 NSRelease(cursor_image);
13983 NSRelease(representation);
13985 objc_msgSend_bool_void(pool, sel_registerName("drain"));
13987 return (void*)cursor;
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;
13997void RGFW_freeMouse(RGFW_mouse* mouse) {
13998 RGFW_ASSERT(mouse);
13999 NSRelease((id)mouse);
14002RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) {
14003 return RGFW_window_setMouseStandard(win, RGFW_mouseArrow);
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);
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 }
14040 id mouse = NSCursor_arrowStr(cursorSelectorStr);
14042 if (mouse == NULL)
14043 return RGFW_FALSE;
14045 RGFW_UNUSED(win);
14046 CGDisplayShowCursor(kCGDirectMainDisplay);
14047 objc_msgSend_void(mouse, sel_registerName("set"));
14048 win->src.mouse = mouse;
14050 return RGFW_TRUE;
14053void RGFW_window_setRawMouseModePlatform(RGFW_window* win, RGFW_bool state) {
14054 RGFW_UNUSED(win); RGFW_UNUSED(state);
14057void RGFW_window_captureMousePlatform(RGFW_window* win, RGFW_bool state) {
14058 RGFW_UNUSED(win);
14059 CGAssociateMouseAndMouseCursorPosition(!(state == RGFW_TRUE));
14062void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y) {
14063 RGFW_UNUSED(win);
14065 win->internal.lastMouseX = x - win->x;
14066 win->internal.lastMouseY = y - win->y;
14067 CGWarpMouseCursorPosition((CGPoint){(CGFloat)x, (CGFloat)y});
14071void RGFW_window_hide(RGFW_window* win) {
14072 objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), false);
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);
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);
14083void RGFW_window_flash(RGFW_window* win, RGFW_flashRequest request) {
14084 if (RGFW_window_isInFocus(win) && request) {
14085 return;
14086 }
14088 id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
14089 pool = objc_msgSend_id(pool, sel_registerName("init"));
14091 if (_RGFW->flash) {
14092 ((void (*)(id, SEL, NSInteger))objc_msgSend) ((id)_RGFW->NSApp, sel_registerName("cancelUserAttentionRequest:"), _RGFW->flash);
14093 }
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 }
14105 objc_msgSend_bool_void(pool, sel_registerName("drain"));
14108RGFW_bool RGFW_window_isHidden(RGFW_window* win) {
14109 RGFW_ASSERT(win != NULL);
14111 bool visible = objc_msgSend_bool(win->src.window, sel_registerName("isVisible"));
14112 return visible == NO && !RGFW_window_isMinimized(win);
14115RGFW_bool RGFW_window_isMinimized(RGFW_window* win) {
14116 RGFW_ASSERT(win != NULL);
14118 return objc_msgSend_bool(win->src.window, sel_registerName("isMiniaturized")) == YES;
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;
14127RGFWDEF id RGFW_getNSScreenForDisplayUInt(u32 uintNum);
14128id RGFW_getNSScreenForDisplayUInt(u32 uintNum) {
14129 Class NSScreenClass = objc_getClass("NSScreen");
14131 id screens = objc_msgSend_id(NSScreenClass, sel_registerName("screens"));
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);
14141 if (CGDisplayUnitNumber((CGDirectDisplayID)objc_msgSend_uint(screenNumber, sel_registerName("unsignedIntValue"))) == uintNum) {
14142 return screen;
14143 }
14144 }
14146 return NULL;
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 }
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;
14165void RGFW_pollMonitors(void) {
14166 static CGDirectDisplayID displays[RGFW_MAX_MONITORS];
14167 u32 count;
14169 if (CGGetActiveDisplayList(RGFW_MAX_MONITORS, displays, &count) != kCGErrorSuccess) {
14170 return;
14171 }
14173 if (count > RGFW_MAX_MONITORS) count = RGFW_MAX_MONITORS;
14175 for (RGFW_monitorNode* node = _RGFW->monitors.list.head; node; node = node->next) {
14176 node->disconnected = RGFW_TRUE;
14177 }
14179 CGDirectDisplayID primary = CGMainDisplayID();
14181 u32 i;
14182 for (i = 0; i < count; i++) {
14183 RGFW_monitor monitor;
14185 u32 uintNum = CGDisplayUnitNumber(displays[i]);
14186 id screen = RGFW_getNSScreenForDisplayUInt(uintNum);
14188 RGFW_monitorNode* node;
14189 for (node = _RGFW->monitors.list.head; node; node = node->next) {
14190 if (node->uintNum == uintNum) break;
14191 }
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 }
14203 const char name[] = "MacOS\0";
14204 RGFW_MEMCPY(monitor.name, name, 6);
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));
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;
14216 monitor.mode.refreshRate = RGFW_osx_getRefreshRate(displays[i], mode);
14217 CFRelease(mode);
14219 CGSize screenSizeMM = CGDisplayScreenSize(displays[i]);
14220 monitor.physW = (float)screenSizeMM.width / 25.4f;
14221 monitor.physH = (float)screenSizeMM.height / 25.4f;
14223 float ppi_width = ((float)monitor.mode.w / monitor.physW);
14224 float ppi_height = ((float)monitor.mode.h / monitor.physH);
14226 monitor.pixelRatio = (float)((CGFloat (*)(id, SEL))abi_objc_msgSend_fpret) (screen, sel_registerName("backingScaleFactor"));
14227 float dpi = 96.0f * monitor.pixelRatio;
14229 monitor.scaleX = ((((float) (ppi_width) / dpi) * 10.0f)) / 10.0f;
14230 monitor.scaleY = ((((float) (ppi_height) / dpi) * 10.0f)) / 10.0f;
14232 node = RGFW_monitors_add(&monitor);
14234 node->screen = (void*)screen;
14235 node->uintNum = uintNum;
14236 node->display = displays[i];
14238 if (displays[i] == primary) {
14239 _RGFW->monitors.primary = node;
14240 }
14242 RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_TRUE);
14243 }
14245 RGFW_monitors_refresh();
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"));
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;
14256 return RGFW_TRUE;
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"));
14263 u32 size = CGDisplayGammaTableCapacity(monitor->node->display);
14264 CGGammaValue* values = (CGGammaValue*)RGFW_ALLOC(size * 3 * sizeof(CGGammaValue));
14266 CGGetDisplayTransferByTable(monitor->node->display, size, values, values + size, values + size * 2, &size);
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 }
14274 RGFW_FREE(values);
14276 objc_msgSend_bool_void(pool, sel_registerName("drain"));
14277 return size;
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"));
14284 CGGammaValue* values = (CGGammaValue*)RGFW_ALLOC(ramp->count * 3 * sizeof(CGGammaValue));
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 }
14292 CGSetDisplayTransferByTable(monitor->node->display, (u32)ramp->count, values, values + ramp->count, values + ramp->count * 2);
14294 RGFW_FREE(values);
14296 objc_msgSend_bool_void(pool, sel_registerName("drain"));
14298 return RGFW_TRUE;
14301size_t RGFW_monitor_getModesPtr(RGFW_monitor* mon, RGFW_monitorMode** modes) {
14302 CGDirectDisplayID display = mon->node->display;
14303 CFArrayRef allModes = CGDisplayCopyAllDisplayModes(display, NULL);
14305 if (allModes == NULL) {
14306 return RGFW_FALSE;
14307 }
14309 size_t count = (size_t)CFArrayGetCount(allModes);
14311 CFIndex i;
14312 for (i = 0; i < (CFIndex)count && modes; i++) {
14313 CGDisplayModeRef cmode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, i);
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 }
14324 CFRelease(allModes);
14325 return count;
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 }
14333 return RGFW_FALSE;
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);
14340 if (allModes == NULL) {
14341 return RGFW_FALSE;
14342 }
14344 CGDisplayModeRef native = NULL;
14346 CFIndex i;
14347 for (i = 0; i < CFArrayGetCount(allModes); i++) {
14348 CGDisplayModeRef cmode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, i);
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;
14357 if (RGFW_monitorModeCompare(mode, &foundMode, request)) {
14358 native = cmode;
14359 mon->mode = foundMode;
14360 break;
14361 }
14362 }
14364 CFRelease(allModes);
14366 if (native) {
14367 if (CGDisplaySetDisplayMode(display, native, NULL) == kCGErrorSuccess) {
14368 return RGFW_TRUE;
14369 }
14370 }
14372 return RGFW_FALSE;
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);
14381 CGDirectDisplayID display = (CGDirectDisplayID)objc_msgSend_uint(screenNumber, sel_registerName("unsignedIntValue"));
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 }
14390 return &node->mon;
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;
14398 if (str != NULL) {
14399 if (strCapacity < clip_len)
14400 return 0;
14402 RGFW_MEMCPY(str, clip, clip_len);
14404 str[clip_len] = '\0';
14405 }
14407 return (RGFW_ssize_t)clip_len;
14410void RGFW_writeClipboard(const char* text, u32 textLen) {
14411 RGFW_UNUSED(textLen);
14413 NSPasteboardType array[] = { NSPasteboardTypeString, NULL };
14414 NSPasteBoard_declareTypes(NSPasteboard_generalPasteboard(), array, 1, NULL);
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));
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);
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; }
14432RGFW_proc RGFW_getProcAddress_OpenGL(const char* procname) {
14433 static CFBundleRef RGFWnsglFramework = NULL;
14434 if (RGFWnsglFramework == NULL)
14435 RGFWnsglFramework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
14437 CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault, procname, kCFStringEncodingASCII);
14439 RGFW_proc symbol = (RGFW_proc)CFBundleGetFunctionPointerForName(RGFWnsglFramework, symbolName);
14441 CFRelease(symbolName);
14443 return symbol;
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;
14450 i32 attribs[40];
14451 size_t render_type_index = 0;
14452 {
14453 RGFW_attribStack stack;
14454 RGFW_attribStack_init(&stack, attribs, 40);
14456 i32 colorBits = (i32)(hints->red + hints->green + hints->blue + hints->alpha) / 4;
14457 RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAColorSize, colorBits);
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);
14469 if (hints->doubleBuffer)
14470 RGFW_attribStack_pushAttrib(&stack, NSOpenGLPFADoubleBuffer);
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
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);
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 }
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;
14496 RGFW_attribStack_pushAttribs(&stack, 0, 0);
14497 }
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");
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;
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 }
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) */
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);
14523 id share = NULL;
14524 if (hints->share) {
14525 share = (id)hints->share->ctx;
14526 }
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);
14532 win->src.ctx.native->format = format;
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);
14540 }
14542 objc_msgSend_void(win->src.ctx.native->ctx, sel_registerName("makeCurrentContext"));
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);
14548 RGFW_window_swapInterval_OpenGL(win, 0);
14550 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized.");
14551 return RGFW_TRUE;
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;
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.");
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"));
14570void* RGFW_getCurrentContext_OpenGL(void) {
14571 return objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("currentContext"));
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"));
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);
14582#endif
14584void RGFW_deinitPlatform(void) {
14585 objc_msgSend_void_id(_RGFW->NSApp, sel_registerName("setDelegate:"), NULL);
14587 objc_msgSend_void_id(_RGFW->NSApp, sel_registerName("stop:"), NULL);
14588 NSRelease(_RGFW->NSApp);
14589 _RGFW->NSApp = NULL;
14591 NSRelease(_RGFW->customNSAppDelegate);
14593 _RGFW->customNSAppDelegate = NULL;
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);
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);
14606 objc_msgSend_id(win->src.window, sel_registerName("close"));
14607 NSRelease(win->src.window);
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);
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"));
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 }
14626 id layer = ((id (*)(id, SEL))objc_msgSend)(nsView, sel_registerName("layer"));
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);
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*/
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;
14649 result = vkCreateMacOSSurfaceMVK(instance, &macos, NULL, surface);
14651 objc_msgSend_bool_void(pool, sel_registerName("drain"));
14653 return result;
14655#endif
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 }
14666 ((void (*)(id, SEL, BOOL))objc_msgSend)(nsView, sel_registerName("setWantsLayer:"), YES);
14667 id layer = ((id (*)(id, SEL))objc_msgSend)(nsView, sel_registerName("layer"));
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;
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
14684 surfaceDesc.nextInChain = (WGPUChainedStruct*)&fromMetal.chain;
14685 return wgpuInstanceCreateSurface(instance, &surfaceDesc);
14687#endif
14689#endif /* RGFW_MACOS */
14691/*
14692 End of MaOS defines
14693*/
14695/*
14696 WASM defines
14697*/
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;
14706EM_BOOL Emscripten_on_fullscreenchange(int eventType, const EmscriptenFullscreenChangeEvent* E, void* userData) {
14707 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
14709 if (!(_RGFW->root->internal.enabledEvents & RGFW_windowResizedFlag)) return EM_TRUE;
14711 static u8 fullscreen = RGFW_FALSE;
14712 static i32 originalW, originalH;
14714 if (fullscreen == RGFW_FALSE) {
14715 originalW = _RGFW->root->w;
14716 originalH = _RGFW->root->h;
14717 }
14719 fullscreen = !fullscreen;
14720 _RGFW->root->w = E->screenWidth;
14721 _RGFW->root->h = E->screenHeight;
14723 EM_ASM("Module.canvas.focus();");
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 }
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;
14745EM_BOOL Emscripten_on_focusin(int eventType, const EmscriptenFocusEvent* E, void* userData) {
14746 RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(E);
14748 RGFW_focusCallback(_RGFW->root, 1);
14749 return EM_TRUE;
14752EM_BOOL Emscripten_on_focusout(int eventType, const EmscriptenFocusEvent* E, void* userData) {
14753 RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(E);
14755 RGFW_focusCallback(_RGFW->root, 0);
14756 return EM_TRUE;
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;
14765EM_BOOL Emscripten_on_mousedown(int eventType, const EmscriptenMouseEvent* E, void* userData) {
14766 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
14768 int button = E->button;
14769 if (button > 2)
14770 button += 2;
14772 RGFW_mouseButtonCallback(_RGFW->root, button, 1);
14773 return EM_TRUE;
14776EM_BOOL Emscripten_on_mouseup(int eventType, const EmscriptenMouseEvent* E, void* userData) {
14777 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
14779 int button = E->button;
14780 if (button > 2)
14781 button += 2;
14783 RGFW_mouseButtonCallback(_RGFW->root, button, 0);
14784 return EM_TRUE;
14787EM_BOOL Emscripten_on_wheel(int eventType, const EmscriptenWheelEvent* E, void* userData) {
14788 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
14790 RGFW_mouseScrollCallback(_RGFW->root, E->deltaX, E->deltaY);
14792 return EM_TRUE;
14795EM_BOOL Emscripten_on_touchstart(int eventType, const EmscriptenTouchEvent* E, void* userData) {
14796 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
14798 if (!(_RGFW->root->internal.enabledEvents & RGFW_mouseButtonPressedFlag)) return EM_TRUE;
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 }
14806 return EM_TRUE;
14809EM_BOOL Emscripten_on_touchmove(int eventType, const EmscriptenTouchEvent* E, void* userData) {
14810 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
14812 if (!(_RGFW->root->internal.enabledEvents & RGFW_mousePosChangedFlag)) return EM_TRUE;
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;
14821EM_BOOL Emscripten_on_touchend(int eventType, const EmscriptenTouchEvent* E, void* userData) {
14822 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
14824 if (!(_RGFW->root->internal.enabledEvents & RGFW_mouseButtonReleasedFlag)) return EM_TRUE;
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;
14834EM_BOOL Emscripten_on_touchcancel(int eventType, const EmscriptenTouchEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); return EM_TRUE; }
14836RGFW_key RGFW_WASMPhysicalToRGFW(u32 hash);
14838void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyEvent(char* code, u32 codepoint, RGFW_bool press) {
14839 const char* iCode = code;
14841 u32 hash = 0;
14842 while(*iCode) hash = ((hash ^ 0x7E057D79U) << 3) ^ (unsigned int)*iCode++;
14844 u32 physicalKey = RGFW_WASMPhysicalToRGFW(hash);
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 }
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);
14856void EMSCRIPTEN_KEEPALIVE Emscripten_onDrop(size_t count) {
14857 RGFW_dataDropCallback(_RGFW->root, _RGFW->files, count);
14860void RGFW_stopCheckEvents(void) {
14861 _RGFW->stopCheckEvents_bool = RGFW_TRUE;
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;
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));
14884void RGFW_surface_freePtr(RGFW_surface* surface) { }
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';
14894#include <sys/stat.h>
14895#include <sys/types.h>
14896#include <errno.h>
14897#include <stdio.h>
14899void EMSCRIPTEN_KEEPALIVE RGFW_mkdir(char* name) { mkdir(name, 0755); }
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;
14906 fwrite(data, sizeof(char), len, file);
14907 fclose(file);
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;
15021i32 RGFW_initPlatform(void) { return 0; }
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);
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);
15041 if (flags & RGFW_windowAllowDND) {
15042 win->internal.flags |= RGFW_windowAllowDND;
15043 }
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"));
15051 var codepoint = event.key.charCodeAt(0);
15052 if(codepoint < 0x7f && event.key.length > 1) {
15053 codepoint = 0;
15054 }
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 });
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;
15077 var filenamesArray = [];
15078 var count = e.dataTransfer.files.length;
15080 /* Read and save the files to emscripten's files */
15081 var drop_dir = '.rgfw_dropped_files';
15082 Module._RGFW_mkdir(drop_dir);
15084 for (var i = 0; i < count; i++) {
15085 var file = e.dataTransfer.files[i];
15087 var path = '/' + drop_dir + '/' + file.name.replace("//", '_');
15088 var reader = new FileReader();
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;
15097 Module._RGFW_writeFile(path, new Uint8Array(data), file.size);
15098 }
15099 };
15101 reader.readAsArrayBuffer(file);
15102 /* This works weird on modern OpenGL */
15103 var filename = stringToNewUTF8(path);
15105 filenamesArray.push(filename);
15107 Module._RGFW_makeSetValue(i, filename);
15108 }
15110 Module._Emscripten_onDrop(count);
15112 for (var i = 0; i < count; i++) {
15113 _free(filenamesArray[i]);
15114 }
15115 }, true);
15117 canvas.addEventListener('dragover', function(e) { e.preventDefault(); return false; }, true);
15118 });
15120 return win;
15123RGFW_key RGFW_physicalToMappedKey(RGFW_key key) {
15124 return key;
15127void RGFW_pollEvents(void) {
15128 RGFW_resetPrevState();
15129 emscripten_sleep(0);
15132void RGFW_window_resize(RGFW_window* win, i32 w, i32 h) {
15133 RGFW_UNUSED(win);
15134 emscripten_set_canvas_element_size("#canvas", w, h);
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; }
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); }
15145RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) {
15146 RGFW_UNUSED(win);
15147 char* cursorName = NULL;
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 }
15174 EM_ASM( { document.getElementById("canvas").style.cursor = UTF8ToString($0); }, cursorName);
15175 return RGFW_TRUE;
15178RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) {
15179 return RGFW_window_setMouseStandard(win, RGFW_mouseNormal);
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';);
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;
15200void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) {
15201 RGFW_UNUSED(win);
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);
15213void RGFW_writeClipboard(const char* text, u32 textLen) {
15214 RGFW_UNUSED(textLen);
15215 EM_ASM({ navigator.clipboard.writeText(UTF8ToString($0)); }, text);
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;
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;
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;
15241 if (hints->doubleBuffer == 0)
15242 attrs.renderViaOffscreenBackBuffer = 0;
15243 else
15244 attrs.renderViaOffscreenBackBuffer = hints->auxBuffers;
15246 attrs.failIfMajorPerformanceCaveat = EM_FALSE;
15247 attrs.majorVersion = (hints->major == 0) ? 1 : hints->major;
15248 attrs.minorVersion = hints->minor;
15250 attrs.enableExtensionsByDefault = EM_TRUE;
15251 attrs.explicitSwapControl = EM_TRUE;
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);
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
15262 RGFW_window_swapInterval_OpenGL(win, 0);
15264 return RGFW_TRUE;
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.");
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);
15281void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) {
15282 RGFW_ASSERT(win && win->src.ctx.native);
15283 emscripten_webgl_commit_frame();
15285void* RGFW_getCurrentContext_OpenGL(void) { return (void*)emscripten_webgl_get_current_context(); }
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;
15294 var supported = gl.getSupportedExtensions();
15295 return supported && supported.includes(ext) ? 1 : 0;
15296 }, extension, len);
15297 return RGFW_FALSE;
15300RGFW_proc RGFW_getProcAddress_OpenGL(const char* procname) {
15301 return (RGFW_proc)emscripten_webgl_get_proc_address(procname);
15302 return NULL;
15305#endif
15307void RGFW_window_swapInterval_OpenGL(RGFW_window* win, i32 swapInterval) { RGFW_UNUSED(win); RGFW_UNUSED(swapInterval); }
15309void RGFW_deinitPlatform(void) { }
15311void RGFW_window_closePlatform(RGFW_window* win) { }
15313int RGFW_innerWidth(void) { return EM_ASM_INT({ return window.innerWidth; }); }
15314int RGFW_innerHeight(void) { return EM_ASM_INT({ return window.innerHeight; }); }
15316void RGFW_window_setRawMouseModePlatform(RGFW_window* win, RGFW_bool state) {
15317 RGFW_UNUSED(win); RGFW_UNUSED(state);
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 }
15329void RGFW_window_setName(RGFW_window* win, const char* name) {
15330 RGFW_UNUSED(win);
15331 if (name == NULL) name = "\0";
15333 emscripten_set_window_title(name);
15336void RGFW_window_maximize(RGFW_window* win) {
15337 RGFW_ASSERT(win != NULL);
15339 RGFW_monitor* mon = RGFW_window_getMonitor(win);
15340 if (mon != NULL) {
15341 RGFW_window_resize(win, mon->mode.w, mon->mode.h);
15342 }
15344 RGFW_window_move(win, 0, 0);
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); );
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);
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};
15374 surfaceDesc.nextInChain = &canvasDesc.chain;
15375 return wgpuInstanceCreateSurface(instance, &surfaceDesc);
15377#endif
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 }
15492 return 0;
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
15525/* end of web asm defines */
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
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;
15664RGFW_functionPointers RGFW_api;
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); }
15695#ifndef RGFW_NO_PASSTHROUGH
15696void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) { RGFW_api.window_setMousePassthrough(win, passthrough); }
15697#endif
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); }
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
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 */
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
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
15879#endif /* wayland AND x11 */
15880/* end of X11 AND wayland defines */
15882#endif /* RGFW_IMPLEMENTATION */
15884#if defined(__cplusplus) && !defined(__EMSCRIPTEN__)
15886#endif
15888#if _MSC_VER
15889 #pragma warning( pop )
15890#endif
index : raylib-jai
---