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