0/*
1*
2* RGFW 1.7.5-dev
4* Copyright (C) 2022-25 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_OSMESA - (optional) use OSmesa as backend (instead of system's opengl api + regular opengl)
36 #define RGFW_BUFFER - (optional) draw directly to (RGFW) window pixel buffer that is drawn to screen (the buffer is in the RGBA format)
37 #define RGFW_EGL - (optional) use EGL for loading an OpenGL context (instead of the system's opengl api)
38 #define RGFW_OPENGL_ES1 - (optional) use EGL to load and use Opengl ES (version 1) for backend rendering (instead of the system's opengl api)
39 This version doesn't work for desktops (I'm pretty sure)
40 #define RGFW_OPENGL_ES2 - (optional) use OpenGL ES (version 2)
41 #define RGFW_OPENGL_ES3 - (optional) use OpenGL ES (version 3)
42 #define RGFW_DIRECTX - (optional) include integration directX functions (windows only)
43 #define RGFW_VULKAN - (optional) include helpful vulkan integration functions and macros
44 #define RGFW_WEBGPU - (optional) use webGPU for rendering (Web ONLY)
45 #define RGFW_NO_API - (optional) don't use any rendering API (no opengl, no vulkan, no directX)
47 #define RGFW_LINK_EGL (optional) (windows only) if EGL is being used, if EGL functions should be defined dymanically (using GetProcAddress)
48 #define RGFW_X11 (optional) (unix only) if X11 should be used. This option is turned on by default by unix systems except for MacOS
49 #define RGFW_WAYLAND (optional) (unix only) use Wayland. (This can be used with X11)
50 #define RGFW_NO_X11 (optional) (unix only) don't fallback to X11 when using Wayland
51 #define RGFW_NO_LOAD_WGL (optional) (windows only) if WGL should be loaded dynamically during runtime
52 #define RGFW_NO_X11_CURSOR (optional) (unix only) don't use XCursor
53 #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)
54 #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)
55 #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)
56 #define RGFW_NO_WINMM (optional) (windows only) don't use winmm
57 #define RGFW_NO_IOKIT (optional) (macOS) don't use IOKit
58 #define RGFW_NO_UNIX_CLOCK (optional) (unix) don't link unix clock functions
59 #define RGFW_NO_DWM (windows only) - do not use or link dwmapi
60 #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)
61 #define RGFW_COCOA_GRAPHICS_SWITCHING - (optional) (cocoa) use automatic graphics switching (allow the system to choose to use GPU or iGPU)
62 #define RGFW_COCOA_FRAME_NAME (optional) (cocoa) set frame name
63 #define RGFW_NO_DPI - do not calculate DPI (no XRM nor libShcore included)
64 #define RGFW_BUFFER_BGR - use the BGR format for bufffers instead of RGB, saves processing time
65 #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)
67 #define RGFW_ALLOC x - choose the default allocation function (defaults to standard malloc)
68 #define RGFW_FREE x - choose the default deallocation function (defaults to standard free)
69 #define RGFW_USERPTR x - choose the default userptr sent to the malloc call, (NULL by default)
71 #define RGFW_EXPORT - use when building RGFW
72 #define RGFW_IMPORT - use when linking with RGFW (not as a single-header)
74 #define RGFW_USE_INT - force the use c-types rather than stdint.h (for systems that might not have stdint.h (msvc))
75 #define RGFW_bool x - choose what type to use for bool, by default u32 is used
76*/
78/*
79Example to get you started :
81linux : gcc main.c -lX11 -lXrandr -lGL
82windows : gcc main.c -lopengl32 -lgdi32
83macos : gcc main.c -framework Cocoa -framework CoreVideo -framework OpenGL -framework IOKit
85#define RGFW_IMPLEMENTATION
86#include "RGFW.h"
88u8 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};
90int main() {
91 RGFW_window* win = RGFW_createWindow("name", RGFW_RECT(100, 100, 500, 500), (u64)0);
93 RGFW_window_setIcon(win, icon, RGFW_AREA(3, 3), 4);
95 while (RGFW_window_shouldClose(win) == RGFW_FALSE) {
96 while (RGFW_window_checkEvent(win)) {
97 if (win->event.type == RGFW_quit || RGFW_isPressed(win, RGFW_escape))
98 break;
99 }
101 RGFW_window_swapBuffers(win);
103 glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
104 glClear(GL_COLOR_BUFFER_BIT);
105 }
107 RGFW_window_close(win);
108}
110 compiling :
112 if you wish to compile the library all you have to do is create a new file with this in it
114 rgfw.c
115 #define RGFW_IMPLEMENTATION
116 #include "RGFW.h"
118 You may also want to add
119 `#define RGFW_EXPORT` when compiling and
120 `#define RGFW_IMPORT`when linking RGFW on it's own:
121 this reduces inline functions and prevents bloat in the object file
123 then you can use gcc (or whatever compile you wish to use) to compile the library into object file
125 ex. gcc -c RGFW.c -fPIC
127 after you compile the library into an object file, you can also turn the object file into an static or shared library
129 (commands ar and gcc can be replaced with whatever equivalent your system uses)
131 static : ar rcs RGFW.a RGFW.o
132 shared :
133 windows:
134 gcc -shared RGFW.o -lopengl32 -lgdi32 -o RGFW.dll
135 linux:
136 gcc -shared RGFW.o -lX11 -lGL -lXrandr -o RGFW.so
137 macos:
138 gcc -shared RGFW.o -framework CoreVideo -framework Cocoa -framework OpenGL -framework IOKit
139*/
143/*
144 Credits :
145 EimaMei/Sacode : Much of the code for creating windows using winapi, Wrote the Silicon library, helped with MacOS Support, siliapp.h -> referencing
147 stb - This project is heavily inspired by the stb single header files
149 GLFW:
150 certain parts of winapi and X11 are very poorly documented,
151 GLFW's source code was referenced and used throughout the project.
153 contributors : (feel free to put yourself here if you contribute)
154 krisvers -> code review
155 EimaMei (SaCode) -> code review
156 Code-Nycticebus -> bug fixes
157 Rob Rohan -> X11 bugs and missing features, MacOS/Cocoa fixing memory issues/bugs
158 AICDG (@THISISAGOODNAME) -> vulkan support (example)
159 @Easymode -> support, testing/debugging, bug fixes and reviews
160 Joshua Rowe (omnisci3nce) - bug fix, review (macOS)
161 @lesleyrs -> bug fix, review (OpenGL)
162 Nick Porcino (meshula) - testing, organization, review (MacOS, examples)
163 @DarekParodia -> code review (X11) (C++)
164*/
166#if _MSC_VER
167 #pragma comment(lib, "gdi32")
168 #pragma comment(lib, "shell32")
169 #pragma comment(lib, "User32")
170 #pragma warning( push )
171 #pragma warning( disable : 4996 4191 4127)
172 #if _MSC_VER < 600
173 #define RGFW_C89
174 #endif
175#else
176 #if defined(__STDC__) && !defined(__STDC_VERSION__)
177 #define RGFW_C89
178 #endif
179#endif
181#ifndef RGFW_USERPTR
182 #define RGFW_USERPTR NULL
183#endif
185#ifndef RGFW_UNUSED
186 #define RGFW_UNUSED(x) (void)(x)
187#endif
189#ifndef RGFW_ROUND
190 #define RGFW_ROUND(x) (i32)((x) >= 0 ? (x) + 0.5f : (x) - 0.5f)
191#endif
193#ifndef RGFW_ALLOC
194 #include <stdlib.h>
195 #define RGFW_ALLOC malloc
196 #define RGFW_FREE free
197#endif
199#ifndef RGFW_ASSERT
200 #include <assert.h>
201 #define RGFW_ASSERT assert
202#endif
204#if !defined(RGFW_MEMCPY) || !defined(RGFW_STRNCMP) || !defined(RGFW_STRNCPY) || !defined(RGFW_MEMSET)
205 #include <string.h>
206#endif
208#ifndef RGFW_MEMSET
209 #define RGFW_MEMSET(ptr, value, num) memset(ptr, value, num)
210#endif
212#ifndef RGFW_MEMCPY
213 #define RGFW_MEMCPY(dist, src, len) memcpy(dist, src, len)
214#endif
216#ifndef RGFW_STRNCMP
217 #define RGFW_STRNCMP(s1, s2, max) strncmp(s1, s2, max)
218#endif
220#ifndef RGFW_STRNCPY
221 #define RGFW_STRNCPY(dist, src, len) strncpy(dist, src, len)
222#endif
224#ifndef RGFW_STRSTR
225 #define RGFW_STRSTR(str, substr) strstr(str, substr)
226#endif
228#ifndef RGFW_STRTOL
229 /* required for X11 XDnD and X11 Monitor DPI */
230 #include <stdlib.h>
231 #define RGFW_STRTOL(str, endptr, base) strtol(str, endptr, base)
232 #define RGFW_ATOF(num) atof(num)
233#endif
235#ifdef RGFW_WIN95 /* for windows 95 testing (not that it really works) */
236 #define RGFW_NO_MONITOR
237 #define RGFW_NO_PASSTHROUGH
238#endif
240#if defined(RGFW_EXPORT) || defined(RGFW_IMPORT)
241 #if defined(_WIN32)
242 #if defined(__TINYC__) && (defined(RGFW_EXPORT) || defined(RGFW_IMPORT))
243 #define __declspec(x) __attribute__((x))
244 #endif
246 #if defined(RGFW_EXPORT)
247 #define RGFWDEF __declspec(dllexport)
248 #else
249 #define RGFWDEF __declspec(dllimport)
250 #endif
251 #else
252 #if defined(RGFW_EXPORT)
253 #define RGFWDEF __attribute__((visibility("default")))
254 #endif
255 #endif
256 #ifndef RGFWDEF
257 #define RGFWDEF
258 #endif
259#endif
261#ifndef RGFWDEF
262 #ifdef RGFW_C89
263 #define RGFWDEF __inline
264 #else
265 #define RGFWDEF inline
266 #endif
267#endif
269#ifndef RGFW_ENUM
270 #define RGFW_ENUM(type, name) type name; enum
271#endif
274#if defined(__cplusplus) && !defined(__EMSCRIPTEN__)
275 extern "C" {
276#endif
278 /* makes sure the header file part is only defined once by default */
279#ifndef RGFW_HEADER
281#define RGFW_HEADER
283#include <stddef.h>
284#ifndef RGFW_INT_DEFINED
285 #ifdef RGFW_USE_INT /* optional for any system that might not have stdint.h */
286 typedef unsigned char u8;
287 typedef signed char i8;
288 typedef unsigned short u16;
289 typedef signed short i16;
290 typedef unsigned long int u32;
291 typedef signed long int i32;
292 typedef unsigned long long u64;
293 typedef signed long long i64;
294 #else /* use stdint standard types instead of c "standard" types */
295 #include <stdint.h>
297 typedef uint8_t u8;
298 typedef int8_t i8;
299 typedef uint16_t u16;
300 typedef int16_t i16;
301 typedef uint32_t u32;
302 typedef int32_t i32;
303 typedef uint64_t u64;
304 typedef int64_t i64;
305 #endif
306 #define RGFW_INT_DEFINED
307#endif
309#ifndef RGFW_BOOL_DEFINED
310 #define RGFW_BOOL_DEFINED
311 typedef u8 RGFW_bool;
312#endif
314#define RGFW_BOOL(x) (RGFW_bool)((x) ? RGFW_TRUE : RGFW_FALSE) /* force an value to be 0 or 1 */
315#define RGFW_TRUE (RGFW_bool)1
316#define RGFW_FALSE (RGFW_bool)0
318/* these OS macros look better & are standardized */
319/* plus it helps with cross-compiling */
321#ifdef __EMSCRIPTEN__
322 #define RGFW_WASM
324 #if !defined(RGFW_NO_API) && !defined(RGFW_WEBGPU)
325 #define RGFW_OPENGL
326 #endif
328 #ifdef RGFW_EGL
329 #undef RGFW_EGL
330 #endif
332 #include <emscripten/html5.h>
333 #include <emscripten/key_codes.h>
335 #ifdef RGFW_WEBGPU
336 #include <emscripten/html5_webgpu.h>
337 #endif
338#endif
340#if defined(RGFW_X11) && defined(__APPLE__) && !defined(RGFW_CUSTOM_BACKEND)
341 #define RGFW_MACOS_X11
342 #define RGFW_UNIX
343 #undef __APPLE__
344#endif
346#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) */
347 #define RGFW_WINDOWS
348 /* make sure the correct architecture is defined */
349 #if defined(_WIN64)
350 #define _AMD64_
351 #undef _X86_
352 #else
353 #undef _AMD64_
354 #ifndef _X86_
355 #define _X86_
356 #endif
357 #endif
359 #ifndef RGFW_NO_XINPUT
360 #ifdef __MINGW32__ /* try to find the right header */
361 #include <xinput.h>
362 #else
363 #include <XInput.h>
364 #endif
365 #endif
366#endif
367#if defined(RGFW_WAYLAND)
368 #define RGFW_DEBUG /* wayland will be in debug mode by default for now */
369 #if !defined(RGFW_NO_API) && (!defined(RGFW_BUFFER) || defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA)
370 #define RGFW_EGL
371 #define RGFW_OPENGL
372 #include <wayland-egl.h>
373 #endif
375 #define RGFW_UNIX
376 #include <wayland-client.h>
377#endif
378#if !defined(RGFW_NO_X11) && (defined(__unix__) || defined(RGFW_MACOS_X11) || defined(RGFW_X11)) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND)
379 #define RGFW_MACOS_X11
380 #define RGFW_X11
381 #define RGFW_UNIX
382 #include <X11/Xlib.h>
383 #include <X11/Xutil.h>
384#elif defined(__APPLE__) && !defined(RGFW_MACOS_X11) && !defined(RGFW_X11) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND)
385 #define RGFW_MACOS
386 #if !defined(RGFW_BUFFER_BGR)
387 #define RGFW_BUFFER_BGR
388 #else
389 #undef RGFW_BUFFER_BGR
390 #endif
391#endif
393#if (defined(RGFW_OPENGL_ES1) || defined(RGFW_OPENGL_ES2) || defined(RGFW_OPENGL_ES3)) && !defined(RGFW_EGL)
394 #define RGFW_EGL
395#endif
397#if !defined(RGFW_OSMESA) && !defined(RGFW_EGL) && !defined(RGFW_OPENGL) && !defined(RGFW_DIRECTX) && !defined(RGFW_BUFFER) && !defined(RGFW_NO_API)
398 #define RGFW_OPENGL
399#endif
401#ifdef RGFW_EGL
402 #include <EGL/egl.h>
403#elif defined(RGFW_OSMESA)
404 #ifdef RGFW_WINDOWS
405 #define OEMRESOURCE
406 #include <GL/gl.h>
407 #ifndef GLAPIENTRY
408 #define GLAPIENTRY APIENTRY
409 #endif
410 #ifndef GLAPI
411 #define GLAPI WINGDIAPI
412 #endif
413 #endif
415 #ifndef __APPLE__
416 #include <GL/osmesa.h>
417 #else
418 #include <OpenGL/osmesa.h>
419 #endif
420#endif
422#if (defined(RGFW_OPENGL) || defined(RGFW_WEGL)) && defined(_MSC_VER)
423 #pragma comment(lib, "opengl32")
424#endif
426#if defined(RGFW_OPENGL) && defined(RGFW_X11)
427 #ifndef GLX_MESA_swap_control
428 #define GLX_MESA_swap_control
429 #endif
430 #include <GL/glx.h> /* GLX defs, xlib.h, gl.h */
431#endif
433#define RGFW_COCOA_FRAME_NAME NULL
435/*! (unix) Toggle use of wayland. This will be on by default if you use `RGFW_WAYLAND` (if you don't use RGFW_WAYLAND, you don't expose WAYLAND functions)
436 this is mostly used to allow you to force the use of XWayland
437*/
438RGFWDEF void RGFW_useWayland(RGFW_bool wayland);
439RGFWDEF RGFW_bool RGFW_usingWayland(void);
440/*
441 regular RGFW stuff
442*/
444#define RGFW_key u8
446typedef RGFW_ENUM(u8, RGFW_eventType) {
447 /*! event codes */
448 RGFW_eventNone = 0, /*!< no event has been sent */
449 RGFW_keyPressed, /* a key has been pressed */
450 RGFW_keyReleased, /*!< a key has been released */
451 /*! key event note
452 the code of the key pressed is stored in
453 RGFW_event.key
454 !!Keycodes defined at the bottom of the RGFW_HEADER part of this file!!
456 while a string version is stored in
457 RGFW_event.KeyString
459 RGFW_event.keyMod holds the current keyMod
460 this means if CapsLock, NumLock are active or not
461 */
462 RGFW_mouseButtonPressed, /*!< a mouse button has been pressed (left,middle,right) */
463 RGFW_mouseButtonReleased, /*!< a mouse button has been released (left,middle,right) */
464 RGFW_mousePosChanged, /*!< the position of the mouse has been changed */
465 /*! mouse event note
466 the x and y of the mouse can be found in the vector, RGFW_event.point
468 RGFW_event.button holds which mouse button was pressed
469 */
470 RGFW_gamepadConnected, /*!< a gamepad was connected */
471 RGFW_gamepadDisconnected, /*!< a gamepad was disconnected */
472 RGFW_gamepadButtonPressed, /*!< a gamepad button was pressed */
473 RGFW_gamepadButtonReleased, /*!< a gamepad button was released */
474 RGFW_gamepadAxisMove, /*!< an axis of a gamepad was moved */
475 /*! gamepad event note
476 RGFW_event.gamepad holds which gamepad was altered, if any
477 RGFW_event.button holds which gamepad button was pressed
479 RGFW_event.axis holds the data of all the axises
480 RGFW_event.axisesCount says how many axises there are
481 */
482 RGFW_windowMoved, /*!< the window was moved (by the user) */
483 RGFW_windowResized, /*!< the window was resized (by the user), [on WASM this means the browser was resized] */
484 RGFW_focusIn, /*!< window is in focus now */
485 RGFW_focusOut, /*!< window is out of focus now */
486 RGFW_mouseEnter, /* mouse entered the window */
487 RGFW_mouseLeave, /* mouse left the window */
488 RGFW_windowRefresh, /* The window content needs to be refreshed */
490 /* attribs change event note
491 The event data is sent straight to the window structure
492 with win->r.x, win->r.y, win->r.w and win->r.h
493 */
494 RGFW_quit, /*!< the user clicked the quit button */
495 RGFW_DND, /*!< a file has been dropped into the window */
496 RGFW_DNDInit, /*!< the start of a dnd event, when the place where the file drop is known */
497 /* dnd data note
498 The x and y coords of the drop are stored in the vector RGFW_event.point
500 RGFW_event.droppedFilesCount holds how many files were dropped
502 This is also the size of the array which stores all the dropped file string,
503 RGFW_event.droppedFiles
504 */
505 RGFW_windowMaximized, /*!< the window was maximized */
506 RGFW_windowMinimized, /*!< the window was minimized */
507 RGFW_windowRestored, /*!< the window was restored */
508 RGFW_scaleUpdated /*!< content scale factor changed */
509};
511/*! mouse button codes (RGFW_event.button) */
512typedef RGFW_ENUM(u8, RGFW_mouseButton) {
513 RGFW_mouseLeft = 0, /*!< left mouse button is pressed */
514 RGFW_mouseMiddle, /*!< mouse-wheel-button is pressed */
515 RGFW_mouseRight, /*!< right mouse button is pressed */
516 RGFW_mouseScrollUp, /*!< mouse wheel is scrolling up */
517 RGFW_mouseScrollDown, /*!< mouse wheel is scrolling down */
518 RGFW_mouseMisc1, RGFW_mouseMisc2, RGFW_mouseMisc3, RGFW_mouseMisc4, RGFW_mouseMisc5,
519 RGFW_mouseFinal
520};
522#ifndef RGFW_MAX_PATH
523#define RGFW_MAX_PATH 260 /* max length of a path (for dnd) */
524#endif
525#ifndef RGFW_MAX_DROPS
526#define RGFW_MAX_DROPS 260 /* max items you can drop at once */
527#endif
529#define RGFW_BIT(x) (1 << x)
531/* for RGFW_event.lockstate */
532typedef RGFW_ENUM(u8, RGFW_keymod) {
533 RGFW_modCapsLock = RGFW_BIT(0),
534 RGFW_modNumLock = RGFW_BIT(1),
535 RGFW_modControl = RGFW_BIT(2),
536 RGFW_modAlt = RGFW_BIT(3),
537 RGFW_modShift = RGFW_BIT(4),
538 RGFW_modSuper = RGFW_BIT(5),
539 RGFW_modScrollLock = RGFW_BIT(6)
540};
542/*! gamepad button codes (based on xbox/playstation), you may need to change these values per controller */
543typedef RGFW_ENUM(u8, RGFW_gamepadCodes) {
544 RGFW_gamepadNone = 0, /*!< or PS X button */
545 RGFW_gamepadA, /*!< or PS X button */
546 RGFW_gamepadB, /*!< or PS circle button */
547 RGFW_gamepadY, /*!< or PS triangle button */
548 RGFW_gamepadX, /*!< or PS square button */
549 RGFW_gamepadStart, /*!< start button */
550 RGFW_gamepadSelect, /*!< select button */
551 RGFW_gamepadHome, /*!< home button */
552 RGFW_gamepadUp, /*!< dpad up */
553 RGFW_gamepadDown, /*!< dpad down */
554 RGFW_gamepadLeft, /*!< dpad left */
555 RGFW_gamepadRight, /*!< dpad right */
556 RGFW_gamepadL1, /*!< left bump */
557 RGFW_gamepadL2, /*!< left trigger */
558 RGFW_gamepadR1, /*!< right bumper */
559 RGFW_gamepadR2, /*!< right trigger */
560 RGFW_gamepadL3, /* left thumb stick */
561 RGFW_gamepadR3, /*!< right thumb stick */
562 RGFW_gamepadFinal
563};
565/*! basic vector type, if there's not already a point/vector type of choice */
566#ifndef RGFW_point
567 typedef struct RGFW_point { i32 x, y; } RGFW_point;
568#endif
570/*! basic rect type, if there's not already a rect type of choice */
571#ifndef RGFW_rect
572 typedef struct RGFW_rect { i32 x, y, w, h; } RGFW_rect;
573#endif
575/*! basic area type, if there's not already a area type of choice */
576#ifndef RGFW_area
577 typedef struct RGFW_area { u32 w, h; } RGFW_area;
578#endif
580#if defined(__cplusplus) && !defined(__APPLE__)
581#define RGFW_POINT(x, y) {(i32)x, (i32)y}
582#define RGFW_RECT(x, y, w, h) {(i32)x, (i32)y, (i32)w, (i32)h}
583#define RGFW_AREA(w, h) {(u32)w, (u32)h}
584#else
585#define RGFW_POINT(x, y) (RGFW_point){(i32)(x), (i32)(y)}
586#define RGFW_RECT(x, y, w, h) (RGFW_rect){(i32)(x), (i32)(y), (i32)(w), (i32)(h)}
587#define RGFW_AREA(w, h) (RGFW_area){(u32)(w), (u32)(h)}
588#endif
590#ifndef RGFW_NO_MONITOR
591 /* monitor mode data | can be changed by the user (with functions)*/
592 typedef struct RGFW_monitorMode {
593 RGFW_area area; /*!< monitor workarea size */
594 u32 refreshRate; /*!< monitor refresh rate */
595 u8 red, blue, green;
596 } RGFW_monitorMode;
598 /*! structure for monitor data */
599 typedef struct RGFW_monitor {
600 i32 x, y; /*!< x - y of the monitor workarea */
601 char name[128]; /*!< monitor name */
602 float scaleX, scaleY; /*!< monitor content scale */
603 float pixelRatio; /*!< pixel ratio for monitor (1.0 for regular, 2.0 for hiDPI) */
604 float physW, physH; /*!< monitor physical size in inches */
606 RGFW_monitorMode mode;
607 } RGFW_monitor;
609 /*! get an array of all the monitors (max 6) */
610 RGFWDEF RGFW_monitor* RGFW_getMonitors(size_t* len);
611 /*! get the primary monitor */
612 RGFWDEF RGFW_monitor RGFW_getPrimaryMonitor(void);
614 typedef RGFW_ENUM(u8, RGFW_modeRequest) {
615 RGFW_monitorScale = RGFW_BIT(0), /*!< scale the monitor size */
616 RGFW_monitorRefresh = RGFW_BIT(1), /*!< change the refresh rate */
617 RGFW_monitorRGB = RGFW_BIT(2), /*!< change the monitor RGB bits size */
618 RGFW_monitorAll = RGFW_monitorScale | RGFW_monitorRefresh | RGFW_monitorRGB
619 };
621 /*! request a specific mode */
622 RGFWDEF RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request);
623 /*! check if 2 monitor modes are the same */
624 RGFWDEF RGFW_bool RGFW_monitorModeCompare(RGFW_monitorMode mon, RGFW_monitorMode mon2, RGFW_modeRequest request);
625#endif
627/* RGFW mouse loading */
628typedef void RGFW_mouse;
630/*!< loads mouse icon from bitmap (similar to RGFW_window_setIcon). Icon NOT resized by default */
631RGFWDEF RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels);
632/*!< frees RGFW_mouse data */
633RGFWDEF void RGFW_freeMouse(RGFW_mouse* mouse);
635/* NOTE: some parts of the data can represent different things based on the event (read comments in RGFW_event struct) */
636/*! Event structure for checking/getting events */
637typedef struct RGFW_event {
638 RGFW_eventType type; /*!< which event has been sent?*/
639 RGFW_point point; /*!< mouse x, y of event (or drop point) */
640 RGFW_point vector; /*!< raw mouse movement */
641 float scaleX, scaleY; /*!< DPI scaling */
643 RGFW_key key; /*!< the physical key of the event, refers to where key is physically !!Keycodes defined at the bottom of the RGFW_HEADER part of this file!! */
644 u8 keyChar; /*!< mapped key char of the event */
646 RGFW_bool repeat; /*!< key press event repeated (the key is being held) */
647 RGFW_keymod keyMod;
649 u8 button; /* !< which mouse (or gamepad) button was pressed */
650 double scroll; /*!< the raw mouse scroll value */
652 u16 gamepad; /*! which gamepad this event applies to (if applicable to any) */
653 u8 axisesCount; /*!< number of axises */
655 u8 whichAxis; /* which axis was effected */
656 RGFW_point axis[4]; /*!< x, y of axises (-100 to 100) */
658 /*! drag and drop data */
659 /* 260 max paths with a max length of 260 */
660 char** droppedFiles; /*!< dropped files */
661 size_t droppedFilesCount; /*!< house many files were dropped */
663 void* _win; /*!< the window this event applies too (for event queue events) */
664} RGFW_event;
666/*! source data for the window (used by the APIs) */
667#ifdef RGFW_WINDOWS
668typedef struct RGFW_window_src {
669 HWND window; /*!< source window */
670 HDC hdc; /*!< source HDC */
671 u32 hOffset; /*!< height offset for window */
672 HICON hIconSmall, hIconBig; /*!< source window icons */
673 #if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL)
674 HGLRC ctx; /*!< source graphics context */
675 #elif defined(RGFW_OSMESA)
676 OSMesaContext ctx;
677 #elif defined(RGFW_EGL)
678 EGLSurface EGL_surface;
679 EGLDisplay EGL_display;
680 EGLContext EGL_context;
681 #endif
683 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
684 HDC hdcMem;
685 HBITMAP bitmap;
686 u8* bitmapBits;
687 #endif
688 RGFW_area maxSize, minSize, aspectRatio; /*!< for setting max/min resize (RGFW_WINDOWS) */
689} RGFW_window_src;
690#elif defined(RGFW_UNIX)
691typedef struct RGFW_window_src {
692#if defined(RGFW_X11)
693 Display* display; /*!< source display */
694 Window window; /*!< source window */
695 #if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL)
696 GLXContext ctx; /*!< source graphics context */
697 GLXFBConfig bestFbc;
698 #elif defined(RGFW_OSMESA)
699 OSMesaContext ctx;
700 #elif defined(RGFW_EGL)
701 EGLSurface EGL_surface;
702 EGLDisplay EGL_display;
703 EGLContext EGL_context;
704 #endif
706 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
707 XImage* bitmap;
708 #endif
709 GC gc;
710 XVisualInfo visual;
711 #ifdef RGFW_ADVANCED_SMOOTH_RESIZE
712 i64 counter_value;
713 XID counter;
714 #endif
715 RGFW_rect r;
716#endif /* RGFW_X11 */
717#if defined(RGFW_WAYLAND)
718 struct wl_display* wl_display;
719 struct wl_surface* surface;
720 struct wl_buffer* wl_buffer;
721 struct wl_keyboard* keyboard;
723 struct wl_compositor* compositor;
724 struct xdg_surface* xdg_surface;
725 struct xdg_toplevel* xdg_toplevel;
726 struct zxdg_toplevel_decoration_v1* decoration;
727 struct xdg_wm_base* xdg_wm_base;
728 struct wl_shm* shm;
729 struct wl_seat *seat;
730 u8* buffer;
731 #if defined(RGFW_EGL)
732 struct wl_egl_window* eglWindow;
733 #endif
734 #if defined(RGFW_EGL) && !defined(RGFW_X11)
735 EGLSurface EGL_surface;
736 EGLDisplay EGL_display;
737 EGLContext EGL_context;
738 #elif defined(RGFW_OSMESA) && !defined(RGFW_X11)
739 OSMesaContext ctx;
740 #endif
741#endif /* RGFW_WAYLAND */
742} RGFW_window_src;
743#endif /* RGFW_UNIX */
744#if defined(RGFW_MACOS)
745typedef struct RGFW_window_src {
746 void* window;
747#if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL)
748 void* ctx; /*!< source graphics context */
749#elif defined(RGFW_OSMESA)
750 OSMesaContext ctx;
751#elif defined(RGFW_EGL)
752 EGLSurface EGL_surface;
753 EGLDisplay EGL_display;
754 EGLContext EGL_context;
755#endif
757 void* view; /* apple viewpoint thingy */
758 void* mouse;
759#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
760#endif
761} RGFW_window_src;
762#elif defined(RGFW_WASM)
763typedef struct RGFW_window_src {
764 #if defined(RGFW_WEBGPU)
765 WGPUInstance ctx;
766 WGPUDevice device;
767 WGPUQueue queue;
768 #elif defined(RGFW_OSMESA)
769 OSMesaContext ctx;
770 #else
771 EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx;
772 #endif
773} RGFW_window_src;
774#endif
776/*! Optional arguments for making a windows */
777typedef RGFW_ENUM(u32, RGFW_windowFlags) {
778 RGFW_windowNoInitAPI = RGFW_BIT(0), /* do NOT init an API (including the software rendering buffer) (mostly for bindings. you can also use `#define RGFW_NO_API`) */
779 RGFW_windowNoBorder = RGFW_BIT(1), /*!< the window doesn't have a border */
780 RGFW_windowNoResize = RGFW_BIT(2), /*!< the window cannot be resized by the user */
781 RGFW_windowAllowDND = RGFW_BIT(3), /*!< the window supports drag and drop */
782 RGFW_windowHideMouse = RGFW_BIT(4), /*! the window should hide the mouse (can be toggled later on using `RGFW_window_mouseShow`) */
783 RGFW_windowFullscreen = RGFW_BIT(5), /*!< the window is fullscreen by default */
784 RGFW_windowTransparent = RGFW_BIT(6), /*!< the window is transparent (only properly works on X11 and MacOS, although it's meant for for windows) */
785 RGFW_windowCenter = RGFW_BIT(7), /*! center the window on the screen */
786 RGFW_windowOpenglSoftware = RGFW_BIT(8), /*! use OpenGL software rendering */
787 RGFW_windowCocoaCHDirToRes = RGFW_BIT(9), /*! (cocoa only), change directory to resource folder */
788 RGFW_windowScaleToMonitor = RGFW_BIT(10), /*! scale the window to the screen */
789 RGFW_windowHide = RGFW_BIT(11), /*! the window is hidden */
790 RGFW_windowMaximize = RGFW_BIT(12),
791 RGFW_windowCenterCursor = RGFW_BIT(13),
792 RGFW_windowFloating = RGFW_BIT(14), /*!< create a floating window */
793 RGFW_windowFreeOnClose = RGFW_BIT(15), /*!< free (RGFW_window_close) the RGFW_window struct when the window is closed (by the end user) */
794 RGFW_windowFocusOnShow = RGFW_BIT(16), /*!< focus the window when it's shown */
795 RGFW_windowMinimize = RGFW_BIT(17), /*!< focus the window when it's shown */
796 RGFW_windowFocus = RGFW_BIT(18), /*!< if the window is in focus */
797 RGFW_windowedFullscreen = RGFW_windowNoBorder | RGFW_windowMaximize
798};
800typedef struct RGFW_window {
801 RGFW_window_src src; /*!< src window data */
803#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
804 u8* buffer; /*!< buffer for non-GPU systems (OSMesa, basic software rendering) */
805 /* when rendering using RGFW_BUFFER, the buffer is in the RGBA format */
806 RGFW_area bufferSize;
807#endif
808 void* userPtr; /* ptr for usr data */
810 RGFW_event event; /*!< current event */
812 RGFW_rect r; /*!< the x, y, w and h of the struct */
814 /*! which key RGFW_window_shouldClose checks. Settting this to RGFW_keyNULL disables the feature. */
815 RGFW_key exitKey;
816 RGFW_point _lastMousePoint; /*!< last cusor point (for raw mouse data) */
818 u32 _flags; /*!< windows flags (for RGFW to check) */
819 RGFW_rect _oldRect; /*!< rect before fullscreen */
820} RGFW_window; /*!< window structure for managing the window */
822#if defined(RGFW_X11) || defined(RGFW_MACOS)
823 typedef u64 RGFW_thread; /*!< thread type unix */
824#else
825 typedef void* RGFW_thread; /*!< thread type for windows */
826#endif
828/*! scale monitor to window size */
829RGFWDEF RGFW_bool RGFW_monitor_scaleToWindow(RGFW_monitor mon, RGFW_window* win);
831/** * @defgroup Window_management
832* @{ */
835/*!
836 * the class name for X11 and WinAPI. apps with the same class will be grouped by the WM
837 * by default the class name will == the root window's name
838*/
839RGFWDEF void RGFW_setClassName(const char* name);
840RGFWDEF void RGFW_setXInstName(const char* name); /*!< X11 instance name (window name will by used by default) */
842/*! (cocoa only) change directory to resource folder */
843RGFWDEF void RGFW_moveToMacOSResourceDir(void);
845/* NOTE: (windows) if the executable has an icon resource named RGFW_ICON, it will be set as the initial icon for the window */
847RGFWDEF RGFW_window* RGFW_createWindow(
848 const char* name, /* name of the window */
849 RGFW_rect rect, /* rect of window */
850 RGFW_windowFlags flags /* extra arguments ((u32)0 means no flags used)*/
851); /*!< function to create a window and struct */
853RGFWDEF RGFW_window* RGFW_createWindowPtr(
854 const char* name, /* name of the window */
855 RGFW_rect rect, /* rect of window */
856 RGFW_windowFlags flags, /* extra arguments (NULL / (u32)0 means no flags used) */
857 RGFW_window* win /* ptr to the window struct you want to use */
858); /*!< function to create a window (without allocating a window struct) */
860RGFWDEF void RGFW_window_initBuffer(RGFW_window* win);
861RGFWDEF void RGFW_window_initBufferSize(RGFW_window* win, RGFW_area area);
862RGFWDEF void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area);
864/*! set the window flags (will undo flags if they don't match the old ones) */
865RGFWDEF void RGFW_window_setFlags(RGFW_window* win, RGFW_windowFlags);
867/*! get the size of the screen to an area struct */
868RGFWDEF RGFW_area RGFW_getScreenSize(void);
871/*!
872 this function checks an *individual* event (and updates window structure attributes)
873 this means, using this function without a while loop may cause event lag
875 ex.
877 while (RGFW_window_checkEvent(win) != NULL) [this keeps checking events until it reaches the last one]
879 this function is optional if you choose to use event callbacks,
880 although you still need some way to tell RGFW to process events eg. `RGFW_window_checkEvents`
881*/
883RGFWDEF RGFW_event* RGFW_window_checkEvent(RGFW_window* win); /*!< check current event (returns a pointer to win->event or NULL if there is no event)*/
885/*!
886 for RGFW_window_eventWait and RGFW_window_checkEvents
887 waitMS -> Allows the function to keep checking for events even after `RGFW_window_checkEvent == NULL`
888 if waitMS == 0, the loop will not wait for events
889 if waitMS > 0, the loop will wait that many miliseconds after there are no more events until it returns
890 if waitMS == -1 or waitMS == the max size of an unsigned 32-bit int, the loop will not return until it gets another event
891*/
892typedef RGFW_ENUM(i32, RGFW_eventWait) {
893 RGFW_eventNoWait = 0,
894 RGFW_eventWaitNext = -1
895};
897/*! sleep until RGFW gets an event or the timer ends (defined by OS) */
898RGFWDEF void RGFW_window_eventWait(RGFW_window* win, i32 waitMS);
900/*!
901 check all the events until there are none left.
902 This should only be used if you're using callbacks only
903*/
904RGFWDEF void RGFW_window_checkEvents(RGFW_window* win, i32 waitMS);
906/*!
907 tell RGFW_window_eventWait to stop waiting (to be ran from another thread)
908*/
909RGFWDEF void RGFW_stopCheckEvents(void);
911/*! window managment functions */
912RGFWDEF void RGFW_window_close(RGFW_window* win); /*!< close the window and free leftover data */
914/*! move a window to a given point */
915RGFWDEF void RGFW_window_move(RGFW_window* win,
916 RGFW_point v /*!< new pos */
917);
919#ifndef RGFW_NO_MONITOR
920 /*! move window to a specific monitor */
921 RGFWDEF void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m /* monitor */);
922#endif
924/*! resize window to a current size/area */
925RGFWDEF void RGFW_window_resize(RGFW_window* win, /*!< source window */
926 RGFW_area a /*!< new size */
927);
929/*! set window aspect ratio */
930RGFWDEF void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a);
931/*! set the minimum dimensions of a window */
932RGFWDEF void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a);
933/*! set the maximum dimensions of a window */
934RGFWDEF void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a);
936RGFWDEF void RGFW_window_focus(RGFW_window* win); /*!< sets the focus to this window */
937RGFWDEF RGFW_bool RGFW_window_isInFocus(RGFW_window* win); /*!< checks the focus to this window */
938RGFWDEF void RGFW_window_raise(RGFW_window* win); /*!< raise the window (to the top) */
939RGFWDEF void RGFW_window_maximize(RGFW_window* win); /*!< maximize the window */
940RGFWDEF void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen); /*!< turn fullscreen on / off for a window */
941RGFWDEF void RGFW_window_center(RGFW_window* win); /*!< center the window */
942RGFWDEF void RGFW_window_minimize(RGFW_window* win); /*!< minimize the window (in taskbar (per OS))*/
943RGFWDEF void RGFW_window_restore(RGFW_window* win); /*!< restore the window from minimized (per OS)*/
944RGFWDEF void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating); /*!< make the window a floating window */
945RGFWDEF void RGFW_window_setOpacity(RGFW_window* win, u8 opacity); /*!< sets the opacity of a window */
947RGFWDEF RGFW_bool RGFW_window_opengl_isSoftware(RGFW_window* win);
949/*! if the window should have a border or not (borderless) based on bool value of `border` */
950RGFWDEF void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border);
951RGFWDEF RGFW_bool RGFW_window_borderless(RGFW_window* win);
953/*! turn on / off dnd (RGFW_windowAllowDND stil must be passed to the window)*/
954RGFWDEF void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow);
955/*! check if DND is allowed */
956RGFWDEF RGFW_bool RGFW_window_allowsDND(RGFW_window* win);
959#ifndef RGFW_NO_PASSTHROUGH
960 /*! turn on / off mouse passthrough */
961 RGFWDEF void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough);
962#endif
964/*! rename window to a given string */
965RGFWDEF void RGFW_window_setName(RGFW_window* win,
966 const char* name
967);
969RGFWDEF RGFW_bool RGFW_window_setIcon(RGFW_window* win, /*!< source window */
970 u8* icon /*!< icon bitmap */,
971 RGFW_area a /*!< width and height of the bitmap */,
972 i32 channels /*!< how many channels the bitmap has (rgb : 3, rgba : 4) */
973); /*!< image MAY be resized by default, set both the taskbar and window icon */
975typedef RGFW_ENUM(u8, RGFW_icon) {
976 RGFW_iconTaskbar = RGFW_BIT(0),
977 RGFW_iconWindow = RGFW_BIT(1),
978 RGFW_iconBoth = RGFW_iconTaskbar | RGFW_iconWindow
979};
980RGFWDEF RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* icon, RGFW_area a, i32 channels, u8 type);
982/*!< sets mouse to RGFW_mouse icon (loaded from a bitmap struct) */
983RGFWDEF void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse);
985/*!< sets the mouse to a standard API cursor (based on RGFW_MOUSE, as seen at the end of the RGFW_HEADER part of this file) */
986RGFWDEF RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse);
988RGFWDEF RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win); /*!< sets the mouse to the default mouse icon */
989/*
990 Locks cursor at the center of the window
991 win->event.point becomes raw mouse movement data
993 this is useful for a 3D camera
994*/
995RGFWDEF void RGFW_window_mouseHold(RGFW_window* win, RGFW_area area);
996/*! if the mouse is held by RGFW */
997RGFWDEF RGFW_bool RGFW_window_mouseHeld(RGFW_window* win);
998/*! stop holding the mouse and let it move freely */
999RGFWDEF void RGFW_window_mouseUnhold(RGFW_window* win);
1001/*! hide the window */
1002RGFWDEF void RGFW_window_hide(RGFW_window* win);
1003/*! show the window */
1004RGFWDEF void RGFW_window_show(RGFW_window* win);
1006/*
1007 makes it so `RGFW_window_shouldClose` returns true or overrides a window close
1008 by modifying window flags
1009*/
1010RGFWDEF void RGFW_window_setShouldClose(RGFW_window* win, RGFW_bool shouldClose);
1012/*! where the mouse is on the screen */
1013RGFWDEF RGFW_point RGFW_getGlobalMousePoint(void);
1015/*! where the mouse is on the window */
1016RGFWDEF RGFW_point RGFW_window_getMousePoint(RGFW_window* win);
1018/*! show the mouse or hide the mouse */
1019RGFWDEF void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show);
1020/*! if the mouse is hidden */
1021RGFWDEF RGFW_bool RGFW_window_mouseHidden(RGFW_window* win);
1022/*! move the mouse to a given point */
1023RGFWDEF void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v);
1025/*! if the window should close (RGFW_close was sent or escape was pressed) */
1026RGFWDEF RGFW_bool RGFW_window_shouldClose(RGFW_window* win);
1027/*! if the window is fullscreen */
1028RGFWDEF RGFW_bool RGFW_window_isFullscreen(RGFW_window* win);
1029/*! if the window is hidden */
1030RGFWDEF RGFW_bool RGFW_window_isHidden(RGFW_window* win);
1031/*! if the window is minimized */
1032RGFWDEF RGFW_bool RGFW_window_isMinimized(RGFW_window* win);
1033/*! if the window is maximized */
1034RGFWDEF RGFW_bool RGFW_window_isMaximized(RGFW_window* win);
1035/*! if the window is floating */
1036RGFWDEF RGFW_bool RGFW_window_isFloating(RGFW_window* win);
1037/** @} */
1039/** * @defgroup Monitor
1040* @{ */
1042#ifndef RGFW_NO_MONITOR
1043/*
1044 scale the window to the monitor.
1045 This is run by default if the user uses the arg `RGFW_scaleToMonitor` during window creation
1046*/
1047RGFWDEF void RGFW_window_scaleToMonitor(RGFW_window* win);
1048/*! get the struct of the window's monitor */
1049RGFWDEF RGFW_monitor RGFW_window_getMonitor(RGFW_window* win);
1050#endif
1052/** @} */
1054/** * @defgroup Input
1055* @{ */
1057/*! if window == NULL, it checks if the key is pressed globally. Otherwise, it checks only if the key is pressed while the window in focus. */
1058RGFWDEF RGFW_bool RGFW_isPressed(RGFW_window* win, RGFW_key key); /*!< if key is pressed (key code)*/
1060RGFWDEF RGFW_bool RGFW_wasPressed(RGFW_window* win, RGFW_key key); /*!< if key was pressed (checks previous state only) (key code) */
1062RGFWDEF RGFW_bool RGFW_isHeld(RGFW_window* win, RGFW_key key); /*!< if key is held (key code) */
1063RGFWDEF RGFW_bool RGFW_isReleased(RGFW_window* win, RGFW_key key); /*!< if key is released (key code) */
1065/* if a key is pressed and then released, pretty much the same as RGFW_isReleased */
1066RGFWDEF RGFW_bool RGFW_isClicked(RGFW_window* win, RGFW_key key /*!< key code */);
1068/*! if a mouse button is pressed */
1069RGFWDEF RGFW_bool RGFW_isMousePressed(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ );
1070/*! if a mouse button is held */
1071RGFWDEF RGFW_bool RGFW_isMouseHeld(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ );
1072/*! if a mouse button was released */
1073RGFWDEF RGFW_bool RGFW_isMouseReleased(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ );
1074/*! if a mouse button was pressed (checks previous state only) */
1075RGFWDEF RGFW_bool RGFW_wasMousePressed(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ );
1076/** @} */
1078/** * @defgroup Clipboard
1079* @{ */
1080typedef ptrdiff_t RGFW_ssize_t;
1082RGFWDEF const char* RGFW_readClipboard(size_t* size); /*!< read clipboard data */
1083/*! read clipboard data or send a NULL str to just get the length of the clipboard data */
1084RGFWDEF RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity);
1085RGFWDEF void RGFW_writeClipboard(const char* text, u32 textLen); /*!< write text to the clipboard */
1086/** @} */
1090/** * @defgroup error handling
1091* @{ */
1092typedef RGFW_ENUM(u8, RGFW_debugType) {
1093 RGFW_typeError = 0, RGFW_typeWarning, RGFW_typeInfo
1094};
1096typedef RGFW_ENUM(u8, RGFW_errorCode) {
1097 RGFW_noError = 0, /*!< no error */
1098 RGFW_errOpenglContext, RGFW_errEGLContext, /*!< error with the OpenGL context */
1099 RGFW_errWayland,
1100 RGFW_errDirectXContext,
1101 RGFW_errIOKit,
1102 RGFW_errClipboard,
1103 RGFW_errFailedFuncLoad,
1104 RGFW_errBuffer,
1105 RGFW_infoMonitor, RGFW_infoWindow, RGFW_infoBuffer, RGFW_infoGlobal, RGFW_infoOpenGL,
1106 RGFW_warningWayland, RGFW_warningOpenGL
1107};
1109typedef struct RGFW_debugContext { RGFW_window* win; RGFW_monitor* monitor; u32 srcError; } RGFW_debugContext;
1111#if defined(__cplusplus) && !defined(__APPLE__)
1112#define RGFW_DEBUG_CTX(win, err) {win, NULL, err}
1113#define RGFW_DEBUG_CTX_MON(monitor) {_RGFW.root, &monitor, 0}
1114#else
1115#define RGFW_DEBUG_CTX(win, err) (RGFW_debugContext){win, NULL, err}
1116#define RGFW_DEBUG_CTX_MON(monitor) (RGFW_debugContext){_RGFW.root, &monitor, 0}
1117#endif
1119typedef void (* RGFW_debugfunc)(RGFW_debugType type, RGFW_errorCode err, RGFW_debugContext ctx, const char* msg);
1120RGFWDEF RGFW_debugfunc RGFW_setDebugCallback(RGFW_debugfunc func);
1121RGFWDEF void RGFW_sendDebugInfo(RGFW_debugType type, RGFW_errorCode err, RGFW_debugContext ctx, const char* msg);
1122/** @} */
1124/**
1127 event callbacks.
1128 These are completely optional, so you can use the normal
1129 RGFW_checkEvent() method if you prefer that
1131* @defgroup Callbacks
1132* @{
1133*/
1135/*! RGFW_windowMoved, the window and its new rect value */
1136typedef void (* RGFW_windowMovedfunc)(RGFW_window* win, RGFW_rect r);
1137/*! RGFW_windowResized, the window and its new rect value */
1138typedef void (* RGFW_windowResizedfunc)(RGFW_window* win, RGFW_rect r);
1139/*! RGFW_windowRestored, the window and its new rect value */
1140typedef void (* RGFW_windowRestoredfunc)(RGFW_window* win, RGFW_rect r);
1141/*! RGFW_windowMaximized, the window and its new rect value */
1142typedef void (* RGFW_windowMaximizedfunc)(RGFW_window* win, RGFW_rect r);
1143/*! RGFW_windowMinimized, the window and its new rect value */
1144typedef void (* RGFW_windowMinimizedfunc)(RGFW_window* win, RGFW_rect r);
1145/*! RGFW_quit, the window that was closed */
1146typedef void (* RGFW_windowQuitfunc)(RGFW_window* win);
1147/*! RGFW_focusIn / RGFW_focusOut, the window who's focus has changed and if its in focus */
1148typedef void (* RGFW_focusfunc)(RGFW_window* win, RGFW_bool inFocus);
1149/*! RGFW_mouseEnter / RGFW_mouseLeave, the window that changed, the point of the mouse (enter only) and if the mouse has entered */
1150typedef void (* RGFW_mouseNotifyfunc)(RGFW_window* win, RGFW_point point, RGFW_bool status);
1151/*! RGFW_mousePosChanged, the window that the move happened on, and the new point of the mouse */
1152typedef void (* RGFW_mousePosfunc)(RGFW_window* win, RGFW_point point, RGFW_point vector);
1153/*! RGFW_DNDInit, the window, the point of the drop on the windows */
1154typedef void (* RGFW_dndInitfunc)(RGFW_window* win, RGFW_point point);
1155/*! RGFW_windowRefresh, the window that needs to be refreshed */
1156typedef void (* RGFW_windowRefreshfunc)(RGFW_window* win);
1157/*! 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) */
1158typedef void (* RGFW_keyfunc)(RGFW_window* win, u8 key, u8 keyChar, RGFW_keymod keyMod, RGFW_bool pressed);
1159/*! 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) */
1160typedef void (* RGFW_mouseButtonfunc)(RGFW_window* win, RGFW_mouseButton button, double scroll, RGFW_bool pressed);
1161/*! RGFW_gamepadButtonPressed, the window that got the event, the button that was pressed, the scroll value, if it was a press (else it's a release) */
1162typedef void (* RGFW_gamepadButtonfunc)(RGFW_window* win, u16 gamepad, u8 button, RGFW_bool pressed);
1163/*! RGFW_gamepadAxisMove, the window that got the event, the gamepad in question, the axis values and the axis count */
1164typedef void (* RGFW_gamepadAxisfunc)(RGFW_window* win, u16 gamepad, RGFW_point axis[2], u8 axisesCount, u8 whichAxis);
1165/*! RGFW_gamepadConnected / RGFW_gamepadDisconnected, the window that got the event, the gamepad in question, if the controller was connected (else it was disconnected) */
1166typedef void (* RGFW_gamepadfunc)(RGFW_window* win, u16 gamepad, RGFW_bool connected);
1167/*! RGFW_dnd, the window that had the drop, the drop data and the number of files dropped */
1168typedef void (* RGFW_dndfunc)(RGFW_window* win, char** droppedFiles, size_t droppedFilesCount);
1169/*! RGFW_scaleUpdated, the window the event was sent to, content scaleX, content scaleY */
1170typedef void (* RGFW_scaleUpdatedfunc)(RGFW_window* win, float scaleX, float scaleY);
1172/*! set callback for a window move event. Returns previous callback function (if it was set) */
1173RGFWDEF RGFW_windowMovedfunc RGFW_setWindowMovedCallback(RGFW_windowMovedfunc func);
1174/*! set callback for a window resize event. Returns previous callback function (if it was set) */
1175RGFWDEF RGFW_windowResizedfunc RGFW_setWindowResizedCallback(RGFW_windowResizedfunc func);
1176/*! set callback for a window quit event. Returns previous callback function (if it was set) */
1177RGFWDEF RGFW_windowQuitfunc RGFW_setWindowQuitCallback(RGFW_windowQuitfunc func);
1178/*! set callback for a mouse move event. Returns previous callback function (if it was set) */
1179RGFWDEF RGFW_mousePosfunc RGFW_setMousePosCallback(RGFW_mousePosfunc func);
1180/*! set callback for a window refresh event. Returns previous callback function (if it was set) */
1181RGFWDEF RGFW_windowRefreshfunc RGFW_setWindowRefreshCallback(RGFW_windowRefreshfunc func);
1182/*! set callback for a window focus change event. Returns previous callback function (if it was set) */
1183RGFWDEF RGFW_focusfunc RGFW_setFocusCallback(RGFW_focusfunc func);
1184/*! set callback for a mouse notify event. Returns previous callback function (if it was set) */
1185RGFWDEF RGFW_mouseNotifyfunc RGFW_setMouseNotifyCallback(RGFW_mouseNotifyfunc func);
1186/*! set callback for a drop event event. Returns previous callback function (if it was set) */
1187RGFWDEF RGFW_dndfunc RGFW_setDndCallback(RGFW_dndfunc func);
1188/*! set callback for a start of a drop event. Returns previous callback function (if it was set) */
1189RGFWDEF RGFW_dndInitfunc RGFW_setDndInitCallback(RGFW_dndInitfunc func);
1190/*! set callback for a key (press / release) event. Returns previous callback function (if it was set) */
1191RGFWDEF RGFW_keyfunc RGFW_setKeyCallback(RGFW_keyfunc func);
1192/*! set callback for a mouse button (press / release) event. Returns previous callback function (if it was set) */
1193RGFWDEF RGFW_mouseButtonfunc RGFW_setMouseButtonCallback(RGFW_mouseButtonfunc func);
1194/*! set callback for a controller button (press / release) event. Returns previous callback function (if it was set) */
1195RGFWDEF RGFW_gamepadButtonfunc RGFW_setGamepadButtonCallback(RGFW_gamepadButtonfunc func);
1196/*! set callback for a gamepad axis move event. Returns previous callback function (if it was set) */
1197RGFWDEF RGFW_gamepadAxisfunc RGFW_setGamepadAxisCallback(RGFW_gamepadAxisfunc func);
1198/*! set callback for when a controller is connected or disconnected. Returns the previous callback function (if it was set) */
1199RGFWDEF RGFW_gamepadfunc RGFW_setGamepadCallback(RGFW_gamepadfunc func);
1200/*! set call back for when window is maximized. Returns the previous callback function (if it was set) */
1201RGFWDEF RGFW_windowResizedfunc RGFW_setWindowMaximizedCallback(RGFW_windowResizedfunc func);
1202/*! set call back for when window is minimized. Returns the previous callback function (if it was set) */
1203RGFWDEF RGFW_windowResizedfunc RGFW_setWindowMinimizedCallback(RGFW_windowResizedfunc func);
1204/*! set call back for when window is restored. Returns the previous callback function (if it was set) */
1205RGFWDEF RGFW_windowResizedfunc RGFW_setWindowRestoredCallback(RGFW_windowResizedfunc func);
1206/*! set callback for when the DPI changes. Returns previous callback function (if it was set) */
1207RGFWDEF RGFW_scaleUpdatedfunc RGFW_setScaleUpdatedCallback(RGFW_scaleUpdatedfunc func);
1208/** @} */
1210/** * @defgroup Threads
1211* @{ */
1213#ifndef RGFW_NO_THREADS
1214/*! threading functions */
1216/*! NOTE! (for X11/linux) : if you define a window in a thread, it must be run after the original thread's window is created or else there will be a memory error */
1217/*
1218 I'd suggest you use sili's threading functions instead
1219 if you're going to use sili
1220 which is a good idea generally
1221*/
1223#if defined(__unix__) || defined(__APPLE__) || defined(RGFW_WASM) || defined(RGFW_CUSTOM_BACKEND)
1224 typedef void* (* RGFW_threadFunc_ptr)(void*);
1225#else
1226 typedef DWORD (__stdcall *RGFW_threadFunc_ptr) (LPVOID lpThreadParameter);
1227#endif
1229RGFWDEF RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args); /*!< create a thread */
1230RGFWDEF void RGFW_cancelThread(RGFW_thread thread); /*!< cancels a thread */
1231RGFWDEF void RGFW_joinThread(RGFW_thread thread); /*!< join thread to current thread */
1232RGFWDEF void RGFW_setThreadPriority(RGFW_thread thread, u8 priority); /*!< sets the priority priority */
1233#endif
1235/** @} */
1237/** * @defgroup gamepad
1238* @{ */
1240typedef RGFW_ENUM(u8, RGFW_gamepadType) {
1241 RGFW_gamepadMicrosoft = 0, RGFW_gamepadSony, RGFW_gamepadNintendo, RGFW_gamepadLogitech, RGFW_gamepadUnknown
1242};
1244/*! gamepad count starts at 0*/
1245RGFWDEF u32 RGFW_isPressedGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button);
1246RGFWDEF u32 RGFW_isReleasedGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button);
1247RGFWDEF u32 RGFW_isHeldGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button);
1248RGFWDEF u32 RGFW_wasPressedGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button);
1249RGFWDEF RGFW_point RGFW_getGamepadAxis(RGFW_window* win, u16 controller, u16 whichAxis);
1250RGFWDEF const char* RGFW_getGamepadName(RGFW_window* win, u16 controller);
1251RGFWDEF size_t RGFW_getGamepadCount(RGFW_window* win);
1252RGFWDEF RGFW_gamepadType RGFW_getGamepadType(RGFW_window* win, u16 controller);
1254/** @} */
1256/** * @defgroup graphics_API
1257* @{ */
1259/*!< make the window the current opengl drawing context
1261 NOTE:
1262 if you want to switch the graphics context's thread,
1263 you have to run RGFW_window_makeCurrent(NULL); on the old thread
1264 then RGFW_window_makeCurrent(valid_window) on the new thread
1265*/
1266RGFWDEF void RGFW_window_makeCurrent(RGFW_window* win);
1268/*! get current RGFW window graphics context */
1269RGFWDEF RGFW_window* RGFW_getCurrent(void);
1271/* supports openGL, directX, OSMesa, EGL and software rendering */
1272RGFWDEF void RGFW_window_swapBuffers(RGFW_window* win); /*!< swap the rendering buffer */
1273RGFWDEF void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval);
1274/*!< render the software rendering buffer (this is called by RGFW_window_swapInterval) */
1275RGFWDEF void RGFW_window_swapBuffers_software(RGFW_window* win);
1277typedef void (*RGFW_proc)(void); /* function pointer equivalent of void* */
1279/*! native API functions */
1280#if defined(RGFW_OPENGL) || defined(RGFW_EGL)
1281/*!< create an opengl context for the RGFW window, run by createWindow by default (unless the RGFW_windowNoInitAPI is included) */
1282RGFWDEF void RGFW_window_initOpenGL(RGFW_window* win);
1283/*!< called by `RGFW_window_close` by default (unless the RGFW_windowNoInitAPI is set) */
1284RGFWDEF void RGFW_window_freeOpenGL(RGFW_window* win);
1286/*! OpenGL init hints */
1287typedef RGFW_ENUM(u8, RGFW_glHints) {
1288 RGFW_glStencil = 0, /*!< set stencil buffer bit size (8 by default) */
1289 RGFW_glSamples, /*!< set number of sampiling buffers (4 by default) */
1290 RGFW_glStereo, /*!< use GL_STEREO (GL_FALSE by default) */
1291 RGFW_glAuxBuffers, /*!< number of aux buffers (0 by default) */
1292 RGFW_glDoubleBuffer, /*!< request double buffering */
1293 RGFW_glRed, RGFW_glGreen, RGFW_glBlue, RGFW_glAlpha, /*!< set RGBA bit sizes */
1294 RGFW_glDepth,
1295 RGFW_glAccumRed, RGFW_glAccumGreen, RGFW_glAccumBlue,RGFW_glAccumAlpha, /*!< set accumulated RGBA bit sizes */
1296 RGFW_glSRGB, /*!< request sRGA */
1297 RGFW_glRobustness, /*!< request a robust context */
1298 RGFW_glDebug, /*!< request opengl debugging */
1299 RGFW_glNoError, /*!< request no opengl errors */
1300 RGFW_glReleaseBehavior,
1301 RGFW_glProfile,
1302 RGFW_glMajor, RGFW_glMinor,
1303 RGFW_glFinalHint = 32, /*!< the final hint (not for setting) */
1304 RGFW_releaseFlush = 0, RGFW_glReleaseNone, /* RGFW_glReleaseBehavior options */
1305 RGFW_glCore = 0, RGFW_glCompatibility /*!< RGFW_glProfile options */
1306};
1307RGFWDEF void RGFW_setGLHint(RGFW_glHints hint, i32 value);
1308RGFWDEF RGFW_bool RGFW_extensionSupported(const char* extension, size_t len); /*!< check if whether the specified API extension is supported by the current OpenGL or OpenGL ES context */
1309RGFWDEF RGFW_proc RGFW_getProcAddress(const char* procname); /*!< get native opengl proc address */
1310RGFWDEF void RGFW_window_makeCurrent_OpenGL(RGFW_window* win); /*!< to be called by RGFW_window_makeCurrent */
1311RGFWDEF void RGFW_window_swapBuffers_OpenGL(RGFW_window* win); /*!< swap opengl buffer (only) called by RGFW_window_swapInterval */
1312void* RGFW_getCurrent_OpenGL(void); /*!< get the current context (OpenGL backend (GLX) (WGL) (EGL) (cocoa) (webgl))*/
1314RGFWDEF RGFW_bool RGFW_extensionSupportedPlatform(const char* extension, size_t len); /*!< check if whether the specified platform-specific API extension is supported by the current OpenGL or OpenGL ES context */
1315#endif
1316#ifdef RGFW_VULKAN
1317 #if defined(RGFW_WAYLAND) && defined(RGFW_X11)
1318 #define VK_USE_PLATFORM_WAYLAND_KHR
1319 #define VK_USE_PLATFORM_XLIB_KHR
1320 #define RGFW_VK_SURFACE ((RGFW_usingWayland()) ? ("VK_KHR_wayland_surface") : ("VK_KHR_xlib_surface"))
1321 #elif defined(RGFW_WAYLAND)
1322 #define VK_USE_PLATFORM_WAYLAND_KHR
1323 #define VK_USE_PLATFORM_XLIB_KHR
1324 #define RGFW_VK_SURFACE "VK_KHR_wayland_surface"
1325 #elif defined(RGFW_X11)
1326 #define VK_USE_PLATFORM_XLIB_KHR
1327 #define RGFW_VK_SURFACE "VK_KHR_xlib_surface"
1328 #elif defined(RGFW_WINDOWS)
1329 #define VK_USE_PLATFORM_WIN32_KHR
1330 #define OEMRESOURCE
1331 #define RGFW_VK_SURFACE "VK_KHR_win32_surface"
1332 #elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11)
1333 #define VK_USE_PLATFORM_MACOS_MVK
1334 #define RGFW_VK_SURFACE "VK_MVK_macos_surface"
1335 #else
1336 #define RGFW_VK_SURFACE NULL
1337 #endif
1339/* if you don't want to use the above macros */
1340RGFWDEF const char** RGFW_getVKRequiredInstanceExtensions(size_t* count); /*!< gets (static) extension array (and size (which will be 2)) */
1342#include <vulkan/vulkan.h>
1344RGFWDEF VkResult RGFW_window_createVKSurface(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface);
1345RGFWDEF RGFW_bool RGFW_getVKPresentationSupport(VkInstance instance, VkPhysicalDevice physicalDevice, u32 queueFamilyIndex);
1346#endif
1347#ifdef RGFW_DIRECTX
1348#ifndef RGFW_WINDOWS
1349 #undef RGFW_DIRECTX
1350#else
1351 #define OEMRESOURCE
1352 #include <dxgi.h>
1354 #ifndef __cplusplus
1355 #define __uuidof(T) IID_##T
1356 #endif
1357RGFWDEF int RGFW_window_createDXSwapChain(RGFW_window* win, IDXGIFactory* pFactory, IUnknown* pDevice, IDXGISwapChain** swapchain);
1358#endif
1359#endif
1361/** @} */
1363/** * @defgroup Supporting
1364* @{ */
1366/*! optional init/deinit function */
1367RGFWDEF i32 RGFW_init(void); /*!< is called by default when the first window is created by default */
1368RGFWDEF void RGFW_deinit(void); /*!< is called by default when the last open window is closed */
1370RGFWDEF double RGFW_getTime(void); /*!< get time in seconds since RGFW_setTime, which ran when the first window is open */
1371RGFWDEF u64 RGFW_getTimeNS(void); /*!< get time in nanoseconds RGFW_setTime, which ran when the first window is open */
1372RGFWDEF void RGFW_sleep(u64 milisecond); /*!< sleep for a set time */
1373RGFWDEF void RGFW_setTime(double time); /*!< set timer in seconds */
1374RGFWDEF u64 RGFW_getTimerValue(void); /*!< get API timer value */
1375RGFWDEF u64 RGFW_getTimerFreq(void); /*!< get API time freq */
1377/*< updates fps / sets fps to cap (must by ran manually by the user at the end of a frame), returns current fps */
1378RGFWDEF u32 RGFW_checkFPS(double startTime, u32 frameCount, u32 fpsCap);
1380/*!< change which window is the root window */
1381RGFWDEF void RGFW_setRootWindow(RGFW_window* win);
1382RGFWDEF RGFW_window* RGFW_getRootWindow(void);
1384/*! standard event queue, used for injecting events and returning source API callback events like any other queue check */
1385/* these are all used internally by RGFW */
1386void RGFW_eventQueuePush(RGFW_event event);
1387RGFW_event* RGFW_eventQueuePop(RGFW_window* win);
1389/* for C++ / C89 */
1390#define RGFW_eventQueuePushEx(eventInit) { RGFW_event e; eventInit; RGFW_eventQueuePush(e); }
1392/*!
1393 key codes and mouse icon enums
1394*/
1395#undef RGFW_key
1396typedef RGFW_ENUM(u8, RGFW_key) {
1397 RGFW_keyNULL = 0,
1398 RGFW_escape = '\033',
1399 RGFW_backtick = '`',
1400 RGFW_0 = '0',
1401 RGFW_1 = '1',
1402 RGFW_2 = '2',
1403 RGFW_3 = '3',
1404 RGFW_4 = '4',
1405 RGFW_5 = '5',
1406 RGFW_6 = '6',
1407 RGFW_7 = '7',
1408 RGFW_8 = '8',
1409 RGFW_9 = '9',
1411 RGFW_minus = '-',
1412 RGFW_equals = '=',
1413 RGFW_backSpace = '\b',
1414 RGFW_tab = '\t',
1415 RGFW_space = ' ',
1417 RGFW_a = 'a',
1418 RGFW_b = 'b',
1419 RGFW_c = 'c',
1420 RGFW_d = 'd',
1421 RGFW_e = 'e',
1422 RGFW_f = 'f',
1423 RGFW_g = 'g',
1424 RGFW_h = 'h',
1425 RGFW_i = 'i',
1426 RGFW_j = 'j',
1427 RGFW_k = 'k',
1428 RGFW_l = 'l',
1429 RGFW_m = 'm',
1430 RGFW_n = 'n',
1431 RGFW_o = 'o',
1432 RGFW_p = 'p',
1433 RGFW_q = 'q',
1434 RGFW_r = 'r',
1435 RGFW_s = 's',
1436 RGFW_t = 't',
1437 RGFW_u = 'u',
1438 RGFW_v = 'v',
1439 RGFW_w = 'w',
1440 RGFW_x = 'x',
1441 RGFW_y = 'y',
1442 RGFW_z = 'z',
1444 RGFW_period = '.',
1445 RGFW_comma = ',',
1446 RGFW_slash = '/',
1447 RGFW_bracket = '[',
1448 RGFW_closeBracket = ']',
1449 RGFW_semicolon = ';',
1450 RGFW_apostrophe = '\'',
1451 RGFW_backSlash = '\\',
1452 RGFW_return = '\n',
1453 RGFW_enter = RGFW_return,
1455 RGFW_delete = '\177', /* 127 */
1457 RGFW_F1,
1458 RGFW_F2,
1459 RGFW_F3,
1460 RGFW_F4,
1461 RGFW_F5,
1462 RGFW_F6,
1463 RGFW_F7,
1464 RGFW_F8,
1465 RGFW_F9,
1466 RGFW_F10,
1467 RGFW_F11,
1468 RGFW_F12,
1470 RGFW_capsLock,
1471 RGFW_shiftL,
1472 RGFW_controlL,
1473 RGFW_altL,
1474 RGFW_superL,
1475 RGFW_shiftR,
1476 RGFW_controlR,
1477 RGFW_altR,
1478 RGFW_superR,
1479 RGFW_up,
1480 RGFW_down,
1481 RGFW_left,
1482 RGFW_right,
1483 RGFW_insert,
1484 RGFW_end,
1485 RGFW_home,
1486 RGFW_pageUp,
1487 RGFW_pageDown,
1489 RGFW_numLock,
1490 RGFW_KP_Slash,
1491 RGFW_multiply,
1492 RGFW_KP_Minus,
1493 RGFW_KP_1,
1494 RGFW_KP_2,
1495 RGFW_KP_3,
1496 RGFW_KP_4,
1497 RGFW_KP_5,
1498 RGFW_KP_6,
1499 RGFW_KP_7,
1500 RGFW_KP_8,
1501 RGFW_KP_9,
1502 RGFW_KP_0,
1503 RGFW_KP_Period,
1504 RGFW_KP_Return,
1505 RGFW_scrollLock,
1506 RGFW_printScreen,
1507 RGFW_pause,
1508 RGFW_keyLast = 256 /* padding for alignment ~(175 by default) */
1509 };
1512/*! converts api keycode to the RGFW unmapped/physical key */
1513RGFWDEF u32 RGFW_apiKeyToRGFW(u32 keycode);
1514/*! converts RGFW keycode to the unmapped/physical api key */
1515RGFWDEF u32 RGFW_rgfwToApiKey(u32 keycode);
1516/*! converts RGFW keycode to the mapped keychar */
1517RGFWDEF u8 RGFW_rgfwToKeyChar(u32 keycode);
1519typedef RGFW_ENUM(u8, RGFW_mouseIcons) {
1520 RGFW_mouseNormal = 0,
1521 RGFW_mouseArrow,
1522 RGFW_mouseIbeam,
1523 RGFW_mouseCrosshair,
1524 RGFW_mousePointingHand,
1525 RGFW_mouseResizeEW,
1526 RGFW_mouseResizeNS,
1527 RGFW_mouseResizeNWSE,
1528 RGFW_mouseResizeNESW,
1529 RGFW_mouseResizeAll,
1530 RGFW_mouseNotAllowed,
1531 RGFW_mouseIconFinal = 16 /* padding for alignment */
1532};
1533/** @} */
1535#endif /* RGFW_HEADER */
1536#if defined(RGFW_X11) || defined(RGFW_WAYLAND)
1537 #define RGFW_OS_BASED_VALUE(l, w, m, h) l
1538#elif defined(RGFW_WINDOWS)
1539 #define RGFW_OS_BASED_VALUE(l, w, m, h) w
1540#elif defined(RGFW_MACOS)
1541 #define RGFW_OS_BASED_VALUE(l, w, m, h) m
1542#elif defined(RGFW_WASM)
1543 #define RGFW_OS_BASED_VALUE(l, w, m, h) h
1544#endif
1547#ifdef RGFW_IMPLEMENTATION
1548RGFW_bool RGFW_useWaylandBool = 1;
1549void RGFW_useWayland(RGFW_bool wayland) { RGFW_useWaylandBool = wayland; }
1550RGFW_bool RGFW_usingWayland(void) { return RGFW_useWaylandBool; }
1552#if !defined(RGFW_NO_X11) && defined(RGFW_WAYLAND)
1553#define RGFW_GOTO_WAYLAND(fallback) if (RGFW_useWaylandBool && fallback == 0) goto wayland
1554#define RGFW_WAYLAND_LABEL wayland:;
1555#else
1556#define RGFW_GOTO_WAYLAND(fallback)
1557#define RGFW_WAYLAND_LABEL
1558#endif
1560char* RGFW_clipboard_data;
1561void RGFW_clipboard_switch(char* newstr);
1562void RGFW_clipboard_switch(char* newstr) {
1563 if (RGFW_clipboard_data != NULL)
1564 RGFW_FREE(RGFW_clipboard_data);
1565 RGFW_clipboard_data = newstr;
1566}
1568#define RGFW_CHECK_CLIPBOARD() \
1569 if (size <= 0 && RGFW_clipboard_data != NULL) \
1570 return (const char*)RGFW_clipboard_data; \
1571 else if (size <= 0) \
1572 return "\0";
1574const char* RGFW_readClipboard(size_t* len) {
1575 RGFW_ssize_t size = RGFW_readClipboardPtr(NULL, 0);
1576 RGFW_CHECK_CLIPBOARD();
1577 char* str = (char*)RGFW_ALLOC((size_t)size);
1578 RGFW_ASSERT(str != NULL);
1579 str[0] = '\0';
1581 size = RGFW_readClipboardPtr(str, (size_t)size);
1583 RGFW_CHECK_CLIPBOARD();
1585 if (len != NULL) *len = (size_t)size;
1587 RGFW_clipboard_switch(str);
1588 return (const char*)str;
1589}
1591RGFW_debugfunc RGFW_debugCallback = NULL;
1592RGFW_debugfunc RGFW_setDebugCallback(RGFW_debugfunc func) {
1593 RGFW_debugfunc RGFW_debugCallbackPrev = RGFW_debugCallback;
1594 RGFW_debugCallback = func;
1595 return RGFW_debugCallbackPrev;
1596}
1598#ifdef RGFW_DEBUG
1599#include <stdio.h>
1600#endif
1602void RGFW_sendDebugInfo(RGFW_debugType type, RGFW_errorCode err, RGFW_debugContext ctx, const char* msg) {
1603 if (RGFW_debugCallback) RGFW_debugCallback(type, err, ctx, msg);
1604 #ifdef RGFW_DEBUG
1605 switch (type) {
1606 case RGFW_typeInfo: printf("RGFW INFO (%i %i): %s", type, err, msg); break;
1607 case RGFW_typeError: printf("RGFW DEBUG (%i %i): %s", type, err, msg); break;
1608 case RGFW_typeWarning: printf("RGFW WARNING (%i %i): %s", type, err, msg); break;
1609 default: break;
1610 }
1612 switch (err) {
1613 #ifdef RGFW_BUFFER
1614 case RGFW_errBuffer: case RGFW_infoBuffer: printf(" buffer size: %i %i\n", ctx.win->bufferSize.w, ctx.win->bufferSize.h); break;
1615 #endif
1616 case RGFW_infoMonitor: printf(": scale (%s):\n rect: {%i, %i, %i, %i}\n physical size:%f %f\n scale: %f %f\n pixelRatio: %f\n refreshRate: %i\n depth: %i\n", ctx.monitor->name, ctx.monitor->x, ctx.monitor->y, ctx.monitor->mode.area.w, ctx.monitor->mode.area.h, ctx.monitor->physW, ctx.monitor->physH, ctx.monitor->scaleX, ctx.monitor->scaleY, ctx.monitor->pixelRatio, ctx.monitor->mode.refreshRate, ctx.monitor->mode.red + ctx.monitor->mode.green + ctx.monitor->mode.blue); break;
1617 case RGFW_infoWindow: printf(" with rect of {%i, %i, %i, %i} \n", ctx.win->r.x, ctx.win->r.y,ctx. win->r.w, ctx.win->r.h); break;
1618 case RGFW_errDirectXContext: printf(" srcError %i\n", ctx.srcError); break;
1619 default: printf("\n");
1620 }
1621 #endif
1622}
1624u64 RGFW_timerOffset = 0;
1625void RGFW_setTime(double time) {
1626 RGFW_timerOffset = RGFW_getTimerValue() - (u64)(time * (double)RGFW_getTimerFreq());
1627}
1629double RGFW_getTime(void) {
1630 return (double) ((double)(RGFW_getTimerValue() - RGFW_timerOffset) / (double)RGFW_getTimerFreq());
1631}
1633u64 RGFW_getTimeNS(void) {
1634 return (u64)(((double)((RGFW_getTimerValue() - RGFW_timerOffset)) * 1e9) / (double)RGFW_getTimerFreq());
1635}
1637/*
1638RGFW_IMPLEMENTATION starts with generic RGFW defines
1640This is the start of keycode data
1641*/
1645/*
1646 the c++ compiler doesn't support setting up an array like,
1647 we'll have to do it during runtime using a function & this messy setup
1648*/
1650#ifndef RGFW_CUSTOM_BACKEND
1652#if !defined(__cplusplus) && !defined(RGFW_C89)
1653#define RGFW_NEXT ,
1654#define RGFW_MAP
1655#else
1656#define RGFW_NEXT ;
1657#define RGFW_MAP RGFW_keycodes
1658#endif
1660u32 RGFW_apiKeycodes[RGFW_keyLast] = { 0 };
1662u8 RGFW_keycodes [RGFW_OS_BASED_VALUE(256, 512, 128, 256)] = {
1663#if defined(__cplusplus) || defined(RGFW_C89)
1664 0
1665};
1666void RGFW_init_keys(void);
1667void RGFW_init_keys(void) {
1668#endif
1669 RGFW_MAP [RGFW_OS_BASED_VALUE(49, 0x029, 50, DOM_VK_BACK_QUOTE)] = RGFW_backtick RGFW_NEXT
1671 RGFW_MAP [RGFW_OS_BASED_VALUE(19, 0x00B, 29, DOM_VK_0)] = RGFW_0 RGFW_NEXT
1672 RGFW_MAP [RGFW_OS_BASED_VALUE(10, 0x002, 18, DOM_VK_1)] = RGFW_1 RGFW_NEXT
1673 RGFW_MAP [RGFW_OS_BASED_VALUE(11, 0x003, 19, DOM_VK_2)] = RGFW_2 RGFW_NEXT
1674 RGFW_MAP [RGFW_OS_BASED_VALUE(12, 0x004, 20, DOM_VK_3)] = RGFW_3 RGFW_NEXT
1675 RGFW_MAP [RGFW_OS_BASED_VALUE(13, 0x005, 21, DOM_VK_4)] = RGFW_4 RGFW_NEXT
1676 RGFW_MAP [RGFW_OS_BASED_VALUE(14, 0x006, 23, DOM_VK_5)] = RGFW_5 RGFW_NEXT
1677 RGFW_MAP [RGFW_OS_BASED_VALUE(15, 0x007, 22, DOM_VK_6)] = RGFW_6 RGFW_NEXT
1678 RGFW_MAP [RGFW_OS_BASED_VALUE(16, 0x008, 26, DOM_VK_7)] = RGFW_7 RGFW_NEXT
1679 RGFW_MAP [RGFW_OS_BASED_VALUE(17, 0x009, 28, DOM_VK_8)] = RGFW_8 RGFW_NEXT
1680 RGFW_MAP [RGFW_OS_BASED_VALUE(18, 0x00A, 25, DOM_VK_9)] = RGFW_9,
1681 RGFW_MAP [RGFW_OS_BASED_VALUE(65, 0x039, 49, DOM_VK_SPACE)] = RGFW_space,
1682 RGFW_MAP [RGFW_OS_BASED_VALUE(38, 0x01E, 0, DOM_VK_A)] = RGFW_a RGFW_NEXT
1683 RGFW_MAP [RGFW_OS_BASED_VALUE(56, 0x030, 11, DOM_VK_B)] = RGFW_b RGFW_NEXT
1684 RGFW_MAP [RGFW_OS_BASED_VALUE(54, 0x02E, 8, DOM_VK_C)] = RGFW_c RGFW_NEXT
1685 RGFW_MAP [RGFW_OS_BASED_VALUE(40, 0x020, 2, DOM_VK_D)] = RGFW_d RGFW_NEXT
1686 RGFW_MAP [RGFW_OS_BASED_VALUE(26, 0x012, 14, DOM_VK_E)] = RGFW_e RGFW_NEXT
1687 RGFW_MAP [RGFW_OS_BASED_VALUE(41, 0x021, 3, DOM_VK_F)] = RGFW_f RGFW_NEXT
1688 RGFW_MAP [RGFW_OS_BASED_VALUE(42, 0x022, 5, DOM_VK_G)] = RGFW_g RGFW_NEXT
1689 RGFW_MAP [RGFW_OS_BASED_VALUE(43, 0x023, 4, DOM_VK_H)] = RGFW_h RGFW_NEXT
1690 RGFW_MAP [RGFW_OS_BASED_VALUE(31, 0x017, 34, DOM_VK_I)] = RGFW_i RGFW_NEXT
1691 RGFW_MAP [RGFW_OS_BASED_VALUE(44, 0x024, 38, DOM_VK_J)] = RGFW_j RGFW_NEXT
1692 RGFW_MAP [RGFW_OS_BASED_VALUE(45, 0x025, 40, DOM_VK_K)] = RGFW_k RGFW_NEXT
1693 RGFW_MAP [RGFW_OS_BASED_VALUE(46, 0x026, 37, DOM_VK_L)] = RGFW_l RGFW_NEXT
1694 RGFW_MAP [RGFW_OS_BASED_VALUE(58, 0x032, 46, DOM_VK_M)] = RGFW_m RGFW_NEXT
1695 RGFW_MAP [RGFW_OS_BASED_VALUE(57, 0x031, 45, DOM_VK_N)] = RGFW_n RGFW_NEXT
1696 RGFW_MAP [RGFW_OS_BASED_VALUE(32, 0x018, 31, DOM_VK_O)] = RGFW_o RGFW_NEXT
1697 RGFW_MAP [RGFW_OS_BASED_VALUE(33, 0x019, 35, DOM_VK_P)] = RGFW_p RGFW_NEXT
1698 RGFW_MAP [RGFW_OS_BASED_VALUE(24, 0x010, 12, DOM_VK_Q)] = RGFW_q RGFW_NEXT
1699 RGFW_MAP [RGFW_OS_BASED_VALUE(27, 0x013, 15, DOM_VK_R)] = RGFW_r RGFW_NEXT
1700 RGFW_MAP [RGFW_OS_BASED_VALUE(39, 0x01F, 1, DOM_VK_S)] = RGFW_s RGFW_NEXT
1701 RGFW_MAP [RGFW_OS_BASED_VALUE(28, 0x014, 17, DOM_VK_T)] = RGFW_t RGFW_NEXT
1702 RGFW_MAP [RGFW_OS_BASED_VALUE(30, 0x016, 32, DOM_VK_U)] = RGFW_u RGFW_NEXT
1703 RGFW_MAP [RGFW_OS_BASED_VALUE(55, 0x02F, 9, DOM_VK_V)] = RGFW_v RGFW_NEXT
1704 RGFW_MAP [RGFW_OS_BASED_VALUE(25, 0x011, 13, DOM_VK_W)] = RGFW_w RGFW_NEXT
1705 RGFW_MAP [RGFW_OS_BASED_VALUE(53, 0x02D, 7, DOM_VK_X)] = RGFW_x RGFW_NEXT
1706 RGFW_MAP [RGFW_OS_BASED_VALUE(29, 0x015, 16, DOM_VK_Y)] = RGFW_y RGFW_NEXT
1707 RGFW_MAP [RGFW_OS_BASED_VALUE(52, 0x02C, 6, DOM_VK_Z)] = RGFW_z,
1708 RGFW_MAP [RGFW_OS_BASED_VALUE(60, 0x034, 47, DOM_VK_PERIOD)] = RGFW_period RGFW_NEXT
1709 RGFW_MAP [RGFW_OS_BASED_VALUE(59, 0x033, 43, DOM_VK_COMMA)] = RGFW_comma RGFW_NEXT
1710 RGFW_MAP [RGFW_OS_BASED_VALUE(61, 0x035, 44, DOM_VK_SLASH)] = RGFW_slash RGFW_NEXT
1711 RGFW_MAP [RGFW_OS_BASED_VALUE(34, 0x01A, 33, DOM_VK_OPEN_BRACKET)] = RGFW_bracket RGFW_NEXT
1712 RGFW_MAP [RGFW_OS_BASED_VALUE(35, 0x01B, 30, DOM_VK_CLOSE_BRACKET)] = RGFW_closeBracket RGFW_NEXT
1713 RGFW_MAP [RGFW_OS_BASED_VALUE(47, 0x027, 41, DOM_VK_SEMICOLON)] = RGFW_semicolon RGFW_NEXT
1714 RGFW_MAP [RGFW_OS_BASED_VALUE(48, 0x028, 39, DOM_VK_QUOTE)] = RGFW_apostrophe RGFW_NEXT
1715 RGFW_MAP [RGFW_OS_BASED_VALUE(51, 0x02B, 42, DOM_VK_BACK_SLASH)] = RGFW_backSlash,
1716 RGFW_MAP [RGFW_OS_BASED_VALUE(36, 0x01C, 36, DOM_VK_RETURN)] = RGFW_return RGFW_NEXT
1717 RGFW_MAP [RGFW_OS_BASED_VALUE(119, 0x153, 118, DOM_VK_DELETE)] = RGFW_delete RGFW_NEXT
1718 RGFW_MAP [RGFW_OS_BASED_VALUE(77, 0x145, 72, DOM_VK_NUM_LOCK)] = RGFW_numLock RGFW_NEXT
1719 RGFW_MAP [RGFW_OS_BASED_VALUE(106, 0x135, 82, DOM_VK_DIVIDE)] = RGFW_KP_Slash RGFW_NEXT
1720 RGFW_MAP [RGFW_OS_BASED_VALUE(63, 0x037, 76, DOM_VK_MULTIPLY)] = RGFW_multiply RGFW_NEXT
1721 RGFW_MAP [RGFW_OS_BASED_VALUE(82, 0x04A, 67, DOM_VK_SUBTRACT)] = RGFW_KP_Minus RGFW_NEXT
1722 RGFW_MAP [RGFW_OS_BASED_VALUE(87, 0x04F, 84, DOM_VK_NUMPAD1)] = RGFW_KP_1 RGFW_NEXT
1723 RGFW_MAP [RGFW_OS_BASED_VALUE(88, 0x050, 85, DOM_VK_NUMPAD2)] = RGFW_KP_2 RGFW_NEXT
1724 RGFW_MAP [RGFW_OS_BASED_VALUE(89, 0x051, 86, DOM_VK_NUMPAD3)] = RGFW_KP_3 RGFW_NEXT
1725 RGFW_MAP [RGFW_OS_BASED_VALUE(83, 0x04B, 87, DOM_VK_NUMPAD4)] = RGFW_KP_4 RGFW_NEXT
1726 RGFW_MAP [RGFW_OS_BASED_VALUE(84, 0x04C, 88, DOM_VK_NUMPAD5)] = RGFW_KP_5 RGFW_NEXT
1727 RGFW_MAP [RGFW_OS_BASED_VALUE(85, 0x04D, 89, DOM_VK_NUMPAD6)] = RGFW_KP_6 RGFW_NEXT
1728 RGFW_MAP [RGFW_OS_BASED_VALUE(79, 0x047, 90, DOM_VK_NUMPAD7)] = RGFW_KP_7 RGFW_NEXT
1729 RGFW_MAP [RGFW_OS_BASED_VALUE(80, 0x048, 92, DOM_VK_NUMPAD8)] = RGFW_KP_8 RGFW_NEXT
1730 RGFW_MAP [RGFW_OS_BASED_VALUE(81, 0x049, 93, DOM_VK_NUMPAD9)] = RGFW_KP_9 RGFW_NEXT
1731 RGFW_MAP [RGFW_OS_BASED_VALUE(90, 0x052, 83, DOM_VK_NUMPAD0)] = RGFW_KP_0 RGFW_NEXT
1732 RGFW_MAP [RGFW_OS_BASED_VALUE(91, 0x053, 65, DOM_VK_DECIMAL)] = RGFW_KP_Period RGFW_NEXT
1733 RGFW_MAP [RGFW_OS_BASED_VALUE(104, 0x11C, 77, 0)] = RGFW_KP_Return,
1734 RGFW_MAP [RGFW_OS_BASED_VALUE(20, 0x00C, 27, DOM_VK_HYPHEN_MINUS)] = RGFW_minus RGFW_NEXT
1735 RGFW_MAP [RGFW_OS_BASED_VALUE(21, 0x00D, 24, DOM_VK_EQUALS)] = RGFW_equals RGFW_NEXT
1736 RGFW_MAP [RGFW_OS_BASED_VALUE(22, 0x00E, 51, DOM_VK_BACK_SPACE)] = RGFW_backSpace RGFW_NEXT
1737 RGFW_MAP [RGFW_OS_BASED_VALUE(23, 0x00F, 48, DOM_VK_TAB)] = RGFW_tab RGFW_NEXT
1738 RGFW_MAP [RGFW_OS_BASED_VALUE(66, 0x03A, 57, DOM_VK_CAPS_LOCK)] = RGFW_capsLock RGFW_NEXT
1739 RGFW_MAP [RGFW_OS_BASED_VALUE(50, 0x02A, 56, DOM_VK_SHIFT)] = RGFW_shiftL RGFW_NEXT
1740 RGFW_MAP [RGFW_OS_BASED_VALUE(37, 0x01D, 59, DOM_VK_CONTROL)] = RGFW_controlL RGFW_NEXT
1741 RGFW_MAP [RGFW_OS_BASED_VALUE(64, 0x038, 58, DOM_VK_ALT)] = RGFW_altL RGFW_NEXT
1742 RGFW_MAP [RGFW_OS_BASED_VALUE(133, 0x15B, 55, DOM_VK_WIN)] = RGFW_superL,
1743 #if !defined(RGFW_MACOS) && !defined(RGFW_WASM)
1744 RGFW_MAP [RGFW_OS_BASED_VALUE(105, 0x11D, 59, 0)] = RGFW_controlR RGFW_NEXT
1745 RGFW_MAP [RGFW_OS_BASED_VALUE(134, 0x15C, 55, 0)] = RGFW_superR,
1746 RGFW_MAP [RGFW_OS_BASED_VALUE(62, 0x036, 56, 0)] = RGFW_shiftR RGFW_NEXT
1747 RGFW_MAP [RGFW_OS_BASED_VALUE(108, 0x138, 58, 0)] = RGFW_altR,
1748 #endif
1749 RGFW_MAP [RGFW_OS_BASED_VALUE(67, 0x03B, 127, DOM_VK_F1)] = RGFW_F1 RGFW_NEXT
1750 RGFW_MAP [RGFW_OS_BASED_VALUE(68, 0x03C, 121, DOM_VK_F2)] = RGFW_F2 RGFW_NEXT
1751 RGFW_MAP [RGFW_OS_BASED_VALUE(69, 0x03D, 100, DOM_VK_F3)] = RGFW_F3 RGFW_NEXT
1752 RGFW_MAP [RGFW_OS_BASED_VALUE(70, 0x03E, 119, DOM_VK_F4)] = RGFW_F4 RGFW_NEXT
1753 RGFW_MAP [RGFW_OS_BASED_VALUE(71, 0x03F, 97, DOM_VK_F5)] = RGFW_F5 RGFW_NEXT
1754 RGFW_MAP [RGFW_OS_BASED_VALUE(72, 0x040, 98, DOM_VK_F6)] = RGFW_F6 RGFW_NEXT
1755 RGFW_MAP [RGFW_OS_BASED_VALUE(73, 0x041, 99, DOM_VK_F7)] = RGFW_F7 RGFW_NEXT
1756 RGFW_MAP [RGFW_OS_BASED_VALUE(74, 0x042, 101, DOM_VK_F8)] = RGFW_F8 RGFW_NEXT
1757 RGFW_MAP [RGFW_OS_BASED_VALUE(75, 0x043, 102, DOM_VK_F9)] = RGFW_F9 RGFW_NEXT
1758 RGFW_MAP [RGFW_OS_BASED_VALUE(76, 0x044, 110, DOM_VK_F10)] = RGFW_F10 RGFW_NEXT
1759 RGFW_MAP [RGFW_OS_BASED_VALUE(95, 0x057, 104, DOM_VK_F11)] = RGFW_F11 RGFW_NEXT
1760 RGFW_MAP [RGFW_OS_BASED_VALUE(96, 0x058, 111, DOM_VK_F12)] = RGFW_F12 RGFW_NEXT
1761 RGFW_MAP [RGFW_OS_BASED_VALUE(111, 0x148, 126, DOM_VK_UP)] = RGFW_up RGFW_NEXT
1762 RGFW_MAP [RGFW_OS_BASED_VALUE(116, 0x150, 125, DOM_VK_DOWN)] = RGFW_down RGFW_NEXT
1763 RGFW_MAP [RGFW_OS_BASED_VALUE(113, 0x14B, 123, DOM_VK_LEFT)] = RGFW_left RGFW_NEXT
1764 RGFW_MAP [RGFW_OS_BASED_VALUE(114, 0x14D, 124, DOM_VK_RIGHT)] = RGFW_right RGFW_NEXT
1765 RGFW_MAP [RGFW_OS_BASED_VALUE(118, 0x152, 115, DOM_VK_INSERT)] = RGFW_insert RGFW_NEXT
1766 RGFW_MAP [RGFW_OS_BASED_VALUE(115, 0x14F, 120, DOM_VK_END)] = RGFW_end RGFW_NEXT
1767 RGFW_MAP [RGFW_OS_BASED_VALUE(112, 0x149, 117, DOM_VK_PAGE_UP)] = RGFW_pageUp RGFW_NEXT
1768 RGFW_MAP [RGFW_OS_BASED_VALUE(117, 0x151, 122, DOM_VK_PAGE_DOWN)] = RGFW_pageDown RGFW_NEXT
1769 RGFW_MAP [RGFW_OS_BASED_VALUE(9, 0x001, 53, DOM_VK_ESCAPE)] = RGFW_escape RGFW_NEXT
1770 RGFW_MAP [RGFW_OS_BASED_VALUE(110, 0x147, 116, DOM_VK_HOME)] = RGFW_home RGFW_NEXT
1771 RGFW_MAP [RGFW_OS_BASED_VALUE(78, 0x046, 107, DOM_VK_SCROLL_LOCK)] = RGFW_scrollLock RGFW_NEXT
1772 RGFW_MAP [RGFW_OS_BASED_VALUE(107, 0x137, 105, DOM_VK_PRINTSCREEN)] = RGFW_printScreen RGFW_NEXT
1773 RGFW_MAP [RGFW_OS_BASED_VALUE(128, 0x045, 113, DOM_VK_PAUSE)] = RGFW_pause RGFW_NEXT
1774#if defined(__cplusplus) || defined(RGFW_C89)
1775}
1776#else
1777};
1778#endif
1780#undef RGFW_NEXT
1781#undef RGFW_MAP
1783u32 RGFW_apiKeyToRGFW(u32 keycode) {
1784 #if defined(__cplusplus) || defined(RGFW_C89)
1785 if (RGFW_keycodes[RGFW_OS_BASED_VALUE(49, 0x029, 50, DOM_VK_BACK_QUOTE)] != RGFW_backtick) {
1786 RGFW_init_keys();
1787 }
1788 #endif
1790 /* make sure the key isn't out of bounds */
1791 if (keycode > sizeof(RGFW_keycodes) / sizeof(u8))
1792 return 0;
1794 return RGFW_keycodes[keycode];
1795}
1797u32 RGFW_rgfwToApiKey(u32 keycode) {
1798 if (RGFW_apiKeycodes[RGFW_backtick] != RGFW_OS_BASED_VALUE(49, 0x029, 50, DOM_VK_BACK_QUOTE)) {
1799 for (u32 i = 0; i < RGFW_keyLast; i++) {
1800 for (u32 y = 0; y < sizeof(RGFW_keycodes); y++) {
1801 if (RGFW_keycodes[y] == i) {
1802 RGFW_apiKeycodes[i] = y;
1803 break;
1804 }
1805 }
1806 }
1807 }
1809 /* make sure the key isn't out of bounds */
1810 if (keycode > sizeof(RGFW_apiKeycodes) / sizeof(u32))
1811 return 0;
1813 return RGFW_apiKeycodes[keycode];
1814}
1815#endif /* RGFW_CUSTOM_BACKEND */
1817typedef struct {
1818 RGFW_bool current : 1;
1819 RGFW_bool prev : 1;
1820} RGFW_keyState;
1822RGFW_keyState RGFW_keyboard[RGFW_keyLast] = { {0, 0} };
1824RGFWDEF void RGFW_resetKeyPrev(void);
1825void RGFW_resetKeyPrev(void) {
1826 size_t i; /*!< reset each previous state */
1827 for (i = 0; i < RGFW_keyLast; i++) RGFW_keyboard[i].prev = 0;
1828}
1829RGFWDEF void RGFW_resetKey(void);
1830void RGFW_resetKey(void) { RGFW_MEMSET(RGFW_keyboard, 0, sizeof(RGFW_keyboard)); }
1831/*
1832 this is the end of keycode data
1833*/
1835/* gamepad data */
1836RGFW_keyState RGFW_gamepadPressed[4][32]; /*!< if a key is currently pressed or not (per gamepad) */
1837RGFW_point RGFW_gamepadAxes[4][4]; /*!< if a key is currently pressed or not (per gamepad) */
1839RGFW_gamepadType RGFW_gamepads_type[4]; /*!< if a key is currently pressed or not (per gamepad) */
1840i32 RGFW_gamepads[4] = {0, 0, 0, 0}; /*!< limit of 4 gamepads at a time */
1841char RGFW_gamepads_name[4][128]; /*!< gamepad names */
1842u16 RGFW_gamepadCount = 0; /*!< the actual amount of gamepads */
1844/*
1845 event callback defines start here
1846*/
1849/*
1850 These exist to avoid the
1851 if (func == NULL) check
1852 for (allegedly) better performance
1854 RGFW_EMPTY_DEF exists to prevent the missing-prototypes warning
1855*/
1856static void RGFW_windowMovedfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); }
1857static void RGFW_windowResizedfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); }
1858static void RGFW_windowRestoredfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); }
1859static void RGFW_windowMinimizedfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); }
1860static void RGFW_windowMaximizedfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); }
1861static void RGFW_windowQuitfuncEMPTY(RGFW_window* win) { RGFW_UNUSED(win); }
1862static void RGFW_focusfuncEMPTY(RGFW_window* win, RGFW_bool inFocus) {RGFW_UNUSED(win); RGFW_UNUSED(inFocus);}
1863static void RGFW_mouseNotifyfuncEMPTY(RGFW_window* win, RGFW_point point, RGFW_bool status) {RGFW_UNUSED(win); RGFW_UNUSED(point); RGFW_UNUSED(status);}
1864static void RGFW_mousePosfuncEMPTY(RGFW_window* win, RGFW_point point, RGFW_point vector) {RGFW_UNUSED(win); RGFW_UNUSED(point); RGFW_UNUSED(vector);}
1865static void RGFW_dndInitfuncEMPTY(RGFW_window* win, RGFW_point point) {RGFW_UNUSED(win); RGFW_UNUSED(point);}
1866static void RGFW_windowRefreshfuncEMPTY(RGFW_window* win) {RGFW_UNUSED(win); }
1867static void RGFW_keyfuncEMPTY(RGFW_window* win, RGFW_key key, u8 keyChar, RGFW_keymod keyMod, RGFW_bool pressed) {RGFW_UNUSED(win); RGFW_UNUSED(key); RGFW_UNUSED(keyChar); RGFW_UNUSED(keyMod); RGFW_UNUSED(pressed);}
1868static void RGFW_mouseButtonfuncEMPTY(RGFW_window* win, RGFW_mouseButton button, double scroll, RGFW_bool pressed) {RGFW_UNUSED(win); RGFW_UNUSED(button); RGFW_UNUSED(scroll); RGFW_UNUSED(pressed);}
1869static void RGFW_gamepadButtonfuncEMPTY(RGFW_window* win, u16 gamepad, u8 button, RGFW_bool pressed) {RGFW_UNUSED(win); RGFW_UNUSED(gamepad); RGFW_UNUSED(button); RGFW_UNUSED(pressed); }
1870static void RGFW_gamepadAxisfuncEMPTY(RGFW_window* win, u16 gamepad, RGFW_point axis[2], u8 axisesCount, u8 whichAxis) {RGFW_UNUSED(win); RGFW_UNUSED(gamepad); RGFW_UNUSED(axis); RGFW_UNUSED(axisesCount); RGFW_UNUSED(whichAxis); }
1871static void RGFW_gamepadfuncEMPTY(RGFW_window* win, u16 gamepad, RGFW_bool connected) {RGFW_UNUSED(win); RGFW_UNUSED(gamepad); RGFW_UNUSED(connected);}
1872static void RGFW_dndfuncEMPTY(RGFW_window* win, char** droppedFiles, size_t droppedFilesCount) {RGFW_UNUSED(win); RGFW_UNUSED(droppedFiles); RGFW_UNUSED(droppedFilesCount);}
1873static void RGFW_scaleUpdatedfuncEMPTY(RGFW_window* win, float scaleX, float scaleY) {RGFW_UNUSED(win); RGFW_UNUSED(scaleX); RGFW_UNUSED(scaleY); }
1875#define RGFW_CALLBACK_DEFINE(x, x2) \
1876RGFW_##x##func RGFW_##x##Callback = RGFW_##x##funcEMPTY; \
1877RGFW_##x##func RGFW_set##x2##Callback(RGFW_##x##func func) { \
1878 RGFW_##x##func prev = RGFW_##x##Callback; \
1879 RGFW_##x##Callback = func; \
1880 return prev; \
1881}
1882RGFW_CALLBACK_DEFINE(windowMaximized, WindowMaximized)
1883RGFW_CALLBACK_DEFINE(windowMinimized, WindowMinimized)
1884RGFW_CALLBACK_DEFINE(windowRestored, WindowRestored)
1885RGFW_CALLBACK_DEFINE(windowMoved, WindowMoved)
1886RGFW_CALLBACK_DEFINE(windowResized, WindowResized)
1887RGFW_CALLBACK_DEFINE(windowQuit, WindowQuit)
1888RGFW_CALLBACK_DEFINE(mousePos, MousePos)
1889RGFW_CALLBACK_DEFINE(windowRefresh, WindowRefresh)
1890RGFW_CALLBACK_DEFINE(focus, Focus)
1891RGFW_CALLBACK_DEFINE(mouseNotify, MouseNotify)
1892RGFW_CALLBACK_DEFINE(dnd, Dnd)
1893RGFW_CALLBACK_DEFINE(dndInit, DndInit)
1894RGFW_CALLBACK_DEFINE(key, Key)
1895RGFW_CALLBACK_DEFINE(mouseButton, MouseButton)
1896RGFW_CALLBACK_DEFINE(gamepadButton, GamepadButton)
1897RGFW_CALLBACK_DEFINE(gamepadAxis, GamepadAxis)
1898RGFW_CALLBACK_DEFINE(gamepad, Gamepad)
1899RGFW_CALLBACK_DEFINE(scaleUpdated, ScaleUpdated)
1900#undef RGFW_CALLBACK_DEFINE
1902void RGFW_window_checkEvents(RGFW_window* win, i32 waitMS) {
1903 RGFW_window_eventWait(win, waitMS);
1905 while (RGFW_window_checkEvent(win) != NULL && RGFW_window_shouldClose(win) == 0) {
1906 if (win->event.type == RGFW_quit) return;
1907 }
1909 #ifdef RGFW_WASM /* WASM needs to run the sleep function for asyncify */
1910 RGFW_sleep(0);
1911 #endif
1912}
1914void RGFW_window_checkMode(RGFW_window* win);
1915void RGFW_window_checkMode(RGFW_window* win) {
1916 if (RGFW_window_isMinimized(win)) {
1917 win->_flags |= RGFW_windowMinimize;
1918 RGFW_windowMinimizedCallback(win, win->r);
1919 } else if (RGFW_window_isMaximized(win)) {
1920 win->_flags |= RGFW_windowMaximize;
1921 RGFW_eventQueuePushEx(e.type = RGFW_windowMaximized; e._win = win);
1922 RGFW_windowMaximizedCallback(win, win->r);
1923 } else if (((win->_flags & RGFW_windowMinimize) && !RGFW_window_isMaximized(win)) ||
1924 (win->_flags & RGFW_windowMaximize && !RGFW_window_isMaximized(win))) {
1925 win->_flags &= ~(u32)RGFW_windowMinimize;
1926 if (RGFW_window_isMaximized(win) == RGFW_FALSE) win->_flags &= ~(u32)RGFW_windowMaximize;
1927 RGFW_eventQueuePushEx(e.type = RGFW_windowRestored; e._win = win);
1928 RGFW_windowRestoredCallback(win, win->r);
1929 }
1930}
1932/*
1933no more event call back defines
1934*/
1936#define SET_ATTRIB(a, v) { \
1937 RGFW_ASSERT(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
1938 attribs[index++] = a; \
1939 attribs[index++] = v; \
1940}
1942#define RGFW_EVENT_PASSED RGFW_BIT(24) /* if a queued event was passed */
1943#define RGFW_EVENT_QUIT RGFW_BIT(25) /* the window close button was pressed */
1944#define RGFW_HOLD_MOUSE RGFW_BIT(26) /*!< hold the moues still */
1945#define RGFW_MOUSE_LEFT RGFW_BIT(27) /* if mouse left the window */
1946#define RGFW_WINDOW_ALLOC RGFW_BIT(28) /* if window was allocated by RGFW */
1947#define RGFW_BUFFER_ALLOC RGFW_BIT(29) /* if window.buffer was allocated by RGFW */
1948#define RGFW_WINDOW_INIT RGFW_BIT(30) /* if window.buffer was allocated by RGFW */
1949#define RGFW_INTERNAL_FLAGS (RGFW_EVENT_QUIT | RGFW_EVENT_PASSED | RGFW_HOLD_MOUSE | RGFW_MOUSE_LEFT | RGFW_WINDOW_ALLOC | RGFW_BUFFER_ALLOC | RGFW_windowFocus)
1951RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, RGFW_windowFlags flags) {
1952 RGFW_window* win = (RGFW_window*)RGFW_ALLOC(sizeof(RGFW_window));
1953 RGFW_ASSERT(win != NULL);
1954 win->_flags = RGFW_WINDOW_ALLOC;
1955 return RGFW_createWindowPtr(name, rect, flags, win);
1956}
1958#if defined(RGFW_USE_XDL) && defined(RGFW_X11)
1959 #define XDL_IMPLEMENTATION
1960 #include "XDL.h"
1961#endif
1963#define RGFW_MAX_EVENTS 32
1964typedef struct RGFW_globalStruct {
1965 RGFW_window* root;
1966 RGFW_window* current;
1967 i32 windowCount;
1968 i32 eventLen;
1969 i32 eventIndex;
1971 #ifdef RGFW_X11
1972 Display* display;
1973 Window helperWindow;
1974 char* clipboard; /* for writing to the clipboard selection */
1975 size_t clipboard_len;
1976 #endif
1977 #ifdef RGFW_WAYLAND
1978 struct wl_display* wl_display;
1979 #endif
1980 #if defined(RGFW_X11) || defined(RGFW_WINDOWS) || defined(RGFW_WAYLAND)
1981 RGFW_mouse* hiddenMouse;
1982 #endif
1983 RGFW_event events[RGFW_MAX_EVENTS];
1985} RGFW_globalStruct;
1986#if !defined(RGFW_C89) && !defined(__cplusplus)
1987RGFW_globalStruct _RGFW = {.root = NULL, .current = NULL, .windowCount = -1, .eventLen = 0, .eventIndex = 0};
1988#define _RGFW_init RGFW_TRUE
1989#else
1990RGFW_bool _RGFW_init = RGFW_FALSE;
1991RGFW_globalStruct _RGFW;
1992#endif
1994void RGFW_eventQueuePush(RGFW_event event) {
1995 if (_RGFW.eventLen >= RGFW_MAX_EVENTS) return;
1996 _RGFW.events[_RGFW.eventLen] = event;
1997 _RGFW.eventLen++;
1998}
2000RGFW_event* RGFW_eventQueuePop(RGFW_window* win) {
2001 RGFW_event* ev;
2002 if (_RGFW.eventLen == 0) return NULL;
2004 ev = (RGFW_event*)&_RGFW.events[_RGFW.eventIndex];
2006 _RGFW.eventLen--;
2007 if (_RGFW.eventLen >= 0 && _RGFW.eventIndex < _RGFW.eventLen) {
2008 _RGFW.eventIndex++;
2009 } else if (_RGFW.eventLen == 0) {
2010 _RGFW.eventIndex = 0;
2011 }
2013 if (ev->_win != win && ev->_win != NULL) {
2014 RGFW_eventQueuePush(*ev);
2015 return NULL;
2016 }
2018 ev->droppedFilesCount = win->event.droppedFilesCount;
2019 ev->droppedFiles = win->event.droppedFiles;
2020 return ev;
2021}
2023RGFW_event* RGFW_window_checkEventCore(RGFW_window* win);
2024RGFW_event* RGFW_window_checkEventCore(RGFW_window* win) {
2025 RGFW_event* ev;
2026 RGFW_ASSERT(win != NULL);
2027 if (win->event.type == 0 && _RGFW.eventLen == 0)
2028 RGFW_resetKeyPrev();
2030 if (win->event.type == RGFW_quit && win->_flags & RGFW_windowFreeOnClose) {
2031 static RGFW_event event;
2032 event = win->event;
2033 RGFW_window_close(win);
2034 return &event;
2035 }
2037 if (win->event.type != RGFW_DNDInit) win->event.type = 0;
2039 /* check queued events */
2040 ev = RGFW_eventQueuePop(win);
2041 if (ev != NULL) {
2042 if (ev->type == RGFW_quit) RGFW_window_setShouldClose(win, RGFW_TRUE);
2043 win->event = *ev;
2044 }
2045 else return NULL;
2047 return &win->event;
2048}
2051RGFWDEF void RGFW_window_basic_init(RGFW_window* win, RGFW_rect rect, RGFW_windowFlags flags);
2052void RGFW_setRootWindow(RGFW_window* win) { _RGFW.root = win; }
2053RGFW_window* RGFW_getRootWindow(void) { return _RGFW.root; }
2055/* do a basic initialization for RGFW_window, this is to standard it for each OS */
2056void RGFW_window_basic_init(RGFW_window* win, RGFW_rect rect, RGFW_windowFlags flags) {
2057 RGFW_UNUSED(flags);
2058 if (_RGFW.windowCount == -1 || _RGFW_init == RGFW_FALSE) RGFW_init();
2059 _RGFW.windowCount++;
2061 /* rect based the requested flags */
2062 if (_RGFW.root == NULL) {
2063 RGFW_setRootWindow(win);
2064 RGFW_setTime(0);
2065 }
2067 if (!(win->_flags & RGFW_WINDOW_ALLOC)) win->_flags = 0;
2069 /* set and init the new window's data */
2070 win->r = rect;
2071 win->exitKey = RGFW_escape;
2072 win->event.droppedFilesCount = 0;
2074 win->_flags = 0 | (win->_flags & RGFW_WINDOW_ALLOC);
2075 win->_flags |= flags;
2076 win->event.keyMod = 0;
2077 win->_lastMousePoint.x = 0;
2078 win->_lastMousePoint.y = 0;
2080 win->event.droppedFiles = (char**)RGFW_ALLOC(RGFW_MAX_PATH * RGFW_MAX_DROPS);
2081 RGFW_ASSERT(win->event.droppedFiles != NULL);
2083 {
2084 u32 i;
2085 for (i = 0; i < RGFW_MAX_DROPS; i++)
2086 win->event.droppedFiles[i] = (char*)(win->event.droppedFiles + RGFW_MAX_DROPS + (i * RGFW_MAX_PATH));
2087 }
2088}
2090void RGFW_window_setFlags(RGFW_window* win, RGFW_windowFlags flags) {
2091 RGFW_windowFlags cmpFlags = win->_flags;
2092 if (win->_flags & RGFW_WINDOW_INIT) cmpFlags = 0;
2094 #ifndef RGFW_NO_MONITOR
2095 if (flags & RGFW_windowScaleToMonitor) RGFW_window_scaleToMonitor(win);
2096 #endif
2098 if (flags & RGFW_windowCenter) RGFW_window_center(win);
2099 if (flags & RGFW_windowCenterCursor)
2100 RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2)));
2101 if (flags & RGFW_windowNoBorder) RGFW_window_setBorder(win, 0);
2102 else RGFW_window_setBorder(win, 1);
2103 if (flags & RGFW_windowFullscreen) RGFW_window_setFullscreen(win, RGFW_TRUE);
2104 else if (cmpFlags & RGFW_windowFullscreen) RGFW_window_setFullscreen(win, 0);
2105 if (flags & RGFW_windowMaximize) RGFW_window_maximize(win);
2106 else if (cmpFlags & RGFW_windowMaximize) RGFW_window_restore(win);
2107 if (flags & RGFW_windowMinimize) RGFW_window_minimize(win);
2108 else if (cmpFlags & RGFW_windowMinimize) RGFW_window_restore(win);
2109 if (flags & RGFW_windowHideMouse) RGFW_window_showMouse(win, 0);
2110 else if (cmpFlags & RGFW_windowHideMouse) RGFW_window_showMouse(win, 1);
2111 if (flags & RGFW_windowHide) RGFW_window_hide(win);
2112 else if (cmpFlags & RGFW_windowHide) RGFW_window_show(win);
2113 if (flags & RGFW_windowCocoaCHDirToRes) RGFW_moveToMacOSResourceDir();
2114 if (flags & RGFW_windowFloating) RGFW_window_setFloating(win, 1);
2115 else if (cmpFlags & RGFW_windowFloating) RGFW_window_setFloating(win, 0);
2116 if (flags & RGFW_windowFocus) RGFW_window_focus(win);
2118 if (flags & RGFW_windowNoResize) {
2119 RGFW_window_setMaxSize(win, RGFW_AREA(win->r.w, win->r.h));
2120 RGFW_window_setMinSize(win, RGFW_AREA(win->r.w, win->r.h));
2121 } else if (cmpFlags & RGFW_windowNoResize) {
2122 RGFW_window_setMaxSize(win, RGFW_AREA(0, 0));
2123 RGFW_window_setMinSize(win, RGFW_AREA(0, 0));
2124 }
2126 win->_flags = flags | (win->_flags & RGFW_INTERNAL_FLAGS);
2127}
2129RGFW_bool RGFW_window_opengl_isSoftware(RGFW_window* win) {
2130 return RGFW_BOOL(win->_flags |= RGFW_windowOpenglSoftware);
2131}
2133RGFW_bool RGFW_window_isInFocus(RGFW_window* win) {
2134#ifdef RGFW_WASM
2135 return RGFW_TRUE;
2136#else
2137 return RGFW_BOOL(win->_flags & RGFW_windowFocus);
2138#endif
2139}
2141void RGFW_window_initBuffer(RGFW_window* win) {
2142 RGFW_area area = RGFW_getScreenSize();
2143 if ((win->_flags & RGFW_windowNoResize))
2144 area = RGFW_AREA(win->r.w, win->r.h);
2146 RGFW_window_initBufferSize(win, area);
2147}
2149void RGFW_window_initBufferSize(RGFW_window* win, RGFW_area area) {
2150#if defined(RGFW_BUFFER) || defined(RGFW_OSMESA)
2151 win->_flags |= RGFW_BUFFER_ALLOC;
2152 #ifndef RGFW_WINDOWS
2153 u8* buffer = (u8*)RGFW_ALLOC(area.w * area.h * 4);
2154 RGFW_ASSERT(buffer != NULL);
2156 RGFW_window_initBufferPtr(win, buffer, area);
2157 #else /* windows's bitmap allocs memory for us */
2158 RGFW_window_initBufferPtr(win, (u8*)NULL, area);
2159 #endif
2160#else
2161 RGFW_UNUSED(win); RGFW_UNUSED(area);
2162#endif
2163}
2165#ifdef RGFW_MACOS
2166RGFWDEF void RGFW_window_cocoaSetLayer(RGFW_window* win, void* layer);
2167RGFWDEF void* RGFW_cocoaGetLayer(void);
2168#endif
2170const char* RGFW_className = NULL;
2171void RGFW_setClassName(const char* name) { RGFW_className = name; }
2173#ifndef RGFW_X11
2174void RGFW_setXInstName(const char* name) { RGFW_UNUSED(name); }
2175#endif
2177RGFW_keyState RGFW_mouseButtons[RGFW_mouseFinal] = { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2179RGFW_bool RGFW_isMousePressed(RGFW_window* win, RGFW_mouseButton button) {
2180 return RGFW_mouseButtons[button].current && (win == NULL || RGFW_window_isInFocus(win));
2181}
2182RGFW_bool RGFW_wasMousePressed(RGFW_window* win, RGFW_mouseButton button) {
2183 return RGFW_mouseButtons[button].prev && (win != NULL || RGFW_window_isInFocus(win));
2184}
2185RGFW_bool RGFW_isMouseHeld(RGFW_window* win, RGFW_mouseButton button) {
2186 return (RGFW_isMousePressed(win, button) && RGFW_wasMousePressed(win, button));
2187}
2188RGFW_bool RGFW_isMouseReleased(RGFW_window* win, RGFW_mouseButton button) {
2189 return (!RGFW_isMousePressed(win, button) && RGFW_wasMousePressed(win, button));
2190}
2192RGFW_point RGFW_window_getMousePoint(RGFW_window* win) {
2193 RGFW_ASSERT(win != NULL);
2194 return win->_lastMousePoint;
2195}
2197RGFW_bool RGFW_isPressed(RGFW_window* win, RGFW_key key) {
2198 return RGFW_keyboard[key].current && (win == NULL || RGFW_window_isInFocus(win));
2199}
2201RGFW_bool RGFW_wasPressed(RGFW_window* win, RGFW_key key) {
2202 return RGFW_keyboard[key].prev && (win == NULL || RGFW_window_isInFocus(win));
2203}
2205RGFW_bool RGFW_isHeld(RGFW_window* win, RGFW_key key) {
2206 return (RGFW_isPressed(win, key) && RGFW_wasPressed(win, key));
2207}
2209RGFW_bool RGFW_isClicked(RGFW_window* win, RGFW_key key) {
2210 return (RGFW_wasPressed(win, key) && !RGFW_isPressed(win, key));
2211}
2213RGFW_bool RGFW_isReleased(RGFW_window* win, RGFW_key key) {
2214 return (!RGFW_isPressed(win, key) && RGFW_wasPressed(win, key));
2215}
2217void RGFW_window_makeCurrent(RGFW_window* win) {
2218 _RGFW.current = win;
2219#if defined(RGFW_OPENGL) || defined(RGFW_EGL)
2220 RGFW_window_makeCurrent_OpenGL(win);
2221#endif
2222}
2224RGFW_window* RGFW_getCurrent(void) {
2225 return _RGFW.current;
2226}
2228void RGFW_window_swapBuffers(RGFW_window* win) {
2229 RGFW_ASSERT(win != NULL);
2230 RGFW_window_swapBuffers_software(win);
2231#if defined(RGFW_OPENGL) || defined(RGFW_EGL)
2232 RGFW_window_swapBuffers_OpenGL(win);
2233#endif
2234}
2236RGFWDEF void RGFW_setBit(u32* data, u32 bit, RGFW_bool value);
2237void RGFW_setBit(u32* data, u32 bit, RGFW_bool value) {
2238 if (value)
2239 *data |= bit;
2240 else if (!value && (*(data) & bit))
2241 *data ^= bit;
2242}
2244void RGFW_window_center(RGFW_window* win) {
2245 RGFW_ASSERT(win != NULL);
2246 RGFW_area screenR = RGFW_getScreenSize();
2247 RGFW_window_move(win, RGFW_POINT((i32)(screenR.w - (u32)win->r.w) / 2, (screenR.h - (u32)win->r.h) / 2));
2248}
2250RGFW_bool RGFW_monitor_scaleToWindow(RGFW_monitor mon, RGFW_window* win) {
2251 RGFW_monitorMode mode;
2252 RGFW_ASSERT(win != NULL);
2254 mode.area.w = (u32)win->r.w;
2255 mode.area.h = (u32)win->r.h;
2256 return RGFW_monitor_requestMode(mon, mode, RGFW_monitorScale);
2257}
2259void RGFW_splitBPP(u32 bpp, RGFW_monitorMode* mode);
2260void RGFW_splitBPP(u32 bpp, RGFW_monitorMode* mode) {
2261 if (bpp == 32) bpp = 24;
2262 mode->red = mode->green = mode->blue = (u8)(bpp / 3);
2264 u32 delta = bpp - (mode->red * 3); /* handle leftovers */
2265 if (delta >= 1) mode->green = mode->green + 1;
2266 if (delta == 2) mode->red = mode->red + 1;
2267}
2269RGFW_bool RGFW_monitorModeCompare(RGFW_monitorMode mon, RGFW_monitorMode mon2, RGFW_modeRequest request) {
2270 return (((mon.area.w == mon2.area.w && mon.area.h == mon2.area.h) || !(request & RGFW_monitorScale)) &&
2271 ((mon.refreshRate == mon2.refreshRate) || !(request & RGFW_monitorRefresh)) &&
2272 ((mon.red == mon2.red && mon.green == mon2.green && mon.blue == mon2.blue) || !(request & RGFW_monitorRGB)));
2273}
2275RGFW_bool RGFW_window_shouldClose(RGFW_window* win) {
2276 return (win == NULL || (win->_flags & RGFW_EVENT_QUIT)|| (win->exitKey && RGFW_isPressed(win, win->exitKey)));
2277}
2279void RGFW_window_setShouldClose(RGFW_window* win, RGFW_bool shouldClose) {
2280 if (shouldClose) {
2281 win->_flags |= RGFW_EVENT_QUIT;
2282 RGFW_windowQuitCallback(win);
2283 } else {
2284 win->_flags &= ~(u32)RGFW_EVENT_QUIT;
2285 }
2286}
2288#ifndef RGFW_NO_MONITOR
2289void RGFW_window_scaleToMonitor(RGFW_window* win) {
2290 RGFW_monitor monitor = RGFW_window_getMonitor(win);
2291 if (monitor.scaleX == 0 && monitor.scaleY == 0)
2292 return;
2294 RGFW_window_resize(win, RGFW_AREA((u32)(monitor.scaleX * (float)win->r.w), (u32)(monitor.scaleY * (float)win->r.h)));
2295}
2297void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m) {
2298 RGFW_window_move(win, RGFW_POINT(m.x + win->r.x, m.y + win->r.y));
2299}
2300#endif
2302RGFW_bool RGFW_window_setIcon(RGFW_window* win, u8* icon, RGFW_area a, i32 channels) {
2303 return RGFW_window_setIconEx(win, icon, a, channels, RGFW_iconBoth);
2304}
2306RGFWDEF void RGFW_captureCursor(RGFW_window* win, RGFW_rect);
2307RGFWDEF void RGFW_releaseCursor(RGFW_window* win);
2310RGFW_bool RGFW_window_mouseHeld(RGFW_window* win) { return RGFW_BOOL(win->_flags & RGFW_HOLD_MOUSE); }
2312void RGFW_window_mouseHold(RGFW_window* win, RGFW_area area) {
2313 if (!area.w && !area.h)
2314 area = RGFW_AREA(win->r.w / 2, win->r.h / 2);
2316 win->_flags |= RGFW_HOLD_MOUSE;
2317 RGFW_captureCursor(win, win->r);
2318 RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2)));
2319}
2321void RGFW_window_mouseUnhold(RGFW_window* win) {
2322 win->_flags &= ~(u32)RGFW_HOLD_MOUSE;
2323 RGFW_releaseCursor(win);
2324}
2326u32 RGFW_checkFPS(double startTime, u32 frameCount, u32 fpsCap) {
2327 double deltaTime = RGFW_getTime() - startTime;
2328 if (deltaTime == 0) return 0;
2330 double fps = (frameCount / deltaTime); /* the numer of frames over the time it took for them to render */
2331 if (fpsCap && fps > fpsCap) {
2332 double frameTime = (double)frameCount / (double)fpsCap; /* how long it should take to finish the frames */
2333 double sleepTime = frameTime - deltaTime; /* subtract how long it should have taken with how long it did take */
2335 if (sleepTime > 0) RGFW_sleep((u32)(sleepTime * 1000));
2336 }
2338 return (u32) fps;
2339}
2341#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
2342void RGFW_RGB_to_BGR(RGFW_window* win, u8* data) {
2343 #if !defined(RGFW_BUFFER_BGR) && !defined(RGFW_OSMESA)
2344 u32 x, y;
2345 for (y = 0; y < (u32)win->r.h; y++) {
2346 for (x = 0; x < (u32)win->r.w; x++) {
2347 u32 index = (y * 4 * win->bufferSize.w) + x * 4;
2349 u8 red = data[index];
2350 data[index] = win->buffer[index + 2];
2351 data[index + 2] = red;
2352 }
2353 }
2354 #elif defined(RGFW_OSMESA)
2355 u32 y;
2356 for(y = 0; y < (u32)win->r.h; y++){
2357 u32 index_from = (y + (win->bufferSize.h - win->r.h)) * 4 * win->bufferSize.w;
2358 u32 index_to = y * 4 * win->bufferSize.w;
2359 memcpy(&data[index_to], &data[index_from], 4 * win->bufferSize.w);
2360 }
2361 #else
2362 RGFW_UNUSED(win); RGFW_UNUSED(data);
2363 #endif
2364}
2365#endif
2367u32 RGFW_isPressedGamepad(RGFW_window* win, u8 c, RGFW_gamepadCodes button) {
2368 RGFW_UNUSED(win);
2369 return RGFW_gamepadPressed[c][button].current;
2370}
2371u32 RGFW_wasPressedGamepad(RGFW_window* win, u8 c, RGFW_gamepadCodes button) {
2372 RGFW_UNUSED(win);
2373 return RGFW_gamepadPressed[c][button].prev;
2374}
2375u32 RGFW_isReleasedGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button) {
2376 RGFW_UNUSED(win);
2377 return !RGFW_isPressedGamepad(win, controller, button) && RGFW_wasPressedGamepad(win, controller, button);
2378}
2379u32 RGFW_isHeldGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button) {
2380 RGFW_UNUSED(win);
2381 return RGFW_isPressedGamepad(win, controller, button) && RGFW_wasPressedGamepad(win, controller, button);
2382}
2384RGFW_point RGFW_getGamepadAxis(RGFW_window* win, u16 controller, u16 whichAxis) {
2385 RGFW_UNUSED(win);
2386 return RGFW_gamepadAxes[controller][whichAxis];
2387}
2388const char* RGFW_getGamepadName(RGFW_window* win, u16 controller) {
2389 RGFW_UNUSED(win);
2390 return (const char*)RGFW_gamepads_name[controller];
2391}
2393size_t RGFW_getGamepadCount(RGFW_window* win) {
2394 RGFW_UNUSED(win);
2395 return RGFW_gamepadCount;
2396}
2398RGFW_gamepadType RGFW_getGamepadType(RGFW_window* win, u16 controller) {
2399 RGFW_UNUSED(win);
2400 return RGFW_gamepads_type[controller];
2401}
2403RGFWDEF void RGFW_updateKeyMod(RGFW_window* win, RGFW_keymod mod, RGFW_bool value);
2404void RGFW_updateKeyMod(RGFW_window* win, RGFW_keymod mod, RGFW_bool value) {
2405 if (value) win->event.keyMod |= mod;
2406 else win->event.keyMod &= ~mod;
2407}
2409RGFWDEF void RGFW_updateKeyModsPro(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll);
2410void RGFW_updateKeyModsPro(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll) {
2411 RGFW_updateKeyMod(win, RGFW_modCapsLock, capital);
2412 RGFW_updateKeyMod(win, RGFW_modNumLock, numlock);
2413 RGFW_updateKeyMod(win, RGFW_modControl, control);
2414 RGFW_updateKeyMod(win, RGFW_modAlt, alt);
2415 RGFW_updateKeyMod(win, RGFW_modShift, shift);
2416 RGFW_updateKeyMod(win, RGFW_modSuper, super);
2417 RGFW_updateKeyMod(win, RGFW_modScrollLock, scroll);
2418}
2420RGFWDEF void RGFW_updateKeyMods(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool scroll);
2421void RGFW_updateKeyMods(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool scroll) {
2422 RGFW_updateKeyModsPro(win, capital, numlock,
2423 RGFW_isPressed(win, RGFW_controlL) || RGFW_isPressed(win, RGFW_controlR),
2424 RGFW_isPressed(win, RGFW_altL) || RGFW_isPressed(win, RGFW_altR),
2425 RGFW_isPressed(win, RGFW_shiftL) || RGFW_isPressed(win, RGFW_shiftR),
2426 RGFW_isPressed(win, RGFW_superL) || RGFW_isPressed(win, RGFW_superR),
2427 scroll);
2428}
2430RGFWDEF void RGFW_window_showMouseFlags(RGFW_window* win, RGFW_bool show);
2431void RGFW_window_showMouseFlags(RGFW_window* win, RGFW_bool show) {
2432 if (show && (win->_flags & RGFW_windowHideMouse))
2433 win->_flags ^= RGFW_windowHideMouse;
2434 else if (!show && !(win->_flags & RGFW_windowHideMouse))
2435 win->_flags |= RGFW_windowHideMouse;
2436}
2438RGFW_bool RGFW_window_mouseHidden(RGFW_window* win) {
2439 return (RGFW_bool)RGFW_BOOL(win->_flags & RGFW_windowHideMouse);
2440}
2442RGFW_bool RGFW_window_borderless(RGFW_window* win) {
2443 return (RGFW_bool)RGFW_BOOL(win->_flags & RGFW_windowNoBorder);
2444}
2446RGFW_bool RGFW_window_isFullscreen(RGFW_window* win){ return RGFW_BOOL(win->_flags & RGFW_windowFullscreen); }
2447RGFW_bool RGFW_window_allowsDND(RGFW_window* win) { return RGFW_BOOL(win->_flags & RGFW_windowAllowDND); }
2449void RGFW_window_focusLost(RGFW_window* win) {
2450 /* standard routines for when a window looses focus */
2451 _RGFW.root->_flags &= ~(u32)RGFW_windowFocus;
2452 if ((win->_flags & RGFW_windowFullscreen))
2453 RGFW_window_minimize(win);
2455 for (size_t key = 0; key < RGFW_keyLast; key++) {
2456 if (RGFW_isPressed(NULL, (u8)key) == RGFW_FALSE) continue;
2457 RGFW_keyboard[key].current = RGFW_FALSE;
2458 u8 keyChar = RGFW_rgfwToKeyChar((u32)key);
2459 RGFW_keyCallback(win, (u8)key, keyChar, win->event.keyMod, RGFW_FALSE);
2460 RGFW_eventQueuePushEx(e.type = RGFW_keyReleased;
2461 e.key = (u8)key;
2462 e.keyChar = keyChar;
2463 e.repeat = RGFW_FALSE;
2464 e.keyMod = win->event.keyMod;
2465 e._win = win);
2466 }
2468 RGFW_resetKey();
2469}
2471#ifndef RGFW_WINDOWS
2472void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow) {
2473 RGFW_setBit(&win->_flags, RGFW_windowAllowDND, allow);
2474}
2475#endif
2477#if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WASM) || defined(RGFW_WAYLAND)
2478#ifndef __USE_POSIX199309
2479 #define __USE_POSIX199309
2480#endif
2481#include <time.h>
2482struct timespec;
2483#endif
2485#if defined(RGFW_WAYLAND) || defined(RGFW_X11) || defined(RGFW_WINDOWS)
2486void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) {
2487 RGFW_window_showMouseFlags(win, show);
2488 if (show == 0)
2489 RGFW_window_setMouse(win, _RGFW.hiddenMouse);
2490 else
2491 RGFW_window_setMouseDefault(win);
2492}
2493#endif
2495#ifndef RGFW_MACOS
2496void RGFW_moveToMacOSResourceDir(void) { }
2497#endif
2499/*
2500 graphics API specific code (end of generic code)
2501 starts here
2502*/
2505/*
2506 OpenGL defines start here (Normal, EGL, OSMesa)
2507*/
2509#if defined(RGFW_OPENGL) || defined(RGFW_EGL)
2511#ifdef RGFW_WINDOWS
2512 #define WIN32_LEAN_AND_MEAN
2513 #define OEMRESOURCE
2514 #include <windows.h>
2515#endif
2517#if !defined(__APPLE__) && !defined(RGFW_NO_GL_HEADER)
2518 #include <GL/gl.h>
2519#elif defined(__APPLE__)
2520 #ifndef GL_SILENCE_DEPRECATION
2521 #define GL_SILENCE_DEPRECATION
2522 #endif
2523 #include <OpenGL/gl.h>
2524 #include <OpenGL/OpenGL.h>
2525#endif
2527/* EGL, normal OpenGL only */
2528#ifndef RGFW_EGL
2529i32 RGFW_GL_HINTS[RGFW_glFinalHint] = {8,
2530#else
2531i32 RGFW_GL_HINTS[RGFW_glFinalHint] = {0,
2532#endif
2533 0, 0, 0, 1, 8, 8, 8, 8, 24, 0, 0, 0, 0, 0, 0, 0, 0, RGFW_glReleaseNone, RGFW_glCore, 0, 0};
2535void RGFW_setGLHint(RGFW_glHints hint, i32 value) {
2536 if (hint < RGFW_glFinalHint && hint) RGFW_GL_HINTS[hint] = value;
2537}
2539RGFW_bool RGFW_extensionSupportedStr(const char* extensions, const char* ext, size_t len) {
2540 const char *start = extensions;
2541 const char *where;
2542 const char* terminator;
2544 if (extensions == NULL || ext == NULL)
2545 return RGFW_FALSE;
2547 where = strstr(extensions, ext);
2548 while (where) {
2549 terminator = where + len;
2550 if ((where == start || *(where - 1) == ' ') &&
2551 (*terminator == ' ' || *terminator == '\0')) {
2552 return RGFW_TRUE;
2553 }
2554 where = RGFW_STRSTR(terminator, ext);
2555 }
2557 return RGFW_FALSE;
2558}
2560RGFW_bool RGFW_extensionSupported(const char* extension, size_t len) {
2561 #ifdef GL_NUM_EXTENSIONS
2562 if (RGFW_GL_HINTS[RGFW_glMajor] >= 3) {
2563 i32 i;
2564 GLint count = 0;
2566 RGFW_proc RGFW_glGetStringi = RGFW_getProcAddress("glGetStringi");
2567 RGFW_proc RGFW_glGetIntegerv = RGFW_getProcAddress("RGFW_glGetIntegerv");
2568 if (RGFW_glGetIntegerv)
2569 ((void(*)(GLenum, GLint*))RGFW_glGetIntegerv)(GL_NUM_EXTENSIONS, &count);
2571 for (i = 0; RGFW_glGetStringi && i < count; i++) {
2572 const char* en = ((const char* (*)(u32, u32))RGFW_glGetStringi)(GL_EXTENSIONS, (u32)i);
2573 if (en && RGFW_STRNCMP(en, extension, len) == 0)
2574 return RGFW_TRUE;
2575 }
2576 } else
2577#endif
2578 {
2579 RGFW_proc RGFW_glGetString = RGFW_getProcAddress("glGetString");
2581 if (RGFW_glGetString) {
2582 const char* extensions = ((const char*(*)(u32))RGFW_glGetString)(GL_EXTENSIONS);
2583 if ((extensions != NULL) && RGFW_extensionSupportedStr(extensions, extension, len))
2584 return RGFW_TRUE;
2585 }
2586 }
2588 return RGFW_extensionSupportedPlatform(extension, len);
2589}
2591/* OPENGL normal only (no EGL / OSMesa) */
2592#if defined(RGFW_OPENGL) && !defined(RGFW_EGL) && !defined(RGFW_CUSTOM_BACKEND) && !defined(RGFW_WASM)
2594#define RGFW_GL_RENDER_TYPE RGFW_OS_BASED_VALUE(GLX_X_VISUAL_TYPE, 0x2003, 73, 0)
2595 #define RGFW_GL_ALPHA_SIZE RGFW_OS_BASED_VALUE(GLX_ALPHA_SIZE, 0x201b, 11, 0)
2596 #define RGFW_GL_DEPTH_SIZE RGFW_OS_BASED_VALUE(GLX_DEPTH_SIZE, 0x2022, 12, 0)
2597 #define RGFW_GL_DOUBLEBUFFER RGFW_OS_BASED_VALUE(GLX_DOUBLEBUFFER, 0x2011, 5, 0)
2598 #define RGFW_GL_STENCIL_SIZE RGFW_OS_BASED_VALUE(GLX_STENCIL_SIZE, 0x2023, 13, 0)
2599 #define RGFW_GL_SAMPLES RGFW_OS_BASED_VALUE(GLX_SAMPLES, 0x2042, 55, 0)
2600 #define RGFW_GL_STEREO RGFW_OS_BASED_VALUE(GLX_STEREO, 0x2012, 6, 0)
2601 #define RGFW_GL_AUX_BUFFERS RGFW_OS_BASED_VALUE(GLX_AUX_BUFFERS, 0x2024, 7, 0)
2603#if defined(RGFW_X11) || defined(RGFW_WINDOWS)
2604 #define RGFW_GL_DRAW RGFW_OS_BASED_VALUE(GLX_X_RENDERABLE, 0x2001, 0, 0)
2605 #define RGFW_GL_DRAW_TYPE RGFW_OS_BASED_VALUE(GLX_RENDER_TYPE, 0x2013, 0, 0)
2606 #define RGFW_GL_FULL_FORMAT RGFW_OS_BASED_VALUE(GLX_TRUE_COLOR, 0x2027, 0, 0)
2607 #define RGFW_GL_RED_SIZE RGFW_OS_BASED_VALUE(GLX_RED_SIZE, 0x2015, 0, 0)
2608 #define RGFW_GL_GREEN_SIZE RGFW_OS_BASED_VALUE(GLX_GREEN_SIZE, 0x2017, 0, 0)
2609 #define RGFW_GL_BLUE_SIZE RGFW_OS_BASED_VALUE(GLX_BLUE_SIZE, 0x2019, 0, 0)
2610 #define RGFW_GL_USE_RGBA RGFW_OS_BASED_VALUE(GLX_RGBA_BIT, 0x202B, 0, 0)
2611 #define RGFW_GL_ACCUM_RED_SIZE RGFW_OS_BASED_VALUE(14, 0x201E, 0, 0)
2612 #define RGFW_GL_ACCUM_GREEN_SIZE RGFW_OS_BASED_VALUE(15, 0x201F, 0, 0)
2613 #define RGFW_GL_ACCUM_BLUE_SIZE RGFW_OS_BASED_VALUE(16, 0x2020, 0, 0)
2614 #define RGFW_GL_ACCUM_ALPHA_SIZE RGFW_OS_BASED_VALUE(17, 0x2021, 0, 0)
2615 #define RGFW_GL_SRGB RGFW_OS_BASED_VALUE(0x20b2, 0x3089, 0, 0)
2616 #define RGFW_GL_NOERROR RGFW_OS_BASED_VALUE(0x31b3, 0x31b3, 0, 0)
2617 #define RGFW_GL_FLAGS RGFW_OS_BASED_VALUE(GLX_CONTEXT_FLAGS_ARB, 0x2094, 0, 0)
2618 #define RGFW_GL_RELEASE_BEHAVIOR RGFW_OS_BASED_VALUE(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, 0x2097 , 0, 0)
2619 #define RGFW_GL_CONTEXT_RELEASE RGFW_OS_BASED_VALUE(GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB, 0x2098, 0, 0)
2620 #define RGFW_GL_CONTEXT_NONE RGFW_OS_BASED_VALUE(GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB, 0x0000, 0, 0)
2621 #define RGFW_GL_FLAGS RGFW_OS_BASED_VALUE(GLX_CONTEXT_FLAGS_ARB, 0x2094, 0, 0)
2622 #define RGFW_GL_DEBUG_BIT RGFW_OS_BASED_VALUE(GLX_CONTEXT_FLAGS_ARB, 0x2094, 0, 0)
2623 #define RGFW_GL_ROBUST_BIT RGFW_OS_BASED_VALUE(GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB, 0x00000004, 0, 0)
2624#endif
2626#ifdef RGFW_WINDOWS
2627 #define WGL_SUPPORT_OPENGL_ARB 0x2010
2628 #define WGL_COLOR_BITS_ARB 0x2014
2629 #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
2630 #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
2631 #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
2632 #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
2633 #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
2634 #define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
2635 #define WGL_SAMPLE_BUFFERS_ARB 0x2041
2636 #define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9
2637 #define WGL_PIXEL_TYPE_ARB 0x2013
2638 #define WGL_TYPE_RGBA_ARB 0x202B
2640 #define WGL_TRANSPARENT_ARB 0x200A
2641#endif
2643/* The window'ing api needs to know how to render the data we (or opengl) give it
2644 MacOS and Windows do this using a structure called a "pixel format"
2645 X11 calls it a "Visual"
2646 This function returns the attributes for the format we want */
2647i32* RGFW_initFormatAttribs(void);
2648i32* RGFW_initFormatAttribs(void) {
2649 static i32 attribs[] = {
2650 #if defined(RGFW_X11) || defined(RGFW_WINDOWS)
2651 RGFW_GL_RENDER_TYPE,
2652 RGFW_GL_FULL_FORMAT,
2653 RGFW_GL_DRAW, 1,
2654 RGFW_GL_DRAW_TYPE , RGFW_GL_USE_RGBA,
2655 #endif
2657 #ifdef RGFW_X11
2658 GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT,
2659 #endif
2661 #ifdef RGFW_MACOS
2662 72,
2663 8, 24,
2664 #endif
2666 #ifdef RGFW_WINDOWS
2667 WGL_SUPPORT_OPENGL_ARB, 1,
2668 WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
2669 WGL_COLOR_BITS_ARB, 32,
2670 #endif
2671 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
2672 };
2674 size_t index = (sizeof(attribs) / sizeof(attribs[0])) - 27;
2676 #define RGFW_GL_ADD_ATTRIB(attrib, attVal) \
2677 if (attVal) { \
2678 attribs[index] = attrib;\
2679 attribs[index + 1] = attVal;\
2680 index += 2;\
2681 }
2683 #if defined(RGFW_MACOS) && defined(RGFW_COCOA_GRAPHICS_SWITCHING)
2684 RGFW_GL_ADD_ATTRIB(96, kCGLPFASupportsAutomaticGraphicsSwitching);
2685 #endif
2687 RGFW_GL_ADD_ATTRIB(RGFW_GL_DOUBLEBUFFER, 1);
2689 RGFW_GL_ADD_ATTRIB(RGFW_GL_ALPHA_SIZE, RGFW_GL_HINTS[RGFW_glAlpha]);
2690 RGFW_GL_ADD_ATTRIB(RGFW_GL_DEPTH_SIZE, RGFW_GL_HINTS[RGFW_glDepth]);
2691 RGFW_GL_ADD_ATTRIB(RGFW_GL_STENCIL_SIZE, RGFW_GL_HINTS[RGFW_glStencil]);
2692 RGFW_GL_ADD_ATTRIB(RGFW_GL_STEREO, RGFW_GL_HINTS[RGFW_glStereo]);
2693 RGFW_GL_ADD_ATTRIB(RGFW_GL_AUX_BUFFERS, RGFW_GL_HINTS[RGFW_glAuxBuffers]);
2695 #if defined(RGFW_X11) || defined(RGFW_WINDOWS)
2696 RGFW_GL_ADD_ATTRIB(RGFW_GL_RED_SIZE, RGFW_GL_HINTS[RGFW_glRed]);
2697 RGFW_GL_ADD_ATTRIB(RGFW_GL_GREEN_SIZE, RGFW_GL_HINTS[RGFW_glBlue]);
2698 RGFW_GL_ADD_ATTRIB(RGFW_GL_BLUE_SIZE, RGFW_GL_HINTS[RGFW_glGreen]);
2699 #endif
2701 #if defined(RGFW_X11) || defined(RGFW_WINDOWS)
2702 RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_RED_SIZE, RGFW_GL_HINTS[RGFW_glAccumRed]);
2703 RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_GREEN_SIZE, RGFW_GL_HINTS[RGFW_glAccumBlue]);
2704 RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_BLUE_SIZE, RGFW_GL_HINTS[RGFW_glAccumGreen]);
2705 RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_ALPHA_SIZE, RGFW_GL_HINTS[RGFW_glAccumAlpha]);
2706 RGFW_GL_ADD_ATTRIB(RGFW_GL_SRGB, RGFW_GL_HINTS[RGFW_glSRGB]);
2707 RGFW_GL_ADD_ATTRIB(RGFW_GL_NOERROR, RGFW_GL_HINTS[RGFW_glNoError]);
2709 if (RGFW_GL_HINTS[RGFW_glReleaseBehavior] == RGFW_releaseFlush) {
2710 RGFW_GL_ADD_ATTRIB(RGFW_GL_RELEASE_BEHAVIOR, RGFW_GL_CONTEXT_RELEASE);
2711 } else if (RGFW_GL_HINTS[RGFW_glReleaseBehavior] == RGFW_glReleaseNone) {
2712 RGFW_GL_ADD_ATTRIB(RGFW_GL_RELEASE_BEHAVIOR, RGFW_GL_CONTEXT_NONE);
2713 }
2715 i32 flags = 0;
2716 if (RGFW_GL_HINTS[RGFW_glDebug]) flags |= RGFW_GL_DEBUG_BIT;
2717 if (RGFW_GL_HINTS[RGFW_glRobustness]) flags |= RGFW_GL_ROBUST_BIT;
2718 RGFW_GL_ADD_ATTRIB(RGFW_GL_FLAGS, flags);
2719 #else
2720 i32 accumSize = (i32)(RGFW_GL_HINTS[RGFW_glAccumRed] + RGFW_GL_HINTS[RGFW_glAccumGreen] + RGFW_GL_HINTS[RGFW_glAccumBlue] + RGFW_GL_HINTS[RGFW_glAccumAlpha]) / 4;
2721 RGFW_GL_ADD_ATTRIB(14, accumSize);
2722 #endif
2724 #ifndef RGFW_X11
2725 RGFW_GL_ADD_ATTRIB(RGFW_GL_SAMPLES, RGFW_GL_HINTS[RGFW_glSamples]);
2726 #endif
2728 #ifdef RGFW_MACOS
2729 if (_RGFW.root->_flags & RGFW_windowOpenglSoftware) {
2730 RGFW_GL_ADD_ATTRIB(70, kCGLRendererGenericFloatID);
2731 } else {
2732 attribs[index] = RGFW_GL_RENDER_TYPE;
2733 index += 1;
2734 }
2735 #endif
2737 #ifdef RGFW_MACOS
2738 /* macOS has the surface attribs and the opengl attribs connected for some reason
2739 maybe this is to give macOS more control to limit openGL/the opengl version? */
2741 attribs[index] = 99;
2742 attribs[index + 1] = 0x1000;
2745 if (RGFW_GL_HINTS[RGFW_glMajor] >= 4 || RGFW_GL_HINTS[RGFW_glMajor] >= 3) {
2746 attribs[index + 1] = (i32) ((RGFW_GL_HINTS[RGFW_glMajor] >= 4) ? 0x4100 : 0x3200);
2747 }
2748 #endif
2750 RGFW_GL_ADD_ATTRIB(0, 0);
2752 return attribs;
2753}
2755/* EGL only (no OSMesa nor normal OPENGL) */
2756#elif defined(RGFW_EGL)
2758#include <EGL/egl.h>
2760#if defined(RGFW_LINK_EGL)
2761 typedef EGLBoolean(EGLAPIENTRY* PFN_eglInitialize)(EGLDisplay, EGLint*, EGLint*);
2763 PFNEGLINITIALIZEPROC eglInitializeSource;
2764 PFNEGLGETCONFIGSPROC eglGetConfigsSource;
2765 PFNEGLCHOOSECONFIgamepadROC eglChooseConfigSource;
2766 PFNEGLCREATEWINDOWSURFACEPROC eglCreateWindowSurfaceSource;
2767 PFNEGLCREATECONTEXTPROC eglCreateContextSource;
2768 PFNEGLMAKECURRENTPROC eglMakeCurrentSource;
2769 PFNEGLGETDISPLAYPROC eglGetDisplaySource;
2770 PFNEGLSWAPBUFFERSPROC eglSwapBuffersSource;
2771 PFNEGLSWAPINTERVALPROC eglSwapIntervalSource;
2772 PFNEGLBINDAPIPROC eglBindAPISource;
2773 PFNEGLDESTROYCONTEXTPROC eglDestroyContextSource;
2774 PFNEGLTERMINATEPROC eglTerminateSource;
2775 PFNEGLDESTROYSURFACEPROC eglDestroySurfaceSource;
2777 #define eglInitialize eglInitializeSource
2778 #define eglGetConfigs eglGetConfigsSource
2779 #define eglChooseConfig eglChooseConfigSource
2780 #define eglCreateWindowSurface eglCreateWindowSurfaceSource
2781 #define eglCreateContext eglCreateContextSource
2782 #define eglMakeCurrent eglMakeCurrentSource
2783 #define eglGetDisplay eglGetDisplaySource
2784 #define eglSwapBuffers eglSwapBuffersSource
2785 #define eglSwapInterval eglSwapIntervalSource
2786 #define eglBindAPI eglBindAPISource
2787 #define eglDestroyContext eglDestroyContextSource
2788 #define eglTerminate eglTerminateSource
2789 #define eglDestroySurface eglDestroySurfaceSource;
2790#endif
2793#define EGL_SURFACE_MAJOR_VERSION_KHR 0x3098
2794#define EGL_SURFACE_MINOR_VERSION_KHR 0x30fb
2796#ifndef RGFW_GL_ADD_ATTRIB
2797#define RGFW_GL_ADD_ATTRIB(attrib, attVal) \
2798 if (attVal) { \
2799 attribs[index] = attrib;\
2800 attribs[index + 1] = attVal;\
2801 index += 2;\
2802 }
2803#endif
2806void RGFW_window_initOpenGL(RGFW_window* win) {
2807#if defined(RGFW_LINK_EGL)
2808 eglInitializeSource = (PFNEGLINITIALIZEPROC) eglGetProcAddress("eglInitialize");
2809 eglGetConfigsSource = (PFNEGLGETCONFIGSPROC) eglGetProcAddress("eglGetConfigs");
2810 eglChooseConfigSource = (PFNEGLCHOOSECONFIgamepadROC) eglGetProcAddress("eglChooseConfig");
2811 eglCreateWindowSurfaceSource = (PFNEGLCREATEWINDOWSURFACEPROC) eglGetProcAddress("eglCreateWindowSurface");
2812 eglCreateContextSource = (PFNEGLCREATECONTEXTPROC) eglGetProcAddress("eglCreateContext");
2813 eglMakeCurrentSource = (PFNEGLMAKECURRENTPROC) eglGetProcAddress("eglMakeCurrent");
2814 eglGetDisplaySource = (PFNEGLGETDISPLAYPROC) eglGetProcAddress("eglGetDisplay");
2815 eglSwapBuffersSource = (PFNEGLSWAPBUFFERSPROC) eglGetProcAddress("eglSwapBuffers");
2816 eglSwapIntervalSource = (PFNEGLSWAPINTERVALPROC) eglGetProcAddress("eglSwapInterval");
2817 eglBindAPISource = (PFNEGLBINDAPIPROC) eglGetProcAddress("eglBindAPI");
2818 eglDestroyContextSource = (PFNEGLDESTROYCONTEXTPROC) eglGetProcAddress("eglDestroyContext");
2819 eglTerminateSource = (PFNEGLTERMINATEPROC) eglGetProcAddress("eglTerminate");
2820 eglDestroySurfaceSource = (PFNEGLDESTROYSURFACEPROC) eglGetProcAddress("eglDestroySurface");
2822 RGFW_ASSERT(eglInitializeSource != NULL &&
2823 eglGetConfigsSource != NULL &&
2824 eglChooseConfigSource != NULL &&
2825 eglCreateWindowSurfaceSource != NULL &&
2826 eglCreateContextSource != NULL &&
2827 eglMakeCurrentSource != NULL &&
2828 eglGetDisplaySource != NULL &&
2829 eglSwapBuffersSource != NULL &&
2830 eglSwapIntervalsSource != NULL &&
2831 eglBindAPISource != NULL &&
2832 eglDestroyContextSource != NULL &&
2833 eglTerminateSource != NULL &&
2834 eglDestroySurfaceSource != NULL);
2835#endif /* RGFW_LINK_EGL */
2837#ifdef RGFW_WAYLAND
2838 if (RGFW_useWaylandBool)
2839 win->src.eglWindow = wl_egl_window_create(win->src.surface, win->r.w, win->r.h);
2840#endif
2842 #ifdef RGFW_WINDOWS
2843 win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.hdc);
2844 #elif defined(RGFW_MACOS)
2845 win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType)0);
2846 #elif defined(RGFW_WAYLAND)
2847 if (RGFW_useWaylandBool)
2848 win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.wl_display);
2849 else
2850 #endif
2851 #ifdef RGFW_X11
2852 win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.display);
2853 #else
2854 {}
2855 #endif
2856 #if !defined(RGFW_WAYLAND) && !defined(RGFW_WINDOWS) && !defined(RGFW_X11)
2857 win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.display);
2858 #endif
2860 EGLint major, minor;
2862 eglInitialize(win->src.EGL_display, &major, &minor);
2864 #ifndef EGL_OPENGL_ES1_BIT
2865 #define EGL_OPENGL_ES1_BIT 0x1
2866 #endif
2868 EGLint egl_config[24] = {
2869 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
2870 EGL_RENDERABLE_TYPE,
2871 #ifdef RGFW_OPENGL_ES1
2872 EGL_OPENGL_ES1_BIT,
2873 #elif defined(RGFW_OPENGL_ES3)
2874 EGL_OPENGL_ES3_BIT,
2875 #elif defined(RGFW_OPENGL_ES2)
2876 EGL_OPENGL_ES2_BIT,
2877 #else
2878 EGL_OPENGL_BIT,
2879 #endif
2880 EGL_NONE, EGL_NONE
2881 };
2883 {
2884 size_t index = 7;
2885 EGLint* attribs = egl_config;
2887 RGFW_GL_ADD_ATTRIB(EGL_RED_SIZE, RGFW_GL_HINTS[RGFW_glRed]);
2888 RGFW_GL_ADD_ATTRIB(EGL_GREEN_SIZE, RGFW_GL_HINTS[RGFW_glBlue]);
2889 RGFW_GL_ADD_ATTRIB(EGL_BLUE_SIZE, RGFW_GL_HINTS[RGFW_glGreen]);
2890 RGFW_GL_ADD_ATTRIB(EGL_ALPHA_SIZE, RGFW_GL_HINTS[RGFW_glAlpha]);
2891 RGFW_GL_ADD_ATTRIB(EGL_DEPTH_SIZE, RGFW_GL_HINTS[RGFW_glDepth]);
2893 if (RGFW_GL_HINTS[RGFW_glSRGB])
2894 RGFW_GL_ADD_ATTRIB(0x3089, RGFW_GL_HINTS[RGFW_glSRGB]);
2896 RGFW_GL_ADD_ATTRIB(EGL_NONE, EGL_NONE);
2897 }
2899 EGLConfig config;
2900 EGLint numConfigs;
2901 eglChooseConfig(win->src.EGL_display, egl_config, &config, 1, &numConfigs);
2903 #if defined(RGFW_MACOS)
2904 void* layer = RGFW_cocoaGetLayer();
2906 RGFW_window_cocoaSetLayer(win, layer);
2908 win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) layer, NULL);
2909 #elif defined(RGFW_WINDOWS)
2910 win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL);
2911 #elif defined(RGFW_WAYLAND)
2912 if (RGFW_useWaylandBool)
2913 win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.eglWindow, NULL);
2914 else
2915 #endif
2916 #ifdef RGFW_X11
2917 win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL);
2918 #else
2919 {}
2920 #endif
2921 #if !defined(RGFW_X11) && !defined(RGFW_WAYLAND) && !defined(RGFW_MACOS)
2922 win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL);
2923 #endif
2925 EGLint attribs[12];
2926 size_t index = 0;
2928#ifdef RGFW_OPENGL_ES1
2929 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, 1);
2930#elif defined(RGFW_OPENGL_ES2)
2931 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, 2);
2932#elif defined(RGFW_OPENGL_ES3)
2933 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, 3);
2934#endif
2936 RGFW_GL_ADD_ATTRIB(EGL_STENCIL_SIZE, RGFW_GL_HINTS[RGFW_glStencil]);
2937 RGFW_GL_ADD_ATTRIB(EGL_SAMPLES, RGFW_GL_HINTS[RGFW_glSamples]);
2939 if (RGFW_GL_HINTS[RGFW_glDoubleBuffer] == 0)
2940 RGFW_GL_ADD_ATTRIB(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER);
2942 if (RGFW_GL_HINTS[RGFW_glMajor]) {
2943 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_MAJOR_VERSION, RGFW_GL_HINTS[RGFW_glMajor]);
2944 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_MINOR_VERSION, RGFW_GL_HINTS[RGFW_glMinor]);
2946 if (RGFW_GL_HINTS[RGFW_glProfile] == RGFW_glCore) {
2947 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT);
2948 }
2949 else {
2950 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT);
2951 }
2952 }
2954 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_ROBUST_ACCESS, RGFW_GL_HINTS[RGFW_glRobustness]);
2955 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_DEBUG, RGFW_GL_HINTS[RGFW_glDebug]);
2956 if (RGFW_GL_HINTS[RGFW_glReleaseBehavior] == RGFW_releaseFlush) {
2957 RGFW_GL_ADD_ATTRIB(0x2097, 0x2098);
2958 } else {
2959 RGFW_GL_ADD_ATTRIB(0x2096, 0x0000);
2960 }
2962 RGFW_GL_ADD_ATTRIB(EGL_NONE, EGL_NONE);
2964 #if defined(RGFW_OPENGL_ES1) || defined(RGFW_OPENGL_ES2) || defined(RGFW_OPENGL_ES3)
2965 eglBindAPI(EGL_OPENGL_ES_API);
2966 #else
2967 eglBindAPI(EGL_OPENGL_API);
2968 #endif
2970 win->src.EGL_context = eglCreateContext(win->src.EGL_display, config, EGL_NO_CONTEXT, attribs);
2972 if (win->src.EGL_context == NULL) {
2973 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errEGLContext, RGFW_DEBUG_CTX(win, 0), "failed to create an EGL opengl context");
2974 return;
2975 }
2977 eglMakeCurrent(win->src.EGL_display, win->src.EGL_surface, win->src.EGL_surface, win->src.EGL_context);
2978 eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface);
2979 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "EGL opengl context initalized");
2980}
2982void RGFW_window_freeOpenGL(RGFW_window* win) {
2983 if (win->src.EGL_display == NULL) return;
2985 eglDestroySurface(win->src.EGL_display, win->src.EGL_surface);
2986 eglDestroyContext(win->src.EGL_display, win->src.EGL_context);
2987 eglTerminate(win->src.EGL_display);
2988 win->src.EGL_display = NULL;
2989 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "EGL opengl context freed");
2990}
2992void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
2993 if (win == NULL)
2994 eglMakeCurrent(_RGFW.root->src.EGL_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
2995 else {
2996 eglMakeCurrent(win->src.EGL_display, win->src.EGL_surface, win->src.EGL_surface, win->src.EGL_context);
2997 }
2998}
3000void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface); }
3002void* RGFW_getCurrent_OpenGL(void) { return eglGetCurrentContext(); }
3004#ifdef RGFW_APPLE
3005void* RGFWnsglFramework = NULL;
3006#elif defined(RGFW_WINDOWS)
3007HMODULE RGFW_wgl_dll = NULL;
3008#endif
3010RGFW_proc RGFW_getProcAddress(const char* procname) {
3011 #if defined(RGFW_WINDOWS)
3012 RGFW_proc proc = (RGFW_proc) GetProcAddress(RGFW_wgl_dll, procname);
3014 if (proc)
3015 return proc;
3016 #endif
3018 return (RGFW_proc) eglGetProcAddress(procname);
3019}
3021RGFW_bool RGFW_extensionSupportedPlatform(const char* extension, size_t len) {
3022 const char* extensions = eglQueryString(_RGFW.root->src.EGL_display, EGL_EXTENSIONS);
3023 return extensions != NULL && RGFW_extensionSupportedStr(extensions, extension, len);
3024}
3026void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) {
3027 RGFW_ASSERT(win != NULL);
3029 eglSwapInterval(win->src.EGL_display, swapInterval);
3031}
3033#endif /* RGFW_EGL */
3035/*
3036 end of RGFW_EGL defines
3037*/
3038#endif /* end of RGFW_GL (OpenGL, EGL, OSMesa )*/
3040/*
3041 RGFW_VULKAN defines
3042*/
3043#ifdef RGFW_VULKAN
3044#ifdef RGFW_MACOS
3045#include <objc/message.h>
3046#endif
3048const char** RGFW_getVKRequiredInstanceExtensions(size_t* count) {
3049 static const char* arr[2] = {VK_KHR_SURFACE_EXTENSION_NAME};
3050 arr[1] = RGFW_VK_SURFACE;
3051 if (count != NULL) *count = 2;
3053 return (const char**)arr;
3054}
3056VkResult RGFW_window_createVKSurface(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface) {
3057 RGFW_ASSERT(win != NULL); RGFW_ASSERT(instance);
3058 RGFW_ASSERT(surface != NULL);
3060 *surface = VK_NULL_HANDLE;
3062#ifdef RGFW_X11
3063 RGFW_GOTO_WAYLAND(0);
3064 VkXlibSurfaceCreateInfoKHR x11 = { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, 0, 0, (Display*) win->src.display, (Window) win->src.window };
3065 return vkCreateXlibSurfaceKHR(instance, &x11, NULL, surface);
3066#endif
3067#if defined(RGFW_WAYLAND)
3068RGFW_WAYLAND_LABEL
3069 VkWaylandSurfaceCreateInfoKHR wayland = { VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, 0, 0, (struct wl_display*) win->src.wl_display, (struct wl_surface*) win->src.surface };
3070 return vkCreateWaylandSurfaceKHR(instance, &wayland, NULL, surface);
3071#elif defined(RGFW_WINDOWS)
3072 VkWin32SurfaceCreateInfoKHR win32 = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, 0, 0, GetModuleHandle(NULL), (HWND)win->src.window };
3074 return vkCreateWin32SurfaceKHR(instance, &win32, NULL, surface);
3075#elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11)
3076 void* contentView = ((void* (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_getUid("contentView"));
3077 VkMacOSSurfaceCreateFlagsMVK macos = { VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK, 0, 0, win->src.display, (void*)contentView };
3079 return vkCreateMacOSSurfaceMVK(instance, &macos, NULL, surface);
3080#endif
3081}
3084RGFW_bool RGFW_getVKPresentationSupport(VkInstance instance, VkPhysicalDevice physicalDevice, u32 queueFamilyIndex) {
3085 RGFW_ASSERT(instance);
3086 if (_RGFW.windowCount == -1 || _RGFW_init == RGFW_FALSE) RGFW_init();
3087#ifdef RGFW_X11
3088 RGFW_GOTO_WAYLAND(0);
3089 Visual* visual = DefaultVisual(_RGFW.display, DefaultScreen(_RGFW.display));
3090 if (_RGFW.root)
3091 visual = _RGFW.root->src.visual.visual;
3093 RGFW_bool out = vkGetPhysicalDeviceXlibPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW.display, XVisualIDFromVisual(visual));
3094 return out;
3095#endif
3096#if defined(RGFW_WAYLAND)
3097RGFW_WAYLAND_LABEL
3098 RGFW_bool wlout = vkGetPhysicalDeviceWaylandPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW.wl_display);
3099 return wlout;
3100#elif defined(RGFW_WINDOWS)
3101#elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11)
3102 return RGFW_FALSE; /* TODO */
3103#endif
3104}
3105#endif /* end of RGFW_vulkan */
3107/*
3108This is where OS specific stuff starts
3109*/
3112#if (defined(RGFW_WAYLAND) || defined(RGFW_X11)) && !defined(RGFW_NO_LINUX)
3113 int RGFW_eventWait_forceStop[] = {0, 0, 0}; /* for wait events */
3115 #if defined(__linux__)
3116 #include <linux/joystick.h>
3117 #include <fcntl.h>
3118 #include <unistd.h>
3119 #include <errno.h>
3121 u32 RGFW_linux_updateGamepad(RGFW_window* win);
3122 u32 RGFW_linux_updateGamepad(RGFW_window* win) {
3123 /* check for new gamepads */
3124 static const char* str[] = {"/dev/input/js0", "/dev/input/js1", "/dev/input/js2", "/dev/input/js3", "/dev/input/js4", "/dev/input/js5"};
3125 static u8 RGFW_rawGamepads[6];
3126 {
3127 u16 i;
3128 for (i = 0; i < 6; i++) {
3129 u16 index = RGFW_gamepadCount;
3130 if (RGFW_rawGamepads[i]) {
3131 struct input_id device_info;
3132 if (ioctl(RGFW_rawGamepads[i], EVIOCGID, &device_info) == -2) {
3133 if (errno == ENODEV) {
3134 RGFW_rawGamepads[i] = 0;
3135 }
3136 }
3137 continue;
3138 }
3140 i32 js = open(str[i], O_RDONLY);
3142 if (js <= 0)
3143 break;
3145 if (RGFW_gamepadCount >= 4) {
3146 close(js);
3147 break;
3148 }
3150 RGFW_rawGamepads[i] = 1;
3152 int axes, buttons;
3153 if (ioctl(js, JSIOCGAXES, &axes) < 0 || ioctl(js, JSIOCGBUTTONS, &buttons) < 0) {
3154 close(js);
3155 continue;
3156 }
3158 if (buttons <= 5 || buttons >= 30) {
3159 close(js);
3160 continue;
3161 }
3163 RGFW_gamepadCount++;
3165 RGFW_gamepads[index] = js;
3167 ioctl(js, JSIOCGNAME(sizeof(RGFW_gamepads_name[index])), RGFW_gamepads_name[index]);
3168 RGFW_gamepads_name[index][sizeof(RGFW_gamepads_name[index]) - 1] = 0;
3170 u8 j;
3171 for (j = 0; j < 16; j++) {
3172 RGFW_gamepadPressed[index][j].prev = 0;
3173 RGFW_gamepadPressed[index][j].current = 0;
3174 }
3176 win->event.type = RGFW_gamepadConnected;
3178 RGFW_gamepads_type[index] = RGFW_gamepadUnknown;
3179 if (RGFW_STRSTR(RGFW_gamepads_name[index], "Microsoft") || RGFW_STRSTR(RGFW_gamepads_name[index], "X-Box"))
3180 RGFW_gamepads_type[index] = RGFW_gamepadMicrosoft;
3181 else if (RGFW_STRSTR(RGFW_gamepads_name[index], "PlayStation") || RGFW_STRSTR(RGFW_gamepads_name[index], "PS3") || RGFW_STRSTR(RGFW_gamepads_name[index], "PS4") || RGFW_STRSTR(RGFW_gamepads_name[index], "PS5"))
3182 RGFW_gamepads_type[index] = RGFW_gamepadSony;
3183 else if (RGFW_STRSTR(RGFW_gamepads_name[index], "Nintendo"))
3184 RGFW_gamepads_type[index] = RGFW_gamepadNintendo;
3185 else if (RGFW_STRSTR(RGFW_gamepads_name[index], "Logitech"))
3186 RGFW_gamepads_type[index] = RGFW_gamepadLogitech;
3188 win->event.gamepad = index;
3189 RGFW_gamepadCallback(win, index, 1);
3190 return 1;
3191 }
3192 }
3193 /* check gamepad events */
3194 u8 i;
3196 for (i = 0; i < RGFW_gamepadCount; i++) {
3197 struct js_event e;
3198 if (RGFW_gamepads[i] == 0)
3199 continue;
3201 i32 flags = fcntl(RGFW_gamepads[i], F_GETFL, 0);
3202 fcntl(RGFW_gamepads[i], F_SETFL, flags | O_NONBLOCK);
3204 ssize_t bytes;
3205 while ((bytes = read(RGFW_gamepads[i], &e, sizeof(e))) > 0) {
3206 switch (e.type) {
3207 case JS_EVENT_BUTTON: {
3208 size_t typeIndex = 0;
3209 if (RGFW_gamepads_type[i] == RGFW_gamepadMicrosoft) typeIndex = 1;
3210 else if (RGFW_gamepads_type[i] == RGFW_gamepadLogitech) typeIndex = 2;
3212 win->event.type = e.value ? RGFW_gamepadButtonPressed : RGFW_gamepadButtonReleased;
3213 u8 RGFW_linux2RGFW[3][RGFW_gamepadR3 + 8] = {{ /* ps */
3214 RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadY, RGFW_gamepadX, RGFW_gamepadL1, RGFW_gamepadR1, RGFW_gamepadL2, RGFW_gamepadR2,
3215 RGFW_gamepadSelect, RGFW_gamepadStart, RGFW_gamepadHome, RGFW_gamepadL3, RGFW_gamepadR3, RGFW_gamepadUp, RGFW_gamepadDown, RGFW_gamepadLeft, RGFW_gamepadRight,
3216 },{ /* xbox */
3217 RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadX, RGFW_gamepadY, RGFW_gamepadL1, RGFW_gamepadR1, RGFW_gamepadSelect, RGFW_gamepadStart,
3218 RGFW_gamepadHome, RGFW_gamepadL3, RGFW_gamepadR3, 255, 255, RGFW_gamepadUp, RGFW_gamepadDown, RGFW_gamepadLeft, RGFW_gamepadRight
3219 },{ /* Logitech */
3220 RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadX, RGFW_gamepadY, RGFW_gamepadL1, RGFW_gamepadR1, RGFW_gamepadL2, RGFW_gamepadR2,
3221 RGFW_gamepadSelect, RGFW_gamepadStart, RGFW_gamepadHome, RGFW_gamepadL3, RGFW_gamepadR3, RGFW_gamepadUp, RGFW_gamepadDown, RGFW_gamepadLeft, RGFW_gamepadRight
3222 }
3223 };
3225 win->event.button = RGFW_linux2RGFW[typeIndex][e.number];
3226 win->event.gamepad = i;
3227 if (win->event.button == 255) break;
3229 RGFW_gamepadPressed[i][win->event.button].prev = RGFW_gamepadPressed[i][win->event.button].current;
3230 RGFW_gamepadPressed[i][win->event.button].current = RGFW_BOOL(e.value);
3231 RGFW_gamepadButtonCallback(win, i, win->event.button, RGFW_BOOL(e.value));
3233 return 1;
3234 }
3235 case JS_EVENT_AXIS: {
3236 size_t axis = e.number / 2;
3237 if (axis == 2) axis = 1;
3239 ioctl(RGFW_gamepads[i], JSIOCGAXES, &win->event.axisesCount);
3240 win->event.axisesCount = 2;
3242 if (axis < 3) {
3243 if (e.number == 0 || e.number == 3)
3244 RGFW_gamepadAxes[i][axis].x = (i32)((e.value / 32767.0f) * 100);
3245 else if (e.number == 1 || e.number == 4) {
3246 RGFW_gamepadAxes[i][axis].y = (i32)((e.value / 32767.0f) * 100);
3247 }
3248 }
3250 win->event.axis[axis] = RGFW_gamepadAxes[i][axis];
3251 win->event.type = RGFW_gamepadAxisMove;
3252 win->event.gamepad = i;
3253 win->event.whichAxis = (u8)axis;
3254 RGFW_gamepadAxisCallback(win, i, win->event.axis, win->event.axisesCount, win->event.whichAxis);
3255 return 1;
3256 }
3257 default: break;
3258 }
3259 }
3260 if (bytes == -1 && errno == ENODEV) {
3261 RGFW_gamepadCount--;
3262 close(RGFW_gamepads[i]);
3263 RGFW_gamepads[i] = 0;
3265 win->event.type = RGFW_gamepadDisconnected;
3266 win->event.gamepad = i;
3267 RGFW_gamepadCallback(win, i, 0);
3268 return 1;
3269 }
3270 }
3271 return 0;
3272 }
3274 #endif
3275#endif
3279/*
3281 Start of Wayland defines
3284*/
3286#ifdef RGFW_WAYLAND
3287/*
3288Wayland TODO: (out of date)
3289- fix RGFW_keyPressed lock state
3291 RGFW_windowMoved, the window was moved (by the user)
3292 RGFW_windowResized the window was resized (by the user), [on WASM this means the browser was resized]
3293 RGFW_windowRefresh The window content needs to be refreshed
3295 RGFW_DND a file has been dropped into the window
3296 RGFW_DNDInit
3298- window args:
3299 #define RGFW_windowNoResize the window cannot be resized by the user
3300 #define RGFW_windowAllowDND the window supports drag and drop
3301 #define RGFW_scaleToMonitor scale the window to the screen
3303- other missing functions functions ("TODO wayland") (~30 functions)
3304- fix buffer rendering weird behavior
3305*/
3306#include <errno.h>
3307#include <unistd.h>
3308#include <sys/mman.h>
3309#include <xkbcommon/xkbcommon.h>
3310#include <xkbcommon/xkbcommon-keysyms.h>
3311#include <dirent.h>
3312#include <linux/kd.h>
3313#include <wayland-cursor.h>
3315RGFW_window* RGFW_key_win = NULL;
3317/* wayland global garbage (wayland bad, X11 is fine (ish) (not really)) */
3318#include "xdg-shell.h"
3319#include "xdg-decoration-unstable-v1.h"
3321struct xkb_context *xkb_context;
3322struct xkb_keymap *keymap = NULL;
3323struct xkb_state *xkb_state = NULL;
3324enum zxdg_toplevel_decoration_v1_mode client_preferred_mode, RGFW_current_mode;
3325struct zxdg_decoration_manager_v1 *decoration_manager = NULL;
3327struct wl_cursor_theme* RGFW_wl_cursor_theme = NULL;
3328struct wl_surface* RGFW_cursor_surface = NULL;
3329struct wl_cursor_image* RGFW_cursor_image = NULL;
3331void xdg_wm_base_ping_handler(void *data,
3332 struct xdg_wm_base *wm_base, uint32_t serial)
3333{
3334 RGFW_UNUSED(data);
3335 xdg_wm_base_pong(wm_base, serial);
3336}
3338const struct xdg_wm_base_listener xdg_wm_base_listener = {
3339 .ping = xdg_wm_base_ping_handler,
3340};
3342RGFW_bool RGFW_wl_configured = 0;
3344void xdg_surface_configure_handler(void *data,
3345 struct xdg_surface *xdg_surface, uint32_t serial)
3346{
3347 RGFW_UNUSED(data);
3348 xdg_surface_ack_configure(xdg_surface, serial);
3349 RGFW_wl_configured = 1;
3350}
3352const struct xdg_surface_listener xdg_surface_listener = {
3353 .configure = xdg_surface_configure_handler,
3354};
3356void xdg_toplevel_configure_handler(void *data,
3357 struct xdg_toplevel *toplevel, int32_t width, int32_t height,
3358 struct wl_array *states)
3359{
3360 RGFW_UNUSED(data); RGFW_UNUSED(toplevel); RGFW_UNUSED(states);
3361 RGFW_UNUSED(width); RGFW_UNUSED(height);
3362}
3364void xdg_toplevel_close_handler(void *data,
3365 struct xdg_toplevel *toplevel)
3366{
3367 RGFW_UNUSED(data);
3368 RGFW_window* win = (RGFW_window*)xdg_toplevel_get_user_data(toplevel);
3369 if (win == NULL)
3370 win = RGFW_key_win;
3372 RGFW_eventQueuePushEx(e.type = RGFW_quit; e._win = win);
3373 RGFW_windowQuitCallback(win);
3374}
3376void shm_format_handler(void *data,
3377 struct wl_shm *shm, uint32_t format)
3378{
3379 RGFW_UNUSED(data); RGFW_UNUSED(shm); RGFW_UNUSED(format);
3380}
3382const struct wl_shm_listener shm_listener = {
3383 .format = shm_format_handler,
3384};
3386const struct xdg_toplevel_listener xdg_toplevel_listener = {
3387 .configure = xdg_toplevel_configure_handler,
3388 .close = xdg_toplevel_close_handler,
3389};
3391RGFW_window* RGFW_mouse_win = NULL;
3393void pointer_enter(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) {
3394 RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(serial); RGFW_UNUSED(surface_x); RGFW_UNUSED(surface_y);
3395 RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
3396 RGFW_mouse_win = win;
3398 RGFW_eventQueuePushEx(e.type = RGFW_mouseEnter;
3399 e.point = RGFW_POINT(wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y));
3400 e._win = win);
3402 RGFW_mouseNotifyCallback(win, win->event.point, RGFW_TRUE);
3403}
3404void pointer_leave(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface) {
3405 RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(serial); RGFW_UNUSED(surface);
3406 RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
3407 if (RGFW_mouse_win == win)
3408 RGFW_mouse_win = NULL;
3410 RGFW_eventQueuePushEx(e.type = RGFW_mouseLeave;
3411 e.point = win->event.point;
3412 e._win = win);
3414 RGFW_mouseNotifyCallback(win, win->event.point, RGFW_FALSE);
3415}
3416void pointer_motion(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t x, wl_fixed_t y) {
3417 RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(x); RGFW_UNUSED(y);
3419 RGFW_ASSERT(RGFW_mouse_win != NULL);
3420 RGFW_eventQueuePushEx(e.type = RGFW_mousePosChanged;
3421 e.point = RGFW_POINT(wl_fixed_to_double(x), wl_fixed_to_double(y));
3422 e._win = RGFW_mouse_win);
3424 RGFW_mousePosCallback(RGFW_mouse_win, RGFW_POINT(wl_fixed_to_double(x), wl_fixed_to_double(y)), RGFW_mouse_win->event.vector);
3425}
3426void pointer_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) {
3427 RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(serial);
3428 RGFW_ASSERT(RGFW_mouse_win != NULL);
3430 u32 b = (button - 0x110);
3432 /* flip right and middle button codes */
3433 if (b == 1) b = 2;
3434 else if (b == 2) b = 1;
3436 RGFW_mouseButtons[b].prev = RGFW_mouseButtons[b].current;
3437 RGFW_mouseButtons[b].current = RGFW_BOOL(state);
3439 RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonReleased - RGFW_BOOL(state);
3440 e.point = RGFW_mouse_win->event.point;
3441 e.button = (u8)b;
3442 e._win = RGFW_mouse_win);
3443 RGFW_mouseButtonCallback(RGFW_mouse_win, (u8)b, 0, RGFW_BOOL(state));
3444}
3445void pointer_axis(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value) {
3446 RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(axis);
3447 RGFW_ASSERT(RGFW_mouse_win != NULL);
3449 double scroll = - wl_fixed_to_double(value);
3451 RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonPressed;
3452 e.point = RGFW_mouse_win->event.point;
3453 e.button = RGFW_mouseScrollUp + (scroll < 0);
3454 e.scroll = scroll;
3455 e._win = RGFW_mouse_win);
3457 RGFW_mouseButtonCallback(RGFW_mouse_win, RGFW_mouseScrollUp + (scroll < 0), scroll, 1);
3458}
3460void RGFW_doNothing(void) { }
3462void keyboard_keymap (void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size) {
3463 RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(format);
3465 char *keymap_string = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0);
3466 xkb_keymap_unref (keymap);
3467 keymap = xkb_keymap_new_from_string (xkb_context, keymap_string, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
3469 munmap (keymap_string, size);
3470 close (fd);
3471 xkb_state_unref (xkb_state);
3472 xkb_state = xkb_state_new (keymap);
3473}
3474void keyboard_enter (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) {
3475 RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(keys);
3477 RGFW_key_win = (RGFW_window*)wl_surface_get_user_data(surface);
3479 RGFW_key_win->_flags |= RGFW_windowFocus;
3480 RGFW_eventQueuePushEx(e.type = RGFW_focusIn; e._win = RGFW_key_win);
3481 RGFW_focusCallback(RGFW_key_win, RGFW_TRUE);
3483 if ((RGFW_key_win->_flags & RGFW_HOLD_MOUSE)) RGFW_window_mouseHold(RGFW_key_win, RGFW_AREA(RGFW_key_win->r.w, RGFW_key_win->r.h));
3484}
3485void keyboard_leave (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface) {
3486 RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial);
3488 RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
3489 if (RGFW_key_win == win)
3490 RGFW_key_win = NULL;
3492 RGFW_eventQueuePushEx(e.type = RGFW_focusOut; e._win = win);
3493 RGFW_focusCallback(win, RGFW_FALSE);
3494 RGFW_window_focusLost(win);
3495}
3496void keyboard_key (void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) {
3497 RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time);
3499 if (RGFW_key_win == NULL) return;
3501 xkb_keysym_t keysym = xkb_state_key_get_one_sym(xkb_state, key + 8);
3503 u32 RGFWkey = RGFW_apiKeyToRGFW(key + 8);
3504 RGFW_keyboard[RGFWkey].prev = RGFW_keyboard[RGFWkey].current;
3505 RGFW_keyboard[RGFWkey].current = RGFW_BOOL(state);
3507 RGFW_eventQueuePushEx(e.type = (u8)(RGFW_keyPressed + state);
3508 e.key = (u8)RGFWkey;
3509 e.keyChar = (u8)keysym;
3510 e.repeat = RGFW_isHeld(RGFW_key_win, (u8)RGFWkey);
3511 e._win = RGFW_key_win);
3513 RGFW_updateKeyMods(RGFW_key_win, RGFW_BOOL(xkb_keymap_mod_get_index(keymap, "Lock")), RGFW_BOOL(xkb_keymap_mod_get_index(keymap, "Mod2")), RGFW_BOOL(xkb_keymap_mod_get_index(keymap, "ScrollLock")));
3514 RGFW_keyCallback(RGFW_key_win, (u8)RGFWkey, (u8)keysym, RGFW_key_win->event.keyMod, RGFW_BOOL(state));
3515}
3516void keyboard_modifiers (void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) {
3517 RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time);
3518 xkb_state_update_mask (xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
3519}
3520struct wl_keyboard_listener keyboard_listener = {&keyboard_keymap, &keyboard_enter, &keyboard_leave, &keyboard_key, &keyboard_modifiers, (void (*)(void *, struct wl_keyboard *,
3521int, int))&RGFW_doNothing};
3523void seat_capabilities (void *data, struct wl_seat *seat, uint32_t capabilities) {
3524 RGFW_UNUSED(data);
3525 static struct wl_pointer_listener pointer_listener = {&pointer_enter, &pointer_leave, &pointer_motion, &pointer_button, &pointer_axis, (void (*)(void *, struct wl_pointer *))&RGFW_doNothing, (void (*)(void *, struct wl_pointer *, uint32_t))&RGFW_doNothing, (void (*)(void *, struct wl_pointer *, uint32_t, uint32_t))&RGFW_doNothing, (void (*)(void *, struct wl_pointer *, uint32_t, int32_t))&RGFW_doNothing, (void (*)(void *, struct wl_pointer *, uint32_t, int32_t))&RGFW_doNothing, (void (*)(void*, struct wl_pointer*, uint32_t, uint32_t))&RGFW_doNothing};
3527 if (capabilities & WL_SEAT_CAPABILITY_POINTER) {
3528 struct wl_pointer *pointer = wl_seat_get_pointer (seat);
3529 wl_pointer_add_listener (pointer, &pointer_listener, NULL);
3530 }
3531 if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) {
3532 struct wl_keyboard *keyboard = wl_seat_get_keyboard (seat);
3533 wl_keyboard_add_listener (keyboard, &keyboard_listener, NULL);
3534 }
3535}
3536struct wl_seat_listener seat_listener = {&seat_capabilities, (void (*)(void *, struct wl_seat *, const char *))&RGFW_doNothing};
3538void wl_global_registry_handler(void *data,
3539 struct wl_registry *registry, uint32_t id, const char *interface,
3540 uint32_t version)
3541{
3542 RGFW_window* win = (RGFW_window*)data;
3543 RGFW_UNUSED(version);
3544 if (RGFW_STRNCMP(interface, "wl_compositor", 16) == 0) {
3545 win->src.compositor = wl_registry_bind(registry,
3546 id, &wl_compositor_interface, 4);
3547 } else if (RGFW_STRNCMP(interface, "xdg_wm_base", 12) == 0) {
3548 win->src.xdg_wm_base = wl_registry_bind(registry,
3549 id, &xdg_wm_base_interface, 1);
3550 } else if (RGFW_STRNCMP(interface, zxdg_decoration_manager_v1_interface.name, 255) == 0) {
3551 decoration_manager = wl_registry_bind(registry, id, &zxdg_decoration_manager_v1_interface, 1);
3552 } else if (RGFW_STRNCMP(interface, "wl_shm", 7) == 0) {
3553 win->src.shm = wl_registry_bind(registry,
3554 id, &wl_shm_interface, 1);
3555 wl_shm_add_listener(win->src.shm, &shm_listener, NULL);
3556 } else if (RGFW_STRNCMP(interface,"wl_seat", 8) == 0) {
3557 win->src.seat = wl_registry_bind(registry, id, &wl_seat_interface, 1);
3558 wl_seat_add_listener(win->src.seat, &seat_listener, NULL);
3559 }
3560}
3562void wl_global_registry_remove(void *data, struct wl_registry *registry, uint32_t name) { RGFW_UNUSED(data); RGFW_UNUSED(registry); RGFW_UNUSED(name); }
3563const struct wl_registry_listener registry_listener = {
3564 .global = wl_global_registry_handler,
3565 .global_remove = wl_global_registry_remove,
3566};
3568void decoration_handle_configure(void *data,
3569 struct zxdg_toplevel_decoration_v1 *decoration,
3570 enum zxdg_toplevel_decoration_v1_mode mode) {
3571 RGFW_UNUSED(data); RGFW_UNUSED(decoration);
3572 RGFW_current_mode = mode;
3573}
3575const struct zxdg_toplevel_decoration_v1_listener decoration_listener = {
3576 .configure = decoration_handle_configure,
3577};
3579void randname(char *buf) {
3580 struct timespec ts;
3581 clock_gettime(CLOCK_REALTIME, &ts);
3582 long r = ts.tv_nsec;
3584 int i;
3585 for (i = 0; i < 6; ++i) {
3586 buf[i] = (char)('A'+(r&15)+(r&16)*2);
3587 r >>= 5;
3588 }
3589}
3591size_t wl_stringlen(char* name) {
3592 size_t i = 0;
3593 while (name[i]) { i++; }
3594 return i;
3595}
3597int anonymous_shm_open(void) {
3598 char name[] = "/RGFW-wayland-XXXXXX";
3599 int retries = 100;
3601 do {
3602 randname(name + wl_stringlen(name) - 6);
3604 --retries;
3605 /* shm_open guarantees that O_CLOEXEC is set */
3606 int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
3607 if (fd >= 0) {
3608 shm_unlink(name);
3609 return fd;
3610 }
3611 } while (retries > 0 && errno == EEXIST);
3613 return -1;
3614}
3616int create_shm_file(off_t size) {
3617 int fd = anonymous_shm_open();
3618 if (fd < 0) {
3619 return fd;
3620 }
3622 if (ftruncate(fd, size) < 0) {
3623 close(fd);
3624 return -1;
3625 }
3627 return fd;
3628}
3630void wl_surface_frame_done(void *data, struct wl_callback *cb, uint32_t time) {
3631 RGFW_UNUSED(data); RGFW_UNUSED(cb); RGFW_UNUSED(time);
3633 #ifdef RGFW_BUFFER
3634 RGFW_window* win = (RGFW_window*)data;
3635 wl_surface_attach(win->src.surface, win->src.wl_buffer, 0, 0);
3636 wl_surface_damage_buffer(win->src.surface, 0, 0, win->r.w, win->r.h);
3637 wl_surface_commit(win->src.surface);
3638 #endif
3639}
3641const struct wl_callback_listener wl_surface_frame_listener = {
3642 .done = wl_surface_frame_done,
3643};
3644#endif /* RGFW_WAYLAND */
3645/*
3646 End of Wayland defines
3647*/
3649/*
3652Start of Linux / Unix defines
3655*/
3657#ifdef RGFW_UNIX
3658#if !defined(RGFW_NO_X11_CURSOR) && defined(RGFW_X11)
3659#include <X11/Xcursor/Xcursor.h>
3660#endif
3662#include <dlfcn.h>
3664#ifndef RGFW_NO_DPI
3665#include <X11/extensions/Xrandr.h>
3666#include <X11/Xresource.h>
3667#endif
3669#include <X11/Xatom.h>
3670#include <X11/keysymdef.h>
3671#include <X11/extensions/sync.h>
3672#include <unistd.h>
3674#include <X11/XKBlib.h> /* for converting keycode to string */
3675#include <X11/cursorfont.h> /* for hiding */
3676#include <X11/extensions/shapeconst.h>
3677#include <X11/extensions/shape.h>
3678#include <X11/extensions/XInput2.h>
3680#include <limits.h> /* for data limits (mainly used in drag and drop functions) */
3681#include <poll.h>
3683/* atoms needed for drag and drop */
3684Atom XdndAware, XtextPlain, XtextUriList;
3685Atom RGFW_XUTF8_STRING = 0;
3687Atom wm_delete_window = 0, RGFW_XCLIPBOARD = 0;
3689#if defined(RGFW_X11) && !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD)
3690 typedef XcursorImage* (*PFN_XcursorImageCreate)(int, int);
3691 typedef void (*PFN_XcursorImageDestroy)(XcursorImage*);
3692 typedef Cursor(*PFN_XcursorImageLoadCursor)(Display*, const XcursorImage*);
3693#endif
3694#if defined(RGFW_OPENGL) && defined(RGFW_X11)
3695 typedef GLXContext(*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
3696#endif
3698#if !defined(RGFW_NO_X11_XI_PRELOAD) && defined(RGFW_X11)
3699 typedef int (* PFN_XISelectEvents)(Display*,Window,XIEventMask*,int);
3700 PFN_XISelectEvents XISelectEventsSRC = NULL;
3701 #define XISelectEvents XISelectEventsSRC
3703 void* X11Xihandle = NULL;
3704#endif
3706#if !defined(RGFW_NO_X11_EXT_PRELOAD) && defined(RGFW_X11)
3707 typedef void (* PFN_XSyncIntToValue)(XSyncValue*, int);
3708 PFN_XSyncIntToValue XSyncIntToValueSRC = NULL;
3709 #define XSyncIntToValue XSyncIntToValueSRC
3711 typedef Status (* PFN_XSyncSetCounter)(Display*, XSyncCounter, XSyncValue);
3712 PFN_XSyncSetCounter XSyncSetCounterSRC = NULL;
3713 #define XSyncSetCounter XSyncSetCounterSRC
3715 typedef XSyncCounter (* PFN_XSyncCreateCounter)(Display*, XSyncValue);
3716 PFN_XSyncCreateCounter XSyncCreateCounterSRC = NULL;
3717 #define XSyncCreateCounter XSyncCreateCounterSRC
3719 typedef void (* PFN_XShapeCombineMask)(Display*,Window,int,int,int,Pixmap,int);
3720 PFN_XShapeCombineMask XShapeCombineMaskSRC;
3721 #define XShapeCombineMask XShapeCombineMaskSRC
3723 typedef void (* PFN_XShapeCombineRegion)(Display*,Window,int,int,int,Region,int);
3724 PFN_XShapeCombineRegion XShapeCombineRegionSRC;
3725 #define XShapeCombineRegion XShapeCombineRegionSRC
3726 void* X11XEXThandle = NULL;
3727#endif
3729#if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD) && defined(RGFW_X11)
3730 PFN_XcursorImageLoadCursor XcursorImageLoadCursorSRC = NULL;
3731 PFN_XcursorImageCreate XcursorImageCreateSRC = NULL;
3732 PFN_XcursorImageDestroy XcursorImageDestroySRC = NULL;
3734 #define XcursorImageLoadCursor XcursorImageLoadCursorSRC
3735 #define XcursorImageCreate XcursorImageCreateSRC
3736 #define XcursorImageDestroy XcursorImageDestroySRC
3738 void* X11Cursorhandle = NULL;
3739#endif
3741#ifdef RGFW_X11
3742const char* RGFW_instName = NULL;
3743void RGFW_setXInstName(const char* name) { RGFW_instName = name; }
3744#endif
3746#if defined(RGFW_OPENGL) && !defined(RGFW_EGL)
3747RGFW_bool RGFW_extensionSupportedPlatform(const char * extension, size_t len) {
3748 const char* extensions = glXQueryExtensionsString(_RGFW.display, XDefaultScreen(_RGFW.display));
3749 return (extensions != NULL) && RGFW_extensionSupportedStr(extensions, extension, len);
3750}
3751RGFW_proc RGFW_getProcAddress(const char* procname) { return (RGFW_proc) glXGetProcAddress((GLubyte*) procname); }
3752#endif
3754void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area) {
3755 RGFW_GOTO_WAYLAND(0);
3757#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
3758 win->buffer = (u8*)buffer;
3759 win->bufferSize = area;
3761 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoBuffer, RGFW_DEBUG_CTX(win, 0), "createing a 4 channel buffer");
3762 #ifdef RGFW_X11
3763 #ifdef RGFW_OSMESA
3764 win->src.ctx = OSMesaCreateContext(OSMESA_BGRA, NULL);
3765 OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h);
3766 OSMesaPixelStore(OSMESA_Y_UP, 0);
3767 #endif
3769 win->src.bitmap = XCreateImage(
3770 win->src.display, win->src.visual.visual, (u32)win->src.visual.depth,
3771 ZPixmap, 0, NULL, area.w, area.h, 32, 0
3772 );
3773 #endif
3774 #ifdef RGFW_WAYLAND
3775 RGFW_WAYLAND_LABEL {}
3776 u32 size = (u32)(win->r.w * win->r.h * 4);
3777 int fd = create_shm_file(size);
3778 if (fd < 0) {
3779 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, RGFW_DEBUG_CTX(win, (u32)fd),"Failed to create a buffer.");
3780 exit(1);
3781 }
3783 win->src.buffer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
3784 if (win->src.buffer == MAP_FAILED) {
3785 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, RGFW_DEBUG_CTX(win, 0), "mmap failed!");
3786 close(fd);
3787 exit(1);
3788 }
3790 win->_flags |= RGFW_BUFFER_ALLOC;
3792 struct wl_shm_pool* pool = wl_shm_create_pool(win->src.shm, fd, (i32)size);
3793 win->src.wl_buffer = wl_shm_pool_create_buffer(pool, 0, win->r.w, win->r.h, win->r.w * 4,
3794 WL_SHM_FORMAT_ARGB8888);
3795 wl_shm_pool_destroy(pool);
3797 close(fd);
3799 wl_surface_attach(win->src.surface, win->src.wl_buffer, 0, 0);
3800 wl_surface_commit(win->src.surface);
3802 u8 color[] = {0x00, 0x00, 0x00, 0xFF};
3804 size_t i;
3805 for (i = 0; i < area.w * area.h * 4; i += 4) {
3806 RGFW_MEMCPY(&win->buffer[i], color, 4);
3807 }
3809 RGFW_MEMCPY(win->src.buffer, win->buffer, (size_t)(win->r.w * win->r.h * 4));
3811 #if defined(RGFW_OSMESA)
3812 win->src.ctx = OSMesaCreateContext(OSMESA_BGRA, NULL);
3813 OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h);
3814 OSMesaPixelStore(OSMESA_Y_UP, 0);
3815 #endif
3816 #endif
3817#else
3818 #ifdef RGFW_WAYLAND
3819 RGFW_WAYLAND_LABEL{}
3820 #endif
3822 RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area);
3823#endif
3824}
3826#define RGFW_LOAD_ATOM(name) \
3827 static Atom name = 0; \
3828 if (name == 0) name = XInternAtom(_RGFW.display, #name, False);
3830void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) {
3831 RGFW_setBit(&win->_flags, RGFW_windowNoBorder, !border);
3833 RGFW_GOTO_WAYLAND(0);
3834 #ifdef RGFW_X11
3835 RGFW_LOAD_ATOM(_MOTIF_WM_HINTS);
3837 struct __x11WindowHints {
3838 unsigned long flags, functions, decorations, status;
3839 long input_mode;
3840 } hints;
3841 hints.flags = 2;
3842 hints.decorations = border;
3844 XChangeProperty(win->src.display, win->src.window, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 32,
3845 PropModeReplace, (u8*)&hints, 5
3846 );
3848 if (RGFW_window_isHidden(win) == 0) {
3849 RGFW_window_hide(win);
3850 RGFW_window_show(win);
3851 }
3853 #endif
3854 #ifdef RGFW_WAYLAND
3855 RGFW_WAYLAND_LABEL
3856 RGFW_UNUSED(win); RGFW_UNUSED(border);
3857 #endif
3858}
3860void RGFW_releaseCursor(RGFW_window* win) {
3861RGFW_GOTO_WAYLAND(0);
3862#ifdef RGFW_X11
3863 XUngrabPointer(win->src.display, CurrentTime);
3865 /* disable raw input */
3866 unsigned char mask[] = { 0 };
3867 XIEventMask em;
3868 em.deviceid = XIAllMasterDevices;
3869 em.mask_len = sizeof(mask);
3870 em.mask = mask;
3872 XISelectEvents(win->src.display, XDefaultRootWindow(win->src.display), &em, 1);
3873#endif
3874#ifdef RGFW_WAYLAND
3875 RGFW_WAYLAND_LABEL
3876 RGFW_UNUSED(win);
3877#endif
3878}
3880void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) {
3881RGFW_GOTO_WAYLAND(0);
3882#ifdef RGFW_X11
3883 /* enable raw input */
3884 unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 };
3885 XISetMask(mask, XI_RawMotion);
3887 XIEventMask em;
3888 em.deviceid = XIAllMasterDevices;
3889 em.mask_len = sizeof(mask);
3890 em.mask = mask;
3892 XISelectEvents(win->src.display, XDefaultRootWindow(win->src.display), &em, 1);
3894 XGrabPointer(win->src.display, win->src.window, True, PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
3895 RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (i32)(r.w / 2), win->r.y + (i32)(r.h / 2)));
3896#endif
3897#ifdef RGFW_WAYLAND
3898 RGFW_WAYLAND_LABEL
3899 RGFW_UNUSED(win); RGFW_UNUSED(r);
3900#endif
3901}
3903#define RGFW_LOAD_LIBRARY(x, lib) if (x == NULL) x = dlopen(lib, RTLD_LAZY | RTLD_LOCAL)
3904#define RGFW_PROC_DEF(proc, name) if (name##SRC == NULL && proc != NULL) { \
3905 void* ptr = dlsym(proc, #name); \
3906 if (ptr != NULL) memcpy(&name##SRC, &ptr, sizeof(PFN_##name)); \
3907}
3909#ifdef RGFW_X11
3910void RGFW_window_getVisual(RGFW_window* win) {
3911#if defined(RGFW_OPENGL) && !defined(RGFW_EGL)
3912 i32* visual_attribs = RGFW_initFormatAttribs();
3913 i32 fbcount;
3914 GLXFBConfig* fbc = glXChooseFBConfig(win->src.display, DefaultScreen(win->src.display), visual_attribs, &fbcount);
3916 i32 best_fbc = -1;
3917 i32 best_depth = 0;
3918 i32 best_samples = 0;
3920 if (fbcount == 0) {
3921 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to find any valid GLX visual configs");
3922 return;
3923 }
3925 i32 i;
3926 for (i = 0; i < fbcount; i++) {
3927 XVisualInfo* vi = glXGetVisualFromFBConfig(win->src.display, fbc[i]);
3928 if (vi == NULL)
3929 continue;
3931 i32 samp_buf, samples;
3932 glXGetFBConfigAttrib(win->src.display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf);
3933 glXGetFBConfigAttrib(win->src.display, fbc[i], GLX_SAMPLES, &samples);
3935 if (best_fbc == -1) best_fbc = i;
3936 if ((!(win->_flags & RGFW_windowTransparent) || vi->depth == 32) && best_depth == 0) {
3937 best_fbc = i;
3938 best_depth = vi->depth;
3939 }
3940 if ((!(win->_flags & RGFW_windowTransparent) || vi->depth == 32) && samples <= RGFW_GL_HINTS[RGFW_glSamples] && samples > best_samples) {
3941 best_fbc = i;
3942 best_depth = vi->depth;
3943 best_samples = samples;
3944 }
3945 XFree(vi);
3946 }
3948 if (best_fbc == -1) {
3949 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to get a valid GLX visual");
3950 return;
3951 }
3953 win->src.bestFbc = fbc[best_fbc];
3954 XVisualInfo* vi = glXGetVisualFromFBConfig(win->src.display, win->src.bestFbc);
3955 if (vi->depth != 32 && (win->_flags & RGFW_windowTransparent))
3956 RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, RGFW_DEBUG_CTX(win, 0), "Failed to to find a matching visual with a 32-bit depth");
3958 if (best_samples < RGFW_GL_HINTS[RGFW_glSamples])
3959 RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, RGFW_DEBUG_CTX(win, 0), "Failed to load matching sampiling");
3961 int configCaveat;
3962 if (glXGetFBConfigAttrib(win->src.display, win->src.bestFbc, GLX_CONFIG_CAVEAT, &configCaveat) == Success &&
3963 configCaveat == GLX_SLOW_CONFIG) {
3964 win->_flags |= RGFW_windowOpenglSoftware;
3965 }
3967 XFree(fbc);
3968 win->src.visual = *vi;
3969 XFree(vi);
3970#else
3971 win->src.visual.visual = DefaultVisual(win->src.display, DefaultScreen(win->src.display));
3972 win->src.visual.depth = DefaultDepth(win->src.display, DefaultScreen(win->src.display));
3973 if (win->_flags & RGFW_windowTransparent) {
3974 XMatchVisualInfo(win->src.display, DefaultScreen(win->src.display), 32, TrueColor, &win->src.visual); /*!< for RGBA backgrounds */
3975 if (win->src.visual.depth != 32)
3976 RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, RGFW_DEBUG_CTX(win, 0), "Failed to load a 32-bit depth");
3977 }
3978#endif
3979}
3980#endif
3981#ifndef RGFW_EGL
3982void RGFW_window_initOpenGL(RGFW_window* win) {
3983#ifdef RGFW_OPENGL
3984 i32 context_attribs[7] = { 0, 0, 0, 0, 0, 0, 0 };
3985 context_attribs[0] = GLX_CONTEXT_PROFILE_MASK_ARB;
3986 if (RGFW_GL_HINTS[RGFW_glProfile] == RGFW_glCore)
3987 context_attribs[1] = GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
3988 else
3989 context_attribs[1] = GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
3991 if (RGFW_GL_HINTS[RGFW_glMinor] || RGFW_GL_HINTS[RGFW_glMajor]) {
3992 context_attribs[2] = GLX_CONTEXT_MAJOR_VERSION_ARB;
3993 context_attribs[3] = RGFW_GL_HINTS[RGFW_glMajor];
3994 context_attribs[4] = GLX_CONTEXT_MINOR_VERSION_ARB;
3995 context_attribs[5] = RGFW_GL_HINTS[RGFW_glMinor];
3996 }
3998 glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
3999 glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)
4000 glXGetProcAddressARB((GLubyte*) "glXCreateContextAttribsARB");
4002 GLXContext ctx = NULL;
4003 if (_RGFW.root != NULL && _RGFW.root != win) {
4004 ctx = _RGFW.root->src.ctx;
4005 RGFW_window_makeCurrent_OpenGL(_RGFW.root);
4006 }
4008 if (glXCreateContextAttribsARB == NULL) {
4009 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "failed to load proc address 'glXCreateContextAttribsARB', loading a generic opengl context");
4010 win->src.ctx = glXCreateContext(win->src.display, &win->src.visual, ctx, True);
4011 }
4012 else {
4013 win->src.ctx = glXCreateContextAttribsARB(win->src.display, win->src.bestFbc, ctx, True, context_attribs);
4014 XSync(win->src.display, False);
4015 if (win->src.ctx == NULL) {
4016 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "failed to create an opengl context with AttribsARB, loading a generic opengl context");
4017 win->src.ctx = glXCreateContext(win->src.display, &win->src.visual, ctx, True);
4018 }
4019 }
4021 glXMakeCurrent(win->src.display, (Drawable) win->src.window, (GLXContext) win->src.ctx);
4022 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context initalized");
4023#else
4024 RGFW_UNUSED(win);
4025#endif
4026}
4028void RGFW_window_freeOpenGL(RGFW_window* win) {
4029#ifdef RGFW_OPENGL
4030 if (win->src.ctx == NULL) return;
4031 glXDestroyContext(win->src.display, win->src.ctx);
4032 win->src.ctx = NULL;
4033 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context freed");
4034#else
4035RGFW_UNUSED(win);
4036#endif
4037}
4038#endif
4041i32 RGFW_init(void) {
4042 RGFW_GOTO_WAYLAND(1);
4043#if defined(RGFW_C89) || defined(__cplusplus)
4044 if (_RGFW_init) return 0;
4045 _RGFW_init = RGFW_TRUE;
4046 _RGFW.root = NULL; _RGFW.current = NULL; _RGFW.windowCount = -1; _RGFW.eventLen = 0; _RGFW.eventIndex = 0;
4047#endif
4049#ifdef RGFW_X11
4050 if (_RGFW.windowCount != -1) return 0;
4051 #ifdef RGFW_USE_XDL
4052 XDL_init();
4053 #endif
4055 #if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD)
4056 #if defined(__CYGWIN__)
4057 RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor-1.so");
4058 #elif defined(__OpenBSD__) || defined(__NetBSD__)
4059 RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor.so");
4060 #else
4061 RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor.so.1");
4062 #endif
4063 RGFW_PROC_DEF(X11Cursorhandle, XcursorImageCreate);
4064 RGFW_PROC_DEF(X11Cursorhandle, XcursorImageDestroy);
4065 RGFW_PROC_DEF(X11Cursorhandle, XcursorImageLoadCursor);
4066 #endif
4068 #if !defined(RGFW_NO_X11_XI_PRELOAD)
4069 #if defined(__CYGWIN__)
4070 RGFW_LOAD_LIBRARY(X11Xihandle, "libXi-6.so");
4071 #elif defined(__OpenBSD__) || defined(__NetBSD__)
4072 RGFW_LOAD_LIBRARY(X11Xihandle, "libXi.so");
4073 #else
4074 RGFW_LOAD_LIBRARY(X11Xihandle, "libXi.so.6");
4075 #endif
4076 RGFW_PROC_DEF(X11Xihandle, XISelectEvents);
4077 #endif
4079 #if !defined(RGFW_NO_X11_EXT_PRELOAD)
4080 #if defined(__CYGWIN__)
4081 RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext-6.so");
4082 #elif defined(__OpenBSD__) || defined(__NetBSD__)
4083 RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext.so");
4084 #else
4085 RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext.so.6");
4086 #endif
4087 RGFW_PROC_DEF(X11XEXThandle, XSyncCreateCounter);
4088 RGFW_PROC_DEF(X11XEXThandle, XSyncIntToValue);
4089 RGFW_PROC_DEF(X11XEXThandle, XSyncSetCounter);
4090 RGFW_PROC_DEF(X11XEXThandle, XShapeCombineRegion);
4091 RGFW_PROC_DEF(X11XEXThandle, XShapeCombineMask);
4092 #endif
4094 XInitThreads(); /*!< init X11 threading */
4095 _RGFW.display = XOpenDisplay(0);
4096 XSetWindowAttributes wa;
4097 RGFW_MEMSET(&wa, 0, sizeof(wa));
4098 wa.event_mask = PropertyChangeMask;
4099 _RGFW.helperWindow = XCreateWindow(_RGFW.display, XDefaultRootWindow(_RGFW.display), 0, 0, 1, 1, 0, 0,
4100 InputOnly, DefaultVisual(_RGFW.display, DefaultScreen(_RGFW.display)), CWEventMask, &wa);
4102 _RGFW.windowCount = 0;
4103 u8 RGFW_blk[] = { 0, 0, 0, 0 };
4104 _RGFW.hiddenMouse = RGFW_loadMouse(RGFW_blk, RGFW_AREA(1, 1), 4);
4105 _RGFW.clipboard = NULL;
4107 XkbComponentNamesRec rec;
4108 XkbDescPtr desc = XkbGetMap(_RGFW.display, 0, XkbUseCoreKbd);
4109 XkbDescPtr evdesc;
4110 u8 old[sizeof(RGFW_keycodes) / sizeof(RGFW_keycodes[0])];
4112 XkbGetNames(_RGFW.display, XkbKeyNamesMask, desc);
4114 RGFW_MEMSET(&rec, 0, sizeof(rec));
4115 rec.keycodes = (char*)"evdev";
4116 evdesc = XkbGetKeyboardByName(_RGFW.display, XkbUseCoreKbd, &rec, XkbGBN_KeyNamesMask, XkbGBN_KeyNamesMask, False);
4117 /* memo: RGFW_keycodes[x11 keycode] = rgfw keycode */
4118 if(evdesc != NULL && desc != NULL){
4119 for(int i = 0; i < (int)sizeof(RGFW_keycodes) / (int)sizeof(RGFW_keycodes[0]); i++){
4120 old[i] = RGFW_keycodes[i];
4121 RGFW_keycodes[i] = 0;
4122 }
4123 for(int i = evdesc->min_key_code; i <= evdesc->max_key_code; i++){
4124 for(int j = desc->min_key_code; j <= desc->max_key_code; j++){
4125 if(strncmp(evdesc->names->keys[i].name, desc->names->keys[j].name, XkbKeyNameLength) == 0){
4126 RGFW_keycodes[j] = old[i];
4127 break;
4128 }
4129 }
4130 }
4131 XkbFreeKeyboard(desc, 0, True);
4132 XkbFreeKeyboard(evdesc, 0, True);
4133 }
4134#endif
4135#ifdef RGFW_WAYLAND
4136RGFW_WAYLAND_LABEL
4137 _RGFW.wl_display = wl_display_connect(NULL);
4138#endif
4139 _RGFW.windowCount = 0;
4140 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context initialized");
4141 return 0;
4142}
4145RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) {
4146 RGFW_window_basic_init(win, rect, flags);
4148#ifdef RGFW_WAYLAND
4149 win->src.compositor = NULL;
4150#endif
4151 RGFW_GOTO_WAYLAND(0);
4152#ifdef RGFW_X11
4153 i64 event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | FocusChangeMask | LeaveWindowMask | EnterWindowMask | ExposureMask; /*!< X11 events accepted */
4155 win->src.display = XOpenDisplay(NULL);
4156 RGFW_window_getVisual(win);
4158 /* make X window attrubutes */
4159 XSetWindowAttributes swa;
4160 RGFW_MEMSET(&swa, 0, sizeof(swa));
4162 Colormap cmap;
4163 swa.colormap = cmap = XCreateColormap(win->src.display,
4164 DefaultRootWindow(win->src.display),
4165 win->src.visual.visual, AllocNone);
4166 swa.event_mask = event_mask;
4168 /* create the window */
4169 win->src.window = XCreateWindow(win->src.display, DefaultRootWindow(win->src.display), win->r.x, win->r.y, (u32)win->r.w, (u32)win->r.h,
4170 0, win->src.visual.depth, InputOutput, win->src.visual.visual,
4171 CWColormap | CWBorderPixel | CWEventMask, &swa);
4173 XFreeColors(win->src.display, cmap, NULL, 0, 0);
4175 win->src.gc = XCreateGC(win->src.display, win->src.window, 0, NULL);
4177 /* In your .desktop app, if you set the property
4178 StartupWMClass=RGFW that will assoicate the launcher icon
4179 with your application - robrohan */
4180 if (RGFW_className == NULL)
4181 RGFW_className = (char*)name;
4183 XClassHint hint;
4184 hint.res_class = (char*)RGFW_className;
4185 if (RGFW_instName == NULL) hint.res_name = (char*)name;
4186 else hint.res_name = (char*)RGFW_instName;
4187 XSetClassHint(win->src.display, win->src.window, &hint);
4189 #ifndef RGFW_NO_MONITOR
4190 if (flags & RGFW_windowScaleToMonitor)
4191 RGFW_window_scaleToMonitor(win);
4192 #endif
4193 XSelectInput(win->src.display, (Drawable) win->src.window, event_mask); /*!< tell X11 what events we want */
4195 /* make it so the user can't close the window until the program does */
4196 if (wm_delete_window == 0) {
4197 wm_delete_window = XInternAtom(win->src.display, "WM_DELETE_WINDOW", False);
4198 RGFW_XUTF8_STRING = XInternAtom(win->src.display, "UTF8_STRING", False);
4199 RGFW_XCLIPBOARD = XInternAtom(win->src.display, "CLIPBOARD", False);
4200 }
4202 XSetWMProtocols(win->src.display, (Drawable) win->src.window, &wm_delete_window, 1);
4203 /* set the background */
4204 RGFW_window_setName(win, name);
4206 XMoveWindow(win->src.display, (Drawable) win->src.window, win->r.x, win->r.y); /*!< move the window to it's proper cords */
4208 if (flags & RGFW_windowAllowDND) { /* init drag and drop atoms and turn on drag and drop for this window */
4209 win->_flags |= RGFW_windowAllowDND;
4211 /* actions */
4212 XtextUriList = XInternAtom(win->src.display, "text/uri-list", False);
4213 XtextPlain = XInternAtom(win->src.display, "text/plain", False);
4214 XdndAware = XInternAtom(win->src.display, "XdndAware", False);
4215 const u8 version = 5;
4217 XChangeProperty(win->src.display, win->src.window,
4218 XdndAware, 4, 32,
4219 PropModeReplace, &version, 1); /*!< turns on drag and drop */
4220 }
4222#ifdef RGFW_ADVANCED_SMOOTH_RESIZE
4223 RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST_COUNTER)
4224 RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST)
4225 Atom protcols[2] = {_NET_WM_SYNC_REQUEST, wm_delete_window};
4226 XSetWMProtocols(win->src.display, win->src.window, protcols, 2);
4228 XSyncValue initial_value;
4229 XSyncIntToValue(&initial_value, 0);
4230 win->src.counter = XSyncCreateCounter(win->src.display, initial_value);
4232 XChangeProperty(win->src.display, win->src.window, _NET_WM_SYNC_REQUEST_COUNTER, XA_CARDINAL, 32, PropModeReplace, (uint8_t*)&win->src.counter, 1);
4233#endif
4235 if ((flags & RGFW_windowNoInitAPI) == 0) {
4236 RGFW_window_initOpenGL(win);
4237 RGFW_window_initBuffer(win);
4238 }
4240 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created");
4241 RGFW_window_setMouseDefault(win);
4242 RGFW_window_setFlags(win, flags);
4244 win->src.r = win->r;
4246 RGFW_window_show(win);
4247 return win; /*return newly created window */
4248#endif
4249#ifdef RGFW_WAYLAND
4250 RGFW_WAYLAND_LABEL
4251 RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningWayland, RGFW_DEBUG_CTX(win, 0), "RGFW Wayland support is experimental");
4253 win->src.wl_display = _RGFW.wl_display;
4254 if (win->src.wl_display == NULL) {
4255 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errWayland, RGFW_DEBUG_CTX(win, 0), "Failed to load Wayland display");
4256 #ifdef RGFW_X11
4257 RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningWayland, RGFW_DEBUG_CTX(win, 0), "Falling back to X11");
4258 RGFW_useWayland(0);
4259 return RGFW_createWindowPtr(name, rect, flags, win);
4260 #endif
4261 return NULL;
4262 }
4265 #ifdef RGFW_X11
4266 win->src.display = _RGFW.display;
4267 win->src.window = _RGFW.helperWindow;
4268 XMapWindow(_RGFW.display, win->src.window);
4269 XFlush(win->src.display);
4270 if (wm_delete_window == 0) {
4271 wm_delete_window = XInternAtom(win->src.display, "WM_DELETE_WINDOW", False);
4272 RGFW_XUTF8_STRING = XInternAtom(win->src.display, "UTF8_STRING", False);
4273 RGFW_XCLIPBOARD = XInternAtom(win->src.display, "CLIPBOARD", False);
4274 }
4275 #endif
4277 struct wl_registry *registry = wl_display_get_registry(win->src.wl_display);
4278 wl_registry_add_listener(registry, ®istry_listener, win);
4280 wl_display_roundtrip(win->src.wl_display);
4281 wl_display_dispatch(win->src.wl_display);
4283 if (win->src.compositor == NULL) {
4284 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errWayland, RGFW_DEBUG_CTX(win, 0), "Can't find compositor.");
4285 return NULL;
4286 }
4288 if (RGFW_wl_cursor_theme == NULL) {
4289 RGFW_wl_cursor_theme = wl_cursor_theme_load(NULL, 24, win->src.shm);
4290 RGFW_cursor_surface = wl_compositor_create_surface(win->src.compositor);
4292 struct wl_cursor* cursor = wl_cursor_theme_get_cursor(RGFW_wl_cursor_theme, "left_ptr");
4293 RGFW_cursor_image = cursor->images[0];
4294 struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(RGFW_cursor_image);
4296 wl_surface_attach(RGFW_cursor_surface, cursor_buffer, 0, 0);
4297 wl_surface_commit(RGFW_cursor_surface);
4298 }
4300 xdg_wm_base_add_listener(win->src.xdg_wm_base, &xdg_wm_base_listener, NULL);
4302 xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
4304 win->src.surface = wl_compositor_create_surface(win->src.compositor);
4305 wl_surface_set_user_data(win->src.surface, win);
4307 win->src.xdg_surface = xdg_wm_base_get_xdg_surface(win->src.xdg_wm_base, win->src.surface);
4308 xdg_surface_add_listener(win->src.xdg_surface, &xdg_surface_listener, NULL);
4310 xdg_wm_base_set_user_data(win->src.xdg_wm_base, win);
4312 win->src.xdg_toplevel = xdg_surface_get_toplevel(win->src.xdg_surface);
4313 xdg_toplevel_set_user_data(win->src.xdg_toplevel, win);
4314 xdg_toplevel_add_listener(win->src.xdg_toplevel, &xdg_toplevel_listener, NULL);
4316 xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->r.w, win->r.h);
4318 if (!(flags & RGFW_windowNoBorder)) {
4319 win->src.decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(
4320 decoration_manager, win->src.xdg_toplevel);
4321 }
4323 wl_display_roundtrip(win->src.wl_display);
4325 wl_surface_commit(win->src.surface);
4326 RGFW_window_show(win);
4328 /* wait for the surface to be configured */
4329 while (wl_display_dispatch(win->src.wl_display) != -1 && !RGFW_wl_configured) { }
4331 if ((flags & RGFW_windowNoInitAPI) == 0) {
4332 RGFW_window_initOpenGL(win);
4333 RGFW_window_initBuffer(win);
4334 }
4335 struct wl_callback* callback = wl_surface_frame(win->src.surface);
4336 wl_callback_add_listener(callback, &wl_surface_frame_listener, win);
4337 wl_surface_commit(win->src.surface);
4338 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created");
4340 #ifndef RGFW_NO_MONITOR
4341 if (flags & RGFW_windowScaleToMonitor)
4342 RGFW_window_scaleToMonitor(win);
4343 #endif
4345 RGFW_window_setName(win, name);
4346 RGFW_window_setMouseDefault(win);
4347 RGFW_window_setFlags(win, flags);
4348 return win; /* return newly created window */
4349#endif
4350}
4352RGFW_area RGFW_getScreenSize(void) {
4353 RGFW_GOTO_WAYLAND(1);
4354 RGFW_init();
4356 #ifdef RGFW_X11
4357 Screen* scrn = DefaultScreenOfDisplay(_RGFW.display);
4358 return RGFW_AREA(scrn->width, scrn->height);
4359 #endif
4360 #ifdef RGFW_WAYLAND
4361 RGFW_WAYLAND_LABEL return RGFW_AREA(_RGFW.root->r.w, _RGFW.root->r.h); /* TODO */
4362 #endif
4363}
4365RGFW_point RGFW_getGlobalMousePoint(void) {
4366 RGFW_init();
4367 RGFW_point RGFWMouse = RGFW_POINT(0, 0);
4368 RGFW_GOTO_WAYLAND(1);
4369#ifdef RGFW_X11
4370 i32 x, y;
4371 u32 z;
4372 Window window1, window2;
4373 XQueryPointer(_RGFW.display, XDefaultRootWindow(_RGFW.display), &window1, &window2, &RGFWMouse.x, &RGFWMouse.y, &x, &y, &z);
4374 return RGFWMouse;
4375#endif
4376#ifdef RGFW_WAYLAND
4377 RGFW_WAYLAND_LABEL
4378 return RGFWMouse;
4379#endif
4380}
4382RGFWDEF void RGFW_XHandleClipboardSelection(XEvent* event);
4383void RGFW_XHandleClipboardSelection(XEvent* event) { RGFW_UNUSED(event);
4384#ifdef RGFW_X11
4385 RGFW_LOAD_ATOM(ATOM_PAIR);
4386 RGFW_LOAD_ATOM(MULTIPLE);
4387 RGFW_LOAD_ATOM(TARGETS);
4388 RGFW_LOAD_ATOM(SAVE_TARGETS);
4390 const XSelectionRequestEvent* request = &event->xselectionrequest;
4391 const Atom formats[] = { RGFW_XUTF8_STRING, XA_STRING };
4392 const int formatCount = sizeof(formats) / sizeof(formats[0]);
4394 if (request->target == TARGETS) {
4395 const Atom targets[] = { TARGETS, MULTIPLE, RGFW_XUTF8_STRING, XA_STRING };
4397 XChangeProperty(_RGFW.display, request->requestor, request->property,
4398 XA_ATOM, 32, PropModeReplace, (u8*) targets, sizeof(targets) / sizeof(Atom));
4399 } else if (request->target == MULTIPLE) {
4400 Atom* targets = NULL;
4402 Atom actualType = 0;
4403 int actualFormat = 0;
4404 unsigned long count = 0, bytesAfter = 0;
4406 XGetWindowProperty(_RGFW.display, request->requestor, request->property, 0, LONG_MAX,
4407 False, ATOM_PAIR, &actualType, &actualFormat, &count, &bytesAfter, (u8**) &targets);
4409 unsigned long i;
4410 for (i = 0; i < (u32)count; i += 2) {
4411 if (targets[i] == RGFW_XUTF8_STRING || targets[i] == XA_STRING)
4412 XChangeProperty(_RGFW.display, request->requestor, targets[i + 1], targets[i],
4413 8, PropModeReplace, (const unsigned char *)_RGFW.clipboard, (i32)_RGFW.clipboard_len);
4414 else
4415 targets[i + 1] = None;
4416 }
4418 XChangeProperty(_RGFW.display,
4419 request->requestor, request->property, ATOM_PAIR, 32,
4420 PropModeReplace, (u8*) targets, (i32)count);
4422 XFlush(_RGFW.display);
4423 XFree(targets);
4424 } else if (request->target == SAVE_TARGETS)
4425 XChangeProperty(_RGFW.display, request->requestor, request->property, 0, 32, PropModeReplace, NULL, 0);
4426 else {
4427 int i;
4428 for (i = 0; i < formatCount; i++) {
4429 if (request->target != formats[i])
4430 continue;
4431 XChangeProperty(_RGFW.display, request->requestor, request->property, request->target,
4432 8, PropModeReplace, (u8*) _RGFW.clipboard, (i32)_RGFW.clipboard_len);
4433 }
4434 }
4436 XEvent reply = { SelectionNotify };
4437 reply.xselection.property = request->property;
4438 reply.xselection.display = request->display;
4439 reply.xselection.requestor = request->requestor;
4440 reply.xselection.selection = request->selection;
4441 reply.xselection.target = request->target;
4442 reply.xselection.time = request->time;
4444 XSendEvent(_RGFW.display, request->requestor, False, 0, &reply);
4445#endif
4446}
4448char* RGFW_strtok(char* str, const char* delimStr);
4449char* RGFW_strtok(char* str, const char* delimStr) {
4450 static char* static_str = NULL;
4452 if (str != NULL)
4453 static_str = str;
4455 if (static_str == NULL) {
4456 return NULL;
4457 }
4459 while (*static_str != '\0') {
4460 RGFW_bool delim = 0;
4461 const char* d;
4462 for (d = delimStr; *d != '\0'; d++) {
4463 if (*static_str == *d) {
4464 delim = 1;
4465 break;
4466 }
4467 }
4468 if (!delim)
4469 break;
4470 static_str++;
4471 }
4473 if (*static_str == '\0')
4474 return NULL;
4476 char* token_start = static_str;
4477 while (*static_str != '\0') {
4478 int delim = 0;
4479 const char* d;
4480 for (d = delimStr; *d != '\0'; d++) {
4481 if (*static_str == *d) {
4482 delim = 1;
4483 break;
4484 }
4485 }
4487 if (delim) {
4488 *static_str = '\0';
4489 static_str++;
4490 break;
4491 }
4492 static_str++;
4493 }
4495 return token_start;
4496}
4498i32 RGFW_XHandleClipboardSelectionHelper(void);
4501u8 RGFW_rgfwToKeyChar(u32 key) {
4502 u32 keycode = RGFW_rgfwToApiKey(key);
4503 RGFW_GOTO_WAYLAND(0);
4504#ifdef RGFW_X11
4505 Window root = DefaultRootWindow(_RGFW.display);
4506 Window ret_root, ret_child;
4507 int root_x, root_y, win_x, win_y;
4508 unsigned int mask;
4509 XQueryPointer(_RGFW.display, root, &ret_root, &ret_child, &root_x, &root_y, &win_x, &win_y, &mask);
4510 KeySym sym = (KeySym)XkbKeycodeToKeysym(_RGFW.display, (KeyCode)keycode, 0, (KeyCode)mask & ShiftMask ? 1 : 0);
4512 if ((mask & LockMask) && sym >= XK_a && sym <= XK_z)
4513 sym = (mask & ShiftMask) ? sym + 32 : sym - 32;
4514 if ((u8)sym != (u32)sym)
4515 sym = 0;
4517 return (u8)sym;
4518#endif
4519#ifdef RGFW_WAYLAND
4520 RGFW_WAYLAND_LABEL RGFW_UNUSED(keycode);
4521 return (u8)key;
4522#endif
4523}
4525RGFW_event* RGFW_window_checkEvent(RGFW_window* win) {
4526 RGFW_XHandleClipboardSelectionHelper();
4528 if (win == NULL || ((win->_flags & RGFW_windowFreeOnClose) && (win->_flags & RGFW_EVENT_QUIT))) return NULL;
4529 RGFW_event* ev = RGFW_window_checkEventCore(win);
4530 if (ev) return ev;
4532 #if defined(__linux__) && !defined(RGFW_NO_LINUX)
4533 if (RGFW_linux_updateGamepad(win)) return &win->event;
4534 #endif
4535 RGFW_GOTO_WAYLAND(0);
4536#ifdef RGFW_X11
4537 RGFW_LOAD_ATOM(XdndTypeList);
4538 RGFW_LOAD_ATOM(XdndSelection);
4539 RGFW_LOAD_ATOM(XdndEnter);
4540 RGFW_LOAD_ATOM(XdndPosition);
4541 RGFW_LOAD_ATOM(XdndStatus);
4542 RGFW_LOAD_ATOM(XdndLeave);
4543 RGFW_LOAD_ATOM(XdndDrop);
4544 RGFW_LOAD_ATOM(XdndFinished);
4545 RGFW_LOAD_ATOM(XdndActionCopy);
4546 RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST);
4547 RGFW_LOAD_ATOM(WM_PROTOCOLS);
4548 XPending(win->src.display);
4550 XEvent E; /*!< raw X11 event */
4552 /* if there is no unread qued events, get a new one */
4553 if ((QLength(win->src.display) || XEventsQueued(win->src.display, QueuedAlready) + XEventsQueued(win->src.display, QueuedAfterReading))
4554 && win->event.type != RGFW_quit
4555 )
4556 XNextEvent(win->src.display, &E);
4557 else {
4558 return NULL;
4559 }
4561 win->event.type = 0;
4563 /* xdnd data */
4564 static Window source = 0;
4565 static long version = 0;
4566 static i32 format = 0;
4568 XEvent reply = { ClientMessage };
4570 switch (E.type) {
4571 case KeyPress:
4572 case KeyRelease: {
4573 win->event.repeat = RGFW_FALSE;
4574 /* check if it's a real key release */
4575 if (E.type == KeyRelease && XEventsQueued(win->src.display, QueuedAfterReading)) { /* get next event if there is one */
4576 XEvent NE;
4577 XPeekEvent(win->src.display, &NE);
4579 if (E.xkey.time == NE.xkey.time && E.xkey.keycode == NE.xkey.keycode) /* check if the current and next are both the same */
4580 win->event.repeat = RGFW_TRUE;
4581 }
4583 /* set event key data */
4584 win->event.key = (u8)RGFW_apiKeyToRGFW(E.xkey.keycode);
4585 win->event.keyChar = (u8)RGFW_rgfwToKeyChar(win->event.key);
4587 RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current;
4589 /* get keystate data */
4590 win->event.type = (E.type == KeyPress) ? RGFW_keyPressed : RGFW_keyReleased;
4592 XKeyboardState keystate;
4593 XGetKeyboardControl(win->src.display, &keystate);
4595 RGFW_keyboard[win->event.key].current = (E.type == KeyPress);
4597 XkbStateRec state;
4598 XkbGetState(win->src.display, XkbUseCoreKbd, &state);
4599 RGFW_updateKeyMods(win, (state.locked_mods & LockMask), (state.locked_mods & Mod2Mask), (state.locked_mods & Mod3Mask));
4601 RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, (E.type == KeyPress));
4602 break;
4603 }
4604 case ButtonPress:
4605 case ButtonRelease:
4606 if (E.xbutton.button > RGFW_mouseFinal) { /* skip this event */
4607 XFlush(win->src.display);
4608 return RGFW_window_checkEvent(win);
4609 }
4611 win->event.type = RGFW_mouseButtonPressed + (E.type == ButtonRelease); /* the events match */
4612 win->event.button = (u8)(E.xbutton.button - 1);
4613 switch(win->event.button) {
4614 case RGFW_mouseScrollUp:
4615 win->event.scroll = 1;
4616 break;
4617 case RGFW_mouseScrollDown:
4618 win->event.scroll = -1;
4619 break;
4620 default: break;
4621 }
4623 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
4625 if (win->event.repeat == RGFW_FALSE)
4626 win->event.repeat = RGFW_isPressed(win, win->event.key);
4628 RGFW_mouseButtons[win->event.button].current = (E.type == ButtonPress);
4629 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, (E.type == ButtonPress));
4630 break;
4632 case MotionNotify:
4633 win->event.point.x = E.xmotion.x;
4634 win->event.point.y = E.xmotion.y;
4636 win->event.vector.x = win->event.point.x - win->_lastMousePoint.x;
4637 win->event.vector.y = win->event.point.y - win->_lastMousePoint.y;
4638 win->_lastMousePoint = win->event.point;
4640 win->event.type = RGFW_mousePosChanged;
4641 RGFW_mousePosCallback(win, win->event.point, win->event.vector);
4642 break;
4644 case GenericEvent: {
4645 /* MotionNotify is used for mouse events if the mouse isn't held */
4646 if (!(win->_flags & RGFW_HOLD_MOUSE)) {
4647 XFreeEventData(win->src.display, &E.xcookie);
4648 break;
4649 }
4651 XGetEventData(win->src.display, &E.xcookie);
4652 if (E.xcookie.evtype == XI_RawMotion) {
4653 XIRawEvent *raw = (XIRawEvent *)E.xcookie.data;
4654 if (raw->valuators.mask_len == 0) {
4655 XFreeEventData(win->src.display, &E.xcookie);
4656 break;
4657 }
4659 double deltaX = 0.0f;
4660 double deltaY = 0.0f;
4662 /* check if relative motion data exists where we think it does */
4663 if (XIMaskIsSet(raw->valuators.mask, 0) != 0)
4664 deltaX += raw->raw_values[0];
4665 if (XIMaskIsSet(raw->valuators.mask, 1) != 0)
4666 deltaY += raw->raw_values[1];
4668 win->event.vector = RGFW_POINT((i32)deltaX, (i32)deltaY);
4669 win->event.point.x = win->_lastMousePoint.x + win->event.vector.x;
4670 win->event.point.y = win->_lastMousePoint.y + win->event.vector.y;
4671 win->_lastMousePoint = win->event.point;
4673 RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2)));
4675 win->event.type = RGFW_mousePosChanged;
4676 RGFW_mousePosCallback(win, win->event.point, win->event.vector);
4677 }
4679 XFreeEventData(win->src.display, &E.xcookie);
4680 break;
4681 }
4683 case Expose: {
4684 win->event.type = RGFW_windowRefresh;
4685 RGFW_windowRefreshCallback(win);
4687#ifdef RGFW_ADVANCED_SMOOTH_RESIZE
4688 XSyncValue value;
4689 XSyncIntToValue(&value, (i32)win->src.counter_value);
4690 XSyncSetCounter(win->src.display, win->src.counter, value);
4691#endif
4692 break;
4693 }
4694 case MapNotify: case UnmapNotify: RGFW_window_checkMode(win); break;
4695 case ClientMessage: {
4696 /* if the client closed the window */
4697 if (E.xclient.data.l[0] == (long)wm_delete_window) {
4698 win->event.type = RGFW_quit;
4699 RGFW_window_setShouldClose(win, RGFW_TRUE);
4700 RGFW_windowQuitCallback(win);
4701 break;
4702 }
4703#ifdef RGFW_ADVANCED_SMOOTH_RESIZE
4704 if (E.xclient.message_type == WM_PROTOCOLS && (Atom)E.xclient.data.l[0] == _NET_WM_SYNC_REQUEST) {
4705 RGFW_windowRefreshCallback(win);
4706 win->src.counter_value = 0;
4707 win->src.counter_value |= E.xclient.data.l[2];
4708 win->src.counter_value |= (E.xclient.data.l[3] << 32);
4710 XSyncValue value;
4711 XSyncIntToValue(&value, (i32)win->src.counter_value);
4712 XSyncSetCounter(win->src.display, win->src.counter, value);
4713 break;
4714 }
4715#endif
4716 if ((win->_flags & RGFW_windowAllowDND) == 0)
4717 break;
4719 reply.xclient.window = source;
4720 reply.xclient.format = 32;
4721 reply.xclient.data.l[0] = (long)win->src.window;
4722 reply.xclient.data.l[1] = 0;
4723 reply.xclient.data.l[2] = None;
4725 if (E.xclient.message_type == XdndEnter) {
4726 if (version > 5)
4727 break;
4729 unsigned long count;
4730 Atom* formats;
4731 Atom real_formats[6];
4732 Bool list = E.xclient.data.l[1] & 1;
4734 source = (unsigned long int)E.xclient.data.l[0];
4735 version = E.xclient.data.l[1] >> 24;
4736 format = None;
4737 if (list) {
4738 Atom actualType;
4739 i32 actualFormat;
4740 unsigned long bytesAfter;
4742 XGetWindowProperty(
4743 win->src.display, source, XdndTypeList,
4744 0, LONG_MAX, False, 4,
4745 &actualType, &actualFormat, &count, &bytesAfter, (u8**)&formats
4746 );
4747 } else {
4748 count = 0;
4750 size_t i;
4751 for (i = 2; i < 5; i++) {
4752 if (E.xclient.data.l[i] != None) {
4753 real_formats[count] = (unsigned long int)E.xclient.data.l[i];
4754 count += 1;
4755 }
4756 }
4758 formats = real_formats;
4759 }
4761 size_t i;
4762 for (i = 0; i < count; i++) {
4763 if (formats[i] == XtextUriList || formats[i] == XtextPlain) {
4764 format = (int)formats[i];
4765 break;
4766 }
4767 }
4769 if (list) {
4770 XFree(formats);
4771 }
4773 break;
4774 }
4776 if (E.xclient.message_type == XdndPosition) {
4777 const i32 xabs = (E.xclient.data.l[2] >> 16) & 0xffff;
4778 const i32 yabs = (E.xclient.data.l[2]) & 0xffff;
4779 Window dummy;
4780 i32 xpos, ypos;
4782 if (version > 5)
4783 break;
4785 XTranslateCoordinates(
4786 win->src.display, XDefaultRootWindow(win->src.display), win->src.window,
4787 xabs, yabs, &xpos, &ypos, &dummy
4788 );
4790 win->event.point.x = xpos;
4791 win->event.point.y = ypos;
4793 reply.xclient.window = source;
4794 reply.xclient.message_type = XdndStatus;
4796 if (format) {
4797 reply.xclient.data.l[1] = 1;
4798 if (version >= 2)
4799 reply.xclient.data.l[4] = (long)XdndActionCopy;
4800 }
4802 XSendEvent(win->src.display, source, False, NoEventMask, &reply);
4803 XFlush(win->src.display);
4804 break;
4805 }
4806 if (E.xclient.message_type != XdndDrop)
4807 break;
4809 if (version > 5)
4810 break;
4812 size_t i;
4813 for (i = 0; i < win->event.droppedFilesCount; i++)
4814 win->event.droppedFiles[i][0] = '\0';
4816 win->event.droppedFilesCount = 0;
4819 win->event.type = RGFW_DNDInit;
4821 if (format) {
4822 Time time = (version >= 1)
4823 ? (Time)E.xclient.data.l[2]
4824 : CurrentTime;
4826 XConvertSelection(
4827 win->src.display, XdndSelection, (Atom)format,
4828 XdndSelection, win->src.window, time
4829 );
4830 } else if (version >= 2) {
4831 XEvent new_reply = { ClientMessage };
4833 XSendEvent(win->src.display, source, False, NoEventMask, &new_reply);
4834 XFlush(win->src.display);
4835 }
4837 RGFW_dndInitCallback(win, win->event.point);
4838 } break;
4839 case SelectionRequest:
4840 RGFW_XHandleClipboardSelection(&E);
4841 XFlush(win->src.display);
4842 return RGFW_window_checkEvent(win);
4843 case SelectionNotify: {
4844 /* this is only for checking for xdnd drops */
4845 if (E.xselection.property != XdndSelection || !(win->_flags & RGFW_windowAllowDND))
4846 break;
4847 char* data;
4848 unsigned long result;
4850 Atom actualType;
4851 i32 actualFormat;
4852 unsigned long bytesAfter;
4854 XGetWindowProperty(win->src.display, E.xselection.requestor, E.xselection.property, 0, LONG_MAX, False, E.xselection.target, &actualType, &actualFormat, &result, &bytesAfter, (u8**) &data);
4856 if (result == 0)
4857 break;
4859 const char* prefix = (const char*)"file://";
4861 char* line;
4863 win->event.droppedFilesCount = 0;
4864 win->event.type = RGFW_DND;
4866 while ((line = (char*)RGFW_strtok(data, "\r\n"))) {
4867 char path[RGFW_MAX_PATH];
4869 data = NULL;
4871 if (line[0] == '#')
4872 continue;
4874 char* l;
4875 for (l = line; 1; l++) {
4876 if ((l - line) > 7)
4877 break;
4878 else if (*l != prefix[(l - line)])
4879 break;
4880 else if (*l == '\0' && prefix[(l - line)] == '\0') {
4881 line += 7;
4882 while (*line != '/')
4883 line++;
4884 break;
4885 } else if (*l == '\0')
4886 break;
4887 }
4889 win->event.droppedFilesCount++;
4891 size_t index = 0;
4892 while (*line) {
4893 if (line[0] == '%' && line[1] && line[2]) {
4894 const char digits[3] = { line[1], line[2], '\0' };
4895 path[index] = (char) RGFW_STRTOL(digits, NULL, 16);
4896 line += 2;
4897 } else
4898 path[index] = *line;
4900 index++;
4901 line++;
4902 }
4903 path[index] = '\0';
4904 RGFW_MEMCPY(win->event.droppedFiles[win->event.droppedFilesCount - 1], path, index + 1);
4905 }
4907 RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount);
4908 if (data)
4909 XFree(data);
4911 if (version >= 2) {
4912 XEvent new_reply = { ClientMessage };
4913 new_reply.xclient.window = source;
4914 new_reply.xclient.message_type = XdndFinished;
4915 new_reply.xclient.format = 32;
4916 new_reply.xclient.data.l[1] = (long int)result;
4917 new_reply.xclient.data.l[2] = (long int)XdndActionCopy;
4918 XSendEvent(win->src.display, source, False, NoEventMask, &new_reply);
4919 XFlush(win->src.display);
4920 }
4921 break;
4922 }
4923 case FocusIn:
4924 if ((win->_flags & RGFW_windowFullscreen))
4925 XMapRaised(win->src.display, win->src.window);
4927 win->_flags |= RGFW_windowFocus;
4928 win->event.type = RGFW_focusIn;
4929 RGFW_focusCallback(win, 1);
4932 if ((win->_flags & RGFW_HOLD_MOUSE)) RGFW_window_mouseHold(win, RGFW_AREA(win->r.w, win->r.h));
4933 break;
4934 case FocusOut:
4935 win->event.type = RGFW_focusOut;
4936 RGFW_focusCallback(win, 0);
4937 RGFW_window_focusLost(win);
4938 break;
4939 case PropertyNotify: RGFW_window_checkMode(win); break;
4940 case EnterNotify: {
4941 win->event.type = RGFW_mouseEnter;
4942 win->event.point.x = E.xcrossing.x;
4943 win->event.point.y = E.xcrossing.y;
4944 RGFW_mouseNotifyCallback(win, win->event.point, 1);
4945 break;
4946 }
4948 case LeaveNotify: {
4949 win->event.type = RGFW_mouseLeave;
4950 RGFW_mouseNotifyCallback(win, win->event.point, 0);
4951 break;
4952 }
4954 case ConfigureNotify: {
4955 /* detect resize */
4956 RGFW_window_checkMode(win);
4957 if (E.xconfigure.width != win->src.r.w || E.xconfigure.height != win->src.r.h) {
4958 win->event.type = RGFW_windowResized;
4959 win->src.r = win->r = RGFW_RECT(win->src.r.x, win->src.r.y, E.xconfigure.width, E.xconfigure.height);
4960 RGFW_windowResizedCallback(win, win->r);
4961 break;
4962 }
4964 /* detect move */
4965 if (E.xconfigure.x != win->src.r.x || E.xconfigure.y != win->src.r.y) {
4966 win->event.type = RGFW_windowMoved;
4967 win->src.r = win->r = RGFW_RECT(E.xconfigure.x, E.xconfigure.y, win->src.r.w, win->src.r.h);
4968 RGFW_windowMovedCallback(win, win->r);
4969 break;
4970 }
4972 break;
4973 }
4974 default:
4975 XFlush(win->src.display);
4976 return RGFW_window_checkEvent(win);
4977 }
4978 XFlush(win->src.display);
4979 if (win->event.type) return &win->event;
4980 else return NULL;
4981#endif
4982#ifdef RGFW_WAYLAND
4983 RGFW_WAYLAND_LABEL
4984 if ((win->_flags & RGFW_windowHide) == 0)
4985 wl_display_roundtrip(win->src.wl_display);
4986 return NULL;
4987#endif
4988}
4990void RGFW_window_move(RGFW_window* win, RGFW_point v) {
4991 RGFW_ASSERT(win != NULL);
4992 win->r.x = v.x;
4993 win->r.y = v.y;
4994 RGFW_GOTO_WAYLAND(0);
4995#ifdef RGFW_X11
4996 XMoveWindow(win->src.display, win->src.window, v.x, v.y);
4997#endif
4998#ifdef RGFW_WAYLAND
4999 RGFW_WAYLAND_LABEL
5000 RGFW_ASSERT(win != NULL);
5002 if (win->src.compositor) {
5003 struct wl_pointer *pointer = wl_seat_get_pointer(win->src.seat);
5004 if (!pointer) {
5005 return;
5006 }
5008 wl_display_flush(win->src.wl_display);
5009 }
5010#endif
5011}
5014void RGFW_window_resize(RGFW_window* win, RGFW_area a) {
5015 RGFW_ASSERT(win != NULL);
5016 win->r.w = (i32)a.w;
5017 win->r.h = (i32)a.h;
5018 RGFW_GOTO_WAYLAND(0);
5019#ifdef RGFW_X11
5020 XResizeWindow(win->src.display, win->src.window, a.w, a.h);
5022 if ((win->_flags & RGFW_windowNoResize)) {
5023 XSizeHints sh;
5024 sh.flags = (1L << 4) | (1L << 5);
5025 sh.min_width = sh.max_width = (i32)a.w;
5026 sh.min_height = sh.max_height = (i32)a.h;
5028 XSetWMSizeHints(win->src.display, (Drawable) win->src.window, &sh, XA_WM_NORMAL_HINTS);
5029 }
5030#endif
5031#ifdef RGFW_WAYLAND
5032 RGFW_WAYLAND_LABEL
5033 if (win->src.compositor) {
5034 xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->r.w, win->r.h);
5035 #ifdef RGFW_OPENGL
5036 wl_egl_window_resize(win->src.eglWindow, (i32)a.w, (i32)a.h, 0, 0);
5037 #endif
5038 }
5039#endif
5040}
5042void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) {
5043 RGFW_ASSERT(win != NULL);
5044 RGFW_GOTO_WAYLAND(0);
5046 if (a.w == 0 && a.h == 0)
5047 return;
5048#ifdef RGFW_X11
5049 XSizeHints hints;
5050 long flags;
5052 XGetWMNormalHints(win->src.display, win->src.window, &hints, &flags);
5054 hints.flags |= PAspect;
5056 hints.min_aspect.x = hints.max_aspect.x = (i32)a.w;
5057 hints.min_aspect.y = hints.max_aspect.y = (i32)a.h;
5059 XSetWMNormalHints(win->src.display, win->src.window, &hints);
5060 return;
5061#endif
5062#ifdef RGFW_WAYLAND
5063 RGFW_WAYLAND_LABEL
5064#endif
5065}
5067void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) {
5068 RGFW_ASSERT(win != NULL);
5069 RGFW_GOTO_WAYLAND(0);
5070#ifdef RGFW_X11
5071 long flags;
5072 XSizeHints hints;
5073 RGFW_MEMSET(&hints, 0, sizeof(XSizeHints));
5075 XGetWMNormalHints(win->src.display, win->src.window, &hints, &flags);
5077 hints.flags |= PMinSize;
5079 hints.min_width = (i32)a.w;
5080 hints.min_height = (i32)a.h;
5082 XSetWMNormalHints(win->src.display, win->src.window, &hints);
5083 return;
5084#endif
5085#ifdef RGFW_WAYLAND
5086RGFW_WAYLAND_LABEL RGFW_UNUSED(a);
5087#endif
5088}
5090void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) {
5091 RGFW_ASSERT(win != NULL);
5092 RGFW_GOTO_WAYLAND(0);
5093#ifdef RGFW_X11
5094 long flags;
5095 XSizeHints hints;
5096 RGFW_MEMSET(&hints, 0, sizeof(XSizeHints));
5098 XGetWMNormalHints(win->src.display, win->src.window, &hints, &flags);
5100 hints.flags |= PMaxSize;
5102 hints.max_width = (i32)a.w;
5103 hints.max_height = (i32)a.h;
5105 XSetWMNormalHints(win->src.display, win->src.window, &hints);
5106#endif
5107#ifdef RGFW_WAYLAND
5108 RGFW_WAYLAND_LABEL RGFW_UNUSED(a);
5109#endif
5110}
5112#ifdef RGFW_X11
5113void RGFW_toggleXMaximized(RGFW_window* win, RGFW_bool maximized);
5114void RGFW_toggleXMaximized(RGFW_window* win, RGFW_bool maximized) {
5115 RGFW_ASSERT(win != NULL);
5116 RGFW_LOAD_ATOM(_NET_WM_STATE);
5117 RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_VERT);
5118 RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ);
5120 XEvent xev = {0};
5121 xev.type = ClientMessage;
5122 xev.xclient.window = win->src.window;
5123 xev.xclient.message_type = _NET_WM_STATE;
5124 xev.xclient.format = 32;
5125 xev.xclient.data.l[0] = maximized;
5126 xev.xclient.data.l[1] = (long int)_NET_WM_STATE_MAXIMIZED_HORZ;
5127 xev.xclient.data.l[2] = (long int)_NET_WM_STATE_MAXIMIZED_VERT;
5128 xev.xclient.data.l[3] = 0;
5129 xev.xclient.data.l[4] = 0;
5131 XSendEvent(win->src.display, DefaultRootWindow(win->src.display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
5132}
5133#endif
5135void RGFW_window_maximize(RGFW_window* win) {
5136 win->_oldRect = win->r;
5137 RGFW_GOTO_WAYLAND(0);
5138#ifdef RGFW_X11
5139 RGFW_toggleXMaximized(win, 1);
5140 return;
5141#endif
5142#ifdef RGFW_WAYLAND
5143 RGFW_WAYLAND_LABEL
5144 return;
5145#endif
5146}
5148void RGFW_window_focus(RGFW_window* win) {
5149 RGFW_ASSERT(win);
5150 RGFW_GOTO_WAYLAND(0);
5151#ifdef RGFW_X11
5152 XWindowAttributes attr;
5153 XGetWindowAttributes(win->src.display, win->src.window, &attr);
5154 if (attr.map_state != IsViewable) return;
5156 XSetInputFocus(win->src.display, win->src.window, RevertToPointerRoot, CurrentTime);
5157 XFlush(win->src.display);
5158#endif
5159#ifdef RGFW_WAYLAND
5160RGFW_WAYLAND_LABEL;
5161#endif
5162}
5164void RGFW_window_raise(RGFW_window* win) {
5165 RGFW_ASSERT(win);
5166 RGFW_GOTO_WAYLAND(0);
5167#ifdef RGFW_X11
5168 XRaiseWindow(win->src.display, win->src.window);
5169 XMapRaised(win->src.display, win->src.window);
5170#endif
5171#ifdef RGFW_WAYLAND
5172RGFW_WAYLAND_LABEL;
5173#endif
5174}
5176#ifdef RGFW_X11
5177void RGFW_window_setXAtom(RGFW_window* win, Atom netAtom, RGFW_bool fullscreen);
5178void RGFW_window_setXAtom(RGFW_window* win, Atom netAtom, RGFW_bool fullscreen) {
5179 RGFW_ASSERT(win != NULL);
5180 RGFW_LOAD_ATOM(_NET_WM_STATE);
5182 XEvent xev = {0};
5183 xev.xclient.type = ClientMessage;
5184 xev.xclient.serial = 0;
5185 xev.xclient.send_event = True;
5186 xev.xclient.message_type = _NET_WM_STATE;
5187 xev.xclient.window = win->src.window;
5188 xev.xclient.format = 32;
5189 xev.xclient.data.l[0] = fullscreen;
5190 xev.xclient.data.l[1] = (long int)netAtom;
5191 xev.xclient.data.l[2] = 0;
5193 XSendEvent(win->src.display, DefaultRootWindow(win->src.display), False, SubstructureNotifyMask | SubstructureRedirectMask, &xev);
5194}
5195#endif
5197void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) {
5198 RGFW_ASSERT(win != NULL);
5199 RGFW_GOTO_WAYLAND(0);
5200 if (fullscreen) {
5201 win->_flags |= RGFW_windowFullscreen;
5202 win->_oldRect = win->r;
5203 }
5204 else win->_flags &= ~(u32)RGFW_windowFullscreen;
5205#ifdef RGFW_X11
5206 RGFW_LOAD_ATOM(_NET_WM_STATE_FULLSCREEN);
5208 RGFW_window_setXAtom(win, _NET_WM_STATE_FULLSCREEN, fullscreen);
5210 XRaiseWindow(win->src.display, win->src.window);
5211 XMapRaised(win->src.display, win->src.window);
5212#endif
5213#ifdef RGFW_WAYLAND
5214 RGFW_WAYLAND_LABEL;
5215#endif
5216}
5218void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) {
5219 RGFW_ASSERT(win != NULL);
5220 RGFW_GOTO_WAYLAND(0);
5221#ifdef RGFW_X11
5222 RGFW_LOAD_ATOM(_NET_WM_STATE_ABOVE);
5223 RGFW_window_setXAtom(win, _NET_WM_STATE_ABOVE, floating);
5224#endif
5225#ifdef RGFW_WAYLAND
5226RGFW_WAYLAND_LABEL RGFW_UNUSED(floating);
5227#endif
5228}
5230void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) {
5231 RGFW_ASSERT(win != NULL);
5232 RGFW_GOTO_WAYLAND(0);
5233#ifdef RGFW_X11
5234 const u32 value = (u32) (0xffffffffu * (double) opacity);
5235 RGFW_LOAD_ATOM(NET_WM_WINDOW_OPACITY);
5236 XChangeProperty(win->src.display, win->src.window,
5237 NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32, PropModeReplace, (unsigned char*) &value, 1);
5238#endif
5239#ifdef RGFW_WAYLAND
5240RGFW_WAYLAND_LABEL RGFW_UNUSED(opacity);
5241#endif
5242}
5244void RGFW_window_minimize(RGFW_window* win) {
5245 RGFW_ASSERT(win != NULL);
5246 RGFW_GOTO_WAYLAND(0);
5247 if (RGFW_window_isMaximized(win)) return;
5249 win->_oldRect = win->r;
5250#ifdef RGFW_X11
5251 XIconifyWindow(win->src.display, win->src.window, DefaultScreen(win->src.display));
5252 XFlush(win->src.display);
5253#endif
5254#ifdef RGFW_WAYLAND
5255 RGFW_WAYLAND_LABEL;
5256#endif
5257}
5259void RGFW_window_restore(RGFW_window* win) {
5260 RGFW_ASSERT(win != NULL);
5261 RGFW_GOTO_WAYLAND(0);
5262#ifdef RGFW_X11
5263 RGFW_toggleXMaximized(win, 0);
5264#endif
5265#ifdef RGFW_WAYLAND
5266 RGFW_WAYLAND_LABEL
5267#endif
5268 win->r = win->_oldRect;
5269 RGFW_window_move(win, RGFW_POINT(win->r.x, win->r.y));
5270 RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h));
5272 RGFW_window_show(win);
5273#ifdef RGFW_X11
5274 XFlush(win->src.display);
5275#endif
5276}
5278RGFW_bool RGFW_window_isFloating(RGFW_window* win) {
5279 RGFW_GOTO_WAYLAND(0);
5280#ifdef RGFW_X11
5281 RGFW_LOAD_ATOM(_NET_WM_STATE);
5282 RGFW_LOAD_ATOM(_NET_WM_STATE_ABOVE);
5284 Atom actual_type;
5285 int actual_format;
5286 unsigned long nitems, bytes_after;
5287 Atom* prop_return = NULL;
5289 int status = XGetWindowProperty(win->src.display, win->src.window, _NET_WM_STATE, 0, (~0L), False, XA_ATOM,
5290 &actual_type, &actual_format, &nitems, &bytes_after,
5291 (unsigned char **)&prop_return);
5293 if (status != Success || actual_type != XA_ATOM)
5294 return RGFW_FALSE;
5296 unsigned long i;
5297 for (i = 0; i < nitems; i++)
5298 if (prop_return[i] == _NET_WM_STATE_ABOVE) return RGFW_TRUE;
5300 if (prop_return)
5301 XFree(prop_return);
5302#endif
5303#ifdef RGFW_WAYLAND
5304 RGFW_WAYLAND_LABEL RGFW_UNUSED(win);
5305#endif
5306 return RGFW_FALSE;
5307}
5309void RGFW_window_setName(RGFW_window* win, const char* name) {
5310 RGFW_ASSERT(win != NULL);
5311 RGFW_GOTO_WAYLAND(0);
5312 #ifdef RGFW_X11
5313 XStoreName(win->src.display, win->src.window, name);
5315 RGFW_LOAD_ATOM(_NET_WM_NAME);
5317 char buf[256];
5318 RGFW_MEMSET(buf, 0, sizeof(buf));
5319 RGFW_STRNCPY(buf, name, sizeof(buf) - 1);
5321 XChangeProperty(
5322 win->src.display, win->src.window, _NET_WM_NAME, RGFW_XUTF8_STRING,
5323 8, PropModeReplace, (u8*)buf, sizeof(buf)
5324 );
5325 #endif
5326 #ifdef RGFW_WAYLAND
5327 RGFW_WAYLAND_LABEL
5328 if (win->src.compositor)
5329 xdg_toplevel_set_title(win->src.xdg_toplevel, name);
5330 #endif
5331}
5333#ifndef RGFW_NO_PASSTHROUGH
5334void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) {
5335 RGFW_ASSERT(win != NULL);
5336 RGFW_GOTO_WAYLAND(0);
5337#ifdef RGFW_X11
5338 if (passthrough) {
5339 Region region = XCreateRegion();
5340 XShapeCombineRegion(win->src.display, win->src.window, ShapeInput, 0, 0, region, ShapeSet);
5341 XDestroyRegion(region);
5343 return;
5344 }
5346 XShapeCombineMask(win->src.display, win->src.window, ShapeInput, 0, 0, None, ShapeSet);
5347#endif
5348#ifdef RGFW_WAYLAND
5349 RGFW_WAYLAND_LABEL RGFW_UNUSED(passthrough);
5350#endif
5351}
5352#endif /* RGFW_NO_PASSTHROUGH */
5354RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* icon, RGFW_area a, i32 channels, u8 type) {
5355 RGFW_ASSERT(win != NULL);
5356 RGFW_GOTO_WAYLAND(0);
5357#ifdef RGFW_X11
5358 RGFW_LOAD_ATOM(_NET_WM_ICON);
5359 if (icon == NULL || (channels != 3 && channels != 4)) {
5360 RGFW_bool res = (RGFW_bool)XChangeProperty(
5361 win->src.display, win->src.window, _NET_WM_ICON, XA_CARDINAL, 32,
5362 PropModeReplace, (u8*)NULL, 0
5363 );
5364 return res;
5365 }
5367 i32 count = (i32)(2 + (a.w * a.h));
5369 unsigned long* data = (unsigned long*) RGFW_ALLOC((u32)count * sizeof(unsigned long));
5370 RGFW_ASSERT(data != NULL);
5372 data[0] = (unsigned long)a.w;
5373 data[1] = (unsigned long)a.h;
5375 unsigned long* target = &data[2];
5376 u32 x, y;
5378 for (x = 0; x < a.w; x++) {
5379 for (y = 0; y < a.h; y++) {
5380 size_t i = y * a.w + x;
5381 u32 alpha = (channels == 4) ? icon[i * 4 + 3] : 0xFF;
5383 target[i] = (unsigned long)((icon[i * 4 + 0]) << 16) |
5384 (unsigned long)((icon[i * 4 + 1]) << 8) |
5385 (unsigned long)((icon[i * 4 + 2]) << 0) |
5386 (unsigned long)(alpha << 24);
5387 }
5388 }
5390 RGFW_bool res = RGFW_TRUE;
5391 if (type & RGFW_iconTaskbar) {
5392 res = (RGFW_bool)XChangeProperty(
5393 win->src.display, win->src.window, _NET_WM_ICON, XA_CARDINAL, 32,
5394 PropModeReplace, (u8*)data, count
5395 );
5396 }
5398 if (type & RGFW_iconWindow) {
5399 XWMHints wm_hints;
5400 wm_hints.flags = IconPixmapHint;
5402 i32 depth = DefaultDepth(win->src.display, DefaultScreen(win->src.display));
5403 XImage *image = XCreateImage(win->src.display, DefaultVisual(win->src.display, DefaultScreen(win->src.display)),
5404 (u32)depth, ZPixmap, 0, (char *)target, a.w, a.h, 32, 0);
5406 wm_hints.icon_pixmap = XCreatePixmap(win->src.display, win->src.window, a.w, a.h, (u32)depth);
5407 XPutImage(win->src.display, wm_hints.icon_pixmap, DefaultGC(win->src.display, DefaultScreen(win->src.display)), image, 0, 0, 0, 0, a.w, a.h);
5408 image->data = NULL;
5409 XDestroyImage(image);
5411 XSetWMHints(win->src.display, win->src.window, &wm_hints);
5412 }
5414 RGFW_FREE(data);
5415 XFlush(win->src.display);
5416 return RGFW_BOOL(res);
5417#endif
5418#ifdef RGFW_WAYLAND
5419 RGFW_WAYLAND_LABEL RGFW_UNUSED(icon); RGFW_UNUSED(a); RGFW_UNUSED(channels); RGFW_UNUSED(type);
5420 return RGFW_FALSE;
5421#endif
5422}
5424RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) {
5425 RGFW_ASSERT(icon);
5426 RGFW_ASSERT(channels == 3 || channels == 4);
5427 RGFW_GOTO_WAYLAND(0);
5429#ifdef RGFW_X11
5430#ifndef RGFW_NO_X11_CURSOR
5431 RGFW_init();
5432 XcursorImage* native = XcursorImageCreate((i32)a.w, (i32)a.h);
5433 native->xhot = 0;
5434 native->yhot = 0;
5436 XcursorPixel* target = native->pixels;
5437 size_t x, y;
5438 for (x = 0; x < a.w; x++) {
5439 for (y = 0; y < a.h; y++) {
5440 size_t i = y * a.w + x;
5441 u32 alpha = (channels == 4) ? icon[i * 4 + 3] : 0xFF;
5443 target[i] = (u32)((icon[i * 4 + 0]) << 16)
5444 | (u32)((icon[i * 4 + 1]) << 8)
5445 | (u32)((icon[i * 4 + 2]) << 0)
5446 | (u32)(alpha << 24);
5447 }
5448 }
5450 Cursor cursor = XcursorImageLoadCursor(_RGFW.display, native);
5451 XcursorImageDestroy(native);
5453 return (void*)cursor;
5454#else
5455 RGFW_UNUSED(image); RGFW_UNUSED(a.w); RGFW_UNUSED(channels);
5456 return NULL;
5457#endif
5458#endif
5459#ifdef RGFW_WAYLAND
5460 RGFW_WAYLAND_LABEL
5461 RGFW_UNUSED(icon); RGFW_UNUSED(a); RGFW_UNUSED(channels);
5462 return NULL; /* TODO */
5463#endif
5464}
5466void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) {
5467RGFW_GOTO_WAYLAND(0);
5468#ifdef RGFW_X11
5469 RGFW_ASSERT(win && mouse);
5470 XDefineCursor(win->src.display, win->src.window, (Cursor)mouse);
5471#endif
5472#ifdef RGFW_WAYLAND
5473 RGFW_WAYLAND_LABEL
5474 RGFW_UNUSED(win); RGFW_UNUSED(mouse);
5475#endif
5476}
5478void RGFW_freeMouse(RGFW_mouse* mouse) {
5479RGFW_GOTO_WAYLAND(0);
5480#ifdef RGFW_X11
5481 RGFW_ASSERT(mouse);
5482 XFreeCursor(_RGFW.display, (Cursor)mouse);
5483#endif
5484#ifdef RGFW_WAYLAND
5485 RGFW_WAYLAND_LABEL
5486 RGFW_UNUSED(mouse);
5487#endif
5488}
5490void RGFW_window_moveMouse(RGFW_window* win, RGFW_point p) {
5491RGFW_GOTO_WAYLAND(1);
5492#ifdef RGFW_X11
5493 RGFW_ASSERT(win != NULL);
5495 XEvent event;
5496 XQueryPointer(win->src.display, DefaultRootWindow(win->src.display),
5497 &event.xbutton.root, &event.xbutton.window,
5498 &event.xbutton.x_root, &event.xbutton.y_root,
5499 &event.xbutton.x, &event.xbutton.y,
5500 &event.xbutton.state);
5502 win->_lastMousePoint = RGFW_POINT(p.x - win->r.x, p.y - win->r.y);
5503 if (event.xbutton.x == p.x && event.xbutton.y == p.y)
5504 return;
5506 XWarpPointer(win->src.display, None, win->src.window, 0, 0, 0, 0, (int) p.x - win->r.x, (int) p.y - win->r.y);
5507#endif
5508#ifdef RGFW_WAYLAND
5509 RGFW_WAYLAND_LABEL
5510 RGFW_UNUSED(win); RGFW_UNUSED(p);
5511#endif
5512}
5514RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) {
5515 return RGFW_window_setMouseStandard(win, RGFW_mouseArrow);
5516}
5518RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) {
5519 RGFW_ASSERT(win != NULL);
5520 RGFW_GOTO_WAYLAND(0);
5521#ifdef RGFW_X11
5522 static const u8 mouseIconSrc[16] = { XC_arrow, XC_left_ptr, XC_xterm, XC_crosshair, XC_hand2, XC_sb_h_double_arrow, XC_sb_v_double_arrow, XC_bottom_left_corner, XC_bottom_right_corner, XC_fleur, XC_X_cursor};
5524 if (mouse > (sizeof(mouseIconSrc) / sizeof(u8)))
5525 return RGFW_FALSE;
5527 mouse = mouseIconSrc[mouse];
5529 Cursor cursor = XCreateFontCursor(win->src.display, mouse);
5530 XDefineCursor(win->src.display, win->src.window, (Cursor) cursor);
5532 XFreeCursor(win->src.display, (Cursor) cursor);
5533 return RGFW_TRUE;
5534#endif
5535#ifdef RGFW_WAYLAND
5536 RGFW_WAYLAND_LABEL { }
5537 static const char* iconStrings[16] = { "left_ptr", "left_ptr", "text", "cross", "pointer", "e-resize", "n-resize", "nw-resize", "ne-resize", "all-resize", "not-allowed" };
5539 struct wl_cursor* wlcursor = wl_cursor_theme_get_cursor(RGFW_wl_cursor_theme, iconStrings[mouse]);
5540 RGFW_cursor_image = wlcursor->images[0];
5541 struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(RGFW_cursor_image);
5543 wl_surface_attach(RGFW_cursor_surface, cursor_buffer, 0, 0);
5544 wl_surface_commit(RGFW_cursor_surface);
5545 return RGFW_TRUE;
5547#endif
5548}
5550void RGFW_window_hide(RGFW_window* win) {
5551 RGFW_GOTO_WAYLAND(0);
5552#ifdef RGFW_X11
5553 XUnmapWindow(win->src.display, win->src.window);
5554#endif
5555#ifdef RGFW_WAYLAND
5556 RGFW_WAYLAND_LABEL
5557 wl_surface_attach(win->src.surface, NULL, 0, 0);
5558 wl_surface_commit(win->src.surface);
5559 win->_flags |= RGFW_windowHide;
5560#endif
5561}
5563void RGFW_window_show(RGFW_window* win) {
5564 win->_flags &= ~(u32)RGFW_windowHide;
5565 if (win->_flags & RGFW_windowFocusOnShow) RGFW_window_focus(win);
5566 RGFW_GOTO_WAYLAND(0);
5567#ifdef RGFW_X11
5568 XMapWindow(win->src.display, win->src.window);
5569#endif
5570#ifdef RGFW_WAYLAND
5571 RGFW_WAYLAND_LABEL
5572 /* wl_surface_attach(win->src.surface, win->rc., 0, 0); */
5573 wl_surface_commit(win->src.surface);
5574#endif
5575}
5577RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) {
5578 RGFW_GOTO_WAYLAND(1);
5579#ifdef RGFW_X11
5580 RGFW_init();
5581 if (XGetSelectionOwner(_RGFW.display, RGFW_XCLIPBOARD) == _RGFW.helperWindow) {
5582 if (str != NULL)
5583 RGFW_STRNCPY(str, _RGFW.clipboard, _RGFW.clipboard_len - 1);
5584 _RGFW.clipboard[_RGFW.clipboard_len - 1] = '\0';
5585 return (RGFW_ssize_t)_RGFW.clipboard_len - 1;
5586 }
5588 XEvent event;
5589 int format;
5590 unsigned long N, sizeN;
5591 char* data;
5592 Atom target;
5594 RGFW_LOAD_ATOM(XSEL_DATA);
5596 XConvertSelection(_RGFW.display, RGFW_XCLIPBOARD, RGFW_XUTF8_STRING, XSEL_DATA, _RGFW.helperWindow, CurrentTime);
5597 XSync(_RGFW.display, 0);
5598 while (1) {
5599 XNextEvent(_RGFW.display, &event);
5600 if (event.type != SelectionNotify) continue;
5602 if (event.xselection.selection != RGFW_XCLIPBOARD || event.xselection.property == 0)
5603 return -1;
5604 break;
5605 }
5607 XGetWindowProperty(event.xselection.display, event.xselection.requestor,
5608 event.xselection.property, 0L, (~0L), 0, AnyPropertyType, &target,
5609 &format, &sizeN, &N, (u8**) &data);
5611 RGFW_ssize_t size;
5612 if (sizeN > strCapacity && str != NULL)
5613 size = -1;
5615 if ((target == RGFW_XUTF8_STRING || target == XA_STRING) && str != NULL) {
5616 RGFW_MEMCPY(str, data, sizeN);
5617 str[sizeN] = '\0';
5618 XFree(data);
5619 } else if (str != NULL) size = -1;
5621 XDeleteProperty(event.xselection.display, event.xselection.requestor, event.xselection.property);
5622 size = (RGFW_ssize_t)sizeN;
5624 return size;
5625 #endif
5626 #if defined(RGFW_WAYLAND)
5627 RGFW_WAYLAND_LABEL RGFW_UNUSED(str); RGFW_UNUSED(strCapacity);
5628 return 0;
5629 #endif
5630}
5632i32 RGFW_XHandleClipboardSelectionHelper(void) {
5633#ifdef RGFW_X11
5634 RGFW_LOAD_ATOM(SAVE_TARGETS);
5636 XEvent event;
5637 XPending(_RGFW.display);
5639 if (QLength(_RGFW.display) || XEventsQueued(_RGFW.display, QueuedAlready) + XEventsQueued(_RGFW.display, QueuedAfterReading))
5640 XNextEvent(_RGFW.display, &event);
5641 else
5642 return 0;
5644 switch (event.type) {
5645 case SelectionRequest:
5646 RGFW_XHandleClipboardSelection(&event);
5647 return 0;
5648 case SelectionNotify:
5649 if (event.xselection.target == SAVE_TARGETS)
5650 return 0;
5651 break;
5652 default: break;
5653 }
5655 return 0;
5656#else
5657 return 1;
5658#endif
5659}
5661void RGFW_writeClipboard(const char* text, u32 textLen) {
5662 RGFW_GOTO_WAYLAND(1);
5663 #ifdef RGFW_X11
5664 RGFW_LOAD_ATOM(SAVE_TARGETS);
5665 RGFW_init();
5667 /* request ownership of the clipboard section and request to convert it, this means its our job to convert it */
5668 XSetSelectionOwner(_RGFW.display, RGFW_XCLIPBOARD, _RGFW.helperWindow, CurrentTime);
5669 if (XGetSelectionOwner(_RGFW.display, RGFW_XCLIPBOARD) != _RGFW.helperWindow) {
5670 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errClipboard, RGFW_DEBUG_CTX(_RGFW.root, 0), "X11 failed to become owner of clipboard selection");
5671 return;
5672 }
5674 if (_RGFW.clipboard)
5675 RGFW_FREE(_RGFW.clipboard);
5677 _RGFW.clipboard = (char*)RGFW_ALLOC(textLen);
5678 RGFW_ASSERT(_RGFW.clipboard != NULL);
5680 RGFW_STRNCPY(_RGFW.clipboard, text, textLen - 1);
5681 _RGFW.clipboard[textLen - 1] = '\0';
5682 _RGFW.clipboard_len = textLen;
5683 #endif
5684 #ifdef RGFW_WAYLAND
5685 RGFW_WAYLAND_LABEL
5686 RGFW_UNUSED(text); RGFW_UNUSED(textLen);
5687 #endif
5688}
5690RGFW_bool RGFW_window_isHidden(RGFW_window* win) {
5691 RGFW_ASSERT(win != NULL);
5692 RGFW_GOTO_WAYLAND(0);
5693#ifdef RGFW_X11
5695 XWindowAttributes windowAttributes;
5696 XGetWindowAttributes(win->src.display, win->src.window, &windowAttributes);
5698 return (windowAttributes.map_state == IsUnmapped && !RGFW_window_isMinimized(win));
5699#endif
5700#ifdef RGFW_WAYLAND
5701 RGFW_WAYLAND_LABEL
5702 return RGFW_FALSE;
5703#endif
5704}
5706RGFW_bool RGFW_window_isMinimized(RGFW_window* win) {
5707 RGFW_ASSERT(win != NULL);
5708 RGFW_GOTO_WAYLAND(0);
5709#ifdef RGFW_X11
5710 RGFW_LOAD_ATOM(WM_STATE);
5712 Atom actual_type;
5713 i32 actual_format;
5714 unsigned long nitems, bytes_after;
5715 unsigned char* prop_data;
5717 i32 status = XGetWindowProperty(win->src.display, win->src.window, WM_STATE, 0, 2, False,
5718 AnyPropertyType, &actual_type, &actual_format,
5719 &nitems, &bytes_after, &prop_data);
5721 if (status == Success && nitems >= 1 && prop_data == (unsigned char*)IconicState) {
5722 XFree(prop_data);
5723 return RGFW_TRUE;
5724 }
5726 if (prop_data != NULL)
5727 XFree(prop_data);
5729 XWindowAttributes windowAttributes;
5730 XGetWindowAttributes(win->src.display, win->src.window, &windowAttributes);
5731 return windowAttributes.map_state != IsViewable;
5732#endif
5733#ifdef RGFW_WAYLAND
5734 RGFW_WAYLAND_LABEL
5735 return RGFW_FALSE;
5736#endif
5737}
5739RGFW_bool RGFW_window_isMaximized(RGFW_window* win) {
5740 RGFW_ASSERT(win != NULL);
5741 RGFW_GOTO_WAYLAND(0);
5742#ifdef RGFW_X11
5743 RGFW_LOAD_ATOM(_NET_WM_STATE);
5744 RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_VERT);
5745 RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ);
5747 Atom actual_type;
5748 i32 actual_format;
5749 unsigned long nitems, bytes_after;
5750 unsigned char* prop_data;
5752 i32 status = XGetWindowProperty(win->src.display, win->src.window, _NET_WM_STATE, 0, 1024, False,
5753 XA_ATOM, &actual_type, &actual_format,
5754 &nitems, &bytes_after, &prop_data);
5756 if (status != Success) {
5757 if (prop_data != NULL)
5758 XFree(prop_data);
5760 return RGFW_FALSE;
5761 }
5763 u64 i;
5764 for (i = 0; i < nitems; ++i) {
5765 if (prop_data[i] == _NET_WM_STATE_MAXIMIZED_VERT ||
5766 prop_data[i] == _NET_WM_STATE_MAXIMIZED_HORZ) {
5767 XFree(prop_data);
5768 return RGFW_TRUE;
5769 }
5770 }
5772 if (prop_data != NULL)
5773 XFree(prop_data);
5774#endif
5775#ifdef RGFW_WAYLAND
5776RGFW_WAYLAND_LABEL;
5777#endif
5778 return RGFW_FALSE;
5779}
5781#ifndef RGFW_NO_DPI
5782u32 RGFW_XCalculateRefreshRate(XRRModeInfo mi);
5783u32 RGFW_XCalculateRefreshRate(XRRModeInfo mi) {
5784 if (mi.hTotal == 0 || mi.vTotal == 0) return 0;
5785 return (u32) RGFW_ROUND((double) mi.dotClock / ((double) mi.hTotal * (double) mi.vTotal));
5786}
5787#endif
5790#ifdef RGFW_X11
5791static float XGetSystemContentDPI(Display* display, i32 screen) {
5792 float dpi = 96.0f;
5794 #ifndef RGFW_NO_DPI
5795 RGFW_UNUSED(screen);
5796 char* rms = XResourceManagerString(display);
5797 XrmDatabase db = NULL;
5798 if (rms) db = XrmGetStringDatabase(rms);
5800 if (rms && db) {
5801 XrmValue value;
5802 char* type = NULL;
5804 if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value) && type && RGFW_STRNCMP(type, "String", 7) == 0)
5805 dpi = (float)RGFW_ATOF(value.addr);
5806 XrmDestroyDatabase(db);
5807 }
5808 #else
5809 dpi = RGFW_ROUND(DisplayWidth(display, screen) / (DisplayWidthMM(display, screen) / 25.4));
5810 #endif
5812 return dpi;
5813}
5814#endif
5816RGFW_monitor RGFW_XCreateMonitor(i32 screen);
5817RGFW_monitor RGFW_XCreateMonitor(i32 screen) {
5818 RGFW_monitor monitor;
5819 RGFW_init();
5821 RGFW_GOTO_WAYLAND(1);
5822#ifdef RGFW_X11
5823 Display* display = _RGFW.display;
5825 if (screen == -1) screen = DefaultScreen(display);
5827 Screen* scrn = DefaultScreenOfDisplay(display);
5828 RGFW_area size = RGFW_AREA(scrn->width, scrn->height);
5830 monitor.x = 0;
5831 monitor.y = 0;
5832 monitor.mode.area = RGFW_AREA(size.w, size.h);
5833 monitor.physW = (float)DisplayWidthMM(display, screen) / 25.4f;
5834 monitor.physH = (float)DisplayHeightMM(display, screen) / 25.4f;
5836 RGFW_splitBPP((u32)DefaultDepth(display, DefaultScreen(display)), &monitor.mode);
5838 char* name = XDisplayName((const char*)display);
5839 RGFW_STRNCPY(monitor.name, name, sizeof(monitor.name) - 1);
5840 monitor.name[sizeof(monitor.name) - 1] = '\0';
5842 float dpi = XGetSystemContentDPI(display, screen);
5843 monitor.pixelRatio = dpi >= 192.0f ? 2 : 1;
5844 monitor.scaleX = (float) (dpi) / 96.0f;
5845 monitor.scaleY = (float) (dpi) / 96.0f;
5847 #ifndef RGFW_NO_DPI
5848 XRRScreenResources* sr = XRRGetScreenResourcesCurrent(display, RootWindow(display, screen));
5849 monitor.mode.refreshRate = RGFW_XCalculateRefreshRate(sr->modes[screen]);
5851 XRRCrtcInfo* ci = NULL;
5852 int crtc = screen;
5854 if (sr->ncrtc > crtc) {
5855 ci = XRRGetCrtcInfo(display, sr, sr->crtcs[crtc]);
5856 }
5857 #endif
5859 #ifndef RGFW_NO_DPI
5860 XRROutputInfo* info = XRRGetOutputInfo (display, sr, sr->outputs[screen]);
5862 if (info == NULL || ci == NULL) {
5863 XRRFreeScreenResources(sr);
5864 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found");
5865 return monitor;
5866 }
5869 float physW = (float)info->mm_width / 25.4f;
5870 float physH = (float)info->mm_height / 25.4f;
5872 RGFW_STRNCPY(monitor.name, info->name, sizeof(monitor.name) - 1);
5873 monitor.name[sizeof(monitor.name) - 1] = '\0';
5875 if ((u8)physW && (u8)physH) {
5876 monitor.physW = physW;
5877 monitor.physH = physH;
5878 }
5880 monitor.x = ci->x;
5881 monitor.y = ci->y;
5883 if (ci->width && ci->height) {
5884 monitor.mode.area.w = (u32)ci->width;
5885 monitor.mode.area.h = (u32)ci->height;
5886 }
5887 #endif
5889 #ifndef RGFW_NO_DPI
5890 XRRFreeCrtcInfo(ci);
5891 XRRFreeScreenResources(sr);
5892 #endif
5894 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found");
5895 return monitor;
5896#endif
5897#ifdef RGFW_WAYLAND
5898RGFW_WAYLAND_LABEL RGFW_UNUSED(screen);
5899 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found");
5900 return monitor;
5901#endif
5902}
5904RGFW_monitor* RGFW_getMonitors(size_t* len) {
5905 static RGFW_monitor monitors[7];
5907 RGFW_GOTO_WAYLAND(1);
5908 #ifdef RGFW_X11
5909 RGFW_init();
5911 Display* display = _RGFW.display;
5912 i32 max = ScreenCount(display);
5914 i32 i;
5915 for (i = 0; i < max && i < 6; i++)
5916 monitors[i] = RGFW_XCreateMonitor(i);
5918 if (len != NULL) *len = (size_t)((max <= 6) ? (max) : (6));
5920 return monitors;
5921 #endif
5922 #ifdef RGFW_WAYLAND
5923 RGFW_WAYLAND_LABEL RGFW_UNUSED(len);
5924 return monitors; /* TODO WAYLAND */
5925 #endif
5926}
5928RGFW_monitor RGFW_getPrimaryMonitor(void) {
5929 RGFW_GOTO_WAYLAND(1);
5930 #ifdef RGFW_X11
5931 return RGFW_XCreateMonitor(-1);
5932 #endif
5933 #ifdef RGFW_WAYLAND
5934 RGFW_WAYLAND_LABEL return (RGFW_monitor){ 0 }; /* TODO WAYLAND */
5935 #endif
5936}
5938RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) {
5939 RGFW_GOTO_WAYLAND(1);
5940#ifdef RGFW_X11
5941 #ifndef RGFW_NO_DPI
5942 RGFW_init();
5943 XRRScreenResources* screenRes = XRRGetScreenResources(_RGFW.display, DefaultRootWindow(_RGFW.display));
5944 if (screenRes == NULL) return RGFW_FALSE;
5946 int i;
5947 for (i = 0; i < screenRes->ncrtc; i++) {
5948 XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(_RGFW.display, screenRes, screenRes->crtcs[i]);
5949 if (!crtcInfo) continue;
5951 if (mon.x == crtcInfo->x && mon.y == crtcInfo->y && (u32)mon.mode.area.w == crtcInfo->width && (u32)mon.mode.area.h == crtcInfo->height) {
5952 RRMode rmode = None;
5953 int index;
5954 for (index = 0; index < screenRes->nmode; index++) {
5955 RGFW_monitorMode foundMode;
5956 foundMode.area = RGFW_AREA(screenRes->modes[index].width, screenRes->modes[index].height);
5957 foundMode.refreshRate = RGFW_XCalculateRefreshRate(screenRes->modes[index]);
5958 RGFW_splitBPP((u32)DefaultDepth(_RGFW.display, DefaultScreen(_RGFW.display)), &foundMode);
5960 if (RGFW_monitorModeCompare(mode, foundMode, request)) {
5961 rmode = screenRes->modes[index].id;
5963 RROutput output = screenRes->outputs[i];
5964 XRROutputInfo* info = XRRGetOutputInfo(_RGFW.display, screenRes, output);
5965 if (info) {
5966 XRRSetCrtcConfig(_RGFW.display, screenRes, screenRes->crtcs[i],
5967 CurrentTime, 0, 0, rmode, RR_Rotate_0, &output, 1);
5968 XRRFreeOutputInfo(info);
5969 XRRFreeCrtcInfo(crtcInfo);
5970 XRRFreeScreenResources(screenRes);
5971 return RGFW_TRUE;
5972 }
5973 }
5974 }
5976 XRRFreeCrtcInfo(crtcInfo);
5977 XRRFreeScreenResources(screenRes);
5978 return RGFW_FALSE;
5979 }
5981 XRRFreeCrtcInfo(crtcInfo);
5982 }
5984 XRRFreeScreenResources(screenRes);
5985 return RGFW_FALSE;
5986 #endif
5987#endif
5988#ifdef RGFW_WAYLAND
5989RGFW_WAYLAND_LABEL RGFW_UNUSED(mon); RGFW_UNUSED(mode); RGFW_UNUSED(request);
5990#endif
5991 return RGFW_FALSE;
5992}
5994RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) {
5995 RGFW_monitor mon;
5996 RGFW_MEMSET(&mon, 0, sizeof(mon));
5998 RGFW_ASSERT(win != NULL);
5999 RGFW_GOTO_WAYLAND(1);
6000#ifdef RGFW_X11
6001 XWindowAttributes attrs;
6002 if (!XGetWindowAttributes(win->src.display, win->src.window, &attrs)) {
6003 return mon;
6004 }
6006 i32 i;
6007 for (i = 0; i < ScreenCount(win->src.display) && i < 6; i++) {
6008 Screen* screen = ScreenOfDisplay(win->src.display, i);
6009 if (attrs.x >= 0 && attrs.x < XWidthOfScreen(screen) &&
6010 attrs.y >= 0 && attrs.y < XHeightOfScreen(screen))
6011 return RGFW_XCreateMonitor(i);
6012 }
6013#endif
6014#ifdef RGFW_WAYLAND
6015RGFW_WAYLAND_LABEL
6016#endif
6017 return mon;
6019}
6021#if defined(RGFW_OPENGL) && !defined(RGFW_EGL)
6022void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
6023 if (win == NULL)
6024 glXMakeCurrent(NULL, (Drawable)NULL, (GLXContext) NULL);
6025 else
6026 glXMakeCurrent(win->src.display, (Drawable) win->src.window, (GLXContext) win->src.ctx);
6027}
6028void* RGFW_getCurrent_OpenGL(void) { return glXGetCurrentContext(); }
6029void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { glXSwapBuffers(win->src.display, win->src.window); }
6030#endif
6032void RGFW_window_swapBuffers_software(RGFW_window* win) {
6033 RGFW_ASSERT(win != NULL);
6034 RGFW_GOTO_WAYLAND(0);
6035#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
6036 #ifdef RGFW_X11
6037 win->src.bitmap->data = (char*) win->buffer;
6038 RGFW_RGB_to_BGR(win, (u8*)win->src.bitmap->data);
6039 XPutImage(win->src.display, win->src.window, win->src.gc, win->src.bitmap, 0, 0, 0, 0, win->bufferSize.w, win->bufferSize.h);
6040 win->src.bitmap->data = NULL;
6041 return;
6042 #endif
6043 #ifdef RGFW_WAYLAND
6044 RGFW_WAYLAND_LABEL
6045 #if !defined(RGFW_BUFFER_BGR) && !defined(RGFW_OSMESA)
6046 RGFW_RGB_to_BGR(win, win->src.buffer);
6047 #else
6048 size_t y;
6049 for (y = 0; y < win->r.h; y++) {
6050 u32 index = (y * 4 * win->r.w);
6051 u32 index2 = (y * 4 * win->bufferSize.w);
6052 RGFW_MEMCPY(&win->src.buffer[index], &win->buffer[index2], win->r.w * 4);
6053 }
6054 #endif
6056 wl_surface_frame_done(win, NULL, 0);
6057 wl_surface_commit(win->src.surface);
6058 #endif
6059#else
6060#ifdef RGFW_WAYLAND
6061 RGFW_WAYLAND_LABEL
6062#endif
6063 RGFW_UNUSED(win);
6064#endif
6065}
6067#if !defined(RGFW_EGL)
6069void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) {
6070 RGFW_ASSERT(win != NULL);
6072 #if defined(RGFW_OPENGL)
6073 // cached pfn to avoid calling glXGetProcAddress more than once
6074 static PFNGLXSWAPINTERVALEXTPROC pfn = (PFNGLXSWAPINTERVALEXTPROC)123;
6075 static int (*pfn2)(int) = NULL;
6077 if (pfn == (PFNGLXSWAPINTERVALEXTPROC)123) {
6078 pfn = ((PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddress((GLubyte*) "glXSwapIntervalEXT"));
6079 if (pfn == NULL) {
6080 const char* array[] = {"GLX_MESA_swap_control", "GLX_SGI_swap_control"};
6081 u32 i;
6082 for (i = 0; i < sizeof(array) / sizeof(char*) && pfn2 == NULL; i++)
6083 pfn2 = ((int(*)(int))glXGetProcAddress((GLubyte*) array[i]));
6085 if (pfn2 != NULL) {
6086 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load swap interval function, fallingback to the native swapinterval function");
6087 } else {
6088 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load swap interval function");
6089 }
6090 }
6091 }
6092 if (pfn != NULL)
6093 pfn(win->src.display, win->src.window, swapInterval);
6094 else if (pfn2 != NULL) {
6095 pfn2(swapInterval);
6096 }
6097 #else
6098 RGFW_UNUSED(swapInterval);
6099 #endif
6100}
6101#endif
6103void RGFW_deinit(void) {
6104 if (_RGFW.windowCount == -1 || _RGFW_init == RGFW_FALSE) return;
6105 #define RGFW_FREE_LIBRARY(x) if (x != NULL) dlclose(x); x = NULL;
6106#ifdef RGFW_X11
6107 /* to save the clipboard on the x server after the window is closed */
6108 RGFW_LOAD_ATOM(CLIPBOARD_MANAGER);
6109 RGFW_LOAD_ATOM(SAVE_TARGETS);
6110 if (XGetSelectionOwner(_RGFW.display, RGFW_XCLIPBOARD) == _RGFW.helperWindow) {
6111 XConvertSelection(_RGFW.display, CLIPBOARD_MANAGER, SAVE_TARGETS, None, _RGFW.helperWindow, CurrentTime);
6112 while (RGFW_XHandleClipboardSelectionHelper());
6113 }
6114 if (_RGFW.clipboard) {
6115 RGFW_FREE(_RGFW.clipboard);
6116 _RGFW.clipboard = NULL;
6117 }
6119 RGFW_freeMouse(_RGFW.hiddenMouse);
6121 XDestroyWindow(_RGFW.display, (Drawable) _RGFW.helperWindow); /*!< close the window */
6122 XCloseDisplay(_RGFW.display); /*!< kill connection to the x server */
6124 #if !defined(RGFW_NO_X11_CURSOR_PRELOAD) && !defined(RGFW_NO_X11_CURSOR)
6125 RGFW_FREE_LIBRARY(X11Cursorhandle);
6126 #endif
6127 #if !defined(RGFW_NO_X11_XI_PRELOAD)
6128 RGFW_FREE_LIBRARY(X11Xihandle);
6129 #endif
6131 #ifdef RGFW_USE_XDL
6132 XDL_close();
6133 #endif
6135 #if !defined(RGFW_NO_X11_EXT_PRELOAD)
6136 RGFW_FREE_LIBRARY(X11XEXThandle);
6137 #endif
6138#endif
6139#ifdef RGFW_WAYLAND
6140 wl_display_disconnect(_RGFW.wl_display);
6141#endif
6142 #ifndef RGFW_NO_LINUX
6143 if (RGFW_eventWait_forceStop[0] || RGFW_eventWait_forceStop[1]){
6144 close(RGFW_eventWait_forceStop[0]);
6145 close(RGFW_eventWait_forceStop[1]);
6146 }
6148 u8 i;
6149 for (i = 0; i < RGFW_gamepadCount; i++) {
6150 if(RGFW_gamepads[i])
6151 close(RGFW_gamepads[i]);
6152 }
6153 #endif
6155 _RGFW.root = NULL;
6156 _RGFW.windowCount = -1;
6157 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized");
6158}
6160void RGFW_window_close(RGFW_window* win) {
6161 RGFW_ASSERT(win != NULL);
6162 if ((win->_flags & RGFW_windowNoInitAPI) == 0) RGFW_window_freeOpenGL(win);
6164 RGFW_GOTO_WAYLAND(0);
6165 #ifdef RGFW_X11
6166 /* ungrab pointer if it was grabbed */
6167 if (win->_flags & RGFW_HOLD_MOUSE)
6168 XUngrabPointer(win->src.display, CurrentTime);
6170 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
6171 if (win->buffer != NULL) {
6172 if ((win->_flags & RGFW_BUFFER_ALLOC))
6173 RGFW_FREE(win->buffer);
6174 XDestroyImage((XImage*) win->src.bitmap);
6175 }
6176 #endif
6178 XFreeGC(win->src.display, win->src.gc);
6179 XDestroyWindow(win->src.display, (Drawable) win->src.window); /*!< close the window */
6180 win->src.window = 0;
6181 XCloseDisplay(win->src.display);
6183 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a window was freed");
6184 _RGFW.windowCount--;
6185 if (_RGFW.windowCount == 0) RGFW_deinit();
6187 RGFW_clipboard_switch(NULL);
6188 RGFW_FREE(win->event.droppedFiles);
6189 if ((win->_flags & RGFW_WINDOW_ALLOC)) {
6190 RGFW_FREE(win);
6191 win = NULL;
6192 }
6193 return;
6194 #endif
6196 #ifdef RGFW_WAYLAND
6197 RGFW_WAYLAND_LABEL
6199 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a window was freed");
6201 xdg_toplevel_destroy(win->src.xdg_toplevel);
6202 xdg_surface_destroy(win->src.xdg_surface);
6203 wl_surface_destroy(win->src.surface);
6205 _RGFW.windowCount--;
6206 if (_RGFW.windowCount == 0) RGFW_deinit();
6208 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
6209 wl_buffer_destroy(win->src.wl_buffer);
6210 if ((win->_flags & RGFW_BUFFER_ALLOC))
6211 RGFW_FREE(win->buffer);
6213 munmap(win->src.buffer, (size_t)(win->r.w * win->r.h * 4));
6214 #endif
6216 RGFW_clipboard_switch(NULL);
6217 RGFW_FREE(win->event.droppedFiles);
6218 if ((win->_flags & RGFW_WINDOW_ALLOC)) {
6219 RGFW_FREE(win);
6220 win = NULL;
6221 }
6222 #endif
6223}
6226/*
6227 End of X11 linux / wayland / unix defines
6228*/
6230#include <fcntl.h>
6231#include <poll.h>
6232#include <unistd.h>
6234void RGFW_stopCheckEvents(void) {
6236 RGFW_eventWait_forceStop[2] = 1;
6237 while (1) {
6238 const char byte = 0;
6239 const ssize_t result = write(RGFW_eventWait_forceStop[1], &byte, 1);
6240 if (result == 1 || result == -1)
6241 break;
6242 }
6243}
6245void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) {
6246 if (waitMS == 0) return;
6248 u8 i;
6249 if (RGFW_eventWait_forceStop[0] == 0 || RGFW_eventWait_forceStop[1] == 0) {
6250 if (pipe(RGFW_eventWait_forceStop) != -1) {
6251 fcntl(RGFW_eventWait_forceStop[0], F_GETFL, 0);
6252 fcntl(RGFW_eventWait_forceStop[0], F_GETFD, 0);
6253 fcntl(RGFW_eventWait_forceStop[1], F_GETFL, 0);
6254 fcntl(RGFW_eventWait_forceStop[1], F_GETFD, 0);
6255 }
6256 }
6258 struct pollfd fds[] = {
6259 #ifdef RGFW_WAYLAND
6260 { wl_display_get_fd(win->src.wl_display), POLLIN, 0 },
6261 #else
6262 { ConnectionNumber(win->src.display), POLLIN, 0 },
6263 #endif
6264 #ifdef RGFW_X11
6265 { ConnectionNumber(_RGFW.display), POLLIN, 0 },
6266 #endif
6267 { RGFW_eventWait_forceStop[0], POLLIN, 0 },
6268 #if defined(__linux__)
6269 { -1, POLLIN, 0 }, {-1, POLLIN, 0 }, {-1, POLLIN, 0 }, {-1, POLLIN, 0}
6270 #endif
6271 };
6273 u8 index = 2;
6274#ifdef RGFW_X11
6275 index++;
6276#endif
6278 #if defined(__linux__) || defined(__NetBSD__)
6279 for (i = 0; i < RGFW_gamepadCount; i++) {
6280 if (RGFW_gamepads[i] == 0)
6281 continue;
6283 fds[index].fd = RGFW_gamepads[i];
6284 index++;
6285 }
6286 #endif
6289 u64 start = RGFW_getTimeNS();
6292 #ifdef RGFW_WAYLAND
6293 while (wl_display_dispatch(win->src.wl_display) <= 0
6294 #else
6295 while (XPending(win->src.display) == 0
6296 #endif
6297 #ifdef RGFW_X11
6298 && XPending(_RGFW.display) == 0
6299 #endif
6300 ) {
6301 if (poll(fds, index, waitMS) <= 0)
6302 break;
6304 if (waitMS != RGFW_eventWaitNext)
6305 waitMS -= (i32)(RGFW_getTimeNS() - start) / (i32)1e+6;
6306 }
6308 /* drain any data in the stop request */
6309 if (RGFW_eventWait_forceStop[2]) {
6310 char data[64];
6311 (void)!read(RGFW_eventWait_forceStop[0], data, sizeof(data));
6313 RGFW_eventWait_forceStop[2] = 0;
6314 }
6315}
6317i32 RGFW_getClock(void);
6318i32 RGFW_getClock(void) {
6319 static i32 clock = -1;
6320 if (clock != -1) return clock;
6322 #if defined(_POSIX_MONOTONIC_CLOCK)
6323 struct timespec ts;
6324 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
6325 clock = CLOCK_MONOTONIC;
6326 #else
6327 clock = CLOCK_REALTIME;
6328 #endif
6330 return clock;
6331}
6333u64 RGFW_getTimerFreq(void) { return 1000000000LLU; }
6334u64 RGFW_getTimerValue(void) {
6335 struct timespec ts;
6336 clock_gettime(CLOCK_REALTIME, &ts);
6337 return (u64)ts.tv_sec * RGFW_getTimerFreq() + (u64)ts.tv_nsec;
6338}
6339#endif /* end of wayland or X11 defines */
6343/*
6345 Start of Windows defines
6348*/
6350#ifdef RGFW_WINDOWS
6351#define WIN32_LEAN_AND_MEAN
6352#define OEMRESOURCE
6353#include <windows.h>
6355#include <processthreadsapi.h>
6356#include <windowsx.h>
6357#include <shellapi.h>
6358#include <shellscalingapi.h>
6359#include <wchar.h>
6360#include <locale.h>
6361#include <winuser.h>
6363#ifndef WM_DPICHANGED
6364#define WM_DPICHANGED 0x02E0
6365#endif
6367#ifndef RGFW_NO_XINPUT
6368 typedef DWORD (WINAPI * PFN_XInputGetState)(DWORD,XINPUT_STATE*);
6369 PFN_XInputGetState XInputGetStateSRC = NULL;
6370 #define XInputGetState XInputGetStateSRC
6372 typedef DWORD (WINAPI * PFN_XInputGetKeystroke)(DWORD, DWORD, PXINPUT_KEYSTROKE);
6373 PFN_XInputGetKeystroke XInputGetKeystrokeSRC = NULL;
6374 #define XInputGetKeystroke XInputGetKeystrokeSRC
6376 HMODULE RGFW_XInput_dll = NULL;
6377#endif
6379char* RGFW_createUTF8FromWideStringWin32(const WCHAR* source);
6381#define GL_FRONT 0x0404
6382#define GL_BACK 0x0405
6383#define GL_LEFT 0x0406
6384#define GL_RIGHT 0x0407
6386typedef int (*PFN_wglGetSwapIntervalEXT)(void);
6387PFN_wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc = NULL;
6388#define wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc
6391void* RGFWgamepadApi = NULL;
6393/* these two wgl functions need to be preloaded */
6394typedef HGLRC (WINAPI *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC hdc, HGLRC hglrc, const int *attribList);
6395PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL;
6397#ifndef RGFW_EGL
6398 HMODULE RGFW_wgl_dll = NULL;
6399#endif
6401#ifndef RGFW_NO_LOAD_WGL
6402 typedef HGLRC(WINAPI* PFN_wglCreateContext)(HDC);
6403 typedef BOOL(WINAPI* PFN_wglDeleteContext)(HGLRC);
6404 typedef PROC(WINAPI* PFN_wglGetProcAddress)(LPCSTR);
6405 typedef BOOL(WINAPI* PFN_wglMakeCurrent)(HDC, HGLRC);
6406 typedef HDC(WINAPI* PFN_wglGetCurrentDC)(void);
6407 typedef HGLRC(WINAPI* PFN_wglGetCurrentContext)(void);
6408 typedef BOOL(WINAPI* PFN_wglShareLists)(HGLRC, HGLRC);
6410 PFN_wglCreateContext wglCreateContextSRC;
6411 PFN_wglDeleteContext wglDeleteContextSRC;
6412 PFN_wglGetProcAddress wglGetProcAddressSRC;
6413 PFN_wglMakeCurrent wglMakeCurrentSRC;
6414 PFN_wglGetCurrentDC wglGetCurrentDCSRC;
6415 PFN_wglGetCurrentContext wglGetCurrentContextSRC;
6416 PFN_wglShareLists wglShareListsSRC;
6418 #define wglCreateContext wglCreateContextSRC
6419 #define wglDeleteContext wglDeleteContextSRC
6420 #define wglGetProcAddress wglGetProcAddressSRC
6421 #define wglMakeCurrent wglMakeCurrentSRC
6422 #define wglGetCurrentDC wglGetCurrentDCSRC
6423 #define wglGetCurrentContext wglGetCurrentContextSRC
6424 #define wglShareLists wglShareListsSRC
6425#endif
6427#if defined(RGFW_OPENGL) && !defined(RGFW_EGL)
6428RGFW_bool RGFW_extensionSupportedPlatform(const char * extension, size_t len) {
6429 const char* extensions = NULL;
6431 RGFW_proc proc = RGFW_getProcAddress("wglGetExtensionsStringARB");
6432 RGFW_proc proc2 = RGFW_getProcAddress("wglGetExtensionsStringEXT");
6434 if (proc)
6435 extensions = ((const char* (*)(HDC))proc)(wglGetCurrentDC());
6436 else if (proc2)
6437 extensions = ((const char*(*)(void))proc2)();
6439 return extensions != NULL && RGFW_extensionSupportedStr(extensions, extension, len);
6440}
6442RGFW_proc RGFW_getProcAddress(const char* procname) {
6443 RGFW_proc proc = (RGFW_proc)wglGetProcAddress(procname);
6444 if (proc)
6445 return proc;
6447 return (RGFW_proc) GetProcAddress(RGFW_wgl_dll, procname);
6448}
6450typedef HRESULT (APIENTRY* PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats);
6451PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL;
6453typedef BOOL(APIENTRY* PFNWGLSWAPINTERVALEXTPROC)(int interval);
6454PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
6455#endif
6457#ifndef RGFW_NO_DWM
6458HMODULE RGFW_dwm_dll = NULL;
6459typedef struct { DWORD dwFlags; int fEnable; HRGN hRgnBlur; int fTransitionOnMaximized;} DWM_BLURBEHIND;
6460typedef HRESULT (WINAPI * PFN_DwmEnableBlurBehindWindow)(HWND, const DWM_BLURBEHIND*);
6461PFN_DwmEnableBlurBehindWindow DwmEnableBlurBehindWindowSRC = NULL;
6462#endif
6463void RGFW_win32_makeWindowTransparent(RGFW_window* win);
6464void RGFW_win32_makeWindowTransparent(RGFW_window* win) {
6465 if (!(win->_flags & RGFW_windowTransparent)) return;
6467 #ifndef RGFW_NO_DWM
6468 if (DwmEnableBlurBehindWindowSRC != NULL) {
6469 DWM_BLURBEHIND bb = {0, 0, 0, 0};
6470 bb.dwFlags = 0x1;
6471 bb.fEnable = TRUE;
6472 bb.hRgnBlur = NULL;
6473 DwmEnableBlurBehindWindowSRC(win->src.window, &bb);
6475 } else
6476 #endif
6477 {
6478 SetWindowLong(win->src.window, GWL_EXSTYLE, WS_EX_LAYERED);
6479 SetLayeredWindowAttributes(win->src.window, 0, 128, LWA_ALPHA);
6480 }
6481}
6483LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
6484LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
6485 RGFW_window* win = (RGFW_window*)GetPropW(hWnd, L"RGFW");
6486 if (win == NULL) return DefWindowProcW(hWnd, message, wParam, lParam);
6488 RECT windowRect;
6489 GetWindowRect(hWnd, &windowRect);
6491 switch (message) {
6492 case WM_CLOSE:
6493 case WM_QUIT:
6494 RGFW_eventQueuePushEx(e.type = RGFW_quit; e._win = win);
6495 RGFW_windowQuitCallback(win);
6496 return 0;
6497 case WM_ACTIVATE: {
6498 RGFW_bool inFocus = RGFW_BOOL(LOWORD(wParam) != WA_INACTIVE);
6499 if (inFocus) win->_flags |= RGFW_windowFocus;
6500 else win->_flags &= ~ (u32)RGFW_windowFocus;
6501 RGFW_eventQueuePushEx(e.type = (RGFW_eventType)((u8)RGFW_focusOut - inFocus); e._win = win);
6503 RGFW_focusCallback(win, inFocus);
6504 RGFW_window_focusLost(win);
6506 if ((win->_flags & RGFW_windowFullscreen) == 0)
6507 return DefWindowProcW(hWnd, message, wParam, lParam);
6509 win->_flags &= ~(u32)RGFW_EVENT_PASSED;
6510 if (inFocus == RGFW_FALSE) RGFW_window_minimize(win);
6511 else RGFW_window_setFullscreen(win, 1);
6512 return DefWindowProcW(hWnd, message, wParam, lParam);
6513 }
6514 case WM_MOVE:
6515 win->r.x = windowRect.left;
6516 win->r.y = windowRect.top;
6517 RGFW_eventQueuePushEx(e.type = RGFW_windowMoved; e._win = win);
6518 RGFW_windowMovedCallback(win, win->r);
6519 return DefWindowProcW(hWnd, message, wParam, lParam);
6520 case WM_SIZE: {
6521 if (win->src.aspectRatio.w != 0 && win->src.aspectRatio.h != 0) {
6522 double aspectRatio = (double)win->src.aspectRatio.w / win->src.aspectRatio.h;
6524 int width = windowRect.right - windowRect.left;
6525 int height = windowRect.bottom - windowRect.top;
6526 int newHeight = (int)(width / aspectRatio);
6527 int newWidth = (int)(height * aspectRatio);
6529 if (win->r.w > windowRect.right - windowRect.left ||
6530 win->r.h > (i32)((u32)(windowRect.bottom - windowRect.top) - win->src.hOffset))
6531 {
6532 if (newHeight > height) windowRect.right = windowRect.left + newWidth;
6533 else windowRect.bottom = windowRect.top + newHeight;
6534 } else {
6535 if (newHeight < height) windowRect.right = windowRect.left + newWidth;
6536 else windowRect.bottom = windowRect.top + newHeight;
6537 }
6539 RGFW_window_resize(win, RGFW_AREA((windowRect.right - windowRect.left),
6540 (u32)(windowRect.bottom - windowRect.top) - (u32)win->src.hOffset));
6541 }
6543 win->r.w = windowRect.right - windowRect.left;
6544 win->r.h = (windowRect.bottom - windowRect.top) - (i32)win->src.hOffset;
6545 RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e._win = win);
6546 RGFW_windowResizedCallback(win, win->r);
6547 RGFW_window_checkMode(win);
6548 return DefWindowProcW(hWnd, message, wParam, lParam);
6549 }
6550 #ifndef RGFW_NO_MONITOR
6551 case WM_DPICHANGED: {
6552 if (win->_flags & RGFW_windowScaleToMonitor) RGFW_window_scaleToMonitor(win);
6554 const float scaleX = HIWORD(wParam) / (float) 96;
6555 const float scaleY = LOWORD(wParam) / (float) 96;
6556 RGFW_scaleUpdatedCallback(win, scaleX, scaleY);
6557 RGFW_eventQueuePushEx(e.type = RGFW_scaleUpdated; e.scaleX = scaleX; e.scaleY = scaleY; e._win = win);
6558 return DefWindowProcW(hWnd, message, wParam, lParam);
6559 }
6560 #endif
6561 case WM_GETMINMAXINFO: {
6562 MINMAXINFO* mmi = (MINMAXINFO*) lParam;
6563 mmi->ptMinTrackSize.x = (LONG)win->src.minSize.w;
6564 mmi->ptMinTrackSize.y = (LONG)(win->src.minSize.h + win->src.hOffset);
6565 if (win->src.maxSize.w == 0 && win->src.maxSize.h == 0)
6566 return DefWindowProcW(hWnd, message, wParam, lParam);
6568 mmi->ptMaxTrackSize.x = (LONG)win->src.maxSize.w;
6569 mmi->ptMaxTrackSize.y = (LONG)(win->src.maxSize.h + win->src.hOffset);
6570 return DefWindowProcW(hWnd, message, wParam, lParam);
6571 }
6572 case WM_PAINT: {
6573 PAINTSTRUCT ps;
6574 BeginPaint(hWnd, &ps);
6575 RGFW_eventQueuePushEx(e.type = RGFW_windowRefresh; e._win = win);
6576 RGFW_windowRefreshCallback(win);
6577 EndPaint(hWnd, &ps);
6579 return DefWindowProcW(hWnd, message, wParam, lParam);
6580 }
6581 #if(_WIN32_WINNT >= 0x0600)
6582 case WM_DWMCOMPOSITIONCHANGED:
6583 case WM_DWMCOLORIZATIONCOLORCHANGED:
6584 RGFW_win32_makeWindowTransparent(win);
6585 break;
6586 #endif
6587/* based on sokol_app.h */
6588#ifdef RGFW_ADVANCED_SMOOTH_RESIZE
6589 case WM_ENTERSIZEMOVE: SetTimer(win->src.window, 1, USER_TIMER_MINIMUM, NULL); break;
6590 case WM_EXITSIZEMOVE: KillTimer(win->src.window, 1); break;
6591 case WM_TIMER: RGFW_windowRefreshCallback(win); break;
6592#endif
6593 case WM_NCLBUTTONDOWN: {
6594 /* workaround for half-second pause when starting to move window
6595 see: https://gamedev.net/forums/topic/672094-keeping-things-moving-during-win32-moveresize-events/5254386/
6596 */
6597 POINT point = { 0, 0 };
6598 if (SendMessage(win->src.window, WM_NCHITTEST, wParam, lParam) != HTCAPTION || GetCursorPos(&point) == FALSE)
6599 break;
6601 ScreenToClient(win->src.window, &point);
6602 PostMessage(win->src.window, WM_MOUSEMOVE, 0, ((uint32_t)point.x)|(((uint32_t)point.y) << 16));
6603 break;
6604 }
6605 default: break;
6606 }
6607 return DefWindowProcW(hWnd, message, wParam, lParam);
6608}
6610#ifndef RGFW_NO_DPI
6611 HMODULE RGFW_Shcore_dll = NULL;
6612 typedef HRESULT (WINAPI *PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*,UINT*);
6613 PFN_GetDpiForMonitor GetDpiForMonitorSRC = NULL;
6614 #define GetDpiForMonitor GetDpiForMonitorSRC
6615#endif
6617#if !defined(RGFW_NO_LOAD_WINMM) && !defined(RGFW_NO_WINMM)
6618 HMODULE RGFW_winmm_dll = NULL;
6619 typedef u32 (WINAPI * PFN_timeBeginPeriod)(u32);
6620 typedef PFN_timeBeginPeriod PFN_timeEndPeriod;
6621 PFN_timeBeginPeriod timeBeginPeriodSRC, timeEndPeriodSRC;
6622 #define timeBeginPeriod timeBeginPeriodSRC
6623 #define timeEndPeriod timeEndPeriodSRC
6624#elif !defined(RGFW_NO_WINMM)
6625 __declspec(dllimport) u32 __stdcall timeBeginPeriod(u32 uPeriod);
6626 __declspec(dllimport) u32 __stdcall timeEndPeriod(u32 uPeriod);
6627#endif
6628#define RGFW_PROC_DEF(proc, name) if (name##SRC == NULL && proc != NULL) { \
6629 name##SRC = (PFN_##name)(RGFW_proc)GetProcAddress((proc), (#name)); \
6630 RGFW_ASSERT(name##SRC != NULL); \
6631 }
6633#ifndef RGFW_NO_XINPUT
6634void RGFW_loadXInput(void);
6635void RGFW_loadXInput(void) {
6636 u32 i;
6637 static const char* names[] = {"xinput1_4.dll", "xinput9_1_0.dll", "xinput1_2.dll", "xinput1_1.dll"};
6639 for (i = 0; i < sizeof(names) / sizeof(const char*) && (XInputGetStateSRC == NULL || XInputGetKeystrokeSRC != NULL); i++) {
6640 RGFW_XInput_dll = LoadLibraryA(names[i]);
6641 RGFW_PROC_DEF(RGFW_XInput_dll, XInputGetState);
6642 RGFW_PROC_DEF(RGFW_XInput_dll, XInputGetKeystroke);
6643 }
6645 if (XInputGetStateSRC == NULL)
6646 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errFailedFuncLoad, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load XInputGetState");
6647 if (XInputGetKeystrokeSRC == NULL)
6648 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errFailedFuncLoad, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load XInputGetKeystroke");
6649}
6650#endif
6652void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area){
6653#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
6654 win->buffer = buffer;
6655 win->bufferSize = area;
6657 BITMAPV5HEADER bi;
6658 ZeroMemory(&bi, sizeof(bi));
6659 bi.bV5Size = sizeof(bi);
6660 bi.bV5Width = (i32)area.w;
6661 bi.bV5Height = -((LONG) area.h);
6662 bi.bV5Planes = 1;
6663 bi.bV5BitCount = 32;
6664 bi.bV5Compression = BI_RGB;
6666 win->src.bitmap = CreateDIBSection(win->src.hdc,
6667 (BITMAPINFO*) &bi, DIB_RGB_COLORS,
6668 (void**) &win->src.bitmapBits,
6669 NULL, (DWORD) 0);
6671 if (win->buffer == NULL)
6672 win->buffer = win->src.bitmapBits;
6674 win->src.hdcMem = CreateCompatibleDC(win->src.hdc);
6675 SelectObject(win->src.hdcMem, win->src.bitmap);
6677 #if defined(RGFW_OSMESA)
6678 win->src.ctx = OSMesaCreateContext(OSMESA_BGRA, NULL);
6679 OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h);
6680 OSMesaPixelStore(OSMESA_Y_UP, 0);
6681 #endif
6682 #else
6683 RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area); /*!< if buffer rendering is not being used */
6684 #endif
6685}
6687void RGFW_releaseCursor(RGFW_window* win) {
6688 RGFW_UNUSED(win);
6689 ClipCursor(NULL);
6690 const RAWINPUTDEVICE id = { 0x01, 0x02, RIDEV_REMOVE, NULL };
6691 RegisterRawInputDevices(&id, 1, sizeof(id));
6692}
6694void RGFW_captureCursor(RGFW_window* win, RGFW_rect rect) {
6695 RGFW_UNUSED(win); RGFW_UNUSED(rect);
6697 RECT clipRect;
6698 GetClientRect(win->src.window, &clipRect);
6699 ClientToScreen(win->src.window, (POINT*) &clipRect.left);
6700 ClientToScreen(win->src.window, (POINT*) &clipRect.right);
6701 ClipCursor(&clipRect);
6703 const RAWINPUTDEVICE id = { 0x01, 0x02, 0, win->src.window };
6704 RegisterRawInputDevices(&id, 1, sizeof(id));
6705}
6707#define RGFW_LOAD_LIBRARY(x, lib) if (x == NULL) { x = LoadLibraryA(lib); RGFW_ASSERT(x != NULL); }
6709#ifdef RGFW_DIRECTX
6710int RGFW_window_createDXSwapChain(RGFW_window* win, IDXGIFactory* pFactory, IUnknown* pDevice, IDXGISwapChain** swapchain) {
6711 RGFW_ASSERT(win && pFactory && pDevice && swapchain);
6713 static DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 };
6714 swapChainDesc.BufferCount = 2;
6715 swapChainDesc.BufferDesc.Width = win->r.w;
6716 swapChainDesc.BufferDesc.Height = win->r.h;
6717 swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
6718 swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
6719 swapChainDesc.OutputWindow = (HWND)win->src.window;
6720 swapChainDesc.SampleDesc.Count = 1;
6721 swapChainDesc.SampleDesc.Quality = 0;
6722 swapChainDesc.Windowed = TRUE;
6723 swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
6725 HRESULT hr = pFactory->lpVtbl->CreateSwapChain(pFactory, (IUnknown*)pDevice, &swapChainDesc, swapchain);
6726 if (FAILED(hr)) {
6727 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errDirectXContext, RGFW_DEBUG_CTX(win, hr), "Failed to create DirectX swap chain!");
6728 return -2;
6729 }
6731 return 0;
6732}
6733#endif
6735void RGFW_win32_loadOpenGLFuncs(HWND dummyWin);
6736void RGFW_win32_loadOpenGLFuncs(HWND dummyWin) {
6737#ifdef RGFW_OPENGL
6738 if (wglSwapIntervalEXT != NULL && wglChoosePixelFormatARB != NULL && wglChoosePixelFormatARB != NULL)
6739 return;
6741 HDC dummy_dc = GetDC(dummyWin);
6742 u32 pfd_flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
6744 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};
6746 int dummy_pixel_format = ChoosePixelFormat(dummy_dc, &pfd);
6747 SetPixelFormat(dummy_dc, dummy_pixel_format, &pfd);
6749 HGLRC dummy_context = wglCreateContext(dummy_dc);
6750 wglMakeCurrent(dummy_dc, dummy_context);
6752 wglCreateContextAttribsARB = ((PFNWGLCREATECONTEXTATTRIBSARBPROC(WINAPI *)(const char*)) wglGetProcAddress)("wglCreateContextAttribsARB");
6753 wglChoosePixelFormatARB = ((PFNWGLCHOOSEPIXELFORMATARBPROC(WINAPI *)(const char*)) wglGetProcAddress)("wglChoosePixelFormatARB");
6755 wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)(RGFW_proc)wglGetProcAddress("wglSwapIntervalEXT");
6756 if (wglSwapIntervalEXT == NULL) {
6757 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load swap interval function");
6758 }
6760 wglMakeCurrent(dummy_dc, 0);
6761 wglDeleteContext(dummy_context);
6762 ReleaseDC(dummyWin, dummy_dc);
6763#else
6764 RGFW_UNUSED(dummyWin);
6765#endif
6766}
6768#ifndef RGFW_EGL
6769void RGFW_window_initOpenGL(RGFW_window* win) {
6770#ifdef RGFW_OPENGL
6771 PIXELFORMATDESCRIPTOR pfd;
6772 pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
6773 pfd.nVersion = 1;
6774 pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
6775 pfd.iPixelType = PFD_TYPE_RGBA;
6776 pfd.iLayerType = PFD_MAIN_PLANE;
6777 pfd.cColorBits = 32;
6778 pfd.cAlphaBits = 8;
6779 pfd.cDepthBits = 24;
6780 pfd.cStencilBits = (BYTE)RGFW_GL_HINTS[RGFW_glStencil];
6781 pfd.cAuxBuffers = (BYTE)RGFW_GL_HINTS[RGFW_glAuxBuffers];
6782 if (RGFW_GL_HINTS[RGFW_glStereo]) pfd.dwFlags |= PFD_STEREO;
6784 /* try to create the pixel format we want for opengl and then try to create an opengl context for the specified version */
6785 if (win->_flags & RGFW_windowOpenglSoftware)
6786 pfd.dwFlags |= PFD_GENERIC_FORMAT | PFD_GENERIC_ACCELERATED;
6788 /* get pixel format, default to a basic pixel format */
6789 int pixel_format = ChoosePixelFormat(win->src.hdc, &pfd);
6790 if (wglChoosePixelFormatARB != NULL) {
6791 i32* pixel_format_attribs = (i32*)RGFW_initFormatAttribs();
6793 int new_pixel_format;
6794 UINT num_formats;
6795 wglChoosePixelFormatARB(win->src.hdc, pixel_format_attribs, 0, 1, &new_pixel_format, &num_formats);
6796 if (!num_formats)
6797 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to create a pixel format for WGL");
6798 else pixel_format = new_pixel_format;
6799 }
6801 PIXELFORMATDESCRIPTOR suggested;
6802 if (!DescribePixelFormat(win->src.hdc, pixel_format, sizeof(suggested), &suggested) ||
6803 !SetPixelFormat(win->src.hdc, pixel_format, &pfd))
6804 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to set the WGL pixel format");
6806 if (!(pfd.dwFlags & PFD_GENERIC_ACCELERATED)) {
6807 win->_flags |= RGFW_windowOpenglSoftware;
6808 }
6810 if (wglCreateContextAttribsARB != NULL) {
6811 /* create opengl/WGL context for the specified version */
6812 u32 index = 0;
6813 i32 attribs[40];
6815 if (RGFW_GL_HINTS[RGFW_glProfile]== RGFW_glCore) {
6816 SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB);
6817 }
6818 else {
6819 SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB);
6820 }
6822 if (RGFW_GL_HINTS[RGFW_glMinor] || RGFW_GL_HINTS[RGFW_glMajor]) {
6823 SET_ATTRIB(WGL_CONTEXT_MAJOR_VERSION_ARB, RGFW_GL_HINTS[RGFW_glMajor]);
6824 SET_ATTRIB(WGL_CONTEXT_MINOR_VERSION_ARB, RGFW_GL_HINTS[RGFW_glMinor]);
6825 }
6827 SET_ATTRIB(0, 0);
6829 win->src.ctx = (HGLRC)wglCreateContextAttribsARB(win->src.hdc, NULL, attribs);
6830 } else { /* fall back to a default context (probably opengl 2 or something) */
6831 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to create an accelerated OpenGL Context");
6832 win->src.ctx = wglCreateContext(win->src.hdc);
6833 }
6835 ReleaseDC(win->src.window, win->src.hdc);
6836 win->src.hdc = GetDC(win->src.window);
6837 wglMakeCurrent(win->src.hdc, win->src.ctx);
6839 if (_RGFW.root != win)
6840 wglShareLists(_RGFW.root->src.ctx, win->src.ctx);
6841 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context initalized");
6842#else
6843 RGFW_UNUSED(win);
6844#endif
6845}
6847void RGFW_window_freeOpenGL(RGFW_window* win) {
6848#ifdef RGFW_OPENGL
6849 if (win->src.ctx == NULL) return;
6850 wglDeleteContext((HGLRC) win->src.ctx); /*!< delete opengl context */
6851 win->src.ctx = NULL;
6852 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context freed");
6853#else
6854 RGFW_UNUSED(win);
6855#endif
6856}
6857#endif
6860i32 RGFW_init(void) {
6861#if defined(RGFW_C89) || defined(__cplusplus)
6862 if (_RGFW_init) return 0;
6863 _RGFW_init = RGFW_TRUE;
6864 _RGFW.root = NULL; _RGFW.current = NULL; _RGFW.windowCount = -1; _RGFW.eventLen = 0; _RGFW.eventIndex = 0;
6865#endif
6867 #ifndef RGFW_NO_XINPUT
6868 if (RGFW_XInput_dll == NULL)
6869 RGFW_loadXInput();
6870 #endif
6872#ifndef RGFW_NO_DPI
6873 #if (_WIN32_WINNT >= 0x0600)
6874 SetProcessDPIAware();
6875 #endif
6876#endif
6878 #ifndef RGFW_NO_WINMM
6879 #ifndef RGFW_NO_LOAD_WINMM
6880 RGFW_LOAD_LIBRARY(RGFW_winmm_dll, "winmm.dll");
6881 RGFW_PROC_DEF(RGFW_winmm_dll, timeBeginPeriod);
6882 RGFW_PROC_DEF(RGFW_winmm_dll, timeEndPeriod);
6883 #endif
6884 timeBeginPeriod(1);
6885 #endif
6887 #ifndef RGFW_NO_DWM
6888 RGFW_LOAD_LIBRARY(RGFW_dwm_dll, "dwmapi.dll");
6889 RGFW_PROC_DEF(RGFW_dwm_dll, DwmEnableBlurBehindWindow);
6890 #endif
6892 RGFW_LOAD_LIBRARY(RGFW_wgl_dll, "opengl32.dll");
6893 #ifndef RGFW_NO_LOAD_WGL
6894 RGFW_PROC_DEF(RGFW_wgl_dll, wglCreateContext);
6895 RGFW_PROC_DEF(RGFW_wgl_dll, wglDeleteContext);
6896 RGFW_PROC_DEF(RGFW_wgl_dll, wglGetProcAddress);
6897 RGFW_PROC_DEF(RGFW_wgl_dll, wglMakeCurrent);
6898 RGFW_PROC_DEF(RGFW_wgl_dll, wglGetCurrentDC);
6899 RGFW_PROC_DEF(RGFW_wgl_dll, wglGetCurrentContext);
6900 RGFW_PROC_DEF(RGFW_wgl_dll, wglShareLists);
6901 #endif
6903 u8 RGFW_blk[] = { 0, 0, 0, 0 };
6904 _RGFW.hiddenMouse = RGFW_loadMouse(RGFW_blk, RGFW_AREA(1, 1), 4);
6906 _RGFW.windowCount = 0;
6907 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context initialized");
6908 return 1;
6909}
6911RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) {
6912 if (name[0] == 0) name = (char*) " ";
6914 RGFW_window_basic_init(win, rect, flags);
6916 win->src.hIconSmall = win->src.hIconBig = NULL;
6917 win->src.maxSize = RGFW_AREA(0, 0);
6918 win->src.minSize = RGFW_AREA(0, 0);
6919 win->src.aspectRatio = RGFW_AREA(0, 0);
6921 HINSTANCE inh = GetModuleHandleA(NULL);
6923 #ifndef __cplusplus
6924 WNDCLASSW Class = { 0 }; /*!< Setup the Window class. */
6925 #else
6926 WNDCLASSW Class = { };
6927 #endif
6929 if (RGFW_className == NULL)
6930 RGFW_className = (char*)name;
6932 wchar_t wide_class[256];
6933 MultiByteToWideChar(CP_UTF8, 0, RGFW_className, -1, wide_class, 255);
6935 Class.lpszClassName = wide_class;
6936 Class.hInstance = inh;
6937 Class.hCursor = LoadCursor(NULL, IDC_ARROW);
6938 Class.lpfnWndProc = WndProcW;
6939 Class.cbClsExtra = sizeof(RGFW_window*);
6941 Class.hIcon = (HICON)LoadImageA(GetModuleHandleW(NULL), "RGFW_ICON", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
6942 if (Class.hIcon == NULL)
6943 Class.hIcon = (HICON)LoadImageA(NULL, (LPCSTR)IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
6945 RegisterClassW(&Class);
6947 DWORD window_style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
6949 RECT windowRect, clientRect;
6951 if (!(flags & RGFW_windowNoBorder)) {
6952 window_style |= WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX | WS_THICKFRAME;
6954 if (!(flags & RGFW_windowNoResize))
6955 window_style |= WS_SIZEBOX | WS_MAXIMIZEBOX;
6956 } else
6957 window_style |= WS_POPUP | WS_VISIBLE | WS_SYSMENU;
6959 wchar_t wide_name[256];
6960 MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_name, 255);
6961 HWND dummyWin = CreateWindowW(Class.lpszClassName, (wchar_t*)wide_name, window_style, win->r.x, win->r.y, win->r.w, win->r.h, 0, 0, inh, 0);
6963 GetWindowRect(dummyWin, &windowRect);
6964 GetClientRect(dummyWin, &clientRect);
6966 RGFW_win32_loadOpenGLFuncs(dummyWin);
6967 DestroyWindow(dummyWin);
6969 win->src.hOffset = (u32)(windowRect.bottom - windowRect.top) - (u32)(clientRect.bottom - clientRect.top);
6970 win->src.window = CreateWindowW(Class.lpszClassName, (wchar_t*)wide_name, window_style, win->r.x, win->r.y, win->r.w, win->r.h + (i32)win->src.hOffset, 0, 0, inh, 0);
6971 SetPropW(win->src.window, L"RGFW", win);
6972 RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h)); /* so WM_GETMINMAXINFO gets called again */
6974 if (flags & RGFW_windowAllowDND) {
6975 win->_flags |= RGFW_windowAllowDND;
6976 RGFW_window_setDND(win, 1);
6977 }
6978 win->src.hdc = GetDC(win->src.window);
6980 if ((flags & RGFW_windowNoInitAPI) == 0) {
6981 RGFW_window_initOpenGL(win);
6982 RGFW_window_initBuffer(win);
6983 }
6985 RGFW_window_setFlags(win, flags);
6986 RGFW_win32_makeWindowTransparent(win);
6987 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created");
6988 RGFW_window_show(win);
6990 return win;
6991}
6993void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) {
6994 RGFW_setBit(&win->_flags, RGFW_windowNoBorder, !border);
6995 LONG style = GetWindowLong(win->src.window, GWL_STYLE);
6998 if (border == 0) {
6999 SetWindowLong(win->src.window, GWL_STYLE, style & ~WS_OVERLAPPEDWINDOW);
7000 SetWindowPos(
7001 win->src.window, HWND_TOP, 0, 0, 0, 0,
7002 SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE
7003 );
7004 }
7005 else {
7006 style |= WS_OVERLAPPEDWINDOW;
7007 if (win->_flags & RGFW_windowNoResize) style &= ~WS_MAXIMIZEBOX;
7008 SetWindowPos(
7009 win->src.window, HWND_TOP, 0, 0, 0, 0,
7010 SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE
7011 );
7012 }
7013}
7015void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow) {
7016 RGFW_setBit(&win->_flags, RGFW_windowAllowDND, allow);
7017 DragAcceptFiles(win->src.window, allow);
7018}
7020RGFW_area RGFW_getScreenSize(void) {
7021 HDC dc = GetDC(NULL);
7022 RGFW_area area = RGFW_AREA(GetDeviceCaps(dc, HORZRES), GetDeviceCaps(dc, VERTRES));
7023 ReleaseDC(NULL, dc);
7024 return area;
7025}
7027RGFW_point RGFW_getGlobalMousePoint(void) {
7028 POINT p;
7029 GetCursorPos(&p);
7031 return RGFW_POINT(p.x, p.y);
7032}
7034void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) {
7035 RGFW_ASSERT(win != NULL);
7036 win->src.aspectRatio = a;
7037}
7039void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) {
7040 RGFW_ASSERT(win != NULL);
7041 win->src.minSize = a;
7042}
7044void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) {
7045 RGFW_ASSERT(win != NULL);
7046 win->src.maxSize = a;
7047}
7049void RGFW_window_focus(RGFW_window* win) {
7050 RGFW_ASSERT(win);
7051 SetForegroundWindow(win->src.window);
7052 SetFocus(win->src.window);
7053}
7055void RGFW_window_raise(RGFW_window* win) {
7056 RGFW_ASSERT(win);
7057 BringWindowToTop(win->src.window);
7058 SetWindowPos(win->src.window, HWND_TOP, win->r.x, win->r.y, win->r.w, win->r.h, SWP_NOSIZE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
7059}
7061void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) {
7062 RGFW_ASSERT(win != NULL);
7064 if (fullscreen == RGFW_FALSE) {
7065 RGFW_window_setBorder(win, 1);
7066 SetWindowPos(win->src.window, HWND_NOTOPMOST, win->_oldRect.x, win->_oldRect.y, win->_oldRect.w, win->_oldRect.h + (i32)win->src.hOffset,
7067 SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
7069 win->_flags &= ~(u32)RGFW_windowFullscreen;
7070 win->r = win->_oldRect;
7071 return;
7072 }
7074 win->_oldRect = win->r;
7075 win->_flags |= RGFW_windowFullscreen;
7077 RGFW_monitor mon = RGFW_window_getMonitor(win);
7078 RGFW_window_setBorder(win, 0);
7080 SetWindowPos(win->src.window, HWND_TOPMOST, 0, 0, (i32)mon.mode.area.w, (i32)mon.mode.area.h, SWP_NOOWNERZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW);
7081 RGFW_monitor_scaleToWindow(mon, win);
7083 win->r = RGFW_RECT(0, 0, mon.mode.area.w, mon.mode.area.h);
7084}
7086void RGFW_window_maximize(RGFW_window* win) {
7087 RGFW_ASSERT(win != NULL);
7088 RGFW_window_hide(win);
7089 ShowWindow(win->src.window, SW_MAXIMIZE);
7090}
7092void RGFW_window_minimize(RGFW_window* win) {
7093 RGFW_ASSERT(win != NULL);
7094 ShowWindow(win->src.window, SW_MINIMIZE);
7095}
7097void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) {
7098 RGFW_ASSERT(win != NULL);
7099 if (floating) SetWindowPos(win->src.window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
7100 else SetWindowPos(win->src.window, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
7101}
7103void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) {
7104 SetWindowLong(win->src.window, GWL_EXSTYLE, WS_EX_LAYERED);
7105 SetLayeredWindowAttributes(win->src.window, 0, opacity, LWA_ALPHA);
7106}
7108void RGFW_window_restore(RGFW_window* win) { RGFW_window_show(win); }
7110RGFW_bool RGFW_window_isFloating(RGFW_window* win) {
7111 return (GetWindowLongPtr(win->src.window, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
7112}
7114u8 RGFW_xinput2RGFW[] = {
7115 RGFW_gamepadA, /* or PS X button */
7116 RGFW_gamepadB, /* or PS circle button */
7117 RGFW_gamepadX, /* or PS square button */
7118 RGFW_gamepadY, /* or PS triangle button */
7119 RGFW_gamepadR1, /* right bumper */
7120 RGFW_gamepadL1, /* left bump */
7121 RGFW_gamepadL2, /* left trigger */
7122 RGFW_gamepadR2, /* right trigger */
7123 0, 0, 0, 0, 0, 0, 0, 0,
7124 RGFW_gamepadUp, /* dpad up */
7125 RGFW_gamepadDown, /* dpad down */
7126 RGFW_gamepadLeft, /* dpad left */
7127 RGFW_gamepadRight, /* dpad right */
7128 RGFW_gamepadStart, /* start button */
7129 RGFW_gamepadSelect,/* select button */
7130 RGFW_gamepadL3,
7131 RGFW_gamepadR3,
7132};
7133i32 RGFW_checkXInput(RGFW_window* win, RGFW_event* e);
7134i32 RGFW_checkXInput(RGFW_window* win, RGFW_event* e) {
7135 #ifndef RGFW_NO_XINPUT
7137 RGFW_UNUSED(win);
7138 u16 i;
7139 for (i = 0; i < 4; i++) {
7140 XINPUT_KEYSTROKE keystroke;
7142 if (XInputGetKeystroke == NULL)
7143 return 0;
7145 DWORD result = XInputGetKeystroke((DWORD)i, 0, &keystroke);
7147 if ((keystroke.Flags & XINPUT_KEYSTROKE_REPEAT) == 0 && result != ERROR_EMPTY) {
7148 if (result != ERROR_SUCCESS)
7149 return 0;
7151 if (keystroke.VirtualKey > VK_PAD_RTHUMB_PRESS)
7152 continue;
7154 /* gamepad + 1 = RGFW_gamepadButtonReleased */
7155 e->type = RGFW_gamepadButtonPressed + !(keystroke.Flags & XINPUT_KEYSTROKE_KEYDOWN);
7156 e->button = RGFW_xinput2RGFW[keystroke.VirtualKey - 0x5800];
7157 RGFW_gamepadPressed[i][e->button].prev = RGFW_gamepadPressed[i][e->button].current;
7158 RGFW_gamepadPressed[i][e->button].current = RGFW_BOOL(keystroke.Flags & XINPUT_KEYSTROKE_KEYDOWN);
7160 RGFW_gamepadButtonCallback(win, i, e->button, e->type == RGFW_gamepadButtonPressed);
7161 return 1;
7162 }
7164 XINPUT_STATE state;
7165 if (XInputGetState == NULL ||
7166 XInputGetState((DWORD) i, &state) == ERROR_DEVICE_NOT_CONNECTED
7167 ) {
7168 if (RGFW_gamepads[i] == 0)
7169 continue;
7171 RGFW_gamepads[i] = 0;
7172 RGFW_gamepadCount--;
7174 win->event.type = RGFW_gamepadDisconnected;
7175 win->event.gamepad = (u16)i;
7176 RGFW_gamepadCallback(win, i, 0);
7177 return 1;
7178 }
7180 if (RGFW_gamepads[i] == 0) {
7181 RGFW_gamepads[i] = 1;
7182 RGFW_gamepadCount++;
7184 char str[] = "Microsoft X-Box (XInput device)";
7185 RGFW_MEMCPY(RGFW_gamepads_name[i], str, sizeof(str));
7186 RGFW_gamepads_name[i][sizeof(RGFW_gamepads_name[i]) - 1] = '\0';
7187 win->event.type = RGFW_gamepadConnected;
7188 win->event.gamepad = i;
7189 RGFW_gamepads_type[i] = RGFW_gamepadMicrosoft;
7191 RGFW_gamepadCallback(win, i, 1);
7192 return 1;
7193 }
7195#define INPUT_DEADZONE ( 0.24f * (float)(0x7FFF) ) /* Default to 24% of the +/- 32767 range. This is a reasonable default value but can be altered if needed. */
7197 if ((state.Gamepad.sThumbLX < INPUT_DEADZONE &&
7198 state.Gamepad.sThumbLX > -INPUT_DEADZONE) &&
7199 (state.Gamepad.sThumbLY < INPUT_DEADZONE &&
7200 state.Gamepad.sThumbLY > -INPUT_DEADZONE))
7201 {
7202 state.Gamepad.sThumbLX = 0;
7203 state.Gamepad.sThumbLY = 0;
7204 }
7206 if ((state.Gamepad.sThumbRX < INPUT_DEADZONE &&
7207 state.Gamepad.sThumbRX > -INPUT_DEADZONE) &&
7208 (state.Gamepad.sThumbRY < INPUT_DEADZONE &&
7209 state.Gamepad.sThumbRY > -INPUT_DEADZONE))
7210 {
7211 state.Gamepad.sThumbRX = 0;
7212 state.Gamepad.sThumbRY = 0;
7213 }
7215 e->axisesCount = 2;
7216 RGFW_point axis1 = RGFW_POINT(((float)state.Gamepad.sThumbLX / 32768.0f) * 100, ((float)state.Gamepad.sThumbLY / -32768.0f) * 100);
7217 RGFW_point axis2 = RGFW_POINT(((float)state.Gamepad.sThumbRX / 32768.0f) * 100, ((float)state.Gamepad.sThumbRY / -32768.0f) * 100);
7219 if (axis1.x != e->axis[0].x || axis1.y != e->axis[0].y){
7220 win->event.whichAxis = 0;
7222 e->type = RGFW_gamepadAxisMove;
7223 e->axis[0] = axis1;
7224 RGFW_gamepadAxes[i][0] = e->axis[0];
7226 RGFW_gamepadAxisCallback(win, e->gamepad, e->axis, e->axisesCount, e->whichAxis);
7227 return 1;
7228 }
7230 if (axis2.x != e->axis[1].x || axis2.y != e->axis[1].y) {
7231 win->event.whichAxis = 1;
7232 e->type = RGFW_gamepadAxisMove;
7233 e->axis[1] = axis2;
7234 RGFW_gamepadAxes[i][1] = e->axis[1];
7236 RGFW_gamepadAxisCallback(win, e->gamepad, e->axis, e->axisesCount, e->whichAxis);
7237 return 1;
7238 }
7239 }
7241 #endif
7243 return 0;
7244}
7246void RGFW_stopCheckEvents(void) {
7247 PostMessageW(_RGFW.root->src.window, WM_NULL, 0, 0);
7248}
7250void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) {
7251 RGFW_UNUSED(win);
7252 MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD)waitMS, QS_ALLINPUT);
7253}
7255u8 RGFW_rgfwToKeyChar(u32 rgfw_keycode) {
7256 UINT vsc = RGFW_rgfwToApiKey(rgfw_keycode); // Should return a Windows VK_* code
7257 BYTE keyboardState[256] = {0};
7259 if (!GetKeyboardState(keyboardState))
7260 return (u8)rgfw_keycode;
7262 UINT vk = MapVirtualKeyW(vsc, MAPVK_VSC_TO_VK);
7263 HKL layout = GetKeyboardLayout(0);
7265 wchar_t charBuffer[2] = {0};
7266 int result = ToUnicodeEx(vk, vsc, keyboardState, charBuffer, 1, 0, layout);
7268 if (result <= 0)
7269 return (u8)rgfw_keycode;
7271 return (u8)charBuffer[0];
7272}
7274RGFW_event* RGFW_window_checkEvent(RGFW_window* win) {
7275 if (win == NULL || ((win->_flags & RGFW_windowFreeOnClose) && (win->_flags & RGFW_EVENT_QUIT))) return NULL;
7276 RGFW_event* ev = RGFW_window_checkEventCore(win);
7277 if (ev) {
7278 return ev;
7279 }
7281 static HDROP drop;
7282 if (win->event.type == RGFW_DNDInit) {
7283 if (win->event.droppedFilesCount) {
7284 u32 i;
7285 for (i = 0; i < win->event.droppedFilesCount; i++)
7286 win->event.droppedFiles[i][0] = '\0';
7287 }
7289 win->event.droppedFilesCount = 0;
7290 win->event.droppedFilesCount = DragQueryFileW(drop, 0xffffffff, NULL, 0);
7292 u32 i;
7293 for (i = 0; i < win->event.droppedFilesCount; i++) {
7294 UINT length = DragQueryFileW(drop, i, NULL, 0);
7295 if (length == 0)
7296 continue;
7298 WCHAR buffer[RGFW_MAX_PATH * 2];
7299 if (length > (RGFW_MAX_PATH * 2) - 1)
7300 length = RGFW_MAX_PATH * 2;
7302 DragQueryFileW(drop, i, buffer, length + 1);
7304 char* str = RGFW_createUTF8FromWideStringWin32(buffer);
7305 if (str != NULL)
7306 RGFW_MEMCPY(win->event.droppedFiles[i], str, length + 1);
7308 win->event.droppedFiles[i][RGFW_MAX_PATH - 1] = '\0';
7309 }
7311 DragFinish(drop);
7312 RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount);
7314 win->event.type = RGFW_DND;
7315 return &win->event;
7316 }
7318 if (RGFW_checkXInput(win, &win->event))
7319 return &win->event;
7321 static BYTE keyboardState[256];
7322 GetKeyboardState(keyboardState);
7324 MSG msg;
7325 if (PeekMessageA(&msg, NULL, 0u, 0u, PM_REMOVE)) {
7326 if (msg.hwnd != win->src.window && msg.hwnd != NULL) {
7327 TranslateMessage(&msg);
7328 DispatchMessageA(&msg);
7329 return RGFW_window_checkEvent(win);
7330 }
7331 } else {
7332 return NULL;
7333 }
7335 switch (msg.message) {
7336 case WM_MOUSELEAVE:
7337 win->event.type = RGFW_mouseLeave;
7338 win->_flags |= RGFW_MOUSE_LEFT;
7339 RGFW_mouseNotifyCallback(win, win->event.point, 0);
7340 break;
7341 case WM_SYSKEYUP: case WM_KEYUP: {
7342 i32 scancode = (HIWORD(msg.lParam) & (KF_EXTENDED | 0xff));
7343 if (scancode == 0)
7344 scancode = (i32)MapVirtualKeyW((UINT)msg.wParam, MAPVK_VK_TO_VSC);
7346 switch (scancode) {
7347 case 0x54: scancode = 0x137; break; /* Alt+PrtS */
7348 case 0x146: scancode = 0x45; break; /* Ctrl+Pause */
7349 case 0x136: scancode = 0x36; break; /* CJK IME sets the extended bit for right Shift */
7350 default: break;
7351 }
7353 win->event.key = (u8)RGFW_apiKeyToRGFW((u32) scancode);
7355 if (msg.wParam == VK_CONTROL) {
7356 if (HIWORD(msg.lParam) & KF_EXTENDED)
7357 win->event.key = RGFW_controlR;
7358 else win->event.key = RGFW_controlL;
7359 }
7361 wchar_t charBuffer;
7362 ToUnicodeEx((UINT)msg.wParam, (UINT)scancode, keyboardState, (wchar_t*)&charBuffer, 1, 0, NULL);
7364 win->event.keyChar = (u8)charBuffer;
7366 RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current;
7367 win->event.type = RGFW_keyReleased;
7368 RGFW_keyboard[win->event.key].current = 0;
7370 RGFW_updateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001), (GetKeyState(VK_SCROLL) & 0x0001));
7372 RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 0);
7373 break;
7374 }
7375 case WM_SYSKEYDOWN: case WM_KEYDOWN: {
7376 i32 scancode = (HIWORD(msg.lParam) & (KF_EXTENDED | 0xff));
7377 if (scancode == 0)
7378 scancode = (i32)MapVirtualKeyW((u32)msg.wParam, MAPVK_VK_TO_VSC);
7380 switch (scancode) {
7381 case 0x54: scancode = 0x137; break; /* Alt+PrtS */
7382 case 0x146: scancode = 0x45; break; /* Ctrl+Pause */
7383 case 0x136: scancode = 0x36; break; /* CJK IME sets the extended bit for right Shift */
7384 default: break;
7385 }
7387 win->event.key = (u8)RGFW_apiKeyToRGFW((u32) scancode);
7388 if (msg.wParam == VK_CONTROL) {
7389 if (HIWORD(msg.lParam) & KF_EXTENDED)
7390 win->event.key = RGFW_controlR;
7391 else win->event.key = RGFW_controlL;
7392 }
7394 wchar_t charBuffer;
7395 ToUnicodeEx((UINT)msg.wParam, (UINT)scancode, keyboardState, &charBuffer, 1, 0, NULL);
7396 win->event.keyChar = (u8)charBuffer;
7398 RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current;
7400 win->event.type = RGFW_keyPressed;
7401 win->event.repeat = RGFW_isPressed(win, win->event.key);
7402 RGFW_keyboard[win->event.key].current = 1;
7403 RGFW_updateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001), (GetKeyState(VK_SCROLL) & 0x0001));
7405 RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 1);
7406 break;
7407 }
7408 case WM_MOUSEMOVE: {
7409 if ((win->_flags & RGFW_HOLD_MOUSE))
7410 break;
7412 win->event.type = RGFW_mousePosChanged;
7414 i32 x = GET_X_LPARAM(msg.lParam);
7415 i32 y = GET_Y_LPARAM(msg.lParam);
7417 RGFW_mousePosCallback(win, win->event.point, win->event.vector);
7419 if (win->_flags & RGFW_MOUSE_LEFT) {
7420 win->_flags &= ~(u32)RGFW_MOUSE_LEFT;
7421 win->event.type = RGFW_mouseEnter;
7422 RGFW_mouseNotifyCallback(win, win->event.point, 1);
7423 }
7425 win->event.point.x = x;
7426 win->event.point.y = y;
7427 win->_lastMousePoint = RGFW_POINT(x, y);
7429 break;
7430 }
7431 case WM_INPUT: {
7432 if (!(win->_flags & RGFW_HOLD_MOUSE))
7433 break;
7435 unsigned size = sizeof(RAWINPUT);
7436 static RAWINPUT raw;
7438 GetRawInputData((HRAWINPUT)msg.lParam, RID_INPUT, &raw, &size, sizeof(RAWINPUTHEADER));
7440 if (raw.header.dwType != RIM_TYPEMOUSE || (raw.data.mouse.lLastX == 0 && raw.data.mouse.lLastY == 0) )
7441 break;
7443 if (raw.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) {
7444 POINT pos = {0, 0};
7445 int width, height;
7447 if (raw.data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP) {
7448 pos.x += GetSystemMetrics(SM_XVIRTUALSCREEN);
7449 pos.y += GetSystemMetrics(SM_YVIRTUALSCREEN);
7450 width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
7451 height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
7452 }
7453 else {
7454 width = GetSystemMetrics(SM_CXSCREEN);
7455 height = GetSystemMetrics(SM_CYSCREEN);
7456 }
7458 pos.x += (int) (((float)raw.data.mouse.lLastX / 65535.f) * (float)width);
7459 pos.y += (int) (((float)raw.data.mouse.lLastY / 65535.f) * (float)height);
7460 ScreenToClient(win->src.window, &pos);
7462 win->event.vector.x = pos.x - win->_lastMousePoint.x;
7463 win->event.vector.y = pos.y - win->_lastMousePoint.y;
7464 } else {
7465 win->event.vector.x = raw.data.mouse.lLastX;
7466 win->event.vector.y = raw.data.mouse.lLastY;
7467 }
7469 win->event.type = RGFW_mousePosChanged;
7470 win->_lastMousePoint.x += win->event.vector.x;
7471 win->_lastMousePoint.y += win->event.vector.y;
7472 win->event.point = win->_lastMousePoint;
7473 RGFW_mousePosCallback(win, win->event.point, win->event.vector);
7474 break;
7475 }
7476 case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: case WM_XBUTTONDOWN:
7477 if (msg.message == WM_XBUTTONDOWN)
7478 win->event.button = RGFW_mouseMisc1 + (GET_XBUTTON_WPARAM(msg.wParam) == XBUTTON2);
7479 else win->event.button = (msg.message == WM_LBUTTONDOWN) ? RGFW_mouseLeft :
7480 (msg.message == WM_RBUTTONDOWN) ? RGFW_mouseRight : RGFW_mouseMiddle;
7482 win->event.type = RGFW_mouseButtonPressed;
7483 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
7484 RGFW_mouseButtons[win->event.button].current = 1;
7485 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
7486 break;
7487 case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MBUTTONUP: case WM_XBUTTONUP:
7488 if (msg.message == WM_XBUTTONUP)
7489 win->event.button = RGFW_mouseMisc1 + (GET_XBUTTON_WPARAM(msg.wParam) == XBUTTON2);
7490 else win->event.button = (msg.message == WM_LBUTTONUP) ? RGFW_mouseLeft :
7491 (msg.message == WM_RBUTTONUP) ? RGFW_mouseRight : RGFW_mouseMiddle;
7492 win->event.type = RGFW_mouseButtonReleased;
7493 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
7494 RGFW_mouseButtons[win->event.button].current = 0;
7495 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0);
7496 break;
7497 case WM_MOUSEWHEEL:
7498 if (msg.wParam > 0)
7499 win->event.button = RGFW_mouseScrollUp;
7500 else
7501 win->event.button = RGFW_mouseScrollDown;
7503 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
7504 RGFW_mouseButtons[win->event.button].current = 1;
7506 win->event.scroll = (SHORT) HIWORD(msg.wParam) / (double) WHEEL_DELTA;
7508 win->event.type = RGFW_mouseButtonPressed;
7509 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
7510 break;
7511 case WM_DROPFILES: {
7512 win->event.type = RGFW_DNDInit;
7514 drop = (HDROP) msg.wParam;
7515 POINT pt;
7517 /* Move the mouse to the position of the drop */
7518 DragQueryPoint(drop, &pt);
7520 win->event.point.x = pt.x;
7521 win->event.point.y = pt.y;
7523 RGFW_dndInitCallback(win, win->event.point);
7524 }
7525 break;
7526 default:
7527 TranslateMessage(&msg);
7528 DispatchMessageA(&msg);
7529 return RGFW_window_checkEvent(win);
7530 }
7532 TranslateMessage(&msg);
7533 DispatchMessageA(&msg);
7535 return &win->event;
7536}
7538RGFW_bool RGFW_window_isHidden(RGFW_window* win) {
7539 RGFW_ASSERT(win != NULL);
7541 return IsWindowVisible(win->src.window) == 0 && !RGFW_window_isMinimized(win);
7542}
7544RGFW_bool RGFW_window_isMinimized(RGFW_window* win) {
7545 RGFW_ASSERT(win != NULL);
7547 #ifndef __cplusplus
7548 WINDOWPLACEMENT placement = { 0 };
7549 #else
7550 WINDOWPLACEMENT placement = { };
7551 #endif
7552 GetWindowPlacement(win->src.window, &placement);
7553 return placement.showCmd == SW_SHOWMINIMIZED;
7554}
7556RGFW_bool RGFW_window_isMaximized(RGFW_window* win) {
7557 RGFW_ASSERT(win != NULL);
7559 #ifndef __cplusplus
7560 WINDOWPLACEMENT placement = { 0 };
7561 #else
7562 WINDOWPLACEMENT placement = { };
7563 #endif
7564 GetWindowPlacement(win->src.window, &placement);
7565 return placement.showCmd == SW_SHOWMAXIMIZED || IsZoomed(win->src.window);
7566}
7568typedef struct { int iIndex; HMONITOR hMonitor; RGFW_monitor* monitors; } RGFW_mInfo;
7569#ifndef RGFW_NO_MONITOR
7570RGFW_monitor win32CreateMonitor(HMONITOR src);
7571RGFW_monitor win32CreateMonitor(HMONITOR src) {
7572 RGFW_monitor monitor;
7573 MONITORINFOEX monitorInfo;
7575 monitorInfo.cbSize = sizeof(MONITORINFOEX);
7576 GetMonitorInfoA(src, (LPMONITORINFO)&monitorInfo);
7578 /* get the monitor's index */
7579 DISPLAY_DEVICEA dd;
7580 dd.cb = sizeof(dd);
7582 DWORD deviceNum;
7583 for (deviceNum = 0; EnumDisplayDevicesA(NULL, deviceNum, &dd, 0); deviceNum++) {
7584 if (!(dd.StateFlags & DISPLAY_DEVICE_ACTIVE))
7585 continue;
7587 DEVMODEA dm;
7588 ZeroMemory(&dm, sizeof(dm));
7589 dm.dmSize = sizeof(dm);
7591 if (EnumDisplaySettingsA(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) {
7592 monitor.mode.refreshRate = dm.dmDisplayFrequency;
7593 RGFW_splitBPP(dm.dmBitsPerPel, &monitor.mode);
7594 }
7596 DISPLAY_DEVICEA mdd;
7597 mdd.cb = sizeof(mdd);
7599 if (EnumDisplayDevicesA(dd.DeviceName, (DWORD)deviceNum, &mdd, 0)) {
7600 RGFW_STRNCPY(monitor.name, mdd.DeviceString, sizeof(monitor.name) - 1);
7601 monitor.name[sizeof(monitor.name) - 1] = '\0';
7602 break;
7603 }
7604 }
7609 monitor.x = monitorInfo.rcWork.left;
7610 monitor.y = monitorInfo.rcWork.top;
7611 monitor.mode.area.w = (u32)(monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left);
7612 monitor.mode.area.h = (u32)(monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top);
7614 HDC hdc = CreateDC(monitorInfo.szDevice, NULL, NULL, NULL);
7615 /* get pixels per inch */
7616 float dpiX = (float)GetDeviceCaps(hdc, LOGPIXELSX);
7617 float dpiY = (float)GetDeviceCaps(hdc, LOGPIXELSX);
7619 monitor.scaleX = dpiX / 96.0f;
7620 monitor.scaleY = dpiY / 96.0f;
7621 monitor.pixelRatio = dpiX >= 192.0f ? 2.0f : 1.0f;
7623 monitor.physW = (float)GetDeviceCaps(hdc, HORZSIZE) / 25.4f;
7624 monitor.physH = (float)GetDeviceCaps(hdc, VERTSIZE) / 25.4f;
7625 DeleteDC(hdc);
7627 #ifndef RGFW_NO_DPI
7628 RGFW_LOAD_LIBRARY(RGFW_Shcore_dll, "shcore.dll");
7629 RGFW_PROC_DEF(RGFW_Shcore_dll, GetDpiForMonitor);
7631 if (GetDpiForMonitor != NULL) {
7632 u32 x, y;
7633 GetDpiForMonitor(src, MDT_EFFECTIVE_DPI, &x, &y);
7634 monitor.scaleX = (float) (x) / (float) 96.0f;
7635 monitor.scaleY = (float) (y) / (float) 96.0f;
7636 monitor.pixelRatio = dpiX >= 192.0f ? 2.0f : 1.0f;
7637 }
7638 #endif
7640 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found");
7641 return monitor;
7642}
7643#endif /* RGFW_NO_MONITOR */
7645#ifndef RGFW_NO_MONITOR
7646BOOL CALLBACK GetMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData);
7647BOOL CALLBACK GetMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
7648 RGFW_UNUSED(hdcMonitor);
7649 RGFW_UNUSED(lprcMonitor);
7651 RGFW_mInfo* info = (RGFW_mInfo*) dwData;
7654 if (info->iIndex >= 6)
7655 return FALSE;
7657 info->monitors[info->iIndex] = win32CreateMonitor(hMonitor);
7658 info->iIndex++;
7660 return TRUE;
7661}
7663RGFW_monitor RGFW_getPrimaryMonitor(void) {
7664 #ifdef __cplusplus
7665 return win32CreateMonitor(MonitorFromPoint({ 0, 0 }, MONITOR_DEFAULTTOPRIMARY));
7666 #else
7667 return win32CreateMonitor(MonitorFromPoint((POINT) { 0, 0 }, MONITOR_DEFAULTTOPRIMARY));
7668 #endif
7669}
7671RGFW_monitor* RGFW_getMonitors(size_t* len) {
7672 static RGFW_monitor monitors[6];
7673 RGFW_mInfo info;
7674 info.iIndex = 0;
7675 info.monitors = monitors;
7677 EnumDisplayMonitors(NULL, NULL, GetMonitorHandle, (LPARAM) &info);
7679 if (len != NULL) *len = (size_t)info.iIndex;
7680 return monitors;
7681}
7683RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) {
7684 HMONITOR src = MonitorFromWindow(win->src.window, MONITOR_DEFAULTTOPRIMARY);
7685 return win32CreateMonitor(src);
7686}
7688RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) {
7689 POINT p = { mon.x, mon.y };
7690 HMONITOR src = MonitorFromPoint(p, MONITOR_DEFAULTTOPRIMARY);
7692 MONITORINFOEX monitorInfo;
7693 monitorInfo.cbSize = sizeof(MONITORINFOEX);
7694 GetMonitorInfoA(src, (LPMONITORINFO)&monitorInfo);
7696 DISPLAY_DEVICEA dd;
7697 dd.cb = sizeof(dd);
7699 /* Enumerate display devices */
7700 DWORD deviceNum;
7701 for (deviceNum = 0; EnumDisplayDevicesA(NULL, deviceNum, &dd, 0); deviceNum++) {
7702 if (!(dd.StateFlags & DISPLAY_DEVICE_ACTIVE))
7703 continue;
7705 if (strcmp(dd.DeviceName, (const char*)monitorInfo.szDevice) != 0)
7706 continue;
7708 DEVMODEA dm;
7709 ZeroMemory(&dm, sizeof(dm));
7710 dm.dmSize = sizeof(dm);
7712 if (EnumDisplaySettingsA(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) {
7713 if (request & RGFW_monitorScale) {
7714 dm.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT;
7715 dm.dmPelsWidth = mode.area.w;
7716 dm.dmPelsHeight = mode.area.h;
7717 }
7719 if (request & RGFW_monitorRefresh) {
7720 dm.dmFields |= DM_DISPLAYFREQUENCY;
7721 dm.dmDisplayFrequency = mode.refreshRate;
7722 }
7724 if (request & RGFW_monitorRGB) {
7725 dm.dmFields |= DM_BITSPERPEL;
7726 dm.dmBitsPerPel = (DWORD)(mode.red + mode.green + mode.blue);
7727 }
7729 if (ChangeDisplaySettingsExA((LPCSTR)dd.DeviceName, (DEVMODE *)&dm, NULL, CDS_TEST, NULL) == DISP_CHANGE_SUCCESSFUL) {
7730 if (ChangeDisplaySettingsExA((LPCSTR)dd.DeviceName, (DEVMODE *)&dm, NULL, CDS_UPDATEREGISTRY, NULL) == DISP_CHANGE_SUCCESSFUL)
7731 return RGFW_TRUE;
7732 return RGFW_FALSE;
7733 } else return RGFW_FALSE;
7734 }
7735 }
7737 return RGFW_FALSE;
7738}
7740#endif
7741HICON RGFW_loadHandleImage(u8* src, i32 c, RGFW_area a, BOOL icon);
7742HICON RGFW_loadHandleImage(u8* src, i32 c, RGFW_area a, BOOL icon) {
7743 size_t channels = (size_t)c;
7745 BITMAPV5HEADER bi;
7746 ZeroMemory(&bi, sizeof(bi));
7747 bi.bV5Size = sizeof(bi);
7748 bi.bV5Width = (i32)a.w;
7749 bi.bV5Height = -((LONG) a.h);
7750 bi.bV5Planes = 1;
7751 bi.bV5BitCount = (WORD)(channels * 8);
7752 bi.bV5Compression = BI_RGB;
7753 HDC dc = GetDC(NULL);
7754 u8* target = NULL;
7756 HBITMAP color = CreateDIBSection(dc,
7757 (BITMAPINFO*) &bi, DIB_RGB_COLORS, (void**) &target,
7758 NULL, (DWORD) 0);
7760 size_t x, y;
7761 for (y = 0; y < a.h; y++) {
7762 for (x = 0; x < a.w; x++) {
7763 size_t index = (y * 4 * (size_t)a.w) + x * channels;
7764 target[index] = src[index + 2];
7765 target[index + 1] = src[index + 1];
7766 target[index + 2] = src[index];
7767 target[index + 3] = src[index + 3];
7768 }
7769 }
7771 ReleaseDC(NULL, dc);
7773 HBITMAP mask = CreateBitmap((i32)a.w, (i32)a.h, 1, 1, NULL);
7775 ICONINFO ii;
7776 ZeroMemory(&ii, sizeof(ii));
7777 ii.fIcon = icon;
7778 ii.xHotspot = a.w / 2;
7779 ii.yHotspot = a.h / 2;
7780 ii.hbmMask = mask;
7781 ii.hbmColor = color;
7783 HICON handle = CreateIconIndirect(&ii);
7785 DeleteObject(color);
7786 DeleteObject(mask);
7788 return handle;
7789}
7791void* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) {
7792 HCURSOR cursor = (HCURSOR) RGFW_loadHandleImage(icon, channels, a, FALSE);
7793 return cursor;
7794}
7796void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) {
7797 RGFW_ASSERT(win && mouse);
7798 SetClassLongPtrA(win->src.window, GCLP_HCURSOR, (LPARAM) mouse);
7799 SetCursor((HCURSOR)mouse);
7800}
7802void RGFW_freeMouse(RGFW_mouse* mouse) {
7803 RGFW_ASSERT(mouse);
7804 DestroyCursor((HCURSOR)mouse);
7805}
7807RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) {
7808 return RGFW_window_setMouseStandard(win, RGFW_mouseArrow);
7809}
7811RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) {
7812 RGFW_ASSERT(win != NULL);
7814 static const u32 mouseIconSrc[16] = {OCR_NORMAL, OCR_NORMAL, OCR_IBEAM, OCR_CROSS, OCR_HAND, OCR_SIZEWE, OCR_SIZENS, OCR_SIZENWSE, OCR_SIZENESW, OCR_SIZEALL, OCR_NO};
7815 if (mouse > (sizeof(mouseIconSrc) / sizeof(u32)))
7816 return RGFW_FALSE;
7818 char* icon = MAKEINTRESOURCEA(mouseIconSrc[mouse]);
7820 SetClassLongPtrA(win->src.window, GCLP_HCURSOR, (LPARAM) LoadCursorA(NULL, icon));
7821 SetCursor(LoadCursorA(NULL, icon));
7822 return RGFW_TRUE;
7823}
7825void RGFW_window_hide(RGFW_window* win) {
7826 ShowWindow(win->src.window, SW_HIDE);
7827}
7829void RGFW_window_show(RGFW_window* win) {
7830 if (win->_flags & RGFW_windowFocusOnShow) RGFW_window_focus(win);
7831 ShowWindow(win->src.window, SW_RESTORE);
7832}
7834#define RGFW_FREE_LIBRARY(x) if (x != NULL) FreeLibrary(x); x = NULL;
7835void RGFW_deinit(void) {
7836 #ifndef RGFW_NO_XINPUT
7837 RGFW_FREE_LIBRARY(RGFW_XInput_dll);
7838 #endif
7840 #ifndef RGFW_NO_DPI
7841 RGFW_FREE_LIBRARY(RGFW_Shcore_dll);
7842 #endif
7844 #ifndef RGFW_NO_WINMM
7845 timeEndPeriod(1);
7846 #ifndef RGFW_NO_LOAD_WINMM
7847 RGFW_FREE_LIBRARY(RGFW_winmm_dll);
7848 #endif
7849 #endif
7851 RGFW_FREE_LIBRARY(RGFW_wgl_dll);
7852 _RGFW.root = NULL;
7854 RGFW_freeMouse(_RGFW.hiddenMouse);
7855 _RGFW.windowCount = -1;
7856 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized");
7857}
7860void RGFW_window_close(RGFW_window* win) {
7861 RGFW_ASSERT(win != NULL);
7862 #ifdef RGFW_BUFFER
7863 DeleteDC(win->src.hdcMem);
7864 DeleteObject(win->src.bitmap);
7865 #endif
7867 if ((win->_flags & RGFW_windowNoInitAPI) == 0) RGFW_window_freeOpenGL(win);
7868 RemovePropW(win->src.window, L"RGFW");
7869 ReleaseDC(win->src.window, win->src.hdc); /*!< delete device context */
7870 DestroyWindow(win->src.window); /*!< delete window */
7872 if (win->src.hIconSmall) DestroyIcon(win->src.hIconSmall);
7873 if (win->src.hIconBig) DestroyIcon(win->src.hIconBig);
7875 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a window was freed");
7876 _RGFW.windowCount--;
7877 if (_RGFW.windowCount == 0) RGFW_deinit();
7879 RGFW_clipboard_switch(NULL);
7880 RGFW_FREE(win->event.droppedFiles);
7881 if ((win->_flags & RGFW_WINDOW_ALLOC)) {
7882 RGFW_FREE(win);
7883 win = NULL;
7884 }
7885}
7887void RGFW_window_move(RGFW_window* win, RGFW_point v) {
7888 RGFW_ASSERT(win != NULL);
7890 win->r.x = v.x;
7891 win->r.y = v.y;
7892 SetWindowPos(win->src.window, HWND_TOP, win->r.x, win->r.y, 0, 0, SWP_NOSIZE);
7893}
7895void RGFW_window_resize(RGFW_window* win, RGFW_area a) {
7896 RGFW_ASSERT(win != NULL);
7898 win->r.w = (i32)a.w;
7899 win->r.h = (i32)a.h;
7900 SetWindowPos(win->src.window, HWND_TOP, 0, 0, win->r.w, win->r.h + (i32)win->src.hOffset, SWP_NOMOVE);
7901}
7904void RGFW_window_setName(RGFW_window* win, const char* name) {
7905 RGFW_ASSERT(win != NULL);
7907 wchar_t wide_name[256];
7908 MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_name, 256);
7909 SetWindowTextW(win->src.window, wide_name);
7910}
7912#ifndef RGFW_NO_PASSTHROUGH
7913void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) {
7914 RGFW_ASSERT(win != NULL);
7915 COLORREF key = 0;
7916 BYTE alpha = 0;
7917 DWORD flags = 0;
7918 i32 exStyle = GetWindowLongW(win->src.window, GWL_EXSTYLE);
7920 if (exStyle & WS_EX_LAYERED)
7921 GetLayeredWindowAttributes(win->src.window, &key, &alpha, &flags);
7923 if (passthrough)
7924 exStyle |= (WS_EX_TRANSPARENT | WS_EX_LAYERED);
7925 else {
7926 exStyle &= ~WS_EX_TRANSPARENT;
7927 if (exStyle & WS_EX_LAYERED && !(flags & LWA_ALPHA))
7928 exStyle &= ~WS_EX_LAYERED;
7929 }
7931 SetWindowLongW(win->src.window, GWL_EXSTYLE, exStyle);
7933 if (passthrough)
7934 SetLayeredWindowAttributes(win->src.window, key, alpha, flags);
7935}
7936#endif
7938RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* src, RGFW_area a, i32 channels, u8 type) {
7939 RGFW_ASSERT(win != NULL);
7940 #ifndef RGFW_WIN95
7941 RGFW_UNUSED(channels);
7943 if (win->src.hIconSmall && (type & RGFW_iconWindow)) DestroyIcon(win->src.hIconSmall);
7944 if (win->src.hIconBig && (type & RGFW_iconTaskbar)) DestroyIcon(win->src.hIconBig);
7946 if (src == NULL) {
7947 HICON defaultIcon = LoadIcon(NULL, IDI_APPLICATION);
7948 if (type & RGFW_iconWindow)
7949 SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)defaultIcon);
7950 if (type & RGFW_iconTaskbar)
7951 SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)defaultIcon);
7952 return RGFW_TRUE;
7953 }
7955 if (type & RGFW_iconWindow) {
7956 win->src.hIconSmall = RGFW_loadHandleImage(src, channels, a, TRUE);
7957 SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)win->src.hIconSmall);
7958 }
7959 if (type & RGFW_iconTaskbar) {
7960 win->src.hIconBig = RGFW_loadHandleImage(src, channels, a, TRUE);
7961 SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)win->src.hIconBig);
7962 }
7963 return RGFW_TRUE;
7964 #else
7965 RGFW_UNUSED(src);
7966 RGFW_UNUSED(a);
7967 RGFW_UNUSED(channels);
7968 return RGFW_FALSE;
7969 #endif
7970}
7972RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) {
7973 /* Open the clipboard */
7974 if (OpenClipboard(NULL) == 0)
7975 return -1;
7977 /* Get the clipboard data as a Unicode string */
7978 HANDLE hData = GetClipboardData(CF_UNICODETEXT);
7979 if (hData == NULL) {
7980 CloseClipboard();
7981 return -1;
7982 }
7984 wchar_t* wstr = (wchar_t*) GlobalLock(hData);
7986 RGFW_ssize_t textLen = 0;
7988 {
7989 setlocale(LC_ALL, "en_US.UTF-8");
7991 textLen = (RGFW_ssize_t)wcstombs(NULL, wstr, 0) + 1;
7992 if (str != NULL && (RGFW_ssize_t)strCapacity <= textLen - 1)
7993 textLen = 0;
7995 if (str != NULL && textLen) {
7996 if (textLen > 1)
7997 wcstombs(str, wstr, (size_t)(textLen));
7999 str[textLen] = '\0';
8000 }
8001 }
8003 /* Release the clipboard data */
8004 GlobalUnlock(hData);
8005 CloseClipboard();
8007 return textLen;
8008}
8010void RGFW_writeClipboard(const char* text, u32 textLen) {
8011 HANDLE object;
8012 WCHAR* buffer;
8014 object = GlobalAlloc(GMEM_MOVEABLE, (1 + textLen) * sizeof(WCHAR));
8015 if (!object)
8016 return;
8018 buffer = (WCHAR*) GlobalLock(object);
8019 if (!buffer) {
8020 GlobalFree(object);
8021 return;
8022 }
8024 MultiByteToWideChar(CP_UTF8, 0, text, -1, buffer, (i32)textLen);
8025 GlobalUnlock(object);
8027 if (!OpenClipboard(_RGFW.root->src.window)) {
8028 GlobalFree(object);
8029 return;
8030 }
8032 EmptyClipboard();
8033 SetClipboardData(CF_UNICODETEXT, object);
8034 CloseClipboard();
8035}
8037void RGFW_window_moveMouse(RGFW_window* win, RGFW_point p) {
8038 RGFW_ASSERT(win != NULL);
8039 win->_lastMousePoint = RGFW_POINT(p.x - win->r.x, p.y - win->r.y);
8040 SetCursorPos(p.x, p.y);
8041}
8043#ifdef RGFW_OPENGL
8044void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
8045 if (win == NULL)
8046 wglMakeCurrent(NULL, NULL);
8047 else
8048 wglMakeCurrent(win->src.hdc, (HGLRC) win->src.ctx);
8049}
8050void* RGFW_getCurrent_OpenGL(void) { return wglGetCurrentContext(); }
8051void RGFW_window_swapBuffers_OpenGL(RGFW_window* win){ SwapBuffers(win->src.hdc); }
8052#endif
8054#ifndef RGFW_EGL
8055void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) {
8056 RGFW_ASSERT(win != NULL);
8057#if defined(RGFW_OPENGL)
8058 if (wglSwapIntervalEXT == NULL || wglSwapIntervalEXT(swapInterval) == FALSE)
8059 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to set swap interval");
8060#else
8061 RGFW_UNUSED(swapInterval);
8062#endif
8063}
8064#endif
8066void RGFW_window_swapBuffers_software(RGFW_window* win) {
8067#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
8068 if (win->buffer != win->src.bitmapBits)
8069 memcpy(win->src.bitmapBits, win->buffer, win->bufferSize.w * win->bufferSize.h * 4);
8071 RGFW_RGB_to_BGR(win, win->src.bitmapBits);
8072 BitBlt(win->src.hdc, 0, 0, win->r.w, win->r.h, win->src.hdcMem, 0, 0, SRCCOPY);
8073#else
8074 RGFW_UNUSED(win);
8075#endif
8076}
8078char* RGFW_createUTF8FromWideStringWin32(const WCHAR* source) {
8079 if (source == NULL) {
8080 return NULL;
8081 }
8082 i32 size = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL);
8083 if (!size) {
8084 return NULL;
8085 }
8087 static char target[RGFW_MAX_PATH * 2];
8088 if (size > RGFW_MAX_PATH * 2)
8089 size = RGFW_MAX_PATH * 2;
8091 target[size] = 0;
8093 if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, size, NULL, NULL)) {
8094 return NULL;
8095 }
8097 return target;
8098}
8100u64 RGFW_getTimerFreq(void) {
8101 static u64 frequency = 0;
8102 if (frequency == 0) QueryPerformanceFrequency((LARGE_INTEGER*)&frequency);
8104 return frequency;
8105}
8107u64 RGFW_getTimerValue(void) {
8108 u64 value;
8109 QueryPerformanceCounter((LARGE_INTEGER*)&value);
8110 return value;
8111}
8113void RGFW_sleep(u64 ms) {
8114 Sleep((u32)ms);
8115}
8117#ifndef RGFW_NO_THREADS
8119RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args) { return CreateThread(NULL, 0, ptr, args, 0, NULL); }
8120void RGFW_cancelThread(RGFW_thread thread) { CloseHandle((HANDLE) thread); }
8121void RGFW_joinThread(RGFW_thread thread) { WaitForSingleObject((HANDLE) thread, INFINITE); }
8122void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { SetThreadPriority((HANDLE) thread, priority); }
8124#endif
8125#endif /* RGFW_WINDOWS */
8127/*
8128 End of Windows defines
8129*/
8133/*
8135 Start of MacOS defines
8138*/
8140#if defined(RGFW_MACOS)
8141/*
8142 based on silicon.h
8143 start of cocoa wrapper
8144*/
8146#include <CoreGraphics/CoreGraphics.h>
8147#include <ApplicationServices/ApplicationServices.h>
8148#include <objc/runtime.h>
8149#include <objc/message.h>
8150#include <mach/mach_time.h>
8151#include <CoreVideo/CoreVideo.h>
8153typedef CGRect NSRect;
8154typedef CGPoint NSPoint;
8155typedef CGSize NSSize;
8157typedef const char* NSPasteboardType;
8158typedef unsigned long NSUInteger;
8159typedef long NSInteger;
8160typedef NSInteger NSModalResponse;
8162#ifdef __arm64__
8163 /* ARM just uses objc_msgSend */
8164#define abi_objc_msgSend_stret objc_msgSend
8165#define abi_objc_msgSend_fpret objc_msgSend
8166#else /* __i386__ */
8167 /* x86 just uses abi_objc_msgSend_fpret and (NSColor *)objc_msgSend_id respectively */
8168#define abi_objc_msgSend_stret objc_msgSend_stret
8169#define abi_objc_msgSend_fpret objc_msgSend_fpret
8170#endif
8172#define NSAlloc(nsclass) objc_msgSend_id((id)nsclass, sel_registerName("alloc"))
8173#define objc_msgSend_bool(x, y) ((BOOL (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
8174#define objc_msgSend_void(x, y) ((void (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
8175#define objc_msgSend_void_id(x, y, z) ((void (*)(id, SEL, id))objc_msgSend) ((id)x, (SEL)y, (id)z)
8176#define objc_msgSend_uint(x, y) ((NSUInteger (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
8177#define objc_msgSend_void_bool(x, y, z) ((void (*)(id, SEL, BOOL))objc_msgSend) ((id)(x), (SEL)y, (BOOL)z)
8178#define objc_msgSend_bool_void(x, y) ((BOOL (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
8179#define objc_msgSend_void_SEL(x, y, z) ((void (*)(id, SEL, SEL))objc_msgSend) ((id)(x), (SEL)y, (SEL)z)
8180#define objc_msgSend_id(x, y) ((id (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
8181#define objc_msgSend_id_id(x, y, z) ((id (*)(id, SEL, id))objc_msgSend) ((id)(x), (SEL)y, (id)z)
8182#define objc_msgSend_id_bool(x, y, z) ((BOOL (*)(id, SEL, id))objc_msgSend) ((id)(x), (SEL)y, (id)z)
8183#define objc_msgSend_int(x, y, z) ((id (*)(id, SEL, int))objc_msgSend) ((id)(x), (SEL)y, (int)z)
8184#define objc_msgSend_arr(x, y, z) ((id (*)(id, SEL, int))objc_msgSend) ((id)(x), (SEL)y, (int)z)
8185#define objc_msgSend_ptr(x, y, z) ((id (*)(id, SEL, void*))objc_msgSend) ((id)(x), (SEL)y, (void*)z)
8186#define objc_msgSend_class(x, y) ((id (*)(Class, SEL))objc_msgSend) ((Class)(x), (SEL)y)
8187#define objc_msgSend_class_char(x, y, z) ((id (*)(Class, SEL, char*))objc_msgSend) ((Class)(x), (SEL)y, (char*)z)
8189id NSApp = NULL;
8191#define NSRelease(obj) objc_msgSend_void((id)obj, sel_registerName("release"))
8192id NSString_stringWithUTF8String(const char* str);
8193id NSString_stringWithUTF8String(const char* str) {
8194 return ((id(*)(id, SEL, const char*))objc_msgSend)
8195 ((id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), str);
8196}
8198const char* NSString_to_char(id str);
8199const char* NSString_to_char(id str) {
8200 return ((const char* (*)(id, SEL)) objc_msgSend) ((id)(id)str, sel_registerName("UTF8String"));
8201}
8203void si_impl_func_to_SEL_with_name(const char* class_name, const char* register_name, void* function);
8204void si_impl_func_to_SEL_with_name(const char* class_name, const char* register_name, void* function) {
8205 Class selected_class;
8207 if (RGFW_STRNCMP(class_name, "NSView", 6) == 0) {
8208 selected_class = objc_getClass("ViewClass");
8209 } else if (RGFW_STRNCMP(class_name, "NSWindow", 8) == 0) {
8210 selected_class = objc_getClass("WindowClass");
8211 } else {
8212 selected_class = objc_getClass(class_name);
8213 }
8215 class_addMethod(selected_class, sel_registerName(register_name), (IMP) function, 0);
8216}
8218/* Header for the array. */
8219typedef struct siArrayHeader {
8220 size_t count;
8221 /* TODO(EimaMei): Add a `type_width` later on. */
8222} siArrayHeader;
8224/* Gets the header of the siArray. */
8225#define SI_ARRAY_HEADER(s) ((siArrayHeader*)s - 1)
8226#define si_array_len(array) (SI_ARRAY_HEADER(array)->count)
8227#define si_func_to_SEL(class_name, function) si_impl_func_to_SEL_with_name(class_name, #function":", (void*)function)
8228/* Creates an Objective-C method (SEL) from a regular C function with the option to set the register name.*/
8229#define si_func_to_SEL_with_name(class_name, register_name, function) si_impl_func_to_SEL_with_name(class_name, register_name":", (void*)function)
8231unsigned char* NSBitmapImageRep_bitmapData(id imageRep);
8232unsigned char* NSBitmapImageRep_bitmapData(id imageRep) {
8233 return ((unsigned char* (*)(id, SEL))objc_msgSend) ((id)imageRep, sel_registerName("bitmapData"));
8234}
8236typedef RGFW_ENUM(NSUInteger, NSBitmapFormat) {
8237 NSBitmapFormatAlphaFirst = 1 << 0, /* 0 means is alpha last (RGBA, CMYKA, etc.) */
8238 NSBitmapFormatAlphaNonpremultiplied = 1 << 1, /* 0 means is premultiplied */
8239 NSBitmapFormatFloatingpointSamples = 1 << 2, /* 0 is integer */
8241 NSBitmapFormatSixteenBitLittleEndian = (1 << 8),
8242 NSBitmapFormatThirtyTwoBitLittleEndian = (1 << 9),
8243 NSBitmapFormatSixteenBitBigEndian = (1 << 10),
8244 NSBitmapFormatThirtyTwoBitBigEndian = (1 << 11)
8245};
8247id 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);
8248id 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) {
8249 SEL func = sel_registerName("initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bitmapFormat:bytesPerRow:bitsPerPixel:");
8251 return (id) ((id(*)(id, SEL, unsigned char**, NSInteger, NSInteger, NSInteger, NSInteger, bool, bool, id, NSBitmapFormat, NSInteger, NSInteger))objc_msgSend)
8252 (NSAlloc((id)objc_getClass("NSBitmapImageRep")), func, planes, width, height, bps, spp, alpha, isPlanar, NSString_stringWithUTF8String(colorSpaceName), bitmapFormat, rowBytes, pixelBits);
8253}
8255id NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha);
8256id NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha) {
8257 void* nsclass = objc_getClass("NSColor");
8258 SEL func = sel_registerName("colorWithSRGBRed:green:blue:alpha:");
8259 return ((id(*)(id, SEL, CGFloat, CGFloat, CGFloat, CGFloat))objc_msgSend)
8260 ((id)nsclass, func, red, green, blue, alpha);
8261}
8263typedef RGFW_ENUM(NSInteger, NSOpenGLContextParameter) {
8264 NSOpenGLContextParameterSwapInterval = 222, /* 1 param. 0 -> Don't sync, 1 -> Sync to vertical retrace */
8265 NSOpenGLContextParametectxaceOrder = 235, /* 1 param. 1 -> Above Window (default), -1 -> Below Window */
8266 NSOpenGLContextParametectxaceOpacity = 236, /* 1 param. 1-> Surface is opaque (default), 0 -> non-opaque */
8267 NSOpenGLContextParametectxaceBackingSize = 304, /* 2 params. Width/height of surface backing size */
8268 NSOpenGLContextParameterReclaimResources = 308, /* 0 params. */
8269 NSOpenGLContextParameterCurrentRendererID = 309, /* 1 param. Retrieves the current renderer ID */
8270 NSOpenGLContextParameterGPUVertexProcessing = 310, /* 1 param. Currently processing vertices with GPU (get) */
8271 NSOpenGLContextParameterGPUFragmentProcessing = 311, /* 1 param. Currently processing fragments with GPU (get) */
8272 NSOpenGLContextParameterHasDrawable = 314, /* 1 param. Boolean returned if drawable is attached */
8273 NSOpenGLContextParameterMPSwapsInFlight = 315, /* 1 param. Max number of swaps queued by the MP GL engine */
8275 NSOpenGLContextParameterSwapRectangle API_DEPRECATED("", macos(10.0, 10.14)) = 200, /* 4 params. Set or get the swap rectangle {x, y, w, h} */
8276 NSOpenGLContextParameterSwapRectangleEnable API_DEPRECATED("", macos(10.0, 10.14)) = 201, /* Enable or disable the swap rectangle */
8277 NSOpenGLContextParameterRasterizationEnable API_DEPRECATED("", macos(10.0, 10.14)) = 221, /* Enable or disable all rasterization */
8278 NSOpenGLContextParameterStateValidation API_DEPRECATED("", macos(10.0, 10.14)) = 301, /* Validate state for multi-screen functionality */
8279 NSOpenGLContextParametectxaceSurfaceVolatile API_DEPRECATED("", macos(10.0, 10.14)) = 306, /* 1 param. Surface volatile state */
8280};
8282typedef RGFW_ENUM(NSInteger, NSWindowButton) {
8283 NSWindowCloseButton = 0,
8284 NSWindowMiniaturizeButton = 1,
8285 NSWindowZoomButton = 2,
8286 NSWindowToolbarButton = 3,
8287 NSWindowDocumentIconButton = 4,
8288 NSWindowDocumentVersionsButton = 6,
8289 NSWindowFullScreenButton = 7,
8290};
8291void NSOpenGLContext_setValues(id context, const int* vals, NSOpenGLContextParameter param);
8292void NSOpenGLContext_setValues(id context, const int* vals, NSOpenGLContextParameter param) {
8293 ((void (*)(id, SEL, const int*, NSOpenGLContextParameter))objc_msgSend)
8294 (context, sel_registerName("setValues:forParameter:"), vals, param);
8295}
8296void* NSOpenGLPixelFormat_initWithAttributes(const uint32_t* attribs);
8297void* NSOpenGLPixelFormat_initWithAttributes(const uint32_t* attribs) {
8298 return (void*) ((id(*)(id, SEL, const uint32_t*))objc_msgSend)
8299 (NSAlloc((id)objc_getClass("NSOpenGLPixelFormat")), sel_registerName("initWithAttributes:"), attribs);
8300}
8302id NSPasteboard_generalPasteboard(void);
8303id NSPasteboard_generalPasteboard(void) {
8304 return (id) objc_msgSend_id((id)objc_getClass("NSPasteboard"), sel_registerName("generalPasteboard"));
8305}
8307id* cstrToNSStringArray(char** strs, size_t len);
8308id* cstrToNSStringArray(char** strs, size_t len) {
8309 static id nstrs[6];
8310 size_t i;
8311 for (i = 0; i < len; i++)
8312 nstrs[i] = NSString_stringWithUTF8String(strs[i]);
8314 return nstrs;
8315}
8317const char* NSPasteboard_stringForType(id pasteboard, NSPasteboardType dataType, size_t* len);
8318const char* NSPasteboard_stringForType(id pasteboard, NSPasteboardType dataType, size_t* len) {
8319 SEL func = sel_registerName("stringForType:");
8320 id nsstr = NSString_stringWithUTF8String(dataType);
8321 id nsString = ((id(*)(id, SEL, id))objc_msgSend)(pasteboard, func, nsstr);
8322 const char* str = NSString_to_char(nsString);
8323 if (len != NULL)
8324 *len = (size_t)((NSUInteger(*)(id, SEL, int))objc_msgSend)(nsString, sel_registerName("maximumLengthOfBytesUsingEncoding:"), 4);
8325 return str;
8326}
8328id c_array_to_NSArray(void* array, size_t len);
8329id c_array_to_NSArray(void* array, size_t len) {
8330 SEL func = sel_registerName("initWithObjects:count:");
8331 void* nsclass = objc_getClass("NSArray");
8332 return ((id (*)(id, SEL, void*, NSUInteger))objc_msgSend)
8333 (NSAlloc(nsclass), func, array, len);
8334}
8337void NSregisterForDraggedTypes(id view, NSPasteboardType* newTypes, size_t len);
8338void NSregisterForDraggedTypes(id view, NSPasteboardType* newTypes, size_t len) {
8339 id* ntypes = cstrToNSStringArray((char**)newTypes, len);
8341 id array = c_array_to_NSArray(ntypes, len);
8342 objc_msgSend_void_id(view, sel_registerName("registerForDraggedTypes:"), array);
8343 NSRelease(array);
8344}
8346NSInteger NSPasteBoard_declareTypes(id pasteboard, NSPasteboardType* newTypes, size_t len, void* owner);
8347NSInteger NSPasteBoard_declareTypes(id pasteboard, NSPasteboardType* newTypes, size_t len, void* owner) {
8348 id* ntypes = cstrToNSStringArray((char**)newTypes, len);
8350 SEL func = sel_registerName("declareTypes:owner:");
8352 id array = c_array_to_NSArray(ntypes, len);
8354 NSInteger output = ((NSInteger(*)(id, SEL, id, void*))objc_msgSend)
8355 (pasteboard, func, array, owner);
8356 NSRelease(array);
8358 return output;
8359}
8361#define NSRetain(obj) objc_msgSend_void((id)obj, sel_registerName("retain"))
8363typedef enum NSApplicationActivationPolicy {
8364 NSApplicationActivationPolicyRegular,
8365 NSApplicationActivationPolicyAccessory,
8366 NSApplicationActivationPolicyProhibited
8367} NSApplicationActivationPolicy;
8369typedef RGFW_ENUM(u32, NSBackingStoreType) {
8370 NSBackingStoreRetained = 0,
8371 NSBackingStoreNonretained = 1,
8372 NSBackingStoreBuffered = 2
8373};
8375typedef RGFW_ENUM(u32, NSWindowStyleMask) {
8376 NSWindowStyleMaskBorderless = 0,
8377 NSWindowStyleMaskTitled = 1 << 0,
8378 NSWindowStyleMaskClosable = 1 << 1,
8379 NSWindowStyleMaskMiniaturizable = 1 << 2,
8380 NSWindowStyleMaskResizable = 1 << 3,
8381 NSWindowStyleMaskTexturedBackground = 1 << 8, /* deprecated */
8382 NSWindowStyleMaskUnifiedTitleAndToolbar = 1 << 12,
8383 NSWindowStyleMaskFullScreen = 1 << 14,
8384 NSWindowStyleMaskFullSizeContentView = 1 << 15,
8385 NSWindowStyleMaskUtilityWindow = 1 << 4,
8386 NSWindowStyleMaskDocModalWindow = 1 << 6,
8387 NSWindowStyleMaskNonactivatingpanel = 1 << 7,
8388 NSWindowStyleMaskHUDWindow = 1 << 13
8389};
8391NSPasteboardType const NSPasteboardTypeString = "public.utf8-plain-text"; /* Replaces NSStringPasteboardType */
8394typedef RGFW_ENUM(i32, NSDragOperation) {
8395 NSDragOperationNone = 0,
8396 NSDragOperationCopy = 1,
8397 NSDragOperationLink = 2,
8398 NSDragOperationGeneric = 4,
8399 NSDragOperationPrivate = 8,
8400 NSDragOperationMove = 16,
8401 NSDragOperationDelete = 32,
8402 NSDragOperationEvery = (int)ULONG_MAX
8403};
8405void* NSArray_objectAtIndex(id array, NSUInteger index) {
8406 SEL func = sel_registerName("objectAtIndex:");
8407 return ((id(*)(id, SEL, NSUInteger))objc_msgSend)(array, func, index);
8408}
8410id NSWindow_contentView(id window) {
8411 SEL func = sel_registerName("contentView");
8412 return objc_msgSend_id(window, func);
8413}
8415/*
8416 End of cocoa wrapper
8417*/
8419#ifdef RGFW_OPENGL
8420/* MacOS opengl API spares us yet again (there are no extensions) */
8421RGFW_bool RGFW_extensionSupportedPlatform(const char * extension, size_t len) { RGFW_UNUSED(extension); RGFW_UNUSED(len); return RGFW_FALSE; }
8422CFBundleRef RGFWnsglFramework = NULL;
8424RGFW_proc RGFW_getProcAddress(const char* procname) {
8425 if (RGFWnsglFramework == NULL)
8426 RGFWnsglFramework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
8428 CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault, procname, kCFStringEncodingASCII);
8430 RGFW_proc symbol = (RGFW_proc)CFBundleGetFunctionPointerForName(RGFWnsglFramework, symbolName);
8432 CFRelease(symbolName);
8434 return symbol;
8435}
8436#endif
8438id NSWindow_delegate(RGFW_window* win) {
8439 return (id) objc_msgSend_id((id)win->src.window, sel_registerName("delegate"));
8440}
8442u32 RGFW_OnClose(id self) {
8443 RGFW_window* win = NULL;
8444 object_getInstanceVariable(self, (const char*)"RGFW_window", (void**)&win);
8445 if (win == NULL)
8446 return true;
8448 RGFW_eventQueuePushEx(e.type = RGFW_quit; e._win = win);
8449 RGFW_windowQuitCallback(win);
8451 return false;
8452}
8454/* NOTE(EimaMei): Fixes the constant clicking when the app is running under a terminal. */
8455bool acceptsFirstResponder(void) { return true; }
8456bool performKeyEquivalent(id event) { RGFW_UNUSED(event); return true; }
8458NSDragOperation draggingEntered(id self, SEL sel, id sender) {
8459 RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel);
8461 return NSDragOperationCopy;
8462}
8463NSDragOperation draggingUpdated(id self, SEL sel, id sender) {
8464 RGFW_UNUSED(sel);
8466 RGFW_window* win = NULL;
8467 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
8468 if (win == NULL || (!(win->_flags & RGFW_windowAllowDND)))
8469 return 0;
8471 NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation"));
8472 RGFW_eventQueuePushEx(e.type = RGFW_DNDInit;
8473 e.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y));
8474 e._win = win);
8476 RGFW_dndInitCallback(win, win->event.point);
8477 return NSDragOperationCopy;
8478}
8479bool prepareForDragOperation(id self) {
8480 RGFW_window* win = NULL;
8481 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
8482 if (win == NULL)
8483 return true;
8485 if (!(win->_flags & RGFW_windowAllowDND)) {
8486 return false;
8487 }
8489 return true;
8490}
8492void RGFW__osxDraggingEnded(id self, SEL sel, id sender);
8493void RGFW__osxDraggingEnded(id self, SEL sel, id sender) { RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel); return; }
8495/* NOTE(EimaMei): Usually, you never need 'id self, SEL cmd' for C -> Obj-C methods. This isn't the case. */
8496bool performDragOperation(id self, SEL sel, id sender) {
8497 RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel);
8499 RGFW_window* win = NULL;
8500 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
8502 if (win == NULL)
8503 return false;
8505 /* id pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard")); */
8507 id pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard"));
8509 /* Get the types of data available on the pasteboard */
8510 id types = objc_msgSend_id(pasteBoard, sel_registerName("types"));
8512 /* Get the string type for file URLs */
8513 id fileURLsType = objc_msgSend_class_char(objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "NSFilenamesPboardType");
8515 /* Check if the pasteboard contains file URLs */
8516 if (objc_msgSend_id_bool(types, sel_registerName("containsObject:"), fileURLsType) == 0) {
8517 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errClipboard, RGFW_DEBUG_CTX(win, 0), "No files found on the pasteboard.");
8518 return 0;
8519 }
8521 id fileURLs = objc_msgSend_id_id(pasteBoard, sel_registerName("propertyListForType:"), fileURLsType);
8522 int count = ((int (*)(id, SEL))objc_msgSend)(fileURLs, sel_registerName("count"));
8524 if (count == 0)
8525 return 0;
8527 int i;
8528 for (i = 0; i < count; i++) {
8529 id fileURL = objc_msgSend_arr(fileURLs, sel_registerName("objectAtIndex:"), i);
8530 const char *filePath = ((const char* (*)(id, SEL))objc_msgSend)(fileURL, sel_registerName("UTF8String"));
8531 RGFW_STRNCPY(win->event.droppedFiles[i], filePath, RGFW_MAX_PATH - 1);
8532 win->event.droppedFiles[i][RGFW_MAX_PATH - 1] = '\0';
8533 }
8534 NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation"));
8536 win->event.droppedFilesCount = (size_t)count;
8537 RGFW_eventQueuePushEx(e.type = RGFW_DND;
8538 e.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y));
8539 e.droppedFilesCount = (size_t)count;
8540 e._win = win);
8542 RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount);
8544 return false;
8545}
8547#ifndef RGFW_NO_IOKIT
8548#include <IOKit/IOKitLib.h>
8549#include <IOKit/hid/IOHIDManager.h>
8551u32 RGFW_osx_getFallbackRefreshRate(CGDirectDisplayID displayID) {
8552 u32 refreshRate = 0;
8553 io_iterator_t it;
8554 io_service_t service;
8555 CFNumberRef indexRef, clockRef, countRef;
8556 uint32_t clock, count;
8558#ifdef kIOMainPortDefault
8559 if (IOServiceGetMatchingServices(kIOMainPortDefault, IOServiceMatching("IOFramebuffer"), &it) != 0)
8560#elif defined(kIOMasterPortDefault)
8561 if (IOServiceGetMatchingServices(kIOMainPortDefault, IOServiceMatching("IOFramebuffer"), &it) != 0)
8562#endif
8563 return RGFW_FALSE;
8565 while ((service = IOIteratorNext(it)) != 0) {
8566 uint32_t index;
8567 indexRef = (CFNumberRef)IORegistryEntryCreateCFProperty(service, CFSTR("IOFramebufferOpenGLIndex"), kCFAllocatorDefault, kNilOptions);
8568 if (indexRef == 0) continue;
8570 if (CFNumberGetValue(indexRef, kCFNumberIntType, &index) && CGOpenGLDisplayMaskToDisplayID(1 << index) == displayID) {
8571 CFRelease(indexRef);
8572 break;
8573 }
8575 CFRelease(indexRef);
8576 }
8578 if (service) {
8579 clockRef = (CFNumberRef)IORegistryEntryCreateCFProperty(service, CFSTR("IOFBCurrentPixelClock"), kCFAllocatorDefault, kNilOptions);
8580 if (clockRef) {
8581 if (CFNumberGetValue(clockRef, kCFNumberIntType, &clock) && clock) {
8582 countRef = (CFNumberRef)IORegistryEntryCreateCFProperty(service, CFSTR("IOFBCurrentPixelCount"), kCFAllocatorDefault, kNilOptions);
8583 if (countRef && CFNumberGetValue(countRef, kCFNumberIntType, &count) && count) {
8584 refreshRate = (u32)RGFW_ROUND(clock / (double) count);
8585 CFRelease(countRef);
8586 }
8587 }
8588 CFRelease(clockRef);
8589 }
8590 }
8592 IOObjectRelease(it);
8593 return refreshRate;
8594}
8596IOHIDDeviceRef RGFW_osxControllers[4] = {NULL};
8598size_t findControllerIndex(IOHIDDeviceRef device) {
8599 size_t i;
8600 for (i = 0; i < 4; i++)
8601 if (RGFW_osxControllers[i] == device)
8602 return i;
8603 return (size_t)-1;
8604}
8606void RGFW__osxInputValueChangedCallback(void *context, IOReturn result, void *sender, IOHIDValueRef value) {
8607 RGFW_UNUSED(context); RGFW_UNUSED(result); RGFW_UNUSED(sender);
8608 IOHIDElementRef element = IOHIDValueGetElement(value);
8610 IOHIDDeviceRef device = IOHIDElementGetDevice(element);
8611 size_t index = findControllerIndex(device);
8612 if (index == (size_t)-1) return;
8614 uint32_t usagePage = IOHIDElementGetUsagePage(element);
8615 uint32_t usage = IOHIDElementGetUsage(element);
8617 CFIndex intValue = IOHIDValueGetIntegerValue(value);
8619 u8 RGFW_osx2RGFWSrc[2][RGFW_gamepadFinal] = {{
8620 0, RGFW_gamepadSelect, RGFW_gamepadL3, RGFW_gamepadR3, RGFW_gamepadStart,
8621 RGFW_gamepadUp, RGFW_gamepadRight, RGFW_gamepadDown, RGFW_gamepadLeft,
8622 RGFW_gamepadL2, RGFW_gamepadR2, RGFW_gamepadL1, RGFW_gamepadR1,
8623 RGFW_gamepadY, RGFW_gamepadB, RGFW_gamepadA, RGFW_gamepadX, RGFW_gamepadHome},
8624 {0, RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadR3, RGFW_gamepadX,
8625 RGFW_gamepadY, RGFW_gamepadRight, RGFW_gamepadL1, RGFW_gamepadR1,
8626 RGFW_gamepadL2, RGFW_gamepadR2, RGFW_gamepadDown, RGFW_gamepadStart,
8627 RGFW_gamepadUp, RGFW_gamepadL3, RGFW_gamepadSelect, RGFW_gamepadStart, RGFW_gamepadHome}
8628 };
8630 u8* RGFW_osx2RGFW = RGFW_osx2RGFWSrc[0];
8631 if (RGFW_gamepads_type[index] == RGFW_gamepadMicrosoft)
8632 RGFW_osx2RGFW = RGFW_osx2RGFWSrc[1];
8634 switch (usagePage) {
8635 case kHIDPage_Button: {
8636 u8 button = 0;
8637 if (usage < sizeof(RGFW_osx2RGFW))
8638 button = RGFW_osx2RGFW[usage];
8640 RGFW_gamepadButtonCallback(_RGFW.root, (u16)index, button, (u8)intValue);
8641 RGFW_gamepadPressed[index][button].prev = RGFW_gamepadPressed[index][button].current;
8642 RGFW_gamepadPressed[index][button].current = RGFW_BOOL(intValue);
8643 RGFW_eventQueuePushEx(e.type = intValue ? RGFW_gamepadButtonPressed: RGFW_gamepadButtonReleased;
8644 e.button = button;
8645 e.gamepad = (u16)index;
8646 e._win = _RGFW.root);
8647 break;
8648 }
8649 case kHIDPage_GenericDesktop: {
8650 CFIndex logicalMin = IOHIDElementGetLogicalMin(element);
8651 CFIndex logicalMax = IOHIDElementGetLogicalMax(element);
8653 if (logicalMax <= logicalMin) return;
8654 if (intValue < logicalMin) intValue = logicalMin;
8655 if (intValue > logicalMax) intValue = logicalMax;
8657 i8 axisValue = (i8)(-100.0 + ((intValue - logicalMin) * 200.0) / (logicalMax - logicalMin));
8659 u8 whichAxis = 0;
8660 switch (usage) {
8661 case kHIDUsage_GD_X: RGFW_gamepadAxes[index][0].x = axisValue; whichAxis = 0; break;
8662 case kHIDUsage_GD_Y: RGFW_gamepadAxes[index][0].y = axisValue; whichAxis = 0; break;
8663 case kHIDUsage_GD_Z: RGFW_gamepadAxes[index][1].x = axisValue; whichAxis = 1; break;
8664 case kHIDUsage_GD_Rz: RGFW_gamepadAxes[index][1].y = axisValue; whichAxis = 1; break;
8665 default: return;
8666 }
8668 RGFW_event e;
8669 e.type = RGFW_gamepadAxisMove;
8670 e.gamepad = (u16)index;
8671 e.whichAxis = whichAxis;
8672 e._win = _RGFW.root;
8673 for (size_t i = 0; i < 4; i++)
8674 e.axis[i] = RGFW_gamepadAxes[index][i];
8676 RGFW_eventQueuePush(e);
8678 RGFW_gamepadAxisCallback(_RGFW.root, (u16)index, RGFW_gamepadAxes[index], 2, whichAxis);
8679 }
8680 }
8681}
8683void RGFW__osxDeviceAddedCallback(void* context, IOReturn result, void *sender, IOHIDDeviceRef device) {
8684 RGFW_UNUSED(context); RGFW_UNUSED(result); RGFW_UNUSED(sender);
8685 CFTypeRef usageRef = (CFTypeRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDPrimaryUsageKey));
8686 int usage = 0;
8687 if (usageRef)
8688 CFNumberGetValue((CFNumberRef)usageRef, kCFNumberIntType, (void*)&usage);
8690 if (usage != kHIDUsage_GD_Joystick && usage != kHIDUsage_GD_GamePad && usage != kHIDUsage_GD_MultiAxisController) {
8691 return;
8692 }
8694 size_t i;
8695 for (i = 0; i < 4; i++) {
8696 if (RGFW_osxControllers[i] != NULL)
8697 continue;
8699 RGFW_osxControllers[i] = device;
8701 IOHIDDeviceRegisterInputValueCallback(device, RGFW__osxInputValueChangedCallback, NULL);
8703 CFStringRef deviceName = (CFStringRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
8704 if (deviceName)
8705 CFStringGetCString(deviceName, RGFW_gamepads_name[i], sizeof(RGFW_gamepads_name[i]), kCFStringEncodingUTF8);
8707 RGFW_gamepads_type[i] = RGFW_gamepadUnknown;
8708 if (RGFW_STRSTR(RGFW_gamepads_name[i], "Microsoft") || RGFW_STRSTR(RGFW_gamepads_name[i], "X-Box") || RGFW_STRSTR(RGFW_gamepads_name[i], "Xbox"))
8709 RGFW_gamepads_type[i] = RGFW_gamepadMicrosoft;
8710 else if (RGFW_STRSTR(RGFW_gamepads_name[i], "PlayStation") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS3") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS4") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS5"))
8711 RGFW_gamepads_type[i] = RGFW_gamepadSony;
8712 else if (RGFW_STRSTR(RGFW_gamepads_name[i], "Nintendo"))
8713 RGFW_gamepads_type[i] = RGFW_gamepadNintendo;
8714 else if (RGFW_STRSTR(RGFW_gamepads_name[i], "Logitech"))
8715 RGFW_gamepads_type[i] = RGFW_gamepadLogitech;
8717 RGFW_gamepads[i] = (u16)i;
8718 RGFW_gamepadCount++;
8720 RGFW_eventQueuePushEx(e.type = RGFW_gamepadConnected;
8721 e.gamepad = (u16)i;
8722 e._win = _RGFW.root);
8724 RGFW_gamepadCallback(_RGFW.root, (u16)i, 1);
8725 break;
8726 }
8727}
8729void RGFW__osxDeviceRemovedCallback(void *context, IOReturn result, void *sender, IOHIDDeviceRef device) {
8730 RGFW_UNUSED(context); RGFW_UNUSED(result); RGFW_UNUSED(sender); RGFW_UNUSED(device);
8731 CFNumberRef usageRef = (CFNumberRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDPrimaryUsageKey));
8732 int usage = 0;
8733 if (usageRef)
8734 CFNumberGetValue(usageRef, kCFNumberIntType, &usage);
8736 if (usage != kHIDUsage_GD_Joystick && usage != kHIDUsage_GD_GamePad && usage != kHIDUsage_GD_MultiAxisController) {
8737 return;
8738 }
8740 size_t index = findControllerIndex(device);
8741 if (index != (size_t)-1)
8742 RGFW_osxControllers[index] = NULL;
8744 RGFW_eventQueuePushEx(e.type = RGFW_gamepadDisconnected;
8745 e.gamepad = (u16)index;
8746 e._win = _RGFW.root);
8747 RGFW_gamepadCallback(_RGFW.root, (u16)index, 0);
8749 RGFW_gamepadCount--;
8750}
8752RGFWDEF void RGFW_osxInitIOKit(void);
8753void RGFW_osxInitIOKit(void) {
8754 IOHIDManagerRef hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
8755 if (!hidManager) {
8756 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errIOKit, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to create IOHIDManager.");
8757 return;
8758 }
8760 CFMutableDictionaryRef matchingDictionary = CFDictionaryCreateMutable(
8761 kCFAllocatorDefault,
8762 0,
8763 &kCFTypeDictionaryKeyCallBacks,
8764 &kCFTypeDictionaryValueCallBacks
8765 );
8766 if (!matchingDictionary) {
8767 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errIOKit, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to create matching dictionary for IOKit.");
8768 CFRelease(hidManager);
8769 return;
8770 }
8772 CFDictionarySetValue(
8773 matchingDictionary,
8774 CFSTR(kIOHIDDeviceUsagePageKey),
8775 CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, (int[]){kHIDPage_GenericDesktop})
8776 );
8778 IOHIDManagerSetDeviceMatching(hidManager, matchingDictionary);
8780 IOHIDManagerRegisterDeviceMatchingCallback(hidManager, RGFW__osxDeviceAddedCallback, NULL);
8781 IOHIDManagerRegisterDeviceRemovalCallback(hidManager, RGFW__osxDeviceRemovedCallback, NULL);
8783 IOHIDManagerScheduleWithRunLoop(hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
8785 IOHIDManagerOpen(hidManager, kIOHIDOptionsTypeNone);
8787 /* Execute the run loop once in order to register any initially-attached joysticks */
8788 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false);
8789}
8790#endif
8792void RGFW_moveToMacOSResourceDir(void) {
8793 char resourcesPath[256];
8795 CFBundleRef bundle = CFBundleGetMainBundle();
8796 if (!bundle)
8797 return;
8799 CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle);
8800 CFStringRef last = CFURLCopyLastPathComponent(resourcesURL);
8802 if (
8803 CFStringCompare(CFSTR("Resources"), last, 0) != kCFCompareEqualTo ||
8804 CFURLGetFileSystemRepresentation(resourcesURL, true, (u8*) resourcesPath, 255) == 0
8805 ) {
8806 CFRelease(last);
8807 CFRelease(resourcesURL);
8808 return;
8809 }
8811 CFRelease(last);
8812 CFRelease(resourcesURL);
8814 chdir(resourcesPath);
8815}
8818void RGFW__osxWindowDeminiaturize(id self, SEL sel) {
8819 RGFW_UNUSED(sel);
8820 RGFW_window* win = NULL;
8821 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
8822 if (win == NULL) return;
8824 win->_flags |= RGFW_windowMinimize;
8825 RGFW_eventQueuePushEx(e.type = RGFW_windowRestored; e._win = win);
8826 RGFW_windowRestoredCallback(win, win->r);
8828}
8829void RGFW__osxWindowMiniaturize(id self, SEL sel) {
8830 RGFW_UNUSED(sel);
8831 RGFW_window* win = NULL;
8832 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
8833 if (win == NULL) return;
8835 win->_flags &= ~(u32)RGFW_windowMinimize;
8836 RGFW_eventQueuePushEx(e.type = RGFW_windowMinimized; e._win = win);
8837 RGFW_windowMinimizedCallback(win, win->r);
8839}
8841void RGFW__osxWindowBecameKey(id self, SEL sel) {
8842 RGFW_UNUSED(sel);
8843 RGFW_window* win = NULL;
8844 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
8845 if (win == NULL) return;
8847 win->_flags |= RGFW_windowFocus;
8848 RGFW_eventQueuePushEx(e.type = RGFW_focusIn; e._win = win);
8850 RGFW_focusCallback(win, RGFW_TRUE);
8852 if ((win->_flags & RGFW_HOLD_MOUSE)) RGFW_window_mouseHold(win, RGFW_AREA(win->r.w, win->r.h));
8853}
8855void RGFW__osxWindowResignKey(id self, SEL sel) {
8856 RGFW_UNUSED(sel);
8857 RGFW_window* win = NULL;
8858 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
8859 if (win == NULL) return;
8861 RGFW_window_focusLost(win);
8862 RGFW_eventQueuePushEx(e.type = RGFW_focusOut; e._win = win);
8863 RGFW_focusCallback(win, RGFW_FALSE);
8864}
8866NSSize RGFW__osxWindowResize(id self, SEL sel, NSSize frameSize) {
8867 RGFW_UNUSED(sel);
8869 RGFW_window* win = NULL;
8870 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
8871 if (win == NULL) return frameSize;
8873 win->r.w = (i32)frameSize.width;
8874 win->r.h = (i32)frameSize.height;
8876 RGFW_monitor mon = RGFW_window_getMonitor(win);
8877 if ((i32)mon.mode.area.w == win->r.w && (i32)mon.mode.area.h - 102 <= win->r.h) {
8878 win->_flags |= RGFW_windowMaximize;
8879 RGFW_eventQueuePushEx(e.type = RGFW_windowMaximized; e._win = win);
8880 RGFW_windowMaximizedCallback(win, win->r);
8881 } else if (win->_flags & RGFW_windowMaximize) {
8882 win->_flags &= ~(u32)RGFW_windowMaximize;
8883 RGFW_eventQueuePushEx(e.type = RGFW_windowRestored; e._win = win);
8884 RGFW_windowRestoredCallback(win, win->r);
8886 }
8889 RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e._win = win);
8890 RGFW_windowResizedCallback(win, win->r);
8891 return frameSize;
8892}
8894void RGFW__osxWindowMove(id self, SEL sel) {
8895 RGFW_UNUSED(sel);
8897 RGFW_window* win = NULL;
8898 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
8899 if (win == NULL) return;
8901 NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame"));
8902 win->r.x = (i32) frame.origin.x;
8903 win->r.y = (i32) frame.origin.y;
8905 RGFW_eventQueuePushEx(e.type = RGFW_windowMoved; e._win = win);
8906 RGFW_windowMovedCallback(win, win->r);
8907}
8909void RGFW__osxViewDidChangeBackingProperties(id self, SEL _cmd) {
8910 RGFW_UNUSED(_cmd);
8911 RGFW_window* win = NULL;
8912 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
8913 if (win == NULL) return;
8915 RGFW_monitor mon = RGFW_window_getMonitor(win);
8916 RGFW_scaleUpdatedCallback(win, mon.scaleX, mon.scaleY);
8917 RGFW_eventQueuePushEx(e.type = RGFW_scaleUpdated; e.scaleX = mon.scaleX; e.scaleY = mon.scaleY ; e._win = win);
8918}
8920void RGFW__osxDrawRect(id self, SEL _cmd, CGRect rect) {
8921 RGFW_UNUSED(rect); RGFW_UNUSED(_cmd);
8922 RGFW_window* win = NULL;
8923 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
8924 if (win == NULL) return;
8926 RGFW_eventQueuePushEx(e.type = RGFW_windowRefresh; e._win = win);
8927 RGFW_windowRefreshCallback(win);
8928}
8930void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area) {
8931 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
8932 win->buffer = buffer;
8933 win->bufferSize = area;
8934 win->_flags |= RGFW_BUFFER_ALLOC;
8935 #ifdef RGFW_OSMESA
8936 win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL);
8937 OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h);
8938 OSMesaPixelStore(OSMESA_Y_UP, 0);
8939 #endif
8940 #else
8941 RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area); /*!< if buffer rendering is not being used */
8942 #endif
8943}
8945void RGFW_window_cocoaSetLayer(RGFW_window* win, void* layer) {
8946 objc_msgSend_void_id((id)win->src.view, sel_registerName("setLayer"), (id)layer);
8947}
8949void* RGFW_cocoaGetLayer(void) {
8950 return objc_msgSend_class((id)objc_getClass("CAMetalLayer"), (SEL)sel_registerName("layer"));
8951}
8953NSPasteboardType const NSPasteboardTypeURL = "public.url";
8954NSPasteboardType const NSPasteboardTypeFileURL = "public.file-url";
8956id RGFW__osx_generateViewClass(const char* subclass, RGFW_window* win) {
8957 Class customViewClass;
8958 customViewClass = objc_allocateClassPair(objc_getClass(subclass), "RGFWCustomView", 0);
8960 class_addIvar( customViewClass, "RGFW_window", sizeof(RGFW_window*), (u8)rint(log2(sizeof(RGFW_window*))), "L");
8961 class_addMethod(customViewClass, sel_registerName("drawRect:"), (IMP)RGFW__osxDrawRect, "v@:{CGRect=ffff}");
8962 class_addMethod(customViewClass, sel_registerName("viewDidChangeBackingProperties"), (IMP)RGFW__osxViewDidChangeBackingProperties, "");
8964 id customView = objc_msgSend_id(NSAlloc(customViewClass), sel_registerName("init"));
8965 object_setInstanceVariable(customView, "RGFW_window", win);
8967 return customView;
8968}
8970#ifndef RGFW_EGL
8971void RGFW_window_initOpenGL(RGFW_window* win) {
8972#ifdef RGFW_OPENGL
8973 void* attrs = RGFW_initFormatAttribs();
8974 void* format = NSOpenGLPixelFormat_initWithAttributes((uint32_t*)attrs);
8976 if (format == NULL) {
8977 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to load pixel format for OpenGL");
8978 win->_flags |= RGFW_windowOpenglSoftware;
8979 void* subAttrs = RGFW_initFormatAttribs();
8980 format = NSOpenGLPixelFormat_initWithAttributes((uint32_t*)subAttrs);
8982 if (format == NULL)
8983 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "and loading software rendering OpenGL failed");
8984 else
8985 RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, RGFW_DEBUG_CTX(win, 0), "Switching to software rendering");
8986 }
8988 /* the pixel format can be passed directly to opengl context creation to create a context
8989 this is because the format also includes information about the opengl version (which may be a bad thing) */
8991 win->src.view = (id) ((id(*)(id, SEL, NSRect, uint32_t*))objc_msgSend) (RGFW__osx_generateViewClass("NSOpenGLView", win),
8992 sel_registerName("initWithFrame:pixelFormat:"), (NSRect){{0, 0}, {win->r.w, win->r.h}}, (uint32_t*)format);
8994 objc_msgSend_void(win->src.view, sel_registerName("prepareOpenGL"));
8995 win->src.ctx = objc_msgSend_id(win->src.view, sel_registerName("openGLContext"));
8997 if (win->_flags & RGFW_windowTransparent) {
8998 i32 opacity = 0;
8999 #define NSOpenGLCPSurfaceOpacity 236
9000 NSOpenGLContext_setValues((id)win->src.ctx, &opacity, NSOpenGLCPSurfaceOpacity);
9001 }
9003 objc_msgSend_void(win->src.ctx, sel_registerName("makeCurrentContext"));
9004 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context initalized");
9005#else
9006 RGFW_UNUSED(win);
9007#endif
9008}
9010void RGFW_window_freeOpenGL(RGFW_window* win) {
9011#ifdef RGFW_OPENGL
9012 if (win->src.ctx == NULL) return;
9013 objc_msgSend_void(win->src.ctx, sel_registerName("release"));
9014 win->src.ctx = NULL;
9015 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context freed");
9016#else
9017 RGFW_UNUSED(win);
9018#endif
9019}
9020#endif
9023i32 RGFW_init(void) {
9024#if defined(RGFW_C89) || defined(__cplusplus)
9025 if (_RGFW_init) return 0;
9026 _RGFW_init = RGFW_TRUE;
9027 _RGFW.root = NULL; _RGFW.current = NULL; _RGFW.windowCount = -1; _RGFW.eventLen = 0; _RGFW.eventIndex = 0;
9028#endif
9030 /* NOTE(EimaMei): Why does Apple hate good code? Like wtf, who thought of methods being a great idea???
9031 Imagine a universe, where MacOS had a proper system API (we would probably have like 20% better performance).
9032 */
9033 si_func_to_SEL_with_name("NSObject", "windowShouldClose", (void*)RGFW_OnClose);
9035 /* NOTE(EimaMei): Fixes the 'Boop' sfx from constantly playing each time you click a key. Only a problem when running in the terminal. */
9036 si_func_to_SEL("NSWindow", acceptsFirstResponder);
9037 si_func_to_SEL("NSWindow", performKeyEquivalent);
9039 if (NSApp == NULL) {
9040 NSApp = objc_msgSend_id((id)objc_getClass("NSApplication"), sel_registerName("sharedApplication"));
9042 ((void (*)(id, SEL, NSUInteger))objc_msgSend)
9043 (NSApp, sel_registerName("setActivationPolicy:"), NSApplicationActivationPolicyRegular);
9045 #ifndef RGFW_NO_IOKIT
9046 RGFW_osxInitIOKit();
9047 #endif
9048 }
9050 _RGFW.windowCount = 0;
9051 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context initialized");
9052 return 0;
9053}
9055RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) {
9056 static u8 RGFW_loaded = 0;
9057 RGFW_window_basic_init(win, rect, flags);
9059 /* RR Create an autorelease pool */
9060 id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
9061 pool = objc_msgSend_id(pool, sel_registerName("init"));
9063 RGFW_window_setMouseDefault(win);
9065 NSRect windowRect;
9066 windowRect.origin.x = win->r.x;
9067 windowRect.origin.y = win->r.y;
9068 windowRect.size.width = win->r.w;
9069 windowRect.size.height = win->r.h;
9071 NSBackingStoreType macArgs = NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSBackingStoreBuffered | NSWindowStyleMaskTitled;
9073 if (!(flags & RGFW_windowNoResize))
9074 macArgs |= NSWindowStyleMaskResizable;
9075 if (!(flags & RGFW_windowNoBorder))
9076 macArgs |= NSWindowStyleMaskTitled;
9077 {
9078 void* nsclass = objc_getClass("NSWindow");
9079 SEL func = sel_registerName("initWithContentRect:styleMask:backing:defer:");
9081 win->src.window = ((id(*)(id, SEL, NSRect, NSWindowStyleMask, NSBackingStoreType, bool))objc_msgSend)
9082 (NSAlloc(nsclass), func, windowRect, macArgs, macArgs, false);
9083 }
9085 id str = NSString_stringWithUTF8String(name);
9086 objc_msgSend_void_id((id)win->src.window, sel_registerName("setTitle:"), str);
9088 if ((flags & RGFW_windowNoInitAPI) == 0) {
9089 RGFW_window_initOpenGL(win);
9090 RGFW_window_initBuffer(win);
9091 }
9093 #ifdef RGFW_OPENGL
9094 else
9095 #endif
9096 {
9097 NSRect contentRect = (NSRect){{0, 0}, {win->r.w, win->r.h}};
9098 win->src.view = ((id(*)(id, SEL, NSRect))objc_msgSend) (NSAlloc(objc_getClass("NSView")), sel_registerName("initWithFrame:"), contentRect);
9099 }
9101 void* contentView = NSWindow_contentView((id)win->src.window);
9102 objc_msgSend_void_bool(contentView, sel_registerName("setWantsLayer:"), true);
9103 objc_msgSend_int((id)win->src.view, sel_registerName("setLayerContentsPlacement:"), 4);
9104 objc_msgSend_void_id((id)win->src.window, sel_registerName("setContentView:"), win->src.view);
9106 if (flags & RGFW_windowTransparent) {
9107 objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), false);
9109 objc_msgSend_void_id((id)win->src.window, sel_registerName("setBackgroundColor:"),
9110 NSColor_colorWithSRGB(0, 0, 0, 0));
9111 }
9113 Class delegateClass = objc_allocateClassPair(objc_getClass("NSObject"), "WindowDelegate", 0);
9115 class_addIvar(
9116 delegateClass, "RGFW_window",
9117 sizeof(RGFW_window*), (u8)rint(log2(sizeof(RGFW_window*))),
9118 "L"
9119 );
9121 class_addMethod(delegateClass, sel_registerName("windowWillResize:toSize:"), (IMP) RGFW__osxWindowResize, "{NSSize=ff}@:{NSSize=ff}");
9122 class_addMethod(delegateClass, sel_registerName("windowWillMove:"), (IMP) RGFW__osxWindowMove, "");
9123 class_addMethod(delegateClass, sel_registerName("windowDidMove:"), (IMP) RGFW__osxWindowMove, "");
9124 class_addMethod(delegateClass, sel_registerName("windowDidMiniaturize:"), (IMP) RGFW__osxWindowMiniaturize, "");
9125 class_addMethod(delegateClass, sel_registerName("windowDidDeminiaturize:"), (IMP) RGFW__osxWindowDeminiaturize, "");
9126 class_addMethod(delegateClass, sel_registerName("windowDidBecomeKey:"), (IMP) RGFW__osxWindowBecameKey, "");
9127 class_addMethod(delegateClass, sel_registerName("windowDidResignKey:"), (IMP) RGFW__osxWindowResignKey, "");
9128 class_addMethod(delegateClass, sel_registerName("draggingEntered:"), (IMP)draggingEntered, "l@:@");
9129 class_addMethod(delegateClass, sel_registerName("draggingUpdated:"), (IMP)draggingUpdated, "l@:@");
9130 class_addMethod(delegateClass, sel_registerName("draggingExited:"), (IMP)RGFW__osxDraggingEnded, "v@:@");
9131 class_addMethod(delegateClass, sel_registerName("draggingEnded:"), (IMP)RGFW__osxDraggingEnded, "v@:@");
9132 class_addMethod(delegateClass, sel_registerName("prepareForDragOperation:"), (IMP)prepareForDragOperation, "B@:@");
9133 class_addMethod(delegateClass, sel_registerName("performDragOperation:"), (IMP)performDragOperation, "B@:@");
9135 id delegate = objc_msgSend_id(NSAlloc(delegateClass), sel_registerName("init"));
9137 if (RGFW_COCOA_FRAME_NAME)
9138 objc_msgSend_ptr(win->src.view, sel_registerName("setFrameAutosaveName:"), RGFW_COCOA_FRAME_NAME);
9140 object_setInstanceVariable(delegate, "RGFW_window", win);
9142 objc_msgSend_void_id((id)win->src.window, sel_registerName("setDelegate:"), delegate);
9144 if (flags & RGFW_windowAllowDND) {
9145 win->_flags |= RGFW_windowAllowDND;
9147 NSPasteboardType types[] = {NSPasteboardTypeURL, NSPasteboardTypeFileURL, NSPasteboardTypeString};
9148 NSregisterForDraggedTypes((id)win->src.window, types, 3);
9149 }
9151 RGFW_window_setFlags(win, flags);
9153 /* Show the window */
9154 objc_msgSend_void_bool(NSApp, sel_registerName("activateIgnoringOtherApps:"), true);
9155 ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("makeKeyAndOrderFront:"), NULL);
9156 RGFW_window_show(win);
9158 if (!RGFW_loaded) {
9159 objc_msgSend_void(win->src.window, sel_registerName("makeMainWindow"));
9161 RGFW_loaded = 1;
9162 }
9164 objc_msgSend_void(win->src.window, sel_registerName("makeKeyWindow"));
9166 objc_msgSend_void(NSApp, sel_registerName("finishLaunching"));
9167 NSRetain(win->src.window);
9168 NSRetain(NSApp);
9170 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created");
9171 return win;
9172}
9174void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) {
9175 NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame"));
9176 NSRect content = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame"));
9177 float offset = 0;
9179 RGFW_setBit(&win->_flags, RGFW_windowNoBorder, !border);
9180 NSBackingStoreType storeType = NSWindowStyleMaskBorderless | NSWindowStyleMaskFullSizeContentView;
9181 if (border)
9182 storeType = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable;
9183 if (!(win->_flags & RGFW_windowNoResize)) {
9184 storeType |= NSWindowStyleMaskResizable;
9185 }
9187 ((void (*)(id, SEL, NSBackingStoreType))objc_msgSend)((id)win->src.window, sel_registerName("setStyleMask:"), storeType);
9189 if (!border) {
9190 id miniaturizeButton = objc_msgSend_int((id)win->src.window, sel_registerName("standardWindowButton:"), NSWindowMiniaturizeButton);
9191 id titleBarView = objc_msgSend_id(miniaturizeButton, sel_registerName("superview"));
9192 objc_msgSend_void_bool(titleBarView, sel_registerName("setHidden:"), true);
9194 offset = (float)(frame.size.height - content.size.height);
9195 }
9197 RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h + offset));
9198 win->r.h -= (i32)offset;
9199}
9201RGFW_area RGFW_getScreenSize(void) {
9202 static CGDirectDisplayID display = 0;
9204 if (display == 0)
9205 display = CGMainDisplayID();
9207 return RGFW_AREA(CGDisplayPixelsWide(display), CGDisplayPixelsHigh(display));
9208}
9210RGFW_point RGFW_getGlobalMousePoint(void) {
9211 RGFW_ASSERT(_RGFW.root != NULL);
9213 CGEventRef e = CGEventCreate(NULL);
9214 CGPoint point = CGEventGetLocation(e);
9215 CFRelease(e);
9217 return RGFW_POINT((u32) point.x, (u32) point.y); /*!< the point is loaded during event checks */
9218}
9220typedef RGFW_ENUM(u32, NSEventType) { /* various types of events */
9221 NSEventTypeLeftMouseDown = 1,
9222 NSEventTypeLeftMouseUp = 2,
9223 NSEventTypeRightMouseDown = 3,
9224 NSEventTypeRightMouseUp = 4,
9225 NSEventTypeMouseMoved = 5,
9226 NSEventTypeLeftMouseDragged = 6,
9227 NSEventTypeRightMouseDragged = 7,
9228 NSEventTypeMouseEntered = 8,
9229 NSEventTypeMouseExited = 9,
9230 NSEventTypeKeyDown = 10,
9231 NSEventTypeKeyUp = 11,
9232 NSEventTypeFlagsChanged = 12,
9233 NSEventTypeAppKitDefined = 13,
9234 NSEventTypeSystemDefined = 14,
9235 NSEventTypeApplicationDefined = 15,
9236 NSEventTypePeriodic = 16,
9237 NSEventTypeCursorUpdate = 17,
9238 NSEventTypeScrollWheel = 22,
9239 NSEventTypeTabletPoint = 23,
9240 NSEventTypeTabletProximity = 24,
9241 NSEventTypeOtherMouseDown = 25,
9242 NSEventTypeOtherMouseUp = 26,
9243 NSEventTypeOtherMouseDragged = 27,
9244 /* The following event types are available on some hardware on 10.5.2 and later */
9245 NSEventTypeGesture = 29,
9246 NSEventTypeMagnify = 30,
9247 NSEventTypeSwipe = 31,
9248 NSEventTypeRotate = 18,
9249 NSEventTypeBeginGesture = 19,
9250 NSEventTypeEndGesture = 20,
9252 NSEventTypeSmartMagnify = 32,
9253 NSEventTypeQuickLook = 33,
9255 NSEventTypePressure = 34,
9256 NSEventTypeDirectTouch = 37,
9258 NSEventTypeChangeMode = 38,
9259};
9261typedef unsigned long long NSEventMask;
9263typedef enum NSEventModifierFlags {
9264 NSEventModifierFlagCapsLock = 1 << 16,
9265 NSEventModifierFlagShift = 1 << 17,
9266 NSEventModifierFlagControl = 1 << 18,
9267 NSEventModifierFlagOption = 1 << 19,
9268 NSEventModifierFlagCommand = 1 << 20,
9269 NSEventModifierFlagNumericPad = 1 << 21
9270} NSEventModifierFlags;
9272void RGFW_stopCheckEvents(void) {
9273 id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
9274 eventPool = objc_msgSend_id(eventPool, sel_registerName("init"));
9276 id e = (id) ((id(*)(Class, SEL, NSEventType, NSPoint, NSEventModifierFlags, void*, NSInteger, void**, short, NSInteger, NSInteger))objc_msgSend)
9277 (objc_getClass("NSEvent"), sel_registerName("otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:"),
9278 NSEventTypeApplicationDefined, (NSPoint){0, 0}, (NSEventModifierFlags)0, NULL, (NSInteger)0, NULL, 0, 0, 0);
9280 ((void (*)(id, SEL, id, bool))objc_msgSend)
9281 (NSApp, sel_registerName("postEvent:atStart:"), e, 1);
9283 objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
9284}
9286void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) {
9287 RGFW_UNUSED(win);
9289 id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
9290 eventPool = objc_msgSend_id(eventPool, sel_registerName("init"));
9292 void* date = (void*) ((id(*)(Class, SEL, double))objc_msgSend)
9293 (objc_getClass("NSDate"), sel_registerName("dateWithTimeIntervalSinceNow:"), waitMS);
9295 SEL eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:");
9296 id e = (id) ((id(*)(id, SEL, NSEventMask, void*, id, bool))objc_msgSend)
9297 (NSApp, eventFunc,
9298 ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true);
9300 if (e) {
9301 ((void (*)(id, SEL, id, bool))objc_msgSend)
9302 (NSApp, sel_registerName("postEvent:atStart:"), e, 1);
9303 }
9305 objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
9306}
9308u8 RGFW_rgfwToKeyChar(u32 rgfw_keycode) {
9309 return (u8)rgfw_keycode; /* TODO */
9310}
9312RGFW_event* RGFW_window_checkEvent(RGFW_window* win) {
9313 if (win == NULL || ((win->_flags & RGFW_windowFreeOnClose) && (win->_flags & RGFW_EVENT_QUIT))) return NULL;
9315 objc_msgSend_void((id)win->src.mouse, sel_registerName("set"));
9316 RGFW_event* ev = RGFW_window_checkEventCore(win);
9317 if (ev) {
9318 ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows"));
9319 return ev;
9320 }
9322 id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
9323 eventPool = objc_msgSend_id(eventPool, sel_registerName("init"));
9325 SEL eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:");
9327 void* date = NULL;
9329 id e = (id) ((id(*)(id, SEL, NSEventMask, void*, id, bool))objc_msgSend)
9330 (NSApp, eventFunc, ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true);
9332 if (e == NULL) {
9333 objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
9334 objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e);
9335 ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows"));
9336 return NULL;
9337 }
9339 if (objc_msgSend_id(e, sel_registerName("window")) != win->src.window) {
9340 ((void (*)(id, SEL, id, bool))objc_msgSend)
9341 (NSApp, sel_registerName("postEvent:atStart:"), e, 0);
9343 objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e);
9344 objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
9345 ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows"));
9346 return NULL;
9347 }
9349 if (win->event.droppedFilesCount) {
9350 u32 i;
9351 for (i = 0; i < win->event.droppedFilesCount; i++)
9352 win->event.droppedFiles[i][0] = '\0';
9353 }
9355 win->event.droppedFilesCount = 0;
9356 win->event.type = 0;
9358 u32 type = (u32)objc_msgSend_uint(e, sel_registerName("type"));
9359 switch (type) {
9360 case NSEventTypeMouseEntered: {
9361 win->event.type = RGFW_mouseEnter;
9362 NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow"));
9364 win->event.point = RGFW_POINT((i32) p.x, (i32) (win->r.h - p.y));
9365 RGFW_mouseNotifyCallback(win, win->event.point, 1);
9366 break;
9367 }
9369 case NSEventTypeMouseExited:
9370 win->event.type = RGFW_mouseLeave;
9371 RGFW_mouseNotifyCallback(win, win->event.point, 0);
9372 break;
9374 case NSEventTypeKeyDown: {
9375 u32 key = (u16) objc_msgSend_uint(e, sel_registerName("keyCode"));
9377 u32 mappedKey = (u32)*(((char*)(const char*) NSString_to_char(objc_msgSend_id(e, sel_registerName("charactersIgnoringModifiers")))));
9378 if (((u8)mappedKey) == 239)
9379 mappedKey = 0;
9381 win->event.keyChar = (u8)mappedKey;
9383 win->event.key = (u8)RGFW_apiKeyToRGFW(key);
9384 RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current;
9386 win->event.type = RGFW_keyPressed;
9387 win->event.repeat = RGFW_isPressed(win, win->event.key);
9388 RGFW_keyboard[win->event.key].current = 1;
9390 RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 1);
9391 break;
9392 }
9394 case NSEventTypeKeyUp: {
9395 u32 key = (u16) objc_msgSend_uint(e, sel_registerName("keyCode"));
9396 u32 mappedKey = (u32)*(((char*)(const char*) NSString_to_char(objc_msgSend_id(e, sel_registerName("charactersIgnoringModifiers")))));
9397 if (((u8)mappedKey) == 239)
9398 mappedKey = 0;
9400 win->event.keyChar = (u8)mappedKey;
9402 win->event.key = (u8)RGFW_apiKeyToRGFW(key);
9404 RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current;
9406 win->event.type = RGFW_keyReleased;
9408 RGFW_keyboard[win->event.key].current = 0;
9409 RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 0);
9410 break;
9411 }
9413 case NSEventTypeFlagsChanged: {
9414 u32 flags = (u32)objc_msgSend_uint(e, sel_registerName("modifierFlags"));
9415 RGFW_updateKeyModsPro(win, ((u32)(flags & NSEventModifierFlagCapsLock) % 255), ((flags & NSEventModifierFlagNumericPad) % 255),
9416 ((flags & NSEventModifierFlagControl) % 255), ((flags & NSEventModifierFlagOption) % 255),
9417 ((flags & NSEventModifierFlagShift) % 255), ((flags & NSEventModifierFlagCommand) % 255), 0);
9418 u8 i;
9419 for (i = 0; i < 9; i++)
9420 RGFW_keyboard[i + RGFW_capsLock].prev = 0;
9422 for (i = 0; i < 5; i++) {
9423 u32 shift = (1 << (i + 16));
9424 u32 key = i + RGFW_capsLock;
9426 if ((flags & shift) && !RGFW_wasPressed(win, (u8)key)) {
9427 RGFW_keyboard[key].current = 1;
9429 if (key != RGFW_capsLock)
9430 RGFW_keyboard[key+ 4].current = 1;
9432 win->event.type = RGFW_keyPressed;
9433 win->event.key = (u8)key;
9434 break;
9435 }
9437 if (!(flags & shift) && RGFW_wasPressed(win, (u8)key)) {
9438 RGFW_keyboard[key].current = 0;
9440 if (key != RGFW_capsLock)
9441 RGFW_keyboard[key + 4].current = 0;
9443 win->event.type = RGFW_keyReleased;
9444 win->event.key = (u8)key;
9445 break;
9446 }
9447 }
9449 RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, win->event.type == RGFW_keyPressed);
9451 break;
9452 }
9453 case NSEventTypeLeftMouseDragged:
9454 case NSEventTypeOtherMouseDragged:
9455 case NSEventTypeRightMouseDragged:
9456 case NSEventTypeMouseMoved: {
9457 win->event.type = RGFW_mousePosChanged;
9458 NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow"));
9459 win->event.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y));
9461 p.x = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaX"));
9462 p.y = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaY"));
9463 win->event.vector = RGFW_POINT((i32)p.x, (i32)p.y);
9465 win->_lastMousePoint = win->event.point;
9466 RGFW_mousePosCallback(win, win->event.point, win->event.vector);
9467 break;
9468 }
9469 case NSEventTypeLeftMouseDown: case NSEventTypeRightMouseDown: case NSEventTypeOtherMouseDown: {
9470 u32 buttonNumber = (u32)objc_msgSend_uint(e, sel_registerName("buttonNumber"));
9471 switch (buttonNumber) {
9472 case 0: win->event.button = RGFW_mouseLeft; break;
9473 case 1: win->event.button = RGFW_mouseRight; break;
9474 case 2: win->event.button = RGFW_mouseMiddle; break;
9475 default: win->event.button = (u8)buttonNumber;
9476 }
9478 win->event.type = RGFW_mouseButtonPressed;
9479 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
9480 RGFW_mouseButtons[win->event.button].current = 1;
9481 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
9482 break;
9483 }
9484 case NSEventTypeLeftMouseUp: case NSEventTypeRightMouseUp: case NSEventTypeOtherMouseUp: {
9485 u32 buttonNumber = (u32)objc_msgSend_uint(e, sel_registerName("buttonNumber"));
9486 switch (buttonNumber) {
9487 case 0: win->event.button = RGFW_mouseLeft; break;
9488 case 1: win->event.button = RGFW_mouseRight; break;
9489 case 2: win->event.button = RGFW_mouseMiddle; break;
9490 default: win->event.button = (u8)buttonNumber;
9491 }
9492 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
9493 RGFW_mouseButtons[win->event.button].current = 0;
9494 win->event.type = RGFW_mouseButtonReleased;
9495 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0);
9496 break;
9497 }
9498 case NSEventTypeScrollWheel: {
9499 double deltaY = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaY"));
9501 if (deltaY > 0) {
9502 win->event.button = RGFW_mouseScrollUp;
9503 }
9504 else if (deltaY < 0) {
9505 win->event.button = RGFW_mouseScrollDown;
9506 }
9508 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
9509 RGFW_mouseButtons[win->event.button].current = 1;
9511 win->event.scroll = deltaY;
9513 win->event.type = RGFW_mouseButtonPressed;
9514 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
9515 break;
9516 }
9518 default:
9519 objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e);
9520 ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows"));
9521 return RGFW_window_checkEvent(win);
9522 }
9524 objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e);
9525 ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows"));
9526 objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
9527 return &win->event;
9528}
9531void RGFW_window_move(RGFW_window* win, RGFW_point v) {
9532 RGFW_ASSERT(win != NULL);
9534 win->r.x = v.x;
9535 win->r.y = v.y;
9536 ((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend)
9537 ((id)win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{win->r.x, win->r.y}, {win->r.w, win->r.h}}, true, true);
9538}
9540void RGFW_window_resize(RGFW_window* win, RGFW_area a) {
9541 RGFW_ASSERT(win != NULL);
9543 NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame"));
9544 NSRect content = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame"));
9545 float offset = (float)(frame.size.height - content.size.height);
9547 win->r.w = (i32)a.w;
9548 win->r.h = (i32)a.h;
9550 ((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend)
9551 ((id)win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{win->r.x, win->r.y}, {win->r.w, win->r.h + offset}}, true, true);
9552}
9554void RGFW_window_focus(RGFW_window* win) {
9555 RGFW_ASSERT(win);
9556 objc_msgSend_void_bool(NSApp, sel_registerName("activateIgnoringOtherApps:"), true);
9557 ((void (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_registerName("makeKeyWindow"));
9558}
9560void RGFW_window_raise(RGFW_window* win) {
9561 RGFW_ASSERT(win != NULL);
9562 ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("orderFront:"), (SEL)NULL);
9563 objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGNormalWindowLevelKey);
9564}
9566void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) {
9567 RGFW_ASSERT(win != NULL);
9568 if (fullscreen && (win->_flags & RGFW_windowFullscreen)) return;
9569 if (!fullscreen && !(win->_flags & RGFW_windowFullscreen)) return;
9571 if (fullscreen) {
9572 win->_oldRect = win->r;
9573 RGFW_monitor mon = RGFW_window_getMonitor(win);
9574 win->r = RGFW_RECT(0, 0, mon.x, mon.y);
9575 win->_flags |= RGFW_windowFullscreen;
9576 RGFW_window_resize(win, RGFW_AREA(mon.mode.area.w, mon.mode.area.h));
9577 RGFW_window_move(win, RGFW_POINT(0, 0));
9578 }
9579 objc_msgSend_void_SEL(win->src.window, sel_registerName("toggleFullScreen:"), NULL);
9581 if (!fullscreen) {
9582 win->r = win->_oldRect;
9583 win->_flags &= ~(u32)RGFW_windowFullscreen;
9585 RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h));
9586 RGFW_window_move(win, RGFW_POINT(win->r.x, win->r.y));
9587 }
9588}
9590void RGFW_window_maximize(RGFW_window* win) {
9591 RGFW_ASSERT(win != NULL);
9592 if (RGFW_window_isMaximized(win)) return;
9594 win->_flags |= RGFW_windowMaximize;
9595 objc_msgSend_void_SEL(win->src.window, sel_registerName("zoom:"), NULL);
9596}
9598void RGFW_window_minimize(RGFW_window* win) {
9599 RGFW_ASSERT(win != NULL);
9600 objc_msgSend_void_SEL(win->src.window, sel_registerName("performMiniaturize:"), NULL);
9601}
9603void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) {
9604 RGFW_ASSERT(win != NULL);
9605 if (floating) objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGFloatingWindowLevelKey);
9606 else objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGNormalWindowLevelKey);
9607}
9609void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) {
9610 objc_msgSend_int(win->src.window, sel_registerName("setAlphaValue:"), opacity);
9611 objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), (opacity < (u8)255));
9613 if (opacity)
9614 objc_msgSend_void_id((id)win->src.window, sel_registerName("setBackgroundColor:"), NSColor_colorWithSRGB(0, 0, 0, opacity));
9616}
9618void RGFW_window_restore(RGFW_window* win) {
9619 RGFW_ASSERT(win != NULL);
9621 if (RGFW_window_isMaximized(win))
9622 objc_msgSend_void_SEL(win->src.window, sel_registerName("zoom:"), NULL);
9624 objc_msgSend_void_SEL(win->src.window, sel_registerName("deminiaturize:"), NULL);
9625 RGFW_window_show(win);
9626}
9628RGFW_bool RGFW_window_isFloating(RGFW_window* win) {
9629 RGFW_ASSERT(win != NULL);
9630 int level = ((int (*)(id, SEL))objc_msgSend) ((id)(win->src.window), (SEL)sel_registerName("level"));
9631 return level > kCGNormalWindowLevelKey;
9632}
9634void RGFW_window_setName(RGFW_window* win, const char* name) {
9635 RGFW_ASSERT(win != NULL);
9637 id str = NSString_stringWithUTF8String(name);
9638 objc_msgSend_void_id((id)win->src.window, sel_registerName("setTitle:"), str);
9639}
9641#ifndef RGFW_NO_PASSTHROUGH
9642void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) {
9643 objc_msgSend_void_bool(win->src.window, sel_registerName("setIgnoresMouseEvents:"), passthrough);
9644}
9645#endif
9647void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) {
9648 if (a.w == 0 && a.h == 0) a = RGFW_AREA(1, 1);
9650 ((void (*)(id, SEL, NSSize))objc_msgSend)
9651 ((id)win->src.window, sel_registerName("setContentAspectRatio:"), (NSSize){a.w, a.h});
9652}
9654void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) {
9655 ((void (*)(id, SEL, NSSize))objc_msgSend)
9656 ((id)win->src.window, sel_registerName("setMinSize:"), (NSSize){a.w, a.h});
9657}
9659void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) {
9660 if (a.w == 0 && a.h == 0) {
9661 a = RGFW_getScreenSize();
9662 }
9664 ((void (*)(id, SEL, NSSize))objc_msgSend)
9665 ((id)win->src.window, sel_registerName("setMaxSize:"), (NSSize){a.w, a.h});
9666}
9668RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, RGFW_area area, i32 channels, u8 type) {
9669 RGFW_ASSERT(win != NULL);
9670 RGFW_UNUSED(type);
9672 if (data == NULL) {
9673 objc_msgSend_void_id(NSApp, sel_registerName("setApplicationIconImage:"), NULL);
9674 return RGFW_TRUE;
9675 }
9677 /* code by EimaMei: Make a bitmap representation, then copy the loaded image into it. */
9678 id representation = NSBitmapImageRep_initWithBitmapData(NULL, area.w, area.h, 8, channels, (channels == 4), false, "NSCalibratedRGBColorSpace", 1 << 1, area.w * (u32)channels, 8 * (u32)channels);
9679 RGFW_MEMCPY(NSBitmapImageRep_bitmapData(representation), data, area.w * area.h * (u32)channels);
9681 /* Add ze representation. */
9682 id dock_image = ((id(*)(id, SEL, NSSize))objc_msgSend) (NSAlloc((id)objc_getClass("NSImage")), sel_registerName("initWithSize:"), ((NSSize){area.w, area.h}));
9684 objc_msgSend_void_id(dock_image, sel_registerName("addRepresentation:"), representation);
9686 /* Finally, set the dock image to it. */
9687 objc_msgSend_void_id(NSApp, sel_registerName("setApplicationIconImage:"), dock_image);
9688 /* Free the garbage. */
9689 NSRelease(dock_image);
9690 NSRelease(representation);
9692 return RGFW_TRUE;
9693}
9695id NSCursor_arrowStr(const char* str) {
9696 void* nclass = objc_getClass("NSCursor");
9697 SEL func = sel_registerName(str);
9698 return (id) objc_msgSend_id(nclass, func);
9699}
9701RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) {
9702 if (icon == NULL) {
9703 objc_msgSend_void(NSCursor_arrowStr("arrowCursor"), sel_registerName("set"));
9704 return NULL;
9705 }
9707 /* NOTE(EimaMei): Code by yours truly. */
9708 /* Make a bitmap representation, then copy the loaded image into it. */
9709 id representation = (id)NSBitmapImageRep_initWithBitmapData(NULL, a.w, a.h, 8, channels, (channels == 4), false, "NSCalibratedRGBColorSpace", 1 << 1, a.w * (u32)channels, 8 * (u32)channels);
9710 RGFW_MEMCPY(NSBitmapImageRep_bitmapData(representation), icon, a.w * a.h * (u32)channels);
9712 /* Add ze representation. */
9713 id cursor_image = ((id(*)(id, SEL, NSSize))objc_msgSend) (NSAlloc((id)objc_getClass("NSImage")), sel_registerName("initWithSize:"), ((NSSize){a.w, a.h}));
9715 objc_msgSend_void_id(cursor_image, sel_registerName("addRepresentation:"), representation);
9717 /* Finally, set the cursor image. */
9718 id cursor = (id) ((id(*)(id, SEL, id, NSPoint))objc_msgSend)
9719 (NSAlloc(objc_getClass("NSCursor")), sel_registerName("initWithImage:hotSpot:"), cursor_image, (NSPoint){0.0, 0.0});
9721 /* Free the garbage. */
9722 NSRelease(cursor_image);
9723 NSRelease(representation);
9725 return (void*)cursor;
9726}
9728void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) {
9729 RGFW_ASSERT(win != NULL); RGFW_ASSERT(mouse);
9730 CGDisplayShowCursor(kCGDirectMainDisplay);
9731 objc_msgSend_void((id)mouse, sel_registerName("set"));
9732 win->src.mouse = mouse;
9733}
9735void RGFW_freeMouse(RGFW_mouse* mouse) {
9736 RGFW_ASSERT(mouse);
9737 NSRelease((id)mouse);
9738}
9740RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) {
9741 return RGFW_window_setMouseStandard(win, RGFW_mouseArrow);
9742}
9744void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) {
9745 RGFW_window_showMouseFlags(win, show);
9746 if (show) CGDisplayShowCursor(kCGDirectMainDisplay);
9747 else CGDisplayHideCursor(kCGDirectMainDisplay);
9748}
9750RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 stdMouses) {
9751 static const char* mouseIconSrc[16] = {"arrowCursor", "arrowCursor", "IBeamCursor", "crosshairCursor", "pointingHandCursor", "resizeLeftRightCursor", "resizeUpDownCursor", "_windowResizeNorthWestSouthEastCursor", "_windowResizeNorthEastSouthWestCursor", "closedHandCursor", "operationNotAllowedCursor"};
9752 if (stdMouses > ((sizeof(mouseIconSrc)) / (sizeof(char*))))
9753 return RGFW_FALSE;
9755 const char* mouseStr = mouseIconSrc[stdMouses];
9756 id mouse = NSCursor_arrowStr(mouseStr);
9758 if (mouse == NULL)
9759 return RGFW_FALSE;
9761 RGFW_UNUSED(win);
9762 CGDisplayShowCursor(kCGDirectMainDisplay);
9763 objc_msgSend_void(mouse, sel_registerName("set"));
9764 win->src.mouse = mouse;
9766 return RGFW_TRUE;
9767}
9769void RGFW_releaseCursor(RGFW_window* win) {
9770 RGFW_UNUSED(win);
9771 CGAssociateMouseAndMouseCursorPosition(1);
9772}
9774void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) {
9775 RGFW_UNUSED(win);
9777 CGWarpMouseCursorPosition((CGPoint){r.x + (r.w / 2), r.y + (r.h / 2)});
9778 CGAssociateMouseAndMouseCursorPosition(0);
9779}
9781void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) {
9782 RGFW_UNUSED(win);
9784 win->_lastMousePoint = RGFW_POINT(v.x - win->r.x, v.y - win->r.y);
9785 CGWarpMouseCursorPosition((CGPoint){v.x, v.y});
9786}
9789void RGFW_window_hide(RGFW_window* win) {
9790 objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), false);
9791}
9793void RGFW_window_show(RGFW_window* win) {
9794 if (win->_flags & RGFW_windowFocusOnShow)
9795 ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("makeKeyAndOrderFront:"), NULL);
9797 ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("orderFront:"), NULL);
9798 objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), true);
9799}
9801RGFW_bool RGFW_window_isHidden(RGFW_window* win) {
9802 RGFW_ASSERT(win != NULL);
9804 bool visible = objc_msgSend_bool(win->src.window, sel_registerName("isVisible"));
9805 return visible == NO && !RGFW_window_isMinimized(win);
9806}
9808RGFW_bool RGFW_window_isMinimized(RGFW_window* win) {
9809 RGFW_ASSERT(win != NULL);
9811 return objc_msgSend_bool(win->src.window, sel_registerName("isMiniaturized")) == YES;
9812}
9814RGFW_bool RGFW_window_isMaximized(RGFW_window* win) {
9815 RGFW_ASSERT(win != NULL);
9816 RGFW_bool b = (RGFW_bool)objc_msgSend_bool(win->src.window, sel_registerName("isZoomed"));
9817 return b;
9818}
9820id RGFW_getNSScreenForDisplayID(CGDirectDisplayID display) {
9821 Class NSScreenClass = objc_getClass("NSScreen");
9823 id screens = objc_msgSend_id(NSScreenClass, sel_registerName("screens"));
9825 NSUInteger count = (NSUInteger)objc_msgSend_uint(screens, sel_registerName("count"));
9826 NSUInteger i;
9827 for (i = 0; i < count; i++) {
9828 id screen = ((id (*)(id, SEL, int))objc_msgSend) (screens, sel_registerName("objectAtIndex:"), (int)i);
9829 id description = objc_msgSend_id(screen, sel_registerName("deviceDescription"));
9830 id screenNumberKey = NSString_stringWithUTF8String("NSScreenNumber");
9831 id screenNumber = objc_msgSend_id_id(description, sel_registerName("objectForKey:"), screenNumberKey);
9833 if ((CGDirectDisplayID)objc_msgSend_uint(screenNumber, sel_registerName("unsignedIntValue")) == display) {
9834 return screen;
9835 }
9836 }
9838 return NULL;
9839}
9841u32 RGFW_osx_getFallbackRefreshRate(CGDirectDisplayID displayID);
9843u32 RGFW_osx_getRefreshRate(CGDirectDisplayID display, CGDisplayModeRef mode) {
9844 if (mode) {
9845 u32 refreshRate = (u32)CGDisplayModeGetRefreshRate(mode);
9846 if (refreshRate != 0) return refreshRate;
9847 }
9849#ifndef RGFW_NO_IOKIT
9850 u32 res = RGFW_osx_getFallbackRefreshRate(display);
9851 if (res != 0) return res;
9852#else
9853 RGFW_UNUSED(display);
9854#endif
9855 return 60;
9856}
9858RGFW_monitor RGFW_NSCreateMonitor(CGDirectDisplayID display, id screen) {
9859 RGFW_monitor monitor;
9861 const char name[] = "MacOS\0";
9862 RGFW_MEMCPY(monitor.name, name, 6);
9864 CGRect bounds = CGDisplayBounds(display);
9865 monitor.x = (i32)bounds.origin.x;
9866 monitor.y = (i32)bounds.origin.y;
9867 monitor.mode.area = RGFW_AREA((int) bounds.size.width, (int) bounds.size.height);
9869 monitor.mode.red = 8; monitor.mode.green = 8; monitor.mode.blue = 8;
9871 CGDisplayModeRef mode = CGDisplayCopyDisplayMode(display);
9872 monitor.mode.refreshRate = RGFW_osx_getRefreshRate(display, mode);
9873 CFRelease(mode);
9875 CGSize screenSizeMM = CGDisplayScreenSize(display);
9876 monitor.physW = (float)screenSizeMM.width / 25.4f;
9877 monitor.physH = (float)screenSizeMM.height / 25.4f;
9879 float ppi_width = (monitor.mode.area.w/monitor.physW);
9880 float ppi_height = (monitor.mode.area.h/monitor.physH);
9882 monitor.pixelRatio = (float)((CGFloat (*)(id, SEL))abi_objc_msgSend_fpret) (screen, sel_registerName("backingScaleFactor"));
9883 float dpi = 96.0f * monitor.pixelRatio;
9885 monitor.scaleX = ((i32)(((float) (ppi_width) / dpi) * 10.0f)) / 10.0f;
9886 monitor.scaleY = ((i32)(((float) (ppi_height) / dpi) * 10.0f)) / 10.0f;
9888 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found");
9889 return monitor;
9890}
9893RGFW_monitor* RGFW_getMonitors(size_t* len) {
9894 static CGDirectDisplayID displays[7];
9895 u32 count;
9897 if (CGGetActiveDisplayList(6, displays, &count) != kCGErrorSuccess)
9898 return NULL;
9900 if (count > 6) count = 6;
9902 static RGFW_monitor monitors[7];
9904 u32 i;
9905 for (i = 0; i < count; i++)
9906 monitors[i] = RGFW_NSCreateMonitor(displays[i], RGFW_getNSScreenForDisplayID(displays[i]));
9908 if (len != NULL) *len = count;
9909 return monitors;
9910}
9912RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) {
9913 CGPoint point = { mon.x, mon.y };
9915 CGDirectDisplayID display;
9916 uint32_t displayCount = 0;
9917 CGError err = CGGetDisplaysWithPoint(point, 1, &display, &displayCount);
9918 if (err != kCGErrorSuccess || displayCount != 1)
9919 return RGFW_FALSE;
9921 CFArrayRef allModes = CGDisplayCopyAllDisplayModes(display, NULL);
9923 if (allModes == NULL)
9924 return RGFW_FALSE;
9926 CFIndex i;
9927 for (i = 0; i < CFArrayGetCount(allModes); i++) {
9928 CGDisplayModeRef cmode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, i);
9930 RGFW_monitorMode foundMode;
9931 foundMode.area = RGFW_AREA(CGDisplayModeGetWidth(cmode), CGDisplayModeGetHeight(cmode));
9932 foundMode.refreshRate = RGFW_osx_getRefreshRate(display, cmode);
9933 foundMode.red = 8; foundMode.green = 8; foundMode.blue = 8;
9935 if (RGFW_monitorModeCompare(mode, foundMode, request)) {
9936 if (CGDisplaySetDisplayMode(display, cmode, NULL) == kCGErrorSuccess) {
9937 CFRelease(allModes);
9938 return RGFW_TRUE;
9939 }
9940 break;
9941 }
9942 }
9944 CFRelease(allModes);
9946 return RGFW_FALSE;
9947}
9949RGFW_monitor RGFW_getPrimaryMonitor(void) {
9950 CGDirectDisplayID primary = CGMainDisplayID();
9951 return RGFW_NSCreateMonitor(primary, RGFW_getNSScreenForDisplayID(primary));
9952}
9954RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) {
9955 id screen = objc_msgSend_id(win->src.window, sel_registerName("screen"));
9956 id description = objc_msgSend_id(screen, sel_registerName("deviceDescription"));
9957 id screenNumberKey = NSString_stringWithUTF8String("NSScreenNumber");
9958 id screenNumber = objc_msgSend_id_id(description, sel_registerName("objectForKey:"), screenNumberKey);
9960 CGDirectDisplayID display = (CGDirectDisplayID)objc_msgSend_uint(screenNumber, sel_registerName("unsignedIntValue"));
9962 return RGFW_NSCreateMonitor(display, screen);
9963}
9965RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) {
9966 size_t clip_len;
9967 char* clip = (char*)NSPasteboard_stringForType(NSPasteboard_generalPasteboard(), NSPasteboardTypeString, &clip_len);
9968 if (clip == NULL) return -1;
9970 if (str != NULL) {
9971 if (strCapacity < clip_len)
9972 return 0;
9974 RGFW_MEMCPY(str, clip, clip_len);
9976 str[clip_len] = '\0';
9977 }
9979 return (RGFW_ssize_t)clip_len;
9980}
9982void RGFW_writeClipboard(const char* text, u32 textLen) {
9983 RGFW_UNUSED(textLen);
9985 NSPasteboardType array[] = { NSPasteboardTypeString, NULL };
9986 NSPasteBoard_declareTypes(NSPasteboard_generalPasteboard(), array, 1, NULL);
9988 SEL func = sel_registerName("setString:forType:");
9989 ((bool (*)(id, SEL, id, id))objc_msgSend)
9990 (NSPasteboard_generalPasteboard(), func, NSString_stringWithUTF8String(text), NSString_stringWithUTF8String(NSPasteboardTypeString));
9991}
9993 #ifdef RGFW_OPENGL
9994 void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
9995 if (win != NULL)
9996 objc_msgSend_void(win->src.ctx, sel_registerName("makeCurrentContext"));
9997 else
9998 objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("clearCurrentContext"));
9999 }
10000 void* RGFW_getCurrent_OpenGL(void) {
10001 return objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("currentContext"));
10002 }
10004 void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) {
10005 objc_msgSend_void(win->src.ctx, sel_registerName("flushBuffer"));
10006 }
10007 #endif
10009 #if !defined(RGFW_EGL)
10011 void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) {
10012 RGFW_ASSERT(win != NULL);
10013 #if defined(RGFW_OPENGL)
10015 NSOpenGLContext_setValues((id)win->src.ctx, &swapInterval, 222);
10016 #else
10017 RGFW_UNUSED(swapInterval);
10018 #endif
10019 }
10021 #endif
10023void RGFW_window_swapBuffers_software(RGFW_window* win) {
10024#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
10025 RGFW_RGB_to_BGR(win, win->buffer);
10026 i32 channels = 4;
10027 id image = ((id (*)(Class, SEL))objc_msgSend)(objc_getClass("NSImage"), sel_getUid("alloc"));
10028 NSSize size = (NSSize){win->bufferSize.w, win->bufferSize.h};
10029 image = ((id (*)(id, SEL, NSSize))objc_msgSend)((id)image, sel_getUid("initWithSize:"), size);
10031 id rep = NSBitmapImageRep_initWithBitmapData(&win->buffer, win->r.w, win->r.h , 8, channels, (channels == 4), false,
10032 "NSDeviceRGBColorSpace", 1 << 1, (u32)win->bufferSize.w * (u32)channels, 8 * (u32)channels);
10033 ((void (*)(id, SEL, id))objc_msgSend)((id)image, sel_getUid("addRepresentation:"), rep);
10035 id contentView = ((id (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_getUid("contentView"));
10036 ((void (*)(id, SEL, BOOL))objc_msgSend)(contentView, sel_getUid("setWantsLayer:"), YES);
10037 id layer = ((id (*)(id, SEL))objc_msgSend)(contentView, sel_getUid("layer"));
10039 ((void (*)(id, SEL, id))objc_msgSend)(layer, sel_getUid("setContents:"), (id)image);
10040 ((void (*)(id, SEL, BOOL))objc_msgSend)(contentView, sel_getUid("setNeedsDisplay:"), YES);
10042 NSRelease(rep);
10043 NSRelease(image);
10044#else
10045 RGFW_UNUSED(win);
10046#endif
10049void RGFW_deinit(void) {
10050 _RGFW.windowCount = -1;
10051 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized");
10054void RGFW_window_close(RGFW_window* win) {
10055 RGFW_ASSERT(win != NULL);
10056 NSRelease(win->src.view);
10057 if ((win->_flags & RGFW_windowNoInitAPI) == 0) RGFW_window_freeOpenGL(win);
10059 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
10060 if ((win->_flags & RGFW_BUFFER_ALLOC))
10061 RGFW_FREE(win->buffer);
10062 #endif
10064 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized");
10065 _RGFW.windowCount--;
10066 if (_RGFW.windowCount == 0) RGFW_deinit();
10068 RGFW_clipboard_switch(NULL);
10069 RGFW_FREE(win->event.droppedFiles);
10070 if ((win->_flags & RGFW_WINDOW_ALLOC)) {
10071 RGFW_FREE(win);
10072 win = NULL;
10073 }
10076u64 RGFW_getTimerFreq(void) {
10077 static u64 freq = 0;
10078 if (freq == 0) {
10079 mach_timebase_info_data_t info;
10080 mach_timebase_info(&info);
10081 freq = (u64)((info.denom * 1e9) / info.numer);
10082 }
10084 return freq;
10087u64 RGFW_getTimerValue(void) { return (u64)mach_absolute_time(); }
10089#endif /* RGFW_MACOS */
10091/*
10092 End of MaOS defines
10093*/
10095/*
10096 WASM defines
10097*/
10099#ifdef RGFW_WASM
10100EM_BOOL Emscripten_on_resize(int eventType, const EmscriptenUiEvent* E, void* userData) {
10101 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
10103 RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e._win = _RGFW.root);
10104 RGFW_windowResizedCallback(_RGFW.root, RGFW_RECT(0, 0, E->windowInnerWidth, E->windowInnerHeight));
10105 return EM_TRUE;
10108EM_BOOL Emscripten_on_fullscreenchange(int eventType, const EmscriptenFullscreenChangeEvent* E, void* userData) {
10109 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
10110 static u8 fullscreen = RGFW_FALSE;
10111 static RGFW_rect ogRect;
10113 if (fullscreen == RGFW_FALSE) {
10114 ogRect = _RGFW.root->r;
10115 }
10117 fullscreen = !fullscreen;
10118 RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e._win = _RGFW.root);
10119 _RGFW.root->r = RGFW_RECT(0, 0, E->screenWidth, E->screenHeight);
10121 EM_ASM("Module.canvas.focus();");
10123 if (fullscreen == RGFW_FALSE) {
10124 _RGFW.root->r = RGFW_RECT(0, 0, ogRect.w, ogRect.h);
10125 /* emscripten_request_fullscreen("#canvas", 0); */
10126 } else {
10127 #if __EMSCRIPTEN_major__ >= 1 && __EMSCRIPTEN_minor__ >= 29 && __EMSCRIPTEN_tiny__ >= 0
10128 EmscriptenFullscreenStrategy FSStrat = {0};
10129 FSStrat.scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH; /* EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT : EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH; */
10130 FSStrat.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF;
10131 FSStrat.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT;
10132 emscripten_request_fullscreen_strategy("#canvas", 1, &FSStrat);
10133 #else
10134 emscripten_request_fullscreen("#canvas", 1);
10135 #endif
10136 }
10138 emscripten_set_canvas_element_size("#canvas", _RGFW.root->r.w, _RGFW.root->r.h);
10140 RGFW_windowResizedCallback(_RGFW.root, _RGFW.root->r);
10141 return EM_TRUE;
10146EM_BOOL Emscripten_on_focusin(int eventType, const EmscriptenFocusEvent* E, void* userData) {
10147 RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(E);
10149 RGFW_eventQueuePushEx(e.type = RGFW_focusIn; e._win = _RGFW.root);
10150 _RGFW.root->_flags |= RGFW_windowFocus;
10151 RGFW_focusCallback(_RGFW.root, 1);
10153 if ((_RGFW.root->_flags & RGFW_HOLD_MOUSE)) RGFW_window_mouseHold(_RGFW.root, RGFW_AREA(_RGFW.root->r.w, _RGFW.root->r.h));
10154 return EM_TRUE;
10157EM_BOOL Emscripten_on_focusout(int eventType, const EmscriptenFocusEvent* E, void* userData) {
10158 RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(E);
10160 RGFW_eventQueuePushEx(e.type = RGFW_focusOut; e._win = _RGFW.root);
10161 RGFW_window_focusLost(_RGFW.root);
10162 RGFW_focusCallback(_RGFW.root, 0);
10163 return EM_TRUE;
10166EM_BOOL Emscripten_on_mousemove(int eventType, const EmscriptenMouseEvent* E, void* userData) {
10167 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
10168 RGFW_eventQueuePushEx(e.type = RGFW_mousePosChanged;
10169 e.point = RGFW_POINT(E->targetX, E->targetY);
10170 e.vector = RGFW_POINT(E->movementX, E->movementY);
10171 e._win = _RGFW.root);
10173 _RGFW.root->_lastMousePoint = RGFW_POINT(E->targetX, E->targetY);
10174 RGFW_mousePosCallback(_RGFW.root, RGFW_POINT(E->targetX, E->targetY), RGFW_POINT(E->movementX, E->movementY));
10175 return EM_TRUE;
10178EM_BOOL Emscripten_on_mousedown(int eventType, const EmscriptenMouseEvent* E, void* userData) {
10179 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
10181 int button = E->button;
10182 if (button > 2)
10183 button += 2;
10185 RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonPressed;
10186 e.point = RGFW_POINT(E->targetX, E->targetY);
10187 e.vector = RGFW_POINT(E->movementX, E->movementY);
10188 e.button = (u8)button;
10189 e.scroll = 0;
10190 e._win = _RGFW.root);
10191 RGFW_mouseButtons[button].prev = RGFW_mouseButtons[button].current;
10192 RGFW_mouseButtons[button].current = 1;
10194 RGFW_mouseButtonCallback(_RGFW.root, button, 0, 1);
10195 return EM_TRUE;
10198EM_BOOL Emscripten_on_mouseup(int eventType, const EmscriptenMouseEvent* E, void* userData) {
10199 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
10201 int button = E->button;
10202 if (button > 2)
10203 button += 2;
10205 RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonReleased;
10206 e.point = RGFW_POINT(E->targetX, E->targetY);
10207 e.vector = RGFW_POINT(E->movementX, E->movementY);
10208 e.button = (u8)button;
10209 e.scroll = 0;
10210 e._win = _RGFW.root);
10211 RGFW_mouseButtons[button].prev = RGFW_mouseButtons[button].current;
10212 RGFW_mouseButtons[button].current = 0;
10214 RGFW_mouseButtonCallback(_RGFW.root, button, 0, 0);
10215 return EM_TRUE;
10218EM_BOOL Emscripten_on_wheel(int eventType, const EmscriptenWheelEvent* E, void* userData) {
10219 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
10221 int button = RGFW_mouseScrollUp + (E->deltaY < 0);
10222 RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonPressed;
10223 e.button = (u8)button;
10224 e.scroll = (double)(E->deltaY < 0 ? 1 : -1);
10225 e._win = _RGFW.root);
10226 RGFW_mouseButtons[button].prev = RGFW_mouseButtons[button].current;
10227 RGFW_mouseButtons[button].current = 1;
10228 RGFW_mouseButtonCallback(_RGFW.root, button, E->deltaY < 0 ? 1 : -1, 1);
10230 return EM_TRUE;
10233EM_BOOL Emscripten_on_touchstart(int eventType, const EmscriptenTouchEvent* E, void* userData) {
10234 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
10236 size_t i;
10237 for (i = 0; i < (size_t)E->numTouches; i++) {
10238 RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonPressed;
10239 e.point = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY);
10240 e.button = RGFW_mouseLeft;
10241 e._win = _RGFW.root);
10243 RGFW_mouseButtons[RGFW_mouseLeft].prev = RGFW_mouseButtons[RGFW_mouseLeft].current;
10244 RGFW_mouseButtons[RGFW_mouseLeft].current = 1;
10246 _RGFW.root->_lastMousePoint = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY);
10247 RGFW_mousePosCallback(_RGFW.root, RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY), _RGFW.root->event.vector);
10248 RGFW_mouseButtonCallback(_RGFW.root, RGFW_mouseLeft, 0, 1);
10249 }
10251 return EM_TRUE;
10253EM_BOOL Emscripten_on_touchmove(int eventType, const EmscriptenTouchEvent* E, void* userData) {
10254 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
10256 size_t i;
10257 for (i = 0; i < (size_t)E->numTouches; i++) {
10258 RGFW_eventQueuePushEx(e.type = RGFW_mousePosChanged;
10259 e.point = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY);
10260 e.button = RGFW_mouseLeft;
10261 e._win = _RGFW.root);
10263 _RGFW.root->_lastMousePoint = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY);
10264 RGFW_mousePosCallback(_RGFW.root, RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY), _RGFW.root->event.vector);
10265 }
10266 return EM_TRUE;
10269EM_BOOL Emscripten_on_touchend(int eventType, const EmscriptenTouchEvent* E, void* userData) {
10270 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
10272 size_t i;
10273 for (i = 0; i < (size_t)E->numTouches; i++) {
10274 RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonReleased;
10275 e.point = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY);
10276 e.button = RGFW_mouseLeft;
10277 e._win = _RGFW.root);
10279 RGFW_mouseButtons[RGFW_mouseLeft].prev = RGFW_mouseButtons[RGFW_mouseLeft].current;
10280 RGFW_mouseButtons[RGFW_mouseLeft].current = 0;
10282 _RGFW.root->_lastMousePoint = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY);
10283 RGFW_mousePosCallback(_RGFW.root, RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY), _RGFW.root->event.vector);
10284 RGFW_mouseButtonCallback(_RGFW.root, RGFW_mouseLeft, 0, 0);
10285 }
10286 return EM_TRUE;
10289EM_BOOL Emscripten_on_touchcancel(int eventType, const EmscriptenTouchEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); return EM_TRUE; }
10291EM_BOOL Emscripten_on_gamepad(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData) {
10292 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
10294 if (gamepadEvent->index >= 4)
10295 return 0;
10297 size_t i = gamepadEvent->index;
10298 if (gamepadEvent->connected) {
10299 RGFW_STRNCPY(RGFW_gamepads_name[gamepadEvent->index], gamepadEvent->id, sizeof(RGFW_gamepads_name[gamepadEvent->index]) - 1);
10300 RGFW_gamepads_name[gamepadEvent->index][sizeof(RGFW_gamepads_name[gamepadEvent->index]) - 1] = '\0';
10301 RGFW_gamepads_type[i] = RGFW_gamepadUnknown;
10302 if (RGFW_STRSTR(RGFW_gamepads_name[i], "Microsoft") || RGFW_STRSTR(RGFW_gamepads_name[i], "X-Box"))
10303 RGFW_gamepads_type[i] = RGFW_gamepadMicrosoft;
10304 else if (RGFW_STRSTR(RGFW_gamepads_name[i], "PlayStation") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS3") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS4") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS5"))
10305 RGFW_gamepads_type[i] = RGFW_gamepadSony;
10306 else if (RGFW_STRSTR(RGFW_gamepads_name[i], "Nintendo"))
10307 RGFW_gamepads_type[i] = RGFW_gamepadNintendo;
10308 else if (RGFW_STRSTR(RGFW_gamepads_name[i], "Logitech"))
10309 RGFW_gamepads_type[i] = RGFW_gamepadLogitech;
10310 RGFW_gamepadCount++;
10311 } else {
10312 RGFW_gamepadCount--;
10313 }
10315 RGFW_eventQueuePushEx(e.type = (RGFW_eventType)(gamepadEvent->connected ? RGFW_gamepadConnected : RGFW_gamepadConnected);
10316 e.gamepad = (u16)gamepadEvent->index;
10317 e._win = _RGFW.root);
10319 RGFW_gamepadCallback(_RGFW.root, gamepadEvent->index, gamepadEvent->connected);
10320 RGFW_gamepads[gamepadEvent->index] = gamepadEvent->connected;
10322 return 1; /* The event was consumed by the callback handler */
10325u32 RGFW_wASMPhysicalToRGFW(u32 hash) {
10326 switch(hash) { /* 0x0000 */
10327 case 0x67243A2DU /* Escape */: return RGFW_escape; /* 0x0001 */
10328 case 0x67251058U /* Digit0 */: return RGFW_0; /* 0x0002 */
10329 case 0x67251059U /* Digit1 */: return RGFW_1; /* 0x0003 */
10330 case 0x6725105AU /* Digit2 */: return RGFW_2; /* 0x0004 */
10331 case 0x6725105BU /* Digit3 */: return RGFW_3; /* 0x0005 */
10332 case 0x6725105CU /* Digit4 */: return RGFW_4; /* 0x0006 */
10333 case 0x6725105DU /* Digit5 */: return RGFW_5; /* 0x0007 */
10334 case 0x6725105EU /* Digit6 */: return RGFW_6; /* 0x0008 */
10335 case 0x6725105FU /* Digit7 */: return RGFW_7; /* 0x0009 */
10336 case 0x67251050U /* Digit8 */: return RGFW_8; /* 0x000A */
10337 case 0x67251051U /* Digit9 */: return RGFW_9; /* 0x000B */
10338 case 0x92E14DD3U /* Minus */: return RGFW_minus; /* 0x000C */
10339 case 0x92E1FBACU /* Equal */: return RGFW_equals; /* 0x000D */
10340 case 0x36BF1CB5U /* Backspace */: return RGFW_backSpace; /* 0x000E */
10341 case 0x7B8E51E2U /* Tab */: return RGFW_tab; /* 0x000F */
10342 case 0x2C595B51U /* KeyQ */: return RGFW_q; /* 0x0010 */
10343 case 0x2C595B57U /* KeyW */: return RGFW_w; /* 0x0011 */
10344 case 0x2C595B45U /* KeyE */: return RGFW_e; /* 0x0012 */
10345 case 0x2C595B52U /* KeyR */: return RGFW_r; /* 0x0013 */
10346 case 0x2C595B54U /* KeyT */: return RGFW_t; /* 0x0014 */
10347 case 0x2C595B59U /* KeyY */: return RGFW_y; /* 0x0015 */
10348 case 0x2C595B55U /* KeyU */: return RGFW_u; /* 0x0016 */
10349 case 0x2C595B4FU /* KeyO */: return RGFW_o; /* 0x0018 */
10350 case 0x2C595B50U /* KeyP */: return RGFW_p; /* 0x0019 */
10351 case 0x45D8158CU /* BracketLeft */: return RGFW_closeBracket; /* 0x001A */
10352 case 0xDEEABF7CU /* BracketRight */: return RGFW_bracket; /* 0x001B */
10353 case 0x92E1C5D2U /* Enter */: return RGFW_return; /* 0x001C */
10354 case 0xE058958CU /* ControlLeft */: return RGFW_controlL; /* 0x001D */
10355 case 0x2C595B41U /* KeyA */: return RGFW_a; /* 0x001E */
10356 case 0x2C595B53U /* KeyS */: return RGFW_s; /* 0x001F */
10357 case 0x2C595B44U /* KeyD */: return RGFW_d; /* 0x0020 */
10358 case 0x2C595B46U /* KeyF */: return RGFW_f; /* 0x0021 */
10359 case 0x2C595B47U /* KeyG */: return RGFW_g; /* 0x0022 */
10360 case 0x2C595B48U /* KeyH */: return RGFW_h; /* 0x0023 */
10361 case 0x2C595B4AU /* KeyJ */: return RGFW_j; /* 0x0024 */
10362 case 0x2C595B4BU /* KeyK */: return RGFW_k; /* 0x0025 */
10363 case 0x2C595B4CU /* KeyL */: return RGFW_l; /* 0x0026 */
10364 case 0x2707219EU /* Semicolon */: return RGFW_semicolon; /* 0x0027 */
10365 case 0x92E0B58DU /* Quote */: return RGFW_apostrophe; /* 0x0028 */
10366 case 0x36BF358DU /* Backquote */: return RGFW_backtick; /* 0x0029 */
10367 case 0x26B1958CU /* ShiftLeft */: return RGFW_shiftL; /* 0x002A */
10368 case 0x36BF2438U /* Backslash */: return RGFW_backSlash; /* 0x002B */
10369 case 0x2C595B5AU /* KeyZ */: return RGFW_z; /* 0x002C */
10370 case 0x2C595B58U /* KeyX */: return RGFW_x; /* 0x002D */
10371 case 0x2C595B43U /* KeyC */: return RGFW_c; /* 0x002E */
10372 case 0x2C595B56U /* KeyV */: return RGFW_v; /* 0x002F */
10373 case 0x2C595B42U /* KeyB */: return RGFW_b; /* 0x0030 */
10374 case 0x2C595B4EU /* KeyN */: return RGFW_n; /* 0x0031 */
10375 case 0x2C595B4DU /* KeyM */: return RGFW_m; /* 0x0032 */
10376 case 0x92E1A1C1U /* Comma */: return RGFW_comma; /* 0x0033 */
10377 case 0x672FFAD4U /* Period */: return RGFW_period; /* 0x0034 */
10378 case 0x92E0A438U /* Slash */: return RGFW_slash; /* 0x0035 */
10379 case 0xC5A6BF7CU /* ShiftRight */: return RGFW_shiftR;
10380 case 0x5D64DA91U /* NumpadMultiply */: return RGFW_multiply;
10381 case 0xC914958CU /* AltLeft */: return RGFW_altL; /* 0x0038 */
10382 case 0x92E09CB5U /* Space */: return RGFW_space; /* 0x0039 */
10383 case 0xB8FAE73BU /* CapsLock */: return RGFW_capsLock; /* 0x003A */
10384 case 0x7174B789U /* F1 */: return RGFW_F1; /* 0x003B */
10385 case 0x7174B78AU /* F2 */: return RGFW_F2; /* 0x003C */
10386 case 0x7174B78BU /* F3 */: return RGFW_F3; /* 0x003D */
10387 case 0x7174B78CU /* F4 */: return RGFW_F4; /* 0x003E */
10388 case 0x7174B78DU /* F5 */: return RGFW_F5; /* 0x003F */
10389 case 0x7174B78EU /* F6 */: return RGFW_F6; /* 0x0040 */
10390 case 0x7174B78FU /* F7 */: return RGFW_F7; /* 0x0041 */
10391 case 0x7174B780U /* F8 */: return RGFW_F8; /* 0x0042 */
10392 case 0x7174B781U /* F9 */: return RGFW_F9; /* 0x0043 */
10393 case 0x7B8E57B0U /* F10 */: return RGFW_F10; /* 0x0044 */
10394 case 0xC925FCDFU /* Numpad7 */: return RGFW_multiply; /* 0x0047 */
10395 case 0xC925FCD0U /* Numpad8 */: return RGFW_KP_8; /* 0x0048 */
10396 case 0xC925FCD1U /* Numpad9 */: return RGFW_KP_9; /* 0x0049 */
10397 case 0x5EA3E8A4U /* NumpadSubtract */: return RGFW_minus; /* 0x004A */
10398 case 0xC925FCDCU /* Numpad4 */: return RGFW_KP_4; /* 0x004B */
10399 case 0xC925FCDDU /* Numpad5 */: return RGFW_KP_5; /* 0x004C */
10400 case 0xC925FCDEU /* Numpad6 */: return RGFW_KP_6; /* 0x004D */
10401 case 0xC925FCD9U /* Numpad1 */: return RGFW_KP_1; /* 0x004F */
10402 case 0xC925FCDAU /* Numpad2 */: return RGFW_KP_2; /* 0x0050 */
10403 case 0xC925FCDBU /* Numpad3 */: return RGFW_KP_3; /* 0x0051 */
10404 case 0xC925FCD8U /* Numpad0 */: return RGFW_KP_0; /* 0x0052 */
10405 case 0x95852DACU /* NumpadDecimal */: return RGFW_period; /* 0x0053 */
10406 case 0x7B8E57B1U /* F11 */: return RGFW_F11; /* 0x0057 */
10407 case 0x7B8E57B2U /* F12 */: return RGFW_F12; /* 0x0058 */
10408 case 0x7393FBACU /* NumpadEqual */: return RGFW_KP_Return;
10409 case 0xB88EBF7CU /* AltRight */: return RGFW_altR; /* 0xE038 */
10410 case 0xC925873BU /* NumLock */: return RGFW_numLock; /* 0xE045 */
10411 case 0x2C595F45U /* Home */: return RGFW_home; /* 0xE047 */
10412 case 0xC91BB690U /* ArrowUp */: return RGFW_up; /* 0xE048 */
10413 case 0x672F9210U /* PageUp */: return RGFW_pageUp; /* 0xE049 */
10414 case 0x3799258CU /* ArrowLeft */: return RGFW_left; /* 0xE04B */
10415 case 0x4CE33F7CU /* ArrowRight */: return RGFW_right; /* 0xE04D */
10416 case 0x7B8E55DCU /* End */: return RGFW_end; /* 0xE04F */
10417 case 0x3799379EU /* ArrowDown */: return RGFW_down; /* 0xE050 */
10418 case 0xBA90179EU /* PageDown */: return RGFW_pageDown; /* 0xE051 */
10419 case 0x6723CB2CU /* Insert */: return RGFW_insert; /* 0xE052 */
10420 case 0x6725C50DU /* Delete */: return RGFW_delete; /* 0xE053 */
10421 case 0x6723658CU /* OSLeft */: return RGFW_superL; /* 0xE05B */
10422 case 0x39643F7CU /* MetaRight */: return RGFW_superR; /* 0xE05C */
10423 }
10425 return 0;
10428void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyEvent(char* key, char* code, RGFW_bool press) {
10429 const char* iCode = code;
10431 u32 hash = 0;
10432 while(*iCode) hash = ((hash ^ 0x7E057D79U) << 3) ^ (unsigned int)*iCode++;
10434 u32 physicalKey = RGFW_wASMPhysicalToRGFW(hash);
10436 u8 mappedKey = (u8)(*((u32*)key));
10438 if (*((u16*)key) != mappedKey) {
10439 mappedKey = 0;
10440 if (*((u32*)key) == *((u32*)"Tab")) mappedKey = RGFW_tab;
10441 }
10443 RGFW_eventQueuePushEx(e.type = (RGFW_eventType)(press ? RGFW_keyPressed : RGFW_keyReleased);
10444 e.key = (u8)physicalKey;
10445 e.keyChar = (u8)mappedKey;
10446 e.keyMod = _RGFW.root->event.keyMod;
10447 e._win = _RGFW.root);
10449 RGFW_keyboard[physicalKey].prev = RGFW_keyboard[physicalKey].current;
10450 RGFW_keyboard[physicalKey].current = press;
10452 RGFW_keyCallback(_RGFW.root, physicalKey, mappedKey, _RGFW.root->event.keyMod, press);
10455void 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) {
10456 RGFW_updateKeyModsPro(_RGFW.root, capital, numlock, control, alt, shift, super, scroll);
10459void EMSCRIPTEN_KEEPALIVE Emscripten_onDrop(size_t count) {
10460 if (!(_RGFW.root->_flags & RGFW_windowAllowDND))
10461 return;
10463 _RGFW.root->event.droppedFilesCount = count;
10464 RGFW_eventQueuePushEx(e.type = RGFW_DND;
10465 e.droppedFilesCount = count;
10466 e._win = _RGFW.root);
10467 RGFW_dndCallback(_RGFW.root, _RGFW.root->event.droppedFiles, count);
10470RGFW_bool RGFW_stopCheckEvents_bool = RGFW_FALSE;
10471void RGFW_stopCheckEvents(void) {
10472 RGFW_stopCheckEvents_bool = RGFW_TRUE;
10475void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) {
10476 RGFW_UNUSED(win);
10477 if (waitMS == 0) return;
10479 u32 start = (u32)(((u64)RGFW_getTimeNS()) / 1e+6);
10481 while ((_RGFW.eventLen == 0) && RGFW_stopCheckEvents_bool == RGFW_FALSE && (RGFW_getTimeNS() / 1e+6) - start < waitMS)
10482 emscripten_sleep(0);
10484 RGFW_stopCheckEvents_bool = RGFW_FALSE;
10487void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area){
10488 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
10489 win->buffer = buffer;
10490 win->bufferSize = area;
10491 #ifdef RGFW_OSMESA
10492 win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL);
10493 OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h);
10494 OSMesaPixelStore(OSMESA_Y_UP, 0);
10495 #endif
10496 #else
10497 RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area); /*!< if buffer rendering is not being used */
10498 #endif
10501void EMSCRIPTEN_KEEPALIVE RGFW_makeSetValue(size_t index, char* file) {
10502 /* This seems like a terrible idea, don't replicate this unless you hate yourself or the OS */
10503 /* TODO: find a better way to do this
10504 */
10505 RGFW_STRNCPY((char*)_RGFW.root->event.droppedFiles[index], file, RGFW_MAX_PATH - 1);
10506 _RGFW.root->event.droppedFiles[index][RGFW_MAX_PATH - 1] = '\0';
10509#include <sys/stat.h>
10510#include <sys/types.h>
10511#include <errno.h>
10512#include <stdio.h>
10514void EMSCRIPTEN_KEEPALIVE RGFW_mkdir(char* name) { mkdir(name, 0755); }
10516void EMSCRIPTEN_KEEPALIVE RGFW_writeFile(const char *path, const char *data, size_t len) {
10517 FILE* file = fopen(path, "w+");
10518 if (file == NULL)
10519 return;
10521 fwrite(data, sizeof(char), len, file);
10522 fclose(file);
10525void RGFW_window_initOpenGL(RGFW_window* win) {
10526#if defined(RGFW_OPENGL) && !defined(RGFW_WEBGPU) && !defined(RGFW_OSMESA) && !defined(RGFW_BUFFER)
10527 EmscriptenWebGLContextAttributes attrs;
10528 attrs.alpha = RGFW_GL_HINTS[RGFW_glDepth];
10529 attrs.depth = RGFW_GL_HINTS[RGFW_glAlpha];
10530 attrs.stencil = RGFW_GL_HINTS[RGFW_glStencil];
10531 attrs.antialias = RGFW_GL_HINTS[RGFW_glSamples];
10532 attrs.premultipliedAlpha = EM_TRUE;
10533 attrs.preserveDrawingBuffer = EM_FALSE;
10535 if (RGFW_GL_HINTS[RGFW_glDoubleBuffer] == 0)
10536 attrs.renderViaOffscreenBackBuffer = 0;
10537 else
10538 attrs.renderViaOffscreenBackBuffer = RGFW_GL_HINTS[RGFW_glAuxBuffers];
10540 attrs.failIfMajorPerformanceCaveat = EM_FALSE;
10541 attrs.majorVersion = (RGFW_GL_HINTS[RGFW_glMajor] == 0) ? 1 : RGFW_GL_HINTS[RGFW_glMajor];
10542 attrs.minorVersion = RGFW_GL_HINTS[RGFW_glMinor];
10544 attrs.enableExtensionsByDefault = EM_TRUE;
10545 attrs.explicitSwapControl = EM_TRUE;
10547 emscripten_webgl_init_context_attributes(&attrs);
10548 win->src.ctx = emscripten_webgl_create_context("#canvas", &attrs);
10549 emscripten_webgl_make_context_current(win->src.ctx);
10551 #ifdef LEGACY_GL_EMULATION
10552 EM_ASM("Module.useWebGL = true; GLImmediate.init();");
10553 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context initalized");
10554 #endif
10555 glViewport(0, 0, win->r.w, win->r.h);
10556#endif
10559void RGFW_window_freeOpenGL(RGFW_window* win) {
10560#if defined(RGFW_OPENGL) && !defined(RGFW_WEBGPU) && !defined(RGFW_OSMESA) && !defined(RGFW_OSMESA)
10561 if (win->src.ctx == 0) return;
10562 emscripten_webgl_destroy_context(win->src.ctx);
10563 win->src.ctx = 0;
10564 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context freed");
10565#elif defined(RGFW_OPENGL) && defined(RGFW_OSMESA)
10566 if(win->src.ctx == 0) return;
10567 OSMesaDestroyContext(win->src.ctx);
10568 win->src.ctx = 0;
10569#else
10570 RGFW_UNUSED(win);
10571#endif
10574i32 RGFW_init(void) {
10575#if defined(RGFW_C89) || defined(__cplusplus)
10576 if (_RGFW_init) return 0;
10577 _RGFW_init = RGFW_TRUE;
10578 _RGFW.root = NULL; _RGFW.current = NULL; _RGFW.windowCount = -2; _RGFW.eventLen = 0; _RGFW.eventIndex = 0;
10579#endif
10581 _RGFW.windowCount = 0;
10582 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context initialized");
10583 return 0;
10586RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) {
10587 RGFW_window_basic_init(win, rect, flags);
10588 RGFW_window_initOpenGL(win);
10590 #if defined(RGFW_WEBGPU)
10591 win->src.ctx = wgpuCreateInstance(NULL);
10592 win->src.device = emscripten_webgpu_get_device();
10593 win->src.queue = wgpuDeviceGetQueue(win->src.device);
10594 #endif
10596 emscripten_set_canvas_element_size("#canvas", rect.w, rect.h);
10597 emscripten_set_window_title(name);
10599 /* load callbacks */
10600 emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_resize);
10601 emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, NULL, EM_FALSE, Emscripten_on_fullscreenchange);
10602 emscripten_set_mousemove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousemove);
10603 emscripten_set_touchstart_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchstart);
10604 emscripten_set_touchend_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchend);
10605 emscripten_set_touchmove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchmove);
10606 emscripten_set_touchcancel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchcancel);
10607 emscripten_set_mousedown_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousedown);
10608 emscripten_set_mouseup_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mouseup);
10609 emscripten_set_wheel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_wheel);
10610 emscripten_set_focusin_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusin);
10611 emscripten_set_focusout_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusout);
10612 emscripten_set_gamepadconnected_callback(NULL, 1, Emscripten_on_gamepad);
10613 emscripten_set_gamepaddisconnected_callback(NULL, 1, Emscripten_on_gamepad);
10615 if (flags & RGFW_windowAllowDND) {
10616 win->_flags |= RGFW_windowAllowDND;
10617 }
10619 EM_ASM({
10620 window.addEventListener("keydown",
10621 (event) => {
10622 var key = stringToNewUTF8(event.key); var code = stringToNewUTF8(event.code);
10623 Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta"), event.getModifierState("ScrollLock"));
10624 Module._RGFW_handleKeyEvent(key, code, 1);
10625 _free(key); _free(code);
10626 },
10627 true);
10628 window.addEventListener("keyup",
10629 (event) => {
10630 var key = stringToNewUTF8(event.key); var code = stringToNewUTF8(event.code);
10631 Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta"), event.getModifierState("ScrollLock"));
10632 Module._RGFW_handleKeyEvent(key, code, 0);
10633 _free(key); _free(code);
10634 },
10635 true);
10636 });
10638 EM_ASM({
10639 var canvas = document.getElementById('canvas');
10640 canvas.addEventListener('drop', function(e) {
10641 e.preventDefault();
10642 if (e.dataTransfer.file < 0)
10643 return;
10645 var filenamesArray = [];
10646 var count = e.dataTransfer.files.length;
10648 /* Read and save the files to emscripten's files */
10649 var drop_dir = '.rgfw_dropped_files';
10650 Module._RGFW_mkdir(drop_dir);
10652 for (var i = 0; i < count; i++) {
10653 var file = e.dataTransfer.files[i];
10655 var path = '/' + drop_dir + '/' + file.name.replace("//", '_');
10656 var reader = new FileReader();
10658 reader.onloadend = (e) => {
10659 if (reader.readyState != 2) {
10660 out('failed to read dropped file: '+file.name+': '+reader.error);
10661 }
10662 else {
10663 var data = e.target.result;
10665 _RGFW_writeFile(path, new Uint8Array(data), file.size);
10666 }
10667 };
10669 reader.readAsArrayBuffer(file);
10670 /* This works weird on modern opengl */
10671 var filename = stringToNewUTF8(path);
10673 filenamesArray.push(filename);
10675 Module._RGFW_makeSetValue(i, filename);
10676 }
10678 Module._Emscripten_onDrop(count);
10680 for (var i = 0; i < count; ++i) {
10681 _free(filenamesArray[i]);
10682 }
10683 }, true);
10685 canvas.addEventListener('dragover', function(e) { e.preventDefault(); return false; }, true);
10686 });
10688 RGFW_window_setFlags(win, flags);
10690 if ((flags & RGFW_windowNoInitAPI) == 0) {
10691 RGFW_window_initBuffer(win);
10692 }
10694 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created");
10695 return win;
10698u8 RGFW_rgfwToKeyChar(u32 rgfw_keycode) {
10699 return (u8)rgfw_keycode; /* TODO */
10702RGFW_event* RGFW_window_checkEvent(RGFW_window* win) {
10703 if (win == NULL || ((win->_flags & RGFW_windowFreeOnClose) && (win->_flags & RGFW_EVENT_QUIT))) return NULL;
10704 RGFW_event* ev = RGFW_window_checkEventCore(win);
10705 if (ev) return ev;
10707 emscripten_sample_gamepad_data();
10708 /* check gamepads */
10709 int i;
10710 for (i = 0; (i < emscripten_get_num_gamepads()) && (i < 4); i++) {
10711 if (RGFW_gamepads[i] == 0)
10712 continue;
10713 EmscriptenGamepadEvent gamepadState;
10715 if (emscripten_get_gamepad_status(i, &gamepadState) != EMSCRIPTEN_RESULT_SUCCESS)
10716 break;
10718 /* Register buttons data for every connected gamepad */
10719 int j;
10720 for (j = 0; (j < gamepadState.numButtons) && (j < 16); j++) {
10721 u32 map[] = {
10722 RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadX, RGFW_gamepadY,
10723 RGFW_gamepadL1, RGFW_gamepadR1, RGFW_gamepadL2, RGFW_gamepadR2,
10724 RGFW_gamepadSelect, RGFW_gamepadStart,
10725 RGFW_gamepadL3, RGFW_gamepadR3,
10726 RGFW_gamepadUp, RGFW_gamepadDown, RGFW_gamepadLeft, RGFW_gamepadRight, RGFW_gamepadHome
10727 };
10730 u32 button = map[j];
10731 if (button == 404)
10732 continue;
10734 if (RGFW_gamepadPressed[i][button].current != gamepadState.digitalButton[j]) {
10735 if (gamepadState.digitalButton[j])
10736 win->event.type = RGFW_gamepadButtonPressed;
10737 else
10738 win->event.type = RGFW_gamepadButtonReleased;
10740 win->event.gamepad = i;
10741 win->event.button = map[j];
10743 RGFW_gamepadPressed[i][button].prev = RGFW_gamepadPressed[i][button].current;
10744 RGFW_gamepadPressed[i][button].current = gamepadState.digitalButton[j];
10746 RGFW_gamepadButtonCallback(win, win->event.gamepad, win->event.button, gamepadState.digitalButton[j]);
10747 return &win->event;
10748 }
10749 }
10751 for (j = 0; (j < gamepadState.numAxes) && (j < 4); j += 2) {
10752 win->event.axisesCount = gamepadState.numAxes / 2;
10753 if (RGFW_gamepadAxes[i][(size_t)(j / 2)].x != (i8)(gamepadState.axis[j] * 100.0f) ||
10754 RGFW_gamepadAxes[i][(size_t)(j / 2)].y != (i8)(gamepadState.axis[j + 1] * 100.0f)
10755 ) {
10757 RGFW_gamepadAxes[i][(size_t)(j / 2)].x = (i8)(gamepadState.axis[j] * 100.0f);
10758 RGFW_gamepadAxes[i][(size_t)(j / 2)].y = (i8)(gamepadState.axis[j + 1] * 100.0f);
10759 win->event.axis[(size_t)(j / 2)] = RGFW_gamepadAxes[i][(size_t)(j / 2)];
10761 win->event.type = RGFW_gamepadAxisMove;
10762 win->event.gamepad = i;
10763 win->event.whichAxis = j / 2;
10765 RGFW_gamepadAxisCallback(win, win->event.gamepad, win->event.axis, win->event.axisesCount, win->event.whichAxis);
10766 return &win->event;
10767 }
10768 }
10769 }
10771 return NULL;
10774void RGFW_window_resize(RGFW_window* win, RGFW_area a) {
10775 RGFW_UNUSED(win);
10776 emscripten_set_canvas_element_size("#canvas", a.w, a.h);
10779/* NOTE: I don't know if this is possible */
10780void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) { RGFW_UNUSED(win); RGFW_UNUSED(v); }
10781/* this one might be possible but it looks iffy */
10782RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) { RGFW_UNUSED(channels); RGFW_UNUSED(a); RGFW_UNUSED(icon); return NULL; }
10784void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) { RGFW_UNUSED(win); RGFW_UNUSED(mouse); }
10785void RGFW_freeMouse(RGFW_mouse* mouse) { RGFW_UNUSED(mouse); }
10787RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) {
10788 static const char cursors[16][16] = {
10789 "default", "default", "text", "crosshair",
10790 "pointer", "ew-resize", "ns-resize", "nwse-resize", "nesw-resize",
10791 "move", "not-allowed"
10792 };
10794 RGFW_UNUSED(win);
10795 EM_ASM( { document.getElementById("canvas").style.cursor = UTF8ToString($0); }, cursors[mouse]);
10796 return RGFW_TRUE;
10799RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) {
10800 return RGFW_window_setMouseStandard(win, RGFW_mouseNormal);
10803void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) {
10804 RGFW_window_showMouseFlags(win, show);
10805 if (show)
10806 RGFW_window_setMouseDefault(win);
10807 else
10808 EM_ASM(document.getElementById('canvas').style.cursor = 'none';);
10811RGFW_point RGFW_getGlobalMousePoint(void) {
10812 RGFW_point point;
10813 point.x = EM_ASM_INT({
10814 return window.mouseX || 0;
10815 });
10816 point.y = EM_ASM_INT({
10817 return window.mouseY || 0;
10818 });
10819 return point;
10822void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) {
10823 RGFW_UNUSED(win);
10825 EM_ASM_({
10826 var canvas = document.getElementById('canvas');
10827 if ($0) {
10828 canvas.style.pointerEvents = 'none';
10829 } else {
10830 canvas.style.pointerEvents = 'auto';
10831 }
10832 }, passthrough);
10835void RGFW_writeClipboard(const char* text, u32 textLen) {
10836 RGFW_UNUSED(textLen);
10837 EM_ASM({ navigator.clipboard.writeText(UTF8ToString($0)); }, text);
10841RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) {
10842 RGFW_UNUSED(str); RGFW_UNUSED(strCapacity);
10843 /*
10844 placeholder code for later
10845 I'm not sure if this is possible do the the async stuff
10846 */
10847 return 0;
10850void RGFW_window_swapBuffers_software(RGFW_window* win) {
10851#if defined(RGFW_OSMESA)
10852 EM_ASM_({
10853 var data = Module.HEAPU8.slice($0, $0 + $1 * $2 * 4);
10854 let context = document.getElementById("canvas").getContext("2d");
10855 let image = context.getImageData(0, 0, $1, $2);
10856 image.data.set(data);
10857 context.putImageData(image, 0, $4 - $2);
10858 }, win->buffer, win->bufferSize.w, win->bufferSize.h, win->r.w, win->r.h);
10859#elif defined(RGFW_BUFFER)
10860 EM_ASM_({
10861 var data = Module.HEAPU8.slice($0, $0 + $1 * $2 * 4);
10862 let context = document.getElementById("canvas").getContext("2d");
10863 let image = context.getImageData(0, 0, $1, $2);
10864 image.data.set(data);
10865 context.putImageData(image, 0, 0);
10866 }, win->buffer, win->bufferSize.w, win->bufferSize.h, win->r.w, win->r.h);
10867 emscripten_sleep(0);
10868#else
10869 RGFW_UNUSED(win);
10870#endif
10873void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
10874#if !defined(RGFW_WEBGPU) && !(defined(RGFW_OSMESA) || defined(RGFW_BUFFER))
10875 if (win == NULL)
10876 emscripten_webgl_make_context_current(0);
10877 else
10878 emscripten_webgl_make_context_current(win->src.ctx);
10879#endif
10883void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) {
10884#ifndef RGFW_WEBGPU
10885 emscripten_webgl_commit_frame();
10887#endif
10888 emscripten_sleep(0);
10891#ifndef RGFW_WEBGPU
10892void* RGFW_getCurrent_OpenGL(void) { return (void*)emscripten_webgl_get_current_context(); }
10893#endif
10895#ifndef RGFW_EGL
10896void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { RGFW_UNUSED(win); RGFW_UNUSED(swapInterval); }
10897#endif
10899void RGFW_deinit(void) { _RGFW.windowCount = -1; RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized"); }
10901void RGFW_window_close(RGFW_window* win) {
10902 if ((win->_flags & RGFW_windowNoInitAPI) == 0) RGFW_window_freeOpenGL(win);
10904 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
10905 if ((win->_flags & RGFW_BUFFER_ALLOC))
10906 RGFW_FREE(win->buffer);
10907 #endif
10909 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a window was freed");
10910 _RGFW.windowCount--;
10911 if (_RGFW.windowCount == 0) RGFW_deinit();
10913 RGFW_clipboard_switch(NULL);
10914 RGFW_FREE(win->event.droppedFiles);
10915 if ((win->_flags & RGFW_WINDOW_ALLOC)) {
10916 RGFW_FREE(win);
10917 win = NULL;
10918 }
10921int RGFW_innerWidth(void) { return EM_ASM_INT({ return window.innerWidth; }); }
10922int RGFW_innerHeight(void) { return EM_ASM_INT({ return window.innerHeight; }); }
10924RGFW_area RGFW_getScreenSize(void) {
10925 return RGFW_AREA(RGFW_innerWidth(), RGFW_innerHeight());
10928RGFW_bool RGFW_extensionSupportedPlatform(const char* extension, size_t len) {
10929#ifdef RGFW_OPENGL
10930 return EM_ASM_INT({
10931 var ext = UTF8ToString($0, $1);
10932 var canvas = document.querySelector('canvas');
10933 var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
10934 if (!gl) return 0;
10936 var supported = gl.getSupportedExtensions();
10937 return supported && supported.includes(ext) ? 1 : 0;
10938 }, extension, len);
10939#else
10940 return RGFW_FALSE;
10941#endif
10944RGFW_proc RGFW_getProcAddress(const char* procname) {
10945#ifdef RGFW_OPENGL
10946 return (RGFW_proc)emscripten_webgl_get_proc_address(procname);
10947#else
10948 return NULL
10949#endif
10952void RGFW_sleep(u64 milisecond) {
10953 emscripten_sleep(milisecond);
10956u64 RGFW_getTimerFreq(void) { return (u64)1000; }
10957u64 RGFW_getTimerValue(void) { return emscripten_get_now() * 1e+6; }
10959void RGFW_releaseCursor(RGFW_window* win) {
10960 RGFW_UNUSED(win);
10961 emscripten_exit_pointerlock();
10964void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) {
10965 RGFW_UNUSED(win); RGFW_UNUSED(r);
10967 emscripten_request_pointerlock("#canvas", 1);
10971void RGFW_window_setName(RGFW_window* win, const char* name) {
10972 RGFW_UNUSED(win);
10973 emscripten_set_window_title(name);
10976void RGFW_window_maximize(RGFW_window* win) {
10977 RGFW_ASSERT(win != NULL);
10979 RGFW_area screen = RGFW_getScreenSize();
10980 RGFW_window_move(win, RGFW_POINT(0, 0));
10981 RGFW_window_resize(win, screen);
10984void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) {
10985 RGFW_ASSERT(win != NULL);
10986 if (fullscreen) {
10987 win->_flags |= RGFW_windowFullscreen;
10988 EM_ASM( Module.requestFullscreen(false, true); );
10989 return;
10990 }
10991 win->_flags &= ~(u32)RGFW_windowFullscreen;
10992 EM_ASM( Module.exitFullscreen(false, true); );
10995void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) {
10996 RGFW_UNUSED(win);
10997 EM_ASM({
10998 var element = document.getElementById("canvas");
10999 if (element)
11000 element.style.opacity = $1;
11001 }, "elementId", opacity);
11004/* unsupported functions */
11005void RGFW_window_focus(RGFW_window* win) { RGFW_UNUSED(win); }
11006void RGFW_window_raise(RGFW_window* win) { RGFW_UNUSED(win); }
11007RGFW_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; }
11008RGFW_monitor* RGFW_getMonitors(size_t* len) { RGFW_UNUSED(len); return NULL; }
11009RGFW_monitor RGFW_getPrimaryMonitor(void) { return (RGFW_monitor){}; }
11010void RGFW_window_move(RGFW_window* win, RGFW_point v) { RGFW_UNUSED(win); RGFW_UNUSED(v); }
11011void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win); RGFW_UNUSED(a); }
11012void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win); RGFW_UNUSED(a); }
11013void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win); RGFW_UNUSED(a); }
11014void RGFW_window_minimize(RGFW_window* win) { RGFW_UNUSED(win); }
11015void RGFW_window_restore(RGFW_window* win) { RGFW_UNUSED(win); }
11016void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) { RGFW_UNUSED(win); RGFW_UNUSED(floating); }
11017void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { RGFW_UNUSED(win); RGFW_UNUSED(border); }
11018RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* icon, RGFW_area a, i32 channels, u8 type) { RGFW_UNUSED(win); RGFW_UNUSED(icon); RGFW_UNUSED(a); RGFW_UNUSED(channels); RGFW_UNUSED(type); return RGFW_FALSE; }
11019void RGFW_window_hide(RGFW_window* win) { RGFW_UNUSED(win); }
11020void RGFW_window_show(RGFW_window* win) {RGFW_UNUSED(win); }
11021RGFW_bool RGFW_window_isHidden(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; }
11022RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; }
11023RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; }
11024RGFW_bool RGFW_window_isFloating(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; }
11025RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { RGFW_UNUSED(win); return (RGFW_monitor){}; }
11026#endif
11028/* end of web asm defines */
11030/* unix (macOS, linux, web asm) only stuff */
11031#if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WASM) || defined(RGFW_WAYLAND)
11032#ifndef RGFW_NO_THREADS
11033#include <pthread.h>
11035RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args) {
11036 RGFW_thread t;
11037 pthread_create((pthread_t*) &t, NULL, *ptr, args);
11038 return t;
11040void RGFW_cancelThread(RGFW_thread thread) { pthread_cancel((pthread_t) thread); }
11041void RGFW_joinThread(RGFW_thread thread) { pthread_join((pthread_t) thread, NULL); }
11043#if defined(__linux__)
11044void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { pthread_setschedprio((pthread_t)thread, priority); }
11045#else
11046void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { RGFW_UNUSED(thread); RGFW_UNUSED(priority); }
11047#endif
11048#endif
11050#ifndef RGFW_WASM
11051void RGFW_sleep(u64 ms) {
11052 struct timespec time;
11053 time.tv_sec = 0;
11054 time.tv_nsec = (long int)((double)ms * 1e+6);
11056 #ifndef RGFW_NO_UNIX_CLOCK
11057 nanosleep(&time, NULL);
11058 #endif
11060#endif
11062#endif /* end of unix / mac stuff */
11063#endif /* RGFW_IMPLEMENTATION */
11065#if defined(__cplusplus) && !defined(__EMSCRIPTEN__)
11067#endif
11069#if _MSC_VER
11070 #pragma warning( pop )
11071#endif
index : raylib-jai
---