Logo

index : raylib-jai

---

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

        
0/*
1*
2* RGFW 1.7.5-dev
3
4* Copyright (C) 2022-25 ColleagueRiley
5*
6* libpng license
7*
8* This software is provided 'as-is', without any express or implied
9* warranty. In no event will the authors be held liable for any damages
10* arising from the use of this software.
11
12* Permission is granted to anyone to use this software for any purpose,
13* including commercial applications, and to alter it and redistribute it
14* freely, subject to the following restrictions:
15*
16* 1. The origin of this software must not be misrepresented; you must not
17* claim that you wrote the original software. If you use this software
18* in a product, an acknowledgment in the product documentation would be
19* appreciated but is not required.
20* 2. Altered source versions must be plainly marked as such, and must not be
21* misrepresented as being the original software.
22* 3. This notice may not be removed or altered from any source distribution.
23*
24*
25*/
26
27/*
28 (MAKE SURE RGFW_IMPLEMENTATION is in exactly one header or you use -D RGFW_IMPLEMENTATION)
29 #define RGFW_IMPLEMENTATION - makes it so source code is included with header
30*/
31
32/*
33 #define RGFW_IMPLEMENTATION - (required) makes it so the source code is included
34 #define RGFW_DEBUG - (optional) makes it so RGFW prints debug messages and errors when they're found
35 #define RGFW_OSMESA - (optional) use OSmesa as backend (instead of system's opengl api + regular opengl)
36 #define RGFW_BUFFER - (optional) draw directly to (RGFW) window pixel buffer that is drawn to screen (the buffer is in the RGBA format)
37 #define RGFW_EGL - (optional) use EGL for loading an OpenGL context (instead of the system's opengl api)
38 #define RGFW_OPENGL_ES1 - (optional) use EGL to load and use Opengl ES (version 1) for backend rendering (instead of the system's opengl api)
39 This version doesn't work for desktops (I'm pretty sure)
40 #define RGFW_OPENGL_ES2 - (optional) use OpenGL ES (version 2)
41 #define RGFW_OPENGL_ES3 - (optional) use OpenGL ES (version 3)
42 #define RGFW_DIRECTX - (optional) include integration directX functions (windows only)
43 #define RGFW_VULKAN - (optional) include helpful vulkan integration functions and macros
44 #define RGFW_WEBGPU - (optional) use webGPU for rendering (Web ONLY)
45 #define RGFW_NO_API - (optional) don't use any rendering API (no opengl, no vulkan, no directX)
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
67 #define RGFW_ALLOC x - choose the default allocation function (defaults to standard malloc)
68 #define RGFW_FREE x - choose the default deallocation function (defaults to standard free)
69 #define RGFW_USERPTR x - choose the default userptr sent to the malloc call, (NULL by default)
70
71 #define RGFW_EXPORT - use when building RGFW
72 #define RGFW_IMPORT - use when linking with RGFW (not as a single-header)
73
74 #define RGFW_USE_INT - force the use c-types rather than stdint.h (for systems that might not have stdint.h (msvc))
75 #define RGFW_bool x - choose what type to use for bool, by default u32 is used
76*/
77
78/*
79Example to get you started :
80
81linux : gcc main.c -lX11 -lXrandr -lGL
82windows : gcc main.c -lopengl32 -lgdi32
83macos : gcc main.c -framework Cocoa -framework CoreVideo -framework OpenGL -framework IOKit
84
85#define RGFW_IMPLEMENTATION
86#include "RGFW.h"
87
88u8 icon[4 * 3 * 3] = {0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF};
89
90int main() {
91 RGFW_window* win = RGFW_createWindow("name", RGFW_RECT(100, 100, 500, 500), (u64)0);
92
93 RGFW_window_setIcon(win, icon, RGFW_AREA(3, 3), 4);
94
95 while (RGFW_window_shouldClose(win) == RGFW_FALSE) {
96 while (RGFW_window_checkEvent(win)) {
97 if (win->event.type == RGFW_quit || RGFW_isPressed(win, RGFW_escape))
98 break;
99 }
100
101 RGFW_window_swapBuffers(win);
102
103 glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
104 glClear(GL_COLOR_BUFFER_BIT);
105 }
106
107 RGFW_window_close(win);
108}
109
110 compiling :
111
112 if you wish to compile the library all you have to do is create a new file with this in it
113
114 rgfw.c
115 #define RGFW_IMPLEMENTATION
116 #include "RGFW.h"
117
118 You may also want to add
119 `#define RGFW_EXPORT` when compiling and
120 `#define RGFW_IMPORT`when linking RGFW on it's own:
121 this reduces inline functions and prevents bloat in the object file
122
123 then you can use gcc (or whatever compile you wish to use) to compile the library into object file
124
125 ex. gcc -c RGFW.c -fPIC
126
127 after you compile the library into an object file, you can also turn the object file into an static or shared library
128
129 (commands ar and gcc can be replaced with whatever equivalent your system uses)
130
131 static : ar rcs RGFW.a RGFW.o
132 shared :
133 windows:
134 gcc -shared RGFW.o -lopengl32 -lgdi32 -o RGFW.dll
135 linux:
136 gcc -shared RGFW.o -lX11 -lGL -lXrandr -o RGFW.so
137 macos:
138 gcc -shared RGFW.o -framework CoreVideo -framework Cocoa -framework OpenGL -framework IOKit
139*/
140
141
142
143/*
144 Credits :
145 EimaMei/Sacode : Much of the code for creating windows using winapi, Wrote the Silicon library, helped with MacOS Support, siliapp.h -> referencing
146
147 stb - This project is heavily inspired by the stb single header files
148
149 GLFW:
150 certain parts of winapi and X11 are very poorly documented,
151 GLFW's source code was referenced and used throughout the project.
152
153 contributors : (feel free to put yourself here if you contribute)
154 krisvers -> code review
155 EimaMei (SaCode) -> code review
156 Code-Nycticebus -> bug fixes
157 Rob Rohan -> X11 bugs and missing features, MacOS/Cocoa fixing memory issues/bugs
158 AICDG (@THISISAGOODNAME) -> vulkan support (example)
159 @Easymode -> support, testing/debugging, bug fixes and reviews
160 Joshua Rowe (omnisci3nce) - bug fix, review (macOS)
161 @lesleyrs -> bug fix, review (OpenGL)
162 Nick Porcino (meshula) - testing, organization, review (MacOS, examples)
163 @DarekParodia -> code review (X11) (C++)
164*/
165
166#if _MSC_VER
167 #pragma comment(lib, "gdi32")
168 #pragma comment(lib, "shell32")
169 #pragma comment(lib, "User32")
170 #pragma warning( push )
171 #pragma warning( disable : 4996 4191 4127)
172 #if _MSC_VER < 600
173 #define RGFW_C89
174 #endif
175#else
176 #if defined(__STDC__) && !defined(__STDC_VERSION__)
177 #define RGFW_C89
178 #endif
179#endif
180
181#ifndef RGFW_USERPTR
182 #define RGFW_USERPTR NULL
183#endif
184
185#ifndef RGFW_UNUSED
186 #define RGFW_UNUSED(x) (void)(x)
187#endif
188
189#ifndef RGFW_ROUND
190 #define RGFW_ROUND(x) (i32)((x) >= 0 ? (x) + 0.5f : (x) - 0.5f)
191#endif
192
193#ifndef RGFW_ALLOC
194 #include <stdlib.h>
195 #define RGFW_ALLOC malloc
196 #define RGFW_FREE free
197#endif
198
199#ifndef RGFW_ASSERT
200 #include <assert.h>
201 #define RGFW_ASSERT assert
202#endif
203
204#if !defined(RGFW_MEMCPY) || !defined(RGFW_STRNCMP) || !defined(RGFW_STRNCPY) || !defined(RGFW_MEMSET)
205 #include <string.h>
206#endif
207
208#ifndef RGFW_MEMSET
209 #define RGFW_MEMSET(ptr, value, num) memset(ptr, value, num)
210#endif
211
212#ifndef RGFW_MEMCPY
213 #define RGFW_MEMCPY(dist, src, len) memcpy(dist, src, len)
214#endif
215
216#ifndef RGFW_STRNCMP
217 #define RGFW_STRNCMP(s1, s2, max) strncmp(s1, s2, max)
218#endif
219
220#ifndef RGFW_STRNCPY
221 #define RGFW_STRNCPY(dist, src, len) strncpy(dist, src, len)
222#endif
223
224#ifndef RGFW_STRSTR
225 #define RGFW_STRSTR(str, substr) strstr(str, substr)
226#endif
227
228#ifndef RGFW_STRTOL
229 /* required for X11 XDnD and X11 Monitor DPI */
230 #include <stdlib.h>
231 #define RGFW_STRTOL(str, endptr, base) strtol(str, endptr, base)
232 #define RGFW_ATOF(num) atof(num)
233#endif
234
235#ifdef RGFW_WIN95 /* for windows 95 testing (not that it really works) */
236 #define RGFW_NO_MONITOR
237 #define RGFW_NO_PASSTHROUGH
238#endif
239
240#if defined(RGFW_EXPORT) || defined(RGFW_IMPORT)
241 #if defined(_WIN32)
242 #if defined(__TINYC__) && (defined(RGFW_EXPORT) || defined(RGFW_IMPORT))
243 #define __declspec(x) __attribute__((x))
244 #endif
245
246 #if defined(RGFW_EXPORT)
247 #define RGFWDEF __declspec(dllexport)
248 #else
249 #define RGFWDEF __declspec(dllimport)
250 #endif
251 #else
252 #if defined(RGFW_EXPORT)
253 #define RGFWDEF __attribute__((visibility("default")))
254 #endif
255 #endif
256 #ifndef RGFWDEF
257 #define RGFWDEF
258 #endif
259#endif
260
261#ifndef RGFWDEF
262 #ifdef RGFW_C89
263 #define RGFWDEF __inline
264 #else
265 #define RGFWDEF inline
266 #endif
267#endif
268
269#ifndef RGFW_ENUM
270 #define RGFW_ENUM(type, name) type name; enum
271#endif
272
273
274#if defined(__cplusplus) && !defined(__EMSCRIPTEN__)
275 extern "C" {
276#endif
277
278 /* makes sure the header file part is only defined once by default */
279#ifndef RGFW_HEADER
280
281#define RGFW_HEADER
282
283#include <stddef.h>
284#ifndef RGFW_INT_DEFINED
285 #ifdef RGFW_USE_INT /* optional for any system that might not have stdint.h */
286 typedef unsigned char u8;
287 typedef signed char i8;
288 typedef unsigned short u16;
289 typedef signed short i16;
290 typedef unsigned long int u32;
291 typedef signed long int i32;
292 typedef unsigned long long u64;
293 typedef signed long long i64;
294 #else /* use stdint standard types instead of c "standard" types */
295 #include <stdint.h>
296
297 typedef uint8_t u8;
298 typedef int8_t i8;
299 typedef uint16_t u16;
300 typedef int16_t i16;
301 typedef uint32_t u32;
302 typedef int32_t i32;
303 typedef uint64_t u64;
304 typedef int64_t i64;
305 #endif
306 #define RGFW_INT_DEFINED
307#endif
308
309#ifndef RGFW_BOOL_DEFINED
310 #define RGFW_BOOL_DEFINED
311 typedef u8 RGFW_bool;
312#endif
313
314#define RGFW_BOOL(x) (RGFW_bool)((x) ? RGFW_TRUE : RGFW_FALSE) /* force an value to be 0 or 1 */
315#define RGFW_TRUE (RGFW_bool)1
316#define RGFW_FALSE (RGFW_bool)0
317
318/* these OS macros look better & are standardized */
319/* plus it helps with cross-compiling */
320
321#ifdef __EMSCRIPTEN__
322 #define RGFW_WASM
323
324 #if !defined(RGFW_NO_API) && !defined(RGFW_WEBGPU)
325 #define RGFW_OPENGL
326 #endif
327
328 #ifdef RGFW_EGL
329 #undef RGFW_EGL
330 #endif
331
332 #include <emscripten/html5.h>
333 #include <emscripten/key_codes.h>
334
335 #ifdef RGFW_WEBGPU
336 #include <emscripten/html5_webgpu.h>
337 #endif
338#endif
339
340#if defined(RGFW_X11) && defined(__APPLE__) && !defined(RGFW_CUSTOM_BACKEND)
341 #define RGFW_MACOS_X11
342 #define RGFW_UNIX
343 #undef __APPLE__
344#endif
345
346#if defined(_WIN32) && !defined(RGFW_X11) && !defined(RGFW_UNIX) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND) /* (if you're using X11 on windows some how) */
347 #define RGFW_WINDOWS
348 /* make sure the correct architecture is defined */
349 #if defined(_WIN64)
350 #define _AMD64_
351 #undef _X86_
352 #else
353 #undef _AMD64_
354 #ifndef _X86_
355 #define _X86_
356 #endif
357 #endif
358
359 #ifndef RGFW_NO_XINPUT
360 #ifdef __MINGW32__ /* try to find the right header */
361 #include <xinput.h>
362 #else
363 #include <XInput.h>
364 #endif
365 #endif
366#endif
367#if defined(RGFW_WAYLAND)
368 #define RGFW_DEBUG /* wayland will be in debug mode by default for now */
369 #if !defined(RGFW_NO_API) && (!defined(RGFW_BUFFER) || defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA)
370 #define RGFW_EGL
371 #define RGFW_OPENGL
372 #include <wayland-egl.h>
373 #endif
374
375 #define RGFW_UNIX
376 #include <wayland-client.h>
377#endif
378#if !defined(RGFW_NO_X11) && (defined(__unix__) || defined(RGFW_MACOS_X11) || defined(RGFW_X11)) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND)
379 #define RGFW_MACOS_X11
380 #define RGFW_X11
381 #define RGFW_UNIX
382 #include <X11/Xlib.h>
383 #include <X11/Xutil.h>
384#elif defined(__APPLE__) && !defined(RGFW_MACOS_X11) && !defined(RGFW_X11) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND)
385 #define RGFW_MACOS
386 #if !defined(RGFW_BUFFER_BGR)
387 #define RGFW_BUFFER_BGR
388 #else
389 #undef RGFW_BUFFER_BGR
390 #endif
391#endif
392
393#if (defined(RGFW_OPENGL_ES1) || defined(RGFW_OPENGL_ES2) || defined(RGFW_OPENGL_ES3)) && !defined(RGFW_EGL)
394 #define RGFW_EGL
395#endif
396
397#if !defined(RGFW_OSMESA) && !defined(RGFW_EGL) && !defined(RGFW_OPENGL) && !defined(RGFW_DIRECTX) && !defined(RGFW_BUFFER) && !defined(RGFW_NO_API)
398 #define RGFW_OPENGL
399#endif
400
401#ifdef RGFW_EGL
402 #include <EGL/egl.h>
403#elif defined(RGFW_OSMESA)
404 #ifdef RGFW_WINDOWS
405 #define OEMRESOURCE
406 #include <GL/gl.h>
407 #ifndef GLAPIENTRY
408 #define GLAPIENTRY APIENTRY
409 #endif
410 #ifndef GLAPI
411 #define GLAPI WINGDIAPI
412 #endif
413 #endif
414
415 #ifndef __APPLE__
416 #include <GL/osmesa.h>
417 #else
418 #include <OpenGL/osmesa.h>
419 #endif
420#endif
421
422#if (defined(RGFW_OPENGL) || defined(RGFW_WEGL)) && defined(_MSC_VER)
423 #pragma comment(lib, "opengl32")
424#endif
425
426#if defined(RGFW_OPENGL) && defined(RGFW_X11)
427 #ifndef GLX_MESA_swap_control
428 #define GLX_MESA_swap_control
429 #endif
430 #include <GL/glx.h> /* GLX defs, xlib.h, gl.h */
431#endif
432
433#define RGFW_COCOA_FRAME_NAME NULL
434
435/*! (unix) Toggle use of wayland. This will be on by default if you use `RGFW_WAYLAND` (if you don't use RGFW_WAYLAND, you don't expose WAYLAND functions)
436 this is mostly used to allow you to force the use of XWayland
437*/
438RGFWDEF void RGFW_useWayland(RGFW_bool wayland);
439RGFWDEF RGFW_bool RGFW_usingWayland(void);
440/*
441 regular RGFW stuff
442*/
443
444#define RGFW_key u8
445
446typedef RGFW_ENUM(u8, RGFW_eventType) {
447 /*! event codes */
448 RGFW_eventNone = 0, /*!< no event has been sent */
449 RGFW_keyPressed, /* a key has been pressed */
450 RGFW_keyReleased, /*!< a key has been released */
451 /*! key event note
452 the code of the key pressed is stored in
453 RGFW_event.key
454 !!Keycodes defined at the bottom of the RGFW_HEADER part of this file!!
455
456 while a string version is stored in
457 RGFW_event.KeyString
458
459 RGFW_event.keyMod holds the current keyMod
460 this means if CapsLock, NumLock are active or not
461 */
462 RGFW_mouseButtonPressed, /*!< a mouse button has been pressed (left,middle,right) */
463 RGFW_mouseButtonReleased, /*!< a mouse button has been released (left,middle,right) */
464 RGFW_mousePosChanged, /*!< the position of the mouse has been changed */
465 /*! mouse event note
466 the x and y of the mouse can be found in the vector, RGFW_event.point
467
468 RGFW_event.button holds which mouse button was pressed
469 */
470 RGFW_gamepadConnected, /*!< a gamepad was connected */
471 RGFW_gamepadDisconnected, /*!< a gamepad was disconnected */
472 RGFW_gamepadButtonPressed, /*!< a gamepad button was pressed */
473 RGFW_gamepadButtonReleased, /*!< a gamepad button was released */
474 RGFW_gamepadAxisMove, /*!< an axis of a gamepad was moved */
475 /*! gamepad event note
476 RGFW_event.gamepad holds which gamepad was altered, if any
477 RGFW_event.button holds which gamepad button was pressed
478
479 RGFW_event.axis holds the data of all the axises
480 RGFW_event.axisesCount says how many axises there are
481 */
482 RGFW_windowMoved, /*!< the window was moved (by the user) */
483 RGFW_windowResized, /*!< the window was resized (by the user), [on WASM this means the browser was resized] */
484 RGFW_focusIn, /*!< window is in focus now */
485 RGFW_focusOut, /*!< window is out of focus now */
486 RGFW_mouseEnter, /* mouse entered the window */
487 RGFW_mouseLeave, /* mouse left the window */
488 RGFW_windowRefresh, /* The window content needs to be refreshed */
489
490 /* attribs change event note
491 The event data is sent straight to the window structure
492 with win->r.x, win->r.y, win->r.w and win->r.h
493 */
494 RGFW_quit, /*!< the user clicked the quit button */
495 RGFW_DND, /*!< a file has been dropped into the window */
496 RGFW_DNDInit, /*!< the start of a dnd event, when the place where the file drop is known */
497 /* dnd data note
498 The x and y coords of the drop are stored in the vector RGFW_event.point
499
500 RGFW_event.droppedFilesCount holds how many files were dropped
501
502 This is also the size of the array which stores all the dropped file string,
503 RGFW_event.droppedFiles
504 */
505 RGFW_windowMaximized, /*!< the window was maximized */
506 RGFW_windowMinimized, /*!< the window was minimized */
507 RGFW_windowRestored, /*!< the window was restored */
508 RGFW_scaleUpdated /*!< content scale factor changed */
509};
510
511/*! mouse button codes (RGFW_event.button) */
512typedef RGFW_ENUM(u8, RGFW_mouseButton) {
513 RGFW_mouseLeft = 0, /*!< left mouse button is pressed */
514 RGFW_mouseMiddle, /*!< mouse-wheel-button is pressed */
515 RGFW_mouseRight, /*!< right mouse button is pressed */
516 RGFW_mouseScrollUp, /*!< mouse wheel is scrolling up */
517 RGFW_mouseScrollDown, /*!< mouse wheel is scrolling down */
518 RGFW_mouseMisc1, RGFW_mouseMisc2, RGFW_mouseMisc3, RGFW_mouseMisc4, RGFW_mouseMisc5,
519 RGFW_mouseFinal
520};
521
522#ifndef RGFW_MAX_PATH
523#define RGFW_MAX_PATH 260 /* max length of a path (for dnd) */
524#endif
525#ifndef RGFW_MAX_DROPS
526#define RGFW_MAX_DROPS 260 /* max items you can drop at once */
527#endif
528
529#define RGFW_BIT(x) (1 << x)
530
531/* for RGFW_event.lockstate */
532typedef RGFW_ENUM(u8, RGFW_keymod) {
533 RGFW_modCapsLock = RGFW_BIT(0),
534 RGFW_modNumLock = RGFW_BIT(1),
535 RGFW_modControl = RGFW_BIT(2),
536 RGFW_modAlt = RGFW_BIT(3),
537 RGFW_modShift = RGFW_BIT(4),
538 RGFW_modSuper = RGFW_BIT(5),
539 RGFW_modScrollLock = RGFW_BIT(6)
540};
541
542/*! gamepad button codes (based on xbox/playstation), you may need to change these values per controller */
543typedef RGFW_ENUM(u8, RGFW_gamepadCodes) {
544 RGFW_gamepadNone = 0, /*!< or PS X button */
545 RGFW_gamepadA, /*!< or PS X button */
546 RGFW_gamepadB, /*!< or PS circle button */
547 RGFW_gamepadY, /*!< or PS triangle button */
548 RGFW_gamepadX, /*!< or PS square button */
549 RGFW_gamepadStart, /*!< start button */
550 RGFW_gamepadSelect, /*!< select button */
551 RGFW_gamepadHome, /*!< home button */
552 RGFW_gamepadUp, /*!< dpad up */
553 RGFW_gamepadDown, /*!< dpad down */
554 RGFW_gamepadLeft, /*!< dpad left */
555 RGFW_gamepadRight, /*!< dpad right */
556 RGFW_gamepadL1, /*!< left bump */
557 RGFW_gamepadL2, /*!< left trigger */
558 RGFW_gamepadR1, /*!< right bumper */
559 RGFW_gamepadR2, /*!< right trigger */
560 RGFW_gamepadL3, /* left thumb stick */
561 RGFW_gamepadR3, /*!< right thumb stick */
562 RGFW_gamepadFinal
563};
564
565/*! basic vector type, if there's not already a point/vector type of choice */
566#ifndef RGFW_point
567 typedef struct RGFW_point { i32 x, y; } RGFW_point;
568#endif
569
570/*! basic rect type, if there's not already a rect type of choice */
571#ifndef RGFW_rect
572 typedef struct RGFW_rect { i32 x, y, w, h; } RGFW_rect;
573#endif
574
575/*! basic area type, if there's not already a area type of choice */
576#ifndef RGFW_area
577 typedef struct RGFW_area { u32 w, h; } RGFW_area;
578#endif
579
580#if defined(__cplusplus) && !defined(__APPLE__)
581#define RGFW_POINT(x, y) {(i32)x, (i32)y}
582#define RGFW_RECT(x, y, w, h) {(i32)x, (i32)y, (i32)w, (i32)h}
583#define RGFW_AREA(w, h) {(u32)w, (u32)h}
584#else
585#define RGFW_POINT(x, y) (RGFW_point){(i32)(x), (i32)(y)}
586#define RGFW_RECT(x, y, w, h) (RGFW_rect){(i32)(x), (i32)(y), (i32)(w), (i32)(h)}
587#define RGFW_AREA(w, h) (RGFW_area){(u32)(w), (u32)(h)}
588#endif
589
590#ifndef RGFW_NO_MONITOR
591 /* monitor mode data | can be changed by the user (with functions)*/
592 typedef struct RGFW_monitorMode {
593 RGFW_area area; /*!< monitor workarea size */
594 u32 refreshRate; /*!< monitor refresh rate */
595 u8 red, blue, green;
596 } RGFW_monitorMode;
597
598 /*! structure for monitor data */
599 typedef struct RGFW_monitor {
600 i32 x, y; /*!< x - y of the monitor workarea */
601 char name[128]; /*!< monitor name */
602 float scaleX, scaleY; /*!< monitor content scale */
603 float pixelRatio; /*!< pixel ratio for monitor (1.0 for regular, 2.0 for hiDPI) */
604 float physW, physH; /*!< monitor physical size in inches */
605
606 RGFW_monitorMode mode;
607 } RGFW_monitor;
608
609 /*! get an array of all the monitors (max 6) */
610 RGFWDEF RGFW_monitor* RGFW_getMonitors(size_t* len);
611 /*! get the primary monitor */
612 RGFWDEF RGFW_monitor RGFW_getPrimaryMonitor(void);
613
614 typedef RGFW_ENUM(u8, RGFW_modeRequest) {
615 RGFW_monitorScale = RGFW_BIT(0), /*!< scale the monitor size */
616 RGFW_monitorRefresh = RGFW_BIT(1), /*!< change the refresh rate */
617 RGFW_monitorRGB = RGFW_BIT(2), /*!< change the monitor RGB bits size */
618 RGFW_monitorAll = RGFW_monitorScale | RGFW_monitorRefresh | RGFW_monitorRGB
619 };
620
621 /*! request a specific mode */
622 RGFWDEF RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request);
623 /*! check if 2 monitor modes are the same */
624 RGFWDEF RGFW_bool RGFW_monitorModeCompare(RGFW_monitorMode mon, RGFW_monitorMode mon2, RGFW_modeRequest request);
625#endif
626
627/* RGFW mouse loading */
628typedef void RGFW_mouse;
629
630/*!< loads mouse icon from bitmap (similar to RGFW_window_setIcon). Icon NOT resized by default */
631RGFWDEF RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels);
632/*!< frees RGFW_mouse data */
633RGFWDEF void RGFW_freeMouse(RGFW_mouse* mouse);
634
635/* NOTE: some parts of the data can represent different things based on the event (read comments in RGFW_event struct) */
636/*! Event structure for checking/getting events */
637typedef struct RGFW_event {
638 RGFW_eventType type; /*!< which event has been sent?*/
639 RGFW_point point; /*!< mouse x, y of event (or drop point) */
640 RGFW_point vector; /*!< raw mouse movement */
641 float scaleX, scaleY; /*!< DPI scaling */
642
643 RGFW_key key; /*!< the physical key of the event, refers to where key is physically !!Keycodes defined at the bottom of the RGFW_HEADER part of this file!! */
644 u8 keyChar; /*!< mapped key char of the event */
645
646 RGFW_bool repeat; /*!< key press event repeated (the key is being held) */
647 RGFW_keymod keyMod;
648
649 u8 button; /* !< which mouse (or gamepad) button was pressed */
650 double scroll; /*!< the raw mouse scroll value */
651
652 u16 gamepad; /*! which gamepad this event applies to (if applicable to any) */
653 u8 axisesCount; /*!< number of axises */
654
655 u8 whichAxis; /* which axis was effected */
656 RGFW_point axis[4]; /*!< x, y of axises (-100 to 100) */
657
658 /*! drag and drop data */
659 /* 260 max paths with a max length of 260 */
660 char** droppedFiles; /*!< dropped files */
661 size_t droppedFilesCount; /*!< house many files were dropped */
662
663 void* _win; /*!< the window this event applies too (for event queue events) */
664} RGFW_event;
665
666/*! source data for the window (used by the APIs) */
667#ifdef RGFW_WINDOWS
668typedef struct RGFW_window_src {
669 HWND window; /*!< source window */
670 HDC hdc; /*!< source HDC */
671 u32 hOffset; /*!< height offset for window */
672 HICON hIconSmall, hIconBig; /*!< source window icons */
673 #if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL)
674 HGLRC ctx; /*!< source graphics context */
675 #elif defined(RGFW_OSMESA)
676 OSMesaContext ctx;
677 #elif defined(RGFW_EGL)
678 EGLSurface EGL_surface;
679 EGLDisplay EGL_display;
680 EGLContext EGL_context;
681 #endif
682
683 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
684 HDC hdcMem;
685 HBITMAP bitmap;
686 u8* bitmapBits;
687 #endif
688 RGFW_area maxSize, minSize, aspectRatio; /*!< for setting max/min resize (RGFW_WINDOWS) */
689} RGFW_window_src;
690#elif defined(RGFW_UNIX)
691typedef struct RGFW_window_src {
692#if defined(RGFW_X11)
693 Display* display; /*!< source display */
694 Window window; /*!< source window */
695 #if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL)
696 GLXContext ctx; /*!< source graphics context */
697 GLXFBConfig bestFbc;
698 #elif defined(RGFW_OSMESA)
699 OSMesaContext ctx;
700 #elif defined(RGFW_EGL)
701 EGLSurface EGL_surface;
702 EGLDisplay EGL_display;
703 EGLContext EGL_context;
704 #endif
705
706 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
707 XImage* bitmap;
708 #endif
709 GC gc;
710 XVisualInfo visual;
711 #ifdef RGFW_ADVANCED_SMOOTH_RESIZE
712 i64 counter_value;
713 XID counter;
714 #endif
715 RGFW_rect r;
716#endif /* RGFW_X11 */
717#if defined(RGFW_WAYLAND)
718 struct wl_display* wl_display;
719 struct wl_surface* surface;
720 struct wl_buffer* wl_buffer;
721 struct wl_keyboard* keyboard;
722
723 struct wl_compositor* compositor;
724 struct xdg_surface* xdg_surface;
725 struct xdg_toplevel* xdg_toplevel;
726 struct zxdg_toplevel_decoration_v1* decoration;
727 struct xdg_wm_base* xdg_wm_base;
728 struct wl_shm* shm;
729 struct wl_seat *seat;
730 u8* buffer;
731 #if defined(RGFW_EGL)
732 struct wl_egl_window* eglWindow;
733 #endif
734 #if defined(RGFW_EGL) && !defined(RGFW_X11)
735 EGLSurface EGL_surface;
736 EGLDisplay EGL_display;
737 EGLContext EGL_context;
738 #elif defined(RGFW_OSMESA) && !defined(RGFW_X11)
739 OSMesaContext ctx;
740 #endif
741#endif /* RGFW_WAYLAND */
742} RGFW_window_src;
743#endif /* RGFW_UNIX */
744#if defined(RGFW_MACOS)
745typedef struct RGFW_window_src {
746 void* window;
747#if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL)
748 void* ctx; /*!< source graphics context */
749#elif defined(RGFW_OSMESA)
750 OSMesaContext ctx;
751#elif defined(RGFW_EGL)
752 EGLSurface EGL_surface;
753 EGLDisplay EGL_display;
754 EGLContext EGL_context;
755#endif
756
757 void* view; /* apple viewpoint thingy */
758 void* mouse;
759#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
760#endif
761} RGFW_window_src;
762#elif defined(RGFW_WASM)
763typedef struct RGFW_window_src {
764 #if defined(RGFW_WEBGPU)
765 WGPUInstance ctx;
766 WGPUDevice device;
767 WGPUQueue queue;
768 #elif defined(RGFW_OSMESA)
769 OSMesaContext ctx;
770 #else
771 EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx;
772 #endif
773} RGFW_window_src;
774#endif
775
776/*! Optional arguments for making a windows */
777typedef RGFW_ENUM(u32, RGFW_windowFlags) {
778 RGFW_windowNoInitAPI = RGFW_BIT(0), /* do NOT init an API (including the software rendering buffer) (mostly for bindings. you can also use `#define RGFW_NO_API`) */
779 RGFW_windowNoBorder = RGFW_BIT(1), /*!< the window doesn't have a border */
780 RGFW_windowNoResize = RGFW_BIT(2), /*!< the window cannot be resized by the user */
781 RGFW_windowAllowDND = RGFW_BIT(3), /*!< the window supports drag and drop */
782 RGFW_windowHideMouse = RGFW_BIT(4), /*! the window should hide the mouse (can be toggled later on using `RGFW_window_mouseShow`) */
783 RGFW_windowFullscreen = RGFW_BIT(5), /*!< the window is fullscreen by default */
784 RGFW_windowTransparent = RGFW_BIT(6), /*!< the window is transparent (only properly works on X11 and MacOS, although it's meant for for windows) */
785 RGFW_windowCenter = RGFW_BIT(7), /*! center the window on the screen */
786 RGFW_windowOpenglSoftware = RGFW_BIT(8), /*! use OpenGL software rendering */
787 RGFW_windowCocoaCHDirToRes = RGFW_BIT(9), /*! (cocoa only), change directory to resource folder */
788 RGFW_windowScaleToMonitor = RGFW_BIT(10), /*! scale the window to the screen */
789 RGFW_windowHide = RGFW_BIT(11), /*! the window is hidden */
790 RGFW_windowMaximize = RGFW_BIT(12),
791 RGFW_windowCenterCursor = RGFW_BIT(13),
792 RGFW_windowFloating = RGFW_BIT(14), /*!< create a floating window */
793 RGFW_windowFreeOnClose = RGFW_BIT(15), /*!< free (RGFW_window_close) the RGFW_window struct when the window is closed (by the end user) */
794 RGFW_windowFocusOnShow = RGFW_BIT(16), /*!< focus the window when it's shown */
795 RGFW_windowMinimize = RGFW_BIT(17), /*!< focus the window when it's shown */
796 RGFW_windowFocus = RGFW_BIT(18), /*!< if the window is in focus */
797 RGFW_windowedFullscreen = RGFW_windowNoBorder | RGFW_windowMaximize
798};
799
800typedef struct RGFW_window {
801 RGFW_window_src src; /*!< src window data */
802
803#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
804 u8* buffer; /*!< buffer for non-GPU systems (OSMesa, basic software rendering) */
805 /* when rendering using RGFW_BUFFER, the buffer is in the RGBA format */
806 RGFW_area bufferSize;
807#endif
808 void* userPtr; /* ptr for usr data */
809
810 RGFW_event event; /*!< current event */
811
812 RGFW_rect r; /*!< the x, y, w and h of the struct */
813
814 /*! which key RGFW_window_shouldClose checks. Settting this to RGFW_keyNULL disables the feature. */
815 RGFW_key exitKey;
816 RGFW_point _lastMousePoint; /*!< last cusor point (for raw mouse data) */
817
818 u32 _flags; /*!< windows flags (for RGFW to check) */
819 RGFW_rect _oldRect; /*!< rect before fullscreen */
820} RGFW_window; /*!< window structure for managing the window */
821
822#if defined(RGFW_X11) || defined(RGFW_MACOS)
823 typedef u64 RGFW_thread; /*!< thread type unix */
824#else
825 typedef void* RGFW_thread; /*!< thread type for windows */
826#endif
827
828/*! scale monitor to window size */
829RGFWDEF RGFW_bool RGFW_monitor_scaleToWindow(RGFW_monitor mon, RGFW_window* win);
830
831/** * @defgroup Window_management
832* @{ */
833
834
835/*!
836 * the class name for X11 and WinAPI. apps with the same class will be grouped by the WM
837 * by default the class name will == the root window's name
838*/
839RGFWDEF void RGFW_setClassName(const char* name);
840RGFWDEF void RGFW_setXInstName(const char* name); /*!< X11 instance name (window name will by used by default) */
841
842/*! (cocoa only) change directory to resource folder */
843RGFWDEF void RGFW_moveToMacOSResourceDir(void);
844
845/* NOTE: (windows) if the executable has an icon resource named RGFW_ICON, it will be set as the initial icon for the window */
846
847RGFWDEF RGFW_window* RGFW_createWindow(
848 const char* name, /* name of the window */
849 RGFW_rect rect, /* rect of window */
850 RGFW_windowFlags flags /* extra arguments ((u32)0 means no flags used)*/
851); /*!< function to create a window and struct */
852
853RGFWDEF RGFW_window* RGFW_createWindowPtr(
854 const char* name, /* name of the window */
855 RGFW_rect rect, /* rect of window */
856 RGFW_windowFlags flags, /* extra arguments (NULL / (u32)0 means no flags used) */
857 RGFW_window* win /* ptr to the window struct you want to use */
858); /*!< function to create a window (without allocating a window struct) */
859
860RGFWDEF void RGFW_window_initBuffer(RGFW_window* win);
861RGFWDEF void RGFW_window_initBufferSize(RGFW_window* win, RGFW_area area);
862RGFWDEF void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area);
863
864/*! set the window flags (will undo flags if they don't match the old ones) */
865RGFWDEF void RGFW_window_setFlags(RGFW_window* win, RGFW_windowFlags);
866
867/*! get the size of the screen to an area struct */
868RGFWDEF RGFW_area RGFW_getScreenSize(void);
869
870
871/*!
872 this function checks an *individual* event (and updates window structure attributes)
873 this means, using this function without a while loop may cause event lag
874
875 ex.
876
877 while (RGFW_window_checkEvent(win) != NULL) [this keeps checking events until it reaches the last one]
878
879 this function is optional if you choose to use event callbacks,
880 although you still need some way to tell RGFW to process events eg. `RGFW_window_checkEvents`
881*/
882
883RGFWDEF RGFW_event* RGFW_window_checkEvent(RGFW_window* win); /*!< check current event (returns a pointer to win->event or NULL if there is no event)*/
884
885/*!
886 for RGFW_window_eventWait and RGFW_window_checkEvents
887 waitMS -> Allows the function to keep checking for events even after `RGFW_window_checkEvent == NULL`
888 if waitMS == 0, the loop will not wait for events
889 if waitMS > 0, the loop will wait that many miliseconds after there are no more events until it returns
890 if waitMS == -1 or waitMS == the max size of an unsigned 32-bit int, the loop will not return until it gets another event
891*/
892typedef RGFW_ENUM(i32, RGFW_eventWait) {
893 RGFW_eventNoWait = 0,
894 RGFW_eventWaitNext = -1
895};
896
897/*! sleep until RGFW gets an event or the timer ends (defined by OS) */
898RGFWDEF void RGFW_window_eventWait(RGFW_window* win, i32 waitMS);
899
900/*!
901 check all the events until there are none left.
902 This should only be used if you're using callbacks only
903*/
904RGFWDEF void RGFW_window_checkEvents(RGFW_window* win, i32 waitMS);
905
906/*!
907 tell RGFW_window_eventWait to stop waiting (to be ran from another thread)
908*/
909RGFWDEF void RGFW_stopCheckEvents(void);
910
911/*! window managment functions */
912RGFWDEF void RGFW_window_close(RGFW_window* win); /*!< close the window and free leftover data */
913
914/*! move a window to a given point */
915RGFWDEF void RGFW_window_move(RGFW_window* win,
916 RGFW_point v /*!< new pos */
917);
918
919#ifndef RGFW_NO_MONITOR
920 /*! move window to a specific monitor */
921 RGFWDEF void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m /* monitor */);
922#endif
923
924/*! resize window to a current size/area */
925RGFWDEF void RGFW_window_resize(RGFW_window* win, /*!< source window */
926 RGFW_area a /*!< new size */
927);
928
929/*! set window aspect ratio */
930RGFWDEF void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a);
931/*! set the minimum dimensions of a window */
932RGFWDEF void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a);
933/*! set the maximum dimensions of a window */
934RGFWDEF void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a);
935
936RGFWDEF void RGFW_window_focus(RGFW_window* win); /*!< sets the focus to this window */
937RGFWDEF RGFW_bool RGFW_window_isInFocus(RGFW_window* win); /*!< checks the focus to this window */
938RGFWDEF void RGFW_window_raise(RGFW_window* win); /*!< raise the window (to the top) */
939RGFWDEF void RGFW_window_maximize(RGFW_window* win); /*!< maximize the window */
940RGFWDEF void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen); /*!< turn fullscreen on / off for a window */
941RGFWDEF void RGFW_window_center(RGFW_window* win); /*!< center the window */
942RGFWDEF void RGFW_window_minimize(RGFW_window* win); /*!< minimize the window (in taskbar (per OS))*/
943RGFWDEF void RGFW_window_restore(RGFW_window* win); /*!< restore the window from minimized (per OS)*/
944RGFWDEF void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating); /*!< make the window a floating window */
945RGFWDEF void RGFW_window_setOpacity(RGFW_window* win, u8 opacity); /*!< sets the opacity of a window */
946
947RGFWDEF RGFW_bool RGFW_window_opengl_isSoftware(RGFW_window* win);
948
949/*! if the window should have a border or not (borderless) based on bool value of `border` */
950RGFWDEF void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border);
951RGFWDEF RGFW_bool RGFW_window_borderless(RGFW_window* win);
952
953/*! turn on / off dnd (RGFW_windowAllowDND stil must be passed to the window)*/
954RGFWDEF void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow);
955/*! check if DND is allowed */
956RGFWDEF RGFW_bool RGFW_window_allowsDND(RGFW_window* win);
957
958
959#ifndef RGFW_NO_PASSTHROUGH
960 /*! turn on / off mouse passthrough */
961 RGFWDEF void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough);
962#endif
963
964/*! rename window to a given string */
965RGFWDEF void RGFW_window_setName(RGFW_window* win,
966 const char* name
967);
968
969RGFWDEF RGFW_bool RGFW_window_setIcon(RGFW_window* win, /*!< source window */
970 u8* icon /*!< icon bitmap */,
971 RGFW_area a /*!< width and height of the bitmap */,
972 i32 channels /*!< how many channels the bitmap has (rgb : 3, rgba : 4) */
973); /*!< image MAY be resized by default, set both the taskbar and window icon */
974
975typedef RGFW_ENUM(u8, RGFW_icon) {
976 RGFW_iconTaskbar = RGFW_BIT(0),
977 RGFW_iconWindow = RGFW_BIT(1),
978 RGFW_iconBoth = RGFW_iconTaskbar | RGFW_iconWindow
979};
980RGFWDEF RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* icon, RGFW_area a, i32 channels, u8 type);
981
982/*!< sets mouse to RGFW_mouse icon (loaded from a bitmap struct) */
983RGFWDEF void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse);
984
985/*!< sets the mouse to a standard API cursor (based on RGFW_MOUSE, as seen at the end of the RGFW_HEADER part of this file) */
986RGFWDEF RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse);
987
988RGFWDEF RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win); /*!< sets the mouse to the default mouse icon */
989/*
990 Locks cursor at the center of the window
991 win->event.point becomes raw mouse movement data
992
993 this is useful for a 3D camera
994*/
995RGFWDEF void RGFW_window_mouseHold(RGFW_window* win, RGFW_area area);
996/*! if the mouse is held by RGFW */
997RGFWDEF RGFW_bool RGFW_window_mouseHeld(RGFW_window* win);
998/*! stop holding the mouse and let it move freely */
999RGFWDEF void RGFW_window_mouseUnhold(RGFW_window* win);
1000
1001/*! hide the window */
1002RGFWDEF void RGFW_window_hide(RGFW_window* win);
1003/*! show the window */
1004RGFWDEF void RGFW_window_show(RGFW_window* win);
1005
1006/*
1007 makes it so `RGFW_window_shouldClose` returns true or overrides a window close
1008 by modifying window flags
1009*/
1010RGFWDEF void RGFW_window_setShouldClose(RGFW_window* win, RGFW_bool shouldClose);
1011
1012/*! where the mouse is on the screen */
1013RGFWDEF RGFW_point RGFW_getGlobalMousePoint(void);
1014
1015/*! where the mouse is on the window */
1016RGFWDEF RGFW_point RGFW_window_getMousePoint(RGFW_window* win);
1017
1018/*! show the mouse or hide the mouse */
1019RGFWDEF void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show);
1020/*! if the mouse is hidden */
1021RGFWDEF RGFW_bool RGFW_window_mouseHidden(RGFW_window* win);
1022/*! move the mouse to a given point */
1023RGFWDEF void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v);
1024
1025/*! if the window should close (RGFW_close was sent or escape was pressed) */
1026RGFWDEF RGFW_bool RGFW_window_shouldClose(RGFW_window* win);
1027/*! if the window is fullscreen */
1028RGFWDEF RGFW_bool RGFW_window_isFullscreen(RGFW_window* win);
1029/*! if the window is hidden */
1030RGFWDEF RGFW_bool RGFW_window_isHidden(RGFW_window* win);
1031/*! if the window is minimized */
1032RGFWDEF RGFW_bool RGFW_window_isMinimized(RGFW_window* win);
1033/*! if the window is maximized */
1034RGFWDEF RGFW_bool RGFW_window_isMaximized(RGFW_window* win);
1035/*! if the window is floating */
1036RGFWDEF RGFW_bool RGFW_window_isFloating(RGFW_window* win);
1037/** @} */
1038
1039/** * @defgroup Monitor
1040* @{ */
1041
1042#ifndef RGFW_NO_MONITOR
1043/*
1044 scale the window to the monitor.
1045 This is run by default if the user uses the arg `RGFW_scaleToMonitor` during window creation
1046*/
1047RGFWDEF void RGFW_window_scaleToMonitor(RGFW_window* win);
1048/*! get the struct of the window's monitor */
1049RGFWDEF RGFW_monitor RGFW_window_getMonitor(RGFW_window* win);
1050#endif
1051
1052/** @} */
1053
1054/** * @defgroup Input
1055* @{ */
1056
1057/*! if window == NULL, it checks if the key is pressed globally. Otherwise, it checks only if the key is pressed while the window in focus. */
1058RGFWDEF RGFW_bool RGFW_isPressed(RGFW_window* win, RGFW_key key); /*!< if key is pressed (key code)*/
1059
1060RGFWDEF RGFW_bool RGFW_wasPressed(RGFW_window* win, RGFW_key key); /*!< if key was pressed (checks previous state only) (key code) */
1061
1062RGFWDEF RGFW_bool RGFW_isHeld(RGFW_window* win, RGFW_key key); /*!< if key is held (key code) */
1063RGFWDEF RGFW_bool RGFW_isReleased(RGFW_window* win, RGFW_key key); /*!< if key is released (key code) */
1064
1065/* if a key is pressed and then released, pretty much the same as RGFW_isReleased */
1066RGFWDEF RGFW_bool RGFW_isClicked(RGFW_window* win, RGFW_key key /*!< key code */);
1067
1068/*! if a mouse button is pressed */
1069RGFWDEF RGFW_bool RGFW_isMousePressed(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ );
1070/*! if a mouse button is held */
1071RGFWDEF RGFW_bool RGFW_isMouseHeld(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ );
1072/*! if a mouse button was released */
1073RGFWDEF RGFW_bool RGFW_isMouseReleased(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ );
1074/*! if a mouse button was pressed (checks previous state only) */
1075RGFWDEF RGFW_bool RGFW_wasMousePressed(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ );
1076/** @} */
1077
1078/** * @defgroup Clipboard
1079* @{ */
1080typedef ptrdiff_t RGFW_ssize_t;
1081
1082RGFWDEF const char* RGFW_readClipboard(size_t* size); /*!< read clipboard data */
1083/*! read clipboard data or send a NULL str to just get the length of the clipboard data */
1084RGFWDEF RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity);
1085RGFWDEF void RGFW_writeClipboard(const char* text, u32 textLen); /*!< write text to the clipboard */
1086/** @} */
1087
1088
1089
1090/** * @defgroup error handling
1091* @{ */
1092typedef RGFW_ENUM(u8, RGFW_debugType) {
1093 RGFW_typeError = 0, RGFW_typeWarning, RGFW_typeInfo
1094};
1095
1096typedef RGFW_ENUM(u8, RGFW_errorCode) {
1097 RGFW_noError = 0, /*!< no error */
1098 RGFW_errOpenglContext, RGFW_errEGLContext, /*!< error with the OpenGL context */
1099 RGFW_errWayland,
1100 RGFW_errDirectXContext,
1101 RGFW_errIOKit,
1102 RGFW_errClipboard,
1103 RGFW_errFailedFuncLoad,
1104 RGFW_errBuffer,
1105 RGFW_infoMonitor, RGFW_infoWindow, RGFW_infoBuffer, RGFW_infoGlobal, RGFW_infoOpenGL,
1106 RGFW_warningWayland, RGFW_warningOpenGL
1107};
1108
1109typedef struct RGFW_debugContext { RGFW_window* win; RGFW_monitor* monitor; u32 srcError; } RGFW_debugContext;
1110
1111#if defined(__cplusplus) && !defined(__APPLE__)
1112#define RGFW_DEBUG_CTX(win, err) {win, NULL, err}
1113#define RGFW_DEBUG_CTX_MON(monitor) {_RGFW.root, &monitor, 0}
1114#else
1115#define RGFW_DEBUG_CTX(win, err) (RGFW_debugContext){win, NULL, err}
1116#define RGFW_DEBUG_CTX_MON(monitor) (RGFW_debugContext){_RGFW.root, &monitor, 0}
1117#endif
1118
1119typedef void (* RGFW_debugfunc)(RGFW_debugType type, RGFW_errorCode err, RGFW_debugContext ctx, const char* msg);
1120RGFWDEF RGFW_debugfunc RGFW_setDebugCallback(RGFW_debugfunc func);
1121RGFWDEF void RGFW_sendDebugInfo(RGFW_debugType type, RGFW_errorCode err, RGFW_debugContext ctx, const char* msg);
1122/** @} */
1123
1124/**
1125
1126
1127 event callbacks.
1128 These are completely optional, so you can use the normal
1129 RGFW_checkEvent() method if you prefer that
1130
1131* @defgroup Callbacks
1132* @{
1133*/
1134
1135/*! RGFW_windowMoved, the window and its new rect value */
1136typedef void (* RGFW_windowMovedfunc)(RGFW_window* win, RGFW_rect r);
1137/*! RGFW_windowResized, the window and its new rect value */
1138typedef void (* RGFW_windowResizedfunc)(RGFW_window* win, RGFW_rect r);
1139/*! RGFW_windowRestored, the window and its new rect value */
1140typedef void (* RGFW_windowRestoredfunc)(RGFW_window* win, RGFW_rect r);
1141/*! RGFW_windowMaximized, the window and its new rect value */
1142typedef void (* RGFW_windowMaximizedfunc)(RGFW_window* win, RGFW_rect r);
1143/*! RGFW_windowMinimized, the window and its new rect value */
1144typedef void (* RGFW_windowMinimizedfunc)(RGFW_window* win, RGFW_rect r);
1145/*! RGFW_quit, the window that was closed */
1146typedef void (* RGFW_windowQuitfunc)(RGFW_window* win);
1147/*! RGFW_focusIn / RGFW_focusOut, the window who's focus has changed and if its in focus */
1148typedef void (* RGFW_focusfunc)(RGFW_window* win, RGFW_bool inFocus);
1149/*! RGFW_mouseEnter / RGFW_mouseLeave, the window that changed, the point of the mouse (enter only) and if the mouse has entered */
1150typedef void (* RGFW_mouseNotifyfunc)(RGFW_window* win, RGFW_point point, RGFW_bool status);
1151/*! RGFW_mousePosChanged, the window that the move happened on, and the new point of the mouse */
1152typedef void (* RGFW_mousePosfunc)(RGFW_window* win, RGFW_point point, RGFW_point vector);
1153/*! RGFW_DNDInit, the window, the point of the drop on the windows */
1154typedef void (* RGFW_dndInitfunc)(RGFW_window* win, RGFW_point point);
1155/*! RGFW_windowRefresh, the window that needs to be refreshed */
1156typedef void (* RGFW_windowRefreshfunc)(RGFW_window* win);
1157/*! RGFW_keyPressed / RGFW_keyReleased, the window that got the event, the mapped key, the physical key, the string version, the state of the mod keys, if it was a press (else it's a release) */
1158typedef void (* RGFW_keyfunc)(RGFW_window* win, u8 key, u8 keyChar, RGFW_keymod keyMod, RGFW_bool pressed);
1159/*! RGFW_mouseButtonPressed / RGFW_mouseButtonReleased, the window that got the event, the button that was pressed, the scroll value, if it was a press (else it's a release) */
1160typedef void (* RGFW_mouseButtonfunc)(RGFW_window* win, RGFW_mouseButton button, double scroll, RGFW_bool pressed);
1161/*! RGFW_gamepadButtonPressed, the window that got the event, the button that was pressed, the scroll value, if it was a press (else it's a release) */
1162typedef void (* RGFW_gamepadButtonfunc)(RGFW_window* win, u16 gamepad, u8 button, RGFW_bool pressed);
1163/*! RGFW_gamepadAxisMove, the window that got the event, the gamepad in question, the axis values and the axis count */
1164typedef void (* RGFW_gamepadAxisfunc)(RGFW_window* win, u16 gamepad, RGFW_point axis[2], u8 axisesCount, u8 whichAxis);
1165/*! RGFW_gamepadConnected / RGFW_gamepadDisconnected, the window that got the event, the gamepad in question, if the controller was connected (else it was disconnected) */
1166typedef void (* RGFW_gamepadfunc)(RGFW_window* win, u16 gamepad, RGFW_bool connected);
1167/*! RGFW_dnd, the window that had the drop, the drop data and the number of files dropped */
1168typedef void (* RGFW_dndfunc)(RGFW_window* win, char** droppedFiles, size_t droppedFilesCount);
1169/*! RGFW_scaleUpdated, the window the event was sent to, content scaleX, content scaleY */
1170typedef void (* RGFW_scaleUpdatedfunc)(RGFW_window* win, float scaleX, float scaleY);
1171
1172/*! set callback for a window move event. Returns previous callback function (if it was set) */
1173RGFWDEF RGFW_windowMovedfunc RGFW_setWindowMovedCallback(RGFW_windowMovedfunc func);
1174/*! set callback for a window resize event. Returns previous callback function (if it was set) */
1175RGFWDEF RGFW_windowResizedfunc RGFW_setWindowResizedCallback(RGFW_windowResizedfunc func);
1176/*! set callback for a window quit event. Returns previous callback function (if it was set) */
1177RGFWDEF RGFW_windowQuitfunc RGFW_setWindowQuitCallback(RGFW_windowQuitfunc func);
1178/*! set callback for a mouse move event. Returns previous callback function (if it was set) */
1179RGFWDEF RGFW_mousePosfunc RGFW_setMousePosCallback(RGFW_mousePosfunc func);
1180/*! set callback for a window refresh event. Returns previous callback function (if it was set) */
1181RGFWDEF RGFW_windowRefreshfunc RGFW_setWindowRefreshCallback(RGFW_windowRefreshfunc func);
1182/*! set callback for a window focus change event. Returns previous callback function (if it was set) */
1183RGFWDEF RGFW_focusfunc RGFW_setFocusCallback(RGFW_focusfunc func);
1184/*! set callback for a mouse notify event. Returns previous callback function (if it was set) */
1185RGFWDEF RGFW_mouseNotifyfunc RGFW_setMouseNotifyCallback(RGFW_mouseNotifyfunc func);
1186/*! set callback for a drop event event. Returns previous callback function (if it was set) */
1187RGFWDEF RGFW_dndfunc RGFW_setDndCallback(RGFW_dndfunc func);
1188/*! set callback for a start of a drop event. Returns previous callback function (if it was set) */
1189RGFWDEF RGFW_dndInitfunc RGFW_setDndInitCallback(RGFW_dndInitfunc func);
1190/*! set callback for a key (press / release) event. Returns previous callback function (if it was set) */
1191RGFWDEF RGFW_keyfunc RGFW_setKeyCallback(RGFW_keyfunc func);
1192/*! set callback for a mouse button (press / release) event. Returns previous callback function (if it was set) */
1193RGFWDEF RGFW_mouseButtonfunc RGFW_setMouseButtonCallback(RGFW_mouseButtonfunc func);
1194/*! set callback for a controller button (press / release) event. Returns previous callback function (if it was set) */
1195RGFWDEF RGFW_gamepadButtonfunc RGFW_setGamepadButtonCallback(RGFW_gamepadButtonfunc func);
1196/*! set callback for a gamepad axis move event. Returns previous callback function (if it was set) */
1197RGFWDEF RGFW_gamepadAxisfunc RGFW_setGamepadAxisCallback(RGFW_gamepadAxisfunc func);
1198/*! set callback for when a controller is connected or disconnected. Returns the previous callback function (if it was set) */
1199RGFWDEF RGFW_gamepadfunc RGFW_setGamepadCallback(RGFW_gamepadfunc func);
1200/*! set call back for when window is maximized. Returns the previous callback function (if it was set) */
1201RGFWDEF RGFW_windowResizedfunc RGFW_setWindowMaximizedCallback(RGFW_windowResizedfunc func);
1202/*! set call back for when window is minimized. Returns the previous callback function (if it was set) */
1203RGFWDEF RGFW_windowResizedfunc RGFW_setWindowMinimizedCallback(RGFW_windowResizedfunc func);
1204/*! set call back for when window is restored. Returns the previous callback function (if it was set) */
1205RGFWDEF RGFW_windowResizedfunc RGFW_setWindowRestoredCallback(RGFW_windowResizedfunc func);
1206/*! set callback for when the DPI changes. Returns previous callback function (if it was set) */
1207RGFWDEF RGFW_scaleUpdatedfunc RGFW_setScaleUpdatedCallback(RGFW_scaleUpdatedfunc func);
1208/** @} */
1209
1210/** * @defgroup Threads
1211* @{ */
1212
1213#ifndef RGFW_NO_THREADS
1214/*! threading functions */
1215
1216/*! NOTE! (for X11/linux) : if you define a window in a thread, it must be run after the original thread's window is created or else there will be a memory error */
1217/*
1218 I'd suggest you use sili's threading functions instead
1219 if you're going to use sili
1220 which is a good idea generally
1221*/
1222
1223#if defined(__unix__) || defined(__APPLE__) || defined(RGFW_WASM) || defined(RGFW_CUSTOM_BACKEND)
1224 typedef void* (* RGFW_threadFunc_ptr)(void*);
1225#else
1226 typedef DWORD (__stdcall *RGFW_threadFunc_ptr) (LPVOID lpThreadParameter);
1227#endif
1228
1229RGFWDEF RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args); /*!< create a thread */
1230RGFWDEF void RGFW_cancelThread(RGFW_thread thread); /*!< cancels a thread */
1231RGFWDEF void RGFW_joinThread(RGFW_thread thread); /*!< join thread to current thread */
1232RGFWDEF void RGFW_setThreadPriority(RGFW_thread thread, u8 priority); /*!< sets the priority priority */
1233#endif
1234
1235/** @} */
1236
1237/** * @defgroup gamepad
1238* @{ */
1239
1240typedef RGFW_ENUM(u8, RGFW_gamepadType) {
1241 RGFW_gamepadMicrosoft = 0, RGFW_gamepadSony, RGFW_gamepadNintendo, RGFW_gamepadLogitech, RGFW_gamepadUnknown
1242};
1243
1244/*! gamepad count starts at 0*/
1245RGFWDEF u32 RGFW_isPressedGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button);
1246RGFWDEF u32 RGFW_isReleasedGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button);
1247RGFWDEF u32 RGFW_isHeldGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button);
1248RGFWDEF u32 RGFW_wasPressedGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button);
1249RGFWDEF RGFW_point RGFW_getGamepadAxis(RGFW_window* win, u16 controller, u16 whichAxis);
1250RGFWDEF const char* RGFW_getGamepadName(RGFW_window* win, u16 controller);
1251RGFWDEF size_t RGFW_getGamepadCount(RGFW_window* win);
1252RGFWDEF RGFW_gamepadType RGFW_getGamepadType(RGFW_window* win, u16 controller);
1253
1254/** @} */
1255
1256/** * @defgroup graphics_API
1257* @{ */
1258
1259/*!< make the window the current opengl drawing context
1260
1261 NOTE:
1262 if you want to switch the graphics context's thread,
1263 you have to run RGFW_window_makeCurrent(NULL); on the old thread
1264 then RGFW_window_makeCurrent(valid_window) on the new thread
1265*/
1266RGFWDEF void RGFW_window_makeCurrent(RGFW_window* win);
1267
1268/*! get current RGFW window graphics context */
1269RGFWDEF RGFW_window* RGFW_getCurrent(void);
1270
1271/* supports openGL, directX, OSMesa, EGL and software rendering */
1272RGFWDEF void RGFW_window_swapBuffers(RGFW_window* win); /*!< swap the rendering buffer */
1273RGFWDEF void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval);
1274/*!< render the software rendering buffer (this is called by RGFW_window_swapInterval) */
1275RGFWDEF void RGFW_window_swapBuffers_software(RGFW_window* win);
1276
1277typedef void (*RGFW_proc)(void); /* function pointer equivalent of void* */
1278
1279/*! native API functions */
1280#if defined(RGFW_OPENGL) || defined(RGFW_EGL)
1281/*!< create an opengl context for the RGFW window, run by createWindow by default (unless the RGFW_windowNoInitAPI is included) */
1282RGFWDEF void RGFW_window_initOpenGL(RGFW_window* win);
1283/*!< called by `RGFW_window_close` by default (unless the RGFW_windowNoInitAPI is set) */
1284RGFWDEF void RGFW_window_freeOpenGL(RGFW_window* win);
1285
1286/*! OpenGL init hints */
1287typedef RGFW_ENUM(u8, RGFW_glHints) {
1288 RGFW_glStencil = 0, /*!< set stencil buffer bit size (8 by default) */
1289 RGFW_glSamples, /*!< set number of sampiling buffers (4 by default) */
1290 RGFW_glStereo, /*!< use GL_STEREO (GL_FALSE by default) */
1291 RGFW_glAuxBuffers, /*!< number of aux buffers (0 by default) */
1292 RGFW_glDoubleBuffer, /*!< request double buffering */
1293 RGFW_glRed, RGFW_glGreen, RGFW_glBlue, RGFW_glAlpha, /*!< set RGBA bit sizes */
1294 RGFW_glDepth,
1295 RGFW_glAccumRed, RGFW_glAccumGreen, RGFW_glAccumBlue,RGFW_glAccumAlpha, /*!< set accumulated RGBA bit sizes */
1296 RGFW_glSRGB, /*!< request sRGA */
1297 RGFW_glRobustness, /*!< request a robust context */
1298 RGFW_glDebug, /*!< request opengl debugging */
1299 RGFW_glNoError, /*!< request no opengl errors */
1300 RGFW_glReleaseBehavior,
1301 RGFW_glProfile,
1302 RGFW_glMajor, RGFW_glMinor,
1303 RGFW_glFinalHint = 32, /*!< the final hint (not for setting) */
1304 RGFW_releaseFlush = 0, RGFW_glReleaseNone, /* RGFW_glReleaseBehavior options */
1305 RGFW_glCore = 0, RGFW_glCompatibility /*!< RGFW_glProfile options */
1306};
1307RGFWDEF void RGFW_setGLHint(RGFW_glHints hint, i32 value);
1308RGFWDEF RGFW_bool RGFW_extensionSupported(const char* extension, size_t len); /*!< check if whether the specified API extension is supported by the current OpenGL or OpenGL ES context */
1309RGFWDEF RGFW_proc RGFW_getProcAddress(const char* procname); /*!< get native opengl proc address */
1310RGFWDEF void RGFW_window_makeCurrent_OpenGL(RGFW_window* win); /*!< to be called by RGFW_window_makeCurrent */
1311RGFWDEF void RGFW_window_swapBuffers_OpenGL(RGFW_window* win); /*!< swap opengl buffer (only) called by RGFW_window_swapInterval */
1312void* RGFW_getCurrent_OpenGL(void); /*!< get the current context (OpenGL backend (GLX) (WGL) (EGL) (cocoa) (webgl))*/
1313
1314RGFWDEF RGFW_bool RGFW_extensionSupportedPlatform(const char* extension, size_t len); /*!< check if whether the specified platform-specific API extension is supported by the current OpenGL or OpenGL ES context */
1315#endif
1316#ifdef RGFW_VULKAN
1317 #if defined(RGFW_WAYLAND) && defined(RGFW_X11)
1318 #define VK_USE_PLATFORM_WAYLAND_KHR
1319 #define VK_USE_PLATFORM_XLIB_KHR
1320 #define RGFW_VK_SURFACE ((RGFW_usingWayland()) ? ("VK_KHR_wayland_surface") : ("VK_KHR_xlib_surface"))
1321 #elif defined(RGFW_WAYLAND)
1322 #define VK_USE_PLATFORM_WAYLAND_KHR
1323 #define VK_USE_PLATFORM_XLIB_KHR
1324 #define RGFW_VK_SURFACE "VK_KHR_wayland_surface"
1325 #elif defined(RGFW_X11)
1326 #define VK_USE_PLATFORM_XLIB_KHR
1327 #define RGFW_VK_SURFACE "VK_KHR_xlib_surface"
1328 #elif defined(RGFW_WINDOWS)
1329 #define VK_USE_PLATFORM_WIN32_KHR
1330 #define OEMRESOURCE
1331 #define RGFW_VK_SURFACE "VK_KHR_win32_surface"
1332 #elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11)
1333 #define VK_USE_PLATFORM_MACOS_MVK
1334 #define RGFW_VK_SURFACE "VK_MVK_macos_surface"
1335 #else
1336 #define RGFW_VK_SURFACE NULL
1337 #endif
1338
1339/* if you don't want to use the above macros */
1340RGFWDEF const char** RGFW_getVKRequiredInstanceExtensions(size_t* count); /*!< gets (static) extension array (and size (which will be 2)) */
1341
1342#include <vulkan/vulkan.h>
1343
1344RGFWDEF VkResult RGFW_window_createVKSurface(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface);
1345RGFWDEF RGFW_bool RGFW_getVKPresentationSupport(VkInstance instance, VkPhysicalDevice physicalDevice, u32 queueFamilyIndex);
1346#endif
1347#ifdef RGFW_DIRECTX
1348#ifndef RGFW_WINDOWS
1349 #undef RGFW_DIRECTX
1350#else
1351 #define OEMRESOURCE
1352 #include <dxgi.h>
1353
1354 #ifndef __cplusplus
1355 #define __uuidof(T) IID_##T
1356 #endif
1357RGFWDEF int RGFW_window_createDXSwapChain(RGFW_window* win, IDXGIFactory* pFactory, IUnknown* pDevice, IDXGISwapChain** swapchain);
1358#endif
1359#endif
1360
1361/** @} */
1362
1363/** * @defgroup Supporting
1364* @{ */
1365
1366/*! optional init/deinit function */
1367RGFWDEF i32 RGFW_init(void); /*!< is called by default when the first window is created by default */
1368RGFWDEF void RGFW_deinit(void); /*!< is called by default when the last open window is closed */
1369
1370RGFWDEF double RGFW_getTime(void); /*!< get time in seconds since RGFW_setTime, which ran when the first window is open */
1371RGFWDEF u64 RGFW_getTimeNS(void); /*!< get time in nanoseconds RGFW_setTime, which ran when the first window is open */
1372RGFWDEF void RGFW_sleep(u64 milisecond); /*!< sleep for a set time */
1373RGFWDEF void RGFW_setTime(double time); /*!< set timer in seconds */
1374RGFWDEF u64 RGFW_getTimerValue(void); /*!< get API timer value */
1375RGFWDEF u64 RGFW_getTimerFreq(void); /*!< get API time freq */
1376
1377/*< updates fps / sets fps to cap (must by ran manually by the user at the end of a frame), returns current fps */
1378RGFWDEF u32 RGFW_checkFPS(double startTime, u32 frameCount, u32 fpsCap);
1379
1380/*!< change which window is the root window */
1381RGFWDEF void RGFW_setRootWindow(RGFW_window* win);
1382RGFWDEF RGFW_window* RGFW_getRootWindow(void);
1383
1384/*! standard event queue, used for injecting events and returning source API callback events like any other queue check */
1385/* these are all used internally by RGFW */
1386void RGFW_eventQueuePush(RGFW_event event);
1387RGFW_event* RGFW_eventQueuePop(RGFW_window* win);
1388
1389/* for C++ / C89 */
1390#define RGFW_eventQueuePushEx(eventInit) { RGFW_event e; eventInit; RGFW_eventQueuePush(e); }
1391
1392/*!
1393 key codes and mouse icon enums
1394*/
1395#undef RGFW_key
1396typedef RGFW_ENUM(u8, RGFW_key) {
1397 RGFW_keyNULL = 0,
1398 RGFW_escape = '\033',
1399 RGFW_backtick = '`',
1400 RGFW_0 = '0',
1401 RGFW_1 = '1',
1402 RGFW_2 = '2',
1403 RGFW_3 = '3',
1404 RGFW_4 = '4',
1405 RGFW_5 = '5',
1406 RGFW_6 = '6',
1407 RGFW_7 = '7',
1408 RGFW_8 = '8',
1409 RGFW_9 = '9',
1410
1411 RGFW_minus = '-',
1412 RGFW_equals = '=',
1413 RGFW_backSpace = '\b',
1414 RGFW_tab = '\t',
1415 RGFW_space = ' ',
1416
1417 RGFW_a = 'a',
1418 RGFW_b = 'b',
1419 RGFW_c = 'c',
1420 RGFW_d = 'd',
1421 RGFW_e = 'e',
1422 RGFW_f = 'f',
1423 RGFW_g = 'g',
1424 RGFW_h = 'h',
1425 RGFW_i = 'i',
1426 RGFW_j = 'j',
1427 RGFW_k = 'k',
1428 RGFW_l = 'l',
1429 RGFW_m = 'm',
1430 RGFW_n = 'n',
1431 RGFW_o = 'o',
1432 RGFW_p = 'p',
1433 RGFW_q = 'q',
1434 RGFW_r = 'r',
1435 RGFW_s = 's',
1436 RGFW_t = 't',
1437 RGFW_u = 'u',
1438 RGFW_v = 'v',
1439 RGFW_w = 'w',
1440 RGFW_x = 'x',
1441 RGFW_y = 'y',
1442 RGFW_z = 'z',
1443
1444 RGFW_period = '.',
1445 RGFW_comma = ',',
1446 RGFW_slash = '/',
1447 RGFW_bracket = '[',
1448 RGFW_closeBracket = ']',
1449 RGFW_semicolon = ';',
1450 RGFW_apostrophe = '\'',
1451 RGFW_backSlash = '\\',
1452 RGFW_return = '\n',
1453 RGFW_enter = RGFW_return,
1454
1455 RGFW_delete = '\177', /* 127 */
1456
1457 RGFW_F1,
1458 RGFW_F2,
1459 RGFW_F3,
1460 RGFW_F4,
1461 RGFW_F5,
1462 RGFW_F6,
1463 RGFW_F7,
1464 RGFW_F8,
1465 RGFW_F9,
1466 RGFW_F10,
1467 RGFW_F11,
1468 RGFW_F12,
1469
1470 RGFW_capsLock,
1471 RGFW_shiftL,
1472 RGFW_controlL,
1473 RGFW_altL,
1474 RGFW_superL,
1475 RGFW_shiftR,
1476 RGFW_controlR,
1477 RGFW_altR,
1478 RGFW_superR,
1479 RGFW_up,
1480 RGFW_down,
1481 RGFW_left,
1482 RGFW_right,
1483 RGFW_insert,
1484 RGFW_end,
1485 RGFW_home,
1486 RGFW_pageUp,
1487 RGFW_pageDown,
1488
1489 RGFW_numLock,
1490 RGFW_KP_Slash,
1491 RGFW_multiply,
1492 RGFW_KP_Minus,
1493 RGFW_KP_1,
1494 RGFW_KP_2,
1495 RGFW_KP_3,
1496 RGFW_KP_4,
1497 RGFW_KP_5,
1498 RGFW_KP_6,
1499 RGFW_KP_7,
1500 RGFW_KP_8,
1501 RGFW_KP_9,
1502 RGFW_KP_0,
1503 RGFW_KP_Period,
1504 RGFW_KP_Return,
1505 RGFW_scrollLock,
1506 RGFW_printScreen,
1507 RGFW_pause,
1508 RGFW_keyLast = 256 /* padding for alignment ~(175 by default) */
1509 };
1510
1511
1512/*! converts api keycode to the RGFW unmapped/physical key */
1513RGFWDEF u32 RGFW_apiKeyToRGFW(u32 keycode);
1514/*! converts RGFW keycode to the unmapped/physical api key */
1515RGFWDEF u32 RGFW_rgfwToApiKey(u32 keycode);
1516/*! converts RGFW keycode to the mapped keychar */
1517RGFWDEF u8 RGFW_rgfwToKeyChar(u32 keycode);
1518
1519typedef RGFW_ENUM(u8, RGFW_mouseIcons) {
1520 RGFW_mouseNormal = 0,
1521 RGFW_mouseArrow,
1522 RGFW_mouseIbeam,
1523 RGFW_mouseCrosshair,
1524 RGFW_mousePointingHand,
1525 RGFW_mouseResizeEW,
1526 RGFW_mouseResizeNS,
1527 RGFW_mouseResizeNWSE,
1528 RGFW_mouseResizeNESW,
1529 RGFW_mouseResizeAll,
1530 RGFW_mouseNotAllowed,
1531 RGFW_mouseIconFinal = 16 /* padding for alignment */
1532};
1533/** @} */
1534
1535#endif /* RGFW_HEADER */
1536#if defined(RGFW_X11) || defined(RGFW_WAYLAND)
1537 #define RGFW_OS_BASED_VALUE(l, w, m, h) l
1538#elif defined(RGFW_WINDOWS)
1539 #define RGFW_OS_BASED_VALUE(l, w, m, h) w
1540#elif defined(RGFW_MACOS)
1541 #define RGFW_OS_BASED_VALUE(l, w, m, h) m
1542#elif defined(RGFW_WASM)
1543 #define RGFW_OS_BASED_VALUE(l, w, m, h) h
1544#endif
1545
1546
1547#ifdef RGFW_IMPLEMENTATION
1548RGFW_bool RGFW_useWaylandBool = 1;
1549void RGFW_useWayland(RGFW_bool wayland) { RGFW_useWaylandBool = wayland; }
1550RGFW_bool RGFW_usingWayland(void) { return RGFW_useWaylandBool; }
1551
1552#if !defined(RGFW_NO_X11) && defined(RGFW_WAYLAND)
1553#define RGFW_GOTO_WAYLAND(fallback) if (RGFW_useWaylandBool && fallback == 0) goto wayland
1554#define RGFW_WAYLAND_LABEL wayland:;
1555#else
1556#define RGFW_GOTO_WAYLAND(fallback)
1557#define RGFW_WAYLAND_LABEL
1558#endif
1559
1560char* RGFW_clipboard_data;
1561void RGFW_clipboard_switch(char* newstr);
1562void RGFW_clipboard_switch(char* newstr) {
1563 if (RGFW_clipboard_data != NULL)
1564 RGFW_FREE(RGFW_clipboard_data);
1565 RGFW_clipboard_data = newstr;
1566}
1567
1568#define RGFW_CHECK_CLIPBOARD() \
1569 if (size <= 0 && RGFW_clipboard_data != NULL) \
1570 return (const char*)RGFW_clipboard_data; \
1571 else if (size <= 0) \
1572 return "\0";
1573
1574const char* RGFW_readClipboard(size_t* len) {
1575 RGFW_ssize_t size = RGFW_readClipboardPtr(NULL, 0);
1576 RGFW_CHECK_CLIPBOARD();
1577 char* str = (char*)RGFW_ALLOC((size_t)size);
1578 RGFW_ASSERT(str != NULL);
1579 str[0] = '\0';
1580
1581 size = RGFW_readClipboardPtr(str, (size_t)size);
1582
1583 RGFW_CHECK_CLIPBOARD();
1584
1585 if (len != NULL) *len = (size_t)size;
1586
1587 RGFW_clipboard_switch(str);
1588 return (const char*)str;
1589}
1590
1591RGFW_debugfunc RGFW_debugCallback = NULL;
1592RGFW_debugfunc RGFW_setDebugCallback(RGFW_debugfunc func) {
1593 RGFW_debugfunc RGFW_debugCallbackPrev = RGFW_debugCallback;
1594 RGFW_debugCallback = func;
1595 return RGFW_debugCallbackPrev;
1596}
1597
1598#ifdef RGFW_DEBUG
1599#include <stdio.h>
1600#endif
1601
1602void RGFW_sendDebugInfo(RGFW_debugType type, RGFW_errorCode err, RGFW_debugContext ctx, const char* msg) {
1603 if (RGFW_debugCallback) RGFW_debugCallback(type, err, ctx, msg);
1604 #ifdef RGFW_DEBUG
1605 switch (type) {
1606 case RGFW_typeInfo: printf("RGFW INFO (%i %i): %s", type, err, msg); break;
1607 case RGFW_typeError: printf("RGFW DEBUG (%i %i): %s", type, err, msg); break;
1608 case RGFW_typeWarning: printf("RGFW WARNING (%i %i): %s", type, err, msg); break;
1609 default: break;
1610 }
1611
1612 switch (err) {
1613 #ifdef RGFW_BUFFER
1614 case RGFW_errBuffer: case RGFW_infoBuffer: printf(" buffer size: %i %i\n", ctx.win->bufferSize.w, ctx.win->bufferSize.h); break;
1615 #endif
1616 case RGFW_infoMonitor: printf(": scale (%s):\n rect: {%i, %i, %i, %i}\n physical size:%f %f\n scale: %f %f\n pixelRatio: %f\n refreshRate: %i\n depth: %i\n", ctx.monitor->name, ctx.monitor->x, ctx.monitor->y, ctx.monitor->mode.area.w, ctx.monitor->mode.area.h, ctx.monitor->physW, ctx.monitor->physH, ctx.monitor->scaleX, ctx.monitor->scaleY, ctx.monitor->pixelRatio, ctx.monitor->mode.refreshRate, ctx.monitor->mode.red + ctx.monitor->mode.green + ctx.monitor->mode.blue); break;
1617 case RGFW_infoWindow: printf(" with rect of {%i, %i, %i, %i} \n", ctx.win->r.x, ctx.win->r.y,ctx. win->r.w, ctx.win->r.h); break;
1618 case RGFW_errDirectXContext: printf(" srcError %i\n", ctx.srcError); break;
1619 default: printf("\n");
1620 }
1621 #endif
1622}
1623
1624u64 RGFW_timerOffset = 0;
1625void RGFW_setTime(double time) {
1626 RGFW_timerOffset = RGFW_getTimerValue() - (u64)(time * (double)RGFW_getTimerFreq());
1627}
1628
1629double RGFW_getTime(void) {
1630 return (double) ((double)(RGFW_getTimerValue() - RGFW_timerOffset) / (double)RGFW_getTimerFreq());
1631}
1632
1633u64 RGFW_getTimeNS(void) {
1634 return (u64)(((double)((RGFW_getTimerValue() - RGFW_timerOffset)) * 1e9) / (double)RGFW_getTimerFreq());
1635}
1636
1637/*
1638RGFW_IMPLEMENTATION starts with generic RGFW defines
1639
1640This is the start of keycode data
1641*/
1642
1643
1644
1645/*
1646 the c++ compiler doesn't support setting up an array like,
1647 we'll have to do it during runtime using a function & this messy setup
1648*/
1649
1650#ifndef RGFW_CUSTOM_BACKEND
1651
1652#if !defined(__cplusplus) && !defined(RGFW_C89)
1653#define RGFW_NEXT ,
1654#define RGFW_MAP
1655#else
1656#define RGFW_NEXT ;
1657#define RGFW_MAP RGFW_keycodes
1658#endif
1659
1660u32 RGFW_apiKeycodes[RGFW_keyLast] = { 0 };
1661
1662u8 RGFW_keycodes [RGFW_OS_BASED_VALUE(256, 512, 128, 256)] = {
1663#if defined(__cplusplus) || defined(RGFW_C89)
1664 0
1665};
1666void RGFW_init_keys(void);
1667void RGFW_init_keys(void) {
1668#endif
1669 RGFW_MAP [RGFW_OS_BASED_VALUE(49, 0x029, 50, DOM_VK_BACK_QUOTE)] = RGFW_backtick RGFW_NEXT
1670
1671 RGFW_MAP [RGFW_OS_BASED_VALUE(19, 0x00B, 29, DOM_VK_0)] = RGFW_0 RGFW_NEXT
1672 RGFW_MAP [RGFW_OS_BASED_VALUE(10, 0x002, 18, DOM_VK_1)] = RGFW_1 RGFW_NEXT
1673 RGFW_MAP [RGFW_OS_BASED_VALUE(11, 0x003, 19, DOM_VK_2)] = RGFW_2 RGFW_NEXT
1674 RGFW_MAP [RGFW_OS_BASED_VALUE(12, 0x004, 20, DOM_VK_3)] = RGFW_3 RGFW_NEXT
1675 RGFW_MAP [RGFW_OS_BASED_VALUE(13, 0x005, 21, DOM_VK_4)] = RGFW_4 RGFW_NEXT
1676 RGFW_MAP [RGFW_OS_BASED_VALUE(14, 0x006, 23, DOM_VK_5)] = RGFW_5 RGFW_NEXT
1677 RGFW_MAP [RGFW_OS_BASED_VALUE(15, 0x007, 22, DOM_VK_6)] = RGFW_6 RGFW_NEXT
1678 RGFW_MAP [RGFW_OS_BASED_VALUE(16, 0x008, 26, DOM_VK_7)] = RGFW_7 RGFW_NEXT
1679 RGFW_MAP [RGFW_OS_BASED_VALUE(17, 0x009, 28, DOM_VK_8)] = RGFW_8 RGFW_NEXT
1680 RGFW_MAP [RGFW_OS_BASED_VALUE(18, 0x00A, 25, DOM_VK_9)] = RGFW_9,
1681 RGFW_MAP [RGFW_OS_BASED_VALUE(65, 0x039, 49, DOM_VK_SPACE)] = RGFW_space,
1682 RGFW_MAP [RGFW_OS_BASED_VALUE(38, 0x01E, 0, DOM_VK_A)] = RGFW_a RGFW_NEXT
1683 RGFW_MAP [RGFW_OS_BASED_VALUE(56, 0x030, 11, DOM_VK_B)] = RGFW_b RGFW_NEXT
1684 RGFW_MAP [RGFW_OS_BASED_VALUE(54, 0x02E, 8, DOM_VK_C)] = RGFW_c RGFW_NEXT
1685 RGFW_MAP [RGFW_OS_BASED_VALUE(40, 0x020, 2, DOM_VK_D)] = RGFW_d RGFW_NEXT
1686 RGFW_MAP [RGFW_OS_BASED_VALUE(26, 0x012, 14, DOM_VK_E)] = RGFW_e RGFW_NEXT
1687 RGFW_MAP [RGFW_OS_BASED_VALUE(41, 0x021, 3, DOM_VK_F)] = RGFW_f RGFW_NEXT
1688 RGFW_MAP [RGFW_OS_BASED_VALUE(42, 0x022, 5, DOM_VK_G)] = RGFW_g RGFW_NEXT
1689 RGFW_MAP [RGFW_OS_BASED_VALUE(43, 0x023, 4, DOM_VK_H)] = RGFW_h RGFW_NEXT
1690 RGFW_MAP [RGFW_OS_BASED_VALUE(31, 0x017, 34, DOM_VK_I)] = RGFW_i RGFW_NEXT
1691 RGFW_MAP [RGFW_OS_BASED_VALUE(44, 0x024, 38, DOM_VK_J)] = RGFW_j RGFW_NEXT
1692 RGFW_MAP [RGFW_OS_BASED_VALUE(45, 0x025, 40, DOM_VK_K)] = RGFW_k RGFW_NEXT
1693 RGFW_MAP [RGFW_OS_BASED_VALUE(46, 0x026, 37, DOM_VK_L)] = RGFW_l RGFW_NEXT
1694 RGFW_MAP [RGFW_OS_BASED_VALUE(58, 0x032, 46, DOM_VK_M)] = RGFW_m RGFW_NEXT
1695 RGFW_MAP [RGFW_OS_BASED_VALUE(57, 0x031, 45, DOM_VK_N)] = RGFW_n RGFW_NEXT
1696 RGFW_MAP [RGFW_OS_BASED_VALUE(32, 0x018, 31, DOM_VK_O)] = RGFW_o RGFW_NEXT
1697 RGFW_MAP [RGFW_OS_BASED_VALUE(33, 0x019, 35, DOM_VK_P)] = RGFW_p RGFW_NEXT
1698 RGFW_MAP [RGFW_OS_BASED_VALUE(24, 0x010, 12, DOM_VK_Q)] = RGFW_q RGFW_NEXT
1699 RGFW_MAP [RGFW_OS_BASED_VALUE(27, 0x013, 15, DOM_VK_R)] = RGFW_r RGFW_NEXT
1700 RGFW_MAP [RGFW_OS_BASED_VALUE(39, 0x01F, 1, DOM_VK_S)] = RGFW_s RGFW_NEXT
1701 RGFW_MAP [RGFW_OS_BASED_VALUE(28, 0x014, 17, DOM_VK_T)] = RGFW_t RGFW_NEXT
1702 RGFW_MAP [RGFW_OS_BASED_VALUE(30, 0x016, 32, DOM_VK_U)] = RGFW_u RGFW_NEXT
1703 RGFW_MAP [RGFW_OS_BASED_VALUE(55, 0x02F, 9, DOM_VK_V)] = RGFW_v RGFW_NEXT
1704 RGFW_MAP [RGFW_OS_BASED_VALUE(25, 0x011, 13, DOM_VK_W)] = RGFW_w RGFW_NEXT
1705 RGFW_MAP [RGFW_OS_BASED_VALUE(53, 0x02D, 7, DOM_VK_X)] = RGFW_x RGFW_NEXT
1706 RGFW_MAP [RGFW_OS_BASED_VALUE(29, 0x015, 16, DOM_VK_Y)] = RGFW_y RGFW_NEXT
1707 RGFW_MAP [RGFW_OS_BASED_VALUE(52, 0x02C, 6, DOM_VK_Z)] = RGFW_z,
1708 RGFW_MAP [RGFW_OS_BASED_VALUE(60, 0x034, 47, DOM_VK_PERIOD)] = RGFW_period RGFW_NEXT
1709 RGFW_MAP [RGFW_OS_BASED_VALUE(59, 0x033, 43, DOM_VK_COMMA)] = RGFW_comma RGFW_NEXT
1710 RGFW_MAP [RGFW_OS_BASED_VALUE(61, 0x035, 44, DOM_VK_SLASH)] = RGFW_slash RGFW_NEXT
1711 RGFW_MAP [RGFW_OS_BASED_VALUE(34, 0x01A, 33, DOM_VK_OPEN_BRACKET)] = RGFW_bracket RGFW_NEXT
1712 RGFW_MAP [RGFW_OS_BASED_VALUE(35, 0x01B, 30, DOM_VK_CLOSE_BRACKET)] = RGFW_closeBracket RGFW_NEXT
1713 RGFW_MAP [RGFW_OS_BASED_VALUE(47, 0x027, 41, DOM_VK_SEMICOLON)] = RGFW_semicolon RGFW_NEXT
1714 RGFW_MAP [RGFW_OS_BASED_VALUE(48, 0x028, 39, DOM_VK_QUOTE)] = RGFW_apostrophe RGFW_NEXT
1715 RGFW_MAP [RGFW_OS_BASED_VALUE(51, 0x02B, 42, DOM_VK_BACK_SLASH)] = RGFW_backSlash,
1716 RGFW_MAP [RGFW_OS_BASED_VALUE(36, 0x01C, 36, DOM_VK_RETURN)] = RGFW_return RGFW_NEXT
1717 RGFW_MAP [RGFW_OS_BASED_VALUE(119, 0x153, 118, DOM_VK_DELETE)] = RGFW_delete RGFW_NEXT
1718 RGFW_MAP [RGFW_OS_BASED_VALUE(77, 0x145, 72, DOM_VK_NUM_LOCK)] = RGFW_numLock RGFW_NEXT
1719 RGFW_MAP [RGFW_OS_BASED_VALUE(106, 0x135, 82, DOM_VK_DIVIDE)] = RGFW_KP_Slash RGFW_NEXT
1720 RGFW_MAP [RGFW_OS_BASED_VALUE(63, 0x037, 76, DOM_VK_MULTIPLY)] = RGFW_multiply RGFW_NEXT
1721 RGFW_MAP [RGFW_OS_BASED_VALUE(82, 0x04A, 67, DOM_VK_SUBTRACT)] = RGFW_KP_Minus RGFW_NEXT
1722 RGFW_MAP [RGFW_OS_BASED_VALUE(87, 0x04F, 84, DOM_VK_NUMPAD1)] = RGFW_KP_1 RGFW_NEXT
1723 RGFW_MAP [RGFW_OS_BASED_VALUE(88, 0x050, 85, DOM_VK_NUMPAD2)] = RGFW_KP_2 RGFW_NEXT
1724 RGFW_MAP [RGFW_OS_BASED_VALUE(89, 0x051, 86, DOM_VK_NUMPAD3)] = RGFW_KP_3 RGFW_NEXT
1725 RGFW_MAP [RGFW_OS_BASED_VALUE(83, 0x04B, 87, DOM_VK_NUMPAD4)] = RGFW_KP_4 RGFW_NEXT
1726 RGFW_MAP [RGFW_OS_BASED_VALUE(84, 0x04C, 88, DOM_VK_NUMPAD5)] = RGFW_KP_5 RGFW_NEXT
1727 RGFW_MAP [RGFW_OS_BASED_VALUE(85, 0x04D, 89, DOM_VK_NUMPAD6)] = RGFW_KP_6 RGFW_NEXT
1728 RGFW_MAP [RGFW_OS_BASED_VALUE(79, 0x047, 90, DOM_VK_NUMPAD7)] = RGFW_KP_7 RGFW_NEXT
1729 RGFW_MAP [RGFW_OS_BASED_VALUE(80, 0x048, 92, DOM_VK_NUMPAD8)] = RGFW_KP_8 RGFW_NEXT
1730 RGFW_MAP [RGFW_OS_BASED_VALUE(81, 0x049, 93, DOM_VK_NUMPAD9)] = RGFW_KP_9 RGFW_NEXT
1731 RGFW_MAP [RGFW_OS_BASED_VALUE(90, 0x052, 83, DOM_VK_NUMPAD0)] = RGFW_KP_0 RGFW_NEXT
1732 RGFW_MAP [RGFW_OS_BASED_VALUE(91, 0x053, 65, DOM_VK_DECIMAL)] = RGFW_KP_Period RGFW_NEXT
1733 RGFW_MAP [RGFW_OS_BASED_VALUE(104, 0x11C, 77, 0)] = RGFW_KP_Return,
1734 RGFW_MAP [RGFW_OS_BASED_VALUE(20, 0x00C, 27, DOM_VK_HYPHEN_MINUS)] = RGFW_minus RGFW_NEXT
1735 RGFW_MAP [RGFW_OS_BASED_VALUE(21, 0x00D, 24, DOM_VK_EQUALS)] = RGFW_equals RGFW_NEXT
1736 RGFW_MAP [RGFW_OS_BASED_VALUE(22, 0x00E, 51, DOM_VK_BACK_SPACE)] = RGFW_backSpace RGFW_NEXT
1737 RGFW_MAP [RGFW_OS_BASED_VALUE(23, 0x00F, 48, DOM_VK_TAB)] = RGFW_tab RGFW_NEXT
1738 RGFW_MAP [RGFW_OS_BASED_VALUE(66, 0x03A, 57, DOM_VK_CAPS_LOCK)] = RGFW_capsLock RGFW_NEXT
1739 RGFW_MAP [RGFW_OS_BASED_VALUE(50, 0x02A, 56, DOM_VK_SHIFT)] = RGFW_shiftL RGFW_NEXT
1740 RGFW_MAP [RGFW_OS_BASED_VALUE(37, 0x01D, 59, DOM_VK_CONTROL)] = RGFW_controlL RGFW_NEXT
1741 RGFW_MAP [RGFW_OS_BASED_VALUE(64, 0x038, 58, DOM_VK_ALT)] = RGFW_altL RGFW_NEXT
1742 RGFW_MAP [RGFW_OS_BASED_VALUE(133, 0x15B, 55, DOM_VK_WIN)] = RGFW_superL,
1743 #if !defined(RGFW_MACOS) && !defined(RGFW_WASM)
1744 RGFW_MAP [RGFW_OS_BASED_VALUE(105, 0x11D, 59, 0)] = RGFW_controlR RGFW_NEXT
1745 RGFW_MAP [RGFW_OS_BASED_VALUE(134, 0x15C, 55, 0)] = RGFW_superR,
1746 RGFW_MAP [RGFW_OS_BASED_VALUE(62, 0x036, 56, 0)] = RGFW_shiftR RGFW_NEXT
1747 RGFW_MAP [RGFW_OS_BASED_VALUE(108, 0x138, 58, 0)] = RGFW_altR,
1748 #endif
1749 RGFW_MAP [RGFW_OS_BASED_VALUE(67, 0x03B, 127, DOM_VK_F1)] = RGFW_F1 RGFW_NEXT
1750 RGFW_MAP [RGFW_OS_BASED_VALUE(68, 0x03C, 121, DOM_VK_F2)] = RGFW_F2 RGFW_NEXT
1751 RGFW_MAP [RGFW_OS_BASED_VALUE(69, 0x03D, 100, DOM_VK_F3)] = RGFW_F3 RGFW_NEXT
1752 RGFW_MAP [RGFW_OS_BASED_VALUE(70, 0x03E, 119, DOM_VK_F4)] = RGFW_F4 RGFW_NEXT
1753 RGFW_MAP [RGFW_OS_BASED_VALUE(71, 0x03F, 97, DOM_VK_F5)] = RGFW_F5 RGFW_NEXT
1754 RGFW_MAP [RGFW_OS_BASED_VALUE(72, 0x040, 98, DOM_VK_F6)] = RGFW_F6 RGFW_NEXT
1755 RGFW_MAP [RGFW_OS_BASED_VALUE(73, 0x041, 99, DOM_VK_F7)] = RGFW_F7 RGFW_NEXT
1756 RGFW_MAP [RGFW_OS_BASED_VALUE(74, 0x042, 101, DOM_VK_F8)] = RGFW_F8 RGFW_NEXT
1757 RGFW_MAP [RGFW_OS_BASED_VALUE(75, 0x043, 102, DOM_VK_F9)] = RGFW_F9 RGFW_NEXT
1758 RGFW_MAP [RGFW_OS_BASED_VALUE(76, 0x044, 110, DOM_VK_F10)] = RGFW_F10 RGFW_NEXT
1759 RGFW_MAP [RGFW_OS_BASED_VALUE(95, 0x057, 104, DOM_VK_F11)] = RGFW_F11 RGFW_NEXT
1760 RGFW_MAP [RGFW_OS_BASED_VALUE(96, 0x058, 111, DOM_VK_F12)] = RGFW_F12 RGFW_NEXT
1761 RGFW_MAP [RGFW_OS_BASED_VALUE(111, 0x148, 126, DOM_VK_UP)] = RGFW_up RGFW_NEXT
1762 RGFW_MAP [RGFW_OS_BASED_VALUE(116, 0x150, 125, DOM_VK_DOWN)] = RGFW_down RGFW_NEXT
1763 RGFW_MAP [RGFW_OS_BASED_VALUE(113, 0x14B, 123, DOM_VK_LEFT)] = RGFW_left RGFW_NEXT
1764 RGFW_MAP [RGFW_OS_BASED_VALUE(114, 0x14D, 124, DOM_VK_RIGHT)] = RGFW_right RGFW_NEXT
1765 RGFW_MAP [RGFW_OS_BASED_VALUE(118, 0x152, 115, DOM_VK_INSERT)] = RGFW_insert RGFW_NEXT
1766 RGFW_MAP [RGFW_OS_BASED_VALUE(115, 0x14F, 120, DOM_VK_END)] = RGFW_end RGFW_NEXT
1767 RGFW_MAP [RGFW_OS_BASED_VALUE(112, 0x149, 117, DOM_VK_PAGE_UP)] = RGFW_pageUp RGFW_NEXT
1768 RGFW_MAP [RGFW_OS_BASED_VALUE(117, 0x151, 122, DOM_VK_PAGE_DOWN)] = RGFW_pageDown RGFW_NEXT
1769 RGFW_MAP [RGFW_OS_BASED_VALUE(9, 0x001, 53, DOM_VK_ESCAPE)] = RGFW_escape RGFW_NEXT
1770 RGFW_MAP [RGFW_OS_BASED_VALUE(110, 0x147, 116, DOM_VK_HOME)] = RGFW_home RGFW_NEXT
1771 RGFW_MAP [RGFW_OS_BASED_VALUE(78, 0x046, 107, DOM_VK_SCROLL_LOCK)] = RGFW_scrollLock RGFW_NEXT
1772 RGFW_MAP [RGFW_OS_BASED_VALUE(107, 0x137, 105, DOM_VK_PRINTSCREEN)] = RGFW_printScreen RGFW_NEXT
1773 RGFW_MAP [RGFW_OS_BASED_VALUE(128, 0x045, 113, DOM_VK_PAUSE)] = RGFW_pause RGFW_NEXT
1774#if defined(__cplusplus) || defined(RGFW_C89)
1775}
1776#else
1777};
1778#endif
1779
1780#undef RGFW_NEXT
1781#undef RGFW_MAP
1782
1783u32 RGFW_apiKeyToRGFW(u32 keycode) {
1784 #if defined(__cplusplus) || defined(RGFW_C89)
1785 if (RGFW_keycodes[RGFW_OS_BASED_VALUE(49, 0x029, 50, DOM_VK_BACK_QUOTE)] != RGFW_backtick) {
1786 RGFW_init_keys();
1787 }
1788 #endif
1789
1790 /* make sure the key isn't out of bounds */
1791 if (keycode > sizeof(RGFW_keycodes) / sizeof(u8))
1792 return 0;
1793
1794 return RGFW_keycodes[keycode];
1795}
1796
1797u32 RGFW_rgfwToApiKey(u32 keycode) {
1798 if (RGFW_apiKeycodes[RGFW_backtick] != RGFW_OS_BASED_VALUE(49, 0x029, 50, DOM_VK_BACK_QUOTE)) {
1799 for (u32 i = 0; i < RGFW_keyLast; i++) {
1800 for (u32 y = 0; y < sizeof(RGFW_keycodes); y++) {
1801 if (RGFW_keycodes[y] == i) {
1802 RGFW_apiKeycodes[i] = y;
1803 break;
1804 }
1805 }
1806 }
1807 }
1808
1809 /* make sure the key isn't out of bounds */
1810 if (keycode > sizeof(RGFW_apiKeycodes) / sizeof(u32))
1811 return 0;
1812
1813 return RGFW_apiKeycodes[keycode];
1814}
1815#endif /* RGFW_CUSTOM_BACKEND */
1816
1817typedef struct {
1818 RGFW_bool current : 1;
1819 RGFW_bool prev : 1;
1820} RGFW_keyState;
1821
1822RGFW_keyState RGFW_keyboard[RGFW_keyLast] = { {0, 0} };
1823
1824RGFWDEF void RGFW_resetKeyPrev(void);
1825void RGFW_resetKeyPrev(void) {
1826 size_t i; /*!< reset each previous state */
1827 for (i = 0; i < RGFW_keyLast; i++) RGFW_keyboard[i].prev = 0;
1828}
1829RGFWDEF void RGFW_resetKey(void);
1830void RGFW_resetKey(void) { RGFW_MEMSET(RGFW_keyboard, 0, sizeof(RGFW_keyboard)); }
1831/*
1832 this is the end of keycode data
1833*/
1834
1835/* gamepad data */
1836RGFW_keyState RGFW_gamepadPressed[4][32]; /*!< if a key is currently pressed or not (per gamepad) */
1837RGFW_point RGFW_gamepadAxes[4][4]; /*!< if a key is currently pressed or not (per gamepad) */
1838
1839RGFW_gamepadType RGFW_gamepads_type[4]; /*!< if a key is currently pressed or not (per gamepad) */
1840i32 RGFW_gamepads[4] = {0, 0, 0, 0}; /*!< limit of 4 gamepads at a time */
1841char RGFW_gamepads_name[4][128]; /*!< gamepad names */
1842u16 RGFW_gamepadCount = 0; /*!< the actual amount of gamepads */
1843
1844/*
1845 event callback defines start here
1846*/
1847
1848
1849/*
1850 These exist to avoid the
1851 if (func == NULL) check
1852 for (allegedly) better performance
1853
1854 RGFW_EMPTY_DEF exists to prevent the missing-prototypes warning
1855*/
1856static void RGFW_windowMovedfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); }
1857static void RGFW_windowResizedfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); }
1858static void RGFW_windowRestoredfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); }
1859static void RGFW_windowMinimizedfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); }
1860static void RGFW_windowMaximizedfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); }
1861static void RGFW_windowQuitfuncEMPTY(RGFW_window* win) { RGFW_UNUSED(win); }
1862static void RGFW_focusfuncEMPTY(RGFW_window* win, RGFW_bool inFocus) {RGFW_UNUSED(win); RGFW_UNUSED(inFocus);}
1863static void RGFW_mouseNotifyfuncEMPTY(RGFW_window* win, RGFW_point point, RGFW_bool status) {RGFW_UNUSED(win); RGFW_UNUSED(point); RGFW_UNUSED(status);}
1864static void RGFW_mousePosfuncEMPTY(RGFW_window* win, RGFW_point point, RGFW_point vector) {RGFW_UNUSED(win); RGFW_UNUSED(point); RGFW_UNUSED(vector);}
1865static void RGFW_dndInitfuncEMPTY(RGFW_window* win, RGFW_point point) {RGFW_UNUSED(win); RGFW_UNUSED(point);}
1866static void RGFW_windowRefreshfuncEMPTY(RGFW_window* win) {RGFW_UNUSED(win); }
1867static void RGFW_keyfuncEMPTY(RGFW_window* win, RGFW_key key, u8 keyChar, RGFW_keymod keyMod, RGFW_bool pressed) {RGFW_UNUSED(win); RGFW_UNUSED(key); RGFW_UNUSED(keyChar); RGFW_UNUSED(keyMod); RGFW_UNUSED(pressed);}
1868static void RGFW_mouseButtonfuncEMPTY(RGFW_window* win, RGFW_mouseButton button, double scroll, RGFW_bool pressed) {RGFW_UNUSED(win); RGFW_UNUSED(button); RGFW_UNUSED(scroll); RGFW_UNUSED(pressed);}
1869static void RGFW_gamepadButtonfuncEMPTY(RGFW_window* win, u16 gamepad, u8 button, RGFW_bool pressed) {RGFW_UNUSED(win); RGFW_UNUSED(gamepad); RGFW_UNUSED(button); RGFW_UNUSED(pressed); }
1870static void RGFW_gamepadAxisfuncEMPTY(RGFW_window* win, u16 gamepad, RGFW_point axis[2], u8 axisesCount, u8 whichAxis) {RGFW_UNUSED(win); RGFW_UNUSED(gamepad); RGFW_UNUSED(axis); RGFW_UNUSED(axisesCount); RGFW_UNUSED(whichAxis); }
1871static void RGFW_gamepadfuncEMPTY(RGFW_window* win, u16 gamepad, RGFW_bool connected) {RGFW_UNUSED(win); RGFW_UNUSED(gamepad); RGFW_UNUSED(connected);}
1872static void RGFW_dndfuncEMPTY(RGFW_window* win, char** droppedFiles, size_t droppedFilesCount) {RGFW_UNUSED(win); RGFW_UNUSED(droppedFiles); RGFW_UNUSED(droppedFilesCount);}
1873static void RGFW_scaleUpdatedfuncEMPTY(RGFW_window* win, float scaleX, float scaleY) {RGFW_UNUSED(win); RGFW_UNUSED(scaleX); RGFW_UNUSED(scaleY); }
1874
1875#define RGFW_CALLBACK_DEFINE(x, x2) \
1876RGFW_##x##func RGFW_##x##Callback = RGFW_##x##funcEMPTY; \
1877RGFW_##x##func RGFW_set##x2##Callback(RGFW_##x##func func) { \
1878 RGFW_##x##func prev = RGFW_##x##Callback; \
1879 RGFW_##x##Callback = func; \
1880 return prev; \
1881}
1882RGFW_CALLBACK_DEFINE(windowMaximized, WindowMaximized)
1883RGFW_CALLBACK_DEFINE(windowMinimized, WindowMinimized)
1884RGFW_CALLBACK_DEFINE(windowRestored, WindowRestored)
1885RGFW_CALLBACK_DEFINE(windowMoved, WindowMoved)
1886RGFW_CALLBACK_DEFINE(windowResized, WindowResized)
1887RGFW_CALLBACK_DEFINE(windowQuit, WindowQuit)
1888RGFW_CALLBACK_DEFINE(mousePos, MousePos)
1889RGFW_CALLBACK_DEFINE(windowRefresh, WindowRefresh)
1890RGFW_CALLBACK_DEFINE(focus, Focus)
1891RGFW_CALLBACK_DEFINE(mouseNotify, MouseNotify)
1892RGFW_CALLBACK_DEFINE(dnd, Dnd)
1893RGFW_CALLBACK_DEFINE(dndInit, DndInit)
1894RGFW_CALLBACK_DEFINE(key, Key)
1895RGFW_CALLBACK_DEFINE(mouseButton, MouseButton)
1896RGFW_CALLBACK_DEFINE(gamepadButton, GamepadButton)
1897RGFW_CALLBACK_DEFINE(gamepadAxis, GamepadAxis)
1898RGFW_CALLBACK_DEFINE(gamepad, Gamepad)
1899RGFW_CALLBACK_DEFINE(scaleUpdated, ScaleUpdated)
1900#undef RGFW_CALLBACK_DEFINE
1901
1902void RGFW_window_checkEvents(RGFW_window* win, i32 waitMS) {
1903 RGFW_window_eventWait(win, waitMS);
1904
1905 while (RGFW_window_checkEvent(win) != NULL && RGFW_window_shouldClose(win) == 0) {
1906 if (win->event.type == RGFW_quit) return;
1907 }
1908
1909 #ifdef RGFW_WASM /* WASM needs to run the sleep function for asyncify */
1910 RGFW_sleep(0);
1911 #endif
1912}
1913
1914void RGFW_window_checkMode(RGFW_window* win);
1915void RGFW_window_checkMode(RGFW_window* win) {
1916 if (RGFW_window_isMinimized(win)) {
1917 win->_flags |= RGFW_windowMinimize;
1918 RGFW_windowMinimizedCallback(win, win->r);
1919 } else if (RGFW_window_isMaximized(win)) {
1920 win->_flags |= RGFW_windowMaximize;
1921 RGFW_eventQueuePushEx(e.type = RGFW_windowMaximized; e._win = win);
1922 RGFW_windowMaximizedCallback(win, win->r);
1923 } else if (((win->_flags & RGFW_windowMinimize) && !RGFW_window_isMaximized(win)) ||
1924 (win->_flags & RGFW_windowMaximize && !RGFW_window_isMaximized(win))) {
1925 win->_flags &= ~(u32)RGFW_windowMinimize;
1926 if (RGFW_window_isMaximized(win) == RGFW_FALSE) win->_flags &= ~(u32)RGFW_windowMaximize;
1927 RGFW_eventQueuePushEx(e.type = RGFW_windowRestored; e._win = win);
1928 RGFW_windowRestoredCallback(win, win->r);
1929 }
1930}
1931
1932/*
1933no more event call back defines
1934*/
1935
1936#define SET_ATTRIB(a, v) { \
1937 RGFW_ASSERT(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
1938 attribs[index++] = a; \
1939 attribs[index++] = v; \
1940}
1941
1942#define RGFW_EVENT_PASSED RGFW_BIT(24) /* if a queued event was passed */
1943#define RGFW_EVENT_QUIT RGFW_BIT(25) /* the window close button was pressed */
1944#define RGFW_HOLD_MOUSE RGFW_BIT(26) /*!< hold the moues still */
1945#define RGFW_MOUSE_LEFT RGFW_BIT(27) /* if mouse left the window */
1946#define RGFW_WINDOW_ALLOC RGFW_BIT(28) /* if window was allocated by RGFW */
1947#define RGFW_BUFFER_ALLOC RGFW_BIT(29) /* if window.buffer was allocated by RGFW */
1948#define RGFW_WINDOW_INIT RGFW_BIT(30) /* if window.buffer was allocated by RGFW */
1949#define RGFW_INTERNAL_FLAGS (RGFW_EVENT_QUIT | RGFW_EVENT_PASSED | RGFW_HOLD_MOUSE | RGFW_MOUSE_LEFT | RGFW_WINDOW_ALLOC | RGFW_BUFFER_ALLOC | RGFW_windowFocus)
1950
1951RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, RGFW_windowFlags flags) {
1952 RGFW_window* win = (RGFW_window*)RGFW_ALLOC(sizeof(RGFW_window));
1953 RGFW_ASSERT(win != NULL);
1954 win->_flags = RGFW_WINDOW_ALLOC;
1955 return RGFW_createWindowPtr(name, rect, flags, win);
1956}
1957
1958#if defined(RGFW_USE_XDL) && defined(RGFW_X11)
1959 #define XDL_IMPLEMENTATION
1960 #include "XDL.h"
1961#endif
1962
1963#define RGFW_MAX_EVENTS 32
1964typedef struct RGFW_globalStruct {
1965 RGFW_window* root;
1966 RGFW_window* current;
1967 i32 windowCount;
1968 i32 eventLen;
1969 i32 eventIndex;
1970
1971 #ifdef RGFW_X11
1972 Display* display;
1973 Window helperWindow;
1974 char* clipboard; /* for writing to the clipboard selection */
1975 size_t clipboard_len;
1976 #endif
1977 #ifdef RGFW_WAYLAND
1978 struct wl_display* wl_display;
1979 #endif
1980 #if defined(RGFW_X11) || defined(RGFW_WINDOWS) || defined(RGFW_WAYLAND)
1981 RGFW_mouse* hiddenMouse;
1982 #endif
1983 RGFW_event events[RGFW_MAX_EVENTS];
1984
1985} RGFW_globalStruct;
1986#if !defined(RGFW_C89) && !defined(__cplusplus)
1987RGFW_globalStruct _RGFW = {.root = NULL, .current = NULL, .windowCount = -1, .eventLen = 0, .eventIndex = 0};
1988#define _RGFW_init RGFW_TRUE
1989#else
1990RGFW_bool _RGFW_init = RGFW_FALSE;
1991RGFW_globalStruct _RGFW;
1992#endif
1993
1994void RGFW_eventQueuePush(RGFW_event event) {
1995 if (_RGFW.eventLen >= RGFW_MAX_EVENTS) return;
1996 _RGFW.events[_RGFW.eventLen] = event;
1997 _RGFW.eventLen++;
1998}
1999
2000RGFW_event* RGFW_eventQueuePop(RGFW_window* win) {
2001 RGFW_event* ev;
2002 if (_RGFW.eventLen == 0) return NULL;
2003
2004 ev = (RGFW_event*)&_RGFW.events[_RGFW.eventIndex];
2005
2006 _RGFW.eventLen--;
2007 if (_RGFW.eventLen >= 0 && _RGFW.eventIndex < _RGFW.eventLen) {
2008 _RGFW.eventIndex++;
2009 } else if (_RGFW.eventLen == 0) {
2010 _RGFW.eventIndex = 0;
2011 }
2012
2013 if (ev->_win != win && ev->_win != NULL) {
2014 RGFW_eventQueuePush(*ev);
2015 return NULL;
2016 }
2017
2018 ev->droppedFilesCount = win->event.droppedFilesCount;
2019 ev->droppedFiles = win->event.droppedFiles;
2020 return ev;
2021}
2022
2023RGFW_event* RGFW_window_checkEventCore(RGFW_window* win);
2024RGFW_event* RGFW_window_checkEventCore(RGFW_window* win) {
2025 RGFW_event* ev;
2026 RGFW_ASSERT(win != NULL);
2027 if (win->event.type == 0 && _RGFW.eventLen == 0)
2028 RGFW_resetKeyPrev();
2029
2030 if (win->event.type == RGFW_quit && win->_flags & RGFW_windowFreeOnClose) {
2031 static RGFW_event event;
2032 event = win->event;
2033 RGFW_window_close(win);
2034 return &event;
2035 }
2036
2037 if (win->event.type != RGFW_DNDInit) win->event.type = 0;
2038
2039 /* check queued events */
2040 ev = RGFW_eventQueuePop(win);
2041 if (ev != NULL) {
2042 if (ev->type == RGFW_quit) RGFW_window_setShouldClose(win, RGFW_TRUE);
2043 win->event = *ev;
2044 }
2045 else return NULL;
2046
2047 return &win->event;
2048}
2049
2050
2051RGFWDEF void RGFW_window_basic_init(RGFW_window* win, RGFW_rect rect, RGFW_windowFlags flags);
2052void RGFW_setRootWindow(RGFW_window* win) { _RGFW.root = win; }
2053RGFW_window* RGFW_getRootWindow(void) { return _RGFW.root; }
2054
2055/* do a basic initialization for RGFW_window, this is to standard it for each OS */
2056void RGFW_window_basic_init(RGFW_window* win, RGFW_rect rect, RGFW_windowFlags flags) {
2057 RGFW_UNUSED(flags);
2058 if (_RGFW.windowCount == -1 || _RGFW_init == RGFW_FALSE) RGFW_init();
2059 _RGFW.windowCount++;
2060
2061 /* rect based the requested flags */
2062 if (_RGFW.root == NULL) {
2063 RGFW_setRootWindow(win);
2064 RGFW_setTime(0);
2065 }
2066
2067 if (!(win->_flags & RGFW_WINDOW_ALLOC)) win->_flags = 0;
2068
2069 /* set and init the new window's data */
2070 win->r = rect;
2071 win->exitKey = RGFW_escape;
2072 win->event.droppedFilesCount = 0;
2073
2074 win->_flags = 0 | (win->_flags & RGFW_WINDOW_ALLOC);
2075 win->_flags |= flags;
2076 win->event.keyMod = 0;
2077 win->_lastMousePoint.x = 0;
2078 win->_lastMousePoint.y = 0;
2079
2080 win->event.droppedFiles = (char**)RGFW_ALLOC(RGFW_MAX_PATH * RGFW_MAX_DROPS);
2081 RGFW_ASSERT(win->event.droppedFiles != NULL);
2082
2083 {
2084 u32 i;
2085 for (i = 0; i < RGFW_MAX_DROPS; i++)
2086 win->event.droppedFiles[i] = (char*)(win->event.droppedFiles + RGFW_MAX_DROPS + (i * RGFW_MAX_PATH));
2087 }
2088}
2089
2090void RGFW_window_setFlags(RGFW_window* win, RGFW_windowFlags flags) {
2091 RGFW_windowFlags cmpFlags = win->_flags;
2092 if (win->_flags & RGFW_WINDOW_INIT) cmpFlags = 0;
2093
2094 #ifndef RGFW_NO_MONITOR
2095 if (flags & RGFW_windowScaleToMonitor) RGFW_window_scaleToMonitor(win);
2096 #endif
2097
2098 if (flags & RGFW_windowCenter) RGFW_window_center(win);
2099 if (flags & RGFW_windowCenterCursor)
2100 RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2)));
2101 if (flags & RGFW_windowNoBorder) RGFW_window_setBorder(win, 0);
2102 else RGFW_window_setBorder(win, 1);
2103 if (flags & RGFW_windowFullscreen) RGFW_window_setFullscreen(win, RGFW_TRUE);
2104 else if (cmpFlags & RGFW_windowFullscreen) RGFW_window_setFullscreen(win, 0);
2105 if (flags & RGFW_windowMaximize) RGFW_window_maximize(win);
2106 else if (cmpFlags & RGFW_windowMaximize) RGFW_window_restore(win);
2107 if (flags & RGFW_windowMinimize) RGFW_window_minimize(win);
2108 else if (cmpFlags & RGFW_windowMinimize) RGFW_window_restore(win);
2109 if (flags & RGFW_windowHideMouse) RGFW_window_showMouse(win, 0);
2110 else if (cmpFlags & RGFW_windowHideMouse) RGFW_window_showMouse(win, 1);
2111 if (flags & RGFW_windowHide) RGFW_window_hide(win);
2112 else if (cmpFlags & RGFW_windowHide) RGFW_window_show(win);
2113 if (flags & RGFW_windowCocoaCHDirToRes) RGFW_moveToMacOSResourceDir();
2114 if (flags & RGFW_windowFloating) RGFW_window_setFloating(win, 1);
2115 else if (cmpFlags & RGFW_windowFloating) RGFW_window_setFloating(win, 0);
2116 if (flags & RGFW_windowFocus) RGFW_window_focus(win);
2117
2118 if (flags & RGFW_windowNoResize) {
2119 RGFW_window_setMaxSize(win, RGFW_AREA(win->r.w, win->r.h));
2120 RGFW_window_setMinSize(win, RGFW_AREA(win->r.w, win->r.h));
2121 } else if (cmpFlags & RGFW_windowNoResize) {
2122 RGFW_window_setMaxSize(win, RGFW_AREA(0, 0));
2123 RGFW_window_setMinSize(win, RGFW_AREA(0, 0));
2124 }
2125
2126 win->_flags = flags | (win->_flags & RGFW_INTERNAL_FLAGS);
2127}
2128
2129RGFW_bool RGFW_window_opengl_isSoftware(RGFW_window* win) {
2130 return RGFW_BOOL(win->_flags |= RGFW_windowOpenglSoftware);
2131}
2132
2133RGFW_bool RGFW_window_isInFocus(RGFW_window* win) {
2134#ifdef RGFW_WASM
2135 return RGFW_TRUE;
2136#else
2137 return RGFW_BOOL(win->_flags & RGFW_windowFocus);
2138#endif
2139}
2140
2141void RGFW_window_initBuffer(RGFW_window* win) {
2142 RGFW_area area = RGFW_getScreenSize();
2143 if ((win->_flags & RGFW_windowNoResize))
2144 area = RGFW_AREA(win->r.w, win->r.h);
2145
2146 RGFW_window_initBufferSize(win, area);
2147}
2148
2149void RGFW_window_initBufferSize(RGFW_window* win, RGFW_area area) {
2150#if defined(RGFW_BUFFER) || defined(RGFW_OSMESA)
2151 win->_flags |= RGFW_BUFFER_ALLOC;
2152 #ifndef RGFW_WINDOWS
2153 u8* buffer = (u8*)RGFW_ALLOC(area.w * area.h * 4);
2154 RGFW_ASSERT(buffer != NULL);
2155
2156 RGFW_window_initBufferPtr(win, buffer, area);
2157 #else /* windows's bitmap allocs memory for us */
2158 RGFW_window_initBufferPtr(win, (u8*)NULL, area);
2159 #endif
2160#else
2161 RGFW_UNUSED(win); RGFW_UNUSED(area);
2162#endif
2163}
2164
2165#ifdef RGFW_MACOS
2166RGFWDEF void RGFW_window_cocoaSetLayer(RGFW_window* win, void* layer);
2167RGFWDEF void* RGFW_cocoaGetLayer(void);
2168#endif
2169
2170const char* RGFW_className = NULL;
2171void RGFW_setClassName(const char* name) { RGFW_className = name; }
2172
2173#ifndef RGFW_X11
2174void RGFW_setXInstName(const char* name) { RGFW_UNUSED(name); }
2175#endif
2176
2177RGFW_keyState RGFW_mouseButtons[RGFW_mouseFinal] = { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2178
2179RGFW_bool RGFW_isMousePressed(RGFW_window* win, RGFW_mouseButton button) {
2180 return RGFW_mouseButtons[button].current && (win == NULL || RGFW_window_isInFocus(win));
2181}
2182RGFW_bool RGFW_wasMousePressed(RGFW_window* win, RGFW_mouseButton button) {
2183 return RGFW_mouseButtons[button].prev && (win != NULL || RGFW_window_isInFocus(win));
2184}
2185RGFW_bool RGFW_isMouseHeld(RGFW_window* win, RGFW_mouseButton button) {
2186 return (RGFW_isMousePressed(win, button) && RGFW_wasMousePressed(win, button));
2187}
2188RGFW_bool RGFW_isMouseReleased(RGFW_window* win, RGFW_mouseButton button) {
2189 return (!RGFW_isMousePressed(win, button) && RGFW_wasMousePressed(win, button));
2190}
2191
2192RGFW_point RGFW_window_getMousePoint(RGFW_window* win) {
2193 RGFW_ASSERT(win != NULL);
2194 return win->_lastMousePoint;
2195}
2196
2197RGFW_bool RGFW_isPressed(RGFW_window* win, RGFW_key key) {
2198 return RGFW_keyboard[key].current && (win == NULL || RGFW_window_isInFocus(win));
2199}
2200
2201RGFW_bool RGFW_wasPressed(RGFW_window* win, RGFW_key key) {
2202 return RGFW_keyboard[key].prev && (win == NULL || RGFW_window_isInFocus(win));
2203}
2204
2205RGFW_bool RGFW_isHeld(RGFW_window* win, RGFW_key key) {
2206 return (RGFW_isPressed(win, key) && RGFW_wasPressed(win, key));
2207}
2208
2209RGFW_bool RGFW_isClicked(RGFW_window* win, RGFW_key key) {
2210 return (RGFW_wasPressed(win, key) && !RGFW_isPressed(win, key));
2211}
2212
2213RGFW_bool RGFW_isReleased(RGFW_window* win, RGFW_key key) {
2214 return (!RGFW_isPressed(win, key) && RGFW_wasPressed(win, key));
2215}
2216
2217void RGFW_window_makeCurrent(RGFW_window* win) {
2218 _RGFW.current = win;
2219#if defined(RGFW_OPENGL) || defined(RGFW_EGL)
2220 RGFW_window_makeCurrent_OpenGL(win);
2221#endif
2222}
2223
2224RGFW_window* RGFW_getCurrent(void) {
2225 return _RGFW.current;
2226}
2227
2228void RGFW_window_swapBuffers(RGFW_window* win) {
2229 RGFW_ASSERT(win != NULL);
2230 RGFW_window_swapBuffers_software(win);
2231#if defined(RGFW_OPENGL) || defined(RGFW_EGL)
2232 RGFW_window_swapBuffers_OpenGL(win);
2233#endif
2234}
2235
2236RGFWDEF void RGFW_setBit(u32* data, u32 bit, RGFW_bool value);
2237void RGFW_setBit(u32* data, u32 bit, RGFW_bool value) {
2238 if (value)
2239 *data |= bit;
2240 else if (!value && (*(data) & bit))
2241 *data ^= bit;
2242}
2243
2244void RGFW_window_center(RGFW_window* win) {
2245 RGFW_ASSERT(win != NULL);
2246 RGFW_area screenR = RGFW_getScreenSize();
2247 RGFW_window_move(win, RGFW_POINT((i32)(screenR.w - (u32)win->r.w) / 2, (screenR.h - (u32)win->r.h) / 2));
2248}
2249
2250RGFW_bool RGFW_monitor_scaleToWindow(RGFW_monitor mon, RGFW_window* win) {
2251 RGFW_monitorMode mode;
2252 RGFW_ASSERT(win != NULL);
2253
2254 mode.area.w = (u32)win->r.w;
2255 mode.area.h = (u32)win->r.h;
2256 return RGFW_monitor_requestMode(mon, mode, RGFW_monitorScale);
2257}
2258
2259void RGFW_splitBPP(u32 bpp, RGFW_monitorMode* mode);
2260void RGFW_splitBPP(u32 bpp, RGFW_monitorMode* mode) {
2261 if (bpp == 32) bpp = 24;
2262 mode->red = mode->green = mode->blue = (u8)(bpp / 3);
2263
2264 u32 delta = bpp - (mode->red * 3); /* handle leftovers */
2265 if (delta >= 1) mode->green = mode->green + 1;
2266 if (delta == 2) mode->red = mode->red + 1;
2267}
2268
2269RGFW_bool RGFW_monitorModeCompare(RGFW_monitorMode mon, RGFW_monitorMode mon2, RGFW_modeRequest request) {
2270 return (((mon.area.w == mon2.area.w && mon.area.h == mon2.area.h) || !(request & RGFW_monitorScale)) &&
2271 ((mon.refreshRate == mon2.refreshRate) || !(request & RGFW_monitorRefresh)) &&
2272 ((mon.red == mon2.red && mon.green == mon2.green && mon.blue == mon2.blue) || !(request & RGFW_monitorRGB)));
2273}
2274
2275RGFW_bool RGFW_window_shouldClose(RGFW_window* win) {
2276 return (win == NULL || (win->_flags & RGFW_EVENT_QUIT)|| (win->exitKey && RGFW_isPressed(win, win->exitKey)));
2277}
2278
2279void RGFW_window_setShouldClose(RGFW_window* win, RGFW_bool shouldClose) {
2280 if (shouldClose) {
2281 win->_flags |= RGFW_EVENT_QUIT;
2282 RGFW_windowQuitCallback(win);
2283 } else {
2284 win->_flags &= ~(u32)RGFW_EVENT_QUIT;
2285 }
2286}
2287
2288#ifndef RGFW_NO_MONITOR
2289void RGFW_window_scaleToMonitor(RGFW_window* win) {
2290 RGFW_monitor monitor = RGFW_window_getMonitor(win);
2291 if (monitor.scaleX == 0 && monitor.scaleY == 0)
2292 return;
2293
2294 RGFW_window_resize(win, RGFW_AREA((u32)(monitor.scaleX * (float)win->r.w), (u32)(monitor.scaleY * (float)win->r.h)));
2295}
2296
2297void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m) {
2298 RGFW_window_move(win, RGFW_POINT(m.x + win->r.x, m.y + win->r.y));
2299}
2300#endif
2301
2302RGFW_bool RGFW_window_setIcon(RGFW_window* win, u8* icon, RGFW_area a, i32 channels) {
2303 return RGFW_window_setIconEx(win, icon, a, channels, RGFW_iconBoth);
2304}
2305
2306RGFWDEF void RGFW_captureCursor(RGFW_window* win, RGFW_rect);
2307RGFWDEF void RGFW_releaseCursor(RGFW_window* win);
2308
2309
2310RGFW_bool RGFW_window_mouseHeld(RGFW_window* win) { return RGFW_BOOL(win->_flags & RGFW_HOLD_MOUSE); }
2311
2312void RGFW_window_mouseHold(RGFW_window* win, RGFW_area area) {
2313 if (!area.w && !area.h)
2314 area = RGFW_AREA(win->r.w / 2, win->r.h / 2);
2315
2316 win->_flags |= RGFW_HOLD_MOUSE;
2317 RGFW_captureCursor(win, win->r);
2318 RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2)));
2319}
2320
2321void RGFW_window_mouseUnhold(RGFW_window* win) {
2322 win->_flags &= ~(u32)RGFW_HOLD_MOUSE;
2323 RGFW_releaseCursor(win);
2324}
2325
2326u32 RGFW_checkFPS(double startTime, u32 frameCount, u32 fpsCap) {
2327 double deltaTime = RGFW_getTime() - startTime;
2328 if (deltaTime == 0) return 0;
2329
2330 double fps = (frameCount / deltaTime); /* the numer of frames over the time it took for them to render */
2331 if (fpsCap && fps > fpsCap) {
2332 double frameTime = (double)frameCount / (double)fpsCap; /* how long it should take to finish the frames */
2333 double sleepTime = frameTime - deltaTime; /* subtract how long it should have taken with how long it did take */
2334
2335 if (sleepTime > 0) RGFW_sleep((u32)(sleepTime * 1000));
2336 }
2337
2338 return (u32) fps;
2339}
2340
2341#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
2342void RGFW_RGB_to_BGR(RGFW_window* win, u8* data) {
2343 #if !defined(RGFW_BUFFER_BGR) && !defined(RGFW_OSMESA)
2344 u32 x, y;
2345 for (y = 0; y < (u32)win->r.h; y++) {
2346 for (x = 0; x < (u32)win->r.w; x++) {
2347 u32 index = (y * 4 * win->bufferSize.w) + x * 4;
2348
2349 u8 red = data[index];
2350 data[index] = win->buffer[index + 2];
2351 data[index + 2] = red;
2352 }
2353 }
2354 #elif defined(RGFW_OSMESA)
2355 u32 y;
2356 for(y = 0; y < (u32)win->r.h; y++){
2357 u32 index_from = (y + (win->bufferSize.h - win->r.h)) * 4 * win->bufferSize.w;
2358 u32 index_to = y * 4 * win->bufferSize.w;
2359 memcpy(&data[index_to], &data[index_from], 4 * win->bufferSize.w);
2360 }
2361 #else
2362 RGFW_UNUSED(win); RGFW_UNUSED(data);
2363 #endif
2364}
2365#endif
2366
2367u32 RGFW_isPressedGamepad(RGFW_window* win, u8 c, RGFW_gamepadCodes button) {
2368 RGFW_UNUSED(win);
2369 return RGFW_gamepadPressed[c][button].current;
2370}
2371u32 RGFW_wasPressedGamepad(RGFW_window* win, u8 c, RGFW_gamepadCodes button) {
2372 RGFW_UNUSED(win);
2373 return RGFW_gamepadPressed[c][button].prev;
2374}
2375u32 RGFW_isReleasedGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button) {
2376 RGFW_UNUSED(win);
2377 return !RGFW_isPressedGamepad(win, controller, button) && RGFW_wasPressedGamepad(win, controller, button);
2378}
2379u32 RGFW_isHeldGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button) {
2380 RGFW_UNUSED(win);
2381 return RGFW_isPressedGamepad(win, controller, button) && RGFW_wasPressedGamepad(win, controller, button);
2382}
2383
2384RGFW_point RGFW_getGamepadAxis(RGFW_window* win, u16 controller, u16 whichAxis) {
2385 RGFW_UNUSED(win);
2386 return RGFW_gamepadAxes[controller][whichAxis];
2387}
2388const char* RGFW_getGamepadName(RGFW_window* win, u16 controller) {
2389 RGFW_UNUSED(win);
2390 return (const char*)RGFW_gamepads_name[controller];
2391}
2392
2393size_t RGFW_getGamepadCount(RGFW_window* win) {
2394 RGFW_UNUSED(win);
2395 return RGFW_gamepadCount;
2396}
2397
2398RGFW_gamepadType RGFW_getGamepadType(RGFW_window* win, u16 controller) {
2399 RGFW_UNUSED(win);
2400 return RGFW_gamepads_type[controller];
2401}
2402
2403RGFWDEF void RGFW_updateKeyMod(RGFW_window* win, RGFW_keymod mod, RGFW_bool value);
2404void RGFW_updateKeyMod(RGFW_window* win, RGFW_keymod mod, RGFW_bool value) {
2405 if (value) win->event.keyMod |= mod;
2406 else win->event.keyMod &= ~mod;
2407}
2408
2409RGFWDEF void RGFW_updateKeyModsPro(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll);
2410void RGFW_updateKeyModsPro(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll) {
2411 RGFW_updateKeyMod(win, RGFW_modCapsLock, capital);
2412 RGFW_updateKeyMod(win, RGFW_modNumLock, numlock);
2413 RGFW_updateKeyMod(win, RGFW_modControl, control);
2414 RGFW_updateKeyMod(win, RGFW_modAlt, alt);
2415 RGFW_updateKeyMod(win, RGFW_modShift, shift);
2416 RGFW_updateKeyMod(win, RGFW_modSuper, super);
2417 RGFW_updateKeyMod(win, RGFW_modScrollLock, scroll);
2418}
2419
2420RGFWDEF void RGFW_updateKeyMods(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool scroll);
2421void RGFW_updateKeyMods(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool scroll) {
2422 RGFW_updateKeyModsPro(win, capital, numlock,
2423 RGFW_isPressed(win, RGFW_controlL) || RGFW_isPressed(win, RGFW_controlR),
2424 RGFW_isPressed(win, RGFW_altL) || RGFW_isPressed(win, RGFW_altR),
2425 RGFW_isPressed(win, RGFW_shiftL) || RGFW_isPressed(win, RGFW_shiftR),
2426 RGFW_isPressed(win, RGFW_superL) || RGFW_isPressed(win, RGFW_superR),
2427 scroll);
2428}
2429
2430RGFWDEF void RGFW_window_showMouseFlags(RGFW_window* win, RGFW_bool show);
2431void RGFW_window_showMouseFlags(RGFW_window* win, RGFW_bool show) {
2432 if (show && (win->_flags & RGFW_windowHideMouse))
2433 win->_flags ^= RGFW_windowHideMouse;
2434 else if (!show && !(win->_flags & RGFW_windowHideMouse))
2435 win->_flags |= RGFW_windowHideMouse;
2436}
2437
2438RGFW_bool RGFW_window_mouseHidden(RGFW_window* win) {
2439 return (RGFW_bool)RGFW_BOOL(win->_flags & RGFW_windowHideMouse);
2440}
2441
2442RGFW_bool RGFW_window_borderless(RGFW_window* win) {
2443 return (RGFW_bool)RGFW_BOOL(win->_flags & RGFW_windowNoBorder);
2444}
2445
2446RGFW_bool RGFW_window_isFullscreen(RGFW_window* win){ return RGFW_BOOL(win->_flags & RGFW_windowFullscreen); }
2447RGFW_bool RGFW_window_allowsDND(RGFW_window* win) { return RGFW_BOOL(win->_flags & RGFW_windowAllowDND); }
2448
2449void RGFW_window_focusLost(RGFW_window* win) {
2450 /* standard routines for when a window looses focus */
2451 _RGFW.root->_flags &= ~(u32)RGFW_windowFocus;
2452 if ((win->_flags & RGFW_windowFullscreen))
2453 RGFW_window_minimize(win);
2454
2455 for (size_t key = 0; key < RGFW_keyLast; key++) {
2456 if (RGFW_isPressed(NULL, (u8)key) == RGFW_FALSE) continue;
2457 RGFW_keyboard[key].current = RGFW_FALSE;
2458 u8 keyChar = RGFW_rgfwToKeyChar((u32)key);
2459 RGFW_keyCallback(win, (u8)key, keyChar, win->event.keyMod, RGFW_FALSE);
2460 RGFW_eventQueuePushEx(e.type = RGFW_keyReleased;
2461 e.key = (u8)key;
2462 e.keyChar = keyChar;
2463 e.repeat = RGFW_FALSE;
2464 e.keyMod = win->event.keyMod;
2465 e._win = win);
2466 }
2467
2468 RGFW_resetKey();
2469}
2470
2471#ifndef RGFW_WINDOWS
2472void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow) {
2473 RGFW_setBit(&win->_flags, RGFW_windowAllowDND, allow);
2474}
2475#endif
2476
2477#if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WASM) || defined(RGFW_WAYLAND)
2478#ifndef __USE_POSIX199309
2479 #define __USE_POSIX199309
2480#endif
2481#include <time.h>
2482struct timespec;
2483#endif
2484
2485#if defined(RGFW_WAYLAND) || defined(RGFW_X11) || defined(RGFW_WINDOWS)
2486void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) {
2487 RGFW_window_showMouseFlags(win, show);
2488 if (show == 0)
2489 RGFW_window_setMouse(win, _RGFW.hiddenMouse);
2490 else
2491 RGFW_window_setMouseDefault(win);
2492}
2493#endif
2494
2495#ifndef RGFW_MACOS
2496void RGFW_moveToMacOSResourceDir(void) { }
2497#endif
2498
2499/*
2500 graphics API specific code (end of generic code)
2501 starts here
2502*/
2503
2504
2505/*
2506 OpenGL defines start here (Normal, EGL, OSMesa)
2507*/
2508
2509#if defined(RGFW_OPENGL) || defined(RGFW_EGL)
2510
2511#ifdef RGFW_WINDOWS
2512 #define WIN32_LEAN_AND_MEAN
2513 #define OEMRESOURCE
2514 #include <windows.h>
2515#endif
2516
2517#if !defined(__APPLE__) && !defined(RGFW_NO_GL_HEADER)
2518 #include <GL/gl.h>
2519#elif defined(__APPLE__)
2520 #ifndef GL_SILENCE_DEPRECATION
2521 #define GL_SILENCE_DEPRECATION
2522 #endif
2523 #include <OpenGL/gl.h>
2524 #include <OpenGL/OpenGL.h>
2525#endif
2526
2527/* EGL, normal OpenGL only */
2528#ifndef RGFW_EGL
2529i32 RGFW_GL_HINTS[RGFW_glFinalHint] = {8,
2530#else
2531i32 RGFW_GL_HINTS[RGFW_glFinalHint] = {0,
2532#endif
2533 0, 0, 0, 1, 8, 8, 8, 8, 24, 0, 0, 0, 0, 0, 0, 0, 0, RGFW_glReleaseNone, RGFW_glCore, 0, 0};
2534
2535void RGFW_setGLHint(RGFW_glHints hint, i32 value) {
2536 if (hint < RGFW_glFinalHint && hint) RGFW_GL_HINTS[hint] = value;
2537}
2538
2539RGFW_bool RGFW_extensionSupportedStr(const char* extensions, const char* ext, size_t len) {
2540 const char *start = extensions;
2541 const char *where;
2542 const char* terminator;
2543
2544 if (extensions == NULL || ext == NULL)
2545 return RGFW_FALSE;
2546
2547 where = strstr(extensions, ext);
2548 while (where) {
2549 terminator = where + len;
2550 if ((where == start || *(where - 1) == ' ') &&
2551 (*terminator == ' ' || *terminator == '\0')) {
2552 return RGFW_TRUE;
2553 }
2554 where = RGFW_STRSTR(terminator, ext);
2555 }
2556
2557 return RGFW_FALSE;
2558}
2559
2560RGFW_bool RGFW_extensionSupported(const char* extension, size_t len) {
2561 #ifdef GL_NUM_EXTENSIONS
2562 if (RGFW_GL_HINTS[RGFW_glMajor] >= 3) {
2563 i32 i;
2564 GLint count = 0;
2565
2566 RGFW_proc RGFW_glGetStringi = RGFW_getProcAddress("glGetStringi");
2567 RGFW_proc RGFW_glGetIntegerv = RGFW_getProcAddress("RGFW_glGetIntegerv");
2568 if (RGFW_glGetIntegerv)
2569 ((void(*)(GLenum, GLint*))RGFW_glGetIntegerv)(GL_NUM_EXTENSIONS, &count);
2570
2571 for (i = 0; RGFW_glGetStringi && i < count; i++) {
2572 const char* en = ((const char* (*)(u32, u32))RGFW_glGetStringi)(GL_EXTENSIONS, (u32)i);
2573 if (en && RGFW_STRNCMP(en, extension, len) == 0)
2574 return RGFW_TRUE;
2575 }
2576 } else
2577#endif
2578 {
2579 RGFW_proc RGFW_glGetString = RGFW_getProcAddress("glGetString");
2580
2581 if (RGFW_glGetString) {
2582 const char* extensions = ((const char*(*)(u32))RGFW_glGetString)(GL_EXTENSIONS);
2583 if ((extensions != NULL) && RGFW_extensionSupportedStr(extensions, extension, len))
2584 return RGFW_TRUE;
2585 }
2586 }
2587
2588 return RGFW_extensionSupportedPlatform(extension, len);
2589}
2590
2591/* OPENGL normal only (no EGL / OSMesa) */
2592#if defined(RGFW_OPENGL) && !defined(RGFW_EGL) && !defined(RGFW_CUSTOM_BACKEND) && !defined(RGFW_WASM)
2593
2594#define RGFW_GL_RENDER_TYPE RGFW_OS_BASED_VALUE(GLX_X_VISUAL_TYPE, 0x2003, 73, 0)
2595 #define RGFW_GL_ALPHA_SIZE RGFW_OS_BASED_VALUE(GLX_ALPHA_SIZE, 0x201b, 11, 0)
2596 #define RGFW_GL_DEPTH_SIZE RGFW_OS_BASED_VALUE(GLX_DEPTH_SIZE, 0x2022, 12, 0)
2597 #define RGFW_GL_DOUBLEBUFFER RGFW_OS_BASED_VALUE(GLX_DOUBLEBUFFER, 0x2011, 5, 0)
2598 #define RGFW_GL_STENCIL_SIZE RGFW_OS_BASED_VALUE(GLX_STENCIL_SIZE, 0x2023, 13, 0)
2599 #define RGFW_GL_SAMPLES RGFW_OS_BASED_VALUE(GLX_SAMPLES, 0x2042, 55, 0)
2600 #define RGFW_GL_STEREO RGFW_OS_BASED_VALUE(GLX_STEREO, 0x2012, 6, 0)
2601 #define RGFW_GL_AUX_BUFFERS RGFW_OS_BASED_VALUE(GLX_AUX_BUFFERS, 0x2024, 7, 0)
2602
2603#if defined(RGFW_X11) || defined(RGFW_WINDOWS)
2604 #define RGFW_GL_DRAW RGFW_OS_BASED_VALUE(GLX_X_RENDERABLE, 0x2001, 0, 0)
2605 #define RGFW_GL_DRAW_TYPE RGFW_OS_BASED_VALUE(GLX_RENDER_TYPE, 0x2013, 0, 0)
2606 #define RGFW_GL_FULL_FORMAT RGFW_OS_BASED_VALUE(GLX_TRUE_COLOR, 0x2027, 0, 0)
2607 #define RGFW_GL_RED_SIZE RGFW_OS_BASED_VALUE(GLX_RED_SIZE, 0x2015, 0, 0)
2608 #define RGFW_GL_GREEN_SIZE RGFW_OS_BASED_VALUE(GLX_GREEN_SIZE, 0x2017, 0, 0)
2609 #define RGFW_GL_BLUE_SIZE RGFW_OS_BASED_VALUE(GLX_BLUE_SIZE, 0x2019, 0, 0)
2610 #define RGFW_GL_USE_RGBA RGFW_OS_BASED_VALUE(GLX_RGBA_BIT, 0x202B, 0, 0)
2611 #define RGFW_GL_ACCUM_RED_SIZE RGFW_OS_BASED_VALUE(14, 0x201E, 0, 0)
2612 #define RGFW_GL_ACCUM_GREEN_SIZE RGFW_OS_BASED_VALUE(15, 0x201F, 0, 0)
2613 #define RGFW_GL_ACCUM_BLUE_SIZE RGFW_OS_BASED_VALUE(16, 0x2020, 0, 0)
2614 #define RGFW_GL_ACCUM_ALPHA_SIZE RGFW_OS_BASED_VALUE(17, 0x2021, 0, 0)
2615 #define RGFW_GL_SRGB RGFW_OS_BASED_VALUE(0x20b2, 0x3089, 0, 0)
2616 #define RGFW_GL_NOERROR RGFW_OS_BASED_VALUE(0x31b3, 0x31b3, 0, 0)
2617 #define RGFW_GL_FLAGS RGFW_OS_BASED_VALUE(GLX_CONTEXT_FLAGS_ARB, 0x2094, 0, 0)
2618 #define RGFW_GL_RELEASE_BEHAVIOR RGFW_OS_BASED_VALUE(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, 0x2097 , 0, 0)
2619 #define RGFW_GL_CONTEXT_RELEASE RGFW_OS_BASED_VALUE(GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB, 0x2098, 0, 0)
2620 #define RGFW_GL_CONTEXT_NONE RGFW_OS_BASED_VALUE(GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB, 0x0000, 0, 0)
2621 #define RGFW_GL_FLAGS RGFW_OS_BASED_VALUE(GLX_CONTEXT_FLAGS_ARB, 0x2094, 0, 0)
2622 #define RGFW_GL_DEBUG_BIT RGFW_OS_BASED_VALUE(GLX_CONTEXT_FLAGS_ARB, 0x2094, 0, 0)
2623 #define RGFW_GL_ROBUST_BIT RGFW_OS_BASED_VALUE(GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB, 0x00000004, 0, 0)
2624#endif
2625
2626#ifdef RGFW_WINDOWS
2627 #define WGL_SUPPORT_OPENGL_ARB 0x2010
2628 #define WGL_COLOR_BITS_ARB 0x2014
2629 #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
2630 #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
2631 #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
2632 #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
2633 #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
2634 #define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
2635 #define WGL_SAMPLE_BUFFERS_ARB 0x2041
2636 #define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9
2637 #define WGL_PIXEL_TYPE_ARB 0x2013
2638 #define WGL_TYPE_RGBA_ARB 0x202B
2639
2640 #define WGL_TRANSPARENT_ARB 0x200A
2641#endif
2642
2643/* The window'ing api needs to know how to render the data we (or opengl) give it
2644 MacOS and Windows do this using a structure called a "pixel format"
2645 X11 calls it a "Visual"
2646 This function returns the attributes for the format we want */
2647i32* RGFW_initFormatAttribs(void);
2648i32* RGFW_initFormatAttribs(void) {
2649 static i32 attribs[] = {
2650 #if defined(RGFW_X11) || defined(RGFW_WINDOWS)
2651 RGFW_GL_RENDER_TYPE,
2652 RGFW_GL_FULL_FORMAT,
2653 RGFW_GL_DRAW, 1,
2654 RGFW_GL_DRAW_TYPE , RGFW_GL_USE_RGBA,
2655 #endif
2656
2657 #ifdef RGFW_X11
2658 GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT,
2659 #endif
2660
2661 #ifdef RGFW_MACOS
2662 72,
2663 8, 24,
2664 #endif
2665
2666 #ifdef RGFW_WINDOWS
2667 WGL_SUPPORT_OPENGL_ARB, 1,
2668 WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
2669 WGL_COLOR_BITS_ARB, 32,
2670 #endif
2671 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
2672 };
2673
2674 size_t index = (sizeof(attribs) / sizeof(attribs[0])) - 27;
2675
2676 #define RGFW_GL_ADD_ATTRIB(attrib, attVal) \
2677 if (attVal) { \
2678 attribs[index] = attrib;\
2679 attribs[index + 1] = attVal;\
2680 index += 2;\
2681 }
2682
2683 #if defined(RGFW_MACOS) && defined(RGFW_COCOA_GRAPHICS_SWITCHING)
2684 RGFW_GL_ADD_ATTRIB(96, kCGLPFASupportsAutomaticGraphicsSwitching);
2685 #endif
2686
2687 RGFW_GL_ADD_ATTRIB(RGFW_GL_DOUBLEBUFFER, 1);
2688
2689 RGFW_GL_ADD_ATTRIB(RGFW_GL_ALPHA_SIZE, RGFW_GL_HINTS[RGFW_glAlpha]);
2690 RGFW_GL_ADD_ATTRIB(RGFW_GL_DEPTH_SIZE, RGFW_GL_HINTS[RGFW_glDepth]);
2691 RGFW_GL_ADD_ATTRIB(RGFW_GL_STENCIL_SIZE, RGFW_GL_HINTS[RGFW_glStencil]);
2692 RGFW_GL_ADD_ATTRIB(RGFW_GL_STEREO, RGFW_GL_HINTS[RGFW_glStereo]);
2693 RGFW_GL_ADD_ATTRIB(RGFW_GL_AUX_BUFFERS, RGFW_GL_HINTS[RGFW_glAuxBuffers]);
2694
2695 #if defined(RGFW_X11) || defined(RGFW_WINDOWS)
2696 RGFW_GL_ADD_ATTRIB(RGFW_GL_RED_SIZE, RGFW_GL_HINTS[RGFW_glRed]);
2697 RGFW_GL_ADD_ATTRIB(RGFW_GL_GREEN_SIZE, RGFW_GL_HINTS[RGFW_glBlue]);
2698 RGFW_GL_ADD_ATTRIB(RGFW_GL_BLUE_SIZE, RGFW_GL_HINTS[RGFW_glGreen]);
2699 #endif
2700
2701 #if defined(RGFW_X11) || defined(RGFW_WINDOWS)
2702 RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_RED_SIZE, RGFW_GL_HINTS[RGFW_glAccumRed]);
2703 RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_GREEN_SIZE, RGFW_GL_HINTS[RGFW_glAccumBlue]);
2704 RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_BLUE_SIZE, RGFW_GL_HINTS[RGFW_glAccumGreen]);
2705 RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_ALPHA_SIZE, RGFW_GL_HINTS[RGFW_glAccumAlpha]);
2706 RGFW_GL_ADD_ATTRIB(RGFW_GL_SRGB, RGFW_GL_HINTS[RGFW_glSRGB]);
2707 RGFW_GL_ADD_ATTRIB(RGFW_GL_NOERROR, RGFW_GL_HINTS[RGFW_glNoError]);
2708
2709 if (RGFW_GL_HINTS[RGFW_glReleaseBehavior] == RGFW_releaseFlush) {
2710 RGFW_GL_ADD_ATTRIB(RGFW_GL_RELEASE_BEHAVIOR, RGFW_GL_CONTEXT_RELEASE);
2711 } else if (RGFW_GL_HINTS[RGFW_glReleaseBehavior] == RGFW_glReleaseNone) {
2712 RGFW_GL_ADD_ATTRIB(RGFW_GL_RELEASE_BEHAVIOR, RGFW_GL_CONTEXT_NONE);
2713 }
2714
2715 i32 flags = 0;
2716 if (RGFW_GL_HINTS[RGFW_glDebug]) flags |= RGFW_GL_DEBUG_BIT;
2717 if (RGFW_GL_HINTS[RGFW_glRobustness]) flags |= RGFW_GL_ROBUST_BIT;
2718 RGFW_GL_ADD_ATTRIB(RGFW_GL_FLAGS, flags);
2719 #else
2720 i32 accumSize = (i32)(RGFW_GL_HINTS[RGFW_glAccumRed] + RGFW_GL_HINTS[RGFW_glAccumGreen] + RGFW_GL_HINTS[RGFW_glAccumBlue] + RGFW_GL_HINTS[RGFW_glAccumAlpha]) / 4;
2721 RGFW_GL_ADD_ATTRIB(14, accumSize);
2722 #endif
2723
2724 #ifndef RGFW_X11
2725 RGFW_GL_ADD_ATTRIB(RGFW_GL_SAMPLES, RGFW_GL_HINTS[RGFW_glSamples]);
2726 #endif
2727
2728 #ifdef RGFW_MACOS
2729 if (_RGFW.root->_flags & RGFW_windowOpenglSoftware) {
2730 RGFW_GL_ADD_ATTRIB(70, kCGLRendererGenericFloatID);
2731 } else {
2732 attribs[index] = RGFW_GL_RENDER_TYPE;
2733 index += 1;
2734 }
2735 #endif
2736
2737 #ifdef RGFW_MACOS
2738 /* macOS has the surface attribs and the opengl attribs connected for some reason
2739 maybe this is to give macOS more control to limit openGL/the opengl version? */
2740
2741 attribs[index] = 99;
2742 attribs[index + 1] = 0x1000;
2743
2744
2745 if (RGFW_GL_HINTS[RGFW_glMajor] >= 4 || RGFW_GL_HINTS[RGFW_glMajor] >= 3) {
2746 attribs[index + 1] = (i32) ((RGFW_GL_HINTS[RGFW_glMajor] >= 4) ? 0x4100 : 0x3200);
2747 }
2748 #endif
2749
2750 RGFW_GL_ADD_ATTRIB(0, 0);
2751
2752 return attribs;
2753}
2754
2755/* EGL only (no OSMesa nor normal OPENGL) */
2756#elif defined(RGFW_EGL)
2757
2758#include <EGL/egl.h>
2759
2760#if defined(RGFW_LINK_EGL)
2761 typedef EGLBoolean(EGLAPIENTRY* PFN_eglInitialize)(EGLDisplay, EGLint*, EGLint*);
2762
2763 PFNEGLINITIALIZEPROC eglInitializeSource;
2764 PFNEGLGETCONFIGSPROC eglGetConfigsSource;
2765 PFNEGLCHOOSECONFIgamepadROC eglChooseConfigSource;
2766 PFNEGLCREATEWINDOWSURFACEPROC eglCreateWindowSurfaceSource;
2767 PFNEGLCREATECONTEXTPROC eglCreateContextSource;
2768 PFNEGLMAKECURRENTPROC eglMakeCurrentSource;
2769 PFNEGLGETDISPLAYPROC eglGetDisplaySource;
2770 PFNEGLSWAPBUFFERSPROC eglSwapBuffersSource;
2771 PFNEGLSWAPINTERVALPROC eglSwapIntervalSource;
2772 PFNEGLBINDAPIPROC eglBindAPISource;
2773 PFNEGLDESTROYCONTEXTPROC eglDestroyContextSource;
2774 PFNEGLTERMINATEPROC eglTerminateSource;
2775 PFNEGLDESTROYSURFACEPROC eglDestroySurfaceSource;
2776
2777 #define eglInitialize eglInitializeSource
2778 #define eglGetConfigs eglGetConfigsSource
2779 #define eglChooseConfig eglChooseConfigSource
2780 #define eglCreateWindowSurface eglCreateWindowSurfaceSource
2781 #define eglCreateContext eglCreateContextSource
2782 #define eglMakeCurrent eglMakeCurrentSource
2783 #define eglGetDisplay eglGetDisplaySource
2784 #define eglSwapBuffers eglSwapBuffersSource
2785 #define eglSwapInterval eglSwapIntervalSource
2786 #define eglBindAPI eglBindAPISource
2787 #define eglDestroyContext eglDestroyContextSource
2788 #define eglTerminate eglTerminateSource
2789 #define eglDestroySurface eglDestroySurfaceSource;
2790#endif
2791
2792
2793#define EGL_SURFACE_MAJOR_VERSION_KHR 0x3098
2794#define EGL_SURFACE_MINOR_VERSION_KHR 0x30fb
2795
2796#ifndef RGFW_GL_ADD_ATTRIB
2797#define RGFW_GL_ADD_ATTRIB(attrib, attVal) \
2798 if (attVal) { \
2799 attribs[index] = attrib;\
2800 attribs[index + 1] = attVal;\
2801 index += 2;\
2802 }
2803#endif
2804
2805
2806void RGFW_window_initOpenGL(RGFW_window* win) {
2807#if defined(RGFW_LINK_EGL)
2808 eglInitializeSource = (PFNEGLINITIALIZEPROC) eglGetProcAddress("eglInitialize");
2809 eglGetConfigsSource = (PFNEGLGETCONFIGSPROC) eglGetProcAddress("eglGetConfigs");
2810 eglChooseConfigSource = (PFNEGLCHOOSECONFIgamepadROC) eglGetProcAddress("eglChooseConfig");
2811 eglCreateWindowSurfaceSource = (PFNEGLCREATEWINDOWSURFACEPROC) eglGetProcAddress("eglCreateWindowSurface");
2812 eglCreateContextSource = (PFNEGLCREATECONTEXTPROC) eglGetProcAddress("eglCreateContext");
2813 eglMakeCurrentSource = (PFNEGLMAKECURRENTPROC) eglGetProcAddress("eglMakeCurrent");
2814 eglGetDisplaySource = (PFNEGLGETDISPLAYPROC) eglGetProcAddress("eglGetDisplay");
2815 eglSwapBuffersSource = (PFNEGLSWAPBUFFERSPROC) eglGetProcAddress("eglSwapBuffers");
2816 eglSwapIntervalSource = (PFNEGLSWAPINTERVALPROC) eglGetProcAddress("eglSwapInterval");
2817 eglBindAPISource = (PFNEGLBINDAPIPROC) eglGetProcAddress("eglBindAPI");
2818 eglDestroyContextSource = (PFNEGLDESTROYCONTEXTPROC) eglGetProcAddress("eglDestroyContext");
2819 eglTerminateSource = (PFNEGLTERMINATEPROC) eglGetProcAddress("eglTerminate");
2820 eglDestroySurfaceSource = (PFNEGLDESTROYSURFACEPROC) eglGetProcAddress("eglDestroySurface");
2821
2822 RGFW_ASSERT(eglInitializeSource != NULL &&
2823 eglGetConfigsSource != NULL &&
2824 eglChooseConfigSource != NULL &&
2825 eglCreateWindowSurfaceSource != NULL &&
2826 eglCreateContextSource != NULL &&
2827 eglMakeCurrentSource != NULL &&
2828 eglGetDisplaySource != NULL &&
2829 eglSwapBuffersSource != NULL &&
2830 eglSwapIntervalsSource != NULL &&
2831 eglBindAPISource != NULL &&
2832 eglDestroyContextSource != NULL &&
2833 eglTerminateSource != NULL &&
2834 eglDestroySurfaceSource != NULL);
2835#endif /* RGFW_LINK_EGL */
2836
2837#ifdef RGFW_WAYLAND
2838 if (RGFW_useWaylandBool)
2839 win->src.eglWindow = wl_egl_window_create(win->src.surface, win->r.w, win->r.h);
2840#endif
2841
2842 #ifdef RGFW_WINDOWS
2843 win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.hdc);
2844 #elif defined(RGFW_MACOS)
2845 win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType)0);
2846 #elif defined(RGFW_WAYLAND)
2847 if (RGFW_useWaylandBool)
2848 win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.wl_display);
2849 else
2850 #endif
2851 #ifdef RGFW_X11
2852 win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.display);
2853 #else
2854 {}
2855 #endif
2856 #if !defined(RGFW_WAYLAND) && !defined(RGFW_WINDOWS) && !defined(RGFW_X11)
2857 win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.display);
2858 #endif
2859
2860 EGLint major, minor;
2861
2862 eglInitialize(win->src.EGL_display, &major, &minor);
2863
2864 #ifndef EGL_OPENGL_ES1_BIT
2865 #define EGL_OPENGL_ES1_BIT 0x1
2866 #endif
2867
2868 EGLint egl_config[24] = {
2869 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
2870 EGL_RENDERABLE_TYPE,
2871 #ifdef RGFW_OPENGL_ES1
2872 EGL_OPENGL_ES1_BIT,
2873 #elif defined(RGFW_OPENGL_ES3)
2874 EGL_OPENGL_ES3_BIT,
2875 #elif defined(RGFW_OPENGL_ES2)
2876 EGL_OPENGL_ES2_BIT,
2877 #else
2878 EGL_OPENGL_BIT,
2879 #endif
2880 EGL_NONE, EGL_NONE
2881 };
2882
2883 {
2884 size_t index = 7;
2885 EGLint* attribs = egl_config;
2886
2887 RGFW_GL_ADD_ATTRIB(EGL_RED_SIZE, RGFW_GL_HINTS[RGFW_glRed]);
2888 RGFW_GL_ADD_ATTRIB(EGL_GREEN_SIZE, RGFW_GL_HINTS[RGFW_glBlue]);
2889 RGFW_GL_ADD_ATTRIB(EGL_BLUE_SIZE, RGFW_GL_HINTS[RGFW_glGreen]);
2890 RGFW_GL_ADD_ATTRIB(EGL_ALPHA_SIZE, RGFW_GL_HINTS[RGFW_glAlpha]);
2891 RGFW_GL_ADD_ATTRIB(EGL_DEPTH_SIZE, RGFW_GL_HINTS[RGFW_glDepth]);
2892
2893 if (RGFW_GL_HINTS[RGFW_glSRGB])
2894 RGFW_GL_ADD_ATTRIB(0x3089, RGFW_GL_HINTS[RGFW_glSRGB]);
2895
2896 RGFW_GL_ADD_ATTRIB(EGL_NONE, EGL_NONE);
2897 }
2898
2899 EGLConfig config;
2900 EGLint numConfigs;
2901 eglChooseConfig(win->src.EGL_display, egl_config, &config, 1, &numConfigs);
2902
2903 #if defined(RGFW_MACOS)
2904 void* layer = RGFW_cocoaGetLayer();
2905
2906 RGFW_window_cocoaSetLayer(win, layer);
2907
2908 win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) layer, NULL);
2909 #elif defined(RGFW_WINDOWS)
2910 win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL);
2911 #elif defined(RGFW_WAYLAND)
2912 if (RGFW_useWaylandBool)
2913 win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.eglWindow, NULL);
2914 else
2915 #endif
2916 #ifdef RGFW_X11
2917 win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL);
2918 #else
2919 {}
2920 #endif
2921 #if !defined(RGFW_X11) && !defined(RGFW_WAYLAND) && !defined(RGFW_MACOS)
2922 win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL);
2923 #endif
2924
2925 EGLint attribs[12];
2926 size_t index = 0;
2927
2928#ifdef RGFW_OPENGL_ES1
2929 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, 1);
2930#elif defined(RGFW_OPENGL_ES2)
2931 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, 2);
2932#elif defined(RGFW_OPENGL_ES3)
2933 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, 3);
2934#endif
2935
2936 RGFW_GL_ADD_ATTRIB(EGL_STENCIL_SIZE, RGFW_GL_HINTS[RGFW_glStencil]);
2937 RGFW_GL_ADD_ATTRIB(EGL_SAMPLES, RGFW_GL_HINTS[RGFW_glSamples]);
2938
2939 if (RGFW_GL_HINTS[RGFW_glDoubleBuffer] == 0)
2940 RGFW_GL_ADD_ATTRIB(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER);
2941
2942 if (RGFW_GL_HINTS[RGFW_glMajor]) {
2943 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_MAJOR_VERSION, RGFW_GL_HINTS[RGFW_glMajor]);
2944 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_MINOR_VERSION, RGFW_GL_HINTS[RGFW_glMinor]);
2945
2946 if (RGFW_GL_HINTS[RGFW_glProfile] == RGFW_glCore) {
2947 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT);
2948 }
2949 else {
2950 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT);
2951 }
2952 }
2953
2954 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_ROBUST_ACCESS, RGFW_GL_HINTS[RGFW_glRobustness]);
2955 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_DEBUG, RGFW_GL_HINTS[RGFW_glDebug]);
2956 if (RGFW_GL_HINTS[RGFW_glReleaseBehavior] == RGFW_releaseFlush) {
2957 RGFW_GL_ADD_ATTRIB(0x2097, 0x2098);
2958 } else {
2959 RGFW_GL_ADD_ATTRIB(0x2096, 0x0000);
2960 }
2961
2962 RGFW_GL_ADD_ATTRIB(EGL_NONE, EGL_NONE);
2963
2964 #if defined(RGFW_OPENGL_ES1) || defined(RGFW_OPENGL_ES2) || defined(RGFW_OPENGL_ES3)
2965 eglBindAPI(EGL_OPENGL_ES_API);
2966 #else
2967 eglBindAPI(EGL_OPENGL_API);
2968 #endif
2969
2970 win->src.EGL_context = eglCreateContext(win->src.EGL_display, config, EGL_NO_CONTEXT, attribs);
2971
2972 if (win->src.EGL_context == NULL) {
2973 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errEGLContext, RGFW_DEBUG_CTX(win, 0), "failed to create an EGL opengl context");
2974 return;
2975 }
2976
2977 eglMakeCurrent(win->src.EGL_display, win->src.EGL_surface, win->src.EGL_surface, win->src.EGL_context);
2978 eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface);
2979 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "EGL opengl context initalized");
2980}
2981
2982void RGFW_window_freeOpenGL(RGFW_window* win) {
2983 if (win->src.EGL_display == NULL) return;
2984
2985 eglDestroySurface(win->src.EGL_display, win->src.EGL_surface);
2986 eglDestroyContext(win->src.EGL_display, win->src.EGL_context);
2987 eglTerminate(win->src.EGL_display);
2988 win->src.EGL_display = NULL;
2989 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "EGL opengl context freed");
2990}
2991
2992void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
2993 if (win == NULL)
2994 eglMakeCurrent(_RGFW.root->src.EGL_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
2995 else {
2996 eglMakeCurrent(win->src.EGL_display, win->src.EGL_surface, win->src.EGL_surface, win->src.EGL_context);
2997 }
2998}
2999
3000void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface); }
3001
3002void* RGFW_getCurrent_OpenGL(void) { return eglGetCurrentContext(); }
3003
3004#ifdef RGFW_APPLE
3005void* RGFWnsglFramework = NULL;
3006#elif defined(RGFW_WINDOWS)
3007HMODULE RGFW_wgl_dll = NULL;
3008#endif
3009
3010RGFW_proc RGFW_getProcAddress(const char* procname) {
3011 #if defined(RGFW_WINDOWS)
3012 RGFW_proc proc = (RGFW_proc) GetProcAddress(RGFW_wgl_dll, procname);
3013
3014 if (proc)
3015 return proc;
3016 #endif
3017
3018 return (RGFW_proc) eglGetProcAddress(procname);
3019}
3020
3021RGFW_bool RGFW_extensionSupportedPlatform(const char* extension, size_t len) {
3022 const char* extensions = eglQueryString(_RGFW.root->src.EGL_display, EGL_EXTENSIONS);
3023 return extensions != NULL && RGFW_extensionSupportedStr(extensions, extension, len);
3024}
3025
3026void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) {
3027 RGFW_ASSERT(win != NULL);
3028
3029 eglSwapInterval(win->src.EGL_display, swapInterval);
3030
3031}
3032
3033#endif /* RGFW_EGL */
3034
3035/*
3036 end of RGFW_EGL defines
3037*/
3038#endif /* end of RGFW_GL (OpenGL, EGL, OSMesa )*/
3039
3040/*
3041 RGFW_VULKAN defines
3042*/
3043#ifdef RGFW_VULKAN
3044#ifdef RGFW_MACOS
3045#include <objc/message.h>
3046#endif
3047
3048const char** RGFW_getVKRequiredInstanceExtensions(size_t* count) {
3049 static const char* arr[2] = {VK_KHR_SURFACE_EXTENSION_NAME};
3050 arr[1] = RGFW_VK_SURFACE;
3051 if (count != NULL) *count = 2;
3052
3053 return (const char**)arr;
3054}
3055
3056VkResult RGFW_window_createVKSurface(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface) {
3057 RGFW_ASSERT(win != NULL); RGFW_ASSERT(instance);
3058 RGFW_ASSERT(surface != NULL);
3059
3060 *surface = VK_NULL_HANDLE;
3061
3062#ifdef RGFW_X11
3063 RGFW_GOTO_WAYLAND(0);
3064 VkXlibSurfaceCreateInfoKHR x11 = { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, 0, 0, (Display*) win->src.display, (Window) win->src.window };
3065 return vkCreateXlibSurfaceKHR(instance, &x11, NULL, surface);
3066#endif
3067#if defined(RGFW_WAYLAND)
3068RGFW_WAYLAND_LABEL
3069 VkWaylandSurfaceCreateInfoKHR wayland = { VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, 0, 0, (struct wl_display*) win->src.wl_display, (struct wl_surface*) win->src.surface };
3070 return vkCreateWaylandSurfaceKHR(instance, &wayland, NULL, surface);
3071#elif defined(RGFW_WINDOWS)
3072 VkWin32SurfaceCreateInfoKHR win32 = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, 0, 0, GetModuleHandle(NULL), (HWND)win->src.window };
3073
3074 return vkCreateWin32SurfaceKHR(instance, &win32, NULL, surface);
3075#elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11)
3076 void* contentView = ((void* (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_getUid("contentView"));
3077 VkMacOSSurfaceCreateFlagsMVK macos = { VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK, 0, 0, win->src.display, (void*)contentView };
3078
3079 return vkCreateMacOSSurfaceMVK(instance, &macos, NULL, surface);
3080#endif
3081}
3082
3083
3084RGFW_bool RGFW_getVKPresentationSupport(VkInstance instance, VkPhysicalDevice physicalDevice, u32 queueFamilyIndex) {
3085 RGFW_ASSERT(instance);
3086 if (_RGFW.windowCount == -1 || _RGFW_init == RGFW_FALSE) RGFW_init();
3087#ifdef RGFW_X11
3088 RGFW_GOTO_WAYLAND(0);
3089 Visual* visual = DefaultVisual(_RGFW.display, DefaultScreen(_RGFW.display));
3090 if (_RGFW.root)
3091 visual = _RGFW.root->src.visual.visual;
3092
3093 RGFW_bool out = vkGetPhysicalDeviceXlibPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW.display, XVisualIDFromVisual(visual));
3094 return out;
3095#endif
3096#if defined(RGFW_WAYLAND)
3097RGFW_WAYLAND_LABEL
3098 RGFW_bool wlout = vkGetPhysicalDeviceWaylandPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW.wl_display);
3099 return wlout;
3100#elif defined(RGFW_WINDOWS)
3101#elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11)
3102 return RGFW_FALSE; /* TODO */
3103#endif
3104}
3105#endif /* end of RGFW_vulkan */
3106
3107/*
3108This is where OS specific stuff starts
3109*/
3110
3111
3112#if (defined(RGFW_WAYLAND) || defined(RGFW_X11)) && !defined(RGFW_NO_LINUX)
3113 int RGFW_eventWait_forceStop[] = {0, 0, 0}; /* for wait events */
3114
3115 #if defined(__linux__)
3116 #include <linux/joystick.h>
3117 #include <fcntl.h>
3118 #include <unistd.h>
3119 #include <errno.h>
3120
3121 u32 RGFW_linux_updateGamepad(RGFW_window* win);
3122 u32 RGFW_linux_updateGamepad(RGFW_window* win) {
3123 /* check for new gamepads */
3124 static const char* str[] = {"/dev/input/js0", "/dev/input/js1", "/dev/input/js2", "/dev/input/js3", "/dev/input/js4", "/dev/input/js5"};
3125 static u8 RGFW_rawGamepads[6];
3126 {
3127 u16 i;
3128 for (i = 0; i < 6; i++) {
3129 u16 index = RGFW_gamepadCount;
3130 if (RGFW_rawGamepads[i]) {
3131 struct input_id device_info;
3132 if (ioctl(RGFW_rawGamepads[i], EVIOCGID, &device_info) == -2) {
3133 if (errno == ENODEV) {
3134 RGFW_rawGamepads[i] = 0;
3135 }
3136 }
3137 continue;
3138 }
3139
3140 i32 js = open(str[i], O_RDONLY);
3141
3142 if (js <= 0)
3143 break;
3144
3145 if (RGFW_gamepadCount >= 4) {
3146 close(js);
3147 break;
3148 }
3149
3150 RGFW_rawGamepads[i] = 1;
3151
3152 int axes, buttons;
3153 if (ioctl(js, JSIOCGAXES, &axes) < 0 || ioctl(js, JSIOCGBUTTONS, &buttons) < 0) {
3154 close(js);
3155 continue;
3156 }
3157
3158 if (buttons <= 5 || buttons >= 30) {
3159 close(js);
3160 continue;
3161 }
3162
3163 RGFW_gamepadCount++;
3164
3165 RGFW_gamepads[index] = js;
3166
3167 ioctl(js, JSIOCGNAME(sizeof(RGFW_gamepads_name[index])), RGFW_gamepads_name[index]);
3168 RGFW_gamepads_name[index][sizeof(RGFW_gamepads_name[index]) - 1] = 0;
3169
3170 u8 j;
3171 for (j = 0; j < 16; j++) {
3172 RGFW_gamepadPressed[index][j].prev = 0;
3173 RGFW_gamepadPressed[index][j].current = 0;
3174 }
3175
3176 win->event.type = RGFW_gamepadConnected;
3177
3178 RGFW_gamepads_type[index] = RGFW_gamepadUnknown;
3179 if (RGFW_STRSTR(RGFW_gamepads_name[index], "Microsoft") || RGFW_STRSTR(RGFW_gamepads_name[index], "X-Box"))
3180 RGFW_gamepads_type[index] = RGFW_gamepadMicrosoft;
3181 else if (RGFW_STRSTR(RGFW_gamepads_name[index], "PlayStation") || RGFW_STRSTR(RGFW_gamepads_name[index], "PS3") || RGFW_STRSTR(RGFW_gamepads_name[index], "PS4") || RGFW_STRSTR(RGFW_gamepads_name[index], "PS5"))
3182 RGFW_gamepads_type[index] = RGFW_gamepadSony;
3183 else if (RGFW_STRSTR(RGFW_gamepads_name[index], "Nintendo"))
3184 RGFW_gamepads_type[index] = RGFW_gamepadNintendo;
3185 else if (RGFW_STRSTR(RGFW_gamepads_name[index], "Logitech"))
3186 RGFW_gamepads_type[index] = RGFW_gamepadLogitech;
3187
3188 win->event.gamepad = index;
3189 RGFW_gamepadCallback(win, index, 1);
3190 return 1;
3191 }
3192 }
3193 /* check gamepad events */
3194 u8 i;
3195
3196 for (i = 0; i < RGFW_gamepadCount; i++) {
3197 struct js_event e;
3198 if (RGFW_gamepads[i] == 0)
3199 continue;
3200
3201 i32 flags = fcntl(RGFW_gamepads[i], F_GETFL, 0);
3202 fcntl(RGFW_gamepads[i], F_SETFL, flags | O_NONBLOCK);
3203
3204 ssize_t bytes;
3205 while ((bytes = read(RGFW_gamepads[i], &e, sizeof(e))) > 0) {
3206 switch (e.type) {
3207 case JS_EVENT_BUTTON: {
3208 size_t typeIndex = 0;
3209 if (RGFW_gamepads_type[i] == RGFW_gamepadMicrosoft) typeIndex = 1;
3210 else if (RGFW_gamepads_type[i] == RGFW_gamepadLogitech) typeIndex = 2;
3211
3212 win->event.type = e.value ? RGFW_gamepadButtonPressed : RGFW_gamepadButtonReleased;
3213 u8 RGFW_linux2RGFW[3][RGFW_gamepadR3 + 8] = {{ /* ps */
3214 RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadY, RGFW_gamepadX, RGFW_gamepadL1, RGFW_gamepadR1, RGFW_gamepadL2, RGFW_gamepadR2,
3215 RGFW_gamepadSelect, RGFW_gamepadStart, RGFW_gamepadHome, RGFW_gamepadL3, RGFW_gamepadR3, RGFW_gamepadUp, RGFW_gamepadDown, RGFW_gamepadLeft, RGFW_gamepadRight,
3216 },{ /* xbox */
3217 RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadX, RGFW_gamepadY, RGFW_gamepadL1, RGFW_gamepadR1, RGFW_gamepadSelect, RGFW_gamepadStart,
3218 RGFW_gamepadHome, RGFW_gamepadL3, RGFW_gamepadR3, 255, 255, RGFW_gamepadUp, RGFW_gamepadDown, RGFW_gamepadLeft, RGFW_gamepadRight
3219 },{ /* Logitech */
3220 RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadX, RGFW_gamepadY, RGFW_gamepadL1, RGFW_gamepadR1, RGFW_gamepadL2, RGFW_gamepadR2,
3221 RGFW_gamepadSelect, RGFW_gamepadStart, RGFW_gamepadHome, RGFW_gamepadL3, RGFW_gamepadR3, RGFW_gamepadUp, RGFW_gamepadDown, RGFW_gamepadLeft, RGFW_gamepadRight
3222 }
3223 };
3224
3225 win->event.button = RGFW_linux2RGFW[typeIndex][e.number];
3226 win->event.gamepad = i;
3227 if (win->event.button == 255) break;
3228
3229 RGFW_gamepadPressed[i][win->event.button].prev = RGFW_gamepadPressed[i][win->event.button].current;
3230 RGFW_gamepadPressed[i][win->event.button].current = RGFW_BOOL(e.value);
3231 RGFW_gamepadButtonCallback(win, i, win->event.button, RGFW_BOOL(e.value));
3232
3233 return 1;
3234 }
3235 case JS_EVENT_AXIS: {
3236 size_t axis = e.number / 2;
3237 if (axis == 2) axis = 1;
3238
3239 ioctl(RGFW_gamepads[i], JSIOCGAXES, &win->event.axisesCount);
3240 win->event.axisesCount = 2;
3241
3242 if (axis < 3) {
3243 if (e.number == 0 || e.number == 3)
3244 RGFW_gamepadAxes[i][axis].x = (i32)((e.value / 32767.0f) * 100);
3245 else if (e.number == 1 || e.number == 4) {
3246 RGFW_gamepadAxes[i][axis].y = (i32)((e.value / 32767.0f) * 100);
3247 }
3248 }
3249
3250 win->event.axis[axis] = RGFW_gamepadAxes[i][axis];
3251 win->event.type = RGFW_gamepadAxisMove;
3252 win->event.gamepad = i;
3253 win->event.whichAxis = (u8)axis;
3254 RGFW_gamepadAxisCallback(win, i, win->event.axis, win->event.axisesCount, win->event.whichAxis);
3255 return 1;
3256 }
3257 default: break;
3258 }
3259 }
3260 if (bytes == -1 && errno == ENODEV) {
3261 RGFW_gamepadCount--;
3262 close(RGFW_gamepads[i]);
3263 RGFW_gamepads[i] = 0;
3264
3265 win->event.type = RGFW_gamepadDisconnected;
3266 win->event.gamepad = i;
3267 RGFW_gamepadCallback(win, i, 0);
3268 return 1;
3269 }
3270 }
3271 return 0;
3272 }
3273
3274 #endif
3275#endif
3276
3277
3278
3279/*
3280
3281 Start of Wayland defines
3282
3283
3284*/
3285
3286#ifdef RGFW_WAYLAND
3287/*
3288Wayland TODO: (out of date)
3289- fix RGFW_keyPressed lock state
3290
3291 RGFW_windowMoved, the window was moved (by the user)
3292 RGFW_windowResized the window was resized (by the user), [on WASM this means the browser was resized]
3293 RGFW_windowRefresh The window content needs to be refreshed
3294
3295 RGFW_DND a file has been dropped into the window
3296 RGFW_DNDInit
3297
3298- window args:
3299 #define RGFW_windowNoResize the window cannot be resized by the user
3300 #define RGFW_windowAllowDND the window supports drag and drop
3301 #define RGFW_scaleToMonitor scale the window to the screen
3302
3303- other missing functions functions ("TODO wayland") (~30 functions)
3304- fix buffer rendering weird behavior
3305*/
3306#include <errno.h>
3307#include <unistd.h>
3308#include <sys/mman.h>
3309#include <xkbcommon/xkbcommon.h>
3310#include <xkbcommon/xkbcommon-keysyms.h>
3311#include <dirent.h>
3312#include <linux/kd.h>
3313#include <wayland-cursor.h>
3314
3315RGFW_window* RGFW_key_win = NULL;
3316
3317/* wayland global garbage (wayland bad, X11 is fine (ish) (not really)) */
3318#include "xdg-shell.h"
3319#include "xdg-decoration-unstable-v1.h"
3320
3321struct xkb_context *xkb_context;
3322struct xkb_keymap *keymap = NULL;
3323struct xkb_state *xkb_state = NULL;
3324enum zxdg_toplevel_decoration_v1_mode client_preferred_mode, RGFW_current_mode;
3325struct zxdg_decoration_manager_v1 *decoration_manager = NULL;
3326
3327struct wl_cursor_theme* RGFW_wl_cursor_theme = NULL;
3328struct wl_surface* RGFW_cursor_surface = NULL;
3329struct wl_cursor_image* RGFW_cursor_image = NULL;
3330
3331void xdg_wm_base_ping_handler(void *data,
3332 struct xdg_wm_base *wm_base, uint32_t serial)
3333{
3334 RGFW_UNUSED(data);
3335 xdg_wm_base_pong(wm_base, serial);
3336}
3337
3338const struct xdg_wm_base_listener xdg_wm_base_listener = {
3339 .ping = xdg_wm_base_ping_handler,
3340};
3341
3342RGFW_bool RGFW_wl_configured = 0;
3343
3344void xdg_surface_configure_handler(void *data,
3345 struct xdg_surface *xdg_surface, uint32_t serial)
3346{
3347 RGFW_UNUSED(data);
3348 xdg_surface_ack_configure(xdg_surface, serial);
3349 RGFW_wl_configured = 1;
3350}
3351
3352const struct xdg_surface_listener xdg_surface_listener = {
3353 .configure = xdg_surface_configure_handler,
3354};
3355
3356void xdg_toplevel_configure_handler(void *data,
3357 struct xdg_toplevel *toplevel, int32_t width, int32_t height,
3358 struct wl_array *states)
3359{
3360 RGFW_UNUSED(data); RGFW_UNUSED(toplevel); RGFW_UNUSED(states);
3361 RGFW_UNUSED(width); RGFW_UNUSED(height);
3362}
3363
3364void xdg_toplevel_close_handler(void *data,
3365 struct xdg_toplevel *toplevel)
3366{
3367 RGFW_UNUSED(data);
3368 RGFW_window* win = (RGFW_window*)xdg_toplevel_get_user_data(toplevel);
3369 if (win == NULL)
3370 win = RGFW_key_win;
3371
3372 RGFW_eventQueuePushEx(e.type = RGFW_quit; e._win = win);
3373 RGFW_windowQuitCallback(win);
3374}
3375
3376void shm_format_handler(void *data,
3377 struct wl_shm *shm, uint32_t format)
3378{
3379 RGFW_UNUSED(data); RGFW_UNUSED(shm); RGFW_UNUSED(format);
3380}
3381
3382const struct wl_shm_listener shm_listener = {
3383 .format = shm_format_handler,
3384};
3385
3386const struct xdg_toplevel_listener xdg_toplevel_listener = {
3387 .configure = xdg_toplevel_configure_handler,
3388 .close = xdg_toplevel_close_handler,
3389};
3390
3391RGFW_window* RGFW_mouse_win = NULL;
3392
3393void pointer_enter(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) {
3394 RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(serial); RGFW_UNUSED(surface_x); RGFW_UNUSED(surface_y);
3395 RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
3396 RGFW_mouse_win = win;
3397
3398 RGFW_eventQueuePushEx(e.type = RGFW_mouseEnter;
3399 e.point = RGFW_POINT(wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y));
3400 e._win = win);
3401
3402 RGFW_mouseNotifyCallback(win, win->event.point, RGFW_TRUE);
3403}
3404void pointer_leave(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface) {
3405 RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(serial); RGFW_UNUSED(surface);
3406 RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
3407 if (RGFW_mouse_win == win)
3408 RGFW_mouse_win = NULL;
3409
3410 RGFW_eventQueuePushEx(e.type = RGFW_mouseLeave;
3411 e.point = win->event.point;
3412 e._win = win);
3413
3414 RGFW_mouseNotifyCallback(win, win->event.point, RGFW_FALSE);
3415}
3416void pointer_motion(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t x, wl_fixed_t y) {
3417 RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(x); RGFW_UNUSED(y);
3418
3419 RGFW_ASSERT(RGFW_mouse_win != NULL);
3420 RGFW_eventQueuePushEx(e.type = RGFW_mousePosChanged;
3421 e.point = RGFW_POINT(wl_fixed_to_double(x), wl_fixed_to_double(y));
3422 e._win = RGFW_mouse_win);
3423
3424 RGFW_mousePosCallback(RGFW_mouse_win, RGFW_POINT(wl_fixed_to_double(x), wl_fixed_to_double(y)), RGFW_mouse_win->event.vector);
3425}
3426void pointer_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) {
3427 RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(serial);
3428 RGFW_ASSERT(RGFW_mouse_win != NULL);
3429
3430 u32 b = (button - 0x110);
3431
3432 /* flip right and middle button codes */
3433 if (b == 1) b = 2;
3434 else if (b == 2) b = 1;
3435
3436 RGFW_mouseButtons[b].prev = RGFW_mouseButtons[b].current;
3437 RGFW_mouseButtons[b].current = RGFW_BOOL(state);
3438
3439 RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonReleased - RGFW_BOOL(state);
3440 e.point = RGFW_mouse_win->event.point;
3441 e.button = (u8)b;
3442 e._win = RGFW_mouse_win);
3443 RGFW_mouseButtonCallback(RGFW_mouse_win, (u8)b, 0, RGFW_BOOL(state));
3444}
3445void pointer_axis(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value) {
3446 RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(axis);
3447 RGFW_ASSERT(RGFW_mouse_win != NULL);
3448
3449 double scroll = - wl_fixed_to_double(value);
3450
3451 RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonPressed;
3452 e.point = RGFW_mouse_win->event.point;
3453 e.button = RGFW_mouseScrollUp + (scroll < 0);
3454 e.scroll = scroll;
3455 e._win = RGFW_mouse_win);
3456
3457 RGFW_mouseButtonCallback(RGFW_mouse_win, RGFW_mouseScrollUp + (scroll < 0), scroll, 1);
3458}
3459
3460void RGFW_doNothing(void) { }
3461
3462void keyboard_keymap (void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size) {
3463 RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(format);
3464
3465 char *keymap_string = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0);
3466 xkb_keymap_unref (keymap);
3467 keymap = xkb_keymap_new_from_string (xkb_context, keymap_string, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
3468
3469 munmap (keymap_string, size);
3470 close (fd);
3471 xkb_state_unref (xkb_state);
3472 xkb_state = xkb_state_new (keymap);
3473}
3474void keyboard_enter (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) {
3475 RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(keys);
3476
3477 RGFW_key_win = (RGFW_window*)wl_surface_get_user_data(surface);
3478
3479 RGFW_key_win->_flags |= RGFW_windowFocus;
3480 RGFW_eventQueuePushEx(e.type = RGFW_focusIn; e._win = RGFW_key_win);
3481 RGFW_focusCallback(RGFW_key_win, RGFW_TRUE);
3482
3483 if ((RGFW_key_win->_flags & RGFW_HOLD_MOUSE)) RGFW_window_mouseHold(RGFW_key_win, RGFW_AREA(RGFW_key_win->r.w, RGFW_key_win->r.h));
3484}
3485void keyboard_leave (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface) {
3486 RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial);
3487
3488 RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
3489 if (RGFW_key_win == win)
3490 RGFW_key_win = NULL;
3491
3492 RGFW_eventQueuePushEx(e.type = RGFW_focusOut; e._win = win);
3493 RGFW_focusCallback(win, RGFW_FALSE);
3494 RGFW_window_focusLost(win);
3495}
3496void keyboard_key (void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) {
3497 RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time);
3498
3499 if (RGFW_key_win == NULL) return;
3500
3501 xkb_keysym_t keysym = xkb_state_key_get_one_sym(xkb_state, key + 8);
3502
3503 u32 RGFWkey = RGFW_apiKeyToRGFW(key + 8);
3504 RGFW_keyboard[RGFWkey].prev = RGFW_keyboard[RGFWkey].current;
3505 RGFW_keyboard[RGFWkey].current = RGFW_BOOL(state);
3506
3507 RGFW_eventQueuePushEx(e.type = (u8)(RGFW_keyPressed + state);
3508 e.key = (u8)RGFWkey;
3509 e.keyChar = (u8)keysym;
3510 e.repeat = RGFW_isHeld(RGFW_key_win, (u8)RGFWkey);
3511 e._win = RGFW_key_win);
3512
3513 RGFW_updateKeyMods(RGFW_key_win, RGFW_BOOL(xkb_keymap_mod_get_index(keymap, "Lock")), RGFW_BOOL(xkb_keymap_mod_get_index(keymap, "Mod2")), RGFW_BOOL(xkb_keymap_mod_get_index(keymap, "ScrollLock")));
3514 RGFW_keyCallback(RGFW_key_win, (u8)RGFWkey, (u8)keysym, RGFW_key_win->event.keyMod, RGFW_BOOL(state));
3515}
3516void keyboard_modifiers (void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) {
3517 RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time);
3518 xkb_state_update_mask (xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
3519}
3520struct wl_keyboard_listener keyboard_listener = {&keyboard_keymap, &keyboard_enter, &keyboard_leave, &keyboard_key, &keyboard_modifiers, (void (*)(void *, struct wl_keyboard *,
3521int, int))&RGFW_doNothing};
3522
3523void seat_capabilities (void *data, struct wl_seat *seat, uint32_t capabilities) {
3524 RGFW_UNUSED(data);
3525 static struct wl_pointer_listener pointer_listener = {&pointer_enter, &pointer_leave, &pointer_motion, &pointer_button, &pointer_axis, (void (*)(void *, struct wl_pointer *))&RGFW_doNothing, (void (*)(void *, struct wl_pointer *, uint32_t))&RGFW_doNothing, (void (*)(void *, struct wl_pointer *, uint32_t, uint32_t))&RGFW_doNothing, (void (*)(void *, struct wl_pointer *, uint32_t, int32_t))&RGFW_doNothing, (void (*)(void *, struct wl_pointer *, uint32_t, int32_t))&RGFW_doNothing, (void (*)(void*, struct wl_pointer*, uint32_t, uint32_t))&RGFW_doNothing};
3526
3527 if (capabilities & WL_SEAT_CAPABILITY_POINTER) {
3528 struct wl_pointer *pointer = wl_seat_get_pointer (seat);
3529 wl_pointer_add_listener (pointer, &pointer_listener, NULL);
3530 }
3531 if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) {
3532 struct wl_keyboard *keyboard = wl_seat_get_keyboard (seat);
3533 wl_keyboard_add_listener (keyboard, &keyboard_listener, NULL);
3534 }
3535}
3536struct wl_seat_listener seat_listener = {&seat_capabilities, (void (*)(void *, struct wl_seat *, const char *))&RGFW_doNothing};
3537
3538void wl_global_registry_handler(void *data,
3539 struct wl_registry *registry, uint32_t id, const char *interface,
3540 uint32_t version)
3541{
3542 RGFW_window* win = (RGFW_window*)data;
3543 RGFW_UNUSED(version);
3544 if (RGFW_STRNCMP(interface, "wl_compositor", 16) == 0) {
3545 win->src.compositor = wl_registry_bind(registry,
3546 id, &wl_compositor_interface, 4);
3547 } else if (RGFW_STRNCMP(interface, "xdg_wm_base", 12) == 0) {
3548 win->src.xdg_wm_base = wl_registry_bind(registry,
3549 id, &xdg_wm_base_interface, 1);
3550 } else if (RGFW_STRNCMP(interface, zxdg_decoration_manager_v1_interface.name, 255) == 0) {
3551 decoration_manager = wl_registry_bind(registry, id, &zxdg_decoration_manager_v1_interface, 1);
3552 } else if (RGFW_STRNCMP(interface, "wl_shm", 7) == 0) {
3553 win->src.shm = wl_registry_bind(registry,
3554 id, &wl_shm_interface, 1);
3555 wl_shm_add_listener(win->src.shm, &shm_listener, NULL);
3556 } else if (RGFW_STRNCMP(interface,"wl_seat", 8) == 0) {
3557 win->src.seat = wl_registry_bind(registry, id, &wl_seat_interface, 1);
3558 wl_seat_add_listener(win->src.seat, &seat_listener, NULL);
3559 }
3560}
3561
3562void wl_global_registry_remove(void *data, struct wl_registry *registry, uint32_t name) { RGFW_UNUSED(data); RGFW_UNUSED(registry); RGFW_UNUSED(name); }
3563const struct wl_registry_listener registry_listener = {
3564 .global = wl_global_registry_handler,
3565 .global_remove = wl_global_registry_remove,
3566};
3567
3568void decoration_handle_configure(void *data,
3569 struct zxdg_toplevel_decoration_v1 *decoration,
3570 enum zxdg_toplevel_decoration_v1_mode mode) {
3571 RGFW_UNUSED(data); RGFW_UNUSED(decoration);
3572 RGFW_current_mode = mode;
3573}
3574
3575const struct zxdg_toplevel_decoration_v1_listener decoration_listener = {
3576 .configure = decoration_handle_configure,
3577};
3578
3579void randname(char *buf) {
3580 struct timespec ts;
3581 clock_gettime(CLOCK_REALTIME, &ts);
3582 long r = ts.tv_nsec;
3583
3584 int i;
3585 for (i = 0; i < 6; ++i) {
3586 buf[i] = (char)('A'+(r&15)+(r&16)*2);
3587 r >>= 5;
3588 }
3589}
3590
3591size_t wl_stringlen(char* name) {
3592 size_t i = 0;
3593 while (name[i]) { i++; }
3594 return i;
3595}
3596
3597int anonymous_shm_open(void) {
3598 char name[] = "/RGFW-wayland-XXXXXX";
3599 int retries = 100;
3600
3601 do {
3602 randname(name + wl_stringlen(name) - 6);
3603
3604 --retries;
3605 /* shm_open guarantees that O_CLOEXEC is set */
3606 int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
3607 if (fd >= 0) {
3608 shm_unlink(name);
3609 return fd;
3610 }
3611 } while (retries > 0 && errno == EEXIST);
3612
3613 return -1;
3614}
3615
3616int create_shm_file(off_t size) {
3617 int fd = anonymous_shm_open();
3618 if (fd < 0) {
3619 return fd;
3620 }
3621
3622 if (ftruncate(fd, size) < 0) {
3623 close(fd);
3624 return -1;
3625 }
3626
3627 return fd;
3628}
3629
3630void wl_surface_frame_done(void *data, struct wl_callback *cb, uint32_t time) {
3631 RGFW_UNUSED(data); RGFW_UNUSED(cb); RGFW_UNUSED(time);
3632
3633 #ifdef RGFW_BUFFER
3634 RGFW_window* win = (RGFW_window*)data;
3635 wl_surface_attach(win->src.surface, win->src.wl_buffer, 0, 0);
3636 wl_surface_damage_buffer(win->src.surface, 0, 0, win->r.w, win->r.h);
3637 wl_surface_commit(win->src.surface);
3638 #endif
3639}
3640
3641const struct wl_callback_listener wl_surface_frame_listener = {
3642 .done = wl_surface_frame_done,
3643};
3644#endif /* RGFW_WAYLAND */
3645/*
3646 End of Wayland defines
3647*/
3648
3649/*
3650
3651
3652Start of Linux / Unix defines
3653
3654
3655*/
3656
3657#ifdef RGFW_UNIX
3658#if !defined(RGFW_NO_X11_CURSOR) && defined(RGFW_X11)
3659#include <X11/Xcursor/Xcursor.h>
3660#endif
3661
3662#include <dlfcn.h>
3663
3664#ifndef RGFW_NO_DPI
3665#include <X11/extensions/Xrandr.h>
3666#include <X11/Xresource.h>
3667#endif
3668
3669#include <X11/Xatom.h>
3670#include <X11/keysymdef.h>
3671#include <X11/extensions/sync.h>
3672#include <unistd.h>
3673
3674#include <X11/XKBlib.h> /* for converting keycode to string */
3675#include <X11/cursorfont.h> /* for hiding */
3676#include <X11/extensions/shapeconst.h>
3677#include <X11/extensions/shape.h>
3678#include <X11/extensions/XInput2.h>
3679
3680#include <limits.h> /* for data limits (mainly used in drag and drop functions) */
3681#include <poll.h>
3682
3683/* atoms needed for drag and drop */
3684Atom XdndAware, XtextPlain, XtextUriList;
3685Atom RGFW_XUTF8_STRING = 0;
3686
3687Atom wm_delete_window = 0, RGFW_XCLIPBOARD = 0;
3688
3689#if defined(RGFW_X11) && !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD)
3690 typedef XcursorImage* (*PFN_XcursorImageCreate)(int, int);
3691 typedef void (*PFN_XcursorImageDestroy)(XcursorImage*);
3692 typedef Cursor(*PFN_XcursorImageLoadCursor)(Display*, const XcursorImage*);
3693#endif
3694#if defined(RGFW_OPENGL) && defined(RGFW_X11)
3695 typedef GLXContext(*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
3696#endif
3697
3698#if !defined(RGFW_NO_X11_XI_PRELOAD) && defined(RGFW_X11)
3699 typedef int (* PFN_XISelectEvents)(Display*,Window,XIEventMask*,int);
3700 PFN_XISelectEvents XISelectEventsSRC = NULL;
3701 #define XISelectEvents XISelectEventsSRC
3702
3703 void* X11Xihandle = NULL;
3704#endif
3705
3706#if !defined(RGFW_NO_X11_EXT_PRELOAD) && defined(RGFW_X11)
3707 typedef void (* PFN_XSyncIntToValue)(XSyncValue*, int);
3708 PFN_XSyncIntToValue XSyncIntToValueSRC = NULL;
3709 #define XSyncIntToValue XSyncIntToValueSRC
3710
3711 typedef Status (* PFN_XSyncSetCounter)(Display*, XSyncCounter, XSyncValue);
3712 PFN_XSyncSetCounter XSyncSetCounterSRC = NULL;
3713 #define XSyncSetCounter XSyncSetCounterSRC
3714
3715 typedef XSyncCounter (* PFN_XSyncCreateCounter)(Display*, XSyncValue);
3716 PFN_XSyncCreateCounter XSyncCreateCounterSRC = NULL;
3717 #define XSyncCreateCounter XSyncCreateCounterSRC
3718
3719 typedef void (* PFN_XShapeCombineMask)(Display*,Window,int,int,int,Pixmap,int);
3720 PFN_XShapeCombineMask XShapeCombineMaskSRC;
3721 #define XShapeCombineMask XShapeCombineMaskSRC
3722
3723 typedef void (* PFN_XShapeCombineRegion)(Display*,Window,int,int,int,Region,int);
3724 PFN_XShapeCombineRegion XShapeCombineRegionSRC;
3725 #define XShapeCombineRegion XShapeCombineRegionSRC
3726 void* X11XEXThandle = NULL;
3727#endif
3728
3729#if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD) && defined(RGFW_X11)
3730 PFN_XcursorImageLoadCursor XcursorImageLoadCursorSRC = NULL;
3731 PFN_XcursorImageCreate XcursorImageCreateSRC = NULL;
3732 PFN_XcursorImageDestroy XcursorImageDestroySRC = NULL;
3733
3734 #define XcursorImageLoadCursor XcursorImageLoadCursorSRC
3735 #define XcursorImageCreate XcursorImageCreateSRC
3736 #define XcursorImageDestroy XcursorImageDestroySRC
3737
3738 void* X11Cursorhandle = NULL;
3739#endif
3740
3741#ifdef RGFW_X11
3742const char* RGFW_instName = NULL;
3743void RGFW_setXInstName(const char* name) { RGFW_instName = name; }
3744#endif
3745
3746#if defined(RGFW_OPENGL) && !defined(RGFW_EGL)
3747RGFW_bool RGFW_extensionSupportedPlatform(const char * extension, size_t len) {
3748 const char* extensions = glXQueryExtensionsString(_RGFW.display, XDefaultScreen(_RGFW.display));
3749 return (extensions != NULL) && RGFW_extensionSupportedStr(extensions, extension, len);
3750}
3751RGFW_proc RGFW_getProcAddress(const char* procname) { return (RGFW_proc) glXGetProcAddress((GLubyte*) procname); }
3752#endif
3753
3754void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area) {
3755 RGFW_GOTO_WAYLAND(0);
3756
3757#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
3758 win->buffer = (u8*)buffer;
3759 win->bufferSize = area;
3760
3761 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoBuffer, RGFW_DEBUG_CTX(win, 0), "createing a 4 channel buffer");
3762 #ifdef RGFW_X11
3763 #ifdef RGFW_OSMESA
3764 win->src.ctx = OSMesaCreateContext(OSMESA_BGRA, NULL);
3765 OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h);
3766 OSMesaPixelStore(OSMESA_Y_UP, 0);
3767 #endif
3768
3769 win->src.bitmap = XCreateImage(
3770 win->src.display, win->src.visual.visual, (u32)win->src.visual.depth,
3771 ZPixmap, 0, NULL, area.w, area.h, 32, 0
3772 );
3773 #endif
3774 #ifdef RGFW_WAYLAND
3775 RGFW_WAYLAND_LABEL {}
3776 u32 size = (u32)(win->r.w * win->r.h * 4);
3777 int fd = create_shm_file(size);
3778 if (fd < 0) {
3779 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, RGFW_DEBUG_CTX(win, (u32)fd),"Failed to create a buffer.");
3780 exit(1);
3781 }
3782
3783 win->src.buffer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
3784 if (win->src.buffer == MAP_FAILED) {
3785 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, RGFW_DEBUG_CTX(win, 0), "mmap failed!");
3786 close(fd);
3787 exit(1);
3788 }
3789
3790 win->_flags |= RGFW_BUFFER_ALLOC;
3791
3792 struct wl_shm_pool* pool = wl_shm_create_pool(win->src.shm, fd, (i32)size);
3793 win->src.wl_buffer = wl_shm_pool_create_buffer(pool, 0, win->r.w, win->r.h, win->r.w * 4,
3794 WL_SHM_FORMAT_ARGB8888);
3795 wl_shm_pool_destroy(pool);
3796
3797 close(fd);
3798
3799 wl_surface_attach(win->src.surface, win->src.wl_buffer, 0, 0);
3800 wl_surface_commit(win->src.surface);
3801
3802 u8 color[] = {0x00, 0x00, 0x00, 0xFF};
3803
3804 size_t i;
3805 for (i = 0; i < area.w * area.h * 4; i += 4) {
3806 RGFW_MEMCPY(&win->buffer[i], color, 4);
3807 }
3808
3809 RGFW_MEMCPY(win->src.buffer, win->buffer, (size_t)(win->r.w * win->r.h * 4));
3810
3811 #if defined(RGFW_OSMESA)
3812 win->src.ctx = OSMesaCreateContext(OSMESA_BGRA, NULL);
3813 OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h);
3814 OSMesaPixelStore(OSMESA_Y_UP, 0);
3815 #endif
3816 #endif
3817#else
3818 #ifdef RGFW_WAYLAND
3819 RGFW_WAYLAND_LABEL{}
3820 #endif
3821
3822 RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area);
3823#endif
3824}
3825
3826#define RGFW_LOAD_ATOM(name) \
3827 static Atom name = 0; \
3828 if (name == 0) name = XInternAtom(_RGFW.display, #name, False);
3829
3830void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) {
3831 RGFW_setBit(&win->_flags, RGFW_windowNoBorder, !border);
3832
3833 RGFW_GOTO_WAYLAND(0);
3834 #ifdef RGFW_X11
3835 RGFW_LOAD_ATOM(_MOTIF_WM_HINTS);
3836
3837 struct __x11WindowHints {
3838 unsigned long flags, functions, decorations, status;
3839 long input_mode;
3840 } hints;
3841 hints.flags = 2;
3842 hints.decorations = border;
3843
3844 XChangeProperty(win->src.display, win->src.window, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 32,
3845 PropModeReplace, (u8*)&hints, 5
3846 );
3847
3848 if (RGFW_window_isHidden(win) == 0) {
3849 RGFW_window_hide(win);
3850 RGFW_window_show(win);
3851 }
3852
3853 #endif
3854 #ifdef RGFW_WAYLAND
3855 RGFW_WAYLAND_LABEL
3856 RGFW_UNUSED(win); RGFW_UNUSED(border);
3857 #endif
3858}
3859
3860void RGFW_releaseCursor(RGFW_window* win) {
3861RGFW_GOTO_WAYLAND(0);
3862#ifdef RGFW_X11
3863 XUngrabPointer(win->src.display, CurrentTime);
3864
3865 /* disable raw input */
3866 unsigned char mask[] = { 0 };
3867 XIEventMask em;
3868 em.deviceid = XIAllMasterDevices;
3869 em.mask_len = sizeof(mask);
3870 em.mask = mask;
3871
3872 XISelectEvents(win->src.display, XDefaultRootWindow(win->src.display), &em, 1);
3873#endif
3874#ifdef RGFW_WAYLAND
3875 RGFW_WAYLAND_LABEL
3876 RGFW_UNUSED(win);
3877#endif
3878}
3879
3880void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) {
3881RGFW_GOTO_WAYLAND(0);
3882#ifdef RGFW_X11
3883 /* enable raw input */
3884 unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 };
3885 XISetMask(mask, XI_RawMotion);
3886
3887 XIEventMask em;
3888 em.deviceid = XIAllMasterDevices;
3889 em.mask_len = sizeof(mask);
3890 em.mask = mask;
3891
3892 XISelectEvents(win->src.display, XDefaultRootWindow(win->src.display), &em, 1);
3893
3894 XGrabPointer(win->src.display, win->src.window, True, PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
3895 RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (i32)(r.w / 2), win->r.y + (i32)(r.h / 2)));
3896#endif
3897#ifdef RGFW_WAYLAND
3898 RGFW_WAYLAND_LABEL
3899 RGFW_UNUSED(win); RGFW_UNUSED(r);
3900#endif
3901}
3902
3903#define RGFW_LOAD_LIBRARY(x, lib) if (x == NULL) x = dlopen(lib, RTLD_LAZY | RTLD_LOCAL)
3904#define RGFW_PROC_DEF(proc, name) if (name##SRC == NULL && proc != NULL) { \
3905 void* ptr = dlsym(proc, #name); \
3906 if (ptr != NULL) memcpy(&name##SRC, &ptr, sizeof(PFN_##name)); \
3907}
3908
3909#ifdef RGFW_X11
3910void RGFW_window_getVisual(RGFW_window* win) {
3911#if defined(RGFW_OPENGL) && !defined(RGFW_EGL)
3912 i32* visual_attribs = RGFW_initFormatAttribs();
3913 i32 fbcount;
3914 GLXFBConfig* fbc = glXChooseFBConfig(win->src.display, DefaultScreen(win->src.display), visual_attribs, &fbcount);
3915
3916 i32 best_fbc = -1;
3917 i32 best_depth = 0;
3918 i32 best_samples = 0;
3919
3920 if (fbcount == 0) {
3921 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to find any valid GLX visual configs");
3922 return;
3923 }
3924
3925 i32 i;
3926 for (i = 0; i < fbcount; i++) {
3927 XVisualInfo* vi = glXGetVisualFromFBConfig(win->src.display, fbc[i]);
3928 if (vi == NULL)
3929 continue;
3930
3931 i32 samp_buf, samples;
3932 glXGetFBConfigAttrib(win->src.display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf);
3933 glXGetFBConfigAttrib(win->src.display, fbc[i], GLX_SAMPLES, &samples);
3934
3935 if (best_fbc == -1) best_fbc = i;
3936 if ((!(win->_flags & RGFW_windowTransparent) || vi->depth == 32) && best_depth == 0) {
3937 best_fbc = i;
3938 best_depth = vi->depth;
3939 }
3940 if ((!(win->_flags & RGFW_windowTransparent) || vi->depth == 32) && samples <= RGFW_GL_HINTS[RGFW_glSamples] && samples > best_samples) {
3941 best_fbc = i;
3942 best_depth = vi->depth;
3943 best_samples = samples;
3944 }
3945 XFree(vi);
3946 }
3947
3948 if (best_fbc == -1) {
3949 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to get a valid GLX visual");
3950 return;
3951 }
3952
3953 win->src.bestFbc = fbc[best_fbc];
3954 XVisualInfo* vi = glXGetVisualFromFBConfig(win->src.display, win->src.bestFbc);
3955 if (vi->depth != 32 && (win->_flags & RGFW_windowTransparent))
3956 RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, RGFW_DEBUG_CTX(win, 0), "Failed to to find a matching visual with a 32-bit depth");
3957
3958 if (best_samples < RGFW_GL_HINTS[RGFW_glSamples])
3959 RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, RGFW_DEBUG_CTX(win, 0), "Failed to load matching sampiling");
3960
3961 int configCaveat;
3962 if (glXGetFBConfigAttrib(win->src.display, win->src.bestFbc, GLX_CONFIG_CAVEAT, &configCaveat) == Success &&
3963 configCaveat == GLX_SLOW_CONFIG) {
3964 win->_flags |= RGFW_windowOpenglSoftware;
3965 }
3966
3967 XFree(fbc);
3968 win->src.visual = *vi;
3969 XFree(vi);
3970#else
3971 win->src.visual.visual = DefaultVisual(win->src.display, DefaultScreen(win->src.display));
3972 win->src.visual.depth = DefaultDepth(win->src.display, DefaultScreen(win->src.display));
3973 if (win->_flags & RGFW_windowTransparent) {
3974 XMatchVisualInfo(win->src.display, DefaultScreen(win->src.display), 32, TrueColor, &win->src.visual); /*!< for RGBA backgrounds */
3975 if (win->src.visual.depth != 32)
3976 RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, RGFW_DEBUG_CTX(win, 0), "Failed to load a 32-bit depth");
3977 }
3978#endif
3979}
3980#endif
3981#ifndef RGFW_EGL
3982void RGFW_window_initOpenGL(RGFW_window* win) {
3983#ifdef RGFW_OPENGL
3984 i32 context_attribs[7] = { 0, 0, 0, 0, 0, 0, 0 };
3985 context_attribs[0] = GLX_CONTEXT_PROFILE_MASK_ARB;
3986 if (RGFW_GL_HINTS[RGFW_glProfile] == RGFW_glCore)
3987 context_attribs[1] = GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
3988 else
3989 context_attribs[1] = GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
3990
3991 if (RGFW_GL_HINTS[RGFW_glMinor] || RGFW_GL_HINTS[RGFW_glMajor]) {
3992 context_attribs[2] = GLX_CONTEXT_MAJOR_VERSION_ARB;
3993 context_attribs[3] = RGFW_GL_HINTS[RGFW_glMajor];
3994 context_attribs[4] = GLX_CONTEXT_MINOR_VERSION_ARB;
3995 context_attribs[5] = RGFW_GL_HINTS[RGFW_glMinor];
3996 }
3997
3998 glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
3999 glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)
4000 glXGetProcAddressARB((GLubyte*) "glXCreateContextAttribsARB");
4001
4002 GLXContext ctx = NULL;
4003 if (_RGFW.root != NULL && _RGFW.root != win) {
4004 ctx = _RGFW.root->src.ctx;
4005 RGFW_window_makeCurrent_OpenGL(_RGFW.root);
4006 }
4007
4008 if (glXCreateContextAttribsARB == NULL) {
4009 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "failed to load proc address 'glXCreateContextAttribsARB', loading a generic opengl context");
4010 win->src.ctx = glXCreateContext(win->src.display, &win->src.visual, ctx, True);
4011 }
4012 else {
4013 win->src.ctx = glXCreateContextAttribsARB(win->src.display, win->src.bestFbc, ctx, True, context_attribs);
4014 XSync(win->src.display, False);
4015 if (win->src.ctx == NULL) {
4016 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "failed to create an opengl context with AttribsARB, loading a generic opengl context");
4017 win->src.ctx = glXCreateContext(win->src.display, &win->src.visual, ctx, True);
4018 }
4019 }
4020
4021 glXMakeCurrent(win->src.display, (Drawable) win->src.window, (GLXContext) win->src.ctx);
4022 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context initalized");
4023#else
4024 RGFW_UNUSED(win);
4025#endif
4026}
4027
4028void RGFW_window_freeOpenGL(RGFW_window* win) {
4029#ifdef RGFW_OPENGL
4030 if (win->src.ctx == NULL) return;
4031 glXDestroyContext(win->src.display, win->src.ctx);
4032 win->src.ctx = NULL;
4033 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context freed");
4034#else
4035RGFW_UNUSED(win);
4036#endif
4037}
4038#endif
4039
4040
4041i32 RGFW_init(void) {
4042 RGFW_GOTO_WAYLAND(1);
4043#if defined(RGFW_C89) || defined(__cplusplus)
4044 if (_RGFW_init) return 0;
4045 _RGFW_init = RGFW_TRUE;
4046 _RGFW.root = NULL; _RGFW.current = NULL; _RGFW.windowCount = -1; _RGFW.eventLen = 0; _RGFW.eventIndex = 0;
4047#endif
4048
4049#ifdef RGFW_X11
4050 if (_RGFW.windowCount != -1) return 0;
4051 #ifdef RGFW_USE_XDL
4052 XDL_init();
4053 #endif
4054
4055 #if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD)
4056 #if defined(__CYGWIN__)
4057 RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor-1.so");
4058 #elif defined(__OpenBSD__) || defined(__NetBSD__)
4059 RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor.so");
4060 #else
4061 RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor.so.1");
4062 #endif
4063 RGFW_PROC_DEF(X11Cursorhandle, XcursorImageCreate);
4064 RGFW_PROC_DEF(X11Cursorhandle, XcursorImageDestroy);
4065 RGFW_PROC_DEF(X11Cursorhandle, XcursorImageLoadCursor);
4066 #endif
4067
4068 #if !defined(RGFW_NO_X11_XI_PRELOAD)
4069 #if defined(__CYGWIN__)
4070 RGFW_LOAD_LIBRARY(X11Xihandle, "libXi-6.so");
4071 #elif defined(__OpenBSD__) || defined(__NetBSD__)
4072 RGFW_LOAD_LIBRARY(X11Xihandle, "libXi.so");
4073 #else
4074 RGFW_LOAD_LIBRARY(X11Xihandle, "libXi.so.6");
4075 #endif
4076 RGFW_PROC_DEF(X11Xihandle, XISelectEvents);
4077 #endif
4078
4079 #if !defined(RGFW_NO_X11_EXT_PRELOAD)
4080 #if defined(__CYGWIN__)
4081 RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext-6.so");
4082 #elif defined(__OpenBSD__) || defined(__NetBSD__)
4083 RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext.so");
4084 #else
4085 RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext.so.6");
4086 #endif
4087 RGFW_PROC_DEF(X11XEXThandle, XSyncCreateCounter);
4088 RGFW_PROC_DEF(X11XEXThandle, XSyncIntToValue);
4089 RGFW_PROC_DEF(X11XEXThandle, XSyncSetCounter);
4090 RGFW_PROC_DEF(X11XEXThandle, XShapeCombineRegion);
4091 RGFW_PROC_DEF(X11XEXThandle, XShapeCombineMask);
4092 #endif
4093
4094 XInitThreads(); /*!< init X11 threading */
4095 _RGFW.display = XOpenDisplay(0);
4096 XSetWindowAttributes wa;
4097 RGFW_MEMSET(&wa, 0, sizeof(wa));
4098 wa.event_mask = PropertyChangeMask;
4099 _RGFW.helperWindow = XCreateWindow(_RGFW.display, XDefaultRootWindow(_RGFW.display), 0, 0, 1, 1, 0, 0,
4100 InputOnly, DefaultVisual(_RGFW.display, DefaultScreen(_RGFW.display)), CWEventMask, &wa);
4101
4102 _RGFW.windowCount = 0;
4103 u8 RGFW_blk[] = { 0, 0, 0, 0 };
4104 _RGFW.hiddenMouse = RGFW_loadMouse(RGFW_blk, RGFW_AREA(1, 1), 4);
4105 _RGFW.clipboard = NULL;
4106
4107 XkbComponentNamesRec rec;
4108 XkbDescPtr desc = XkbGetMap(_RGFW.display, 0, XkbUseCoreKbd);
4109 XkbDescPtr evdesc;
4110 u8 old[sizeof(RGFW_keycodes) / sizeof(RGFW_keycodes[0])];
4111
4112 XkbGetNames(_RGFW.display, XkbKeyNamesMask, desc);
4113
4114 RGFW_MEMSET(&rec, 0, sizeof(rec));
4115 rec.keycodes = (char*)"evdev";
4116 evdesc = XkbGetKeyboardByName(_RGFW.display, XkbUseCoreKbd, &rec, XkbGBN_KeyNamesMask, XkbGBN_KeyNamesMask, False);
4117 /* memo: RGFW_keycodes[x11 keycode] = rgfw keycode */
4118 if(evdesc != NULL && desc != NULL){
4119 for(int i = 0; i < (int)sizeof(RGFW_keycodes) / (int)sizeof(RGFW_keycodes[0]); i++){
4120 old[i] = RGFW_keycodes[i];
4121 RGFW_keycodes[i] = 0;
4122 }
4123 for(int i = evdesc->min_key_code; i <= evdesc->max_key_code; i++){
4124 for(int j = desc->min_key_code; j <= desc->max_key_code; j++){
4125 if(strncmp(evdesc->names->keys[i].name, desc->names->keys[j].name, XkbKeyNameLength) == 0){
4126 RGFW_keycodes[j] = old[i];
4127 break;
4128 }
4129 }
4130 }
4131 XkbFreeKeyboard(desc, 0, True);
4132 XkbFreeKeyboard(evdesc, 0, True);
4133 }
4134#endif
4135#ifdef RGFW_WAYLAND
4136RGFW_WAYLAND_LABEL
4137 _RGFW.wl_display = wl_display_connect(NULL);
4138#endif
4139 _RGFW.windowCount = 0;
4140 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context initialized");
4141 return 0;
4142}
4143
4144
4145RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) {
4146 RGFW_window_basic_init(win, rect, flags);
4147
4148#ifdef RGFW_WAYLAND
4149 win->src.compositor = NULL;
4150#endif
4151 RGFW_GOTO_WAYLAND(0);
4152#ifdef RGFW_X11
4153 i64 event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | FocusChangeMask | LeaveWindowMask | EnterWindowMask | ExposureMask; /*!< X11 events accepted */
4154
4155 win->src.display = XOpenDisplay(NULL);
4156 RGFW_window_getVisual(win);
4157
4158 /* make X window attrubutes */
4159 XSetWindowAttributes swa;
4160 RGFW_MEMSET(&swa, 0, sizeof(swa));
4161
4162 Colormap cmap;
4163 swa.colormap = cmap = XCreateColormap(win->src.display,
4164 DefaultRootWindow(win->src.display),
4165 win->src.visual.visual, AllocNone);
4166 swa.event_mask = event_mask;
4167
4168 /* create the window */
4169 win->src.window = XCreateWindow(win->src.display, DefaultRootWindow(win->src.display), win->r.x, win->r.y, (u32)win->r.w, (u32)win->r.h,
4170 0, win->src.visual.depth, InputOutput, win->src.visual.visual,
4171 CWColormap | CWBorderPixel | CWEventMask, &swa);
4172
4173 XFreeColors(win->src.display, cmap, NULL, 0, 0);
4174
4175 win->src.gc = XCreateGC(win->src.display, win->src.window, 0, NULL);
4176
4177 /* In your .desktop app, if you set the property
4178 StartupWMClass=RGFW that will assoicate the launcher icon
4179 with your application - robrohan */
4180 if (RGFW_className == NULL)
4181 RGFW_className = (char*)name;
4182
4183 XClassHint hint;
4184 hint.res_class = (char*)RGFW_className;
4185 if (RGFW_instName == NULL) hint.res_name = (char*)name;
4186 else hint.res_name = (char*)RGFW_instName;
4187 XSetClassHint(win->src.display, win->src.window, &hint);
4188
4189 #ifndef RGFW_NO_MONITOR
4190 if (flags & RGFW_windowScaleToMonitor)
4191 RGFW_window_scaleToMonitor(win);
4192 #endif
4193 XSelectInput(win->src.display, (Drawable) win->src.window, event_mask); /*!< tell X11 what events we want */
4194
4195 /* make it so the user can't close the window until the program does */
4196 if (wm_delete_window == 0) {
4197 wm_delete_window = XInternAtom(win->src.display, "WM_DELETE_WINDOW", False);
4198 RGFW_XUTF8_STRING = XInternAtom(win->src.display, "UTF8_STRING", False);
4199 RGFW_XCLIPBOARD = XInternAtom(win->src.display, "CLIPBOARD", False);
4200 }
4201
4202 XSetWMProtocols(win->src.display, (Drawable) win->src.window, &wm_delete_window, 1);
4203 /* set the background */
4204 RGFW_window_setName(win, name);
4205
4206 XMoveWindow(win->src.display, (Drawable) win->src.window, win->r.x, win->r.y); /*!< move the window to it's proper cords */
4207
4208 if (flags & RGFW_windowAllowDND) { /* init drag and drop atoms and turn on drag and drop for this window */
4209 win->_flags |= RGFW_windowAllowDND;
4210
4211 /* actions */
4212 XtextUriList = XInternAtom(win->src.display, "text/uri-list", False);
4213 XtextPlain = XInternAtom(win->src.display, "text/plain", False);
4214 XdndAware = XInternAtom(win->src.display, "XdndAware", False);
4215 const u8 version = 5;
4216
4217 XChangeProperty(win->src.display, win->src.window,
4218 XdndAware, 4, 32,
4219 PropModeReplace, &version, 1); /*!< turns on drag and drop */
4220 }
4221
4222#ifdef RGFW_ADVANCED_SMOOTH_RESIZE
4223 RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST_COUNTER)
4224 RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST)
4225 Atom protcols[2] = {_NET_WM_SYNC_REQUEST, wm_delete_window};
4226 XSetWMProtocols(win->src.display, win->src.window, protcols, 2);
4227
4228 XSyncValue initial_value;
4229 XSyncIntToValue(&initial_value, 0);
4230 win->src.counter = XSyncCreateCounter(win->src.display, initial_value);
4231
4232 XChangeProperty(win->src.display, win->src.window, _NET_WM_SYNC_REQUEST_COUNTER, XA_CARDINAL, 32, PropModeReplace, (uint8_t*)&win->src.counter, 1);
4233#endif
4234
4235 if ((flags & RGFW_windowNoInitAPI) == 0) {
4236 RGFW_window_initOpenGL(win);
4237 RGFW_window_initBuffer(win);
4238 }
4239
4240 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created");
4241 RGFW_window_setMouseDefault(win);
4242 RGFW_window_setFlags(win, flags);
4243
4244 win->src.r = win->r;
4245
4246 RGFW_window_show(win);
4247 return win; /*return newly created window */
4248#endif
4249#ifdef RGFW_WAYLAND
4250 RGFW_WAYLAND_LABEL
4251 RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningWayland, RGFW_DEBUG_CTX(win, 0), "RGFW Wayland support is experimental");
4252
4253 win->src.wl_display = _RGFW.wl_display;
4254 if (win->src.wl_display == NULL) {
4255 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errWayland, RGFW_DEBUG_CTX(win, 0), "Failed to load Wayland display");
4256 #ifdef RGFW_X11
4257 RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningWayland, RGFW_DEBUG_CTX(win, 0), "Falling back to X11");
4258 RGFW_useWayland(0);
4259 return RGFW_createWindowPtr(name, rect, flags, win);
4260 #endif
4261 return NULL;
4262 }
4263
4264
4265 #ifdef RGFW_X11
4266 win->src.display = _RGFW.display;
4267 win->src.window = _RGFW.helperWindow;
4268 XMapWindow(_RGFW.display, win->src.window);
4269 XFlush(win->src.display);
4270 if (wm_delete_window == 0) {
4271 wm_delete_window = XInternAtom(win->src.display, "WM_DELETE_WINDOW", False);
4272 RGFW_XUTF8_STRING = XInternAtom(win->src.display, "UTF8_STRING", False);
4273 RGFW_XCLIPBOARD = XInternAtom(win->src.display, "CLIPBOARD", False);
4274 }
4275 #endif
4276
4277 struct wl_registry *registry = wl_display_get_registry(win->src.wl_display);
4278 wl_registry_add_listener(registry, &registry_listener, win);
4279
4280 wl_display_roundtrip(win->src.wl_display);
4281 wl_display_dispatch(win->src.wl_display);
4282
4283 if (win->src.compositor == NULL) {
4284 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errWayland, RGFW_DEBUG_CTX(win, 0), "Can't find compositor.");
4285 return NULL;
4286 }
4287
4288 if (RGFW_wl_cursor_theme == NULL) {
4289 RGFW_wl_cursor_theme = wl_cursor_theme_load(NULL, 24, win->src.shm);
4290 RGFW_cursor_surface = wl_compositor_create_surface(win->src.compositor);
4291
4292 struct wl_cursor* cursor = wl_cursor_theme_get_cursor(RGFW_wl_cursor_theme, "left_ptr");
4293 RGFW_cursor_image = cursor->images[0];
4294 struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(RGFW_cursor_image);
4295
4296 wl_surface_attach(RGFW_cursor_surface, cursor_buffer, 0, 0);
4297 wl_surface_commit(RGFW_cursor_surface);
4298 }
4299
4300 xdg_wm_base_add_listener(win->src.xdg_wm_base, &xdg_wm_base_listener, NULL);
4301
4302 xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
4303
4304 win->src.surface = wl_compositor_create_surface(win->src.compositor);
4305 wl_surface_set_user_data(win->src.surface, win);
4306
4307 win->src.xdg_surface = xdg_wm_base_get_xdg_surface(win->src.xdg_wm_base, win->src.surface);
4308 xdg_surface_add_listener(win->src.xdg_surface, &xdg_surface_listener, NULL);
4309
4310 xdg_wm_base_set_user_data(win->src.xdg_wm_base, win);
4311
4312 win->src.xdg_toplevel = xdg_surface_get_toplevel(win->src.xdg_surface);
4313 xdg_toplevel_set_user_data(win->src.xdg_toplevel, win);
4314 xdg_toplevel_add_listener(win->src.xdg_toplevel, &xdg_toplevel_listener, NULL);
4315
4316 xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->r.w, win->r.h);
4317
4318 if (!(flags & RGFW_windowNoBorder)) {
4319 win->src.decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(
4320 decoration_manager, win->src.xdg_toplevel);
4321 }
4322
4323 wl_display_roundtrip(win->src.wl_display);
4324
4325 wl_surface_commit(win->src.surface);
4326 RGFW_window_show(win);
4327
4328 /* wait for the surface to be configured */
4329 while (wl_display_dispatch(win->src.wl_display) != -1 && !RGFW_wl_configured) { }
4330
4331 if ((flags & RGFW_windowNoInitAPI) == 0) {
4332 RGFW_window_initOpenGL(win);
4333 RGFW_window_initBuffer(win);
4334 }
4335 struct wl_callback* callback = wl_surface_frame(win->src.surface);
4336 wl_callback_add_listener(callback, &wl_surface_frame_listener, win);
4337 wl_surface_commit(win->src.surface);
4338 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created");
4339
4340 #ifndef RGFW_NO_MONITOR
4341 if (flags & RGFW_windowScaleToMonitor)
4342 RGFW_window_scaleToMonitor(win);
4343 #endif
4344
4345 RGFW_window_setName(win, name);
4346 RGFW_window_setMouseDefault(win);
4347 RGFW_window_setFlags(win, flags);
4348 return win; /* return newly created window */
4349#endif
4350}
4351
4352RGFW_area RGFW_getScreenSize(void) {
4353 RGFW_GOTO_WAYLAND(1);
4354 RGFW_init();
4355
4356 #ifdef RGFW_X11
4357 Screen* scrn = DefaultScreenOfDisplay(_RGFW.display);
4358 return RGFW_AREA(scrn->width, scrn->height);
4359 #endif
4360 #ifdef RGFW_WAYLAND
4361 RGFW_WAYLAND_LABEL return RGFW_AREA(_RGFW.root->r.w, _RGFW.root->r.h); /* TODO */
4362 #endif
4363}
4364
4365RGFW_point RGFW_getGlobalMousePoint(void) {
4366 RGFW_init();
4367 RGFW_point RGFWMouse = RGFW_POINT(0, 0);
4368 RGFW_GOTO_WAYLAND(1);
4369#ifdef RGFW_X11
4370 i32 x, y;
4371 u32 z;
4372 Window window1, window2;
4373 XQueryPointer(_RGFW.display, XDefaultRootWindow(_RGFW.display), &window1, &window2, &RGFWMouse.x, &RGFWMouse.y, &x, &y, &z);
4374 return RGFWMouse;
4375#endif
4376#ifdef RGFW_WAYLAND
4377 RGFW_WAYLAND_LABEL
4378 return RGFWMouse;
4379#endif
4380}
4381
4382RGFWDEF void RGFW_XHandleClipboardSelection(XEvent* event);
4383void RGFW_XHandleClipboardSelection(XEvent* event) { RGFW_UNUSED(event);
4384#ifdef RGFW_X11
4385 RGFW_LOAD_ATOM(ATOM_PAIR);
4386 RGFW_LOAD_ATOM(MULTIPLE);
4387 RGFW_LOAD_ATOM(TARGETS);
4388 RGFW_LOAD_ATOM(SAVE_TARGETS);
4389
4390 const XSelectionRequestEvent* request = &event->xselectionrequest;
4391 const Atom formats[] = { RGFW_XUTF8_STRING, XA_STRING };
4392 const int formatCount = sizeof(formats) / sizeof(formats[0]);
4393
4394 if (request->target == TARGETS) {
4395 const Atom targets[] = { TARGETS, MULTIPLE, RGFW_XUTF8_STRING, XA_STRING };
4396
4397 XChangeProperty(_RGFW.display, request->requestor, request->property,
4398 XA_ATOM, 32, PropModeReplace, (u8*) targets, sizeof(targets) / sizeof(Atom));
4399 } else if (request->target == MULTIPLE) {
4400 Atom* targets = NULL;
4401
4402 Atom actualType = 0;
4403 int actualFormat = 0;
4404 unsigned long count = 0, bytesAfter = 0;
4405
4406 XGetWindowProperty(_RGFW.display, request->requestor, request->property, 0, LONG_MAX,
4407 False, ATOM_PAIR, &actualType, &actualFormat, &count, &bytesAfter, (u8**) &targets);
4408
4409 unsigned long i;
4410 for (i = 0; i < (u32)count; i += 2) {
4411 if (targets[i] == RGFW_XUTF8_STRING || targets[i] == XA_STRING)
4412 XChangeProperty(_RGFW.display, request->requestor, targets[i + 1], targets[i],
4413 8, PropModeReplace, (const unsigned char *)_RGFW.clipboard, (i32)_RGFW.clipboard_len);
4414 else
4415 targets[i + 1] = None;
4416 }
4417
4418 XChangeProperty(_RGFW.display,
4419 request->requestor, request->property, ATOM_PAIR, 32,
4420 PropModeReplace, (u8*) targets, (i32)count);
4421
4422 XFlush(_RGFW.display);
4423 XFree(targets);
4424 } else if (request->target == SAVE_TARGETS)
4425 XChangeProperty(_RGFW.display, request->requestor, request->property, 0, 32, PropModeReplace, NULL, 0);
4426 else {
4427 int i;
4428 for (i = 0; i < formatCount; i++) {
4429 if (request->target != formats[i])
4430 continue;
4431 XChangeProperty(_RGFW.display, request->requestor, request->property, request->target,
4432 8, PropModeReplace, (u8*) _RGFW.clipboard, (i32)_RGFW.clipboard_len);
4433 }
4434 }
4435
4436 XEvent reply = { SelectionNotify };
4437 reply.xselection.property = request->property;
4438 reply.xselection.display = request->display;
4439 reply.xselection.requestor = request->requestor;
4440 reply.xselection.selection = request->selection;
4441 reply.xselection.target = request->target;
4442 reply.xselection.time = request->time;
4443
4444 XSendEvent(_RGFW.display, request->requestor, False, 0, &reply);
4445#endif
4446}
4447
4448char* RGFW_strtok(char* str, const char* delimStr);
4449char* RGFW_strtok(char* str, const char* delimStr) {
4450 static char* static_str = NULL;
4451
4452 if (str != NULL)
4453 static_str = str;
4454
4455 if (static_str == NULL) {
4456 return NULL;
4457 }
4458
4459 while (*static_str != '\0') {
4460 RGFW_bool delim = 0;
4461 const char* d;
4462 for (d = delimStr; *d != '\0'; d++) {
4463 if (*static_str == *d) {
4464 delim = 1;
4465 break;
4466 }
4467 }
4468 if (!delim)
4469 break;
4470 static_str++;
4471 }
4472
4473 if (*static_str == '\0')
4474 return NULL;
4475
4476 char* token_start = static_str;
4477 while (*static_str != '\0') {
4478 int delim = 0;
4479 const char* d;
4480 for (d = delimStr; *d != '\0'; d++) {
4481 if (*static_str == *d) {
4482 delim = 1;
4483 break;
4484 }
4485 }
4486
4487 if (delim) {
4488 *static_str = '\0';
4489 static_str++;
4490 break;
4491 }
4492 static_str++;
4493 }
4494
4495 return token_start;
4496}
4497
4498i32 RGFW_XHandleClipboardSelectionHelper(void);
4499
4500
4501u8 RGFW_rgfwToKeyChar(u32 key) {
4502 u32 keycode = RGFW_rgfwToApiKey(key);
4503 RGFW_GOTO_WAYLAND(0);
4504#ifdef RGFW_X11
4505 Window root = DefaultRootWindow(_RGFW.display);
4506 Window ret_root, ret_child;
4507 int root_x, root_y, win_x, win_y;
4508 unsigned int mask;
4509 XQueryPointer(_RGFW.display, root, &ret_root, &ret_child, &root_x, &root_y, &win_x, &win_y, &mask);
4510 KeySym sym = (KeySym)XkbKeycodeToKeysym(_RGFW.display, (KeyCode)keycode, 0, (KeyCode)mask & ShiftMask ? 1 : 0);
4511
4512 if ((mask & LockMask) && sym >= XK_a && sym <= XK_z)
4513 sym = (mask & ShiftMask) ? sym + 32 : sym - 32;
4514 if ((u8)sym != (u32)sym)
4515 sym = 0;
4516
4517 return (u8)sym;
4518#endif
4519#ifdef RGFW_WAYLAND
4520 RGFW_WAYLAND_LABEL RGFW_UNUSED(keycode);
4521 return (u8)key;
4522#endif
4523}
4524
4525RGFW_event* RGFW_window_checkEvent(RGFW_window* win) {
4526 RGFW_XHandleClipboardSelectionHelper();
4527
4528 if (win == NULL || ((win->_flags & RGFW_windowFreeOnClose) && (win->_flags & RGFW_EVENT_QUIT))) return NULL;
4529 RGFW_event* ev = RGFW_window_checkEventCore(win);
4530 if (ev) return ev;
4531
4532 #if defined(__linux__) && !defined(RGFW_NO_LINUX)
4533 if (RGFW_linux_updateGamepad(win)) return &win->event;
4534 #endif
4535 RGFW_GOTO_WAYLAND(0);
4536#ifdef RGFW_X11
4537 RGFW_LOAD_ATOM(XdndTypeList);
4538 RGFW_LOAD_ATOM(XdndSelection);
4539 RGFW_LOAD_ATOM(XdndEnter);
4540 RGFW_LOAD_ATOM(XdndPosition);
4541 RGFW_LOAD_ATOM(XdndStatus);
4542 RGFW_LOAD_ATOM(XdndLeave);
4543 RGFW_LOAD_ATOM(XdndDrop);
4544 RGFW_LOAD_ATOM(XdndFinished);
4545 RGFW_LOAD_ATOM(XdndActionCopy);
4546 RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST);
4547 RGFW_LOAD_ATOM(WM_PROTOCOLS);
4548 XPending(win->src.display);
4549
4550 XEvent E; /*!< raw X11 event */
4551
4552 /* if there is no unread qued events, get a new one */
4553 if ((QLength(win->src.display) || XEventsQueued(win->src.display, QueuedAlready) + XEventsQueued(win->src.display, QueuedAfterReading))
4554 && win->event.type != RGFW_quit
4555 )
4556 XNextEvent(win->src.display, &E);
4557 else {
4558 return NULL;
4559 }
4560
4561 win->event.type = 0;
4562
4563 /* xdnd data */
4564 static Window source = 0;
4565 static long version = 0;
4566 static i32 format = 0;
4567
4568 XEvent reply = { ClientMessage };
4569
4570 switch (E.type) {
4571 case KeyPress:
4572 case KeyRelease: {
4573 win->event.repeat = RGFW_FALSE;
4574 /* check if it's a real key release */
4575 if (E.type == KeyRelease && XEventsQueued(win->src.display, QueuedAfterReading)) { /* get next event if there is one */
4576 XEvent NE;
4577 XPeekEvent(win->src.display, &NE);
4578
4579 if (E.xkey.time == NE.xkey.time && E.xkey.keycode == NE.xkey.keycode) /* check if the current and next are both the same */
4580 win->event.repeat = RGFW_TRUE;
4581 }
4582
4583 /* set event key data */
4584 win->event.key = (u8)RGFW_apiKeyToRGFW(E.xkey.keycode);
4585 win->event.keyChar = (u8)RGFW_rgfwToKeyChar(win->event.key);
4586
4587 RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current;
4588
4589 /* get keystate data */
4590 win->event.type = (E.type == KeyPress) ? RGFW_keyPressed : RGFW_keyReleased;
4591
4592 XKeyboardState keystate;
4593 XGetKeyboardControl(win->src.display, &keystate);
4594
4595 RGFW_keyboard[win->event.key].current = (E.type == KeyPress);
4596
4597 XkbStateRec state;
4598 XkbGetState(win->src.display, XkbUseCoreKbd, &state);
4599 RGFW_updateKeyMods(win, (state.locked_mods & LockMask), (state.locked_mods & Mod2Mask), (state.locked_mods & Mod3Mask));
4600
4601 RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, (E.type == KeyPress));
4602 break;
4603 }
4604 case ButtonPress:
4605 case ButtonRelease:
4606 if (E.xbutton.button > RGFW_mouseFinal) { /* skip this event */
4607 XFlush(win->src.display);
4608 return RGFW_window_checkEvent(win);
4609 }
4610
4611 win->event.type = RGFW_mouseButtonPressed + (E.type == ButtonRelease); /* the events match */
4612 win->event.button = (u8)(E.xbutton.button - 1);
4613 switch(win->event.button) {
4614 case RGFW_mouseScrollUp:
4615 win->event.scroll = 1;
4616 break;
4617 case RGFW_mouseScrollDown:
4618 win->event.scroll = -1;
4619 break;
4620 default: break;
4621 }
4622
4623 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
4624
4625 if (win->event.repeat == RGFW_FALSE)
4626 win->event.repeat = RGFW_isPressed(win, win->event.key);
4627
4628 RGFW_mouseButtons[win->event.button].current = (E.type == ButtonPress);
4629 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, (E.type == ButtonPress));
4630 break;
4631
4632 case MotionNotify:
4633 win->event.point.x = E.xmotion.x;
4634 win->event.point.y = E.xmotion.y;
4635
4636 win->event.vector.x = win->event.point.x - win->_lastMousePoint.x;
4637 win->event.vector.y = win->event.point.y - win->_lastMousePoint.y;
4638 win->_lastMousePoint = win->event.point;
4639
4640 win->event.type = RGFW_mousePosChanged;
4641 RGFW_mousePosCallback(win, win->event.point, win->event.vector);
4642 break;
4643
4644 case GenericEvent: {
4645 /* MotionNotify is used for mouse events if the mouse isn't held */
4646 if (!(win->_flags & RGFW_HOLD_MOUSE)) {
4647 XFreeEventData(win->src.display, &E.xcookie);
4648 break;
4649 }
4650
4651 XGetEventData(win->src.display, &E.xcookie);
4652 if (E.xcookie.evtype == XI_RawMotion) {
4653 XIRawEvent *raw = (XIRawEvent *)E.xcookie.data;
4654 if (raw->valuators.mask_len == 0) {
4655 XFreeEventData(win->src.display, &E.xcookie);
4656 break;
4657 }
4658
4659 double deltaX = 0.0f;
4660 double deltaY = 0.0f;
4661
4662 /* check if relative motion data exists where we think it does */
4663 if (XIMaskIsSet(raw->valuators.mask, 0) != 0)
4664 deltaX += raw->raw_values[0];
4665 if (XIMaskIsSet(raw->valuators.mask, 1) != 0)
4666 deltaY += raw->raw_values[1];
4667
4668 win->event.vector = RGFW_POINT((i32)deltaX, (i32)deltaY);
4669 win->event.point.x = win->_lastMousePoint.x + win->event.vector.x;
4670 win->event.point.y = win->_lastMousePoint.y + win->event.vector.y;
4671 win->_lastMousePoint = win->event.point;
4672
4673 RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2)));
4674
4675 win->event.type = RGFW_mousePosChanged;
4676 RGFW_mousePosCallback(win, win->event.point, win->event.vector);
4677 }
4678
4679 XFreeEventData(win->src.display, &E.xcookie);
4680 break;
4681 }
4682
4683 case Expose: {
4684 win->event.type = RGFW_windowRefresh;
4685 RGFW_windowRefreshCallback(win);
4686
4687#ifdef RGFW_ADVANCED_SMOOTH_RESIZE
4688 XSyncValue value;
4689 XSyncIntToValue(&value, (i32)win->src.counter_value);
4690 XSyncSetCounter(win->src.display, win->src.counter, value);
4691#endif
4692 break;
4693 }
4694 case MapNotify: case UnmapNotify: RGFW_window_checkMode(win); break;
4695 case ClientMessage: {
4696 /* if the client closed the window */
4697 if (E.xclient.data.l[0] == (long)wm_delete_window) {
4698 win->event.type = RGFW_quit;
4699 RGFW_window_setShouldClose(win, RGFW_TRUE);
4700 RGFW_windowQuitCallback(win);
4701 break;
4702 }
4703#ifdef RGFW_ADVANCED_SMOOTH_RESIZE
4704 if (E.xclient.message_type == WM_PROTOCOLS && (Atom)E.xclient.data.l[0] == _NET_WM_SYNC_REQUEST) {
4705 RGFW_windowRefreshCallback(win);
4706 win->src.counter_value = 0;
4707 win->src.counter_value |= E.xclient.data.l[2];
4708 win->src.counter_value |= (E.xclient.data.l[3] << 32);
4709
4710 XSyncValue value;
4711 XSyncIntToValue(&value, (i32)win->src.counter_value);
4712 XSyncSetCounter(win->src.display, win->src.counter, value);
4713 break;
4714 }
4715#endif
4716 if ((win->_flags & RGFW_windowAllowDND) == 0)
4717 break;
4718
4719 reply.xclient.window = source;
4720 reply.xclient.format = 32;
4721 reply.xclient.data.l[0] = (long)win->src.window;
4722 reply.xclient.data.l[1] = 0;
4723 reply.xclient.data.l[2] = None;
4724
4725 if (E.xclient.message_type == XdndEnter) {
4726 if (version > 5)
4727 break;
4728
4729 unsigned long count;
4730 Atom* formats;
4731 Atom real_formats[6];
4732 Bool list = E.xclient.data.l[1] & 1;
4733
4734 source = (unsigned long int)E.xclient.data.l[0];
4735 version = E.xclient.data.l[1] >> 24;
4736 format = None;
4737 if (list) {
4738 Atom actualType;
4739 i32 actualFormat;
4740 unsigned long bytesAfter;
4741
4742 XGetWindowProperty(
4743 win->src.display, source, XdndTypeList,
4744 0, LONG_MAX, False, 4,
4745 &actualType, &actualFormat, &count, &bytesAfter, (u8**)&formats
4746 );
4747 } else {
4748 count = 0;
4749
4750 size_t i;
4751 for (i = 2; i < 5; i++) {
4752 if (E.xclient.data.l[i] != None) {
4753 real_formats[count] = (unsigned long int)E.xclient.data.l[i];
4754 count += 1;
4755 }
4756 }
4757
4758 formats = real_formats;
4759 }
4760
4761 size_t i;
4762 for (i = 0; i < count; i++) {
4763 if (formats[i] == XtextUriList || formats[i] == XtextPlain) {
4764 format = (int)formats[i];
4765 break;
4766 }
4767 }
4768
4769 if (list) {
4770 XFree(formats);
4771 }
4772
4773 break;
4774 }
4775
4776 if (E.xclient.message_type == XdndPosition) {
4777 const i32 xabs = (E.xclient.data.l[2] >> 16) & 0xffff;
4778 const i32 yabs = (E.xclient.data.l[2]) & 0xffff;
4779 Window dummy;
4780 i32 xpos, ypos;
4781
4782 if (version > 5)
4783 break;
4784
4785 XTranslateCoordinates(
4786 win->src.display, XDefaultRootWindow(win->src.display), win->src.window,
4787 xabs, yabs, &xpos, &ypos, &dummy
4788 );
4789
4790 win->event.point.x = xpos;
4791 win->event.point.y = ypos;
4792
4793 reply.xclient.window = source;
4794 reply.xclient.message_type = XdndStatus;
4795
4796 if (format) {
4797 reply.xclient.data.l[1] = 1;
4798 if (version >= 2)
4799 reply.xclient.data.l[4] = (long)XdndActionCopy;
4800 }
4801
4802 XSendEvent(win->src.display, source, False, NoEventMask, &reply);
4803 XFlush(win->src.display);
4804 break;
4805 }
4806 if (E.xclient.message_type != XdndDrop)
4807 break;
4808
4809 if (version > 5)
4810 break;
4811
4812 size_t i;
4813 for (i = 0; i < win->event.droppedFilesCount; i++)
4814 win->event.droppedFiles[i][0] = '\0';
4815
4816 win->event.droppedFilesCount = 0;
4817
4818
4819 win->event.type = RGFW_DNDInit;
4820
4821 if (format) {
4822 Time time = (version >= 1)
4823 ? (Time)E.xclient.data.l[2]
4824 : CurrentTime;
4825
4826 XConvertSelection(
4827 win->src.display, XdndSelection, (Atom)format,
4828 XdndSelection, win->src.window, time
4829 );
4830 } else if (version >= 2) {
4831 XEvent new_reply = { ClientMessage };
4832
4833 XSendEvent(win->src.display, source, False, NoEventMask, &new_reply);
4834 XFlush(win->src.display);
4835 }
4836
4837 RGFW_dndInitCallback(win, win->event.point);
4838 } break;
4839 case SelectionRequest:
4840 RGFW_XHandleClipboardSelection(&E);
4841 XFlush(win->src.display);
4842 return RGFW_window_checkEvent(win);
4843 case SelectionNotify: {
4844 /* this is only for checking for xdnd drops */
4845 if (E.xselection.property != XdndSelection || !(win->_flags & RGFW_windowAllowDND))
4846 break;
4847 char* data;
4848 unsigned long result;
4849
4850 Atom actualType;
4851 i32 actualFormat;
4852 unsigned long bytesAfter;
4853
4854 XGetWindowProperty(win->src.display, E.xselection.requestor, E.xselection.property, 0, LONG_MAX, False, E.xselection.target, &actualType, &actualFormat, &result, &bytesAfter, (u8**) &data);
4855
4856 if (result == 0)
4857 break;
4858
4859 const char* prefix = (const char*)"file://";
4860
4861 char* line;
4862
4863 win->event.droppedFilesCount = 0;
4864 win->event.type = RGFW_DND;
4865
4866 while ((line = (char*)RGFW_strtok(data, "\r\n"))) {
4867 char path[RGFW_MAX_PATH];
4868
4869 data = NULL;
4870
4871 if (line[0] == '#')
4872 continue;
4873
4874 char* l;
4875 for (l = line; 1; l++) {
4876 if ((l - line) > 7)
4877 break;
4878 else if (*l != prefix[(l - line)])
4879 break;
4880 else if (*l == '\0' && prefix[(l - line)] == '\0') {
4881 line += 7;
4882 while (*line != '/')
4883 line++;
4884 break;
4885 } else if (*l == '\0')
4886 break;
4887 }
4888
4889 win->event.droppedFilesCount++;
4890
4891 size_t index = 0;
4892 while (*line) {
4893 if (line[0] == '%' && line[1] && line[2]) {
4894 const char digits[3] = { line[1], line[2], '\0' };
4895 path[index] = (char) RGFW_STRTOL(digits, NULL, 16);
4896 line += 2;
4897 } else
4898 path[index] = *line;
4899
4900 index++;
4901 line++;
4902 }
4903 path[index] = '\0';
4904 RGFW_MEMCPY(win->event.droppedFiles[win->event.droppedFilesCount - 1], path, index + 1);
4905 }
4906
4907 RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount);
4908 if (data)
4909 XFree(data);
4910
4911 if (version >= 2) {
4912 XEvent new_reply = { ClientMessage };
4913 new_reply.xclient.window = source;
4914 new_reply.xclient.message_type = XdndFinished;
4915 new_reply.xclient.format = 32;
4916 new_reply.xclient.data.l[1] = (long int)result;
4917 new_reply.xclient.data.l[2] = (long int)XdndActionCopy;
4918 XSendEvent(win->src.display, source, False, NoEventMask, &new_reply);
4919 XFlush(win->src.display);
4920 }
4921 break;
4922 }
4923 case FocusIn:
4924 if ((win->_flags & RGFW_windowFullscreen))
4925 XMapRaised(win->src.display, win->src.window);
4926
4927 win->_flags |= RGFW_windowFocus;
4928 win->event.type = RGFW_focusIn;
4929 RGFW_focusCallback(win, 1);
4930
4931
4932 if ((win->_flags & RGFW_HOLD_MOUSE)) RGFW_window_mouseHold(win, RGFW_AREA(win->r.w, win->r.h));
4933 break;
4934 case FocusOut:
4935 win->event.type = RGFW_focusOut;
4936 RGFW_focusCallback(win, 0);
4937 RGFW_window_focusLost(win);
4938 break;
4939 case PropertyNotify: RGFW_window_checkMode(win); break;
4940 case EnterNotify: {
4941 win->event.type = RGFW_mouseEnter;
4942 win->event.point.x = E.xcrossing.x;
4943 win->event.point.y = E.xcrossing.y;
4944 RGFW_mouseNotifyCallback(win, win->event.point, 1);
4945 break;
4946 }
4947
4948 case LeaveNotify: {
4949 win->event.type = RGFW_mouseLeave;
4950 RGFW_mouseNotifyCallback(win, win->event.point, 0);
4951 break;
4952 }
4953
4954 case ConfigureNotify: {
4955 /* detect resize */
4956 RGFW_window_checkMode(win);
4957 if (E.xconfigure.width != win->src.r.w || E.xconfigure.height != win->src.r.h) {
4958 win->event.type = RGFW_windowResized;
4959 win->src.r = win->r = RGFW_RECT(win->src.r.x, win->src.r.y, E.xconfigure.width, E.xconfigure.height);
4960 RGFW_windowResizedCallback(win, win->r);
4961 break;
4962 }
4963
4964 /* detect move */
4965 if (E.xconfigure.x != win->src.r.x || E.xconfigure.y != win->src.r.y) {
4966 win->event.type = RGFW_windowMoved;
4967 win->src.r = win->r = RGFW_RECT(E.xconfigure.x, E.xconfigure.y, win->src.r.w, win->src.r.h);
4968 RGFW_windowMovedCallback(win, win->r);
4969 break;
4970 }
4971
4972 break;
4973 }
4974 default:
4975 XFlush(win->src.display);
4976 return RGFW_window_checkEvent(win);
4977 }
4978 XFlush(win->src.display);
4979 if (win->event.type) return &win->event;
4980 else return NULL;
4981#endif
4982#ifdef RGFW_WAYLAND
4983 RGFW_WAYLAND_LABEL
4984 if ((win->_flags & RGFW_windowHide) == 0)
4985 wl_display_roundtrip(win->src.wl_display);
4986 return NULL;
4987#endif
4988}
4989
4990void RGFW_window_move(RGFW_window* win, RGFW_point v) {
4991 RGFW_ASSERT(win != NULL);
4992 win->r.x = v.x;
4993 win->r.y = v.y;
4994 RGFW_GOTO_WAYLAND(0);
4995#ifdef RGFW_X11
4996 XMoveWindow(win->src.display, win->src.window, v.x, v.y);
4997#endif
4998#ifdef RGFW_WAYLAND
4999 RGFW_WAYLAND_LABEL
5000 RGFW_ASSERT(win != NULL);
5001
5002 if (win->src.compositor) {
5003 struct wl_pointer *pointer = wl_seat_get_pointer(win->src.seat);
5004 if (!pointer) {
5005 return;
5006 }
5007
5008 wl_display_flush(win->src.wl_display);
5009 }
5010#endif
5011}
5012
5013
5014void RGFW_window_resize(RGFW_window* win, RGFW_area a) {
5015 RGFW_ASSERT(win != NULL);
5016 win->r.w = (i32)a.w;
5017 win->r.h = (i32)a.h;
5018 RGFW_GOTO_WAYLAND(0);
5019#ifdef RGFW_X11
5020 XResizeWindow(win->src.display, win->src.window, a.w, a.h);
5021
5022 if ((win->_flags & RGFW_windowNoResize)) {
5023 XSizeHints sh;
5024 sh.flags = (1L << 4) | (1L << 5);
5025 sh.min_width = sh.max_width = (i32)a.w;
5026 sh.min_height = sh.max_height = (i32)a.h;
5027
5028 XSetWMSizeHints(win->src.display, (Drawable) win->src.window, &sh, XA_WM_NORMAL_HINTS);
5029 }
5030#endif
5031#ifdef RGFW_WAYLAND
5032 RGFW_WAYLAND_LABEL
5033 if (win->src.compositor) {
5034 xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->r.w, win->r.h);
5035 #ifdef RGFW_OPENGL
5036 wl_egl_window_resize(win->src.eglWindow, (i32)a.w, (i32)a.h, 0, 0);
5037 #endif
5038 }
5039#endif
5040}
5041
5042void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) {
5043 RGFW_ASSERT(win != NULL);
5044 RGFW_GOTO_WAYLAND(0);
5045
5046 if (a.w == 0 && a.h == 0)
5047 return;
5048#ifdef RGFW_X11
5049 XSizeHints hints;
5050 long flags;
5051
5052 XGetWMNormalHints(win->src.display, win->src.window, &hints, &flags);
5053
5054 hints.flags |= PAspect;
5055
5056 hints.min_aspect.x = hints.max_aspect.x = (i32)a.w;
5057 hints.min_aspect.y = hints.max_aspect.y = (i32)a.h;
5058
5059 XSetWMNormalHints(win->src.display, win->src.window, &hints);
5060 return;
5061#endif
5062#ifdef RGFW_WAYLAND
5063 RGFW_WAYLAND_LABEL
5064#endif
5065}
5066
5067void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) {
5068 RGFW_ASSERT(win != NULL);
5069 RGFW_GOTO_WAYLAND(0);
5070#ifdef RGFW_X11
5071 long flags;
5072 XSizeHints hints;
5073 RGFW_MEMSET(&hints, 0, sizeof(XSizeHints));
5074
5075 XGetWMNormalHints(win->src.display, win->src.window, &hints, &flags);
5076
5077 hints.flags |= PMinSize;
5078
5079 hints.min_width = (i32)a.w;
5080 hints.min_height = (i32)a.h;
5081
5082 XSetWMNormalHints(win->src.display, win->src.window, &hints);
5083 return;
5084#endif
5085#ifdef RGFW_WAYLAND
5086RGFW_WAYLAND_LABEL RGFW_UNUSED(a);
5087#endif
5088}
5089
5090void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) {
5091 RGFW_ASSERT(win != NULL);
5092 RGFW_GOTO_WAYLAND(0);
5093#ifdef RGFW_X11
5094 long flags;
5095 XSizeHints hints;
5096 RGFW_MEMSET(&hints, 0, sizeof(XSizeHints));
5097
5098 XGetWMNormalHints(win->src.display, win->src.window, &hints, &flags);
5099
5100 hints.flags |= PMaxSize;
5101
5102 hints.max_width = (i32)a.w;
5103 hints.max_height = (i32)a.h;
5104
5105 XSetWMNormalHints(win->src.display, win->src.window, &hints);
5106#endif
5107#ifdef RGFW_WAYLAND
5108 RGFW_WAYLAND_LABEL RGFW_UNUSED(a);
5109#endif
5110}
5111
5112#ifdef RGFW_X11
5113void RGFW_toggleXMaximized(RGFW_window* win, RGFW_bool maximized);
5114void RGFW_toggleXMaximized(RGFW_window* win, RGFW_bool maximized) {
5115 RGFW_ASSERT(win != NULL);
5116 RGFW_LOAD_ATOM(_NET_WM_STATE);
5117 RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_VERT);
5118 RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ);
5119
5120 XEvent xev = {0};
5121 xev.type = ClientMessage;
5122 xev.xclient.window = win->src.window;
5123 xev.xclient.message_type = _NET_WM_STATE;
5124 xev.xclient.format = 32;
5125 xev.xclient.data.l[0] = maximized;
5126 xev.xclient.data.l[1] = (long int)_NET_WM_STATE_MAXIMIZED_HORZ;
5127 xev.xclient.data.l[2] = (long int)_NET_WM_STATE_MAXIMIZED_VERT;
5128 xev.xclient.data.l[3] = 0;
5129 xev.xclient.data.l[4] = 0;
5130
5131 XSendEvent(win->src.display, DefaultRootWindow(win->src.display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
5132}
5133#endif
5134
5135void RGFW_window_maximize(RGFW_window* win) {
5136 win->_oldRect = win->r;
5137 RGFW_GOTO_WAYLAND(0);
5138#ifdef RGFW_X11
5139 RGFW_toggleXMaximized(win, 1);
5140 return;
5141#endif
5142#ifdef RGFW_WAYLAND
5143 RGFW_WAYLAND_LABEL
5144 return;
5145#endif
5146}
5147
5148void RGFW_window_focus(RGFW_window* win) {
5149 RGFW_ASSERT(win);
5150 RGFW_GOTO_WAYLAND(0);
5151#ifdef RGFW_X11
5152 XWindowAttributes attr;
5153 XGetWindowAttributes(win->src.display, win->src.window, &attr);
5154 if (attr.map_state != IsViewable) return;
5155
5156 XSetInputFocus(win->src.display, win->src.window, RevertToPointerRoot, CurrentTime);
5157 XFlush(win->src.display);
5158#endif
5159#ifdef RGFW_WAYLAND
5160RGFW_WAYLAND_LABEL;
5161#endif
5162}
5163
5164void RGFW_window_raise(RGFW_window* win) {
5165 RGFW_ASSERT(win);
5166 RGFW_GOTO_WAYLAND(0);
5167#ifdef RGFW_X11
5168 XRaiseWindow(win->src.display, win->src.window);
5169 XMapRaised(win->src.display, win->src.window);
5170#endif
5171#ifdef RGFW_WAYLAND
5172RGFW_WAYLAND_LABEL;
5173#endif
5174}
5175
5176#ifdef RGFW_X11
5177void RGFW_window_setXAtom(RGFW_window* win, Atom netAtom, RGFW_bool fullscreen);
5178void RGFW_window_setXAtom(RGFW_window* win, Atom netAtom, RGFW_bool fullscreen) {
5179 RGFW_ASSERT(win != NULL);
5180 RGFW_LOAD_ATOM(_NET_WM_STATE);
5181
5182 XEvent xev = {0};
5183 xev.xclient.type = ClientMessage;
5184 xev.xclient.serial = 0;
5185 xev.xclient.send_event = True;
5186 xev.xclient.message_type = _NET_WM_STATE;
5187 xev.xclient.window = win->src.window;
5188 xev.xclient.format = 32;
5189 xev.xclient.data.l[0] = fullscreen;
5190 xev.xclient.data.l[1] = (long int)netAtom;
5191 xev.xclient.data.l[2] = 0;
5192
5193 XSendEvent(win->src.display, DefaultRootWindow(win->src.display), False, SubstructureNotifyMask | SubstructureRedirectMask, &xev);
5194}
5195#endif
5196
5197void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) {
5198 RGFW_ASSERT(win != NULL);
5199 RGFW_GOTO_WAYLAND(0);
5200 if (fullscreen) {
5201 win->_flags |= RGFW_windowFullscreen;
5202 win->_oldRect = win->r;
5203 }
5204 else win->_flags &= ~(u32)RGFW_windowFullscreen;
5205#ifdef RGFW_X11
5206 RGFW_LOAD_ATOM(_NET_WM_STATE_FULLSCREEN);
5207
5208 RGFW_window_setXAtom(win, _NET_WM_STATE_FULLSCREEN, fullscreen);
5209
5210 XRaiseWindow(win->src.display, win->src.window);
5211 XMapRaised(win->src.display, win->src.window);
5212#endif
5213#ifdef RGFW_WAYLAND
5214 RGFW_WAYLAND_LABEL;
5215#endif
5216}
5217
5218void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) {
5219 RGFW_ASSERT(win != NULL);
5220 RGFW_GOTO_WAYLAND(0);
5221#ifdef RGFW_X11
5222 RGFW_LOAD_ATOM(_NET_WM_STATE_ABOVE);
5223 RGFW_window_setXAtom(win, _NET_WM_STATE_ABOVE, floating);
5224#endif
5225#ifdef RGFW_WAYLAND
5226RGFW_WAYLAND_LABEL RGFW_UNUSED(floating);
5227#endif
5228}
5229
5230void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) {
5231 RGFW_ASSERT(win != NULL);
5232 RGFW_GOTO_WAYLAND(0);
5233#ifdef RGFW_X11
5234 const u32 value = (u32) (0xffffffffu * (double) opacity);
5235 RGFW_LOAD_ATOM(NET_WM_WINDOW_OPACITY);
5236 XChangeProperty(win->src.display, win->src.window,
5237 NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32, PropModeReplace, (unsigned char*) &value, 1);
5238#endif
5239#ifdef RGFW_WAYLAND
5240RGFW_WAYLAND_LABEL RGFW_UNUSED(opacity);
5241#endif
5242}
5243
5244void RGFW_window_minimize(RGFW_window* win) {
5245 RGFW_ASSERT(win != NULL);
5246 RGFW_GOTO_WAYLAND(0);
5247 if (RGFW_window_isMaximized(win)) return;
5248
5249 win->_oldRect = win->r;
5250#ifdef RGFW_X11
5251 XIconifyWindow(win->src.display, win->src.window, DefaultScreen(win->src.display));
5252 XFlush(win->src.display);
5253#endif
5254#ifdef RGFW_WAYLAND
5255 RGFW_WAYLAND_LABEL;
5256#endif
5257}
5258
5259void RGFW_window_restore(RGFW_window* win) {
5260 RGFW_ASSERT(win != NULL);
5261 RGFW_GOTO_WAYLAND(0);
5262#ifdef RGFW_X11
5263 RGFW_toggleXMaximized(win, 0);
5264#endif
5265#ifdef RGFW_WAYLAND
5266 RGFW_WAYLAND_LABEL
5267#endif
5268 win->r = win->_oldRect;
5269 RGFW_window_move(win, RGFW_POINT(win->r.x, win->r.y));
5270 RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h));
5271
5272 RGFW_window_show(win);
5273#ifdef RGFW_X11
5274 XFlush(win->src.display);
5275#endif
5276}
5277
5278RGFW_bool RGFW_window_isFloating(RGFW_window* win) {
5279 RGFW_GOTO_WAYLAND(0);
5280#ifdef RGFW_X11
5281 RGFW_LOAD_ATOM(_NET_WM_STATE);
5282 RGFW_LOAD_ATOM(_NET_WM_STATE_ABOVE);
5283
5284 Atom actual_type;
5285 int actual_format;
5286 unsigned long nitems, bytes_after;
5287 Atom* prop_return = NULL;
5288
5289 int status = XGetWindowProperty(win->src.display, win->src.window, _NET_WM_STATE, 0, (~0L), False, XA_ATOM,
5290 &actual_type, &actual_format, &nitems, &bytes_after,
5291 (unsigned char **)&prop_return);
5292
5293 if (status != Success || actual_type != XA_ATOM)
5294 return RGFW_FALSE;
5295
5296 unsigned long i;
5297 for (i = 0; i < nitems; i++)
5298 if (prop_return[i] == _NET_WM_STATE_ABOVE) return RGFW_TRUE;
5299
5300 if (prop_return)
5301 XFree(prop_return);
5302#endif
5303#ifdef RGFW_WAYLAND
5304 RGFW_WAYLAND_LABEL RGFW_UNUSED(win);
5305#endif
5306 return RGFW_FALSE;
5307}
5308
5309void RGFW_window_setName(RGFW_window* win, const char* name) {
5310 RGFW_ASSERT(win != NULL);
5311 RGFW_GOTO_WAYLAND(0);
5312 #ifdef RGFW_X11
5313 XStoreName(win->src.display, win->src.window, name);
5314
5315 RGFW_LOAD_ATOM(_NET_WM_NAME);
5316
5317 char buf[256];
5318 RGFW_MEMSET(buf, 0, sizeof(buf));
5319 RGFW_STRNCPY(buf, name, sizeof(buf) - 1);
5320
5321 XChangeProperty(
5322 win->src.display, win->src.window, _NET_WM_NAME, RGFW_XUTF8_STRING,
5323 8, PropModeReplace, (u8*)buf, sizeof(buf)
5324 );
5325 #endif
5326 #ifdef RGFW_WAYLAND
5327 RGFW_WAYLAND_LABEL
5328 if (win->src.compositor)
5329 xdg_toplevel_set_title(win->src.xdg_toplevel, name);
5330 #endif
5331}
5332
5333#ifndef RGFW_NO_PASSTHROUGH
5334void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) {
5335 RGFW_ASSERT(win != NULL);
5336 RGFW_GOTO_WAYLAND(0);
5337#ifdef RGFW_X11
5338 if (passthrough) {
5339 Region region = XCreateRegion();
5340 XShapeCombineRegion(win->src.display, win->src.window, ShapeInput, 0, 0, region, ShapeSet);
5341 XDestroyRegion(region);
5342
5343 return;
5344 }
5345
5346 XShapeCombineMask(win->src.display, win->src.window, ShapeInput, 0, 0, None, ShapeSet);
5347#endif
5348#ifdef RGFW_WAYLAND
5349 RGFW_WAYLAND_LABEL RGFW_UNUSED(passthrough);
5350#endif
5351}
5352#endif /* RGFW_NO_PASSTHROUGH */
5353
5354RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* icon, RGFW_area a, i32 channels, u8 type) {
5355 RGFW_ASSERT(win != NULL);
5356 RGFW_GOTO_WAYLAND(0);
5357#ifdef RGFW_X11
5358 RGFW_LOAD_ATOM(_NET_WM_ICON);
5359 if (icon == NULL || (channels != 3 && channels != 4)) {
5360 RGFW_bool res = (RGFW_bool)XChangeProperty(
5361 win->src.display, win->src.window, _NET_WM_ICON, XA_CARDINAL, 32,
5362 PropModeReplace, (u8*)NULL, 0
5363 );
5364 return res;
5365 }
5366
5367 i32 count = (i32)(2 + (a.w * a.h));
5368
5369 unsigned long* data = (unsigned long*) RGFW_ALLOC((u32)count * sizeof(unsigned long));
5370 RGFW_ASSERT(data != NULL);
5371
5372 data[0] = (unsigned long)a.w;
5373 data[1] = (unsigned long)a.h;
5374
5375 unsigned long* target = &data[2];
5376 u32 x, y;
5377
5378 for (x = 0; x < a.w; x++) {
5379 for (y = 0; y < a.h; y++) {
5380 size_t i = y * a.w + x;
5381 u32 alpha = (channels == 4) ? icon[i * 4 + 3] : 0xFF;
5382
5383 target[i] = (unsigned long)((icon[i * 4 + 0]) << 16) |
5384 (unsigned long)((icon[i * 4 + 1]) << 8) |
5385 (unsigned long)((icon[i * 4 + 2]) << 0) |
5386 (unsigned long)(alpha << 24);
5387 }
5388 }
5389
5390 RGFW_bool res = RGFW_TRUE;
5391 if (type & RGFW_iconTaskbar) {
5392 res = (RGFW_bool)XChangeProperty(
5393 win->src.display, win->src.window, _NET_WM_ICON, XA_CARDINAL, 32,
5394 PropModeReplace, (u8*)data, count
5395 );
5396 }
5397
5398 if (type & RGFW_iconWindow) {
5399 XWMHints wm_hints;
5400 wm_hints.flags = IconPixmapHint;
5401
5402 i32 depth = DefaultDepth(win->src.display, DefaultScreen(win->src.display));
5403 XImage *image = XCreateImage(win->src.display, DefaultVisual(win->src.display, DefaultScreen(win->src.display)),
5404 (u32)depth, ZPixmap, 0, (char *)target, a.w, a.h, 32, 0);
5405
5406 wm_hints.icon_pixmap = XCreatePixmap(win->src.display, win->src.window, a.w, a.h, (u32)depth);
5407 XPutImage(win->src.display, wm_hints.icon_pixmap, DefaultGC(win->src.display, DefaultScreen(win->src.display)), image, 0, 0, 0, 0, a.w, a.h);
5408 image->data = NULL;
5409 XDestroyImage(image);
5410
5411 XSetWMHints(win->src.display, win->src.window, &wm_hints);
5412 }
5413
5414 RGFW_FREE(data);
5415 XFlush(win->src.display);
5416 return RGFW_BOOL(res);
5417#endif
5418#ifdef RGFW_WAYLAND
5419 RGFW_WAYLAND_LABEL RGFW_UNUSED(icon); RGFW_UNUSED(a); RGFW_UNUSED(channels); RGFW_UNUSED(type);
5420 return RGFW_FALSE;
5421#endif
5422}
5423
5424RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) {
5425 RGFW_ASSERT(icon);
5426 RGFW_ASSERT(channels == 3 || channels == 4);
5427 RGFW_GOTO_WAYLAND(0);
5428
5429#ifdef RGFW_X11
5430#ifndef RGFW_NO_X11_CURSOR
5431 RGFW_init();
5432 XcursorImage* native = XcursorImageCreate((i32)a.w, (i32)a.h);
5433 native->xhot = 0;
5434 native->yhot = 0;
5435
5436 XcursorPixel* target = native->pixels;
5437 size_t x, y;
5438 for (x = 0; x < a.w; x++) {
5439 for (y = 0; y < a.h; y++) {
5440 size_t i = y * a.w + x;
5441 u32 alpha = (channels == 4) ? icon[i * 4 + 3] : 0xFF;
5442
5443 target[i] = (u32)((icon[i * 4 + 0]) << 16)
5444 | (u32)((icon[i * 4 + 1]) << 8)
5445 | (u32)((icon[i * 4 + 2]) << 0)
5446 | (u32)(alpha << 24);
5447 }
5448 }
5449
5450 Cursor cursor = XcursorImageLoadCursor(_RGFW.display, native);
5451 XcursorImageDestroy(native);
5452
5453 return (void*)cursor;
5454#else
5455 RGFW_UNUSED(image); RGFW_UNUSED(a.w); RGFW_UNUSED(channels);
5456 return NULL;
5457#endif
5458#endif
5459#ifdef RGFW_WAYLAND
5460 RGFW_WAYLAND_LABEL
5461 RGFW_UNUSED(icon); RGFW_UNUSED(a); RGFW_UNUSED(channels);
5462 return NULL; /* TODO */
5463#endif
5464}
5465
5466void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) {
5467RGFW_GOTO_WAYLAND(0);
5468#ifdef RGFW_X11
5469 RGFW_ASSERT(win && mouse);
5470 XDefineCursor(win->src.display, win->src.window, (Cursor)mouse);
5471#endif
5472#ifdef RGFW_WAYLAND
5473 RGFW_WAYLAND_LABEL
5474 RGFW_UNUSED(win); RGFW_UNUSED(mouse);
5475#endif
5476}
5477
5478void RGFW_freeMouse(RGFW_mouse* mouse) {
5479RGFW_GOTO_WAYLAND(0);
5480#ifdef RGFW_X11
5481 RGFW_ASSERT(mouse);
5482 XFreeCursor(_RGFW.display, (Cursor)mouse);
5483#endif
5484#ifdef RGFW_WAYLAND
5485 RGFW_WAYLAND_LABEL
5486 RGFW_UNUSED(mouse);
5487#endif
5488}
5489
5490void RGFW_window_moveMouse(RGFW_window* win, RGFW_point p) {
5491RGFW_GOTO_WAYLAND(1);
5492#ifdef RGFW_X11
5493 RGFW_ASSERT(win != NULL);
5494
5495 XEvent event;
5496 XQueryPointer(win->src.display, DefaultRootWindow(win->src.display),
5497 &event.xbutton.root, &event.xbutton.window,
5498 &event.xbutton.x_root, &event.xbutton.y_root,
5499 &event.xbutton.x, &event.xbutton.y,
5500 &event.xbutton.state);
5501
5502 win->_lastMousePoint = RGFW_POINT(p.x - win->r.x, p.y - win->r.y);
5503 if (event.xbutton.x == p.x && event.xbutton.y == p.y)
5504 return;
5505
5506 XWarpPointer(win->src.display, None, win->src.window, 0, 0, 0, 0, (int) p.x - win->r.x, (int) p.y - win->r.y);
5507#endif
5508#ifdef RGFW_WAYLAND
5509 RGFW_WAYLAND_LABEL
5510 RGFW_UNUSED(win); RGFW_UNUSED(p);
5511#endif
5512}
5513
5514RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) {
5515 return RGFW_window_setMouseStandard(win, RGFW_mouseArrow);
5516}
5517
5518RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) {
5519 RGFW_ASSERT(win != NULL);
5520 RGFW_GOTO_WAYLAND(0);
5521#ifdef RGFW_X11
5522 static const u8 mouseIconSrc[16] = { XC_arrow, XC_left_ptr, XC_xterm, XC_crosshair, XC_hand2, XC_sb_h_double_arrow, XC_sb_v_double_arrow, XC_bottom_left_corner, XC_bottom_right_corner, XC_fleur, XC_X_cursor};
5523
5524 if (mouse > (sizeof(mouseIconSrc) / sizeof(u8)))
5525 return RGFW_FALSE;
5526
5527 mouse = mouseIconSrc[mouse];
5528
5529 Cursor cursor = XCreateFontCursor(win->src.display, mouse);
5530 XDefineCursor(win->src.display, win->src.window, (Cursor) cursor);
5531
5532 XFreeCursor(win->src.display, (Cursor) cursor);
5533 return RGFW_TRUE;
5534#endif
5535#ifdef RGFW_WAYLAND
5536 RGFW_WAYLAND_LABEL { }
5537 static const char* iconStrings[16] = { "left_ptr", "left_ptr", "text", "cross", "pointer", "e-resize", "n-resize", "nw-resize", "ne-resize", "all-resize", "not-allowed" };
5538
5539 struct wl_cursor* wlcursor = wl_cursor_theme_get_cursor(RGFW_wl_cursor_theme, iconStrings[mouse]);
5540 RGFW_cursor_image = wlcursor->images[0];
5541 struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(RGFW_cursor_image);
5542
5543 wl_surface_attach(RGFW_cursor_surface, cursor_buffer, 0, 0);
5544 wl_surface_commit(RGFW_cursor_surface);
5545 return RGFW_TRUE;
5546
5547#endif
5548}
5549
5550void RGFW_window_hide(RGFW_window* win) {
5551 RGFW_GOTO_WAYLAND(0);
5552#ifdef RGFW_X11
5553 XUnmapWindow(win->src.display, win->src.window);
5554#endif
5555#ifdef RGFW_WAYLAND
5556 RGFW_WAYLAND_LABEL
5557 wl_surface_attach(win->src.surface, NULL, 0, 0);
5558 wl_surface_commit(win->src.surface);
5559 win->_flags |= RGFW_windowHide;
5560#endif
5561}
5562
5563void RGFW_window_show(RGFW_window* win) {
5564 win->_flags &= ~(u32)RGFW_windowHide;
5565 if (win->_flags & RGFW_windowFocusOnShow) RGFW_window_focus(win);
5566 RGFW_GOTO_WAYLAND(0);
5567#ifdef RGFW_X11
5568 XMapWindow(win->src.display, win->src.window);
5569#endif
5570#ifdef RGFW_WAYLAND
5571 RGFW_WAYLAND_LABEL
5572 /* wl_surface_attach(win->src.surface, win->rc., 0, 0); */
5573 wl_surface_commit(win->src.surface);
5574#endif
5575}
5576
5577RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) {
5578 RGFW_GOTO_WAYLAND(1);
5579#ifdef RGFW_X11
5580 RGFW_init();
5581 if (XGetSelectionOwner(_RGFW.display, RGFW_XCLIPBOARD) == _RGFW.helperWindow) {
5582 if (str != NULL)
5583 RGFW_STRNCPY(str, _RGFW.clipboard, _RGFW.clipboard_len - 1);
5584 _RGFW.clipboard[_RGFW.clipboard_len - 1] = '\0';
5585 return (RGFW_ssize_t)_RGFW.clipboard_len - 1;
5586 }
5587
5588 XEvent event;
5589 int format;
5590 unsigned long N, sizeN;
5591 char* data;
5592 Atom target;
5593
5594 RGFW_LOAD_ATOM(XSEL_DATA);
5595
5596 XConvertSelection(_RGFW.display, RGFW_XCLIPBOARD, RGFW_XUTF8_STRING, XSEL_DATA, _RGFW.helperWindow, CurrentTime);
5597 XSync(_RGFW.display, 0);
5598 while (1) {
5599 XNextEvent(_RGFW.display, &event);
5600 if (event.type != SelectionNotify) continue;
5601
5602 if (event.xselection.selection != RGFW_XCLIPBOARD || event.xselection.property == 0)
5603 return -1;
5604 break;
5605 }
5606
5607 XGetWindowProperty(event.xselection.display, event.xselection.requestor,
5608 event.xselection.property, 0L, (~0L), 0, AnyPropertyType, &target,
5609 &format, &sizeN, &N, (u8**) &data);
5610
5611 RGFW_ssize_t size;
5612 if (sizeN > strCapacity && str != NULL)
5613 size = -1;
5614
5615 if ((target == RGFW_XUTF8_STRING || target == XA_STRING) && str != NULL) {
5616 RGFW_MEMCPY(str, data, sizeN);
5617 str[sizeN] = '\0';
5618 XFree(data);
5619 } else if (str != NULL) size = -1;
5620
5621 XDeleteProperty(event.xselection.display, event.xselection.requestor, event.xselection.property);
5622 size = (RGFW_ssize_t)sizeN;
5623
5624 return size;
5625 #endif
5626 #if defined(RGFW_WAYLAND)
5627 RGFW_WAYLAND_LABEL RGFW_UNUSED(str); RGFW_UNUSED(strCapacity);
5628 return 0;
5629 #endif
5630}
5631
5632i32 RGFW_XHandleClipboardSelectionHelper(void) {
5633#ifdef RGFW_X11
5634 RGFW_LOAD_ATOM(SAVE_TARGETS);
5635
5636 XEvent event;
5637 XPending(_RGFW.display);
5638
5639 if (QLength(_RGFW.display) || XEventsQueued(_RGFW.display, QueuedAlready) + XEventsQueued(_RGFW.display, QueuedAfterReading))
5640 XNextEvent(_RGFW.display, &event);
5641 else
5642 return 0;
5643
5644 switch (event.type) {
5645 case SelectionRequest:
5646 RGFW_XHandleClipboardSelection(&event);
5647 return 0;
5648 case SelectionNotify:
5649 if (event.xselection.target == SAVE_TARGETS)
5650 return 0;
5651 break;
5652 default: break;
5653 }
5654
5655 return 0;
5656#else
5657 return 1;
5658#endif
5659}
5660
5661void RGFW_writeClipboard(const char* text, u32 textLen) {
5662 RGFW_GOTO_WAYLAND(1);
5663 #ifdef RGFW_X11
5664 RGFW_LOAD_ATOM(SAVE_TARGETS);
5665 RGFW_init();
5666
5667 /* request ownership of the clipboard section and request to convert it, this means its our job to convert it */
5668 XSetSelectionOwner(_RGFW.display, RGFW_XCLIPBOARD, _RGFW.helperWindow, CurrentTime);
5669 if (XGetSelectionOwner(_RGFW.display, RGFW_XCLIPBOARD) != _RGFW.helperWindow) {
5670 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errClipboard, RGFW_DEBUG_CTX(_RGFW.root, 0), "X11 failed to become owner of clipboard selection");
5671 return;
5672 }
5673
5674 if (_RGFW.clipboard)
5675 RGFW_FREE(_RGFW.clipboard);
5676
5677 _RGFW.clipboard = (char*)RGFW_ALLOC(textLen);
5678 RGFW_ASSERT(_RGFW.clipboard != NULL);
5679
5680 RGFW_STRNCPY(_RGFW.clipboard, text, textLen - 1);
5681 _RGFW.clipboard[textLen - 1] = '\0';
5682 _RGFW.clipboard_len = textLen;
5683 #endif
5684 #ifdef RGFW_WAYLAND
5685 RGFW_WAYLAND_LABEL
5686 RGFW_UNUSED(text); RGFW_UNUSED(textLen);
5687 #endif
5688}
5689
5690RGFW_bool RGFW_window_isHidden(RGFW_window* win) {
5691 RGFW_ASSERT(win != NULL);
5692 RGFW_GOTO_WAYLAND(0);
5693#ifdef RGFW_X11
5694
5695 XWindowAttributes windowAttributes;
5696 XGetWindowAttributes(win->src.display, win->src.window, &windowAttributes);
5697
5698 return (windowAttributes.map_state == IsUnmapped && !RGFW_window_isMinimized(win));
5699#endif
5700#ifdef RGFW_WAYLAND
5701 RGFW_WAYLAND_LABEL
5702 return RGFW_FALSE;
5703#endif
5704}
5705
5706RGFW_bool RGFW_window_isMinimized(RGFW_window* win) {
5707 RGFW_ASSERT(win != NULL);
5708 RGFW_GOTO_WAYLAND(0);
5709#ifdef RGFW_X11
5710 RGFW_LOAD_ATOM(WM_STATE);
5711
5712 Atom actual_type;
5713 i32 actual_format;
5714 unsigned long nitems, bytes_after;
5715 unsigned char* prop_data;
5716
5717 i32 status = XGetWindowProperty(win->src.display, win->src.window, WM_STATE, 0, 2, False,
5718 AnyPropertyType, &actual_type, &actual_format,
5719 &nitems, &bytes_after, &prop_data);
5720
5721 if (status == Success && nitems >= 1 && prop_data == (unsigned char*)IconicState) {
5722 XFree(prop_data);
5723 return RGFW_TRUE;
5724 }
5725
5726 if (prop_data != NULL)
5727 XFree(prop_data);
5728
5729 XWindowAttributes windowAttributes;
5730 XGetWindowAttributes(win->src.display, win->src.window, &windowAttributes);
5731 return windowAttributes.map_state != IsViewable;
5732#endif
5733#ifdef RGFW_WAYLAND
5734 RGFW_WAYLAND_LABEL
5735 return RGFW_FALSE;
5736#endif
5737}
5738
5739RGFW_bool RGFW_window_isMaximized(RGFW_window* win) {
5740 RGFW_ASSERT(win != NULL);
5741 RGFW_GOTO_WAYLAND(0);
5742#ifdef RGFW_X11
5743 RGFW_LOAD_ATOM(_NET_WM_STATE);
5744 RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_VERT);
5745 RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ);
5746
5747 Atom actual_type;
5748 i32 actual_format;
5749 unsigned long nitems, bytes_after;
5750 unsigned char* prop_data;
5751
5752 i32 status = XGetWindowProperty(win->src.display, win->src.window, _NET_WM_STATE, 0, 1024, False,
5753 XA_ATOM, &actual_type, &actual_format,
5754 &nitems, &bytes_after, &prop_data);
5755
5756 if (status != Success) {
5757 if (prop_data != NULL)
5758 XFree(prop_data);
5759
5760 return RGFW_FALSE;
5761 }
5762
5763 u64 i;
5764 for (i = 0; i < nitems; ++i) {
5765 if (prop_data[i] == _NET_WM_STATE_MAXIMIZED_VERT ||
5766 prop_data[i] == _NET_WM_STATE_MAXIMIZED_HORZ) {
5767 XFree(prop_data);
5768 return RGFW_TRUE;
5769 }
5770 }
5771
5772 if (prop_data != NULL)
5773 XFree(prop_data);
5774#endif
5775#ifdef RGFW_WAYLAND
5776RGFW_WAYLAND_LABEL;
5777#endif
5778 return RGFW_FALSE;
5779}
5780
5781#ifndef RGFW_NO_DPI
5782u32 RGFW_XCalculateRefreshRate(XRRModeInfo mi);
5783u32 RGFW_XCalculateRefreshRate(XRRModeInfo mi) {
5784 if (mi.hTotal == 0 || mi.vTotal == 0) return 0;
5785 return (u32) RGFW_ROUND((double) mi.dotClock / ((double) mi.hTotal * (double) mi.vTotal));
5786}
5787#endif
5788
5789
5790#ifdef RGFW_X11
5791static float XGetSystemContentDPI(Display* display, i32 screen) {
5792 float dpi = 96.0f;
5793
5794 #ifndef RGFW_NO_DPI
5795 RGFW_UNUSED(screen);
5796 char* rms = XResourceManagerString(display);
5797 XrmDatabase db = NULL;
5798 if (rms) db = XrmGetStringDatabase(rms);
5799
5800 if (rms && db) {
5801 XrmValue value;
5802 char* type = NULL;
5803
5804 if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value) && type && RGFW_STRNCMP(type, "String", 7) == 0)
5805 dpi = (float)RGFW_ATOF(value.addr);
5806 XrmDestroyDatabase(db);
5807 }
5808 #else
5809 dpi = RGFW_ROUND(DisplayWidth(display, screen) / (DisplayWidthMM(display, screen) / 25.4));
5810 #endif
5811
5812 return dpi;
5813}
5814#endif
5815
5816RGFW_monitor RGFW_XCreateMonitor(i32 screen);
5817RGFW_monitor RGFW_XCreateMonitor(i32 screen) {
5818 RGFW_monitor monitor;
5819 RGFW_init();
5820
5821 RGFW_GOTO_WAYLAND(1);
5822#ifdef RGFW_X11
5823 Display* display = _RGFW.display;
5824
5825 if (screen == -1) screen = DefaultScreen(display);
5826
5827 Screen* scrn = DefaultScreenOfDisplay(display);
5828 RGFW_area size = RGFW_AREA(scrn->width, scrn->height);
5829
5830 monitor.x = 0;
5831 monitor.y = 0;
5832 monitor.mode.area = RGFW_AREA(size.w, size.h);
5833 monitor.physW = (float)DisplayWidthMM(display, screen) / 25.4f;
5834 monitor.physH = (float)DisplayHeightMM(display, screen) / 25.4f;
5835
5836 RGFW_splitBPP((u32)DefaultDepth(display, DefaultScreen(display)), &monitor.mode);
5837
5838 char* name = XDisplayName((const char*)display);
5839 RGFW_STRNCPY(monitor.name, name, sizeof(monitor.name) - 1);
5840 monitor.name[sizeof(monitor.name) - 1] = '\0';
5841
5842 float dpi = XGetSystemContentDPI(display, screen);
5843 monitor.pixelRatio = dpi >= 192.0f ? 2 : 1;
5844 monitor.scaleX = (float) (dpi) / 96.0f;
5845 monitor.scaleY = (float) (dpi) / 96.0f;
5846
5847 #ifndef RGFW_NO_DPI
5848 XRRScreenResources* sr = XRRGetScreenResourcesCurrent(display, RootWindow(display, screen));
5849 monitor.mode.refreshRate = RGFW_XCalculateRefreshRate(sr->modes[screen]);
5850
5851 XRRCrtcInfo* ci = NULL;
5852 int crtc = screen;
5853
5854 if (sr->ncrtc > crtc) {
5855 ci = XRRGetCrtcInfo(display, sr, sr->crtcs[crtc]);
5856 }
5857 #endif
5858
5859 #ifndef RGFW_NO_DPI
5860 XRROutputInfo* info = XRRGetOutputInfo (display, sr, sr->outputs[screen]);
5861
5862 if (info == NULL || ci == NULL) {
5863 XRRFreeScreenResources(sr);
5864 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found");
5865 return monitor;
5866 }
5867
5868
5869 float physW = (float)info->mm_width / 25.4f;
5870 float physH = (float)info->mm_height / 25.4f;
5871
5872 RGFW_STRNCPY(monitor.name, info->name, sizeof(monitor.name) - 1);
5873 monitor.name[sizeof(monitor.name) - 1] = '\0';
5874
5875 if ((u8)physW && (u8)physH) {
5876 monitor.physW = physW;
5877 monitor.physH = physH;
5878 }
5879
5880 monitor.x = ci->x;
5881 monitor.y = ci->y;
5882
5883 if (ci->width && ci->height) {
5884 monitor.mode.area.w = (u32)ci->width;
5885 monitor.mode.area.h = (u32)ci->height;
5886 }
5887 #endif
5888
5889 #ifndef RGFW_NO_DPI
5890 XRRFreeCrtcInfo(ci);
5891 XRRFreeScreenResources(sr);
5892 #endif
5893
5894 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found");
5895 return monitor;
5896#endif
5897#ifdef RGFW_WAYLAND
5898RGFW_WAYLAND_LABEL RGFW_UNUSED(screen);
5899 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found");
5900 return monitor;
5901#endif
5902}
5903
5904RGFW_monitor* RGFW_getMonitors(size_t* len) {
5905 static RGFW_monitor monitors[7];
5906
5907 RGFW_GOTO_WAYLAND(1);
5908 #ifdef RGFW_X11
5909 RGFW_init();
5910
5911 Display* display = _RGFW.display;
5912 i32 max = ScreenCount(display);
5913
5914 i32 i;
5915 for (i = 0; i < max && i < 6; i++)
5916 monitors[i] = RGFW_XCreateMonitor(i);
5917
5918 if (len != NULL) *len = (size_t)((max <= 6) ? (max) : (6));
5919
5920 return monitors;
5921 #endif
5922 #ifdef RGFW_WAYLAND
5923 RGFW_WAYLAND_LABEL RGFW_UNUSED(len);
5924 return monitors; /* TODO WAYLAND */
5925 #endif
5926}
5927
5928RGFW_monitor RGFW_getPrimaryMonitor(void) {
5929 RGFW_GOTO_WAYLAND(1);
5930 #ifdef RGFW_X11
5931 return RGFW_XCreateMonitor(-1);
5932 #endif
5933 #ifdef RGFW_WAYLAND
5934 RGFW_WAYLAND_LABEL return (RGFW_monitor){ 0 }; /* TODO WAYLAND */
5935 #endif
5936}
5937
5938RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) {
5939 RGFW_GOTO_WAYLAND(1);
5940#ifdef RGFW_X11
5941 #ifndef RGFW_NO_DPI
5942 RGFW_init();
5943 XRRScreenResources* screenRes = XRRGetScreenResources(_RGFW.display, DefaultRootWindow(_RGFW.display));
5944 if (screenRes == NULL) return RGFW_FALSE;
5945
5946 int i;
5947 for (i = 0; i < screenRes->ncrtc; i++) {
5948 XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(_RGFW.display, screenRes, screenRes->crtcs[i]);
5949 if (!crtcInfo) continue;
5950
5951 if (mon.x == crtcInfo->x && mon.y == crtcInfo->y && (u32)mon.mode.area.w == crtcInfo->width && (u32)mon.mode.area.h == crtcInfo->height) {
5952 RRMode rmode = None;
5953 int index;
5954 for (index = 0; index < screenRes->nmode; index++) {
5955 RGFW_monitorMode foundMode;
5956 foundMode.area = RGFW_AREA(screenRes->modes[index].width, screenRes->modes[index].height);
5957 foundMode.refreshRate = RGFW_XCalculateRefreshRate(screenRes->modes[index]);
5958 RGFW_splitBPP((u32)DefaultDepth(_RGFW.display, DefaultScreen(_RGFW.display)), &foundMode);
5959
5960 if (RGFW_monitorModeCompare(mode, foundMode, request)) {
5961 rmode = screenRes->modes[index].id;
5962
5963 RROutput output = screenRes->outputs[i];
5964 XRROutputInfo* info = XRRGetOutputInfo(_RGFW.display, screenRes, output);
5965 if (info) {
5966 XRRSetCrtcConfig(_RGFW.display, screenRes, screenRes->crtcs[i],
5967 CurrentTime, 0, 0, rmode, RR_Rotate_0, &output, 1);
5968 XRRFreeOutputInfo(info);
5969 XRRFreeCrtcInfo(crtcInfo);
5970 XRRFreeScreenResources(screenRes);
5971 return RGFW_TRUE;
5972 }
5973 }
5974 }
5975
5976 XRRFreeCrtcInfo(crtcInfo);
5977 XRRFreeScreenResources(screenRes);
5978 return RGFW_FALSE;
5979 }
5980
5981 XRRFreeCrtcInfo(crtcInfo);
5982 }
5983
5984 XRRFreeScreenResources(screenRes);
5985 return RGFW_FALSE;
5986 #endif
5987#endif
5988#ifdef RGFW_WAYLAND
5989RGFW_WAYLAND_LABEL RGFW_UNUSED(mon); RGFW_UNUSED(mode); RGFW_UNUSED(request);
5990#endif
5991 return RGFW_FALSE;
5992}
5993
5994RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) {
5995 RGFW_monitor mon;
5996 RGFW_MEMSET(&mon, 0, sizeof(mon));
5997
5998 RGFW_ASSERT(win != NULL);
5999 RGFW_GOTO_WAYLAND(1);
6000#ifdef RGFW_X11
6001 XWindowAttributes attrs;
6002 if (!XGetWindowAttributes(win->src.display, win->src.window, &attrs)) {
6003 return mon;
6004 }
6005
6006 i32 i;
6007 for (i = 0; i < ScreenCount(win->src.display) && i < 6; i++) {
6008 Screen* screen = ScreenOfDisplay(win->src.display, i);
6009 if (attrs.x >= 0 && attrs.x < XWidthOfScreen(screen) &&
6010 attrs.y >= 0 && attrs.y < XHeightOfScreen(screen))
6011 return RGFW_XCreateMonitor(i);
6012 }
6013#endif
6014#ifdef RGFW_WAYLAND
6015RGFW_WAYLAND_LABEL
6016#endif
6017 return mon;
6018
6019}
6020
6021#if defined(RGFW_OPENGL) && !defined(RGFW_EGL)
6022void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
6023 if (win == NULL)
6024 glXMakeCurrent(NULL, (Drawable)NULL, (GLXContext) NULL);
6025 else
6026 glXMakeCurrent(win->src.display, (Drawable) win->src.window, (GLXContext) win->src.ctx);
6027}
6028void* RGFW_getCurrent_OpenGL(void) { return glXGetCurrentContext(); }
6029void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { glXSwapBuffers(win->src.display, win->src.window); }
6030#endif
6031
6032void RGFW_window_swapBuffers_software(RGFW_window* win) {
6033 RGFW_ASSERT(win != NULL);
6034 RGFW_GOTO_WAYLAND(0);
6035#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
6036 #ifdef RGFW_X11
6037 win->src.bitmap->data = (char*) win->buffer;
6038 RGFW_RGB_to_BGR(win, (u8*)win->src.bitmap->data);
6039 XPutImage(win->src.display, win->src.window, win->src.gc, win->src.bitmap, 0, 0, 0, 0, win->bufferSize.w, win->bufferSize.h);
6040 win->src.bitmap->data = NULL;
6041 return;
6042 #endif
6043 #ifdef RGFW_WAYLAND
6044 RGFW_WAYLAND_LABEL
6045 #if !defined(RGFW_BUFFER_BGR) && !defined(RGFW_OSMESA)
6046 RGFW_RGB_to_BGR(win, win->src.buffer);
6047 #else
6048 size_t y;
6049 for (y = 0; y < win->r.h; y++) {
6050 u32 index = (y * 4 * win->r.w);
6051 u32 index2 = (y * 4 * win->bufferSize.w);
6052 RGFW_MEMCPY(&win->src.buffer[index], &win->buffer[index2], win->r.w * 4);
6053 }
6054 #endif
6055
6056 wl_surface_frame_done(win, NULL, 0);
6057 wl_surface_commit(win->src.surface);
6058 #endif
6059#else
6060#ifdef RGFW_WAYLAND
6061 RGFW_WAYLAND_LABEL
6062#endif
6063 RGFW_UNUSED(win);
6064#endif
6065}
6066
6067#if !defined(RGFW_EGL)
6068
6069void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) {
6070 RGFW_ASSERT(win != NULL);
6071
6072 #if defined(RGFW_OPENGL)
6073 // cached pfn to avoid calling glXGetProcAddress more than once
6074 static PFNGLXSWAPINTERVALEXTPROC pfn = (PFNGLXSWAPINTERVALEXTPROC)123;
6075 static int (*pfn2)(int) = NULL;
6076
6077 if (pfn == (PFNGLXSWAPINTERVALEXTPROC)123) {
6078 pfn = ((PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddress((GLubyte*) "glXSwapIntervalEXT"));
6079 if (pfn == NULL) {
6080 const char* array[] = {"GLX_MESA_swap_control", "GLX_SGI_swap_control"};
6081 u32 i;
6082 for (i = 0; i < sizeof(array) / sizeof(char*) && pfn2 == NULL; i++)
6083 pfn2 = ((int(*)(int))glXGetProcAddress((GLubyte*) array[i]));
6084
6085 if (pfn2 != NULL) {
6086 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load swap interval function, fallingback to the native swapinterval function");
6087 } else {
6088 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load swap interval function");
6089 }
6090 }
6091 }
6092 if (pfn != NULL)
6093 pfn(win->src.display, win->src.window, swapInterval);
6094 else if (pfn2 != NULL) {
6095 pfn2(swapInterval);
6096 }
6097 #else
6098 RGFW_UNUSED(swapInterval);
6099 #endif
6100}
6101#endif
6102
6103void RGFW_deinit(void) {
6104 if (_RGFW.windowCount == -1 || _RGFW_init == RGFW_FALSE) return;
6105 #define RGFW_FREE_LIBRARY(x) if (x != NULL) dlclose(x); x = NULL;
6106#ifdef RGFW_X11
6107 /* to save the clipboard on the x server after the window is closed */
6108 RGFW_LOAD_ATOM(CLIPBOARD_MANAGER);
6109 RGFW_LOAD_ATOM(SAVE_TARGETS);
6110 if (XGetSelectionOwner(_RGFW.display, RGFW_XCLIPBOARD) == _RGFW.helperWindow) {
6111 XConvertSelection(_RGFW.display, CLIPBOARD_MANAGER, SAVE_TARGETS, None, _RGFW.helperWindow, CurrentTime);
6112 while (RGFW_XHandleClipboardSelectionHelper());
6113 }
6114 if (_RGFW.clipboard) {
6115 RGFW_FREE(_RGFW.clipboard);
6116 _RGFW.clipboard = NULL;
6117 }
6118
6119 RGFW_freeMouse(_RGFW.hiddenMouse);
6120
6121 XDestroyWindow(_RGFW.display, (Drawable) _RGFW.helperWindow); /*!< close the window */
6122 XCloseDisplay(_RGFW.display); /*!< kill connection to the x server */
6123
6124 #if !defined(RGFW_NO_X11_CURSOR_PRELOAD) && !defined(RGFW_NO_X11_CURSOR)
6125 RGFW_FREE_LIBRARY(X11Cursorhandle);
6126 #endif
6127 #if !defined(RGFW_NO_X11_XI_PRELOAD)
6128 RGFW_FREE_LIBRARY(X11Xihandle);
6129 #endif
6130
6131 #ifdef RGFW_USE_XDL
6132 XDL_close();
6133 #endif
6134
6135 #if !defined(RGFW_NO_X11_EXT_PRELOAD)
6136 RGFW_FREE_LIBRARY(X11XEXThandle);
6137 #endif
6138#endif
6139#ifdef RGFW_WAYLAND
6140 wl_display_disconnect(_RGFW.wl_display);
6141#endif
6142 #ifndef RGFW_NO_LINUX
6143 if (RGFW_eventWait_forceStop[0] || RGFW_eventWait_forceStop[1]){
6144 close(RGFW_eventWait_forceStop[0]);
6145 close(RGFW_eventWait_forceStop[1]);
6146 }
6147
6148 u8 i;
6149 for (i = 0; i < RGFW_gamepadCount; i++) {
6150 if(RGFW_gamepads[i])
6151 close(RGFW_gamepads[i]);
6152 }
6153 #endif
6154
6155 _RGFW.root = NULL;
6156 _RGFW.windowCount = -1;
6157 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized");
6158}
6159
6160void RGFW_window_close(RGFW_window* win) {
6161 RGFW_ASSERT(win != NULL);
6162 if ((win->_flags & RGFW_windowNoInitAPI) == 0) RGFW_window_freeOpenGL(win);
6163
6164 RGFW_GOTO_WAYLAND(0);
6165 #ifdef RGFW_X11
6166 /* ungrab pointer if it was grabbed */
6167 if (win->_flags & RGFW_HOLD_MOUSE)
6168 XUngrabPointer(win->src.display, CurrentTime);
6169
6170 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
6171 if (win->buffer != NULL) {
6172 if ((win->_flags & RGFW_BUFFER_ALLOC))
6173 RGFW_FREE(win->buffer);
6174 XDestroyImage((XImage*) win->src.bitmap);
6175 }
6176 #endif
6177
6178 XFreeGC(win->src.display, win->src.gc);
6179 XDestroyWindow(win->src.display, (Drawable) win->src.window); /*!< close the window */
6180 win->src.window = 0;
6181 XCloseDisplay(win->src.display);
6182
6183 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a window was freed");
6184 _RGFW.windowCount--;
6185 if (_RGFW.windowCount == 0) RGFW_deinit();
6186
6187 RGFW_clipboard_switch(NULL);
6188 RGFW_FREE(win->event.droppedFiles);
6189 if ((win->_flags & RGFW_WINDOW_ALLOC)) {
6190 RGFW_FREE(win);
6191 win = NULL;
6192 }
6193 return;
6194 #endif
6195
6196 #ifdef RGFW_WAYLAND
6197 RGFW_WAYLAND_LABEL
6198
6199 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a window was freed");
6200
6201 xdg_toplevel_destroy(win->src.xdg_toplevel);
6202 xdg_surface_destroy(win->src.xdg_surface);
6203 wl_surface_destroy(win->src.surface);
6204
6205 _RGFW.windowCount--;
6206 if (_RGFW.windowCount == 0) RGFW_deinit();
6207
6208 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
6209 wl_buffer_destroy(win->src.wl_buffer);
6210 if ((win->_flags & RGFW_BUFFER_ALLOC))
6211 RGFW_FREE(win->buffer);
6212
6213 munmap(win->src.buffer, (size_t)(win->r.w * win->r.h * 4));
6214 #endif
6215
6216 RGFW_clipboard_switch(NULL);
6217 RGFW_FREE(win->event.droppedFiles);
6218 if ((win->_flags & RGFW_WINDOW_ALLOC)) {
6219 RGFW_FREE(win);
6220 win = NULL;
6221 }
6222 #endif
6223}
6224
6225
6226/*
6227 End of X11 linux / wayland / unix defines
6228*/
6229
6230#include <fcntl.h>
6231#include <poll.h>
6232#include <unistd.h>
6233
6234void RGFW_stopCheckEvents(void) {
6235
6236 RGFW_eventWait_forceStop[2] = 1;
6237 while (1) {
6238 const char byte = 0;
6239 const ssize_t result = write(RGFW_eventWait_forceStop[1], &byte, 1);
6240 if (result == 1 || result == -1)
6241 break;
6242 }
6243}
6244
6245void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) {
6246 if (waitMS == 0) return;
6247
6248 u8 i;
6249 if (RGFW_eventWait_forceStop[0] == 0 || RGFW_eventWait_forceStop[1] == 0) {
6250 if (pipe(RGFW_eventWait_forceStop) != -1) {
6251 fcntl(RGFW_eventWait_forceStop[0], F_GETFL, 0);
6252 fcntl(RGFW_eventWait_forceStop[0], F_GETFD, 0);
6253 fcntl(RGFW_eventWait_forceStop[1], F_GETFL, 0);
6254 fcntl(RGFW_eventWait_forceStop[1], F_GETFD, 0);
6255 }
6256 }
6257
6258 struct pollfd fds[] = {
6259 #ifdef RGFW_WAYLAND
6260 { wl_display_get_fd(win->src.wl_display), POLLIN, 0 },
6261 #else
6262 { ConnectionNumber(win->src.display), POLLIN, 0 },
6263 #endif
6264 #ifdef RGFW_X11
6265 { ConnectionNumber(_RGFW.display), POLLIN, 0 },
6266 #endif
6267 { RGFW_eventWait_forceStop[0], POLLIN, 0 },
6268 #if defined(__linux__)
6269 { -1, POLLIN, 0 }, {-1, POLLIN, 0 }, {-1, POLLIN, 0 }, {-1, POLLIN, 0}
6270 #endif
6271 };
6272
6273 u8 index = 2;
6274#ifdef RGFW_X11
6275 index++;
6276#endif
6277
6278 #if defined(__linux__) || defined(__NetBSD__)
6279 for (i = 0; i < RGFW_gamepadCount; i++) {
6280 if (RGFW_gamepads[i] == 0)
6281 continue;
6282
6283 fds[index].fd = RGFW_gamepads[i];
6284 index++;
6285 }
6286 #endif
6287
6288
6289 u64 start = RGFW_getTimeNS();
6290
6291
6292 #ifdef RGFW_WAYLAND
6293 while (wl_display_dispatch(win->src.wl_display) <= 0
6294 #else
6295 while (XPending(win->src.display) == 0
6296 #endif
6297 #ifdef RGFW_X11
6298 && XPending(_RGFW.display) == 0
6299 #endif
6300 ) {
6301 if (poll(fds, index, waitMS) <= 0)
6302 break;
6303
6304 if (waitMS != RGFW_eventWaitNext)
6305 waitMS -= (i32)(RGFW_getTimeNS() - start) / (i32)1e+6;
6306 }
6307
6308 /* drain any data in the stop request */
6309 if (RGFW_eventWait_forceStop[2]) {
6310 char data[64];
6311 (void)!read(RGFW_eventWait_forceStop[0], data, sizeof(data));
6312
6313 RGFW_eventWait_forceStop[2] = 0;
6314 }
6315}
6316
6317i32 RGFW_getClock(void);
6318i32 RGFW_getClock(void) {
6319 static i32 clock = -1;
6320 if (clock != -1) return clock;
6321
6322 #if defined(_POSIX_MONOTONIC_CLOCK)
6323 struct timespec ts;
6324 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
6325 clock = CLOCK_MONOTONIC;
6326 #else
6327 clock = CLOCK_REALTIME;
6328 #endif
6329
6330 return clock;
6331}
6332
6333u64 RGFW_getTimerFreq(void) { return 1000000000LLU; }
6334u64 RGFW_getTimerValue(void) {
6335 struct timespec ts;
6336 clock_gettime(CLOCK_REALTIME, &ts);
6337 return (u64)ts.tv_sec * RGFW_getTimerFreq() + (u64)ts.tv_nsec;
6338}
6339#endif /* end of wayland or X11 defines */
6340
6341
6342
6343/*
6344
6345 Start of Windows defines
6346
6347
6348*/
6349
6350#ifdef RGFW_WINDOWS
6351#define WIN32_LEAN_AND_MEAN
6352#define OEMRESOURCE
6353#include <windows.h>
6354
6355#include <processthreadsapi.h>
6356#include <windowsx.h>
6357#include <shellapi.h>
6358#include <shellscalingapi.h>
6359#include <wchar.h>
6360#include <locale.h>
6361#include <winuser.h>
6362
6363#ifndef WM_DPICHANGED
6364#define WM_DPICHANGED 0x02E0
6365#endif
6366
6367#ifndef RGFW_NO_XINPUT
6368 typedef DWORD (WINAPI * PFN_XInputGetState)(DWORD,XINPUT_STATE*);
6369 PFN_XInputGetState XInputGetStateSRC = NULL;
6370 #define XInputGetState XInputGetStateSRC
6371
6372 typedef DWORD (WINAPI * PFN_XInputGetKeystroke)(DWORD, DWORD, PXINPUT_KEYSTROKE);
6373 PFN_XInputGetKeystroke XInputGetKeystrokeSRC = NULL;
6374 #define XInputGetKeystroke XInputGetKeystrokeSRC
6375
6376 HMODULE RGFW_XInput_dll = NULL;
6377#endif
6378
6379char* RGFW_createUTF8FromWideStringWin32(const WCHAR* source);
6380
6381#define GL_FRONT 0x0404
6382#define GL_BACK 0x0405
6383#define GL_LEFT 0x0406
6384#define GL_RIGHT 0x0407
6385
6386typedef int (*PFN_wglGetSwapIntervalEXT)(void);
6387PFN_wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc = NULL;
6388#define wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc
6389
6390
6391void* RGFWgamepadApi = NULL;
6392
6393/* these two wgl functions need to be preloaded */
6394typedef HGLRC (WINAPI *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC hdc, HGLRC hglrc, const int *attribList);
6395PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL;
6396
6397#ifndef RGFW_EGL
6398 HMODULE RGFW_wgl_dll = NULL;
6399#endif
6400
6401#ifndef RGFW_NO_LOAD_WGL
6402 typedef HGLRC(WINAPI* PFN_wglCreateContext)(HDC);
6403 typedef BOOL(WINAPI* PFN_wglDeleteContext)(HGLRC);
6404 typedef PROC(WINAPI* PFN_wglGetProcAddress)(LPCSTR);
6405 typedef BOOL(WINAPI* PFN_wglMakeCurrent)(HDC, HGLRC);
6406 typedef HDC(WINAPI* PFN_wglGetCurrentDC)(void);
6407 typedef HGLRC(WINAPI* PFN_wglGetCurrentContext)(void);
6408 typedef BOOL(WINAPI* PFN_wglShareLists)(HGLRC, HGLRC);
6409
6410 PFN_wglCreateContext wglCreateContextSRC;
6411 PFN_wglDeleteContext wglDeleteContextSRC;
6412 PFN_wglGetProcAddress wglGetProcAddressSRC;
6413 PFN_wglMakeCurrent wglMakeCurrentSRC;
6414 PFN_wglGetCurrentDC wglGetCurrentDCSRC;
6415 PFN_wglGetCurrentContext wglGetCurrentContextSRC;
6416 PFN_wglShareLists wglShareListsSRC;
6417
6418 #define wglCreateContext wglCreateContextSRC
6419 #define wglDeleteContext wglDeleteContextSRC
6420 #define wglGetProcAddress wglGetProcAddressSRC
6421 #define wglMakeCurrent wglMakeCurrentSRC
6422 #define wglGetCurrentDC wglGetCurrentDCSRC
6423 #define wglGetCurrentContext wglGetCurrentContextSRC
6424 #define wglShareLists wglShareListsSRC
6425#endif
6426
6427#if defined(RGFW_OPENGL) && !defined(RGFW_EGL)
6428RGFW_bool RGFW_extensionSupportedPlatform(const char * extension, size_t len) {
6429 const char* extensions = NULL;
6430
6431 RGFW_proc proc = RGFW_getProcAddress("wglGetExtensionsStringARB");
6432 RGFW_proc proc2 = RGFW_getProcAddress("wglGetExtensionsStringEXT");
6433
6434 if (proc)
6435 extensions = ((const char* (*)(HDC))proc)(wglGetCurrentDC());
6436 else if (proc2)
6437 extensions = ((const char*(*)(void))proc2)();
6438
6439 return extensions != NULL && RGFW_extensionSupportedStr(extensions, extension, len);
6440}
6441
6442RGFW_proc RGFW_getProcAddress(const char* procname) {
6443 RGFW_proc proc = (RGFW_proc)wglGetProcAddress(procname);
6444 if (proc)
6445 return proc;
6446
6447 return (RGFW_proc) GetProcAddress(RGFW_wgl_dll, procname);
6448}
6449
6450typedef HRESULT (APIENTRY* PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats);
6451PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL;
6452
6453typedef BOOL(APIENTRY* PFNWGLSWAPINTERVALEXTPROC)(int interval);
6454PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
6455#endif
6456
6457#ifndef RGFW_NO_DWM
6458HMODULE RGFW_dwm_dll = NULL;
6459typedef struct { DWORD dwFlags; int fEnable; HRGN hRgnBlur; int fTransitionOnMaximized;} DWM_BLURBEHIND;
6460typedef HRESULT (WINAPI * PFN_DwmEnableBlurBehindWindow)(HWND, const DWM_BLURBEHIND*);
6461PFN_DwmEnableBlurBehindWindow DwmEnableBlurBehindWindowSRC = NULL;
6462#endif
6463void RGFW_win32_makeWindowTransparent(RGFW_window* win);
6464void RGFW_win32_makeWindowTransparent(RGFW_window* win) {
6465 if (!(win->_flags & RGFW_windowTransparent)) return;
6466
6467 #ifndef RGFW_NO_DWM
6468 if (DwmEnableBlurBehindWindowSRC != NULL) {
6469 DWM_BLURBEHIND bb = {0, 0, 0, 0};
6470 bb.dwFlags = 0x1;
6471 bb.fEnable = TRUE;
6472 bb.hRgnBlur = NULL;
6473 DwmEnableBlurBehindWindowSRC(win->src.window, &bb);
6474
6475 } else
6476 #endif
6477 {
6478 SetWindowLong(win->src.window, GWL_EXSTYLE, WS_EX_LAYERED);
6479 SetLayeredWindowAttributes(win->src.window, 0, 128, LWA_ALPHA);
6480 }
6481}
6482
6483LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
6484LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
6485 RGFW_window* win = (RGFW_window*)GetPropW(hWnd, L"RGFW");
6486 if (win == NULL) return DefWindowProcW(hWnd, message, wParam, lParam);
6487
6488 RECT windowRect;
6489 GetWindowRect(hWnd, &windowRect);
6490
6491 switch (message) {
6492 case WM_CLOSE:
6493 case WM_QUIT:
6494 RGFW_eventQueuePushEx(e.type = RGFW_quit; e._win = win);
6495 RGFW_windowQuitCallback(win);
6496 return 0;
6497 case WM_ACTIVATE: {
6498 RGFW_bool inFocus = RGFW_BOOL(LOWORD(wParam) != WA_INACTIVE);
6499 if (inFocus) win->_flags |= RGFW_windowFocus;
6500 else win->_flags &= ~ (u32)RGFW_windowFocus;
6501 RGFW_eventQueuePushEx(e.type = (RGFW_eventType)((u8)RGFW_focusOut - inFocus); e._win = win);
6502
6503 RGFW_focusCallback(win, inFocus);
6504 RGFW_window_focusLost(win);
6505
6506 if ((win->_flags & RGFW_windowFullscreen) == 0)
6507 return DefWindowProcW(hWnd, message, wParam, lParam);
6508
6509 win->_flags &= ~(u32)RGFW_EVENT_PASSED;
6510 if (inFocus == RGFW_FALSE) RGFW_window_minimize(win);
6511 else RGFW_window_setFullscreen(win, 1);
6512 return DefWindowProcW(hWnd, message, wParam, lParam);
6513 }
6514 case WM_MOVE:
6515 win->r.x = windowRect.left;
6516 win->r.y = windowRect.top;
6517 RGFW_eventQueuePushEx(e.type = RGFW_windowMoved; e._win = win);
6518 RGFW_windowMovedCallback(win, win->r);
6519 return DefWindowProcW(hWnd, message, wParam, lParam);
6520 case WM_SIZE: {
6521 if (win->src.aspectRatio.w != 0 && win->src.aspectRatio.h != 0) {
6522 double aspectRatio = (double)win->src.aspectRatio.w / win->src.aspectRatio.h;
6523
6524 int width = windowRect.right - windowRect.left;
6525 int height = windowRect.bottom - windowRect.top;
6526 int newHeight = (int)(width / aspectRatio);
6527 int newWidth = (int)(height * aspectRatio);
6528
6529 if (win->r.w > windowRect.right - windowRect.left ||
6530 win->r.h > (i32)((u32)(windowRect.bottom - windowRect.top) - win->src.hOffset))
6531 {
6532 if (newHeight > height) windowRect.right = windowRect.left + newWidth;
6533 else windowRect.bottom = windowRect.top + newHeight;
6534 } else {
6535 if (newHeight < height) windowRect.right = windowRect.left + newWidth;
6536 else windowRect.bottom = windowRect.top + newHeight;
6537 }
6538
6539 RGFW_window_resize(win, RGFW_AREA((windowRect.right - windowRect.left),
6540 (u32)(windowRect.bottom - windowRect.top) - (u32)win->src.hOffset));
6541 }
6542
6543 win->r.w = windowRect.right - windowRect.left;
6544 win->r.h = (windowRect.bottom - windowRect.top) - (i32)win->src.hOffset;
6545 RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e._win = win);
6546 RGFW_windowResizedCallback(win, win->r);
6547 RGFW_window_checkMode(win);
6548 return DefWindowProcW(hWnd, message, wParam, lParam);
6549 }
6550 #ifndef RGFW_NO_MONITOR
6551 case WM_DPICHANGED: {
6552 if (win->_flags & RGFW_windowScaleToMonitor) RGFW_window_scaleToMonitor(win);
6553
6554 const float scaleX = HIWORD(wParam) / (float) 96;
6555 const float scaleY = LOWORD(wParam) / (float) 96;
6556 RGFW_scaleUpdatedCallback(win, scaleX, scaleY);
6557 RGFW_eventQueuePushEx(e.type = RGFW_scaleUpdated; e.scaleX = scaleX; e.scaleY = scaleY; e._win = win);
6558 return DefWindowProcW(hWnd, message, wParam, lParam);
6559 }
6560 #endif
6561 case WM_GETMINMAXINFO: {
6562 MINMAXINFO* mmi = (MINMAXINFO*) lParam;
6563 mmi->ptMinTrackSize.x = (LONG)win->src.minSize.w;
6564 mmi->ptMinTrackSize.y = (LONG)(win->src.minSize.h + win->src.hOffset);
6565 if (win->src.maxSize.w == 0 && win->src.maxSize.h == 0)
6566 return DefWindowProcW(hWnd, message, wParam, lParam);
6567
6568 mmi->ptMaxTrackSize.x = (LONG)win->src.maxSize.w;
6569 mmi->ptMaxTrackSize.y = (LONG)(win->src.maxSize.h + win->src.hOffset);
6570 return DefWindowProcW(hWnd, message, wParam, lParam);
6571 }
6572 case WM_PAINT: {
6573 PAINTSTRUCT ps;
6574 BeginPaint(hWnd, &ps);
6575 RGFW_eventQueuePushEx(e.type = RGFW_windowRefresh; e._win = win);
6576 RGFW_windowRefreshCallback(win);
6577 EndPaint(hWnd, &ps);
6578
6579 return DefWindowProcW(hWnd, message, wParam, lParam);
6580 }
6581 #if(_WIN32_WINNT >= 0x0600)
6582 case WM_DWMCOMPOSITIONCHANGED:
6583 case WM_DWMCOLORIZATIONCOLORCHANGED:
6584 RGFW_win32_makeWindowTransparent(win);
6585 break;
6586 #endif
6587/* based on sokol_app.h */
6588#ifdef RGFW_ADVANCED_SMOOTH_RESIZE
6589 case WM_ENTERSIZEMOVE: SetTimer(win->src.window, 1, USER_TIMER_MINIMUM, NULL); break;
6590 case WM_EXITSIZEMOVE: KillTimer(win->src.window, 1); break;
6591 case WM_TIMER: RGFW_windowRefreshCallback(win); break;
6592#endif
6593 case WM_NCLBUTTONDOWN: {
6594 /* workaround for half-second pause when starting to move window
6595 see: https://gamedev.net/forums/topic/672094-keeping-things-moving-during-win32-moveresize-events/5254386/
6596 */
6597 POINT point = { 0, 0 };
6598 if (SendMessage(win->src.window, WM_NCHITTEST, wParam, lParam) != HTCAPTION || GetCursorPos(&point) == FALSE)
6599 break;
6600
6601 ScreenToClient(win->src.window, &point);
6602 PostMessage(win->src.window, WM_MOUSEMOVE, 0, ((uint32_t)point.x)|(((uint32_t)point.y) << 16));
6603 break;
6604 }
6605 default: break;
6606 }
6607 return DefWindowProcW(hWnd, message, wParam, lParam);
6608}
6609
6610#ifndef RGFW_NO_DPI
6611 HMODULE RGFW_Shcore_dll = NULL;
6612 typedef HRESULT (WINAPI *PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*,UINT*);
6613 PFN_GetDpiForMonitor GetDpiForMonitorSRC = NULL;
6614 #define GetDpiForMonitor GetDpiForMonitorSRC
6615#endif
6616
6617#if !defined(RGFW_NO_LOAD_WINMM) && !defined(RGFW_NO_WINMM)
6618 HMODULE RGFW_winmm_dll = NULL;
6619 typedef u32 (WINAPI * PFN_timeBeginPeriod)(u32);
6620 typedef PFN_timeBeginPeriod PFN_timeEndPeriod;
6621 PFN_timeBeginPeriod timeBeginPeriodSRC, timeEndPeriodSRC;
6622 #define timeBeginPeriod timeBeginPeriodSRC
6623 #define timeEndPeriod timeEndPeriodSRC
6624#elif !defined(RGFW_NO_WINMM)
6625 __declspec(dllimport) u32 __stdcall timeBeginPeriod(u32 uPeriod);
6626 __declspec(dllimport) u32 __stdcall timeEndPeriod(u32 uPeriod);
6627#endif
6628#define RGFW_PROC_DEF(proc, name) if (name##SRC == NULL && proc != NULL) { \
6629 name##SRC = (PFN_##name)(RGFW_proc)GetProcAddress((proc), (#name)); \
6630 RGFW_ASSERT(name##SRC != NULL); \
6631 }
6632
6633#ifndef RGFW_NO_XINPUT
6634void RGFW_loadXInput(void);
6635void RGFW_loadXInput(void) {
6636 u32 i;
6637 static const char* names[] = {"xinput1_4.dll", "xinput9_1_0.dll", "xinput1_2.dll", "xinput1_1.dll"};
6638
6639 for (i = 0; i < sizeof(names) / sizeof(const char*) && (XInputGetStateSRC == NULL || XInputGetKeystrokeSRC != NULL); i++) {
6640 RGFW_XInput_dll = LoadLibraryA(names[i]);
6641 RGFW_PROC_DEF(RGFW_XInput_dll, XInputGetState);
6642 RGFW_PROC_DEF(RGFW_XInput_dll, XInputGetKeystroke);
6643 }
6644
6645 if (XInputGetStateSRC == NULL)
6646 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errFailedFuncLoad, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load XInputGetState");
6647 if (XInputGetKeystrokeSRC == NULL)
6648 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errFailedFuncLoad, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load XInputGetKeystroke");
6649}
6650#endif
6651
6652void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area){
6653#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
6654 win->buffer = buffer;
6655 win->bufferSize = area;
6656
6657 BITMAPV5HEADER bi;
6658 ZeroMemory(&bi, sizeof(bi));
6659 bi.bV5Size = sizeof(bi);
6660 bi.bV5Width = (i32)area.w;
6661 bi.bV5Height = -((LONG) area.h);
6662 bi.bV5Planes = 1;
6663 bi.bV5BitCount = 32;
6664 bi.bV5Compression = BI_RGB;
6665
6666 win->src.bitmap = CreateDIBSection(win->src.hdc,
6667 (BITMAPINFO*) &bi, DIB_RGB_COLORS,
6668 (void**) &win->src.bitmapBits,
6669 NULL, (DWORD) 0);
6670
6671 if (win->buffer == NULL)
6672 win->buffer = win->src.bitmapBits;
6673
6674 win->src.hdcMem = CreateCompatibleDC(win->src.hdc);
6675 SelectObject(win->src.hdcMem, win->src.bitmap);
6676
6677 #if defined(RGFW_OSMESA)
6678 win->src.ctx = OSMesaCreateContext(OSMESA_BGRA, NULL);
6679 OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h);
6680 OSMesaPixelStore(OSMESA_Y_UP, 0);
6681 #endif
6682 #else
6683 RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area); /*!< if buffer rendering is not being used */
6684 #endif
6685}
6686
6687void RGFW_releaseCursor(RGFW_window* win) {
6688 RGFW_UNUSED(win);
6689 ClipCursor(NULL);
6690 const RAWINPUTDEVICE id = { 0x01, 0x02, RIDEV_REMOVE, NULL };
6691 RegisterRawInputDevices(&id, 1, sizeof(id));
6692}
6693
6694void RGFW_captureCursor(RGFW_window* win, RGFW_rect rect) {
6695 RGFW_UNUSED(win); RGFW_UNUSED(rect);
6696
6697 RECT clipRect;
6698 GetClientRect(win->src.window, &clipRect);
6699 ClientToScreen(win->src.window, (POINT*) &clipRect.left);
6700 ClientToScreen(win->src.window, (POINT*) &clipRect.right);
6701 ClipCursor(&clipRect);
6702
6703 const RAWINPUTDEVICE id = { 0x01, 0x02, 0, win->src.window };
6704 RegisterRawInputDevices(&id, 1, sizeof(id));
6705}
6706
6707#define RGFW_LOAD_LIBRARY(x, lib) if (x == NULL) { x = LoadLibraryA(lib); RGFW_ASSERT(x != NULL); }
6708
6709#ifdef RGFW_DIRECTX
6710int RGFW_window_createDXSwapChain(RGFW_window* win, IDXGIFactory* pFactory, IUnknown* pDevice, IDXGISwapChain** swapchain) {
6711 RGFW_ASSERT(win && pFactory && pDevice && swapchain);
6712
6713 static DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 };
6714 swapChainDesc.BufferCount = 2;
6715 swapChainDesc.BufferDesc.Width = win->r.w;
6716 swapChainDesc.BufferDesc.Height = win->r.h;
6717 swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
6718 swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
6719 swapChainDesc.OutputWindow = (HWND)win->src.window;
6720 swapChainDesc.SampleDesc.Count = 1;
6721 swapChainDesc.SampleDesc.Quality = 0;
6722 swapChainDesc.Windowed = TRUE;
6723 swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
6724
6725 HRESULT hr = pFactory->lpVtbl->CreateSwapChain(pFactory, (IUnknown*)pDevice, &swapChainDesc, swapchain);
6726 if (FAILED(hr)) {
6727 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errDirectXContext, RGFW_DEBUG_CTX(win, hr), "Failed to create DirectX swap chain!");
6728 return -2;
6729 }
6730
6731 return 0;
6732}
6733#endif
6734
6735void RGFW_win32_loadOpenGLFuncs(HWND dummyWin);
6736void RGFW_win32_loadOpenGLFuncs(HWND dummyWin) {
6737#ifdef RGFW_OPENGL
6738 if (wglSwapIntervalEXT != NULL && wglChoosePixelFormatARB != NULL && wglChoosePixelFormatARB != NULL)
6739 return;
6740
6741 HDC dummy_dc = GetDC(dummyWin);
6742 u32 pfd_flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
6743
6744 PIXELFORMATDESCRIPTOR pfd = {sizeof(pfd), 1, pfd_flags, PFD_TYPE_RGBA, 32, 8, PFD_MAIN_PLANE, 32, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 32, 8, 0, PFD_MAIN_PLANE, 0, 0, 0, 0};
6745
6746 int dummy_pixel_format = ChoosePixelFormat(dummy_dc, &pfd);
6747 SetPixelFormat(dummy_dc, dummy_pixel_format, &pfd);
6748
6749 HGLRC dummy_context = wglCreateContext(dummy_dc);
6750 wglMakeCurrent(dummy_dc, dummy_context);
6751
6752 wglCreateContextAttribsARB = ((PFNWGLCREATECONTEXTATTRIBSARBPROC(WINAPI *)(const char*)) wglGetProcAddress)("wglCreateContextAttribsARB");
6753 wglChoosePixelFormatARB = ((PFNWGLCHOOSEPIXELFORMATARBPROC(WINAPI *)(const char*)) wglGetProcAddress)("wglChoosePixelFormatARB");
6754
6755 wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)(RGFW_proc)wglGetProcAddress("wglSwapIntervalEXT");
6756 if (wglSwapIntervalEXT == NULL) {
6757 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load swap interval function");
6758 }
6759
6760 wglMakeCurrent(dummy_dc, 0);
6761 wglDeleteContext(dummy_context);
6762 ReleaseDC(dummyWin, dummy_dc);
6763#else
6764 RGFW_UNUSED(dummyWin);
6765#endif
6766}
6767
6768#ifndef RGFW_EGL
6769void RGFW_window_initOpenGL(RGFW_window* win) {
6770#ifdef RGFW_OPENGL
6771 PIXELFORMATDESCRIPTOR pfd;
6772 pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
6773 pfd.nVersion = 1;
6774 pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
6775 pfd.iPixelType = PFD_TYPE_RGBA;
6776 pfd.iLayerType = PFD_MAIN_PLANE;
6777 pfd.cColorBits = 32;
6778 pfd.cAlphaBits = 8;
6779 pfd.cDepthBits = 24;
6780 pfd.cStencilBits = (BYTE)RGFW_GL_HINTS[RGFW_glStencil];
6781 pfd.cAuxBuffers = (BYTE)RGFW_GL_HINTS[RGFW_glAuxBuffers];
6782 if (RGFW_GL_HINTS[RGFW_glStereo]) pfd.dwFlags |= PFD_STEREO;
6783
6784 /* try to create the pixel format we want for opengl and then try to create an opengl context for the specified version */
6785 if (win->_flags & RGFW_windowOpenglSoftware)
6786 pfd.dwFlags |= PFD_GENERIC_FORMAT | PFD_GENERIC_ACCELERATED;
6787
6788 /* get pixel format, default to a basic pixel format */
6789 int pixel_format = ChoosePixelFormat(win->src.hdc, &pfd);
6790 if (wglChoosePixelFormatARB != NULL) {
6791 i32* pixel_format_attribs = (i32*)RGFW_initFormatAttribs();
6792
6793 int new_pixel_format;
6794 UINT num_formats;
6795 wglChoosePixelFormatARB(win->src.hdc, pixel_format_attribs, 0, 1, &new_pixel_format, &num_formats);
6796 if (!num_formats)
6797 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to create a pixel format for WGL");
6798 else pixel_format = new_pixel_format;
6799 }
6800
6801 PIXELFORMATDESCRIPTOR suggested;
6802 if (!DescribePixelFormat(win->src.hdc, pixel_format, sizeof(suggested), &suggested) ||
6803 !SetPixelFormat(win->src.hdc, pixel_format, &pfd))
6804 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to set the WGL pixel format");
6805
6806 if (!(pfd.dwFlags & PFD_GENERIC_ACCELERATED)) {
6807 win->_flags |= RGFW_windowOpenglSoftware;
6808 }
6809
6810 if (wglCreateContextAttribsARB != NULL) {
6811 /* create opengl/WGL context for the specified version */
6812 u32 index = 0;
6813 i32 attribs[40];
6814
6815 if (RGFW_GL_HINTS[RGFW_glProfile]== RGFW_glCore) {
6816 SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB);
6817 }
6818 else {
6819 SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB);
6820 }
6821
6822 if (RGFW_GL_HINTS[RGFW_glMinor] || RGFW_GL_HINTS[RGFW_glMajor]) {
6823 SET_ATTRIB(WGL_CONTEXT_MAJOR_VERSION_ARB, RGFW_GL_HINTS[RGFW_glMajor]);
6824 SET_ATTRIB(WGL_CONTEXT_MINOR_VERSION_ARB, RGFW_GL_HINTS[RGFW_glMinor]);
6825 }
6826
6827 SET_ATTRIB(0, 0);
6828
6829 win->src.ctx = (HGLRC)wglCreateContextAttribsARB(win->src.hdc, NULL, attribs);
6830 } else { /* fall back to a default context (probably opengl 2 or something) */
6831 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to create an accelerated OpenGL Context");
6832 win->src.ctx = wglCreateContext(win->src.hdc);
6833 }
6834
6835 ReleaseDC(win->src.window, win->src.hdc);
6836 win->src.hdc = GetDC(win->src.window);
6837 wglMakeCurrent(win->src.hdc, win->src.ctx);
6838
6839 if (_RGFW.root != win)
6840 wglShareLists(_RGFW.root->src.ctx, win->src.ctx);
6841 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context initalized");
6842#else
6843 RGFW_UNUSED(win);
6844#endif
6845}
6846
6847void RGFW_window_freeOpenGL(RGFW_window* win) {
6848#ifdef RGFW_OPENGL
6849 if (win->src.ctx == NULL) return;
6850 wglDeleteContext((HGLRC) win->src.ctx); /*!< delete opengl context */
6851 win->src.ctx = NULL;
6852 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context freed");
6853#else
6854 RGFW_UNUSED(win);
6855#endif
6856}
6857#endif
6858
6859
6860i32 RGFW_init(void) {
6861#if defined(RGFW_C89) || defined(__cplusplus)
6862 if (_RGFW_init) return 0;
6863 _RGFW_init = RGFW_TRUE;
6864 _RGFW.root = NULL; _RGFW.current = NULL; _RGFW.windowCount = -1; _RGFW.eventLen = 0; _RGFW.eventIndex = 0;
6865#endif
6866
6867 #ifndef RGFW_NO_XINPUT
6868 if (RGFW_XInput_dll == NULL)
6869 RGFW_loadXInput();
6870 #endif
6871
6872#ifndef RGFW_NO_DPI
6873 #if (_WIN32_WINNT >= 0x0600)
6874 SetProcessDPIAware();
6875 #endif
6876#endif
6877
6878 #ifndef RGFW_NO_WINMM
6879 #ifndef RGFW_NO_LOAD_WINMM
6880 RGFW_LOAD_LIBRARY(RGFW_winmm_dll, "winmm.dll");
6881 RGFW_PROC_DEF(RGFW_winmm_dll, timeBeginPeriod);
6882 RGFW_PROC_DEF(RGFW_winmm_dll, timeEndPeriod);
6883 #endif
6884 timeBeginPeriod(1);
6885 #endif
6886
6887 #ifndef RGFW_NO_DWM
6888 RGFW_LOAD_LIBRARY(RGFW_dwm_dll, "dwmapi.dll");
6889 RGFW_PROC_DEF(RGFW_dwm_dll, DwmEnableBlurBehindWindow);
6890 #endif
6891
6892 RGFW_LOAD_LIBRARY(RGFW_wgl_dll, "opengl32.dll");
6893 #ifndef RGFW_NO_LOAD_WGL
6894 RGFW_PROC_DEF(RGFW_wgl_dll, wglCreateContext);
6895 RGFW_PROC_DEF(RGFW_wgl_dll, wglDeleteContext);
6896 RGFW_PROC_DEF(RGFW_wgl_dll, wglGetProcAddress);
6897 RGFW_PROC_DEF(RGFW_wgl_dll, wglMakeCurrent);
6898 RGFW_PROC_DEF(RGFW_wgl_dll, wglGetCurrentDC);
6899 RGFW_PROC_DEF(RGFW_wgl_dll, wglGetCurrentContext);
6900 RGFW_PROC_DEF(RGFW_wgl_dll, wglShareLists);
6901 #endif
6902
6903 u8 RGFW_blk[] = { 0, 0, 0, 0 };
6904 _RGFW.hiddenMouse = RGFW_loadMouse(RGFW_blk, RGFW_AREA(1, 1), 4);
6905
6906 _RGFW.windowCount = 0;
6907 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context initialized");
6908 return 1;
6909}
6910
6911RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) {
6912 if (name[0] == 0) name = (char*) " ";
6913
6914 RGFW_window_basic_init(win, rect, flags);
6915
6916 win->src.hIconSmall = win->src.hIconBig = NULL;
6917 win->src.maxSize = RGFW_AREA(0, 0);
6918 win->src.minSize = RGFW_AREA(0, 0);
6919 win->src.aspectRatio = RGFW_AREA(0, 0);
6920
6921 HINSTANCE inh = GetModuleHandleA(NULL);
6922
6923 #ifndef __cplusplus
6924 WNDCLASSW Class = { 0 }; /*!< Setup the Window class. */
6925 #else
6926 WNDCLASSW Class = { };
6927 #endif
6928
6929 if (RGFW_className == NULL)
6930 RGFW_className = (char*)name;
6931
6932 wchar_t wide_class[256];
6933 MultiByteToWideChar(CP_UTF8, 0, RGFW_className, -1, wide_class, 255);
6934
6935 Class.lpszClassName = wide_class;
6936 Class.hInstance = inh;
6937 Class.hCursor = LoadCursor(NULL, IDC_ARROW);
6938 Class.lpfnWndProc = WndProcW;
6939 Class.cbClsExtra = sizeof(RGFW_window*);
6940
6941 Class.hIcon = (HICON)LoadImageA(GetModuleHandleW(NULL), "RGFW_ICON", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
6942 if (Class.hIcon == NULL)
6943 Class.hIcon = (HICON)LoadImageA(NULL, (LPCSTR)IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
6944
6945 RegisterClassW(&Class);
6946
6947 DWORD window_style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
6948
6949 RECT windowRect, clientRect;
6950
6951 if (!(flags & RGFW_windowNoBorder)) {
6952 window_style |= WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX | WS_THICKFRAME;
6953
6954 if (!(flags & RGFW_windowNoResize))
6955 window_style |= WS_SIZEBOX | WS_MAXIMIZEBOX;
6956 } else
6957 window_style |= WS_POPUP | WS_VISIBLE | WS_SYSMENU;
6958
6959 wchar_t wide_name[256];
6960 MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_name, 255);
6961 HWND dummyWin = CreateWindowW(Class.lpszClassName, (wchar_t*)wide_name, window_style, win->r.x, win->r.y, win->r.w, win->r.h, 0, 0, inh, 0);
6962
6963 GetWindowRect(dummyWin, &windowRect);
6964 GetClientRect(dummyWin, &clientRect);
6965
6966 RGFW_win32_loadOpenGLFuncs(dummyWin);
6967 DestroyWindow(dummyWin);
6968
6969 win->src.hOffset = (u32)(windowRect.bottom - windowRect.top) - (u32)(clientRect.bottom - clientRect.top);
6970 win->src.window = CreateWindowW(Class.lpszClassName, (wchar_t*)wide_name, window_style, win->r.x, win->r.y, win->r.w, win->r.h + (i32)win->src.hOffset, 0, 0, inh, 0);
6971 SetPropW(win->src.window, L"RGFW", win);
6972 RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h)); /* so WM_GETMINMAXINFO gets called again */
6973
6974 if (flags & RGFW_windowAllowDND) {
6975 win->_flags |= RGFW_windowAllowDND;
6976 RGFW_window_setDND(win, 1);
6977 }
6978 win->src.hdc = GetDC(win->src.window);
6979
6980 if ((flags & RGFW_windowNoInitAPI) == 0) {
6981 RGFW_window_initOpenGL(win);
6982 RGFW_window_initBuffer(win);
6983 }
6984
6985 RGFW_window_setFlags(win, flags);
6986 RGFW_win32_makeWindowTransparent(win);
6987 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created");
6988 RGFW_window_show(win);
6989
6990 return win;
6991}
6992
6993void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) {
6994 RGFW_setBit(&win->_flags, RGFW_windowNoBorder, !border);
6995 LONG style = GetWindowLong(win->src.window, GWL_STYLE);
6996
6997
6998 if (border == 0) {
6999 SetWindowLong(win->src.window, GWL_STYLE, style & ~WS_OVERLAPPEDWINDOW);
7000 SetWindowPos(
7001 win->src.window, HWND_TOP, 0, 0, 0, 0,
7002 SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE
7003 );
7004 }
7005 else {
7006 style |= WS_OVERLAPPEDWINDOW;
7007 if (win->_flags & RGFW_windowNoResize) style &= ~WS_MAXIMIZEBOX;
7008 SetWindowPos(
7009 win->src.window, HWND_TOP, 0, 0, 0, 0,
7010 SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE
7011 );
7012 }
7013}
7014
7015void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow) {
7016 RGFW_setBit(&win->_flags, RGFW_windowAllowDND, allow);
7017 DragAcceptFiles(win->src.window, allow);
7018}
7019
7020RGFW_area RGFW_getScreenSize(void) {
7021 HDC dc = GetDC(NULL);
7022 RGFW_area area = RGFW_AREA(GetDeviceCaps(dc, HORZRES), GetDeviceCaps(dc, VERTRES));
7023 ReleaseDC(NULL, dc);
7024 return area;
7025}
7026
7027RGFW_point RGFW_getGlobalMousePoint(void) {
7028 POINT p;
7029 GetCursorPos(&p);
7030
7031 return RGFW_POINT(p.x, p.y);
7032}
7033
7034void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) {
7035 RGFW_ASSERT(win != NULL);
7036 win->src.aspectRatio = a;
7037}
7038
7039void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) {
7040 RGFW_ASSERT(win != NULL);
7041 win->src.minSize = a;
7042}
7043
7044void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) {
7045 RGFW_ASSERT(win != NULL);
7046 win->src.maxSize = a;
7047}
7048
7049void RGFW_window_focus(RGFW_window* win) {
7050 RGFW_ASSERT(win);
7051 SetForegroundWindow(win->src.window);
7052 SetFocus(win->src.window);
7053}
7054
7055void RGFW_window_raise(RGFW_window* win) {
7056 RGFW_ASSERT(win);
7057 BringWindowToTop(win->src.window);
7058 SetWindowPos(win->src.window, HWND_TOP, win->r.x, win->r.y, win->r.w, win->r.h, SWP_NOSIZE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
7059}
7060
7061void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) {
7062 RGFW_ASSERT(win != NULL);
7063
7064 if (fullscreen == RGFW_FALSE) {
7065 RGFW_window_setBorder(win, 1);
7066 SetWindowPos(win->src.window, HWND_NOTOPMOST, win->_oldRect.x, win->_oldRect.y, win->_oldRect.w, win->_oldRect.h + (i32)win->src.hOffset,
7067 SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
7068
7069 win->_flags &= ~(u32)RGFW_windowFullscreen;
7070 win->r = win->_oldRect;
7071 return;
7072 }
7073
7074 win->_oldRect = win->r;
7075 win->_flags |= RGFW_windowFullscreen;
7076
7077 RGFW_monitor mon = RGFW_window_getMonitor(win);
7078 RGFW_window_setBorder(win, 0);
7079
7080 SetWindowPos(win->src.window, HWND_TOPMOST, 0, 0, (i32)mon.mode.area.w, (i32)mon.mode.area.h, SWP_NOOWNERZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW);
7081 RGFW_monitor_scaleToWindow(mon, win);
7082
7083 win->r = RGFW_RECT(0, 0, mon.mode.area.w, mon.mode.area.h);
7084}
7085
7086void RGFW_window_maximize(RGFW_window* win) {
7087 RGFW_ASSERT(win != NULL);
7088 RGFW_window_hide(win);
7089 ShowWindow(win->src.window, SW_MAXIMIZE);
7090}
7091
7092void RGFW_window_minimize(RGFW_window* win) {
7093 RGFW_ASSERT(win != NULL);
7094 ShowWindow(win->src.window, SW_MINIMIZE);
7095}
7096
7097void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) {
7098 RGFW_ASSERT(win != NULL);
7099 if (floating) SetWindowPos(win->src.window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
7100 else SetWindowPos(win->src.window, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
7101}
7102
7103void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) {
7104 SetWindowLong(win->src.window, GWL_EXSTYLE, WS_EX_LAYERED);
7105 SetLayeredWindowAttributes(win->src.window, 0, opacity, LWA_ALPHA);
7106}
7107
7108void RGFW_window_restore(RGFW_window* win) { RGFW_window_show(win); }
7109
7110RGFW_bool RGFW_window_isFloating(RGFW_window* win) {
7111 return (GetWindowLongPtr(win->src.window, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
7112}
7113
7114u8 RGFW_xinput2RGFW[] = {
7115 RGFW_gamepadA, /* or PS X button */
7116 RGFW_gamepadB, /* or PS circle button */
7117 RGFW_gamepadX, /* or PS square button */
7118 RGFW_gamepadY, /* or PS triangle button */
7119 RGFW_gamepadR1, /* right bumper */
7120 RGFW_gamepadL1, /* left bump */
7121 RGFW_gamepadL2, /* left trigger */
7122 RGFW_gamepadR2, /* right trigger */
7123 0, 0, 0, 0, 0, 0, 0, 0,
7124 RGFW_gamepadUp, /* dpad up */
7125 RGFW_gamepadDown, /* dpad down */
7126 RGFW_gamepadLeft, /* dpad left */
7127 RGFW_gamepadRight, /* dpad right */
7128 RGFW_gamepadStart, /* start button */
7129 RGFW_gamepadSelect,/* select button */
7130 RGFW_gamepadL3,
7131 RGFW_gamepadR3,
7132};
7133i32 RGFW_checkXInput(RGFW_window* win, RGFW_event* e);
7134i32 RGFW_checkXInput(RGFW_window* win, RGFW_event* e) {
7135 #ifndef RGFW_NO_XINPUT
7136
7137 RGFW_UNUSED(win);
7138 u16 i;
7139 for (i = 0; i < 4; i++) {
7140 XINPUT_KEYSTROKE keystroke;
7141
7142 if (XInputGetKeystroke == NULL)
7143 return 0;
7144
7145 DWORD result = XInputGetKeystroke((DWORD)i, 0, &keystroke);
7146
7147 if ((keystroke.Flags & XINPUT_KEYSTROKE_REPEAT) == 0 && result != ERROR_EMPTY) {
7148 if (result != ERROR_SUCCESS)
7149 return 0;
7150
7151 if (keystroke.VirtualKey > VK_PAD_RTHUMB_PRESS)
7152 continue;
7153
7154 /* gamepad + 1 = RGFW_gamepadButtonReleased */
7155 e->type = RGFW_gamepadButtonPressed + !(keystroke.Flags & XINPUT_KEYSTROKE_KEYDOWN);
7156 e->button = RGFW_xinput2RGFW[keystroke.VirtualKey - 0x5800];
7157 RGFW_gamepadPressed[i][e->button].prev = RGFW_gamepadPressed[i][e->button].current;
7158 RGFW_gamepadPressed[i][e->button].current = RGFW_BOOL(keystroke.Flags & XINPUT_KEYSTROKE_KEYDOWN);
7159
7160 RGFW_gamepadButtonCallback(win, i, e->button, e->type == RGFW_gamepadButtonPressed);
7161 return 1;
7162 }
7163
7164 XINPUT_STATE state;
7165 if (XInputGetState == NULL ||
7166 XInputGetState((DWORD) i, &state) == ERROR_DEVICE_NOT_CONNECTED
7167 ) {
7168 if (RGFW_gamepads[i] == 0)
7169 continue;
7170
7171 RGFW_gamepads[i] = 0;
7172 RGFW_gamepadCount--;
7173
7174 win->event.type = RGFW_gamepadDisconnected;
7175 win->event.gamepad = (u16)i;
7176 RGFW_gamepadCallback(win, i, 0);
7177 return 1;
7178 }
7179
7180 if (RGFW_gamepads[i] == 0) {
7181 RGFW_gamepads[i] = 1;
7182 RGFW_gamepadCount++;
7183
7184 char str[] = "Microsoft X-Box (XInput device)";
7185 RGFW_MEMCPY(RGFW_gamepads_name[i], str, sizeof(str));
7186 RGFW_gamepads_name[i][sizeof(RGFW_gamepads_name[i]) - 1] = '\0';
7187 win->event.type = RGFW_gamepadConnected;
7188 win->event.gamepad = i;
7189 RGFW_gamepads_type[i] = RGFW_gamepadMicrosoft;
7190
7191 RGFW_gamepadCallback(win, i, 1);
7192 return 1;
7193 }
7194
7195#define INPUT_DEADZONE ( 0.24f * (float)(0x7FFF) ) /* Default to 24% of the +/- 32767 range. This is a reasonable default value but can be altered if needed. */
7196
7197 if ((state.Gamepad.sThumbLX < INPUT_DEADZONE &&
7198 state.Gamepad.sThumbLX > -INPUT_DEADZONE) &&
7199 (state.Gamepad.sThumbLY < INPUT_DEADZONE &&
7200 state.Gamepad.sThumbLY > -INPUT_DEADZONE))
7201 {
7202 state.Gamepad.sThumbLX = 0;
7203 state.Gamepad.sThumbLY = 0;
7204 }
7205
7206 if ((state.Gamepad.sThumbRX < INPUT_DEADZONE &&
7207 state.Gamepad.sThumbRX > -INPUT_DEADZONE) &&
7208 (state.Gamepad.sThumbRY < INPUT_DEADZONE &&
7209 state.Gamepad.sThumbRY > -INPUT_DEADZONE))
7210 {
7211 state.Gamepad.sThumbRX = 0;
7212 state.Gamepad.sThumbRY = 0;
7213 }
7214
7215 e->axisesCount = 2;
7216 RGFW_point axis1 = RGFW_POINT(((float)state.Gamepad.sThumbLX / 32768.0f) * 100, ((float)state.Gamepad.sThumbLY / -32768.0f) * 100);
7217 RGFW_point axis2 = RGFW_POINT(((float)state.Gamepad.sThumbRX / 32768.0f) * 100, ((float)state.Gamepad.sThumbRY / -32768.0f) * 100);
7218
7219 if (axis1.x != e->axis[0].x || axis1.y != e->axis[0].y){
7220 win->event.whichAxis = 0;
7221
7222 e->type = RGFW_gamepadAxisMove;
7223 e->axis[0] = axis1;
7224 RGFW_gamepadAxes[i][0] = e->axis[0];
7225
7226 RGFW_gamepadAxisCallback(win, e->gamepad, e->axis, e->axisesCount, e->whichAxis);
7227 return 1;
7228 }
7229
7230 if (axis2.x != e->axis[1].x || axis2.y != e->axis[1].y) {
7231 win->event.whichAxis = 1;
7232 e->type = RGFW_gamepadAxisMove;
7233 e->axis[1] = axis2;
7234 RGFW_gamepadAxes[i][1] = e->axis[1];
7235
7236 RGFW_gamepadAxisCallback(win, e->gamepad, e->axis, e->axisesCount, e->whichAxis);
7237 return 1;
7238 }
7239 }
7240
7241 #endif
7242
7243 return 0;
7244}
7245
7246void RGFW_stopCheckEvents(void) {
7247 PostMessageW(_RGFW.root->src.window, WM_NULL, 0, 0);
7248}
7249
7250void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) {
7251 RGFW_UNUSED(win);
7252 MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD)waitMS, QS_ALLINPUT);
7253}
7254
7255u8 RGFW_rgfwToKeyChar(u32 rgfw_keycode) {
7256 UINT vsc = RGFW_rgfwToApiKey(rgfw_keycode); // Should return a Windows VK_* code
7257 BYTE keyboardState[256] = {0};
7258
7259 if (!GetKeyboardState(keyboardState))
7260 return (u8)rgfw_keycode;
7261
7262 UINT vk = MapVirtualKeyW(vsc, MAPVK_VSC_TO_VK);
7263 HKL layout = GetKeyboardLayout(0);
7264
7265 wchar_t charBuffer[2] = {0};
7266 int result = ToUnicodeEx(vk, vsc, keyboardState, charBuffer, 1, 0, layout);
7267
7268 if (result <= 0)
7269 return (u8)rgfw_keycode;
7270
7271 return (u8)charBuffer[0];
7272}
7273
7274RGFW_event* RGFW_window_checkEvent(RGFW_window* win) {
7275 if (win == NULL || ((win->_flags & RGFW_windowFreeOnClose) && (win->_flags & RGFW_EVENT_QUIT))) return NULL;
7276 RGFW_event* ev = RGFW_window_checkEventCore(win);
7277 if (ev) {
7278 return ev;
7279 }
7280
7281 static HDROP drop;
7282 if (win->event.type == RGFW_DNDInit) {
7283 if (win->event.droppedFilesCount) {
7284 u32 i;
7285 for (i = 0; i < win->event.droppedFilesCount; i++)
7286 win->event.droppedFiles[i][0] = '\0';
7287 }
7288
7289 win->event.droppedFilesCount = 0;
7290 win->event.droppedFilesCount = DragQueryFileW(drop, 0xffffffff, NULL, 0);
7291
7292 u32 i;
7293 for (i = 0; i < win->event.droppedFilesCount; i++) {
7294 UINT length = DragQueryFileW(drop, i, NULL, 0);
7295 if (length == 0)
7296 continue;
7297
7298 WCHAR buffer[RGFW_MAX_PATH * 2];
7299 if (length > (RGFW_MAX_PATH * 2) - 1)
7300 length = RGFW_MAX_PATH * 2;
7301
7302 DragQueryFileW(drop, i, buffer, length + 1);
7303
7304 char* str = RGFW_createUTF8FromWideStringWin32(buffer);
7305 if (str != NULL)
7306 RGFW_MEMCPY(win->event.droppedFiles[i], str, length + 1);
7307
7308 win->event.droppedFiles[i][RGFW_MAX_PATH - 1] = '\0';
7309 }
7310
7311 DragFinish(drop);
7312 RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount);
7313
7314 win->event.type = RGFW_DND;
7315 return &win->event;
7316 }
7317
7318 if (RGFW_checkXInput(win, &win->event))
7319 return &win->event;
7320
7321 static BYTE keyboardState[256];
7322 GetKeyboardState(keyboardState);
7323
7324 MSG msg;
7325 if (PeekMessageA(&msg, NULL, 0u, 0u, PM_REMOVE)) {
7326 if (msg.hwnd != win->src.window && msg.hwnd != NULL) {
7327 TranslateMessage(&msg);
7328 DispatchMessageA(&msg);
7329 return RGFW_window_checkEvent(win);
7330 }
7331 } else {
7332 return NULL;
7333 }
7334
7335 switch (msg.message) {
7336 case WM_MOUSELEAVE:
7337 win->event.type = RGFW_mouseLeave;
7338 win->_flags |= RGFW_MOUSE_LEFT;
7339 RGFW_mouseNotifyCallback(win, win->event.point, 0);
7340 break;
7341 case WM_SYSKEYUP: case WM_KEYUP: {
7342 i32 scancode = (HIWORD(msg.lParam) & (KF_EXTENDED | 0xff));
7343 if (scancode == 0)
7344 scancode = (i32)MapVirtualKeyW((UINT)msg.wParam, MAPVK_VK_TO_VSC);
7345
7346 switch (scancode) {
7347 case 0x54: scancode = 0x137; break; /* Alt+PrtS */
7348 case 0x146: scancode = 0x45; break; /* Ctrl+Pause */
7349 case 0x136: scancode = 0x36; break; /* CJK IME sets the extended bit for right Shift */
7350 default: break;
7351 }
7352
7353 win->event.key = (u8)RGFW_apiKeyToRGFW((u32) scancode);
7354
7355 if (msg.wParam == VK_CONTROL) {
7356 if (HIWORD(msg.lParam) & KF_EXTENDED)
7357 win->event.key = RGFW_controlR;
7358 else win->event.key = RGFW_controlL;
7359 }
7360
7361 wchar_t charBuffer;
7362 ToUnicodeEx((UINT)msg.wParam, (UINT)scancode, keyboardState, (wchar_t*)&charBuffer, 1, 0, NULL);
7363
7364 win->event.keyChar = (u8)charBuffer;
7365
7366 RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current;
7367 win->event.type = RGFW_keyReleased;
7368 RGFW_keyboard[win->event.key].current = 0;
7369
7370 RGFW_updateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001), (GetKeyState(VK_SCROLL) & 0x0001));
7371
7372 RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 0);
7373 break;
7374 }
7375 case WM_SYSKEYDOWN: case WM_KEYDOWN: {
7376 i32 scancode = (HIWORD(msg.lParam) & (KF_EXTENDED | 0xff));
7377 if (scancode == 0)
7378 scancode = (i32)MapVirtualKeyW((u32)msg.wParam, MAPVK_VK_TO_VSC);
7379
7380 switch (scancode) {
7381 case 0x54: scancode = 0x137; break; /* Alt+PrtS */
7382 case 0x146: scancode = 0x45; break; /* Ctrl+Pause */
7383 case 0x136: scancode = 0x36; break; /* CJK IME sets the extended bit for right Shift */
7384 default: break;
7385 }
7386
7387 win->event.key = (u8)RGFW_apiKeyToRGFW((u32) scancode);
7388 if (msg.wParam == VK_CONTROL) {
7389 if (HIWORD(msg.lParam) & KF_EXTENDED)
7390 win->event.key = RGFW_controlR;
7391 else win->event.key = RGFW_controlL;
7392 }
7393
7394 wchar_t charBuffer;
7395 ToUnicodeEx((UINT)msg.wParam, (UINT)scancode, keyboardState, &charBuffer, 1, 0, NULL);
7396 win->event.keyChar = (u8)charBuffer;
7397
7398 RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current;
7399
7400 win->event.type = RGFW_keyPressed;
7401 win->event.repeat = RGFW_isPressed(win, win->event.key);
7402 RGFW_keyboard[win->event.key].current = 1;
7403 RGFW_updateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001), (GetKeyState(VK_SCROLL) & 0x0001));
7404
7405 RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 1);
7406 break;
7407 }
7408 case WM_MOUSEMOVE: {
7409 if ((win->_flags & RGFW_HOLD_MOUSE))
7410 break;
7411
7412 win->event.type = RGFW_mousePosChanged;
7413
7414 i32 x = GET_X_LPARAM(msg.lParam);
7415 i32 y = GET_Y_LPARAM(msg.lParam);
7416
7417 RGFW_mousePosCallback(win, win->event.point, win->event.vector);
7418
7419 if (win->_flags & RGFW_MOUSE_LEFT) {
7420 win->_flags &= ~(u32)RGFW_MOUSE_LEFT;
7421 win->event.type = RGFW_mouseEnter;
7422 RGFW_mouseNotifyCallback(win, win->event.point, 1);
7423 }
7424
7425 win->event.point.x = x;
7426 win->event.point.y = y;
7427 win->_lastMousePoint = RGFW_POINT(x, y);
7428
7429 break;
7430 }
7431 case WM_INPUT: {
7432 if (!(win->_flags & RGFW_HOLD_MOUSE))
7433 break;
7434
7435 unsigned size = sizeof(RAWINPUT);
7436 static RAWINPUT raw;
7437
7438 GetRawInputData((HRAWINPUT)msg.lParam, RID_INPUT, &raw, &size, sizeof(RAWINPUTHEADER));
7439
7440 if (raw.header.dwType != RIM_TYPEMOUSE || (raw.data.mouse.lLastX == 0 && raw.data.mouse.lLastY == 0) )
7441 break;
7442
7443 if (raw.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) {
7444 POINT pos = {0, 0};
7445 int width, height;
7446
7447 if (raw.data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP) {
7448 pos.x += GetSystemMetrics(SM_XVIRTUALSCREEN);
7449 pos.y += GetSystemMetrics(SM_YVIRTUALSCREEN);
7450 width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
7451 height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
7452 }
7453 else {
7454 width = GetSystemMetrics(SM_CXSCREEN);
7455 height = GetSystemMetrics(SM_CYSCREEN);
7456 }
7457
7458 pos.x += (int) (((float)raw.data.mouse.lLastX / 65535.f) * (float)width);
7459 pos.y += (int) (((float)raw.data.mouse.lLastY / 65535.f) * (float)height);
7460 ScreenToClient(win->src.window, &pos);
7461
7462 win->event.vector.x = pos.x - win->_lastMousePoint.x;
7463 win->event.vector.y = pos.y - win->_lastMousePoint.y;
7464 } else {
7465 win->event.vector.x = raw.data.mouse.lLastX;
7466 win->event.vector.y = raw.data.mouse.lLastY;
7467 }
7468
7469 win->event.type = RGFW_mousePosChanged;
7470 win->_lastMousePoint.x += win->event.vector.x;
7471 win->_lastMousePoint.y += win->event.vector.y;
7472 win->event.point = win->_lastMousePoint;
7473 RGFW_mousePosCallback(win, win->event.point, win->event.vector);
7474 break;
7475 }
7476 case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: case WM_XBUTTONDOWN:
7477 if (msg.message == WM_XBUTTONDOWN)
7478 win->event.button = RGFW_mouseMisc1 + (GET_XBUTTON_WPARAM(msg.wParam) == XBUTTON2);
7479 else win->event.button = (msg.message == WM_LBUTTONDOWN) ? RGFW_mouseLeft :
7480 (msg.message == WM_RBUTTONDOWN) ? RGFW_mouseRight : RGFW_mouseMiddle;
7481
7482 win->event.type = RGFW_mouseButtonPressed;
7483 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
7484 RGFW_mouseButtons[win->event.button].current = 1;
7485 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
7486 break;
7487 case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MBUTTONUP: case WM_XBUTTONUP:
7488 if (msg.message == WM_XBUTTONUP)
7489 win->event.button = RGFW_mouseMisc1 + (GET_XBUTTON_WPARAM(msg.wParam) == XBUTTON2);
7490 else win->event.button = (msg.message == WM_LBUTTONUP) ? RGFW_mouseLeft :
7491 (msg.message == WM_RBUTTONUP) ? RGFW_mouseRight : RGFW_mouseMiddle;
7492 win->event.type = RGFW_mouseButtonReleased;
7493 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
7494 RGFW_mouseButtons[win->event.button].current = 0;
7495 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0);
7496 break;
7497 case WM_MOUSEWHEEL:
7498 if (msg.wParam > 0)
7499 win->event.button = RGFW_mouseScrollUp;
7500 else
7501 win->event.button = RGFW_mouseScrollDown;
7502
7503 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
7504 RGFW_mouseButtons[win->event.button].current = 1;
7505
7506 win->event.scroll = (SHORT) HIWORD(msg.wParam) / (double) WHEEL_DELTA;
7507
7508 win->event.type = RGFW_mouseButtonPressed;
7509 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
7510 break;
7511 case WM_DROPFILES: {
7512 win->event.type = RGFW_DNDInit;
7513
7514 drop = (HDROP) msg.wParam;
7515 POINT pt;
7516
7517 /* Move the mouse to the position of the drop */
7518 DragQueryPoint(drop, &pt);
7519
7520 win->event.point.x = pt.x;
7521 win->event.point.y = pt.y;
7522
7523 RGFW_dndInitCallback(win, win->event.point);
7524 }
7525 break;
7526 default:
7527 TranslateMessage(&msg);
7528 DispatchMessageA(&msg);
7529 return RGFW_window_checkEvent(win);
7530 }
7531
7532 TranslateMessage(&msg);
7533 DispatchMessageA(&msg);
7534
7535 return &win->event;
7536}
7537
7538RGFW_bool RGFW_window_isHidden(RGFW_window* win) {
7539 RGFW_ASSERT(win != NULL);
7540
7541 return IsWindowVisible(win->src.window) == 0 && !RGFW_window_isMinimized(win);
7542}
7543
7544RGFW_bool RGFW_window_isMinimized(RGFW_window* win) {
7545 RGFW_ASSERT(win != NULL);
7546
7547 #ifndef __cplusplus
7548 WINDOWPLACEMENT placement = { 0 };
7549 #else
7550 WINDOWPLACEMENT placement = { };
7551 #endif
7552 GetWindowPlacement(win->src.window, &placement);
7553 return placement.showCmd == SW_SHOWMINIMIZED;
7554}
7555
7556RGFW_bool RGFW_window_isMaximized(RGFW_window* win) {
7557 RGFW_ASSERT(win != NULL);
7558
7559 #ifndef __cplusplus
7560 WINDOWPLACEMENT placement = { 0 };
7561 #else
7562 WINDOWPLACEMENT placement = { };
7563 #endif
7564 GetWindowPlacement(win->src.window, &placement);
7565 return placement.showCmd == SW_SHOWMAXIMIZED || IsZoomed(win->src.window);
7566}
7567
7568typedef struct { int iIndex; HMONITOR hMonitor; RGFW_monitor* monitors; } RGFW_mInfo;
7569#ifndef RGFW_NO_MONITOR
7570RGFW_monitor win32CreateMonitor(HMONITOR src);
7571RGFW_monitor win32CreateMonitor(HMONITOR src) {
7572 RGFW_monitor monitor;
7573 MONITORINFOEX monitorInfo;
7574
7575 monitorInfo.cbSize = sizeof(MONITORINFOEX);
7576 GetMonitorInfoA(src, (LPMONITORINFO)&monitorInfo);
7577
7578 /* get the monitor's index */
7579 DISPLAY_DEVICEA dd;
7580 dd.cb = sizeof(dd);
7581
7582 DWORD deviceNum;
7583 for (deviceNum = 0; EnumDisplayDevicesA(NULL, deviceNum, &dd, 0); deviceNum++) {
7584 if (!(dd.StateFlags & DISPLAY_DEVICE_ACTIVE))
7585 continue;
7586
7587 DEVMODEA dm;
7588 ZeroMemory(&dm, sizeof(dm));
7589 dm.dmSize = sizeof(dm);
7590
7591 if (EnumDisplaySettingsA(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) {
7592 monitor.mode.refreshRate = dm.dmDisplayFrequency;
7593 RGFW_splitBPP(dm.dmBitsPerPel, &monitor.mode);
7594 }
7595
7596 DISPLAY_DEVICEA mdd;
7597 mdd.cb = sizeof(mdd);
7598
7599 if (EnumDisplayDevicesA(dd.DeviceName, (DWORD)deviceNum, &mdd, 0)) {
7600 RGFW_STRNCPY(monitor.name, mdd.DeviceString, sizeof(monitor.name) - 1);
7601 monitor.name[sizeof(monitor.name) - 1] = '\0';
7602 break;
7603 }
7604 }
7605
7606
7607
7608
7609 monitor.x = monitorInfo.rcWork.left;
7610 monitor.y = monitorInfo.rcWork.top;
7611 monitor.mode.area.w = (u32)(monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left);
7612 monitor.mode.area.h = (u32)(monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top);
7613
7614 HDC hdc = CreateDC(monitorInfo.szDevice, NULL, NULL, NULL);
7615 /* get pixels per inch */
7616 float dpiX = (float)GetDeviceCaps(hdc, LOGPIXELSX);
7617 float dpiY = (float)GetDeviceCaps(hdc, LOGPIXELSX);
7618
7619 monitor.scaleX = dpiX / 96.0f;
7620 monitor.scaleY = dpiY / 96.0f;
7621 monitor.pixelRatio = dpiX >= 192.0f ? 2.0f : 1.0f;
7622
7623 monitor.physW = (float)GetDeviceCaps(hdc, HORZSIZE) / 25.4f;
7624 monitor.physH = (float)GetDeviceCaps(hdc, VERTSIZE) / 25.4f;
7625 DeleteDC(hdc);
7626
7627 #ifndef RGFW_NO_DPI
7628 RGFW_LOAD_LIBRARY(RGFW_Shcore_dll, "shcore.dll");
7629 RGFW_PROC_DEF(RGFW_Shcore_dll, GetDpiForMonitor);
7630
7631 if (GetDpiForMonitor != NULL) {
7632 u32 x, y;
7633 GetDpiForMonitor(src, MDT_EFFECTIVE_DPI, &x, &y);
7634 monitor.scaleX = (float) (x) / (float) 96.0f;
7635 monitor.scaleY = (float) (y) / (float) 96.0f;
7636 monitor.pixelRatio = dpiX >= 192.0f ? 2.0f : 1.0f;
7637 }
7638 #endif
7639
7640 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found");
7641 return monitor;
7642}
7643#endif /* RGFW_NO_MONITOR */
7644
7645#ifndef RGFW_NO_MONITOR
7646BOOL CALLBACK GetMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData);
7647BOOL CALLBACK GetMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
7648 RGFW_UNUSED(hdcMonitor);
7649 RGFW_UNUSED(lprcMonitor);
7650
7651 RGFW_mInfo* info = (RGFW_mInfo*) dwData;
7652
7653
7654 if (info->iIndex >= 6)
7655 return FALSE;
7656
7657 info->monitors[info->iIndex] = win32CreateMonitor(hMonitor);
7658 info->iIndex++;
7659
7660 return TRUE;
7661}
7662
7663RGFW_monitor RGFW_getPrimaryMonitor(void) {
7664 #ifdef __cplusplus
7665 return win32CreateMonitor(MonitorFromPoint({ 0, 0 }, MONITOR_DEFAULTTOPRIMARY));
7666 #else
7667 return win32CreateMonitor(MonitorFromPoint((POINT) { 0, 0 }, MONITOR_DEFAULTTOPRIMARY));
7668 #endif
7669}
7670
7671RGFW_monitor* RGFW_getMonitors(size_t* len) {
7672 static RGFW_monitor monitors[6];
7673 RGFW_mInfo info;
7674 info.iIndex = 0;
7675 info.monitors = monitors;
7676
7677 EnumDisplayMonitors(NULL, NULL, GetMonitorHandle, (LPARAM) &info);
7678
7679 if (len != NULL) *len = (size_t)info.iIndex;
7680 return monitors;
7681}
7682
7683RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) {
7684 HMONITOR src = MonitorFromWindow(win->src.window, MONITOR_DEFAULTTOPRIMARY);
7685 return win32CreateMonitor(src);
7686}
7687
7688RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) {
7689 POINT p = { mon.x, mon.y };
7690 HMONITOR src = MonitorFromPoint(p, MONITOR_DEFAULTTOPRIMARY);
7691
7692 MONITORINFOEX monitorInfo;
7693 monitorInfo.cbSize = sizeof(MONITORINFOEX);
7694 GetMonitorInfoA(src, (LPMONITORINFO)&monitorInfo);
7695
7696 DISPLAY_DEVICEA dd;
7697 dd.cb = sizeof(dd);
7698
7699 /* Enumerate display devices */
7700 DWORD deviceNum;
7701 for (deviceNum = 0; EnumDisplayDevicesA(NULL, deviceNum, &dd, 0); deviceNum++) {
7702 if (!(dd.StateFlags & DISPLAY_DEVICE_ACTIVE))
7703 continue;
7704
7705 if (strcmp(dd.DeviceName, (const char*)monitorInfo.szDevice) != 0)
7706 continue;
7707
7708 DEVMODEA dm;
7709 ZeroMemory(&dm, sizeof(dm));
7710 dm.dmSize = sizeof(dm);
7711
7712 if (EnumDisplaySettingsA(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) {
7713 if (request & RGFW_monitorScale) {
7714 dm.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT;
7715 dm.dmPelsWidth = mode.area.w;
7716 dm.dmPelsHeight = mode.area.h;
7717 }
7718
7719 if (request & RGFW_monitorRefresh) {
7720 dm.dmFields |= DM_DISPLAYFREQUENCY;
7721 dm.dmDisplayFrequency = mode.refreshRate;
7722 }
7723
7724 if (request & RGFW_monitorRGB) {
7725 dm.dmFields |= DM_BITSPERPEL;
7726 dm.dmBitsPerPel = (DWORD)(mode.red + mode.green + mode.blue);
7727 }
7728
7729 if (ChangeDisplaySettingsExA((LPCSTR)dd.DeviceName, (DEVMODE *)&dm, NULL, CDS_TEST, NULL) == DISP_CHANGE_SUCCESSFUL) {
7730 if (ChangeDisplaySettingsExA((LPCSTR)dd.DeviceName, (DEVMODE *)&dm, NULL, CDS_UPDATEREGISTRY, NULL) == DISP_CHANGE_SUCCESSFUL)
7731 return RGFW_TRUE;
7732 return RGFW_FALSE;
7733 } else return RGFW_FALSE;
7734 }
7735 }
7736
7737 return RGFW_FALSE;
7738}
7739
7740#endif
7741HICON RGFW_loadHandleImage(u8* src, i32 c, RGFW_area a, BOOL icon);
7742HICON RGFW_loadHandleImage(u8* src, i32 c, RGFW_area a, BOOL icon) {
7743 size_t channels = (size_t)c;
7744
7745 BITMAPV5HEADER bi;
7746 ZeroMemory(&bi, sizeof(bi));
7747 bi.bV5Size = sizeof(bi);
7748 bi.bV5Width = (i32)a.w;
7749 bi.bV5Height = -((LONG) a.h);
7750 bi.bV5Planes = 1;
7751 bi.bV5BitCount = (WORD)(channels * 8);
7752 bi.bV5Compression = BI_RGB;
7753 HDC dc = GetDC(NULL);
7754 u8* target = NULL;
7755
7756 HBITMAP color = CreateDIBSection(dc,
7757 (BITMAPINFO*) &bi, DIB_RGB_COLORS, (void**) &target,
7758 NULL, (DWORD) 0);
7759
7760 size_t x, y;
7761 for (y = 0; y < a.h; y++) {
7762 for (x = 0; x < a.w; x++) {
7763 size_t index = (y * 4 * (size_t)a.w) + x * channels;
7764 target[index] = src[index + 2];
7765 target[index + 1] = src[index + 1];
7766 target[index + 2] = src[index];
7767 target[index + 3] = src[index + 3];
7768 }
7769 }
7770
7771 ReleaseDC(NULL, dc);
7772
7773 HBITMAP mask = CreateBitmap((i32)a.w, (i32)a.h, 1, 1, NULL);
7774
7775 ICONINFO ii;
7776 ZeroMemory(&ii, sizeof(ii));
7777 ii.fIcon = icon;
7778 ii.xHotspot = a.w / 2;
7779 ii.yHotspot = a.h / 2;
7780 ii.hbmMask = mask;
7781 ii.hbmColor = color;
7782
7783 HICON handle = CreateIconIndirect(&ii);
7784
7785 DeleteObject(color);
7786 DeleteObject(mask);
7787
7788 return handle;
7789}
7790
7791void* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) {
7792 HCURSOR cursor = (HCURSOR) RGFW_loadHandleImage(icon, channels, a, FALSE);
7793 return cursor;
7794}
7795
7796void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) {
7797 RGFW_ASSERT(win && mouse);
7798 SetClassLongPtrA(win->src.window, GCLP_HCURSOR, (LPARAM) mouse);
7799 SetCursor((HCURSOR)mouse);
7800}
7801
7802void RGFW_freeMouse(RGFW_mouse* mouse) {
7803 RGFW_ASSERT(mouse);
7804 DestroyCursor((HCURSOR)mouse);
7805}
7806
7807RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) {
7808 return RGFW_window_setMouseStandard(win, RGFW_mouseArrow);
7809}
7810
7811RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) {
7812 RGFW_ASSERT(win != NULL);
7813
7814 static const u32 mouseIconSrc[16] = {OCR_NORMAL, OCR_NORMAL, OCR_IBEAM, OCR_CROSS, OCR_HAND, OCR_SIZEWE, OCR_SIZENS, OCR_SIZENWSE, OCR_SIZENESW, OCR_SIZEALL, OCR_NO};
7815 if (mouse > (sizeof(mouseIconSrc) / sizeof(u32)))
7816 return RGFW_FALSE;
7817
7818 char* icon = MAKEINTRESOURCEA(mouseIconSrc[mouse]);
7819
7820 SetClassLongPtrA(win->src.window, GCLP_HCURSOR, (LPARAM) LoadCursorA(NULL, icon));
7821 SetCursor(LoadCursorA(NULL, icon));
7822 return RGFW_TRUE;
7823}
7824
7825void RGFW_window_hide(RGFW_window* win) {
7826 ShowWindow(win->src.window, SW_HIDE);
7827}
7828
7829void RGFW_window_show(RGFW_window* win) {
7830 if (win->_flags & RGFW_windowFocusOnShow) RGFW_window_focus(win);
7831 ShowWindow(win->src.window, SW_RESTORE);
7832}
7833
7834#define RGFW_FREE_LIBRARY(x) if (x != NULL) FreeLibrary(x); x = NULL;
7835void RGFW_deinit(void) {
7836 #ifndef RGFW_NO_XINPUT
7837 RGFW_FREE_LIBRARY(RGFW_XInput_dll);
7838 #endif
7839
7840 #ifndef RGFW_NO_DPI
7841 RGFW_FREE_LIBRARY(RGFW_Shcore_dll);
7842 #endif
7843
7844 #ifndef RGFW_NO_WINMM
7845 timeEndPeriod(1);
7846 #ifndef RGFW_NO_LOAD_WINMM
7847 RGFW_FREE_LIBRARY(RGFW_winmm_dll);
7848 #endif
7849 #endif
7850
7851 RGFW_FREE_LIBRARY(RGFW_wgl_dll);
7852 _RGFW.root = NULL;
7853
7854 RGFW_freeMouse(_RGFW.hiddenMouse);
7855 _RGFW.windowCount = -1;
7856 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized");
7857}
7858
7859
7860void RGFW_window_close(RGFW_window* win) {
7861 RGFW_ASSERT(win != NULL);
7862 #ifdef RGFW_BUFFER
7863 DeleteDC(win->src.hdcMem);
7864 DeleteObject(win->src.bitmap);
7865 #endif
7866
7867 if ((win->_flags & RGFW_windowNoInitAPI) == 0) RGFW_window_freeOpenGL(win);
7868 RemovePropW(win->src.window, L"RGFW");
7869 ReleaseDC(win->src.window, win->src.hdc); /*!< delete device context */
7870 DestroyWindow(win->src.window); /*!< delete window */
7871
7872 if (win->src.hIconSmall) DestroyIcon(win->src.hIconSmall);
7873 if (win->src.hIconBig) DestroyIcon(win->src.hIconBig);
7874
7875 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a window was freed");
7876 _RGFW.windowCount--;
7877 if (_RGFW.windowCount == 0) RGFW_deinit();
7878
7879 RGFW_clipboard_switch(NULL);
7880 RGFW_FREE(win->event.droppedFiles);
7881 if ((win->_flags & RGFW_WINDOW_ALLOC)) {
7882 RGFW_FREE(win);
7883 win = NULL;
7884 }
7885}
7886
7887void RGFW_window_move(RGFW_window* win, RGFW_point v) {
7888 RGFW_ASSERT(win != NULL);
7889
7890 win->r.x = v.x;
7891 win->r.y = v.y;
7892 SetWindowPos(win->src.window, HWND_TOP, win->r.x, win->r.y, 0, 0, SWP_NOSIZE);
7893}
7894
7895void RGFW_window_resize(RGFW_window* win, RGFW_area a) {
7896 RGFW_ASSERT(win != NULL);
7897
7898 win->r.w = (i32)a.w;
7899 win->r.h = (i32)a.h;
7900 SetWindowPos(win->src.window, HWND_TOP, 0, 0, win->r.w, win->r.h + (i32)win->src.hOffset, SWP_NOMOVE);
7901}
7902
7903
7904void RGFW_window_setName(RGFW_window* win, const char* name) {
7905 RGFW_ASSERT(win != NULL);
7906
7907 wchar_t wide_name[256];
7908 MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_name, 256);
7909 SetWindowTextW(win->src.window, wide_name);
7910}
7911
7912#ifndef RGFW_NO_PASSTHROUGH
7913void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) {
7914 RGFW_ASSERT(win != NULL);
7915 COLORREF key = 0;
7916 BYTE alpha = 0;
7917 DWORD flags = 0;
7918 i32 exStyle = GetWindowLongW(win->src.window, GWL_EXSTYLE);
7919
7920 if (exStyle & WS_EX_LAYERED)
7921 GetLayeredWindowAttributes(win->src.window, &key, &alpha, &flags);
7922
7923 if (passthrough)
7924 exStyle |= (WS_EX_TRANSPARENT | WS_EX_LAYERED);
7925 else {
7926 exStyle &= ~WS_EX_TRANSPARENT;
7927 if (exStyle & WS_EX_LAYERED && !(flags & LWA_ALPHA))
7928 exStyle &= ~WS_EX_LAYERED;
7929 }
7930
7931 SetWindowLongW(win->src.window, GWL_EXSTYLE, exStyle);
7932
7933 if (passthrough)
7934 SetLayeredWindowAttributes(win->src.window, key, alpha, flags);
7935}
7936#endif
7937
7938RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* src, RGFW_area a, i32 channels, u8 type) {
7939 RGFW_ASSERT(win != NULL);
7940 #ifndef RGFW_WIN95
7941 RGFW_UNUSED(channels);
7942
7943 if (win->src.hIconSmall && (type & RGFW_iconWindow)) DestroyIcon(win->src.hIconSmall);
7944 if (win->src.hIconBig && (type & RGFW_iconTaskbar)) DestroyIcon(win->src.hIconBig);
7945
7946 if (src == NULL) {
7947 HICON defaultIcon = LoadIcon(NULL, IDI_APPLICATION);
7948 if (type & RGFW_iconWindow)
7949 SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)defaultIcon);
7950 if (type & RGFW_iconTaskbar)
7951 SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)defaultIcon);
7952 return RGFW_TRUE;
7953 }
7954
7955 if (type & RGFW_iconWindow) {
7956 win->src.hIconSmall = RGFW_loadHandleImage(src, channels, a, TRUE);
7957 SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)win->src.hIconSmall);
7958 }
7959 if (type & RGFW_iconTaskbar) {
7960 win->src.hIconBig = RGFW_loadHandleImage(src, channels, a, TRUE);
7961 SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)win->src.hIconBig);
7962 }
7963 return RGFW_TRUE;
7964 #else
7965 RGFW_UNUSED(src);
7966 RGFW_UNUSED(a);
7967 RGFW_UNUSED(channels);
7968 return RGFW_FALSE;
7969 #endif
7970}
7971
7972RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) {
7973 /* Open the clipboard */
7974 if (OpenClipboard(NULL) == 0)
7975 return -1;
7976
7977 /* Get the clipboard data as a Unicode string */
7978 HANDLE hData = GetClipboardData(CF_UNICODETEXT);
7979 if (hData == NULL) {
7980 CloseClipboard();
7981 return -1;
7982 }
7983
7984 wchar_t* wstr = (wchar_t*) GlobalLock(hData);
7985
7986 RGFW_ssize_t textLen = 0;
7987
7988 {
7989 setlocale(LC_ALL, "en_US.UTF-8");
7990
7991 textLen = (RGFW_ssize_t)wcstombs(NULL, wstr, 0) + 1;
7992 if (str != NULL && (RGFW_ssize_t)strCapacity <= textLen - 1)
7993 textLen = 0;
7994
7995 if (str != NULL && textLen) {
7996 if (textLen > 1)
7997 wcstombs(str, wstr, (size_t)(textLen));
7998
7999 str[textLen] = '\0';
8000 }
8001 }
8002
8003 /* Release the clipboard data */
8004 GlobalUnlock(hData);
8005 CloseClipboard();
8006
8007 return textLen;
8008}
8009
8010void RGFW_writeClipboard(const char* text, u32 textLen) {
8011 HANDLE object;
8012 WCHAR* buffer;
8013
8014 object = GlobalAlloc(GMEM_MOVEABLE, (1 + textLen) * sizeof(WCHAR));
8015 if (!object)
8016 return;
8017
8018 buffer = (WCHAR*) GlobalLock(object);
8019 if (!buffer) {
8020 GlobalFree(object);
8021 return;
8022 }
8023
8024 MultiByteToWideChar(CP_UTF8, 0, text, -1, buffer, (i32)textLen);
8025 GlobalUnlock(object);
8026
8027 if (!OpenClipboard(_RGFW.root->src.window)) {
8028 GlobalFree(object);
8029 return;
8030 }
8031
8032 EmptyClipboard();
8033 SetClipboardData(CF_UNICODETEXT, object);
8034 CloseClipboard();
8035}
8036
8037void RGFW_window_moveMouse(RGFW_window* win, RGFW_point p) {
8038 RGFW_ASSERT(win != NULL);
8039 win->_lastMousePoint = RGFW_POINT(p.x - win->r.x, p.y - win->r.y);
8040 SetCursorPos(p.x, p.y);
8041}
8042
8043#ifdef RGFW_OPENGL
8044void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
8045 if (win == NULL)
8046 wglMakeCurrent(NULL, NULL);
8047 else
8048 wglMakeCurrent(win->src.hdc, (HGLRC) win->src.ctx);
8049}
8050void* RGFW_getCurrent_OpenGL(void) { return wglGetCurrentContext(); }
8051void RGFW_window_swapBuffers_OpenGL(RGFW_window* win){ SwapBuffers(win->src.hdc); }
8052#endif
8053
8054#ifndef RGFW_EGL
8055void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) {
8056 RGFW_ASSERT(win != NULL);
8057#if defined(RGFW_OPENGL)
8058 if (wglSwapIntervalEXT == NULL || wglSwapIntervalEXT(swapInterval) == FALSE)
8059 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to set swap interval");
8060#else
8061 RGFW_UNUSED(swapInterval);
8062#endif
8063}
8064#endif
8065
8066void RGFW_window_swapBuffers_software(RGFW_window* win) {
8067#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
8068 if (win->buffer != win->src.bitmapBits)
8069 memcpy(win->src.bitmapBits, win->buffer, win->bufferSize.w * win->bufferSize.h * 4);
8070
8071 RGFW_RGB_to_BGR(win, win->src.bitmapBits);
8072 BitBlt(win->src.hdc, 0, 0, win->r.w, win->r.h, win->src.hdcMem, 0, 0, SRCCOPY);
8073#else
8074 RGFW_UNUSED(win);
8075#endif
8076}
8077
8078char* RGFW_createUTF8FromWideStringWin32(const WCHAR* source) {
8079 if (source == NULL) {
8080 return NULL;
8081 }
8082 i32 size = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL);
8083 if (!size) {
8084 return NULL;
8085 }
8086
8087 static char target[RGFW_MAX_PATH * 2];
8088 if (size > RGFW_MAX_PATH * 2)
8089 size = RGFW_MAX_PATH * 2;
8090
8091 target[size] = 0;
8092
8093 if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, size, NULL, NULL)) {
8094 return NULL;
8095 }
8096
8097 return target;
8098}
8099
8100u64 RGFW_getTimerFreq(void) {
8101 static u64 frequency = 0;
8102 if (frequency == 0) QueryPerformanceFrequency((LARGE_INTEGER*)&frequency);
8103
8104 return frequency;
8105}
8106
8107u64 RGFW_getTimerValue(void) {
8108 u64 value;
8109 QueryPerformanceCounter((LARGE_INTEGER*)&value);
8110 return value;
8111}
8112
8113void RGFW_sleep(u64 ms) {
8114 Sleep((u32)ms);
8115}
8116
8117#ifndef RGFW_NO_THREADS
8118
8119RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args) { return CreateThread(NULL, 0, ptr, args, 0, NULL); }
8120void RGFW_cancelThread(RGFW_thread thread) { CloseHandle((HANDLE) thread); }
8121void RGFW_joinThread(RGFW_thread thread) { WaitForSingleObject((HANDLE) thread, INFINITE); }
8122void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { SetThreadPriority((HANDLE) thread, priority); }
8123
8124#endif
8125#endif /* RGFW_WINDOWS */
8126
8127/*
8128 End of Windows defines
8129*/
8130
8131
8132
8133/*
8134
8135 Start of MacOS defines
8136
8137
8138*/
8139
8140#if defined(RGFW_MACOS)
8141/*
8142 based on silicon.h
8143 start of cocoa wrapper
8144*/
8145
8146#include <CoreGraphics/CoreGraphics.h>
8147#include <ApplicationServices/ApplicationServices.h>
8148#include <objc/runtime.h>
8149#include <objc/message.h>
8150#include <mach/mach_time.h>
8151#include <CoreVideo/CoreVideo.h>
8152
8153typedef CGRect NSRect;
8154typedef CGPoint NSPoint;
8155typedef CGSize NSSize;
8156
8157typedef const char* NSPasteboardType;
8158typedef unsigned long NSUInteger;
8159typedef long NSInteger;
8160typedef NSInteger NSModalResponse;
8161
8162#ifdef __arm64__
8163 /* ARM just uses objc_msgSend */
8164#define abi_objc_msgSend_stret objc_msgSend
8165#define abi_objc_msgSend_fpret objc_msgSend
8166#else /* __i386__ */
8167 /* x86 just uses abi_objc_msgSend_fpret and (NSColor *)objc_msgSend_id respectively */
8168#define abi_objc_msgSend_stret objc_msgSend_stret
8169#define abi_objc_msgSend_fpret objc_msgSend_fpret
8170#endif
8171
8172#define NSAlloc(nsclass) objc_msgSend_id((id)nsclass, sel_registerName("alloc"))
8173#define objc_msgSend_bool(x, y) ((BOOL (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
8174#define objc_msgSend_void(x, y) ((void (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
8175#define objc_msgSend_void_id(x, y, z) ((void (*)(id, SEL, id))objc_msgSend) ((id)x, (SEL)y, (id)z)
8176#define objc_msgSend_uint(x, y) ((NSUInteger (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
8177#define objc_msgSend_void_bool(x, y, z) ((void (*)(id, SEL, BOOL))objc_msgSend) ((id)(x), (SEL)y, (BOOL)z)
8178#define objc_msgSend_bool_void(x, y) ((BOOL (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
8179#define objc_msgSend_void_SEL(x, y, z) ((void (*)(id, SEL, SEL))objc_msgSend) ((id)(x), (SEL)y, (SEL)z)
8180#define objc_msgSend_id(x, y) ((id (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
8181#define objc_msgSend_id_id(x, y, z) ((id (*)(id, SEL, id))objc_msgSend) ((id)(x), (SEL)y, (id)z)
8182#define objc_msgSend_id_bool(x, y, z) ((BOOL (*)(id, SEL, id))objc_msgSend) ((id)(x), (SEL)y, (id)z)
8183#define objc_msgSend_int(x, y, z) ((id (*)(id, SEL, int))objc_msgSend) ((id)(x), (SEL)y, (int)z)
8184#define objc_msgSend_arr(x, y, z) ((id (*)(id, SEL, int))objc_msgSend) ((id)(x), (SEL)y, (int)z)
8185#define objc_msgSend_ptr(x, y, z) ((id (*)(id, SEL, void*))objc_msgSend) ((id)(x), (SEL)y, (void*)z)
8186#define objc_msgSend_class(x, y) ((id (*)(Class, SEL))objc_msgSend) ((Class)(x), (SEL)y)
8187#define objc_msgSend_class_char(x, y, z) ((id (*)(Class, SEL, char*))objc_msgSend) ((Class)(x), (SEL)y, (char*)z)
8188
8189id NSApp = NULL;
8190
8191#define NSRelease(obj) objc_msgSend_void((id)obj, sel_registerName("release"))
8192id NSString_stringWithUTF8String(const char* str);
8193id NSString_stringWithUTF8String(const char* str) {
8194 return ((id(*)(id, SEL, const char*))objc_msgSend)
8195 ((id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), str);
8196}
8197
8198const char* NSString_to_char(id str);
8199const char* NSString_to_char(id str) {
8200 return ((const char* (*)(id, SEL)) objc_msgSend) ((id)(id)str, sel_registerName("UTF8String"));
8201}
8202
8203void si_impl_func_to_SEL_with_name(const char* class_name, const char* register_name, void* function);
8204void si_impl_func_to_SEL_with_name(const char* class_name, const char* register_name, void* function) {
8205 Class selected_class;
8206
8207 if (RGFW_STRNCMP(class_name, "NSView", 6) == 0) {
8208 selected_class = objc_getClass("ViewClass");
8209 } else if (RGFW_STRNCMP(class_name, "NSWindow", 8) == 0) {
8210 selected_class = objc_getClass("WindowClass");
8211 } else {
8212 selected_class = objc_getClass(class_name);
8213 }
8214
8215 class_addMethod(selected_class, sel_registerName(register_name), (IMP) function, 0);
8216}
8217
8218/* Header for the array. */
8219typedef struct siArrayHeader {
8220 size_t count;
8221 /* TODO(EimaMei): Add a `type_width` later on. */
8222} siArrayHeader;
8223
8224/* Gets the header of the siArray. */
8225#define SI_ARRAY_HEADER(s) ((siArrayHeader*)s - 1)
8226#define si_array_len(array) (SI_ARRAY_HEADER(array)->count)
8227#define si_func_to_SEL(class_name, function) si_impl_func_to_SEL_with_name(class_name, #function":", (void*)function)
8228/* Creates an Objective-C method (SEL) from a regular C function with the option to set the register name.*/
8229#define si_func_to_SEL_with_name(class_name, register_name, function) si_impl_func_to_SEL_with_name(class_name, register_name":", (void*)function)
8230
8231unsigned char* NSBitmapImageRep_bitmapData(id imageRep);
8232unsigned char* NSBitmapImageRep_bitmapData(id imageRep) {
8233 return ((unsigned char* (*)(id, SEL))objc_msgSend) ((id)imageRep, sel_registerName("bitmapData"));
8234}
8235
8236typedef RGFW_ENUM(NSUInteger, NSBitmapFormat) {
8237 NSBitmapFormatAlphaFirst = 1 << 0, /* 0 means is alpha last (RGBA, CMYKA, etc.) */
8238 NSBitmapFormatAlphaNonpremultiplied = 1 << 1, /* 0 means is premultiplied */
8239 NSBitmapFormatFloatingpointSamples = 1 << 2, /* 0 is integer */
8240
8241 NSBitmapFormatSixteenBitLittleEndian = (1 << 8),
8242 NSBitmapFormatThirtyTwoBitLittleEndian = (1 << 9),
8243 NSBitmapFormatSixteenBitBigEndian = (1 << 10),
8244 NSBitmapFormatThirtyTwoBitBigEndian = (1 << 11)
8245};
8246
8247id NSBitmapImageRep_initWithBitmapData(unsigned char** planes, NSInteger width, NSInteger height, NSInteger bps, NSInteger spp, bool alpha, bool isPlanar, const char* colorSpaceName, NSBitmapFormat bitmapFormat, NSInteger rowBytes, NSInteger pixelBits);
8248id NSBitmapImageRep_initWithBitmapData(unsigned char** planes, NSInteger width, NSInteger height, NSInteger bps, NSInteger spp, bool alpha, bool isPlanar, const char* colorSpaceName, NSBitmapFormat bitmapFormat, NSInteger rowBytes, NSInteger pixelBits) {
8249 SEL func = sel_registerName("initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bitmapFormat:bytesPerRow:bitsPerPixel:");
8250
8251 return (id) ((id(*)(id, SEL, unsigned char**, NSInteger, NSInteger, NSInteger, NSInteger, bool, bool, id, NSBitmapFormat, NSInteger, NSInteger))objc_msgSend)
8252 (NSAlloc((id)objc_getClass("NSBitmapImageRep")), func, planes, width, height, bps, spp, alpha, isPlanar, NSString_stringWithUTF8String(colorSpaceName), bitmapFormat, rowBytes, pixelBits);
8253}
8254
8255id NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha);
8256id NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha) {
8257 void* nsclass = objc_getClass("NSColor");
8258 SEL func = sel_registerName("colorWithSRGBRed:green:blue:alpha:");
8259 return ((id(*)(id, SEL, CGFloat, CGFloat, CGFloat, CGFloat))objc_msgSend)
8260 ((id)nsclass, func, red, green, blue, alpha);
8261}
8262
8263typedef RGFW_ENUM(NSInteger, NSOpenGLContextParameter) {
8264 NSOpenGLContextParameterSwapInterval = 222, /* 1 param. 0 -> Don't sync, 1 -> Sync to vertical retrace */
8265 NSOpenGLContextParametectxaceOrder = 235, /* 1 param. 1 -> Above Window (default), -1 -> Below Window */
8266 NSOpenGLContextParametectxaceOpacity = 236, /* 1 param. 1-> Surface is opaque (default), 0 -> non-opaque */
8267 NSOpenGLContextParametectxaceBackingSize = 304, /* 2 params. Width/height of surface backing size */
8268 NSOpenGLContextParameterReclaimResources = 308, /* 0 params. */
8269 NSOpenGLContextParameterCurrentRendererID = 309, /* 1 param. Retrieves the current renderer ID */
8270 NSOpenGLContextParameterGPUVertexProcessing = 310, /* 1 param. Currently processing vertices with GPU (get) */
8271 NSOpenGLContextParameterGPUFragmentProcessing = 311, /* 1 param. Currently processing fragments with GPU (get) */
8272 NSOpenGLContextParameterHasDrawable = 314, /* 1 param. Boolean returned if drawable is attached */
8273 NSOpenGLContextParameterMPSwapsInFlight = 315, /* 1 param. Max number of swaps queued by the MP GL engine */
8274
8275 NSOpenGLContextParameterSwapRectangle API_DEPRECATED("", macos(10.0, 10.14)) = 200, /* 4 params. Set or get the swap rectangle {x, y, w, h} */
8276 NSOpenGLContextParameterSwapRectangleEnable API_DEPRECATED("", macos(10.0, 10.14)) = 201, /* Enable or disable the swap rectangle */
8277 NSOpenGLContextParameterRasterizationEnable API_DEPRECATED("", macos(10.0, 10.14)) = 221, /* Enable or disable all rasterization */
8278 NSOpenGLContextParameterStateValidation API_DEPRECATED("", macos(10.0, 10.14)) = 301, /* Validate state for multi-screen functionality */
8279 NSOpenGLContextParametectxaceSurfaceVolatile API_DEPRECATED("", macos(10.0, 10.14)) = 306, /* 1 param. Surface volatile state */
8280};
8281
8282typedef RGFW_ENUM(NSInteger, NSWindowButton) {
8283 NSWindowCloseButton = 0,
8284 NSWindowMiniaturizeButton = 1,
8285 NSWindowZoomButton = 2,
8286 NSWindowToolbarButton = 3,
8287 NSWindowDocumentIconButton = 4,
8288 NSWindowDocumentVersionsButton = 6,
8289 NSWindowFullScreenButton = 7,
8290};
8291void NSOpenGLContext_setValues(id context, const int* vals, NSOpenGLContextParameter param);
8292void NSOpenGLContext_setValues(id context, const int* vals, NSOpenGLContextParameter param) {
8293 ((void (*)(id, SEL, const int*, NSOpenGLContextParameter))objc_msgSend)
8294 (context, sel_registerName("setValues:forParameter:"), vals, param);
8295}
8296void* NSOpenGLPixelFormat_initWithAttributes(const uint32_t* attribs);
8297void* NSOpenGLPixelFormat_initWithAttributes(const uint32_t* attribs) {
8298 return (void*) ((id(*)(id, SEL, const uint32_t*))objc_msgSend)
8299 (NSAlloc((id)objc_getClass("NSOpenGLPixelFormat")), sel_registerName("initWithAttributes:"), attribs);
8300}
8301
8302id NSPasteboard_generalPasteboard(void);
8303id NSPasteboard_generalPasteboard(void) {
8304 return (id) objc_msgSend_id((id)objc_getClass("NSPasteboard"), sel_registerName("generalPasteboard"));
8305}
8306
8307id* cstrToNSStringArray(char** strs, size_t len);
8308id* cstrToNSStringArray(char** strs, size_t len) {
8309 static id nstrs[6];
8310 size_t i;
8311 for (i = 0; i < len; i++)
8312 nstrs[i] = NSString_stringWithUTF8String(strs[i]);
8313
8314 return nstrs;
8315}
8316
8317const char* NSPasteboard_stringForType(id pasteboard, NSPasteboardType dataType, size_t* len);
8318const char* NSPasteboard_stringForType(id pasteboard, NSPasteboardType dataType, size_t* len) {
8319 SEL func = sel_registerName("stringForType:");
8320 id nsstr = NSString_stringWithUTF8String(dataType);
8321 id nsString = ((id(*)(id, SEL, id))objc_msgSend)(pasteboard, func, nsstr);
8322 const char* str = NSString_to_char(nsString);
8323 if (len != NULL)
8324 *len = (size_t)((NSUInteger(*)(id, SEL, int))objc_msgSend)(nsString, sel_registerName("maximumLengthOfBytesUsingEncoding:"), 4);
8325 return str;
8326}
8327
8328id c_array_to_NSArray(void* array, size_t len);
8329id c_array_to_NSArray(void* array, size_t len) {
8330 SEL func = sel_registerName("initWithObjects:count:");
8331 void* nsclass = objc_getClass("NSArray");
8332 return ((id (*)(id, SEL, void*, NSUInteger))objc_msgSend)
8333 (NSAlloc(nsclass), func, array, len);
8334}
8335
8336
8337void NSregisterForDraggedTypes(id view, NSPasteboardType* newTypes, size_t len);
8338void NSregisterForDraggedTypes(id view, NSPasteboardType* newTypes, size_t len) {
8339 id* ntypes = cstrToNSStringArray((char**)newTypes, len);
8340
8341 id array = c_array_to_NSArray(ntypes, len);
8342 objc_msgSend_void_id(view, sel_registerName("registerForDraggedTypes:"), array);
8343 NSRelease(array);
8344}
8345
8346NSInteger NSPasteBoard_declareTypes(id pasteboard, NSPasteboardType* newTypes, size_t len, void* owner);
8347NSInteger NSPasteBoard_declareTypes(id pasteboard, NSPasteboardType* newTypes, size_t len, void* owner) {
8348 id* ntypes = cstrToNSStringArray((char**)newTypes, len);
8349
8350 SEL func = sel_registerName("declareTypes:owner:");
8351
8352 id array = c_array_to_NSArray(ntypes, len);
8353
8354 NSInteger output = ((NSInteger(*)(id, SEL, id, void*))objc_msgSend)
8355 (pasteboard, func, array, owner);
8356 NSRelease(array);
8357
8358 return output;
8359}
8360
8361#define NSRetain(obj) objc_msgSend_void((id)obj, sel_registerName("retain"))
8362
8363typedef enum NSApplicationActivationPolicy {
8364 NSApplicationActivationPolicyRegular,
8365 NSApplicationActivationPolicyAccessory,
8366 NSApplicationActivationPolicyProhibited
8367} NSApplicationActivationPolicy;
8368
8369typedef RGFW_ENUM(u32, NSBackingStoreType) {
8370 NSBackingStoreRetained = 0,
8371 NSBackingStoreNonretained = 1,
8372 NSBackingStoreBuffered = 2
8373};
8374
8375typedef RGFW_ENUM(u32, NSWindowStyleMask) {
8376 NSWindowStyleMaskBorderless = 0,
8377 NSWindowStyleMaskTitled = 1 << 0,
8378 NSWindowStyleMaskClosable = 1 << 1,
8379 NSWindowStyleMaskMiniaturizable = 1 << 2,
8380 NSWindowStyleMaskResizable = 1 << 3,
8381 NSWindowStyleMaskTexturedBackground = 1 << 8, /* deprecated */
8382 NSWindowStyleMaskUnifiedTitleAndToolbar = 1 << 12,
8383 NSWindowStyleMaskFullScreen = 1 << 14,
8384 NSWindowStyleMaskFullSizeContentView = 1 << 15,
8385 NSWindowStyleMaskUtilityWindow = 1 << 4,
8386 NSWindowStyleMaskDocModalWindow = 1 << 6,
8387 NSWindowStyleMaskNonactivatingpanel = 1 << 7,
8388 NSWindowStyleMaskHUDWindow = 1 << 13
8389};
8390
8391NSPasteboardType const NSPasteboardTypeString = "public.utf8-plain-text"; /* Replaces NSStringPasteboardType */
8392
8393
8394typedef RGFW_ENUM(i32, NSDragOperation) {
8395 NSDragOperationNone = 0,
8396 NSDragOperationCopy = 1,
8397 NSDragOperationLink = 2,
8398 NSDragOperationGeneric = 4,
8399 NSDragOperationPrivate = 8,
8400 NSDragOperationMove = 16,
8401 NSDragOperationDelete = 32,
8402 NSDragOperationEvery = (int)ULONG_MAX
8403};
8404
8405void* NSArray_objectAtIndex(id array, NSUInteger index) {
8406 SEL func = sel_registerName("objectAtIndex:");
8407 return ((id(*)(id, SEL, NSUInteger))objc_msgSend)(array, func, index);
8408}
8409
8410id NSWindow_contentView(id window) {
8411 SEL func = sel_registerName("contentView");
8412 return objc_msgSend_id(window, func);
8413}
8414
8415/*
8416 End of cocoa wrapper
8417*/
8418
8419#ifdef RGFW_OPENGL
8420/* MacOS opengl API spares us yet again (there are no extensions) */
8421RGFW_bool RGFW_extensionSupportedPlatform(const char * extension, size_t len) { RGFW_UNUSED(extension); RGFW_UNUSED(len); return RGFW_FALSE; }
8422CFBundleRef RGFWnsglFramework = NULL;
8423
8424RGFW_proc RGFW_getProcAddress(const char* procname) {
8425 if (RGFWnsglFramework == NULL)
8426 RGFWnsglFramework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
8427
8428 CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault, procname, kCFStringEncodingASCII);
8429
8430 RGFW_proc symbol = (RGFW_proc)CFBundleGetFunctionPointerForName(RGFWnsglFramework, symbolName);
8431
8432 CFRelease(symbolName);
8433
8434 return symbol;
8435}
8436#endif
8437
8438id NSWindow_delegate(RGFW_window* win) {
8439 return (id) objc_msgSend_id((id)win->src.window, sel_registerName("delegate"));
8440}
8441
8442u32 RGFW_OnClose(id self) {
8443 RGFW_window* win = NULL;
8444 object_getInstanceVariable(self, (const char*)"RGFW_window", (void**)&win);
8445 if (win == NULL)
8446 return true;
8447
8448 RGFW_eventQueuePushEx(e.type = RGFW_quit; e._win = win);
8449 RGFW_windowQuitCallback(win);
8450
8451 return false;
8452}
8453
8454/* NOTE(EimaMei): Fixes the constant clicking when the app is running under a terminal. */
8455bool acceptsFirstResponder(void) { return true; }
8456bool performKeyEquivalent(id event) { RGFW_UNUSED(event); return true; }
8457
8458NSDragOperation draggingEntered(id self, SEL sel, id sender) {
8459 RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel);
8460
8461 return NSDragOperationCopy;
8462}
8463NSDragOperation draggingUpdated(id self, SEL sel, id sender) {
8464 RGFW_UNUSED(sel);
8465
8466 RGFW_window* win = NULL;
8467 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
8468 if (win == NULL || (!(win->_flags & RGFW_windowAllowDND)))
8469 return 0;
8470
8471 NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation"));
8472 RGFW_eventQueuePushEx(e.type = RGFW_DNDInit;
8473 e.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y));
8474 e._win = win);
8475
8476 RGFW_dndInitCallback(win, win->event.point);
8477 return NSDragOperationCopy;
8478}
8479bool prepareForDragOperation(id self) {
8480 RGFW_window* win = NULL;
8481 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
8482 if (win == NULL)
8483 return true;
8484
8485 if (!(win->_flags & RGFW_windowAllowDND)) {
8486 return false;
8487 }
8488
8489 return true;
8490}
8491
8492void RGFW__osxDraggingEnded(id self, SEL sel, id sender);
8493void RGFW__osxDraggingEnded(id self, SEL sel, id sender) { RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel); return; }
8494
8495/* NOTE(EimaMei): Usually, you never need 'id self, SEL cmd' for C -> Obj-C methods. This isn't the case. */
8496bool performDragOperation(id self, SEL sel, id sender) {
8497 RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel);
8498
8499 RGFW_window* win = NULL;
8500 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
8501
8502 if (win == NULL)
8503 return false;
8504
8505 /* id pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard")); */
8506
8507 id pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard"));
8508
8509 /* Get the types of data available on the pasteboard */
8510 id types = objc_msgSend_id(pasteBoard, sel_registerName("types"));
8511
8512 /* Get the string type for file URLs */
8513 id fileURLsType = objc_msgSend_class_char(objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "NSFilenamesPboardType");
8514
8515 /* Check if the pasteboard contains file URLs */
8516 if (objc_msgSend_id_bool(types, sel_registerName("containsObject:"), fileURLsType) == 0) {
8517 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errClipboard, RGFW_DEBUG_CTX(win, 0), "No files found on the pasteboard.");
8518 return 0;
8519 }
8520
8521 id fileURLs = objc_msgSend_id_id(pasteBoard, sel_registerName("propertyListForType:"), fileURLsType);
8522 int count = ((int (*)(id, SEL))objc_msgSend)(fileURLs, sel_registerName("count"));
8523
8524 if (count == 0)
8525 return 0;
8526
8527 int i;
8528 for (i = 0; i < count; i++) {
8529 id fileURL = objc_msgSend_arr(fileURLs, sel_registerName("objectAtIndex:"), i);
8530 const char *filePath = ((const char* (*)(id, SEL))objc_msgSend)(fileURL, sel_registerName("UTF8String"));
8531 RGFW_STRNCPY(win->event.droppedFiles[i], filePath, RGFW_MAX_PATH - 1);
8532 win->event.droppedFiles[i][RGFW_MAX_PATH - 1] = '\0';
8533 }
8534 NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation"));
8535
8536 win->event.droppedFilesCount = (size_t)count;
8537 RGFW_eventQueuePushEx(e.type = RGFW_DND;
8538 e.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y));
8539 e.droppedFilesCount = (size_t)count;
8540 e._win = win);
8541
8542 RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount);
8543
8544 return false;
8545}
8546
8547#ifndef RGFW_NO_IOKIT
8548#include <IOKit/IOKitLib.h>
8549#include <IOKit/hid/IOHIDManager.h>
8550
8551u32 RGFW_osx_getFallbackRefreshRate(CGDirectDisplayID displayID) {
8552 u32 refreshRate = 0;
8553 io_iterator_t it;
8554 io_service_t service;
8555 CFNumberRef indexRef, clockRef, countRef;
8556 uint32_t clock, count;
8557
8558#ifdef kIOMainPortDefault
8559 if (IOServiceGetMatchingServices(kIOMainPortDefault, IOServiceMatching("IOFramebuffer"), &it) != 0)
8560#elif defined(kIOMasterPortDefault)
8561 if (IOServiceGetMatchingServices(kIOMainPortDefault, IOServiceMatching("IOFramebuffer"), &it) != 0)
8562#endif
8563 return RGFW_FALSE;
8564
8565 while ((service = IOIteratorNext(it)) != 0) {
8566 uint32_t index;
8567 indexRef = (CFNumberRef)IORegistryEntryCreateCFProperty(service, CFSTR("IOFramebufferOpenGLIndex"), kCFAllocatorDefault, kNilOptions);
8568 if (indexRef == 0) continue;
8569
8570 if (CFNumberGetValue(indexRef, kCFNumberIntType, &index) && CGOpenGLDisplayMaskToDisplayID(1 << index) == displayID) {
8571 CFRelease(indexRef);
8572 break;
8573 }
8574
8575 CFRelease(indexRef);
8576 }
8577
8578 if (service) {
8579 clockRef = (CFNumberRef)IORegistryEntryCreateCFProperty(service, CFSTR("IOFBCurrentPixelClock"), kCFAllocatorDefault, kNilOptions);
8580 if (clockRef) {
8581 if (CFNumberGetValue(clockRef, kCFNumberIntType, &clock) && clock) {
8582 countRef = (CFNumberRef)IORegistryEntryCreateCFProperty(service, CFSTR("IOFBCurrentPixelCount"), kCFAllocatorDefault, kNilOptions);
8583 if (countRef && CFNumberGetValue(countRef, kCFNumberIntType, &count) && count) {
8584 refreshRate = (u32)RGFW_ROUND(clock / (double) count);
8585 CFRelease(countRef);
8586 }
8587 }
8588 CFRelease(clockRef);
8589 }
8590 }
8591
8592 IOObjectRelease(it);
8593 return refreshRate;
8594}
8595
8596IOHIDDeviceRef RGFW_osxControllers[4] = {NULL};
8597
8598size_t findControllerIndex(IOHIDDeviceRef device) {
8599 size_t i;
8600 for (i = 0; i < 4; i++)
8601 if (RGFW_osxControllers[i] == device)
8602 return i;
8603 return (size_t)-1;
8604}
8605
8606void RGFW__osxInputValueChangedCallback(void *context, IOReturn result, void *sender, IOHIDValueRef value) {
8607 RGFW_UNUSED(context); RGFW_UNUSED(result); RGFW_UNUSED(sender);
8608 IOHIDElementRef element = IOHIDValueGetElement(value);
8609
8610 IOHIDDeviceRef device = IOHIDElementGetDevice(element);
8611 size_t index = findControllerIndex(device);
8612 if (index == (size_t)-1) return;
8613
8614 uint32_t usagePage = IOHIDElementGetUsagePage(element);
8615 uint32_t usage = IOHIDElementGetUsage(element);
8616
8617 CFIndex intValue = IOHIDValueGetIntegerValue(value);
8618
8619 u8 RGFW_osx2RGFWSrc[2][RGFW_gamepadFinal] = {{
8620 0, RGFW_gamepadSelect, RGFW_gamepadL3, RGFW_gamepadR3, RGFW_gamepadStart,
8621 RGFW_gamepadUp, RGFW_gamepadRight, RGFW_gamepadDown, RGFW_gamepadLeft,
8622 RGFW_gamepadL2, RGFW_gamepadR2, RGFW_gamepadL1, RGFW_gamepadR1,
8623 RGFW_gamepadY, RGFW_gamepadB, RGFW_gamepadA, RGFW_gamepadX, RGFW_gamepadHome},
8624 {0, RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadR3, RGFW_gamepadX,
8625 RGFW_gamepadY, RGFW_gamepadRight, RGFW_gamepadL1, RGFW_gamepadR1,
8626 RGFW_gamepadL2, RGFW_gamepadR2, RGFW_gamepadDown, RGFW_gamepadStart,
8627 RGFW_gamepadUp, RGFW_gamepadL3, RGFW_gamepadSelect, RGFW_gamepadStart, RGFW_gamepadHome}
8628 };
8629
8630 u8* RGFW_osx2RGFW = RGFW_osx2RGFWSrc[0];
8631 if (RGFW_gamepads_type[index] == RGFW_gamepadMicrosoft)
8632 RGFW_osx2RGFW = RGFW_osx2RGFWSrc[1];
8633
8634 switch (usagePage) {
8635 case kHIDPage_Button: {
8636 u8 button = 0;
8637 if (usage < sizeof(RGFW_osx2RGFW))
8638 button = RGFW_osx2RGFW[usage];
8639
8640 RGFW_gamepadButtonCallback(_RGFW.root, (u16)index, button, (u8)intValue);
8641 RGFW_gamepadPressed[index][button].prev = RGFW_gamepadPressed[index][button].current;
8642 RGFW_gamepadPressed[index][button].current = RGFW_BOOL(intValue);
8643 RGFW_eventQueuePushEx(e.type = intValue ? RGFW_gamepadButtonPressed: RGFW_gamepadButtonReleased;
8644 e.button = button;
8645 e.gamepad = (u16)index;
8646 e._win = _RGFW.root);
8647 break;
8648 }
8649 case kHIDPage_GenericDesktop: {
8650 CFIndex logicalMin = IOHIDElementGetLogicalMin(element);
8651 CFIndex logicalMax = IOHIDElementGetLogicalMax(element);
8652
8653 if (logicalMax <= logicalMin) return;
8654 if (intValue < logicalMin) intValue = logicalMin;
8655 if (intValue > logicalMax) intValue = logicalMax;
8656
8657 i8 axisValue = (i8)(-100.0 + ((intValue - logicalMin) * 200.0) / (logicalMax - logicalMin));
8658
8659 u8 whichAxis = 0;
8660 switch (usage) {
8661 case kHIDUsage_GD_X: RGFW_gamepadAxes[index][0].x = axisValue; whichAxis = 0; break;
8662 case kHIDUsage_GD_Y: RGFW_gamepadAxes[index][0].y = axisValue; whichAxis = 0; break;
8663 case kHIDUsage_GD_Z: RGFW_gamepadAxes[index][1].x = axisValue; whichAxis = 1; break;
8664 case kHIDUsage_GD_Rz: RGFW_gamepadAxes[index][1].y = axisValue; whichAxis = 1; break;
8665 default: return;
8666 }
8667
8668 RGFW_event e;
8669 e.type = RGFW_gamepadAxisMove;
8670 e.gamepad = (u16)index;
8671 e.whichAxis = whichAxis;
8672 e._win = _RGFW.root;
8673 for (size_t i = 0; i < 4; i++)
8674 e.axis[i] = RGFW_gamepadAxes[index][i];
8675
8676 RGFW_eventQueuePush(e);
8677
8678 RGFW_gamepadAxisCallback(_RGFW.root, (u16)index, RGFW_gamepadAxes[index], 2, whichAxis);
8679 }
8680 }
8681}
8682
8683void RGFW__osxDeviceAddedCallback(void* context, IOReturn result, void *sender, IOHIDDeviceRef device) {
8684 RGFW_UNUSED(context); RGFW_UNUSED(result); RGFW_UNUSED(sender);
8685 CFTypeRef usageRef = (CFTypeRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDPrimaryUsageKey));
8686 int usage = 0;
8687 if (usageRef)
8688 CFNumberGetValue((CFNumberRef)usageRef, kCFNumberIntType, (void*)&usage);
8689
8690 if (usage != kHIDUsage_GD_Joystick && usage != kHIDUsage_GD_GamePad && usage != kHIDUsage_GD_MultiAxisController) {
8691 return;
8692 }
8693
8694 size_t i;
8695 for (i = 0; i < 4; i++) {
8696 if (RGFW_osxControllers[i] != NULL)
8697 continue;
8698
8699 RGFW_osxControllers[i] = device;
8700
8701 IOHIDDeviceRegisterInputValueCallback(device, RGFW__osxInputValueChangedCallback, NULL);
8702
8703 CFStringRef deviceName = (CFStringRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
8704 if (deviceName)
8705 CFStringGetCString(deviceName, RGFW_gamepads_name[i], sizeof(RGFW_gamepads_name[i]), kCFStringEncodingUTF8);
8706
8707 RGFW_gamepads_type[i] = RGFW_gamepadUnknown;
8708 if (RGFW_STRSTR(RGFW_gamepads_name[i], "Microsoft") || RGFW_STRSTR(RGFW_gamepads_name[i], "X-Box") || RGFW_STRSTR(RGFW_gamepads_name[i], "Xbox"))
8709 RGFW_gamepads_type[i] = RGFW_gamepadMicrosoft;
8710 else if (RGFW_STRSTR(RGFW_gamepads_name[i], "PlayStation") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS3") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS4") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS5"))
8711 RGFW_gamepads_type[i] = RGFW_gamepadSony;
8712 else if (RGFW_STRSTR(RGFW_gamepads_name[i], "Nintendo"))
8713 RGFW_gamepads_type[i] = RGFW_gamepadNintendo;
8714 else if (RGFW_STRSTR(RGFW_gamepads_name[i], "Logitech"))
8715 RGFW_gamepads_type[i] = RGFW_gamepadLogitech;
8716
8717 RGFW_gamepads[i] = (u16)i;
8718 RGFW_gamepadCount++;
8719
8720 RGFW_eventQueuePushEx(e.type = RGFW_gamepadConnected;
8721 e.gamepad = (u16)i;
8722 e._win = _RGFW.root);
8723
8724 RGFW_gamepadCallback(_RGFW.root, (u16)i, 1);
8725 break;
8726 }
8727}
8728
8729void RGFW__osxDeviceRemovedCallback(void *context, IOReturn result, void *sender, IOHIDDeviceRef device) {
8730 RGFW_UNUSED(context); RGFW_UNUSED(result); RGFW_UNUSED(sender); RGFW_UNUSED(device);
8731 CFNumberRef usageRef = (CFNumberRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDPrimaryUsageKey));
8732 int usage = 0;
8733 if (usageRef)
8734 CFNumberGetValue(usageRef, kCFNumberIntType, &usage);
8735
8736 if (usage != kHIDUsage_GD_Joystick && usage != kHIDUsage_GD_GamePad && usage != kHIDUsage_GD_MultiAxisController) {
8737 return;
8738 }
8739
8740 size_t index = findControllerIndex(device);
8741 if (index != (size_t)-1)
8742 RGFW_osxControllers[index] = NULL;
8743
8744 RGFW_eventQueuePushEx(e.type = RGFW_gamepadDisconnected;
8745 e.gamepad = (u16)index;
8746 e._win = _RGFW.root);
8747 RGFW_gamepadCallback(_RGFW.root, (u16)index, 0);
8748
8749 RGFW_gamepadCount--;
8750}
8751
8752RGFWDEF void RGFW_osxInitIOKit(void);
8753void RGFW_osxInitIOKit(void) {
8754 IOHIDManagerRef hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
8755 if (!hidManager) {
8756 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errIOKit, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to create IOHIDManager.");
8757 return;
8758 }
8759
8760 CFMutableDictionaryRef matchingDictionary = CFDictionaryCreateMutable(
8761 kCFAllocatorDefault,
8762 0,
8763 &kCFTypeDictionaryKeyCallBacks,
8764 &kCFTypeDictionaryValueCallBacks
8765 );
8766 if (!matchingDictionary) {
8767 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errIOKit, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to create matching dictionary for IOKit.");
8768 CFRelease(hidManager);
8769 return;
8770 }
8771
8772 CFDictionarySetValue(
8773 matchingDictionary,
8774 CFSTR(kIOHIDDeviceUsagePageKey),
8775 CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, (int[]){kHIDPage_GenericDesktop})
8776 );
8777
8778 IOHIDManagerSetDeviceMatching(hidManager, matchingDictionary);
8779
8780 IOHIDManagerRegisterDeviceMatchingCallback(hidManager, RGFW__osxDeviceAddedCallback, NULL);
8781 IOHIDManagerRegisterDeviceRemovalCallback(hidManager, RGFW__osxDeviceRemovedCallback, NULL);
8782
8783 IOHIDManagerScheduleWithRunLoop(hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
8784
8785 IOHIDManagerOpen(hidManager, kIOHIDOptionsTypeNone);
8786
8787 /* Execute the run loop once in order to register any initially-attached joysticks */
8788 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false);
8789}
8790#endif
8791
8792void RGFW_moveToMacOSResourceDir(void) {
8793 char resourcesPath[256];
8794
8795 CFBundleRef bundle = CFBundleGetMainBundle();
8796 if (!bundle)
8797 return;
8798
8799 CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle);
8800 CFStringRef last = CFURLCopyLastPathComponent(resourcesURL);
8801
8802 if (
8803 CFStringCompare(CFSTR("Resources"), last, 0) != kCFCompareEqualTo ||
8804 CFURLGetFileSystemRepresentation(resourcesURL, true, (u8*) resourcesPath, 255) == 0
8805 ) {
8806 CFRelease(last);
8807 CFRelease(resourcesURL);
8808 return;
8809 }
8810
8811 CFRelease(last);
8812 CFRelease(resourcesURL);
8813
8814 chdir(resourcesPath);
8815}
8816
8817
8818void RGFW__osxWindowDeminiaturize(id self, SEL sel) {
8819 RGFW_UNUSED(sel);
8820 RGFW_window* win = NULL;
8821 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
8822 if (win == NULL) return;
8823
8824 win->_flags |= RGFW_windowMinimize;
8825 RGFW_eventQueuePushEx(e.type = RGFW_windowRestored; e._win = win);
8826 RGFW_windowRestoredCallback(win, win->r);
8827
8828}
8829void RGFW__osxWindowMiniaturize(id self, SEL sel) {
8830 RGFW_UNUSED(sel);
8831 RGFW_window* win = NULL;
8832 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
8833 if (win == NULL) return;
8834
8835 win->_flags &= ~(u32)RGFW_windowMinimize;
8836 RGFW_eventQueuePushEx(e.type = RGFW_windowMinimized; e._win = win);
8837 RGFW_windowMinimizedCallback(win, win->r);
8838
8839}
8840
8841void RGFW__osxWindowBecameKey(id self, SEL sel) {
8842 RGFW_UNUSED(sel);
8843 RGFW_window* win = NULL;
8844 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
8845 if (win == NULL) return;
8846
8847 win->_flags |= RGFW_windowFocus;
8848 RGFW_eventQueuePushEx(e.type = RGFW_focusIn; e._win = win);
8849
8850 RGFW_focusCallback(win, RGFW_TRUE);
8851
8852 if ((win->_flags & RGFW_HOLD_MOUSE)) RGFW_window_mouseHold(win, RGFW_AREA(win->r.w, win->r.h));
8853}
8854
8855void RGFW__osxWindowResignKey(id self, SEL sel) {
8856 RGFW_UNUSED(sel);
8857 RGFW_window* win = NULL;
8858 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
8859 if (win == NULL) return;
8860
8861 RGFW_window_focusLost(win);
8862 RGFW_eventQueuePushEx(e.type = RGFW_focusOut; e._win = win);
8863 RGFW_focusCallback(win, RGFW_FALSE);
8864}
8865
8866NSSize RGFW__osxWindowResize(id self, SEL sel, NSSize frameSize) {
8867 RGFW_UNUSED(sel);
8868
8869 RGFW_window* win = NULL;
8870 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
8871 if (win == NULL) return frameSize;
8872
8873 win->r.w = (i32)frameSize.width;
8874 win->r.h = (i32)frameSize.height;
8875
8876 RGFW_monitor mon = RGFW_window_getMonitor(win);
8877 if ((i32)mon.mode.area.w == win->r.w && (i32)mon.mode.area.h - 102 <= win->r.h) {
8878 win->_flags |= RGFW_windowMaximize;
8879 RGFW_eventQueuePushEx(e.type = RGFW_windowMaximized; e._win = win);
8880 RGFW_windowMaximizedCallback(win, win->r);
8881 } else if (win->_flags & RGFW_windowMaximize) {
8882 win->_flags &= ~(u32)RGFW_windowMaximize;
8883 RGFW_eventQueuePushEx(e.type = RGFW_windowRestored; e._win = win);
8884 RGFW_windowRestoredCallback(win, win->r);
8885
8886 }
8887
8888
8889 RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e._win = win);
8890 RGFW_windowResizedCallback(win, win->r);
8891 return frameSize;
8892}
8893
8894void RGFW__osxWindowMove(id self, SEL sel) {
8895 RGFW_UNUSED(sel);
8896
8897 RGFW_window* win = NULL;
8898 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
8899 if (win == NULL) return;
8900
8901 NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame"));
8902 win->r.x = (i32) frame.origin.x;
8903 win->r.y = (i32) frame.origin.y;
8904
8905 RGFW_eventQueuePushEx(e.type = RGFW_windowMoved; e._win = win);
8906 RGFW_windowMovedCallback(win, win->r);
8907}
8908
8909void RGFW__osxViewDidChangeBackingProperties(id self, SEL _cmd) {
8910 RGFW_UNUSED(_cmd);
8911 RGFW_window* win = NULL;
8912 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
8913 if (win == NULL) return;
8914
8915 RGFW_monitor mon = RGFW_window_getMonitor(win);
8916 RGFW_scaleUpdatedCallback(win, mon.scaleX, mon.scaleY);
8917 RGFW_eventQueuePushEx(e.type = RGFW_scaleUpdated; e.scaleX = mon.scaleX; e.scaleY = mon.scaleY ; e._win = win);
8918}
8919
8920void RGFW__osxDrawRect(id self, SEL _cmd, CGRect rect) {
8921 RGFW_UNUSED(rect); RGFW_UNUSED(_cmd);
8922 RGFW_window* win = NULL;
8923 object_getInstanceVariable(self, "RGFW_window", (void**)&win);
8924 if (win == NULL) return;
8925
8926 RGFW_eventQueuePushEx(e.type = RGFW_windowRefresh; e._win = win);
8927 RGFW_windowRefreshCallback(win);
8928}
8929
8930void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area) {
8931 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
8932 win->buffer = buffer;
8933 win->bufferSize = area;
8934 win->_flags |= RGFW_BUFFER_ALLOC;
8935 #ifdef RGFW_OSMESA
8936 win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL);
8937 OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h);
8938 OSMesaPixelStore(OSMESA_Y_UP, 0);
8939 #endif
8940 #else
8941 RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area); /*!< if buffer rendering is not being used */
8942 #endif
8943}
8944
8945void RGFW_window_cocoaSetLayer(RGFW_window* win, void* layer) {
8946 objc_msgSend_void_id((id)win->src.view, sel_registerName("setLayer"), (id)layer);
8947}
8948
8949void* RGFW_cocoaGetLayer(void) {
8950 return objc_msgSend_class((id)objc_getClass("CAMetalLayer"), (SEL)sel_registerName("layer"));
8951}
8952
8953NSPasteboardType const NSPasteboardTypeURL = "public.url";
8954NSPasteboardType const NSPasteboardTypeFileURL = "public.file-url";
8955
8956id RGFW__osx_generateViewClass(const char* subclass, RGFW_window* win) {
8957 Class customViewClass;
8958 customViewClass = objc_allocateClassPair(objc_getClass(subclass), "RGFWCustomView", 0);
8959
8960 class_addIvar( customViewClass, "RGFW_window", sizeof(RGFW_window*), (u8)rint(log2(sizeof(RGFW_window*))), "L");
8961 class_addMethod(customViewClass, sel_registerName("drawRect:"), (IMP)RGFW__osxDrawRect, "v@:{CGRect=ffff}");
8962 class_addMethod(customViewClass, sel_registerName("viewDidChangeBackingProperties"), (IMP)RGFW__osxViewDidChangeBackingProperties, "");
8963
8964 id customView = objc_msgSend_id(NSAlloc(customViewClass), sel_registerName("init"));
8965 object_setInstanceVariable(customView, "RGFW_window", win);
8966
8967 return customView;
8968}
8969
8970#ifndef RGFW_EGL
8971void RGFW_window_initOpenGL(RGFW_window* win) {
8972#ifdef RGFW_OPENGL
8973 void* attrs = RGFW_initFormatAttribs();
8974 void* format = NSOpenGLPixelFormat_initWithAttributes((uint32_t*)attrs);
8975
8976 if (format == NULL) {
8977 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to load pixel format for OpenGL");
8978 win->_flags |= RGFW_windowOpenglSoftware;
8979 void* subAttrs = RGFW_initFormatAttribs();
8980 format = NSOpenGLPixelFormat_initWithAttributes((uint32_t*)subAttrs);
8981
8982 if (format == NULL)
8983 RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "and loading software rendering OpenGL failed");
8984 else
8985 RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, RGFW_DEBUG_CTX(win, 0), "Switching to software rendering");
8986 }
8987
8988 /* the pixel format can be passed directly to opengl context creation to create a context
8989 this is because the format also includes information about the opengl version (which may be a bad thing) */
8990
8991 win->src.view = (id) ((id(*)(id, SEL, NSRect, uint32_t*))objc_msgSend) (RGFW__osx_generateViewClass("NSOpenGLView", win),
8992 sel_registerName("initWithFrame:pixelFormat:"), (NSRect){{0, 0}, {win->r.w, win->r.h}}, (uint32_t*)format);
8993
8994 objc_msgSend_void(win->src.view, sel_registerName("prepareOpenGL"));
8995 win->src.ctx = objc_msgSend_id(win->src.view, sel_registerName("openGLContext"));
8996
8997 if (win->_flags & RGFW_windowTransparent) {
8998 i32 opacity = 0;
8999 #define NSOpenGLCPSurfaceOpacity 236
9000 NSOpenGLContext_setValues((id)win->src.ctx, &opacity, NSOpenGLCPSurfaceOpacity);
9001 }
9002
9003 objc_msgSend_void(win->src.ctx, sel_registerName("makeCurrentContext"));
9004 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context initalized");
9005#else
9006 RGFW_UNUSED(win);
9007#endif
9008}
9009
9010void RGFW_window_freeOpenGL(RGFW_window* win) {
9011#ifdef RGFW_OPENGL
9012 if (win->src.ctx == NULL) return;
9013 objc_msgSend_void(win->src.ctx, sel_registerName("release"));
9014 win->src.ctx = NULL;
9015 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context freed");
9016#else
9017 RGFW_UNUSED(win);
9018#endif
9019}
9020#endif
9021
9022
9023i32 RGFW_init(void) {
9024#if defined(RGFW_C89) || defined(__cplusplus)
9025 if (_RGFW_init) return 0;
9026 _RGFW_init = RGFW_TRUE;
9027 _RGFW.root = NULL; _RGFW.current = NULL; _RGFW.windowCount = -1; _RGFW.eventLen = 0; _RGFW.eventIndex = 0;
9028#endif
9029
9030 /* NOTE(EimaMei): Why does Apple hate good code? Like wtf, who thought of methods being a great idea???
9031 Imagine a universe, where MacOS had a proper system API (we would probably have like 20% better performance).
9032 */
9033 si_func_to_SEL_with_name("NSObject", "windowShouldClose", (void*)RGFW_OnClose);
9034
9035 /* NOTE(EimaMei): Fixes the 'Boop' sfx from constantly playing each time you click a key. Only a problem when running in the terminal. */
9036 si_func_to_SEL("NSWindow", acceptsFirstResponder);
9037 si_func_to_SEL("NSWindow", performKeyEquivalent);
9038
9039 if (NSApp == NULL) {
9040 NSApp = objc_msgSend_id((id)objc_getClass("NSApplication"), sel_registerName("sharedApplication"));
9041
9042 ((void (*)(id, SEL, NSUInteger))objc_msgSend)
9043 (NSApp, sel_registerName("setActivationPolicy:"), NSApplicationActivationPolicyRegular);
9044
9045 #ifndef RGFW_NO_IOKIT
9046 RGFW_osxInitIOKit();
9047 #endif
9048 }
9049
9050 _RGFW.windowCount = 0;
9051 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context initialized");
9052 return 0;
9053}
9054
9055RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) {
9056 static u8 RGFW_loaded = 0;
9057 RGFW_window_basic_init(win, rect, flags);
9058
9059 /* RR Create an autorelease pool */
9060 id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
9061 pool = objc_msgSend_id(pool, sel_registerName("init"));
9062
9063 RGFW_window_setMouseDefault(win);
9064
9065 NSRect windowRect;
9066 windowRect.origin.x = win->r.x;
9067 windowRect.origin.y = win->r.y;
9068 windowRect.size.width = win->r.w;
9069 windowRect.size.height = win->r.h;
9070
9071 NSBackingStoreType macArgs = NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSBackingStoreBuffered | NSWindowStyleMaskTitled;
9072
9073 if (!(flags & RGFW_windowNoResize))
9074 macArgs |= NSWindowStyleMaskResizable;
9075 if (!(flags & RGFW_windowNoBorder))
9076 macArgs |= NSWindowStyleMaskTitled;
9077 {
9078 void* nsclass = objc_getClass("NSWindow");
9079 SEL func = sel_registerName("initWithContentRect:styleMask:backing:defer:");
9080
9081 win->src.window = ((id(*)(id, SEL, NSRect, NSWindowStyleMask, NSBackingStoreType, bool))objc_msgSend)
9082 (NSAlloc(nsclass), func, windowRect, macArgs, macArgs, false);
9083 }
9084
9085 id str = NSString_stringWithUTF8String(name);
9086 objc_msgSend_void_id((id)win->src.window, sel_registerName("setTitle:"), str);
9087
9088 if ((flags & RGFW_windowNoInitAPI) == 0) {
9089 RGFW_window_initOpenGL(win);
9090 RGFW_window_initBuffer(win);
9091 }
9092
9093 #ifdef RGFW_OPENGL
9094 else
9095 #endif
9096 {
9097 NSRect contentRect = (NSRect){{0, 0}, {win->r.w, win->r.h}};
9098 win->src.view = ((id(*)(id, SEL, NSRect))objc_msgSend) (NSAlloc(objc_getClass("NSView")), sel_registerName("initWithFrame:"), contentRect);
9099 }
9100
9101 void* contentView = NSWindow_contentView((id)win->src.window);
9102 objc_msgSend_void_bool(contentView, sel_registerName("setWantsLayer:"), true);
9103 objc_msgSend_int((id)win->src.view, sel_registerName("setLayerContentsPlacement:"), 4);
9104 objc_msgSend_void_id((id)win->src.window, sel_registerName("setContentView:"), win->src.view);
9105
9106 if (flags & RGFW_windowTransparent) {
9107 objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), false);
9108
9109 objc_msgSend_void_id((id)win->src.window, sel_registerName("setBackgroundColor:"),
9110 NSColor_colorWithSRGB(0, 0, 0, 0));
9111 }
9112
9113 Class delegateClass = objc_allocateClassPair(objc_getClass("NSObject"), "WindowDelegate", 0);
9114
9115 class_addIvar(
9116 delegateClass, "RGFW_window",
9117 sizeof(RGFW_window*), (u8)rint(log2(sizeof(RGFW_window*))),
9118 "L"
9119 );
9120
9121 class_addMethod(delegateClass, sel_registerName("windowWillResize:toSize:"), (IMP) RGFW__osxWindowResize, "{NSSize=ff}@:{NSSize=ff}");
9122 class_addMethod(delegateClass, sel_registerName("windowWillMove:"), (IMP) RGFW__osxWindowMove, "");
9123 class_addMethod(delegateClass, sel_registerName("windowDidMove:"), (IMP) RGFW__osxWindowMove, "");
9124 class_addMethod(delegateClass, sel_registerName("windowDidMiniaturize:"), (IMP) RGFW__osxWindowMiniaturize, "");
9125 class_addMethod(delegateClass, sel_registerName("windowDidDeminiaturize:"), (IMP) RGFW__osxWindowDeminiaturize, "");
9126 class_addMethod(delegateClass, sel_registerName("windowDidBecomeKey:"), (IMP) RGFW__osxWindowBecameKey, "");
9127 class_addMethod(delegateClass, sel_registerName("windowDidResignKey:"), (IMP) RGFW__osxWindowResignKey, "");
9128 class_addMethod(delegateClass, sel_registerName("draggingEntered:"), (IMP)draggingEntered, "l@:@");
9129 class_addMethod(delegateClass, sel_registerName("draggingUpdated:"), (IMP)draggingUpdated, "l@:@");
9130 class_addMethod(delegateClass, sel_registerName("draggingExited:"), (IMP)RGFW__osxDraggingEnded, "v@:@");
9131 class_addMethod(delegateClass, sel_registerName("draggingEnded:"), (IMP)RGFW__osxDraggingEnded, "v@:@");
9132 class_addMethod(delegateClass, sel_registerName("prepareForDragOperation:"), (IMP)prepareForDragOperation, "B@:@");
9133 class_addMethod(delegateClass, sel_registerName("performDragOperation:"), (IMP)performDragOperation, "B@:@");
9134
9135 id delegate = objc_msgSend_id(NSAlloc(delegateClass), sel_registerName("init"));
9136
9137 if (RGFW_COCOA_FRAME_NAME)
9138 objc_msgSend_ptr(win->src.view, sel_registerName("setFrameAutosaveName:"), RGFW_COCOA_FRAME_NAME);
9139
9140 object_setInstanceVariable(delegate, "RGFW_window", win);
9141
9142 objc_msgSend_void_id((id)win->src.window, sel_registerName("setDelegate:"), delegate);
9143
9144 if (flags & RGFW_windowAllowDND) {
9145 win->_flags |= RGFW_windowAllowDND;
9146
9147 NSPasteboardType types[] = {NSPasteboardTypeURL, NSPasteboardTypeFileURL, NSPasteboardTypeString};
9148 NSregisterForDraggedTypes((id)win->src.window, types, 3);
9149 }
9150
9151 RGFW_window_setFlags(win, flags);
9152
9153 /* Show the window */
9154 objc_msgSend_void_bool(NSApp, sel_registerName("activateIgnoringOtherApps:"), true);
9155 ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("makeKeyAndOrderFront:"), NULL);
9156 RGFW_window_show(win);
9157
9158 if (!RGFW_loaded) {
9159 objc_msgSend_void(win->src.window, sel_registerName("makeMainWindow"));
9160
9161 RGFW_loaded = 1;
9162 }
9163
9164 objc_msgSend_void(win->src.window, sel_registerName("makeKeyWindow"));
9165
9166 objc_msgSend_void(NSApp, sel_registerName("finishLaunching"));
9167 NSRetain(win->src.window);
9168 NSRetain(NSApp);
9169
9170 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created");
9171 return win;
9172}
9173
9174void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) {
9175 NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame"));
9176 NSRect content = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame"));
9177 float offset = 0;
9178
9179 RGFW_setBit(&win->_flags, RGFW_windowNoBorder, !border);
9180 NSBackingStoreType storeType = NSWindowStyleMaskBorderless | NSWindowStyleMaskFullSizeContentView;
9181 if (border)
9182 storeType = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable;
9183 if (!(win->_flags & RGFW_windowNoResize)) {
9184 storeType |= NSWindowStyleMaskResizable;
9185 }
9186
9187 ((void (*)(id, SEL, NSBackingStoreType))objc_msgSend)((id)win->src.window, sel_registerName("setStyleMask:"), storeType);
9188
9189 if (!border) {
9190 id miniaturizeButton = objc_msgSend_int((id)win->src.window, sel_registerName("standardWindowButton:"), NSWindowMiniaturizeButton);
9191 id titleBarView = objc_msgSend_id(miniaturizeButton, sel_registerName("superview"));
9192 objc_msgSend_void_bool(titleBarView, sel_registerName("setHidden:"), true);
9193
9194 offset = (float)(frame.size.height - content.size.height);
9195 }
9196
9197 RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h + offset));
9198 win->r.h -= (i32)offset;
9199}
9200
9201RGFW_area RGFW_getScreenSize(void) {
9202 static CGDirectDisplayID display = 0;
9203
9204 if (display == 0)
9205 display = CGMainDisplayID();
9206
9207 return RGFW_AREA(CGDisplayPixelsWide(display), CGDisplayPixelsHigh(display));
9208}
9209
9210RGFW_point RGFW_getGlobalMousePoint(void) {
9211 RGFW_ASSERT(_RGFW.root != NULL);
9212
9213 CGEventRef e = CGEventCreate(NULL);
9214 CGPoint point = CGEventGetLocation(e);
9215 CFRelease(e);
9216
9217 return RGFW_POINT((u32) point.x, (u32) point.y); /*!< the point is loaded during event checks */
9218}
9219
9220typedef RGFW_ENUM(u32, NSEventType) { /* various types of events */
9221 NSEventTypeLeftMouseDown = 1,
9222 NSEventTypeLeftMouseUp = 2,
9223 NSEventTypeRightMouseDown = 3,
9224 NSEventTypeRightMouseUp = 4,
9225 NSEventTypeMouseMoved = 5,
9226 NSEventTypeLeftMouseDragged = 6,
9227 NSEventTypeRightMouseDragged = 7,
9228 NSEventTypeMouseEntered = 8,
9229 NSEventTypeMouseExited = 9,
9230 NSEventTypeKeyDown = 10,
9231 NSEventTypeKeyUp = 11,
9232 NSEventTypeFlagsChanged = 12,
9233 NSEventTypeAppKitDefined = 13,
9234 NSEventTypeSystemDefined = 14,
9235 NSEventTypeApplicationDefined = 15,
9236 NSEventTypePeriodic = 16,
9237 NSEventTypeCursorUpdate = 17,
9238 NSEventTypeScrollWheel = 22,
9239 NSEventTypeTabletPoint = 23,
9240 NSEventTypeTabletProximity = 24,
9241 NSEventTypeOtherMouseDown = 25,
9242 NSEventTypeOtherMouseUp = 26,
9243 NSEventTypeOtherMouseDragged = 27,
9244 /* The following event types are available on some hardware on 10.5.2 and later */
9245 NSEventTypeGesture = 29,
9246 NSEventTypeMagnify = 30,
9247 NSEventTypeSwipe = 31,
9248 NSEventTypeRotate = 18,
9249 NSEventTypeBeginGesture = 19,
9250 NSEventTypeEndGesture = 20,
9251
9252 NSEventTypeSmartMagnify = 32,
9253 NSEventTypeQuickLook = 33,
9254
9255 NSEventTypePressure = 34,
9256 NSEventTypeDirectTouch = 37,
9257
9258 NSEventTypeChangeMode = 38,
9259};
9260
9261typedef unsigned long long NSEventMask;
9262
9263typedef enum NSEventModifierFlags {
9264 NSEventModifierFlagCapsLock = 1 << 16,
9265 NSEventModifierFlagShift = 1 << 17,
9266 NSEventModifierFlagControl = 1 << 18,
9267 NSEventModifierFlagOption = 1 << 19,
9268 NSEventModifierFlagCommand = 1 << 20,
9269 NSEventModifierFlagNumericPad = 1 << 21
9270} NSEventModifierFlags;
9271
9272void RGFW_stopCheckEvents(void) {
9273 id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
9274 eventPool = objc_msgSend_id(eventPool, sel_registerName("init"));
9275
9276 id e = (id) ((id(*)(Class, SEL, NSEventType, NSPoint, NSEventModifierFlags, void*, NSInteger, void**, short, NSInteger, NSInteger))objc_msgSend)
9277 (objc_getClass("NSEvent"), sel_registerName("otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:"),
9278 NSEventTypeApplicationDefined, (NSPoint){0, 0}, (NSEventModifierFlags)0, NULL, (NSInteger)0, NULL, 0, 0, 0);
9279
9280 ((void (*)(id, SEL, id, bool))objc_msgSend)
9281 (NSApp, sel_registerName("postEvent:atStart:"), e, 1);
9282
9283 objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
9284}
9285
9286void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) {
9287 RGFW_UNUSED(win);
9288
9289 id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
9290 eventPool = objc_msgSend_id(eventPool, sel_registerName("init"));
9291
9292 void* date = (void*) ((id(*)(Class, SEL, double))objc_msgSend)
9293 (objc_getClass("NSDate"), sel_registerName("dateWithTimeIntervalSinceNow:"), waitMS);
9294
9295 SEL eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:");
9296 id e = (id) ((id(*)(id, SEL, NSEventMask, void*, id, bool))objc_msgSend)
9297 (NSApp, eventFunc,
9298 ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true);
9299
9300 if (e) {
9301 ((void (*)(id, SEL, id, bool))objc_msgSend)
9302 (NSApp, sel_registerName("postEvent:atStart:"), e, 1);
9303 }
9304
9305 objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
9306}
9307
9308u8 RGFW_rgfwToKeyChar(u32 rgfw_keycode) {
9309 return (u8)rgfw_keycode; /* TODO */
9310}
9311
9312RGFW_event* RGFW_window_checkEvent(RGFW_window* win) {
9313 if (win == NULL || ((win->_flags & RGFW_windowFreeOnClose) && (win->_flags & RGFW_EVENT_QUIT))) return NULL;
9314
9315 objc_msgSend_void((id)win->src.mouse, sel_registerName("set"));
9316 RGFW_event* ev = RGFW_window_checkEventCore(win);
9317 if (ev) {
9318 ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows"));
9319 return ev;
9320 }
9321
9322 id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
9323 eventPool = objc_msgSend_id(eventPool, sel_registerName("init"));
9324
9325 SEL eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:");
9326
9327 void* date = NULL;
9328
9329 id e = (id) ((id(*)(id, SEL, NSEventMask, void*, id, bool))objc_msgSend)
9330 (NSApp, eventFunc, ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true);
9331
9332 if (e == NULL) {
9333 objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
9334 objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e);
9335 ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows"));
9336 return NULL;
9337 }
9338
9339 if (objc_msgSend_id(e, sel_registerName("window")) != win->src.window) {
9340 ((void (*)(id, SEL, id, bool))objc_msgSend)
9341 (NSApp, sel_registerName("postEvent:atStart:"), e, 0);
9342
9343 objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e);
9344 objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
9345 ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows"));
9346 return NULL;
9347 }
9348
9349 if (win->event.droppedFilesCount) {
9350 u32 i;
9351 for (i = 0; i < win->event.droppedFilesCount; i++)
9352 win->event.droppedFiles[i][0] = '\0';
9353 }
9354
9355 win->event.droppedFilesCount = 0;
9356 win->event.type = 0;
9357
9358 u32 type = (u32)objc_msgSend_uint(e, sel_registerName("type"));
9359 switch (type) {
9360 case NSEventTypeMouseEntered: {
9361 win->event.type = RGFW_mouseEnter;
9362 NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow"));
9363
9364 win->event.point = RGFW_POINT((i32) p.x, (i32) (win->r.h - p.y));
9365 RGFW_mouseNotifyCallback(win, win->event.point, 1);
9366 break;
9367 }
9368
9369 case NSEventTypeMouseExited:
9370 win->event.type = RGFW_mouseLeave;
9371 RGFW_mouseNotifyCallback(win, win->event.point, 0);
9372 break;
9373
9374 case NSEventTypeKeyDown: {
9375 u32 key = (u16) objc_msgSend_uint(e, sel_registerName("keyCode"));
9376
9377 u32 mappedKey = (u32)*(((char*)(const char*) NSString_to_char(objc_msgSend_id(e, sel_registerName("charactersIgnoringModifiers")))));
9378 if (((u8)mappedKey) == 239)
9379 mappedKey = 0;
9380
9381 win->event.keyChar = (u8)mappedKey;
9382
9383 win->event.key = (u8)RGFW_apiKeyToRGFW(key);
9384 RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current;
9385
9386 win->event.type = RGFW_keyPressed;
9387 win->event.repeat = RGFW_isPressed(win, win->event.key);
9388 RGFW_keyboard[win->event.key].current = 1;
9389
9390 RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 1);
9391 break;
9392 }
9393
9394 case NSEventTypeKeyUp: {
9395 u32 key = (u16) objc_msgSend_uint(e, sel_registerName("keyCode"));
9396 u32 mappedKey = (u32)*(((char*)(const char*) NSString_to_char(objc_msgSend_id(e, sel_registerName("charactersIgnoringModifiers")))));
9397 if (((u8)mappedKey) == 239)
9398 mappedKey = 0;
9399
9400 win->event.keyChar = (u8)mappedKey;
9401
9402 win->event.key = (u8)RGFW_apiKeyToRGFW(key);
9403
9404 RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current;
9405
9406 win->event.type = RGFW_keyReleased;
9407
9408 RGFW_keyboard[win->event.key].current = 0;
9409 RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 0);
9410 break;
9411 }
9412
9413 case NSEventTypeFlagsChanged: {
9414 u32 flags = (u32)objc_msgSend_uint(e, sel_registerName("modifierFlags"));
9415 RGFW_updateKeyModsPro(win, ((u32)(flags & NSEventModifierFlagCapsLock) % 255), ((flags & NSEventModifierFlagNumericPad) % 255),
9416 ((flags & NSEventModifierFlagControl) % 255), ((flags & NSEventModifierFlagOption) % 255),
9417 ((flags & NSEventModifierFlagShift) % 255), ((flags & NSEventModifierFlagCommand) % 255), 0);
9418 u8 i;
9419 for (i = 0; i < 9; i++)
9420 RGFW_keyboard[i + RGFW_capsLock].prev = 0;
9421
9422 for (i = 0; i < 5; i++) {
9423 u32 shift = (1 << (i + 16));
9424 u32 key = i + RGFW_capsLock;
9425
9426 if ((flags & shift) && !RGFW_wasPressed(win, (u8)key)) {
9427 RGFW_keyboard[key].current = 1;
9428
9429 if (key != RGFW_capsLock)
9430 RGFW_keyboard[key+ 4].current = 1;
9431
9432 win->event.type = RGFW_keyPressed;
9433 win->event.key = (u8)key;
9434 break;
9435 }
9436
9437 if (!(flags & shift) && RGFW_wasPressed(win, (u8)key)) {
9438 RGFW_keyboard[key].current = 0;
9439
9440 if (key != RGFW_capsLock)
9441 RGFW_keyboard[key + 4].current = 0;
9442
9443 win->event.type = RGFW_keyReleased;
9444 win->event.key = (u8)key;
9445 break;
9446 }
9447 }
9448
9449 RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, win->event.type == RGFW_keyPressed);
9450
9451 break;
9452 }
9453 case NSEventTypeLeftMouseDragged:
9454 case NSEventTypeOtherMouseDragged:
9455 case NSEventTypeRightMouseDragged:
9456 case NSEventTypeMouseMoved: {
9457 win->event.type = RGFW_mousePosChanged;
9458 NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow"));
9459 win->event.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y));
9460
9461 p.x = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaX"));
9462 p.y = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaY"));
9463 win->event.vector = RGFW_POINT((i32)p.x, (i32)p.y);
9464
9465 win->_lastMousePoint = win->event.point;
9466 RGFW_mousePosCallback(win, win->event.point, win->event.vector);
9467 break;
9468 }
9469 case NSEventTypeLeftMouseDown: case NSEventTypeRightMouseDown: case NSEventTypeOtherMouseDown: {
9470 u32 buttonNumber = (u32)objc_msgSend_uint(e, sel_registerName("buttonNumber"));
9471 switch (buttonNumber) {
9472 case 0: win->event.button = RGFW_mouseLeft; break;
9473 case 1: win->event.button = RGFW_mouseRight; break;
9474 case 2: win->event.button = RGFW_mouseMiddle; break;
9475 default: win->event.button = (u8)buttonNumber;
9476 }
9477
9478 win->event.type = RGFW_mouseButtonPressed;
9479 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
9480 RGFW_mouseButtons[win->event.button].current = 1;
9481 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
9482 break;
9483 }
9484 case NSEventTypeLeftMouseUp: case NSEventTypeRightMouseUp: case NSEventTypeOtherMouseUp: {
9485 u32 buttonNumber = (u32)objc_msgSend_uint(e, sel_registerName("buttonNumber"));
9486 switch (buttonNumber) {
9487 case 0: win->event.button = RGFW_mouseLeft; break;
9488 case 1: win->event.button = RGFW_mouseRight; break;
9489 case 2: win->event.button = RGFW_mouseMiddle; break;
9490 default: win->event.button = (u8)buttonNumber;
9491 }
9492 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
9493 RGFW_mouseButtons[win->event.button].current = 0;
9494 win->event.type = RGFW_mouseButtonReleased;
9495 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0);
9496 break;
9497 }
9498 case NSEventTypeScrollWheel: {
9499 double deltaY = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaY"));
9500
9501 if (deltaY > 0) {
9502 win->event.button = RGFW_mouseScrollUp;
9503 }
9504 else if (deltaY < 0) {
9505 win->event.button = RGFW_mouseScrollDown;
9506 }
9507
9508 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
9509 RGFW_mouseButtons[win->event.button].current = 1;
9510
9511 win->event.scroll = deltaY;
9512
9513 win->event.type = RGFW_mouseButtonPressed;
9514 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
9515 break;
9516 }
9517
9518 default:
9519 objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e);
9520 ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows"));
9521 return RGFW_window_checkEvent(win);
9522 }
9523
9524 objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e);
9525 ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows"));
9526 objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
9527 return &win->event;
9528}
9529
9530
9531void RGFW_window_move(RGFW_window* win, RGFW_point v) {
9532 RGFW_ASSERT(win != NULL);
9533
9534 win->r.x = v.x;
9535 win->r.y = v.y;
9536 ((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend)
9537 ((id)win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{win->r.x, win->r.y}, {win->r.w, win->r.h}}, true, true);
9538}
9539
9540void RGFW_window_resize(RGFW_window* win, RGFW_area a) {
9541 RGFW_ASSERT(win != NULL);
9542
9543 NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame"));
9544 NSRect content = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame"));
9545 float offset = (float)(frame.size.height - content.size.height);
9546
9547 win->r.w = (i32)a.w;
9548 win->r.h = (i32)a.h;
9549
9550 ((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend)
9551 ((id)win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{win->r.x, win->r.y}, {win->r.w, win->r.h + offset}}, true, true);
9552}
9553
9554void RGFW_window_focus(RGFW_window* win) {
9555 RGFW_ASSERT(win);
9556 objc_msgSend_void_bool(NSApp, sel_registerName("activateIgnoringOtherApps:"), true);
9557 ((void (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_registerName("makeKeyWindow"));
9558}
9559
9560void RGFW_window_raise(RGFW_window* win) {
9561 RGFW_ASSERT(win != NULL);
9562 ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("orderFront:"), (SEL)NULL);
9563 objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGNormalWindowLevelKey);
9564}
9565
9566void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) {
9567 RGFW_ASSERT(win != NULL);
9568 if (fullscreen && (win->_flags & RGFW_windowFullscreen)) return;
9569 if (!fullscreen && !(win->_flags & RGFW_windowFullscreen)) return;
9570
9571 if (fullscreen) {
9572 win->_oldRect = win->r;
9573 RGFW_monitor mon = RGFW_window_getMonitor(win);
9574 win->r = RGFW_RECT(0, 0, mon.x, mon.y);
9575 win->_flags |= RGFW_windowFullscreen;
9576 RGFW_window_resize(win, RGFW_AREA(mon.mode.area.w, mon.mode.area.h));
9577 RGFW_window_move(win, RGFW_POINT(0, 0));
9578 }
9579 objc_msgSend_void_SEL(win->src.window, sel_registerName("toggleFullScreen:"), NULL);
9580
9581 if (!fullscreen) {
9582 win->r = win->_oldRect;
9583 win->_flags &= ~(u32)RGFW_windowFullscreen;
9584
9585 RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h));
9586 RGFW_window_move(win, RGFW_POINT(win->r.x, win->r.y));
9587 }
9588}
9589
9590void RGFW_window_maximize(RGFW_window* win) {
9591 RGFW_ASSERT(win != NULL);
9592 if (RGFW_window_isMaximized(win)) return;
9593
9594 win->_flags |= RGFW_windowMaximize;
9595 objc_msgSend_void_SEL(win->src.window, sel_registerName("zoom:"), NULL);
9596}
9597
9598void RGFW_window_minimize(RGFW_window* win) {
9599 RGFW_ASSERT(win != NULL);
9600 objc_msgSend_void_SEL(win->src.window, sel_registerName("performMiniaturize:"), NULL);
9601}
9602
9603void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) {
9604 RGFW_ASSERT(win != NULL);
9605 if (floating) objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGFloatingWindowLevelKey);
9606 else objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGNormalWindowLevelKey);
9607}
9608
9609void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) {
9610 objc_msgSend_int(win->src.window, sel_registerName("setAlphaValue:"), opacity);
9611 objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), (opacity < (u8)255));
9612
9613 if (opacity)
9614 objc_msgSend_void_id((id)win->src.window, sel_registerName("setBackgroundColor:"), NSColor_colorWithSRGB(0, 0, 0, opacity));
9615
9616}
9617
9618void RGFW_window_restore(RGFW_window* win) {
9619 RGFW_ASSERT(win != NULL);
9620
9621 if (RGFW_window_isMaximized(win))
9622 objc_msgSend_void_SEL(win->src.window, sel_registerName("zoom:"), NULL);
9623
9624 objc_msgSend_void_SEL(win->src.window, sel_registerName("deminiaturize:"), NULL);
9625 RGFW_window_show(win);
9626}
9627
9628RGFW_bool RGFW_window_isFloating(RGFW_window* win) {
9629 RGFW_ASSERT(win != NULL);
9630 int level = ((int (*)(id, SEL))objc_msgSend) ((id)(win->src.window), (SEL)sel_registerName("level"));
9631 return level > kCGNormalWindowLevelKey;
9632}
9633
9634void RGFW_window_setName(RGFW_window* win, const char* name) {
9635 RGFW_ASSERT(win != NULL);
9636
9637 id str = NSString_stringWithUTF8String(name);
9638 objc_msgSend_void_id((id)win->src.window, sel_registerName("setTitle:"), str);
9639}
9640
9641#ifndef RGFW_NO_PASSTHROUGH
9642void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) {
9643 objc_msgSend_void_bool(win->src.window, sel_registerName("setIgnoresMouseEvents:"), passthrough);
9644}
9645#endif
9646
9647void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) {
9648 if (a.w == 0 && a.h == 0) a = RGFW_AREA(1, 1);
9649
9650 ((void (*)(id, SEL, NSSize))objc_msgSend)
9651 ((id)win->src.window, sel_registerName("setContentAspectRatio:"), (NSSize){a.w, a.h});
9652}
9653
9654void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) {
9655 ((void (*)(id, SEL, NSSize))objc_msgSend)
9656 ((id)win->src.window, sel_registerName("setMinSize:"), (NSSize){a.w, a.h});
9657}
9658
9659void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) {
9660 if (a.w == 0 && a.h == 0) {
9661 a = RGFW_getScreenSize();
9662 }
9663
9664 ((void (*)(id, SEL, NSSize))objc_msgSend)
9665 ((id)win->src.window, sel_registerName("setMaxSize:"), (NSSize){a.w, a.h});
9666}
9667
9668RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, RGFW_area area, i32 channels, u8 type) {
9669 RGFW_ASSERT(win != NULL);
9670 RGFW_UNUSED(type);
9671
9672 if (data == NULL) {
9673 objc_msgSend_void_id(NSApp, sel_registerName("setApplicationIconImage:"), NULL);
9674 return RGFW_TRUE;
9675 }
9676
9677 /* code by EimaMei: Make a bitmap representation, then copy the loaded image into it. */
9678 id representation = NSBitmapImageRep_initWithBitmapData(NULL, area.w, area.h, 8, channels, (channels == 4), false, "NSCalibratedRGBColorSpace", 1 << 1, area.w * (u32)channels, 8 * (u32)channels);
9679 RGFW_MEMCPY(NSBitmapImageRep_bitmapData(representation), data, area.w * area.h * (u32)channels);
9680
9681 /* Add ze representation. */
9682 id dock_image = ((id(*)(id, SEL, NSSize))objc_msgSend) (NSAlloc((id)objc_getClass("NSImage")), sel_registerName("initWithSize:"), ((NSSize){area.w, area.h}));
9683
9684 objc_msgSend_void_id(dock_image, sel_registerName("addRepresentation:"), representation);
9685
9686 /* Finally, set the dock image to it. */
9687 objc_msgSend_void_id(NSApp, sel_registerName("setApplicationIconImage:"), dock_image);
9688 /* Free the garbage. */
9689 NSRelease(dock_image);
9690 NSRelease(representation);
9691
9692 return RGFW_TRUE;
9693}
9694
9695id NSCursor_arrowStr(const char* str) {
9696 void* nclass = objc_getClass("NSCursor");
9697 SEL func = sel_registerName(str);
9698 return (id) objc_msgSend_id(nclass, func);
9699}
9700
9701RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) {
9702 if (icon == NULL) {
9703 objc_msgSend_void(NSCursor_arrowStr("arrowCursor"), sel_registerName("set"));
9704 return NULL;
9705 }
9706
9707 /* NOTE(EimaMei): Code by yours truly. */
9708 /* Make a bitmap representation, then copy the loaded image into it. */
9709 id representation = (id)NSBitmapImageRep_initWithBitmapData(NULL, a.w, a.h, 8, channels, (channels == 4), false, "NSCalibratedRGBColorSpace", 1 << 1, a.w * (u32)channels, 8 * (u32)channels);
9710 RGFW_MEMCPY(NSBitmapImageRep_bitmapData(representation), icon, a.w * a.h * (u32)channels);
9711
9712 /* Add ze representation. */
9713 id cursor_image = ((id(*)(id, SEL, NSSize))objc_msgSend) (NSAlloc((id)objc_getClass("NSImage")), sel_registerName("initWithSize:"), ((NSSize){a.w, a.h}));
9714
9715 objc_msgSend_void_id(cursor_image, sel_registerName("addRepresentation:"), representation);
9716
9717 /* Finally, set the cursor image. */
9718 id cursor = (id) ((id(*)(id, SEL, id, NSPoint))objc_msgSend)
9719 (NSAlloc(objc_getClass("NSCursor")), sel_registerName("initWithImage:hotSpot:"), cursor_image, (NSPoint){0.0, 0.0});
9720
9721 /* Free the garbage. */
9722 NSRelease(cursor_image);
9723 NSRelease(representation);
9724
9725 return (void*)cursor;
9726}
9727
9728void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) {
9729 RGFW_ASSERT(win != NULL); RGFW_ASSERT(mouse);
9730 CGDisplayShowCursor(kCGDirectMainDisplay);
9731 objc_msgSend_void((id)mouse, sel_registerName("set"));
9732 win->src.mouse = mouse;
9733}
9734
9735void RGFW_freeMouse(RGFW_mouse* mouse) {
9736 RGFW_ASSERT(mouse);
9737 NSRelease((id)mouse);
9738}
9739
9740RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) {
9741 return RGFW_window_setMouseStandard(win, RGFW_mouseArrow);
9742}
9743
9744void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) {
9745 RGFW_window_showMouseFlags(win, show);
9746 if (show) CGDisplayShowCursor(kCGDirectMainDisplay);
9747 else CGDisplayHideCursor(kCGDirectMainDisplay);
9748}
9749
9750RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 stdMouses) {
9751 static const char* mouseIconSrc[16] = {"arrowCursor", "arrowCursor", "IBeamCursor", "crosshairCursor", "pointingHandCursor", "resizeLeftRightCursor", "resizeUpDownCursor", "_windowResizeNorthWestSouthEastCursor", "_windowResizeNorthEastSouthWestCursor", "closedHandCursor", "operationNotAllowedCursor"};
9752 if (stdMouses > ((sizeof(mouseIconSrc)) / (sizeof(char*))))
9753 return RGFW_FALSE;
9754
9755 const char* mouseStr = mouseIconSrc[stdMouses];
9756 id mouse = NSCursor_arrowStr(mouseStr);
9757
9758 if (mouse == NULL)
9759 return RGFW_FALSE;
9760
9761 RGFW_UNUSED(win);
9762 CGDisplayShowCursor(kCGDirectMainDisplay);
9763 objc_msgSend_void(mouse, sel_registerName("set"));
9764 win->src.mouse = mouse;
9765
9766 return RGFW_TRUE;
9767}
9768
9769void RGFW_releaseCursor(RGFW_window* win) {
9770 RGFW_UNUSED(win);
9771 CGAssociateMouseAndMouseCursorPosition(1);
9772}
9773
9774void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) {
9775 RGFW_UNUSED(win);
9776
9777 CGWarpMouseCursorPosition((CGPoint){r.x + (r.w / 2), r.y + (r.h / 2)});
9778 CGAssociateMouseAndMouseCursorPosition(0);
9779}
9780
9781void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) {
9782 RGFW_UNUSED(win);
9783
9784 win->_lastMousePoint = RGFW_POINT(v.x - win->r.x, v.y - win->r.y);
9785 CGWarpMouseCursorPosition((CGPoint){v.x, v.y});
9786}
9787
9788
9789void RGFW_window_hide(RGFW_window* win) {
9790 objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), false);
9791}
9792
9793void RGFW_window_show(RGFW_window* win) {
9794 if (win->_flags & RGFW_windowFocusOnShow)
9795 ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("makeKeyAndOrderFront:"), NULL);
9796
9797 ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("orderFront:"), NULL);
9798 objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), true);
9799}
9800
9801RGFW_bool RGFW_window_isHidden(RGFW_window* win) {
9802 RGFW_ASSERT(win != NULL);
9803
9804 bool visible = objc_msgSend_bool(win->src.window, sel_registerName("isVisible"));
9805 return visible == NO && !RGFW_window_isMinimized(win);
9806}
9807
9808RGFW_bool RGFW_window_isMinimized(RGFW_window* win) {
9809 RGFW_ASSERT(win != NULL);
9810
9811 return objc_msgSend_bool(win->src.window, sel_registerName("isMiniaturized")) == YES;
9812}
9813
9814RGFW_bool RGFW_window_isMaximized(RGFW_window* win) {
9815 RGFW_ASSERT(win != NULL);
9816 RGFW_bool b = (RGFW_bool)objc_msgSend_bool(win->src.window, sel_registerName("isZoomed"));
9817 return b;
9818}
9819
9820id RGFW_getNSScreenForDisplayID(CGDirectDisplayID display) {
9821 Class NSScreenClass = objc_getClass("NSScreen");
9822
9823 id screens = objc_msgSend_id(NSScreenClass, sel_registerName("screens"));
9824
9825 NSUInteger count = (NSUInteger)objc_msgSend_uint(screens, sel_registerName("count"));
9826 NSUInteger i;
9827 for (i = 0; i < count; i++) {
9828 id screen = ((id (*)(id, SEL, int))objc_msgSend) (screens, sel_registerName("objectAtIndex:"), (int)i);
9829 id description = objc_msgSend_id(screen, sel_registerName("deviceDescription"));
9830 id screenNumberKey = NSString_stringWithUTF8String("NSScreenNumber");
9831 id screenNumber = objc_msgSend_id_id(description, sel_registerName("objectForKey:"), screenNumberKey);
9832
9833 if ((CGDirectDisplayID)objc_msgSend_uint(screenNumber, sel_registerName("unsignedIntValue")) == display) {
9834 return screen;
9835 }
9836 }
9837
9838 return NULL;
9839}
9840
9841u32 RGFW_osx_getFallbackRefreshRate(CGDirectDisplayID displayID);
9842
9843u32 RGFW_osx_getRefreshRate(CGDirectDisplayID display, CGDisplayModeRef mode) {
9844 if (mode) {
9845 u32 refreshRate = (u32)CGDisplayModeGetRefreshRate(mode);
9846 if (refreshRate != 0) return refreshRate;
9847 }
9848
9849#ifndef RGFW_NO_IOKIT
9850 u32 res = RGFW_osx_getFallbackRefreshRate(display);
9851 if (res != 0) return res;
9852#else
9853 RGFW_UNUSED(display);
9854#endif
9855 return 60;
9856}
9857
9858RGFW_monitor RGFW_NSCreateMonitor(CGDirectDisplayID display, id screen) {
9859 RGFW_monitor monitor;
9860
9861 const char name[] = "MacOS\0";
9862 RGFW_MEMCPY(monitor.name, name, 6);
9863
9864 CGRect bounds = CGDisplayBounds(display);
9865 monitor.x = (i32)bounds.origin.x;
9866 monitor.y = (i32)bounds.origin.y;
9867 monitor.mode.area = RGFW_AREA((int) bounds.size.width, (int) bounds.size.height);
9868
9869 monitor.mode.red = 8; monitor.mode.green = 8; monitor.mode.blue = 8;
9870
9871 CGDisplayModeRef mode = CGDisplayCopyDisplayMode(display);
9872 monitor.mode.refreshRate = RGFW_osx_getRefreshRate(display, mode);
9873 CFRelease(mode);
9874
9875 CGSize screenSizeMM = CGDisplayScreenSize(display);
9876 monitor.physW = (float)screenSizeMM.width / 25.4f;
9877 monitor.physH = (float)screenSizeMM.height / 25.4f;
9878
9879 float ppi_width = (monitor.mode.area.w/monitor.physW);
9880 float ppi_height = (monitor.mode.area.h/monitor.physH);
9881
9882 monitor.pixelRatio = (float)((CGFloat (*)(id, SEL))abi_objc_msgSend_fpret) (screen, sel_registerName("backingScaleFactor"));
9883 float dpi = 96.0f * monitor.pixelRatio;
9884
9885 monitor.scaleX = ((i32)(((float) (ppi_width) / dpi) * 10.0f)) / 10.0f;
9886 monitor.scaleY = ((i32)(((float) (ppi_height) / dpi) * 10.0f)) / 10.0f;
9887
9888 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found");
9889 return monitor;
9890}
9891
9892
9893RGFW_monitor* RGFW_getMonitors(size_t* len) {
9894 static CGDirectDisplayID displays[7];
9895 u32 count;
9896
9897 if (CGGetActiveDisplayList(6, displays, &count) != kCGErrorSuccess)
9898 return NULL;
9899
9900 if (count > 6) count = 6;
9901
9902 static RGFW_monitor monitors[7];
9903
9904 u32 i;
9905 for (i = 0; i < count; i++)
9906 monitors[i] = RGFW_NSCreateMonitor(displays[i], RGFW_getNSScreenForDisplayID(displays[i]));
9907
9908 if (len != NULL) *len = count;
9909 return monitors;
9910}
9911
9912RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) {
9913 CGPoint point = { mon.x, mon.y };
9914
9915 CGDirectDisplayID display;
9916 uint32_t displayCount = 0;
9917 CGError err = CGGetDisplaysWithPoint(point, 1, &display, &displayCount);
9918 if (err != kCGErrorSuccess || displayCount != 1)
9919 return RGFW_FALSE;
9920
9921 CFArrayRef allModes = CGDisplayCopyAllDisplayModes(display, NULL);
9922
9923 if (allModes == NULL)
9924 return RGFW_FALSE;
9925
9926 CFIndex i;
9927 for (i = 0; i < CFArrayGetCount(allModes); i++) {
9928 CGDisplayModeRef cmode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, i);
9929
9930 RGFW_monitorMode foundMode;
9931 foundMode.area = RGFW_AREA(CGDisplayModeGetWidth(cmode), CGDisplayModeGetHeight(cmode));
9932 foundMode.refreshRate = RGFW_osx_getRefreshRate(display, cmode);
9933 foundMode.red = 8; foundMode.green = 8; foundMode.blue = 8;
9934
9935 if (RGFW_monitorModeCompare(mode, foundMode, request)) {
9936 if (CGDisplaySetDisplayMode(display, cmode, NULL) == kCGErrorSuccess) {
9937 CFRelease(allModes);
9938 return RGFW_TRUE;
9939 }
9940 break;
9941 }
9942 }
9943
9944 CFRelease(allModes);
9945
9946 return RGFW_FALSE;
9947}
9948
9949RGFW_monitor RGFW_getPrimaryMonitor(void) {
9950 CGDirectDisplayID primary = CGMainDisplayID();
9951 return RGFW_NSCreateMonitor(primary, RGFW_getNSScreenForDisplayID(primary));
9952}
9953
9954RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) {
9955 id screen = objc_msgSend_id(win->src.window, sel_registerName("screen"));
9956 id description = objc_msgSend_id(screen, sel_registerName("deviceDescription"));
9957 id screenNumberKey = NSString_stringWithUTF8String("NSScreenNumber");
9958 id screenNumber = objc_msgSend_id_id(description, sel_registerName("objectForKey:"), screenNumberKey);
9959
9960 CGDirectDisplayID display = (CGDirectDisplayID)objc_msgSend_uint(screenNumber, sel_registerName("unsignedIntValue"));
9961
9962 return RGFW_NSCreateMonitor(display, screen);
9963}
9964
9965RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) {
9966 size_t clip_len;
9967 char* clip = (char*)NSPasteboard_stringForType(NSPasteboard_generalPasteboard(), NSPasteboardTypeString, &clip_len);
9968 if (clip == NULL) return -1;
9969
9970 if (str != NULL) {
9971 if (strCapacity < clip_len)
9972 return 0;
9973
9974 RGFW_MEMCPY(str, clip, clip_len);
9975
9976 str[clip_len] = '\0';
9977 }
9978
9979 return (RGFW_ssize_t)clip_len;
9980}
9981
9982void RGFW_writeClipboard(const char* text, u32 textLen) {
9983 RGFW_UNUSED(textLen);
9984
9985 NSPasteboardType array[] = { NSPasteboardTypeString, NULL };
9986 NSPasteBoard_declareTypes(NSPasteboard_generalPasteboard(), array, 1, NULL);
9987
9988 SEL func = sel_registerName("setString:forType:");
9989 ((bool (*)(id, SEL, id, id))objc_msgSend)
9990 (NSPasteboard_generalPasteboard(), func, NSString_stringWithUTF8String(text), NSString_stringWithUTF8String(NSPasteboardTypeString));
9991}
9992
9993 #ifdef RGFW_OPENGL
9994 void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
9995 if (win != NULL)
9996 objc_msgSend_void(win->src.ctx, sel_registerName("makeCurrentContext"));
9997 else
9998 objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("clearCurrentContext"));
9999 }
10000 void* RGFW_getCurrent_OpenGL(void) {
10001 return objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("currentContext"));
10002 }
10003
10004 void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) {
10005 objc_msgSend_void(win->src.ctx, sel_registerName("flushBuffer"));
10006 }
10007 #endif
10008
10009 #if !defined(RGFW_EGL)
10010
10011 void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) {
10012 RGFW_ASSERT(win != NULL);
10013 #if defined(RGFW_OPENGL)
10014
10015 NSOpenGLContext_setValues((id)win->src.ctx, &swapInterval, 222);
10016 #else
10017 RGFW_UNUSED(swapInterval);
10018 #endif
10019 }
10020
10021 #endif
10022
10023void RGFW_window_swapBuffers_software(RGFW_window* win) {
10024#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
10025 RGFW_RGB_to_BGR(win, win->buffer);
10026 i32 channels = 4;
10027 id image = ((id (*)(Class, SEL))objc_msgSend)(objc_getClass("NSImage"), sel_getUid("alloc"));
10028 NSSize size = (NSSize){win->bufferSize.w, win->bufferSize.h};
10029 image = ((id (*)(id, SEL, NSSize))objc_msgSend)((id)image, sel_getUid("initWithSize:"), size);
10030
10031 id rep = NSBitmapImageRep_initWithBitmapData(&win->buffer, win->r.w, win->r.h , 8, channels, (channels == 4), false,
10032 "NSDeviceRGBColorSpace", 1 << 1, (u32)win->bufferSize.w * (u32)channels, 8 * (u32)channels);
10033 ((void (*)(id, SEL, id))objc_msgSend)((id)image, sel_getUid("addRepresentation:"), rep);
10034
10035 id contentView = ((id (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_getUid("contentView"));
10036 ((void (*)(id, SEL, BOOL))objc_msgSend)(contentView, sel_getUid("setWantsLayer:"), YES);
10037 id layer = ((id (*)(id, SEL))objc_msgSend)(contentView, sel_getUid("layer"));
10038
10039 ((void (*)(id, SEL, id))objc_msgSend)(layer, sel_getUid("setContents:"), (id)image);
10040 ((void (*)(id, SEL, BOOL))objc_msgSend)(contentView, sel_getUid("setNeedsDisplay:"), YES);
10041
10042 NSRelease(rep);
10043 NSRelease(image);
10044#else
10045 RGFW_UNUSED(win);
10046#endif
10047}
10048
10049void RGFW_deinit(void) {
10050 _RGFW.windowCount = -1;
10051 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized");
10052}
10053
10054void RGFW_window_close(RGFW_window* win) {
10055 RGFW_ASSERT(win != NULL);
10056 NSRelease(win->src.view);
10057 if ((win->_flags & RGFW_windowNoInitAPI) == 0) RGFW_window_freeOpenGL(win);
10058
10059 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
10060 if ((win->_flags & RGFW_BUFFER_ALLOC))
10061 RGFW_FREE(win->buffer);
10062 #endif
10063
10064 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized");
10065 _RGFW.windowCount--;
10066 if (_RGFW.windowCount == 0) RGFW_deinit();
10067
10068 RGFW_clipboard_switch(NULL);
10069 RGFW_FREE(win->event.droppedFiles);
10070 if ((win->_flags & RGFW_WINDOW_ALLOC)) {
10071 RGFW_FREE(win);
10072 win = NULL;
10073 }
10074}
10075
10076u64 RGFW_getTimerFreq(void) {
10077 static u64 freq = 0;
10078 if (freq == 0) {
10079 mach_timebase_info_data_t info;
10080 mach_timebase_info(&info);
10081 freq = (u64)((info.denom * 1e9) / info.numer);
10082 }
10083
10084 return freq;
10085}
10086
10087u64 RGFW_getTimerValue(void) { return (u64)mach_absolute_time(); }
10088
10089#endif /* RGFW_MACOS */
10090
10091/*
10092 End of MaOS defines
10093*/
10094
10095/*
10096 WASM defines
10097*/
10098
10099#ifdef RGFW_WASM
10100EM_BOOL Emscripten_on_resize(int eventType, const EmscriptenUiEvent* E, void* userData) {
10101 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
10102
10103 RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e._win = _RGFW.root);
10104 RGFW_windowResizedCallback(_RGFW.root, RGFW_RECT(0, 0, E->windowInnerWidth, E->windowInnerHeight));
10105 return EM_TRUE;
10106}
10107
10108EM_BOOL Emscripten_on_fullscreenchange(int eventType, const EmscriptenFullscreenChangeEvent* E, void* userData) {
10109 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
10110 static u8 fullscreen = RGFW_FALSE;
10111 static RGFW_rect ogRect;
10112
10113 if (fullscreen == RGFW_FALSE) {
10114 ogRect = _RGFW.root->r;
10115 }
10116
10117 fullscreen = !fullscreen;
10118 RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e._win = _RGFW.root);
10119 _RGFW.root->r = RGFW_RECT(0, 0, E->screenWidth, E->screenHeight);
10120
10121 EM_ASM("Module.canvas.focus();");
10122
10123 if (fullscreen == RGFW_FALSE) {
10124 _RGFW.root->r = RGFW_RECT(0, 0, ogRect.w, ogRect.h);
10125 /* emscripten_request_fullscreen("#canvas", 0); */
10126 } else {
10127 #if __EMSCRIPTEN_major__ >= 1 && __EMSCRIPTEN_minor__ >= 29 && __EMSCRIPTEN_tiny__ >= 0
10128 EmscriptenFullscreenStrategy FSStrat = {0};
10129 FSStrat.scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH; /* EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT : EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH; */
10130 FSStrat.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF;
10131 FSStrat.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT;
10132 emscripten_request_fullscreen_strategy("#canvas", 1, &FSStrat);
10133 #else
10134 emscripten_request_fullscreen("#canvas", 1);
10135 #endif
10136 }
10137
10138 emscripten_set_canvas_element_size("#canvas", _RGFW.root->r.w, _RGFW.root->r.h);
10139
10140 RGFW_windowResizedCallback(_RGFW.root, _RGFW.root->r);
10141 return EM_TRUE;
10142}
10143
10144
10145
10146EM_BOOL Emscripten_on_focusin(int eventType, const EmscriptenFocusEvent* E, void* userData) {
10147 RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(E);
10148
10149 RGFW_eventQueuePushEx(e.type = RGFW_focusIn; e._win = _RGFW.root);
10150 _RGFW.root->_flags |= RGFW_windowFocus;
10151 RGFW_focusCallback(_RGFW.root, 1);
10152
10153 if ((_RGFW.root->_flags & RGFW_HOLD_MOUSE)) RGFW_window_mouseHold(_RGFW.root, RGFW_AREA(_RGFW.root->r.w, _RGFW.root->r.h));
10154 return EM_TRUE;
10155}
10156
10157EM_BOOL Emscripten_on_focusout(int eventType, const EmscriptenFocusEvent* E, void* userData) {
10158 RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(E);
10159
10160 RGFW_eventQueuePushEx(e.type = RGFW_focusOut; e._win = _RGFW.root);
10161 RGFW_window_focusLost(_RGFW.root);
10162 RGFW_focusCallback(_RGFW.root, 0);
10163 return EM_TRUE;
10164}
10165
10166EM_BOOL Emscripten_on_mousemove(int eventType, const EmscriptenMouseEvent* E, void* userData) {
10167 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
10168 RGFW_eventQueuePushEx(e.type = RGFW_mousePosChanged;
10169 e.point = RGFW_POINT(E->targetX, E->targetY);
10170 e.vector = RGFW_POINT(E->movementX, E->movementY);
10171 e._win = _RGFW.root);
10172
10173 _RGFW.root->_lastMousePoint = RGFW_POINT(E->targetX, E->targetY);
10174 RGFW_mousePosCallback(_RGFW.root, RGFW_POINT(E->targetX, E->targetY), RGFW_POINT(E->movementX, E->movementY));
10175 return EM_TRUE;
10176}
10177
10178EM_BOOL Emscripten_on_mousedown(int eventType, const EmscriptenMouseEvent* E, void* userData) {
10179 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
10180
10181 int button = E->button;
10182 if (button > 2)
10183 button += 2;
10184
10185 RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonPressed;
10186 e.point = RGFW_POINT(E->targetX, E->targetY);
10187 e.vector = RGFW_POINT(E->movementX, E->movementY);
10188 e.button = (u8)button;
10189 e.scroll = 0;
10190 e._win = _RGFW.root);
10191 RGFW_mouseButtons[button].prev = RGFW_mouseButtons[button].current;
10192 RGFW_mouseButtons[button].current = 1;
10193
10194 RGFW_mouseButtonCallback(_RGFW.root, button, 0, 1);
10195 return EM_TRUE;
10196}
10197
10198EM_BOOL Emscripten_on_mouseup(int eventType, const EmscriptenMouseEvent* E, void* userData) {
10199 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
10200
10201 int button = E->button;
10202 if (button > 2)
10203 button += 2;
10204
10205 RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonReleased;
10206 e.point = RGFW_POINT(E->targetX, E->targetY);
10207 e.vector = RGFW_POINT(E->movementX, E->movementY);
10208 e.button = (u8)button;
10209 e.scroll = 0;
10210 e._win = _RGFW.root);
10211 RGFW_mouseButtons[button].prev = RGFW_mouseButtons[button].current;
10212 RGFW_mouseButtons[button].current = 0;
10213
10214 RGFW_mouseButtonCallback(_RGFW.root, button, 0, 0);
10215 return EM_TRUE;
10216}
10217
10218EM_BOOL Emscripten_on_wheel(int eventType, const EmscriptenWheelEvent* E, void* userData) {
10219 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
10220
10221 int button = RGFW_mouseScrollUp + (E->deltaY < 0);
10222 RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonPressed;
10223 e.button = (u8)button;
10224 e.scroll = (double)(E->deltaY < 0 ? 1 : -1);
10225 e._win = _RGFW.root);
10226 RGFW_mouseButtons[button].prev = RGFW_mouseButtons[button].current;
10227 RGFW_mouseButtons[button].current = 1;
10228 RGFW_mouseButtonCallback(_RGFW.root, button, E->deltaY < 0 ? 1 : -1, 1);
10229
10230 return EM_TRUE;
10231}
10232
10233EM_BOOL Emscripten_on_touchstart(int eventType, const EmscriptenTouchEvent* E, void* userData) {
10234 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
10235
10236 size_t i;
10237 for (i = 0; i < (size_t)E->numTouches; i++) {
10238 RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonPressed;
10239 e.point = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY);
10240 e.button = RGFW_mouseLeft;
10241 e._win = _RGFW.root);
10242
10243 RGFW_mouseButtons[RGFW_mouseLeft].prev = RGFW_mouseButtons[RGFW_mouseLeft].current;
10244 RGFW_mouseButtons[RGFW_mouseLeft].current = 1;
10245
10246 _RGFW.root->_lastMousePoint = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY);
10247 RGFW_mousePosCallback(_RGFW.root, RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY), _RGFW.root->event.vector);
10248 RGFW_mouseButtonCallback(_RGFW.root, RGFW_mouseLeft, 0, 1);
10249 }
10250
10251 return EM_TRUE;
10252}
10253EM_BOOL Emscripten_on_touchmove(int eventType, const EmscriptenTouchEvent* E, void* userData) {
10254 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
10255
10256 size_t i;
10257 for (i = 0; i < (size_t)E->numTouches; i++) {
10258 RGFW_eventQueuePushEx(e.type = RGFW_mousePosChanged;
10259 e.point = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY);
10260 e.button = RGFW_mouseLeft;
10261 e._win = _RGFW.root);
10262
10263 _RGFW.root->_lastMousePoint = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY);
10264 RGFW_mousePosCallback(_RGFW.root, RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY), _RGFW.root->event.vector);
10265 }
10266 return EM_TRUE;
10267}
10268
10269EM_BOOL Emscripten_on_touchend(int eventType, const EmscriptenTouchEvent* E, void* userData) {
10270 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
10271
10272 size_t i;
10273 for (i = 0; i < (size_t)E->numTouches; i++) {
10274 RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonReleased;
10275 e.point = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY);
10276 e.button = RGFW_mouseLeft;
10277 e._win = _RGFW.root);
10278
10279 RGFW_mouseButtons[RGFW_mouseLeft].prev = RGFW_mouseButtons[RGFW_mouseLeft].current;
10280 RGFW_mouseButtons[RGFW_mouseLeft].current = 0;
10281
10282 _RGFW.root->_lastMousePoint = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY);
10283 RGFW_mousePosCallback(_RGFW.root, RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY), _RGFW.root->event.vector);
10284 RGFW_mouseButtonCallback(_RGFW.root, RGFW_mouseLeft, 0, 0);
10285 }
10286 return EM_TRUE;
10287}
10288
10289EM_BOOL Emscripten_on_touchcancel(int eventType, const EmscriptenTouchEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); return EM_TRUE; }
10290
10291EM_BOOL Emscripten_on_gamepad(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData) {
10292 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
10293
10294 if (gamepadEvent->index >= 4)
10295 return 0;
10296
10297 size_t i = gamepadEvent->index;
10298 if (gamepadEvent->connected) {
10299 RGFW_STRNCPY(RGFW_gamepads_name[gamepadEvent->index], gamepadEvent->id, sizeof(RGFW_gamepads_name[gamepadEvent->index]) - 1);
10300 RGFW_gamepads_name[gamepadEvent->index][sizeof(RGFW_gamepads_name[gamepadEvent->index]) - 1] = '\0';
10301 RGFW_gamepads_type[i] = RGFW_gamepadUnknown;
10302 if (RGFW_STRSTR(RGFW_gamepads_name[i], "Microsoft") || RGFW_STRSTR(RGFW_gamepads_name[i], "X-Box"))
10303 RGFW_gamepads_type[i] = RGFW_gamepadMicrosoft;
10304 else if (RGFW_STRSTR(RGFW_gamepads_name[i], "PlayStation") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS3") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS4") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS5"))
10305 RGFW_gamepads_type[i] = RGFW_gamepadSony;
10306 else if (RGFW_STRSTR(RGFW_gamepads_name[i], "Nintendo"))
10307 RGFW_gamepads_type[i] = RGFW_gamepadNintendo;
10308 else if (RGFW_STRSTR(RGFW_gamepads_name[i], "Logitech"))
10309 RGFW_gamepads_type[i] = RGFW_gamepadLogitech;
10310 RGFW_gamepadCount++;
10311 } else {
10312 RGFW_gamepadCount--;
10313 }
10314
10315 RGFW_eventQueuePushEx(e.type = (RGFW_eventType)(gamepadEvent->connected ? RGFW_gamepadConnected : RGFW_gamepadConnected);
10316 e.gamepad = (u16)gamepadEvent->index;
10317 e._win = _RGFW.root);
10318
10319 RGFW_gamepadCallback(_RGFW.root, gamepadEvent->index, gamepadEvent->connected);
10320 RGFW_gamepads[gamepadEvent->index] = gamepadEvent->connected;
10321
10322 return 1; /* The event was consumed by the callback handler */
10323}
10324
10325u32 RGFW_wASMPhysicalToRGFW(u32 hash) {
10326 switch(hash) { /* 0x0000 */
10327 case 0x67243A2DU /* Escape */: return RGFW_escape; /* 0x0001 */
10328 case 0x67251058U /* Digit0 */: return RGFW_0; /* 0x0002 */
10329 case 0x67251059U /* Digit1 */: return RGFW_1; /* 0x0003 */
10330 case 0x6725105AU /* Digit2 */: return RGFW_2; /* 0x0004 */
10331 case 0x6725105BU /* Digit3 */: return RGFW_3; /* 0x0005 */
10332 case 0x6725105CU /* Digit4 */: return RGFW_4; /* 0x0006 */
10333 case 0x6725105DU /* Digit5 */: return RGFW_5; /* 0x0007 */
10334 case 0x6725105EU /* Digit6 */: return RGFW_6; /* 0x0008 */
10335 case 0x6725105FU /* Digit7 */: return RGFW_7; /* 0x0009 */
10336 case 0x67251050U /* Digit8 */: return RGFW_8; /* 0x000A */
10337 case 0x67251051U /* Digit9 */: return RGFW_9; /* 0x000B */
10338 case 0x92E14DD3U /* Minus */: return RGFW_minus; /* 0x000C */
10339 case 0x92E1FBACU /* Equal */: return RGFW_equals; /* 0x000D */
10340 case 0x36BF1CB5U /* Backspace */: return RGFW_backSpace; /* 0x000E */
10341 case 0x7B8E51E2U /* Tab */: return RGFW_tab; /* 0x000F */
10342 case 0x2C595B51U /* KeyQ */: return RGFW_q; /* 0x0010 */
10343 case 0x2C595B57U /* KeyW */: return RGFW_w; /* 0x0011 */
10344 case 0x2C595B45U /* KeyE */: return RGFW_e; /* 0x0012 */
10345 case 0x2C595B52U /* KeyR */: return RGFW_r; /* 0x0013 */
10346 case 0x2C595B54U /* KeyT */: return RGFW_t; /* 0x0014 */
10347 case 0x2C595B59U /* KeyY */: return RGFW_y; /* 0x0015 */
10348 case 0x2C595B55U /* KeyU */: return RGFW_u; /* 0x0016 */
10349 case 0x2C595B4FU /* KeyO */: return RGFW_o; /* 0x0018 */
10350 case 0x2C595B50U /* KeyP */: return RGFW_p; /* 0x0019 */
10351 case 0x45D8158CU /* BracketLeft */: return RGFW_closeBracket; /* 0x001A */
10352 case 0xDEEABF7CU /* BracketRight */: return RGFW_bracket; /* 0x001B */
10353 case 0x92E1C5D2U /* Enter */: return RGFW_return; /* 0x001C */
10354 case 0xE058958CU /* ControlLeft */: return RGFW_controlL; /* 0x001D */
10355 case 0x2C595B41U /* KeyA */: return RGFW_a; /* 0x001E */
10356 case 0x2C595B53U /* KeyS */: return RGFW_s; /* 0x001F */
10357 case 0x2C595B44U /* KeyD */: return RGFW_d; /* 0x0020 */
10358 case 0x2C595B46U /* KeyF */: return RGFW_f; /* 0x0021 */
10359 case 0x2C595B47U /* KeyG */: return RGFW_g; /* 0x0022 */
10360 case 0x2C595B48U /* KeyH */: return RGFW_h; /* 0x0023 */
10361 case 0x2C595B4AU /* KeyJ */: return RGFW_j; /* 0x0024 */
10362 case 0x2C595B4BU /* KeyK */: return RGFW_k; /* 0x0025 */
10363 case 0x2C595B4CU /* KeyL */: return RGFW_l; /* 0x0026 */
10364 case 0x2707219EU /* Semicolon */: return RGFW_semicolon; /* 0x0027 */
10365 case 0x92E0B58DU /* Quote */: return RGFW_apostrophe; /* 0x0028 */
10366 case 0x36BF358DU /* Backquote */: return RGFW_backtick; /* 0x0029 */
10367 case 0x26B1958CU /* ShiftLeft */: return RGFW_shiftL; /* 0x002A */
10368 case 0x36BF2438U /* Backslash */: return RGFW_backSlash; /* 0x002B */
10369 case 0x2C595B5AU /* KeyZ */: return RGFW_z; /* 0x002C */
10370 case 0x2C595B58U /* KeyX */: return RGFW_x; /* 0x002D */
10371 case 0x2C595B43U /* KeyC */: return RGFW_c; /* 0x002E */
10372 case 0x2C595B56U /* KeyV */: return RGFW_v; /* 0x002F */
10373 case 0x2C595B42U /* KeyB */: return RGFW_b; /* 0x0030 */
10374 case 0x2C595B4EU /* KeyN */: return RGFW_n; /* 0x0031 */
10375 case 0x2C595B4DU /* KeyM */: return RGFW_m; /* 0x0032 */
10376 case 0x92E1A1C1U /* Comma */: return RGFW_comma; /* 0x0033 */
10377 case 0x672FFAD4U /* Period */: return RGFW_period; /* 0x0034 */
10378 case 0x92E0A438U /* Slash */: return RGFW_slash; /* 0x0035 */
10379 case 0xC5A6BF7CU /* ShiftRight */: return RGFW_shiftR;
10380 case 0x5D64DA91U /* NumpadMultiply */: return RGFW_multiply;
10381 case 0xC914958CU /* AltLeft */: return RGFW_altL; /* 0x0038 */
10382 case 0x92E09CB5U /* Space */: return RGFW_space; /* 0x0039 */
10383 case 0xB8FAE73BU /* CapsLock */: return RGFW_capsLock; /* 0x003A */
10384 case 0x7174B789U /* F1 */: return RGFW_F1; /* 0x003B */
10385 case 0x7174B78AU /* F2 */: return RGFW_F2; /* 0x003C */
10386 case 0x7174B78BU /* F3 */: return RGFW_F3; /* 0x003D */
10387 case 0x7174B78CU /* F4 */: return RGFW_F4; /* 0x003E */
10388 case 0x7174B78DU /* F5 */: return RGFW_F5; /* 0x003F */
10389 case 0x7174B78EU /* F6 */: return RGFW_F6; /* 0x0040 */
10390 case 0x7174B78FU /* F7 */: return RGFW_F7; /* 0x0041 */
10391 case 0x7174B780U /* F8 */: return RGFW_F8; /* 0x0042 */
10392 case 0x7174B781U /* F9 */: return RGFW_F9; /* 0x0043 */
10393 case 0x7B8E57B0U /* F10 */: return RGFW_F10; /* 0x0044 */
10394 case 0xC925FCDFU /* Numpad7 */: return RGFW_multiply; /* 0x0047 */
10395 case 0xC925FCD0U /* Numpad8 */: return RGFW_KP_8; /* 0x0048 */
10396 case 0xC925FCD1U /* Numpad9 */: return RGFW_KP_9; /* 0x0049 */
10397 case 0x5EA3E8A4U /* NumpadSubtract */: return RGFW_minus; /* 0x004A */
10398 case 0xC925FCDCU /* Numpad4 */: return RGFW_KP_4; /* 0x004B */
10399 case 0xC925FCDDU /* Numpad5 */: return RGFW_KP_5; /* 0x004C */
10400 case 0xC925FCDEU /* Numpad6 */: return RGFW_KP_6; /* 0x004D */
10401 case 0xC925FCD9U /* Numpad1 */: return RGFW_KP_1; /* 0x004F */
10402 case 0xC925FCDAU /* Numpad2 */: return RGFW_KP_2; /* 0x0050 */
10403 case 0xC925FCDBU /* Numpad3 */: return RGFW_KP_3; /* 0x0051 */
10404 case 0xC925FCD8U /* Numpad0 */: return RGFW_KP_0; /* 0x0052 */
10405 case 0x95852DACU /* NumpadDecimal */: return RGFW_period; /* 0x0053 */
10406 case 0x7B8E57B1U /* F11 */: return RGFW_F11; /* 0x0057 */
10407 case 0x7B8E57B2U /* F12 */: return RGFW_F12; /* 0x0058 */
10408 case 0x7393FBACU /* NumpadEqual */: return RGFW_KP_Return;
10409 case 0xB88EBF7CU /* AltRight */: return RGFW_altR; /* 0xE038 */
10410 case 0xC925873BU /* NumLock */: return RGFW_numLock; /* 0xE045 */
10411 case 0x2C595F45U /* Home */: return RGFW_home; /* 0xE047 */
10412 case 0xC91BB690U /* ArrowUp */: return RGFW_up; /* 0xE048 */
10413 case 0x672F9210U /* PageUp */: return RGFW_pageUp; /* 0xE049 */
10414 case 0x3799258CU /* ArrowLeft */: return RGFW_left; /* 0xE04B */
10415 case 0x4CE33F7CU /* ArrowRight */: return RGFW_right; /* 0xE04D */
10416 case 0x7B8E55DCU /* End */: return RGFW_end; /* 0xE04F */
10417 case 0x3799379EU /* ArrowDown */: return RGFW_down; /* 0xE050 */
10418 case 0xBA90179EU /* PageDown */: return RGFW_pageDown; /* 0xE051 */
10419 case 0x6723CB2CU /* Insert */: return RGFW_insert; /* 0xE052 */
10420 case 0x6725C50DU /* Delete */: return RGFW_delete; /* 0xE053 */
10421 case 0x6723658CU /* OSLeft */: return RGFW_superL; /* 0xE05B */
10422 case 0x39643F7CU /* MetaRight */: return RGFW_superR; /* 0xE05C */
10423 }
10424
10425 return 0;
10426}
10427
10428void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyEvent(char* key, char* code, RGFW_bool press) {
10429 const char* iCode = code;
10430
10431 u32 hash = 0;
10432 while(*iCode) hash = ((hash ^ 0x7E057D79U) << 3) ^ (unsigned int)*iCode++;
10433
10434 u32 physicalKey = RGFW_wASMPhysicalToRGFW(hash);
10435
10436 u8 mappedKey = (u8)(*((u32*)key));
10437
10438 if (*((u16*)key) != mappedKey) {
10439 mappedKey = 0;
10440 if (*((u32*)key) == *((u32*)"Tab")) mappedKey = RGFW_tab;
10441 }
10442
10443 RGFW_eventQueuePushEx(e.type = (RGFW_eventType)(press ? RGFW_keyPressed : RGFW_keyReleased);
10444 e.key = (u8)physicalKey;
10445 e.keyChar = (u8)mappedKey;
10446 e.keyMod = _RGFW.root->event.keyMod;
10447 e._win = _RGFW.root);
10448
10449 RGFW_keyboard[physicalKey].prev = RGFW_keyboard[physicalKey].current;
10450 RGFW_keyboard[physicalKey].current = press;
10451
10452 RGFW_keyCallback(_RGFW.root, physicalKey, mappedKey, _RGFW.root->event.keyMod, press);
10453}
10454
10455void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyMods(RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll) {
10456 RGFW_updateKeyModsPro(_RGFW.root, capital, numlock, control, alt, shift, super, scroll);
10457}
10458
10459void EMSCRIPTEN_KEEPALIVE Emscripten_onDrop(size_t count) {
10460 if (!(_RGFW.root->_flags & RGFW_windowAllowDND))
10461 return;
10462
10463 _RGFW.root->event.droppedFilesCount = count;
10464 RGFW_eventQueuePushEx(e.type = RGFW_DND;
10465 e.droppedFilesCount = count;
10466 e._win = _RGFW.root);
10467 RGFW_dndCallback(_RGFW.root, _RGFW.root->event.droppedFiles, count);
10468}
10469
10470RGFW_bool RGFW_stopCheckEvents_bool = RGFW_FALSE;
10471void RGFW_stopCheckEvents(void) {
10472 RGFW_stopCheckEvents_bool = RGFW_TRUE;
10473}
10474
10475void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) {
10476 RGFW_UNUSED(win);
10477 if (waitMS == 0) return;
10478
10479 u32 start = (u32)(((u64)RGFW_getTimeNS()) / 1e+6);
10480
10481 while ((_RGFW.eventLen == 0) && RGFW_stopCheckEvents_bool == RGFW_FALSE && (RGFW_getTimeNS() / 1e+6) - start < waitMS)
10482 emscripten_sleep(0);
10483
10484 RGFW_stopCheckEvents_bool = RGFW_FALSE;
10485}
10486
10487void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area){
10488 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
10489 win->buffer = buffer;
10490 win->bufferSize = area;
10491 #ifdef RGFW_OSMESA
10492 win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL);
10493 OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h);
10494 OSMesaPixelStore(OSMESA_Y_UP, 0);
10495 #endif
10496 #else
10497 RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area); /*!< if buffer rendering is not being used */
10498 #endif
10499}
10500
10501void EMSCRIPTEN_KEEPALIVE RGFW_makeSetValue(size_t index, char* file) {
10502 /* This seems like a terrible idea, don't replicate this unless you hate yourself or the OS */
10503 /* TODO: find a better way to do this
10504 */
10505 RGFW_STRNCPY((char*)_RGFW.root->event.droppedFiles[index], file, RGFW_MAX_PATH - 1);
10506 _RGFW.root->event.droppedFiles[index][RGFW_MAX_PATH - 1] = '\0';
10507}
10508
10509#include <sys/stat.h>
10510#include <sys/types.h>
10511#include <errno.h>
10512#include <stdio.h>
10513
10514void EMSCRIPTEN_KEEPALIVE RGFW_mkdir(char* name) { mkdir(name, 0755); }
10515
10516void EMSCRIPTEN_KEEPALIVE RGFW_writeFile(const char *path, const char *data, size_t len) {
10517 FILE* file = fopen(path, "w+");
10518 if (file == NULL)
10519 return;
10520
10521 fwrite(data, sizeof(char), len, file);
10522 fclose(file);
10523}
10524
10525void RGFW_window_initOpenGL(RGFW_window* win) {
10526#if defined(RGFW_OPENGL) && !defined(RGFW_WEBGPU) && !defined(RGFW_OSMESA) && !defined(RGFW_BUFFER)
10527 EmscriptenWebGLContextAttributes attrs;
10528 attrs.alpha = RGFW_GL_HINTS[RGFW_glDepth];
10529 attrs.depth = RGFW_GL_HINTS[RGFW_glAlpha];
10530 attrs.stencil = RGFW_GL_HINTS[RGFW_glStencil];
10531 attrs.antialias = RGFW_GL_HINTS[RGFW_glSamples];
10532 attrs.premultipliedAlpha = EM_TRUE;
10533 attrs.preserveDrawingBuffer = EM_FALSE;
10534
10535 if (RGFW_GL_HINTS[RGFW_glDoubleBuffer] == 0)
10536 attrs.renderViaOffscreenBackBuffer = 0;
10537 else
10538 attrs.renderViaOffscreenBackBuffer = RGFW_GL_HINTS[RGFW_glAuxBuffers];
10539
10540 attrs.failIfMajorPerformanceCaveat = EM_FALSE;
10541 attrs.majorVersion = (RGFW_GL_HINTS[RGFW_glMajor] == 0) ? 1 : RGFW_GL_HINTS[RGFW_glMajor];
10542 attrs.minorVersion = RGFW_GL_HINTS[RGFW_glMinor];
10543
10544 attrs.enableExtensionsByDefault = EM_TRUE;
10545 attrs.explicitSwapControl = EM_TRUE;
10546
10547 emscripten_webgl_init_context_attributes(&attrs);
10548 win->src.ctx = emscripten_webgl_create_context("#canvas", &attrs);
10549 emscripten_webgl_make_context_current(win->src.ctx);
10550
10551 #ifdef LEGACY_GL_EMULATION
10552 EM_ASM("Module.useWebGL = true; GLImmediate.init();");
10553 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context initalized");
10554 #endif
10555 glViewport(0, 0, win->r.w, win->r.h);
10556#endif
10557}
10558
10559void RGFW_window_freeOpenGL(RGFW_window* win) {
10560#if defined(RGFW_OPENGL) && !defined(RGFW_WEBGPU) && !defined(RGFW_OSMESA) && !defined(RGFW_OSMESA)
10561 if (win->src.ctx == 0) return;
10562 emscripten_webgl_destroy_context(win->src.ctx);
10563 win->src.ctx = 0;
10564 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context freed");
10565#elif defined(RGFW_OPENGL) && defined(RGFW_OSMESA)
10566 if(win->src.ctx == 0) return;
10567 OSMesaDestroyContext(win->src.ctx);
10568 win->src.ctx = 0;
10569#else
10570 RGFW_UNUSED(win);
10571#endif
10572}
10573
10574i32 RGFW_init(void) {
10575#if defined(RGFW_C89) || defined(__cplusplus)
10576 if (_RGFW_init) return 0;
10577 _RGFW_init = RGFW_TRUE;
10578 _RGFW.root = NULL; _RGFW.current = NULL; _RGFW.windowCount = -2; _RGFW.eventLen = 0; _RGFW.eventIndex = 0;
10579#endif
10580
10581 _RGFW.windowCount = 0;
10582 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context initialized");
10583 return 0;
10584}
10585
10586RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) {
10587 RGFW_window_basic_init(win, rect, flags);
10588 RGFW_window_initOpenGL(win);
10589
10590 #if defined(RGFW_WEBGPU)
10591 win->src.ctx = wgpuCreateInstance(NULL);
10592 win->src.device = emscripten_webgpu_get_device();
10593 win->src.queue = wgpuDeviceGetQueue(win->src.device);
10594 #endif
10595
10596 emscripten_set_canvas_element_size("#canvas", rect.w, rect.h);
10597 emscripten_set_window_title(name);
10598
10599 /* load callbacks */
10600 emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_resize);
10601 emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, NULL, EM_FALSE, Emscripten_on_fullscreenchange);
10602 emscripten_set_mousemove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousemove);
10603 emscripten_set_touchstart_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchstart);
10604 emscripten_set_touchend_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchend);
10605 emscripten_set_touchmove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchmove);
10606 emscripten_set_touchcancel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchcancel);
10607 emscripten_set_mousedown_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousedown);
10608 emscripten_set_mouseup_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mouseup);
10609 emscripten_set_wheel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_wheel);
10610 emscripten_set_focusin_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusin);
10611 emscripten_set_focusout_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusout);
10612 emscripten_set_gamepadconnected_callback(NULL, 1, Emscripten_on_gamepad);
10613 emscripten_set_gamepaddisconnected_callback(NULL, 1, Emscripten_on_gamepad);
10614
10615 if (flags & RGFW_windowAllowDND) {
10616 win->_flags |= RGFW_windowAllowDND;
10617 }
10618
10619 EM_ASM({
10620 window.addEventListener("keydown",
10621 (event) => {
10622 var key = stringToNewUTF8(event.key); var code = stringToNewUTF8(event.code);
10623 Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta"), event.getModifierState("ScrollLock"));
10624 Module._RGFW_handleKeyEvent(key, code, 1);
10625 _free(key); _free(code);
10626 },
10627 true);
10628 window.addEventListener("keyup",
10629 (event) => {
10630 var key = stringToNewUTF8(event.key); var code = stringToNewUTF8(event.code);
10631 Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta"), event.getModifierState("ScrollLock"));
10632 Module._RGFW_handleKeyEvent(key, code, 0);
10633 _free(key); _free(code);
10634 },
10635 true);
10636 });
10637
10638 EM_ASM({
10639 var canvas = document.getElementById('canvas');
10640 canvas.addEventListener('drop', function(e) {
10641 e.preventDefault();
10642 if (e.dataTransfer.file < 0)
10643 return;
10644
10645 var filenamesArray = [];
10646 var count = e.dataTransfer.files.length;
10647
10648 /* Read and save the files to emscripten's files */
10649 var drop_dir = '.rgfw_dropped_files';
10650 Module._RGFW_mkdir(drop_dir);
10651
10652 for (var i = 0; i < count; i++) {
10653 var file = e.dataTransfer.files[i];
10654
10655 var path = '/' + drop_dir + '/' + file.name.replace("//", '_');
10656 var reader = new FileReader();
10657
10658 reader.onloadend = (e) => {
10659 if (reader.readyState != 2) {
10660 out('failed to read dropped file: '+file.name+': '+reader.error);
10661 }
10662 else {
10663 var data = e.target.result;
10664
10665 _RGFW_writeFile(path, new Uint8Array(data), file.size);
10666 }
10667 };
10668
10669 reader.readAsArrayBuffer(file);
10670 /* This works weird on modern opengl */
10671 var filename = stringToNewUTF8(path);
10672
10673 filenamesArray.push(filename);
10674
10675 Module._RGFW_makeSetValue(i, filename);
10676 }
10677
10678 Module._Emscripten_onDrop(count);
10679
10680 for (var i = 0; i < count; ++i) {
10681 _free(filenamesArray[i]);
10682 }
10683 }, true);
10684
10685 canvas.addEventListener('dragover', function(e) { e.preventDefault(); return false; }, true);
10686 });
10687
10688 RGFW_window_setFlags(win, flags);
10689
10690 if ((flags & RGFW_windowNoInitAPI) == 0) {
10691 RGFW_window_initBuffer(win);
10692 }
10693
10694 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created");
10695 return win;
10696}
10697
10698u8 RGFW_rgfwToKeyChar(u32 rgfw_keycode) {
10699 return (u8)rgfw_keycode; /* TODO */
10700}
10701
10702RGFW_event* RGFW_window_checkEvent(RGFW_window* win) {
10703 if (win == NULL || ((win->_flags & RGFW_windowFreeOnClose) && (win->_flags & RGFW_EVENT_QUIT))) return NULL;
10704 RGFW_event* ev = RGFW_window_checkEventCore(win);
10705 if (ev) return ev;
10706
10707 emscripten_sample_gamepad_data();
10708 /* check gamepads */
10709 int i;
10710 for (i = 0; (i < emscripten_get_num_gamepads()) && (i < 4); i++) {
10711 if (RGFW_gamepads[i] == 0)
10712 continue;
10713 EmscriptenGamepadEvent gamepadState;
10714
10715 if (emscripten_get_gamepad_status(i, &gamepadState) != EMSCRIPTEN_RESULT_SUCCESS)
10716 break;
10717
10718 /* Register buttons data for every connected gamepad */
10719 int j;
10720 for (j = 0; (j < gamepadState.numButtons) && (j < 16); j++) {
10721 u32 map[] = {
10722 RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadX, RGFW_gamepadY,
10723 RGFW_gamepadL1, RGFW_gamepadR1, RGFW_gamepadL2, RGFW_gamepadR2,
10724 RGFW_gamepadSelect, RGFW_gamepadStart,
10725 RGFW_gamepadL3, RGFW_gamepadR3,
10726 RGFW_gamepadUp, RGFW_gamepadDown, RGFW_gamepadLeft, RGFW_gamepadRight, RGFW_gamepadHome
10727 };
10728
10729
10730 u32 button = map[j];
10731 if (button == 404)
10732 continue;
10733
10734 if (RGFW_gamepadPressed[i][button].current != gamepadState.digitalButton[j]) {
10735 if (gamepadState.digitalButton[j])
10736 win->event.type = RGFW_gamepadButtonPressed;
10737 else
10738 win->event.type = RGFW_gamepadButtonReleased;
10739
10740 win->event.gamepad = i;
10741 win->event.button = map[j];
10742
10743 RGFW_gamepadPressed[i][button].prev = RGFW_gamepadPressed[i][button].current;
10744 RGFW_gamepadPressed[i][button].current = gamepadState.digitalButton[j];
10745
10746 RGFW_gamepadButtonCallback(win, win->event.gamepad, win->event.button, gamepadState.digitalButton[j]);
10747 return &win->event;
10748 }
10749 }
10750
10751 for (j = 0; (j < gamepadState.numAxes) && (j < 4); j += 2) {
10752 win->event.axisesCount = gamepadState.numAxes / 2;
10753 if (RGFW_gamepadAxes[i][(size_t)(j / 2)].x != (i8)(gamepadState.axis[j] * 100.0f) ||
10754 RGFW_gamepadAxes[i][(size_t)(j / 2)].y != (i8)(gamepadState.axis[j + 1] * 100.0f)
10755 ) {
10756
10757 RGFW_gamepadAxes[i][(size_t)(j / 2)].x = (i8)(gamepadState.axis[j] * 100.0f);
10758 RGFW_gamepadAxes[i][(size_t)(j / 2)].y = (i8)(gamepadState.axis[j + 1] * 100.0f);
10759 win->event.axis[(size_t)(j / 2)] = RGFW_gamepadAxes[i][(size_t)(j / 2)];
10760
10761 win->event.type = RGFW_gamepadAxisMove;
10762 win->event.gamepad = i;
10763 win->event.whichAxis = j / 2;
10764
10765 RGFW_gamepadAxisCallback(win, win->event.gamepad, win->event.axis, win->event.axisesCount, win->event.whichAxis);
10766 return &win->event;
10767 }
10768 }
10769 }
10770
10771 return NULL;
10772}
10773
10774void RGFW_window_resize(RGFW_window* win, RGFW_area a) {
10775 RGFW_UNUSED(win);
10776 emscripten_set_canvas_element_size("#canvas", a.w, a.h);
10777}
10778
10779/* NOTE: I don't know if this is possible */
10780void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) { RGFW_UNUSED(win); RGFW_UNUSED(v); }
10781/* this one might be possible but it looks iffy */
10782RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) { RGFW_UNUSED(channels); RGFW_UNUSED(a); RGFW_UNUSED(icon); return NULL; }
10783
10784void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) { RGFW_UNUSED(win); RGFW_UNUSED(mouse); }
10785void RGFW_freeMouse(RGFW_mouse* mouse) { RGFW_UNUSED(mouse); }
10786
10787RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) {
10788 static const char cursors[16][16] = {
10789 "default", "default", "text", "crosshair",
10790 "pointer", "ew-resize", "ns-resize", "nwse-resize", "nesw-resize",
10791 "move", "not-allowed"
10792 };
10793
10794 RGFW_UNUSED(win);
10795 EM_ASM( { document.getElementById("canvas").style.cursor = UTF8ToString($0); }, cursors[mouse]);
10796 return RGFW_TRUE;
10797}
10798
10799RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) {
10800 return RGFW_window_setMouseStandard(win, RGFW_mouseNormal);
10801}
10802
10803void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) {
10804 RGFW_window_showMouseFlags(win, show);
10805 if (show)
10806 RGFW_window_setMouseDefault(win);
10807 else
10808 EM_ASM(document.getElementById('canvas').style.cursor = 'none';);
10809}
10810
10811RGFW_point RGFW_getGlobalMousePoint(void) {
10812 RGFW_point point;
10813 point.x = EM_ASM_INT({
10814 return window.mouseX || 0;
10815 });
10816 point.y = EM_ASM_INT({
10817 return window.mouseY || 0;
10818 });
10819 return point;
10820}
10821
10822void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) {
10823 RGFW_UNUSED(win);
10824
10825 EM_ASM_({
10826 var canvas = document.getElementById('canvas');
10827 if ($0) {
10828 canvas.style.pointerEvents = 'none';
10829 } else {
10830 canvas.style.pointerEvents = 'auto';
10831 }
10832 }, passthrough);
10833}
10834
10835void RGFW_writeClipboard(const char* text, u32 textLen) {
10836 RGFW_UNUSED(textLen);
10837 EM_ASM({ navigator.clipboard.writeText(UTF8ToString($0)); }, text);
10838}
10839
10840
10841RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) {
10842 RGFW_UNUSED(str); RGFW_UNUSED(strCapacity);
10843 /*
10844 placeholder code for later
10845 I'm not sure if this is possible do the the async stuff
10846 */
10847 return 0;
10848}
10849
10850void RGFW_window_swapBuffers_software(RGFW_window* win) {
10851#if defined(RGFW_OSMESA)
10852 EM_ASM_({
10853 var data = Module.HEAPU8.slice($0, $0 + $1 * $2 * 4);
10854 let context = document.getElementById("canvas").getContext("2d");
10855 let image = context.getImageData(0, 0, $1, $2);
10856 image.data.set(data);
10857 context.putImageData(image, 0, $4 - $2);
10858 }, win->buffer, win->bufferSize.w, win->bufferSize.h, win->r.w, win->r.h);
10859#elif defined(RGFW_BUFFER)
10860 EM_ASM_({
10861 var data = Module.HEAPU8.slice($0, $0 + $1 * $2 * 4);
10862 let context = document.getElementById("canvas").getContext("2d");
10863 let image = context.getImageData(0, 0, $1, $2);
10864 image.data.set(data);
10865 context.putImageData(image, 0, 0);
10866 }, win->buffer, win->bufferSize.w, win->bufferSize.h, win->r.w, win->r.h);
10867 emscripten_sleep(0);
10868#else
10869 RGFW_UNUSED(win);
10870#endif
10871}
10872
10873void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
10874#if !defined(RGFW_WEBGPU) && !(defined(RGFW_OSMESA) || defined(RGFW_BUFFER))
10875 if (win == NULL)
10876 emscripten_webgl_make_context_current(0);
10877 else
10878 emscripten_webgl_make_context_current(win->src.ctx);
10879#endif
10880}
10881
10882
10883void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) {
10884#ifndef RGFW_WEBGPU
10885 emscripten_webgl_commit_frame();
10886
10887#endif
10888 emscripten_sleep(0);
10889}
10890
10891#ifndef RGFW_WEBGPU
10892void* RGFW_getCurrent_OpenGL(void) { return (void*)emscripten_webgl_get_current_context(); }
10893#endif
10894
10895#ifndef RGFW_EGL
10896void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { RGFW_UNUSED(win); RGFW_UNUSED(swapInterval); }
10897#endif
10898
10899void RGFW_deinit(void) { _RGFW.windowCount = -1; RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized"); }
10900
10901void RGFW_window_close(RGFW_window* win) {
10902 if ((win->_flags & RGFW_windowNoInitAPI) == 0) RGFW_window_freeOpenGL(win);
10903
10904 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
10905 if ((win->_flags & RGFW_BUFFER_ALLOC))
10906 RGFW_FREE(win->buffer);
10907 #endif
10908
10909 RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a window was freed");
10910 _RGFW.windowCount--;
10911 if (_RGFW.windowCount == 0) RGFW_deinit();
10912
10913 RGFW_clipboard_switch(NULL);
10914 RGFW_FREE(win->event.droppedFiles);
10915 if ((win->_flags & RGFW_WINDOW_ALLOC)) {
10916 RGFW_FREE(win);
10917 win = NULL;
10918 }
10919}
10920
10921int RGFW_innerWidth(void) { return EM_ASM_INT({ return window.innerWidth; }); }
10922int RGFW_innerHeight(void) { return EM_ASM_INT({ return window.innerHeight; }); }
10923
10924RGFW_area RGFW_getScreenSize(void) {
10925 return RGFW_AREA(RGFW_innerWidth(), RGFW_innerHeight());
10926}
10927
10928RGFW_bool RGFW_extensionSupportedPlatform(const char* extension, size_t len) {
10929#ifdef RGFW_OPENGL
10930 return EM_ASM_INT({
10931 var ext = UTF8ToString($0, $1);
10932 var canvas = document.querySelector('canvas');
10933 var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
10934 if (!gl) return 0;
10935
10936 var supported = gl.getSupportedExtensions();
10937 return supported && supported.includes(ext) ? 1 : 0;
10938 }, extension, len);
10939#else
10940 return RGFW_FALSE;
10941#endif
10942}
10943
10944RGFW_proc RGFW_getProcAddress(const char* procname) {
10945#ifdef RGFW_OPENGL
10946 return (RGFW_proc)emscripten_webgl_get_proc_address(procname);
10947#else
10948 return NULL
10949#endif
10950}
10951
10952void RGFW_sleep(u64 milisecond) {
10953 emscripten_sleep(milisecond);
10954}
10955
10956u64 RGFW_getTimerFreq(void) { return (u64)1000; }
10957u64 RGFW_getTimerValue(void) { return emscripten_get_now() * 1e+6; }
10958
10959void RGFW_releaseCursor(RGFW_window* win) {
10960 RGFW_UNUSED(win);
10961 emscripten_exit_pointerlock();
10962}
10963
10964void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) {
10965 RGFW_UNUSED(win); RGFW_UNUSED(r);
10966
10967 emscripten_request_pointerlock("#canvas", 1);
10968}
10969
10970
10971void RGFW_window_setName(RGFW_window* win, const char* name) {
10972 RGFW_UNUSED(win);
10973 emscripten_set_window_title(name);
10974}
10975
10976void RGFW_window_maximize(RGFW_window* win) {
10977 RGFW_ASSERT(win != NULL);
10978
10979 RGFW_area screen = RGFW_getScreenSize();
10980 RGFW_window_move(win, RGFW_POINT(0, 0));
10981 RGFW_window_resize(win, screen);
10982}
10983
10984void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) {
10985 RGFW_ASSERT(win != NULL);
10986 if (fullscreen) {
10987 win->_flags |= RGFW_windowFullscreen;
10988 EM_ASM( Module.requestFullscreen(false, true); );
10989 return;
10990 }
10991 win->_flags &= ~(u32)RGFW_windowFullscreen;
10992 EM_ASM( Module.exitFullscreen(false, true); );
10993}
10994
10995void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) {
10996 RGFW_UNUSED(win);
10997 EM_ASM({
10998 var element = document.getElementById("canvas");
10999 if (element)
11000 element.style.opacity = $1;
11001 }, "elementId", opacity);
11002}
11003
11004/* unsupported functions */
11005void RGFW_window_focus(RGFW_window* win) { RGFW_UNUSED(win); }
11006void RGFW_window_raise(RGFW_window* win) { RGFW_UNUSED(win); }
11007RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { RGFW_UNUSED(mon); RGFW_UNUSED(mode); RGFW_UNUSED(request); return RGFW_FALSE; }
11008RGFW_monitor* RGFW_getMonitors(size_t* len) { RGFW_UNUSED(len); return NULL; }
11009RGFW_monitor RGFW_getPrimaryMonitor(void) { return (RGFW_monitor){}; }
11010void RGFW_window_move(RGFW_window* win, RGFW_point v) { RGFW_UNUSED(win); RGFW_UNUSED(v); }
11011void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win); RGFW_UNUSED(a); }
11012void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win); RGFW_UNUSED(a); }
11013void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win); RGFW_UNUSED(a); }
11014void RGFW_window_minimize(RGFW_window* win) { RGFW_UNUSED(win); }
11015void RGFW_window_restore(RGFW_window* win) { RGFW_UNUSED(win); }
11016void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) { RGFW_UNUSED(win); RGFW_UNUSED(floating); }
11017void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { RGFW_UNUSED(win); RGFW_UNUSED(border); }
11018RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* icon, RGFW_area a, i32 channels, u8 type) { RGFW_UNUSED(win); RGFW_UNUSED(icon); RGFW_UNUSED(a); RGFW_UNUSED(channels); RGFW_UNUSED(type); return RGFW_FALSE; }
11019void RGFW_window_hide(RGFW_window* win) { RGFW_UNUSED(win); }
11020void RGFW_window_show(RGFW_window* win) {RGFW_UNUSED(win); }
11021RGFW_bool RGFW_window_isHidden(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; }
11022RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; }
11023RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; }
11024RGFW_bool RGFW_window_isFloating(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; }
11025RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { RGFW_UNUSED(win); return (RGFW_monitor){}; }
11026#endif
11027
11028/* end of web asm defines */
11029
11030/* unix (macOS, linux, web asm) only stuff */
11031#if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WASM) || defined(RGFW_WAYLAND)
11032#ifndef RGFW_NO_THREADS
11033#include <pthread.h>
11034
11035RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args) {
11036 RGFW_thread t;
11037 pthread_create((pthread_t*) &t, NULL, *ptr, args);
11038 return t;
11039}
11040void RGFW_cancelThread(RGFW_thread thread) { pthread_cancel((pthread_t) thread); }
11041void RGFW_joinThread(RGFW_thread thread) { pthread_join((pthread_t) thread, NULL); }
11042
11043#if defined(__linux__)
11044void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { pthread_setschedprio((pthread_t)thread, priority); }
11045#else
11046void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { RGFW_UNUSED(thread); RGFW_UNUSED(priority); }
11047#endif
11048#endif
11049
11050#ifndef RGFW_WASM
11051void RGFW_sleep(u64 ms) {
11052 struct timespec time;
11053 time.tv_sec = 0;
11054 time.tv_nsec = (long int)((double)ms * 1e+6);
11055
11056 #ifndef RGFW_NO_UNIX_CLOCK
11057 nanosleep(&time, NULL);
11058 #endif
11059}
11060#endif
11061
11062#endif /* end of unix / mac stuff */
11063#endif /* RGFW_IMPLEMENTATION */
11064
11065#if defined(__cplusplus) && !defined(__EMSCRIPTEN__)
11066}
11067#endif
11068
11069#if _MSC_VER
11070 #pragma warning( pop )
11071#endif
11072
Copyright 2026  E766CB298A6D1E64 | Git-Thing heavily inspired by cgit