aboutsummaryrefslogtreecommitdiff
path: root/raylib/src/external/RGFW.h
diff options
context:
space:
mode:
authorSebastiano Tronto <sebastiano@tronto.net>2025-04-21 11:09:56 +0200
committerSebastiano Tronto <sebastiano@tronto.net>2025-04-21 11:09:56 +0200
commit123144c93bfc77883c8fb517828b47bbe13b8671 (patch)
tree762739afedb5f3f168051367515cb9b9a06ec68d /raylib/src/external/RGFW.h
downloadminesweeper-master.tar.gz
minesweeper-master.zip
Initial commitHEADmaster
Diffstat (limited to 'raylib/src/external/RGFW.h')
-rw-r--r--raylib/src/external/RGFW.h9015
1 files changed, 9015 insertions, 0 deletions
diff --git a/raylib/src/external/RGFW.h b/raylib/src/external/RGFW.h
new file mode 100644
index 0000000..978536f
--- /dev/null
+++ b/raylib/src/external/RGFW.h
@@ -0,0 +1,9015 @@
1/*
2* Copyright (C) 2023-24 ColleagueRiley
3*
4* libpng license
5*
6* This software is provided 'as-is', without any express or implied
7* warranty. In no event will the authors be held liable for any damages
8* arising from the use of this software.
9*
10* Permission is granted to anyone to use this software for any purpose,
11* including commercial applications, and to alter it and redistribute it
12* freely, subject to the following restrictions:
13*
14* 1. The origin of this software must not be misrepresented; you must not
15* claim that you wrote the original software. If you use this software
16* in a product, an acknowledgment in the product documentation would be
17* appreciated but is not required.
18* 2. Altered source versions must be plainly marked as such, and must not be
19* misrepresented as being the original software.
20* 3. This notice may not be removed or altered from any source distribution.
21*
22*
23*/
24
25/*
26 (MAKE SURE RGFW_IMPLEMENTATION is in exactly one header or you use -D RGFW_IMPLEMENTATION)
27 #define RGFW_IMPLEMENTATION - makes it so source code is included with header
28*/
29
30/*
31 #define RGFW_IMPLEMENTATION - (required) makes it so the source code is included
32 #define RGFW_PRINT_ERRORS - (optional) makes it so RGFW prints errors when they're found
33 #define RGFW_OSMESA - (optional) use OSmesa as backend (instead of system's opengl api + regular opengl)
34 #define RGFW_BUFFER - (optional) just draw directly to (RGFW) window pixel buffer that is drawn to screen (the buffer is in the RGBA format)
35 #define RGFW_EGL - (optional) use EGL for loading an OpenGL context (instead of the system's opengl api)
36 #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)
37 This version doesn't work for desktops (I'm pretty sure)
38 #define RGFW_OPENGL_ES2 - (optional) use OpenGL ES (version 2)
39 #define RGFW_OPENGL_ES3 - (optional) use OpenGL ES (version 3)
40 #define RGFW_DIRECTX - (optional) use directX for the rendering backend (rather than opengl) (windows only, defaults to opengl for unix)
41 #define RGFW_WEBGPU - (optional) use webGPU for rendering (Web ONLY)
42 #define RGFW_NO_API - (optional) don't use any rendering API (no opengl, no vulkan, no directX)
43
44 #define RGFW_LINK_EGL (optional) (windows only) if EGL is being used, if EGL functions should be defined dymanically (using GetProcAddress)
45 #define RGFW_LINK_OSMESA (optional) (windows only) if EGL is being used, if OS Mesa functions should be defined dymanically (using GetProcAddress)
46
47 #define RGFW_X11 (optional) (unix only) if X11 should be used. This option is turned on by default by unix systems except for MacOS
48 #define RGFW_WGL_LOAD (optional) (windows only) if WGL should be loaded dynamically during runtime
49 #define RGFW_NO_X11_CURSOR (optional) (unix only) don't use XCursor
50 #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)
51
52 #define RGFW_NO_DPI - Do not include calculate DPI (no XRM nor libShcore included)
53
54 #define RGFW_ALLOC_DROPFILES (optional) if room should be allocating for drop files (by default it's global data)
55 #define RGFW_MALLOC x - choose what function to use to allocate, by default the standard malloc is used
56 #define RGFW_CALLOC x - choose what function to use to allocate (calloc), by default the standard calloc is used
57 #define RGFW_FREE x - choose what function to use to allocated memory, by default the standard free is used
58
59 #define RGFW_EXPORT - Use when building RGFW
60 #define RGFW_IMPORT - Use when linking with RGFW (not as a single-header)
61
62 #define RGFW_STD_INT - force the use stdint.h (for systems that might not have stdint.h (msvc))
63*/
64
65/*
66 Credits :
67 EimaMei/Sacode : Much of the code for creating windows using winapi, Wrote the Silicon library, helped with MacOS Support, siliapp.h -> referencing
68
69 stb - This project is heavily inspired by the stb single header files
70
71 GLFW:
72 certain parts of winapi and X11 are very poorly documented,
73 GLFW's source code was referenced and used throughout the project (used code is marked in some way),
74 this mainly includes, code for drag and drops, code for setting the icon to a bitmap and the code for managing the clipboard for X11 (as these parts are not documented very well)
75
76 GLFW Copyright, https::/github.com/GLFW/GLFW
77
78 Copyright (c) 2002-2006 Marcus Geelnard
79 Copyright (c) 2006-2019 Camilla Löwy
80
81 contributors : (feel free to put yourself here if you contribute)
82 krisvers -> code review
83 EimaMei (SaCode) -> code review
84 Code-Nycticebus -> bug fixes
85 Rob Rohan -> X11 bugs and missing features, MacOS/Cocoa fixing memory issues/bugs
86 AICDG (@THISISAGOODNAME) -> vulkan support (example)
87 @Easymode -> support, testing/debugging, bug fixes and reviews
88 Joshua Rowe (omnisci3nce) - bug fix, review (macOS)
89 @lesleyrs -> bug fix, review (OpenGL)
90 Nick Porcino (meshula) - testing, organization, review (MacOS, examples)
91*/
92
93#if _MSC_VER
94 #pragma comment(lib, "gdi32")
95 #pragma comment(lib, "shell32")
96 #pragma comment(lib, "opengl32")
97 #pragma comment(lib, "winmm")
98 #pragma comment(lib, "user32")
99#endif
100
101#ifndef RGFW_MALLOC
102 #include <stdlib.h>
103
104 #ifndef __USE_POSIX199309
105 #define __USE_POSIX199309
106 #endif
107
108 #include <time.h>
109 #define RGFW_MALLOC malloc
110 #define RGFW_CALLOC calloc
111 #define RGFW_FREE free
112#endif
113
114#if !_MSC_VER
115 #ifndef inline
116 #ifndef __APPLE__
117 #define inline __inline
118 #endif
119 #endif
120#endif
121
122#ifdef RGFW_WIN95 /* for windows 95 testing (not that it really works) */
123 #define RGFW_NO_MONITOR
124 #define RGFW_NO_PASSTHROUGH
125#endif
126
127#if defined(RGFW_EXPORT) || defined(RGFW_IMPORT)
128 #if defined(_WIN32)
129 #if defined(__TINYC__) && (defined(RGFW_EXPORT) || defined(RGFW_IMPORT))
130 #define __declspec(x) __attribute__((x))
131 #endif
132
133 #if defined(RGFW_EXPORT)
134 #define RGFWDEF __declspec(dllexport)
135 #else
136 #define RGFWDEF __declspec(dllimport)
137 #endif
138 #else
139 #if defined(RGFW_EXPORT)
140 #define RGFWDEF __attribute__((visibility("default")))
141 #endif
142 #endif
143#endif
144
145#ifndef RGFWDEF
146 #ifdef __clang__
147 #define RGFWDEF static inline
148 #else
149 #define RGFWDEF inline
150 #endif
151#endif
152
153#ifndef RGFW_ENUM
154 #define RGFW_ENUM(type, name) type name; enum
155#endif
156
157#ifndef RGFW_UNUSED
158 #define RGFW_UNUSED(x) (void)(x);
159#endif
160
161#if defined(__cplusplus) && !defined(__EMSCRIPTEN__)
162 extern "C" {
163#endif
164
165 /* makes sure the header file part is only defined once by default */
166#ifndef RGFW_HEADER
167
168#define RGFW_HEADER
169
170#if !defined(u8)
171 #if ((defined(_MSC_VER) || defined(__SYMBIAN32__)) && !defined(RGFW_STD_INT)) /* MSVC might not have stdint.h */
172 typedef unsigned char u8;
173 typedef signed char i8;
174 typedef unsigned short u16;
175 typedef signed short i16;
176 typedef unsigned int u32;
177 typedef signed int i32;
178 typedef unsigned long u64;
179 typedef signed long i64;
180 #else /* use stdint standard types instead of c ""standard"" types */
181 #include <stdint.h>
182
183 typedef uint8_t u8;
184 typedef int8_t i8;
185 typedef uint16_t u16;
186 typedef int16_t i16;
187 typedef uint32_t u32;
188 typedef int32_t i32;
189 typedef uint64_t u64;
190 typedef int64_t i64;
191 #endif
192#endif
193
194#if !defined(b8) /* RGFW bool type */
195 typedef u8 b8;
196 typedef u32 b32;
197#endif
198
199#define RGFW_TRUE (!(0))
200#define RGFW_FALSE 0
201
202/* thse OS macros looks better & are standardized */
203/* plus it helps with cross-compiling */
204
205#ifdef __EMSCRIPTEN__
206 #define RGFW_WEBASM
207
208 #if !defined(RGFW_NO_API) && !defined(RGFW_WEBGPU)
209 #define RGFW_OPENGL
210 #endif
211
212 #ifdef RGFW_EGL
213 #undef RGFW_EGL
214 #endif
215
216 #include <emscripten/html5.h>
217 #include <emscripten/key_codes.h>
218
219 #ifdef RGFW_WEBGPU
220 #include <emscripten/html5_webgpu.h>
221 #endif
222#endif
223
224#if defined(RGFW_X11) && defined(__APPLE__)
225 #define RGFW_MACOS_X11
226 #undef __APPLE__
227#endif
228
229#if defined(_WIN32) && !defined(RGFW_X11) && !defined(RGFW_WEBASM) /* (if you're using X11 on windows some how) */
230 #define RGFW_WINDOWS
231
232 /* make sure the correct architecture is defined */
233 #if defined(_WIN64)
234 #define _AMD64_
235 #undef _X86_
236 #else
237 #undef _AMD64_
238 #ifndef _X86_
239 #define _X86_
240 #endif
241 #endif
242
243 #ifndef RGFW_NO_XINPUT
244 #ifdef __MINGW32__ /* try to find the right header */
245 #include <xinput.h>
246 #else
247 #include <XInput.h>
248 #endif
249 #endif
250
251 #if defined(RGFW_DIRECTX)
252 #include <d3d11.h>
253 #include <dxgi.h>
254 #include <dxgi.h>
255 #include <d3dcompiler.h>
256
257 #ifndef __cplusplus
258 #define __uuidof(T) IID_##T
259 #endif
260 #endif
261
262#elif defined(RGFW_WAYLAND)
263 #if !defined(RGFW_NO_API) && (!defined(RGFW_BUFFER) || defined(RGFW_OPENGL))
264 #define RGFW_EGL
265 #define RGFW_OPENGL
266 #include <wayland-egl.h>
267 #endif
268
269 #include <wayland-client.h>
270#elif (defined(__unix__) || defined(RGFW_MACOS_X11) || defined(RGFW_X11)) && !defined(RGFW_WEBASM)
271 #define RGFW_MACOS_X11
272 #define RGFW_X11
273 #include <X11/Xlib.h>
274#elif defined(__APPLE__) && !defined(RGFW_MACOS_X11) && !defined(RGFW_X11) && !defined(RGFW_WEBASM)
275 #define RGFW_MACOS
276#endif
277
278#if (defined(RGFW_OPENGL_ES1) || defined(RGFW_OPENGL_ES2) || defined(RGFW_OPENGL_ES3)) && !defined(RGFW_EGL)
279 #define RGFW_EGL
280#endif
281
282#if !defined(RGFW_OSMESA) && !defined(RGFW_EGL) && !defined(RGFW_OPENGL) && !defined(RGFW_DIRECTX) && !defined(RGFW_BUFFER) && !defined(RGFW_NO_API)
283 #define RGFW_OPENGL
284#endif
285
286#ifdef RGFW_EGL
287 #include <EGL/egl.h>
288#elif defined(RGFW_OSMESA)
289 #ifndef __APPLE__
290 #include <GL/osmesa.h>
291 #else
292 #include <OpenGL/osmesa.h>
293 #endif
294#endif
295
296#if defined(RGFW_OPENGL) && defined(RGFW_X11)
297 #ifndef GLX_MESA_swap_control
298 #define GLX_MESA_swap_control
299 #endif
300 #include <GL/glx.h> /* GLX defs, xlib.h, gl.h */
301#endif
302
303#ifndef RGFW_ALPHA
304 #define RGFW_ALPHA 128 /* alpha value for RGFW_TRANSPARENT_WINDOW (WINAPI ONLY, macOS + linux don't need this) */
305#endif
306
307/*! Optional arguments for making a windows */
308#define RGFW_TRANSPARENT_WINDOW (1L<<9) /*!< the window is transparent (only properly works on X11 and MacOS, although it's although for windows) */
309#define RGFW_NO_BORDER (1L<<3) /*!< the window doesn't have border */
310#define RGFW_NO_RESIZE (1L<<4) /*!< the window cannot be resized by the user */
311#define RGFW_ALLOW_DND (1L<<5) /*!< the window supports drag and drop*/
312#define RGFW_HIDE_MOUSE (1L<<6) /*! the window should hide the mouse or not (can be toggled later on) using `RGFW_window_mouseShow*/
313#define RGFW_FULLSCREEN (1L<<8) /* the window is fullscreen by default or not */
314#define RGFW_CENTER (1L<<10) /*! center the window on the screen */
315#define RGFW_OPENGL_SOFTWARE (1L<<11) /*! use OpenGL software rendering */
316#define RGFW_COCOA_MOVE_TO_RESOURCE_DIR (1L << 12) /* (cocoa only), move to resource folder */
317#define RGFW_SCALE_TO_MONITOR (1L << 13) /* scale the window to the screen */
318#define RGFW_NO_INIT_API (1L << 2) /* DO not init an API (mostly for bindings, you should use `#define RGFW_NO_API` in C */
319
320#define RGFW_NO_GPU_RENDER (1L<<14) /* don't render (using the GPU based API)*/
321#define RGFW_NO_CPU_RENDER (1L<<15) /* don't render (using the CPU based buffer rendering)*/
322#define RGFW_WINDOW_HIDE (1L << 16)/* the window is hidden */
323
324typedef RGFW_ENUM(u8, RGFW_event_types) {
325 /*! event codes */
326 RGFW_keyPressed = 1, /* a key has been pressed */
327 RGFW_keyReleased, /*!< a key has been released*/
328 /*! key event note
329 the code of the key pressed is stored in
330 RGFW_Event.keyCode
331 !!Keycodes defined at the bottom of the RGFW_HEADER part of this file!!
332
333 while a string version is stored in
334 RGFW_Event.KeyString
335
336 RGFW_Event.lockState holds the current lockState
337 this means if CapsLock, NumLock are active or not
338 */
339 RGFW_mouseButtonPressed, /*!< a mouse button has been pressed (left,middle,right)*/
340 RGFW_mouseButtonReleased, /*!< a mouse button has been released (left,middle,right)*/
341 RGFW_mousePosChanged, /*!< the position of the mouse has been changed*/
342 /*! mouse event note
343 the x and y of the mouse can be found in the vector, RGFW_Event.point
344
345 RGFW_Event.button holds which mouse button was pressed
346 */
347 RGFW_jsButtonPressed, /*!< a joystick button was pressed */
348 RGFW_jsButtonReleased, /*!< a joystick button was released */
349 RGFW_jsAxisMove, /*!< an axis of a joystick was moved*/
350 /*! joystick event note
351 RGFW_Event.joystick holds which joystick was altered, if any
352 RGFW_Event.button holds which joystick button was pressed
353
354 RGFW_Event.axis holds the data of all the axis
355 RGFW_Event.axisCount says how many axis there are
356 */
357 RGFW_windowMoved, /*!< the window was moved (by the user) */
358 RGFW_windowResized, /*!< the window was resized (by the user), [on webASM this means the browser was resized] */
359 RGFW_focusIn, /*!< window is in focus now */
360 RGFW_focusOut, /*!< window is out of focus now */
361 RGFW_mouseEnter, /* mouse entered the window */
362 RGFW_mouseLeave, /* mouse left the window */
363 RGFW_windowRefresh, /* The window content needs to be refreshed */
364
365 /* attribs change event note
366 The event data is sent straight to the window structure
367 with win->r.x, win->r.y, win->r.w and win->r.h
368 */
369 RGFW_quit, /*!< the user clicked the quit button*/
370 RGFW_dnd, /*!< a file has been dropped into the window*/
371 RGFW_dnd_init /*!< the start of a dnd event, when the place where the file drop is known */
372 /* dnd data note
373 The x and y coords of the drop are stored in the vector RGFW_Event.point
374
375 RGFW_Event.droppedFilesCount holds how many files were dropped
376
377 This is also the size of the array which stores all the dropped file string,
378 RGFW_Event.droppedFiles
379 */
380};
381
382/*! mouse button codes (RGFW_Event.button) */
383#define RGFW_mouseLeft 1 /*!< left mouse button is pressed*/
384#define RGFW_mouseMiddle 2 /*!< mouse-wheel-button is pressed*/
385#define RGFW_mouseRight 3 /*!< right mouse button is pressed*/
386#define RGFW_mouseScrollUp 4 /*!< mouse wheel is scrolling up*/
387#define RGFW_mouseScrollDown 5 /*!< mouse wheel is scrolling down*/
388
389#ifndef RGFW_MAX_PATH
390#define RGFW_MAX_PATH 260 /* max length of a path (for dnd) */
391#endif
392#ifndef RGFW_MAX_DROPS
393#define RGFW_MAX_DROPS 260 /* max items you can drop at once */
394#endif
395
396
397/* for RGFW_Event.lockstate */
398#define RGFW_CAPSLOCK (1L << 1)
399#define RGFW_NUMLOCK (1L << 2)
400
401/*! joystick button codes (based on xbox/playstation), you may need to change these values per controller */
402#ifndef RGFW_joystick_codes
403 typedef RGFW_ENUM(u8, RGFW_joystick_codes) {
404 RGFW_JS_A = 0, /*!< or PS X button */
405 RGFW_JS_B = 1, /*!< or PS circle button */
406 RGFW_JS_Y = 2, /*!< or PS triangle button */
407 RGFW_JS_X = 3, /*!< or PS square button */
408 RGFW_JS_START = 9, /*!< start button */
409 RGFW_JS_SELECT = 8, /*!< select button */
410 RGFW_JS_HOME = 10, /*!< home button */
411 RGFW_JS_UP = 13, /*!< dpad up */
412 RGFW_JS_DOWN = 14, /*!< dpad down*/
413 RGFW_JS_LEFT = 15, /*!< dpad left */
414 RGFW_JS_RIGHT = 16, /*!< dpad right */
415 RGFW_JS_L1 = 4, /*!< left bump */
416 RGFW_JS_L2 = 5, /*!< left trigger*/
417 RGFW_JS_R1 = 6, /*!< right bumper */
418 RGFW_JS_R2 = 7, /*!< right trigger */
419 };
420#endif
421
422/*! basic vector type, if there's not already a point/vector type of choice */
423#ifndef RGFW_point
424 typedef struct { i32 x, y; } RGFW_point;
425#endif
426
427/*! basic rect type, if there's not already a rect type of choice */
428#ifndef RGFW_rect
429 typedef struct { i32 x, y, w, h; } RGFW_rect;
430#endif
431
432/*! basic area type, if there's not already a area type of choice */
433#ifndef RGFW_area
434 typedef struct { u32 w, h; } RGFW_area;
435#endif
436
437#ifndef __cplusplus
438#define RGFW_POINT(x, y) (RGFW_point){(i32)(x), (i32)(y)}
439#define RGFW_RECT(x, y, w, h) (RGFW_rect){(i32)(x), (i32)(y), (i32)(w), (i32)(h)}
440#define RGFW_AREA(w, h) (RGFW_area){(u32)(w), (u32)(h)}
441#else
442#define RGFW_POINT(x, y) {(i32)(x), (i32)(y)}
443#define RGFW_RECT(x, y, w, h) {(i32)(x), (i32)(y), (i32)(w), (i32)(h)}
444#define RGFW_AREA(w, h) {(u32)(w), (u32)(h)}
445#endif
446
447#ifndef RGFW_NO_MONITOR
448 /*! structure for monitor data */
449 typedef struct RGFW_monitor {
450 char name[128]; /*!< monitor name */
451 RGFW_rect rect; /*!< monitor Workarea */
452 float scaleX, scaleY; /*!< monitor content scale*/
453 float physW, physH; /*!< monitor physical size */
454 } RGFW_monitor;
455
456 /*
457 NOTE : Monitor functions should be ran only as many times as needed (not in a loop)
458 */
459
460 /*! get an array of all the monitors (max 6) */
461 RGFWDEF RGFW_monitor* RGFW_getMonitors(void);
462 /*! get the primary monitor */
463 RGFWDEF RGFW_monitor RGFW_getPrimaryMonitor(void);
464#endif
465
466/* NOTE: some parts of the data can represent different things based on the event (read comments in RGFW_Event struct) */
467/*! Event structure for checking/getting events */
468typedef struct RGFW_Event {
469 char keyName[16]; /*!< key name of event*/
470
471 /*! drag and drop data */
472 /* 260 max paths with a max length of 260 */
473#ifdef RGFW_ALLOC_DROPFILES
474 char** droppedFiles;
475#else
476 char droppedFiles[RGFW_MAX_DROPS][RGFW_MAX_PATH]; /*!< dropped files*/
477#endif
478 u32 droppedFilesCount; /*!< house many files were dropped */
479
480 u32 type; /*!< which event has been sent?*/
481 RGFW_point point; /*!< mouse x, y of event (or drop point) */
482
483 u8 keyCode; /*!< keycode of event !!Keycodes defined at the bottom of the RGFW_HEADER part of this file!! */
484
485 b8 repeat; /*!< key press event repeated (the key is being held) */
486 b8 inFocus; /*!< if the window is in focus or not (this is always true for MacOS windows due to the api being weird) */
487
488 u8 lockState;
489
490 u8 button; /* !< which mouse button was pressed */
491 double scroll; /*!< the raw mouse scroll value */
492
493 u16 joystick; /*! which joystick this event applies to (if applicable to any) */
494 u8 axisesCount; /*!< number of axises */
495 RGFW_point axis[2]; /*!< x, y of axises (-100 to 100) */
496
497 u64 frameTime, frameTime2; /*!< this is used for counting the fps */
498} RGFW_Event;
499
500/*! source data for the window (used by the APIs) */
501typedef struct RGFW_window_src {
502#ifdef RGFW_WINDOWS
503 HWND window; /*!< source window */
504 HDC hdc; /*!< source HDC */
505 u32 hOffset; /*!< height offset for window */
506 #if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL)
507 HGLRC ctx; /*!< source graphics context */
508 #elif defined(RGFW_OSMESA)
509 OSMesaContext ctx;
510 #elif defined(RGFW_DIRECTX)
511 IDXGISwapChain* swapchain;
512 ID3D11RenderTargetView* renderTargetView;
513 ID3D11DepthStencilView* pDepthStencilView;
514 #elif defined(RGFW_EGL)
515 EGLSurface EGL_surface;
516 EGLDisplay EGL_display;
517 EGLContext EGL_context;
518 #endif
519
520 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
521 HDC hdcMem;
522 HBITMAP bitmap;
523 #endif
524 RGFW_area maxSize, minSize; /*!< for setting max/min resize (RGFW_WINDOWS) */
525#elif defined(RGFW_X11)
526 Display* display; /*!< source display */
527 Window window; /*!< source window */
528 #if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL)
529 GLXContext ctx; /*!< source graphics context */
530 #elif defined(RGFW_OSMESA)
531 OSMesaContext ctx;
532 #elif defined(RGFW_EGL)
533 EGLSurface EGL_surface;
534 EGLDisplay EGL_display;
535 EGLContext EGL_context;
536 #endif
537
538#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
539 XImage* bitmap;
540 GC gc;
541#endif
542#elif defined(RGFW_WAYLAND)
543 struct wl_display* display;
544 struct wl_surface* surface;
545 struct wl_buffer* wl_buffer;
546 struct wl_keyboard* keyboard;
547
548 struct xdg_surface* xdg_surface;
549 struct xdg_toplevel* xdg_toplevel;
550 struct zxdg_toplevel_decoration_v1* decoration;
551 RGFW_Event events[20];
552 i32 eventLen;
553 size_t eventIndex;
554 #if defined(RGFW_EGL)
555 struct wl_egl_window* window;
556 EGLSurface EGL_surface;
557 EGLDisplay EGL_display;
558 EGLContext EGL_context;
559 #elif defined(RGFW_OSMESA)
560 OSMesaContext ctx;
561 #endif
562#elif defined(RGFW_MACOS)
563 u32 display;
564 void* displayLink;
565 void* window;
566 b8 dndPassed;
567#if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL)
568 void* ctx; /*!< source graphics context */
569#elif defined(RGFW_OSMESA)
570 OSMesaContext ctx;
571#elif defined(RGFW_EGL)
572 EGLSurface EGL_surface;
573 EGLDisplay EGL_display;
574 EGLContext EGL_context;
575#endif
576
577 void* view; /*apple viewpoint thingy*/
578
579#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
580 void* bitmap; /*!< API's bitmap for storing or managing */
581 void* image;
582#endif
583#elif defined(RGFW_WEBASM)
584 #ifdef RGFW_WEBGPU
585 WGPUInstance ctx;
586 WGPUDevice device;
587 WGPUQueue queue;
588 #else
589 EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx;
590 #endif
591#endif
592} RGFW_window_src;
593
594
595
596typedef struct RGFW_window {
597 RGFW_window_src src; /*!< src window data */
598
599#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
600 u8* buffer; /*!< buffer for non-GPU systems (OSMesa, basic software rendering) */
601 /* when rendering using RGFW_BUFFER, the buffer is in the RGBA format */
602#endif
603 void* userPtr; /* ptr for usr data */
604
605 RGFW_Event event; /*!< current event */
606
607 RGFW_rect r; /*!< the x, y, w and h of the struct */
608
609 RGFW_point _lastMousePoint; /*!< last cusor point (for raw mouse data) */
610
611 u32 _winArgs; /*!< windows args (for RGFW to check) */
612} RGFW_window; /*!< Window structure for managing the window */
613
614#if defined(RGFW_X11) || defined(RGFW_MACOS)
615 typedef u64 RGFW_thread; /*!< thread type unix */
616#else
617 typedef void* RGFW_thread; /*!< thread type for window */
618#endif
619
620/** * @defgroup Window_management
621* @{ */
622
623
624/*!
625 * the class name for X11 and WinAPI. apps with the same class will be grouped by the WM
626 * by default the class name will == the root window's name
627*/
628RGFWDEF void RGFW_setClassName(char* name);
629
630/*! this has to be set before createWindow is called, else the fulscreen size is used */
631RGFWDEF void RGFW_setBufferSize(RGFW_area size); /*!< the buffer cannot be resized (by RGFW) */
632
633RGFWDEF RGFW_window* RGFW_createWindow(
634 const char* name, /* name of the window */
635 RGFW_rect rect, /* rect of window */
636 u16 args /* extra arguments (NULL / (u16)0 means no args used)*/
637); /*!< function to create a window struct */
638
639/*! get the size of the screen to an area struct */
640RGFWDEF RGFW_area RGFW_getScreenSize(void);
641
642/*!
643 this function checks an *individual* event (and updates window structure attributes)
644 this means, using this function without a while loop may cause event lag
645
646 ex.
647
648 while (RGFW_window_checkEvent(win) != NULL) [this keeps checking events until it reaches the last one]
649
650 this function is optional if you choose to use event callbacks,
651 although you still need some way to tell RGFW to process events eg. `RGFW_window_checkEvents`
652*/
653
654RGFWDEF RGFW_Event* RGFW_window_checkEvent(RGFW_window* win); /*!< check current event (returns a pointer to win->event or NULL if there is no event)*/
655
656/*!
657 for RGFW_window_eventWait and RGFW_window_checkEvents
658 waitMS -> Allows th e function to keep checking for events even after `RGFW_window_checkEvent == NULL`
659 if waitMS == 0, the loop will not wait for events
660 if waitMS == a positive integer, the loop will wait that many miliseconds after there are no more events until it returns
661 if waitMS == a negative integer, the loop will not return until it gets another event
662*/
663typedef RGFW_ENUM(i32, RGFW_eventWait) {
664 RGFW_NEXT = -1,
665 RGFW_NO_WAIT = 0
666};
667
668/*! sleep until RGFW gets an event or the timer ends (defined by OS) */
669RGFWDEF void RGFW_window_eventWait(RGFW_window* win, i32 waitMS);
670
671/*!
672 check all the events until there are none left,
673 this should only be used if you're using callbacks only
674*/
675RGFWDEF void RGFW_window_checkEvents(RGFW_window* win, i32 waitMS);
676
677/*!
678 Tell RGFW_window_eventWait to stop waiting, to be ran from another thread
679*/
680RGFWDEF void RGFW_stopCheckEvents(void);
681
682/*! window managment functions*/
683RGFWDEF void RGFW_window_close(RGFW_window* win); /*!< close the window and free leftover data */
684
685/*! moves window to a given point */
686RGFWDEF void RGFW_window_move(RGFW_window* win,
687 RGFW_point v/*!< new pos*/
688);
689
690#ifndef RGFW_NO_MONITOR
691 /*! move to a specific monitor */
692 RGFWDEF void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m /* monitor */);
693#endif
694
695/*! resize window to a current size/area */
696RGFWDEF void RGFW_window_resize(RGFW_window* win, /*!< source window */
697 RGFW_area a/*!< new size*/
698);
699
700/*! set the minimum size a user can shrink a window to a given size/area */
701RGFWDEF void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a);
702/*! set the minimum size a user can extend a window to a given size/area */
703RGFWDEF void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a);
704
705RGFWDEF void RGFW_window_maximize(RGFW_window* win); /*!< maximize the window size */
706RGFWDEF void RGFW_window_minimize(RGFW_window* win); /*!< minimize the window (in taskbar (per OS))*/
707RGFWDEF void RGFW_window_restore(RGFW_window* win); /*!< restore the window from minimized (per OS)*/
708
709/*! if the window should have a border or not (borderless) based on bool value of `border` */
710RGFWDEF void RGFW_window_setBorder(RGFW_window* win, b8 border);
711
712/*! turn on / off dnd (RGFW_ALLOW_DND stil must be passed to the window)*/
713RGFWDEF void RGFW_window_setDND(RGFW_window* win, b8 allow);
714
715#ifndef RGFW_NO_PASSTHROUGH
716 /*!! turn on / off mouse passthrough */
717 RGFWDEF void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough);
718#endif
719
720/*! rename window to a given string */
721RGFWDEF void RGFW_window_setName(RGFW_window* win,
722 char* name
723);
724
725RGFWDEF void RGFW_window_setIcon(RGFW_window* win, /*!< source window */
726 u8* icon /*!< icon bitmap */,
727 RGFW_area a /*!< width and height of the bitmap*/,
728 i32 channels /*!< how many channels the bitmap has (rgb : 3, rgba : 4) */
729); /*!< image resized by default */
730
731/*!< sets mouse to bitmap (very simular to RGFW_window_setIcon), image NOT resized by default*/
732RGFWDEF void RGFW_window_setMouse(RGFW_window* win, u8* image, RGFW_area a, i32 channels);
733
734/*!< 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) */
735RGFWDEF void RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse);
736
737RGFWDEF void RGFW_window_setMouseDefault(RGFW_window* win); /*!< sets the mouse to the default mouse icon */
738/*
739 Locks cursor at the center of the window
740 win->event.point become raw mouse movement data
741
742 this is useful for a 3D camera
743*/
744RGFWDEF void RGFW_window_mouseHold(RGFW_window* win, RGFW_area area);
745/*! stop holding the mouse and let it move freely */
746RGFWDEF void RGFW_window_mouseUnhold(RGFW_window* win);
747
748/*! hide the window */
749RGFWDEF void RGFW_window_hide(RGFW_window* win);
750/*! show the window */
751RGFWDEF void RGFW_window_show(RGFW_window* win);
752
753/*
754 makes it so `RGFW_window_shouldClose` returns true
755 by setting the window event.type to RGFW_quit
756*/
757RGFWDEF void RGFW_window_setShouldClose(RGFW_window* win);
758
759/*! where the mouse is on the screen */
760RGFWDEF RGFW_point RGFW_getGlobalMousePoint(void);
761
762/*! where the mouse is on the window */
763RGFWDEF RGFW_point RGFW_window_getMousePoint(RGFW_window* win);
764
765/*! show the mouse or hide the mouse*/
766RGFWDEF void RGFW_window_showMouse(RGFW_window* win, i8 show);
767/*! move the mouse to a set x, y pos*/
768RGFWDEF void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v);
769
770/*! if the window should close (RGFW_close was sent or escape was pressed) */
771RGFWDEF b8 RGFW_window_shouldClose(RGFW_window* win);
772/*! if window is fullscreen'd */
773RGFWDEF b8 RGFW_window_isFullscreen(RGFW_window* win);
774/*! if window is hidden */
775RGFWDEF b8 RGFW_window_isHidden(RGFW_window* win);
776/*! if window is minimized */
777RGFWDEF b8 RGFW_window_isMinimized(RGFW_window* win);
778/*! if window is maximized */
779RGFWDEF b8 RGFW_window_isMaximized(RGFW_window* win);
780
781/** @} */
782
783/** * @defgroup Monitor
784* @{ */
785
786#ifndef RGFW_NO_MONITOR
787/*
788scale the window to the monitor,
789this is run by default if the user uses the arg `RGFW_SCALE_TO_MONITOR` during window creation
790*/
791RGFWDEF void RGFW_window_scaleToMonitor(RGFW_window* win);
792/*! get the struct of the window's monitor */
793RGFWDEF RGFW_monitor RGFW_window_getMonitor(RGFW_window* win);
794#endif
795
796/** @} */
797
798/** * @defgroup Input
799* @{ */
800
801/*error handling*/
802RGFWDEF b8 RGFW_Error(void); /*!< returns true if an error has occurred (doesn't print errors itself) */
803
804/*! returns true if the key should be shifted */
805RGFWDEF b8 RGFW_shouldShift(u32 keycode, u8 lockState);
806
807/*! get char from RGFW keycode (using a LUT), uses shift'd version if shift = true */
808RGFWDEF char RGFW_keyCodeToChar(u32 keycode, b8 shift);
809/*! get char from RGFW keycode (using a LUT), uses lockState for shouldShift) */
810RGFWDEF char RGFW_keyCodeToCharAuto(u32 keycode, u8 lockState);
811
812/*! 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.*/
813RGFWDEF b8 RGFW_isPressed(RGFW_window* win, u8 key); /*!< if key is pressed (key code)*/
814
815RGFWDEF b8 RGFW_wasPressed(RGFW_window* win, u8 key); /*!< if key was pressed (checks previous state only) (key code)*/
816
817RGFWDEF b8 RGFW_isHeld(RGFW_window* win, u8 key); /*!< if key is held (key code)*/
818RGFWDEF b8 RGFW_isReleased(RGFW_window* win, u8 key); /*!< if key is released (key code)*/
819
820/* if a key is pressed and then released, pretty much the same as RGFW_isReleased */
821RGFWDEF b8 RGFW_isClicked(RGFW_window* win, u8 key /*!< key code*/);
822
823/*! if a mouse button is pressed */
824RGFWDEF b8 RGFW_isMousePressed(RGFW_window* win, u8 button /*!< mouse button code */ );
825/*! if a mouse button is held */
826RGFWDEF b8 RGFW_isMouseHeld(RGFW_window* win, u8 button /*!< mouse button code */ );
827/*! if a mouse button was released */
828RGFWDEF b8 RGFW_isMouseReleased(RGFW_window* win, u8 button /*!< mouse button code */ );
829/*! if a mouse button was pressed (checks previous state only) */
830RGFWDEF b8 RGFW_wasMousePressed(RGFW_window* win, u8 button /*!< mouse button code */ );
831/** @} */
832
833/** * @defgroup Clipboard
834* @{ */
835RGFWDEF char* RGFW_readClipboard(size_t* size); /*!< read clipboard data */
836RGFWDEF void RGFW_clipboardFree(char* str); /*!< the string returned from RGFW_readClipboard must be freed */
837
838RGFWDEF void RGFW_writeClipboard(const char* text, u32 textLen); /*!< write text to the clipboard */
839/** @} */
840
841/**
842
843
844 Event callbacks,
845 these are completely optional, you can use the normal
846 RGFW_checkEvent() method if you prefer that
847
848* @defgroup Callbacks
849* @{
850*/
851
852/*! RGFW_windowMoved, the window and its new rect value */
853typedef void (* RGFW_windowmovefunc)(RGFW_window* win, RGFW_rect r);
854/*! RGFW_windowResized, the window and its new rect value */
855typedef void (* RGFW_windowresizefunc)(RGFW_window* win, RGFW_rect r);
856/*! RGFW_quit, the window that was closed */
857typedef void (* RGFW_windowquitfunc)(RGFW_window* win);
858/*! RGFW_focusIn / RGFW_focusOut, the window who's focus has changed and if its inFocus */
859typedef void (* RGFW_focusfunc)(RGFW_window* win, b8 inFocus);
860/*! RGFW_mouseEnter / RGFW_mouseLeave, the window that changed, the point of the mouse (enter only) and if the mouse has entered */
861typedef void (* RGFW_mouseNotifyfunc)(RGFW_window* win, RGFW_point point, b8 status);
862/*! RGFW_mousePosChanged, the window that the move happened on and the new point of the mouse */
863typedef void (* RGFW_mouseposfunc)(RGFW_window* win, RGFW_point point);
864/*! RGFW_dnd_init, the window, the point of the drop on the windows */
865typedef void (* RGFW_dndInitfunc)(RGFW_window* win, RGFW_point point);
866/*! RGFW_windowRefresh, the window that needs to be refreshed */
867typedef void (* RGFW_windowrefreshfunc)(RGFW_window* win);
868/*! RGFW_keyPressed / RGFW_keyReleased, the window that got the event, the keycode, the string version, the state of mod keys, if it was a press (else it's a release) */
869typedef void (* RGFW_keyfunc)(RGFW_window* win, u32 keycode, char keyName[16], u8 lockState, b8 pressed);
870/*! 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) */
871typedef void (* RGFW_mousebuttonfunc)(RGFW_window* win, u8 button, double scroll, b8 pressed);
872/*! RGFW_jsButtonPressed / RGFW_jsButtonReleased, the window that got the event, the button that was pressed, the scroll value, if it was a press (else it's a release) */
873typedef void (* RGFW_jsButtonfunc)(RGFW_window* win, u16 joystick, u8 button, b8 pressed);
874/*! RGFW_jsAxisMove, the window that got the event, the joystick in question, the axis values and the amount of axises */
875typedef void (* RGFW_jsAxisfunc)(RGFW_window* win, u16 joystick, RGFW_point axis[2], u8 axisesCount);
876
877
878/*! RGFW_dnd, the window that had the drop, the drop data and the amount files dropped returns previous callback function (if it was set) */
879#ifdef RGFW_ALLOC_DROPFILES
880 typedef void (* RGFW_dndfunc)(RGFW_window* win, char** droppedFiles, u32 droppedFilesCount);
881#else
882 typedef void (* RGFW_dndfunc)(RGFW_window* win, char droppedFiles[RGFW_MAX_DROPS][RGFW_MAX_PATH], u32 droppedFilesCount);
883#endif
884/*! set callback for a window move event returns previous callback function (if it was set) */
885RGFWDEF RGFW_windowmovefunc RGFW_setWindowMoveCallback(RGFW_windowmovefunc func);
886/*! set callback for a window resize event returns previous callback function (if it was set) */
887RGFWDEF RGFW_windowresizefunc RGFW_setWindowResizeCallback(RGFW_windowresizefunc func);
888/*! set callback for a window quit event returns previous callback function (if it was set) */
889RGFWDEF RGFW_windowquitfunc RGFW_setWindowQuitCallback(RGFW_windowquitfunc func);
890/*! set callback for a mouse move event returns previous callback function (if it was set) */
891RGFWDEF RGFW_mouseposfunc RGFW_setMousePosCallback(RGFW_mouseposfunc func);
892/*! set callback for a window refresh event returns previous callback function (if it was set) */
893RGFWDEF RGFW_windowrefreshfunc RGFW_setWindowRefreshCallback(RGFW_windowrefreshfunc func);
894/*! set callback for a window focus change event returns previous callback function (if it was set) */
895RGFWDEF RGFW_focusfunc RGFW_setFocusCallback(RGFW_focusfunc func);
896/*! set callback for a mouse notify event returns previous callback function (if it was set) */
897RGFWDEF RGFW_mouseNotifyfunc RGFW_setMouseNotifyCallBack(RGFW_mouseNotifyfunc func);
898/*! set callback for a drop event event returns previous callback function (if it was set) */
899RGFWDEF RGFW_dndfunc RGFW_setDndCallback(RGFW_dndfunc func);
900/*! set callback for a start of a drop event returns previous callback function (if it was set) */
901RGFWDEF RGFW_dndInitfunc RGFW_setDndInitCallback(RGFW_dndInitfunc func);
902/*! set callback for a key (press / release ) event returns previous callback function (if it was set) */
903RGFWDEF RGFW_keyfunc RGFW_setKeyCallback(RGFW_keyfunc func);
904/*! set callback for a mouse button (press / release ) event returns previous callback function (if it was set) */
905RGFWDEF RGFW_mousebuttonfunc RGFW_setMouseButtonCallback(RGFW_mousebuttonfunc func);
906/*! set callback for a controller button (press / release ) event returns previous callback function (if it was set) */
907RGFWDEF RGFW_jsButtonfunc RGFW_setjsButtonCallback(RGFW_jsButtonfunc func);
908/*! set callback for a joystick axis mov event returns previous callback function (if it was set) */
909RGFWDEF RGFW_jsAxisfunc RGFW_setjsAxisCallback(RGFW_jsAxisfunc func);
910
911/** @} */
912
913/** * @defgroup Threads
914* @{ */
915
916#ifndef RGFW_NO_THREADS
917 /*! threading functions*/
918
919 /*! 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 */
920 /*
921 I'd suggest you use sili's threading functions instead
922 if you're going to use sili
923 which is a good idea generally
924 */
925
926 #if defined(__unix__) || defined(__APPLE__) || defined(RGFW_WEBASM)
927 typedef void* (* RGFW_threadFunc_ptr)(void*);
928 #else
929 typedef DWORD (__stdcall *RGFW_threadFunc_ptr) (LPVOID lpThreadParameter);
930 #endif
931
932 RGFWDEF RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args); /*!< create a thread*/
933 RGFWDEF void RGFW_cancelThread(RGFW_thread thread); /*!< cancels a thread*/
934 RGFWDEF void RGFW_joinThread(RGFW_thread thread); /*!< join thread to current thread */
935 RGFWDEF void RGFW_setThreadPriority(RGFW_thread thread, u8 priority); /*!< sets the priority priority */
936#endif
937
938/** @} */
939
940/** * @defgroup joystick
941* @{ */
942
943/*! joystick count starts at 0*/
944/*!< register joystick to window based on a number (the number is based on when it was connected eg. /dev/js0)*/
945RGFWDEF u16 RGFW_registerJoystick(RGFW_window* win, i32 jsNumber);
946RGFWDEF u16 RGFW_registerJoystickF(RGFW_window* win, char* file);
947
948RGFWDEF u32 RGFW_isPressedJS(RGFW_window* win, u16 controller, u8 button);
949
950/** @} */
951
952/** * @defgroup graphics_API
953* @{ */
954
955/*!< make the window the current opengl drawing context
956
957 NOTE:
958 if you want to switch the graphics context's thread,
959 you have to run RGFW_window_makeCurrent(NULL); on the old thread
960 then RGFW_window_makeCurrent(valid_window) on the new thread
961*/
962RGFWDEF void RGFW_window_makeCurrent(RGFW_window* win);
963
964/*< updates fps / sets fps to cap (must by ran manually by the user at the end of a frame), returns current fps */
965RGFWDEF u32 RGFW_window_checkFPS(RGFW_window* win, u32 fpsCap);
966
967/* supports openGL, directX, OSMesa, EGL and software rendering */
968RGFWDEF void RGFW_window_swapBuffers(RGFW_window* win); /*!< swap the rendering buffer */
969RGFWDEF void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval);
970
971RGFWDEF void RGFW_window_setGPURender(RGFW_window* win, i8 set);
972RGFWDEF void RGFW_window_setCPURender(RGFW_window* win, i8 set);
973
974/*! native API functions */
975#if defined(RGFW_OPENGL) || defined(RGFW_EGL)
976 /*! OpenGL init hints */
977 RGFWDEF void RGFW_setGLStencil(i32 stencil); /*!< set stencil buffer bit size (8 by default) */
978 RGFWDEF void RGFW_setGLSamples(i32 samples); /*!< set number of sampiling buffers (4 by default) */
979 RGFWDEF void RGFW_setGLStereo(i32 stereo); /*!< use GL_STEREO (GL_FALSE by default) */
980 RGFWDEF void RGFW_setGLAuxBuffers(i32 auxBuffers); /*!< number of aux buffers (0 by default) */
981
982 /*! which profile to use for the opengl verion */
983 typedef RGFW_ENUM(u8, RGFW_GL_profile) { RGFW_GL_CORE = 0, RGFW_GL_COMPATIBILITY };
984 /*! Set OpenGL version hint (core or compatibility profile)*/
985 RGFWDEF void RGFW_setGLVersion(RGFW_GL_profile profile, i32 major, i32 minor);
986 RGFWDEF void RGFW_setDoubleBuffer(b8 useDoubleBuffer);
987 RGFWDEF void* RGFW_getProcAddress(const char* procname); /*!< get native opengl proc address */
988 RGFWDEF void RGFW_window_makeCurrent_OpenGL(RGFW_window* win); /*!< to be called by RGFW_window_makeCurrent */
989#elif defined(RGFW_DIRECTX)
990 typedef struct {
991 IDXGIFactory* pFactory;
992 IDXGIAdapter* pAdapter;
993 ID3D11Device* pDevice;
994 ID3D11DeviceContext* pDeviceContext;
995 } RGFW_directXinfo;
996
997 /*
998 RGFW stores a global instance of RGFW_directXinfo,
999 you can use this function to get a pointer the instance
1000 */
1001 RGFWDEF RGFW_directXinfo* RGFW_getDirectXInfo(void);
1002#endif
1003
1004/** @} */
1005
1006/** * @defgroup Supporting
1007* @{ */
1008RGFWDEF u64 RGFW_getTime(void); /*!< get time in seconds */
1009RGFWDEF u64 RGFW_getTimeNS(void); /*!< get time in nanoseconds */
1010RGFWDEF void RGFW_sleep(u64 milisecond); /*!< sleep for a set time */
1011
1012/*!
1013 key codes and mouse icon enums
1014*/
1015
1016typedef RGFW_ENUM(u8, RGFW_Key) {
1017 RGFW_KEY_NULL = 0,
1018 RGFW_Escape,
1019 RGFW_F1,
1020 RGFW_F2,
1021 RGFW_F3,
1022 RGFW_F4,
1023 RGFW_F5,
1024 RGFW_F6,
1025 RGFW_F7,
1026 RGFW_F8,
1027 RGFW_F9,
1028 RGFW_F10,
1029 RGFW_F11,
1030 RGFW_F12,
1031
1032 RGFW_Backtick,
1033
1034 RGFW_0,
1035 RGFW_1,
1036 RGFW_2,
1037 RGFW_3,
1038 RGFW_4,
1039 RGFW_5,
1040 RGFW_6,
1041 RGFW_7,
1042 RGFW_8,
1043 RGFW_9,
1044
1045 RGFW_Minus,
1046 RGFW_Equals,
1047 RGFW_BackSpace,
1048 RGFW_Tab,
1049 RGFW_CapsLock,
1050 RGFW_ShiftL,
1051 RGFW_ControlL,
1052 RGFW_AltL,
1053 RGFW_SuperL,
1054 RGFW_ShiftR,
1055 RGFW_ControlR,
1056 RGFW_AltR,
1057 RGFW_SuperR,
1058 RGFW_Space,
1059
1060 RGFW_a,
1061 RGFW_b,
1062 RGFW_c,
1063 RGFW_d,
1064 RGFW_e,
1065 RGFW_f,
1066 RGFW_g,
1067 RGFW_h,
1068 RGFW_i,
1069 RGFW_j,
1070 RGFW_k,
1071 RGFW_l,
1072 RGFW_m,
1073 RGFW_n,
1074 RGFW_o,
1075 RGFW_p,
1076 RGFW_q,
1077 RGFW_r,
1078 RGFW_s,
1079 RGFW_t,
1080 RGFW_u,
1081 RGFW_v,
1082 RGFW_w,
1083 RGFW_x,
1084 RGFW_y,
1085 RGFW_z,
1086
1087 RGFW_Period,
1088 RGFW_Comma,
1089 RGFW_Slash,
1090 RGFW_Bracket,
1091 RGFW_CloseBracket,
1092 RGFW_Semicolon,
1093 RGFW_Return,
1094 RGFW_Quote,
1095 RGFW_BackSlash,
1096
1097 RGFW_Up,
1098 RGFW_Down,
1099 RGFW_Left,
1100 RGFW_Right,
1101
1102 RGFW_Delete,
1103 RGFW_Insert,
1104 RGFW_End,
1105 RGFW_Home,
1106 RGFW_PageUp,
1107 RGFW_PageDown,
1108
1109 RGFW_Numlock,
1110 RGFW_KP_Slash,
1111 RGFW_Multiply,
1112 RGFW_KP_Minus,
1113 RGFW_KP_1,
1114 RGFW_KP_2,
1115 RGFW_KP_3,
1116 RGFW_KP_4,
1117 RGFW_KP_5,
1118 RGFW_KP_6,
1119 RGFW_KP_7,
1120 RGFW_KP_8,
1121 RGFW_KP_9,
1122 RGFW_KP_0,
1123 RGFW_KP_Period,
1124 RGFW_KP_Return,
1125
1126 final_key,
1127};
1128
1129
1130typedef RGFW_ENUM(u8, RGFW_mouseIcons) {
1131 RGFW_MOUSE_NORMAL = 0,
1132 RGFW_MOUSE_ARROW,
1133 RGFW_MOUSE_IBEAM,
1134 RGFW_MOUSE_CROSSHAIR,
1135 RGFW_MOUSE_POINTING_HAND,
1136 RGFW_MOUSE_RESIZE_EW,
1137 RGFW_MOUSE_RESIZE_NS,
1138 RGFW_MOUSE_RESIZE_NWSE,
1139 RGFW_MOUSE_RESIZE_NESW,
1140 RGFW_MOUSE_RESIZE_ALL,
1141 RGFW_MOUSE_NOT_ALLOWED,
1142};
1143
1144/** @} */
1145
1146#endif /* RGFW_HEADER */
1147
1148/*
1149Example to get you started :
1150
1151linux : gcc main.c -lX11 -lXcursor -lGL
1152windows : gcc main.c -lopengl32 -lshell32 -lgdi32
1153macos : gcc main.c -framework Foundation -framework AppKit -framework OpenGL -framework CoreVideo
1154
1155#define RGFW_IMPLEMENTATION
1156#include "RGFW.h"
1157
1158u8 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};
1159
1160int main() {
1161 RGFW_window* win = RGFW_createWindow("name", RGFW_RECT(500, 500, 500, 500), (u64)0);
1162
1163 RGFW_window_setIcon(win, icon, RGFW_AREA(3, 3), 4);
1164
1165 for (;;) {
1166 RGFW_window_checkEvent(win); // NOTE: checking events outside of a while loop may cause input lag
1167 if (win->event.type == RGFW_quit || RGFW_isPressed(win, RGFW_Escape))
1168 break;
1169
1170 RGFW_window_swapBuffers(win);
1171
1172 glClearColor(0xFF, 0XFF, 0xFF, 0xFF);
1173 glClear(GL_COLOR_BUFFER_BIT);
1174 }
1175
1176 RGFW_window_close(win);
1177}
1178
1179 compiling :
1180
1181 if you wish to compile the library all you have to do is create a new file with this in it
1182
1183 rgfw.c
1184 #define RGFW_IMPLEMENTATION
1185 #include "RGFW.h"
1186
1187 then you can use gcc (or whatever compile you wish to use) to compile the library into object file
1188
1189 ex. gcc -c RGFW.c -fPIC
1190
1191 after you compile the library into an object file, you can also turn the object file into an static or shared library
1192
1193 (commands ar and gcc can be replaced with whatever equivalent your system uses)
1194 static : ar rcs RGFW.a RGFW.o
1195 shared :
1196 windows:
1197 gcc -shared RGFW.o -lwinmm -lopengl32 -lshell32 -lgdi32 -o RGFW.dll
1198 linux:
1199 gcc -shared RGFW.o -lX11 -lXcursor -lGL -lXrandr -o RGFW.so
1200 macos:
1201 gcc -shared RGFW.o -framework Foundation -framework AppKit -framework OpenGL -framework CoreVideo
1202*/
1203
1204#ifdef RGFW_X11
1205 #define RGFW_OS_BASED_VALUE(l, w, m, h, ww) l
1206#elif defined(RGFW_WINDOWS)
1207 #define RGFW_OS_BASED_VALUE(l, w, m, h, ww) w
1208#elif defined(RGFW_MACOS)
1209 #define RGFW_OS_BASED_VALUE(l, w, m, h, ww) m
1210#elif defined(RGFW_WEBASM)
1211 #define RGFW_OS_BASED_VALUE(l, w, m, h, ww) h
1212#elif defined(RGFW_WAYLAND)
1213 #define RGFW_OS_BASED_VALUE(l, w, m, h, ww) ww
1214#endif
1215
1216
1217#ifdef RGFW_IMPLEMENTATION
1218
1219#include <stdio.h>
1220#include <string.h>
1221#include <math.h>
1222#include <assert.h>
1223
1224/*
1225RGFW_IMPLEMENTATION starts with generic RGFW defines
1226
1227This is the start of keycode data
1228
1229 Why not use macros instead of the numbers itself?
1230 Windows -> Not all virtual keys are macros (VK_0 - VK_1, VK_a - VK_z)
1231 Linux -> Only symcodes are values, (XK_0 - XK_1, XK_a - XK_z) are larger than 0xFF00, I can't find any way to work with them without making the array an unreasonable size
1232 MacOS -> windows and linux already don't have keycodes as macros, so there's no point
1233*/
1234
1235
1236
1237/*
1238 the c++ compiler doesn't support setting up an array like,
1239 we'll have to do it during runtime using a function & this messy setup
1240*/
1241#ifndef __cplusplus
1242#define RGFW_NEXT ,
1243#define RGFW_MAP
1244#else
1245#define RGFW_NEXT ;
1246#define RGFW_MAP RGFW_keycodes
1247#endif
1248
1249#ifdef RGFW_WAYLAND
1250#include <linux/input-event-codes.h>
1251#endif
1252
1253u8 RGFW_keycodes [RGFW_OS_BASED_VALUE(136, 337, 128, DOM_VK_WIN_OEM_CLEAR + 1, 130)] = {
1254#ifdef __cplusplus
1255 0
1256};
1257void RGFW_init_keys(void) {
1258#endif
1259 RGFW_MAP [RGFW_OS_BASED_VALUE(49, 192, 50, DOM_VK_BACK_QUOTE, KEY_GRAVE)] = RGFW_Backtick RGFW_NEXT
1260
1261 RGFW_MAP [RGFW_OS_BASED_VALUE(19, 0x30, 29, DOM_VK_0, KEY_0)] = RGFW_0 RGFW_NEXT
1262 RGFW_MAP [RGFW_OS_BASED_VALUE(10, 0x31, 18, DOM_VK_1, KEY_1)] = RGFW_1 RGFW_NEXT
1263 RGFW_MAP [RGFW_OS_BASED_VALUE(11, 0x32, 19, DOM_VK_2, KEY_2)] = RGFW_2 RGFW_NEXT
1264 RGFW_MAP [RGFW_OS_BASED_VALUE(12, 0x33, 20, DOM_VK_3, KEY_3)] = RGFW_3 RGFW_NEXT
1265 RGFW_MAP [RGFW_OS_BASED_VALUE(13, 0x34, 21, DOM_VK_4, KEY_4)] = RGFW_4 RGFW_NEXT
1266 RGFW_MAP [RGFW_OS_BASED_VALUE(14, 0x35, 23, DOM_VK_5, KEY_5)] = RGFW_5 RGFW_NEXT
1267 RGFW_MAP [RGFW_OS_BASED_VALUE(15, 0x36, 22, DOM_VK_6, KEY_6)] = RGFW_6 RGFW_NEXT
1268 RGFW_MAP [RGFW_OS_BASED_VALUE(16, 0x37, 26, DOM_VK_7, KEY_7)] = RGFW_7 RGFW_NEXT
1269 RGFW_MAP [RGFW_OS_BASED_VALUE(17, 0x38, 28, DOM_VK_8, KEY_8)] = RGFW_8 RGFW_NEXT
1270 RGFW_MAP [RGFW_OS_BASED_VALUE(18, 0x39, 25, DOM_VK_9, KEY_9)] = RGFW_9,
1271
1272 RGFW_MAP [RGFW_OS_BASED_VALUE(65, 0x20, 49, DOM_VK_SPACE, KEY_SPACE)] = RGFW_Space,
1273
1274 RGFW_MAP [RGFW_OS_BASED_VALUE(38, 0x41, 0, DOM_VK_A, KEY_A)] = RGFW_a RGFW_NEXT
1275 RGFW_MAP [RGFW_OS_BASED_VALUE(56, 0x42, 11, DOM_VK_B, KEY_B)] = RGFW_b RGFW_NEXT
1276 RGFW_MAP [RGFW_OS_BASED_VALUE(54, 0x43, 8, DOM_VK_C, KEY_C)] = RGFW_c RGFW_NEXT
1277 RGFW_MAP [RGFW_OS_BASED_VALUE(40, 0x44, 2, DOM_VK_D, KEY_D)] = RGFW_d RGFW_NEXT
1278 RGFW_MAP [RGFW_OS_BASED_VALUE(26, 0x45, 14, DOM_VK_E, KEY_E)] = RGFW_e RGFW_NEXT
1279 RGFW_MAP [RGFW_OS_BASED_VALUE(41, 0x46, 3, DOM_VK_F, KEY_F)] = RGFW_f RGFW_NEXT
1280 RGFW_MAP [RGFW_OS_BASED_VALUE(42, 0x47, 5, DOM_VK_G, KEY_G)] = RGFW_g RGFW_NEXT
1281 RGFW_MAP [RGFW_OS_BASED_VALUE(43, 0x48, 4, DOM_VK_H, KEY_H)] = RGFW_h RGFW_NEXT
1282 RGFW_MAP [RGFW_OS_BASED_VALUE(31, 0x49, 34, DOM_VK_I, KEY_I)] = RGFW_i RGFW_NEXT
1283 RGFW_MAP [RGFW_OS_BASED_VALUE(44, 0x4A, 38, DOM_VK_J, KEY_J)] = RGFW_j RGFW_NEXT
1284 RGFW_MAP [RGFW_OS_BASED_VALUE(45, 0x4B, 40, DOM_VK_K, KEY_K)] = RGFW_k RGFW_NEXT
1285 RGFW_MAP [RGFW_OS_BASED_VALUE(46, 0x4C, 37, DOM_VK_L, KEY_L)] = RGFW_l RGFW_NEXT
1286 RGFW_MAP [RGFW_OS_BASED_VALUE(58, 0x4D, 46, DOM_VK_M, KEY_M)] = RGFW_m RGFW_NEXT
1287 RGFW_MAP [RGFW_OS_BASED_VALUE(57, 0x4E, 45, DOM_VK_N, KEY_N)] = RGFW_n RGFW_NEXT
1288 RGFW_MAP [RGFW_OS_BASED_VALUE(32, 0x4F, 31, DOM_VK_O, KEY_O)] = RGFW_o RGFW_NEXT
1289 RGFW_MAP [RGFW_OS_BASED_VALUE(33, 0x50, 35, DOM_VK_P, KEY_P)] = RGFW_p RGFW_NEXT
1290 RGFW_MAP [RGFW_OS_BASED_VALUE(24, 0x51, 12, DOM_VK_Q, KEY_Q)] = RGFW_q RGFW_NEXT
1291 RGFW_MAP [RGFW_OS_BASED_VALUE(27, 0x52, 15, DOM_VK_R, KEY_R)] = RGFW_r RGFW_NEXT
1292 RGFW_MAP [RGFW_OS_BASED_VALUE(39, 0x53, 1, DOM_VK_S, KEY_S)] = RGFW_s RGFW_NEXT
1293 RGFW_MAP [RGFW_OS_BASED_VALUE(28, 0x54, 17, DOM_VK_T, KEY_T)] = RGFW_t RGFW_NEXT
1294 RGFW_MAP [RGFW_OS_BASED_VALUE(30, 0x55, 32, DOM_VK_U, KEY_U)] = RGFW_u RGFW_NEXT
1295 RGFW_MAP [RGFW_OS_BASED_VALUE(55, 0x56, 9, DOM_VK_V, KEY_V)] = RGFW_v RGFW_NEXT
1296 RGFW_MAP [RGFW_OS_BASED_VALUE(25, 0x57, 13, DOM_VK_W, KEY_W)] = RGFW_w RGFW_NEXT
1297 RGFW_MAP [RGFW_OS_BASED_VALUE(53, 0x58, 7, DOM_VK_X, KEY_X)] = RGFW_x RGFW_NEXT
1298 RGFW_MAP [RGFW_OS_BASED_VALUE(29, 0x59, 16, DOM_VK_Y, KEY_Y)] = RGFW_y RGFW_NEXT
1299 RGFW_MAP [RGFW_OS_BASED_VALUE(52, 0x5A, 6, DOM_VK_Z, KEY_Z)] = RGFW_z,
1300
1301 RGFW_MAP [RGFW_OS_BASED_VALUE(60, 190, 47, DOM_VK_PERIOD, KEY_DOT)] = RGFW_Period RGFW_NEXT
1302 RGFW_MAP [RGFW_OS_BASED_VALUE(59, 188, 43, DOM_VK_COMMA, KEY_COMMA)] = RGFW_Comma RGFW_NEXT
1303 RGFW_MAP [RGFW_OS_BASED_VALUE(61, 191, 44, DOM_VK_SLASH, KEY_SLASH)] = RGFW_Slash RGFW_NEXT
1304 RGFW_MAP [RGFW_OS_BASED_VALUE(34, 219, 33, DOM_VK_OPEN_BRACKET, KEY_LEFTBRACE)] = RGFW_Bracket RGFW_NEXT
1305 RGFW_MAP [RGFW_OS_BASED_VALUE(35, 221, 30, DOM_VK_CLOSE_BRACKET, KEY_RIGHTBRACE)] = RGFW_CloseBracket RGFW_NEXT
1306 RGFW_MAP [RGFW_OS_BASED_VALUE(47, 186, 41, DOM_VK_SEMICOLON, KEY_SEMICOLON)] = RGFW_Semicolon RGFW_NEXT
1307 RGFW_MAP [RGFW_OS_BASED_VALUE(48, 222, 39, DOM_VK_QUOTE, KEY_APOSTROPHE)] = RGFW_Quote RGFW_NEXT
1308 RGFW_MAP [RGFW_OS_BASED_VALUE(51, 322, 42, DOM_VK_BACK_SLASH, KEY_BACKSLASH)] = RGFW_BackSlash,
1309
1310 RGFW_MAP [RGFW_OS_BASED_VALUE(36, 0x0D, 36, DOM_VK_RETURN, KEY_ENTER)] = RGFW_Return RGFW_NEXT
1311 RGFW_MAP [RGFW_OS_BASED_VALUE(119, 0x2E, 118, DOM_VK_DELETE, KEY_DELETE)] = RGFW_Delete RGFW_NEXT
1312 RGFW_MAP [RGFW_OS_BASED_VALUE(77, 0x90, 72, DOM_VK_NUM_LOCK, KEY_NUMLOCK)] = RGFW_Numlock RGFW_NEXT
1313 RGFW_MAP [RGFW_OS_BASED_VALUE(106, 0x6F, 82, DOM_VK_DIVIDE, KEY_KPSLASH)] = RGFW_KP_Slash RGFW_NEXT
1314 RGFW_MAP [RGFW_OS_BASED_VALUE(63, 0x6A, 76, DOM_VK_MULTIPLY, KEY_KPASTERISK)] = RGFW_Multiply RGFW_NEXT
1315 RGFW_MAP [RGFW_OS_BASED_VALUE(82, 0x6D, 67, DOM_VK_SUBTRACT, KEY_KPMINUS)] = RGFW_KP_Minus RGFW_NEXT
1316 RGFW_MAP [RGFW_OS_BASED_VALUE(87, 0x61, 84, DOM_VK_NUMPAD1, KEY_KP1)] = RGFW_KP_1 RGFW_NEXT
1317 RGFW_MAP [RGFW_OS_BASED_VALUE(88, 0x62, 85, DOM_VK_NUMPAD2, KEY_KP2)] = RGFW_KP_2 RGFW_NEXT
1318 RGFW_MAP [RGFW_OS_BASED_VALUE(89, 0x63, 86, DOM_VK_NUMPAD3, KEY_KP3)] = RGFW_KP_3 RGFW_NEXT
1319 RGFW_MAP [RGFW_OS_BASED_VALUE(83, 0x64, 87, DOM_VK_NUMPAD4, KEY_KP4)] = RGFW_KP_4 RGFW_NEXT
1320 RGFW_MAP [RGFW_OS_BASED_VALUE(84, 0x65, 88, DOM_VK_NUMPAD5, KEY_KP5)] = RGFW_KP_5 RGFW_NEXT
1321 RGFW_MAP [RGFW_OS_BASED_VALUE(85, 0x66, 89, DOM_VK_NUMPAD6, KEY_KP6)] = RGFW_KP_6 RGFW_NEXT
1322 RGFW_MAP [RGFW_OS_BASED_VALUE(79, 0x67, 90, DOM_VK_NUMPAD7, KEY_KP7)] = RGFW_KP_7 RGFW_NEXT
1323 RGFW_MAP [RGFW_OS_BASED_VALUE(80, 0x68, 92, DOM_VK_NUMPAD8, KEY_KP8)] = RGFW_KP_8 RGFW_NEXT
1324 RGFW_MAP [RGFW_OS_BASED_VALUE(81, 0x69, 93, DOM_VK_NUMPAD9, KEY_KP9)] = RGFW_KP_9 RGFW_NEXT
1325 RGFW_MAP [RGFW_OS_BASED_VALUE(90, 0x60, 83, DOM_VK_NUMPAD0, KEY_KP0)] = RGFW_KP_0 RGFW_NEXT
1326 RGFW_MAP [RGFW_OS_BASED_VALUE(91, 0x6E, 65, DOM_VK_DECIMAL, KEY_KPDOT)] = RGFW_KP_Period RGFW_NEXT
1327 RGFW_MAP [RGFW_OS_BASED_VALUE(104, 0x92, 77, 0, KEY_KPENTER)] = RGFW_KP_Return,
1328
1329 RGFW_MAP [RGFW_OS_BASED_VALUE(20, 189, 27, DOM_VK_HYPHEN_MINUS, KEY_MINUS)] = RGFW_Minus RGFW_NEXT
1330 RGFW_MAP [RGFW_OS_BASED_VALUE(21, 187, 24, DOM_VK_EQUALS, KEY_EQUAL)] = RGFW_Equals RGFW_NEXT
1331 RGFW_MAP [RGFW_OS_BASED_VALUE(22, 8, 51, DOM_VK_BACK_SPACE, KEY_BACKSPACE)] = RGFW_BackSpace RGFW_NEXT
1332 RGFW_MAP [RGFW_OS_BASED_VALUE(23, 0x09, 48, DOM_VK_TAB, KEY_TAB)] = RGFW_Tab RGFW_NEXT
1333 RGFW_MAP [RGFW_OS_BASED_VALUE(66, 20, 57, DOM_VK_CAPS_LOCK, KEY_CAPSLOCK)] = RGFW_CapsLock RGFW_NEXT
1334 RGFW_MAP [RGFW_OS_BASED_VALUE(50, 0x10, 56, DOM_VK_SHIFT, KEY_LEFTSHIFT)] = RGFW_ShiftL RGFW_NEXT
1335 RGFW_MAP [RGFW_OS_BASED_VALUE(37, 0x11, 59, DOM_VK_CONTROL, KEY_LEFTCTRL)] = RGFW_ControlL RGFW_NEXT
1336 RGFW_MAP [RGFW_OS_BASED_VALUE(64,0x12, 58, DOM_VK_ALT, KEY_LEFTALT)] = RGFW_AltL RGFW_NEXT
1337 RGFW_MAP [RGFW_OS_BASED_VALUE(133, 0x5B, 55, DOM_VK_WIN, KEY_LEFTMETA)] = RGFW_SuperL,
1338
1339 #if !defined(RGFW_WINDOWS) && !defined(RGFW_MACOS) && !defined(RGFW_WEBASM)
1340 RGFW_MAP [RGFW_OS_BASED_VALUE(105, 0x11, 59, 0, KEY_RIGHTCTRL)] = RGFW_ControlR RGFW_NEXT
1341 RGFW_MAP [RGFW_OS_BASED_VALUE(135, 0xA4, 55, 0, KEY_RIGHTMETA)] = RGFW_SuperR,
1342 RGFW_MAP [RGFW_OS_BASED_VALUE(62, 0x5C, 56, 0, KEY_RIGHTSHIFT)] = RGFW_ShiftR RGFW_NEXT
1343 RGFW_MAP [RGFW_OS_BASED_VALUE(108, 165, 58, 0, KEY_RIGHTALT)] = RGFW_AltR,
1344 #endif
1345
1346 RGFW_MAP [RGFW_OS_BASED_VALUE(67, 0x70, 127, DOM_VK_F1, KEY_F1)] = RGFW_F1 RGFW_NEXT
1347 RGFW_MAP [RGFW_OS_BASED_VALUE(68, 0x71, 121, DOM_VK_F2, KEY_F2)] = RGFW_F2 RGFW_NEXT
1348 RGFW_MAP [RGFW_OS_BASED_VALUE(69, 0x72, 100, DOM_VK_F3, KEY_F3)] = RGFW_F3 RGFW_NEXT
1349 RGFW_MAP [RGFW_OS_BASED_VALUE(70, 0x73, 119, DOM_VK_F4, KEY_F4)] = RGFW_F4 RGFW_NEXT
1350 RGFW_MAP [RGFW_OS_BASED_VALUE(71, 0x74, 97, DOM_VK_F5, KEY_F5)] = RGFW_F5 RGFW_NEXT
1351 RGFW_MAP [RGFW_OS_BASED_VALUE(72, 0x75, 98, DOM_VK_F6, KEY_F6)] = RGFW_F6 RGFW_NEXT
1352 RGFW_MAP [RGFW_OS_BASED_VALUE(73, 0x76, 99, DOM_VK_F7, KEY_F7)] = RGFW_F7 RGFW_NEXT
1353 RGFW_MAP [RGFW_OS_BASED_VALUE(74, 0x77, 101, DOM_VK_F8, KEY_F8)] = RGFW_F8 RGFW_NEXT
1354 RGFW_MAP [RGFW_OS_BASED_VALUE(75, 0x78, 102, DOM_VK_F9, KEY_F9)] = RGFW_F9 RGFW_NEXT
1355 RGFW_MAP [RGFW_OS_BASED_VALUE(76, 0x79, 110, DOM_VK_F10, KEY_F10)] = RGFW_F10 RGFW_NEXT
1356 RGFW_MAP [RGFW_OS_BASED_VALUE(95, 0x7A, 104, DOM_VK_F11, KEY_F11)] = RGFW_F11 RGFW_NEXT
1357 RGFW_MAP [RGFW_OS_BASED_VALUE(96, 0x7B, 112, DOM_VK_F12, KEY_F12)] = RGFW_F12 RGFW_NEXT
1358 RGFW_MAP [RGFW_OS_BASED_VALUE(111, 0x26, 126, DOM_VK_UP, KEY_UP)] = RGFW_Up RGFW_NEXT
1359 RGFW_MAP [RGFW_OS_BASED_VALUE(116, 0x28, 125, DOM_VK_DOWN, KEY_DOWN)] = RGFW_Down RGFW_NEXT
1360 RGFW_MAP [RGFW_OS_BASED_VALUE(113, 0x25, 123, DOM_VK_LEFT, KEY_LEFT)] = RGFW_Left RGFW_NEXT
1361 RGFW_MAP [RGFW_OS_BASED_VALUE(114, 0x27, 124, DOM_VK_RIGHT, KEY_RIGHT)] = RGFW_Right RGFW_NEXT
1362 RGFW_MAP [RGFW_OS_BASED_VALUE(118, 0x2D, 115, DOM_VK_INSERT, KEY_INSERT)] = RGFW_Insert RGFW_NEXT
1363 RGFW_MAP [RGFW_OS_BASED_VALUE(115, 0x23, 120, DOM_VK_END, KEY_END)] = RGFW_End RGFW_NEXT
1364 RGFW_MAP [RGFW_OS_BASED_VALUE(112, 336, 117, DOM_VK_PAGE_UP, KEY_PAGEUP)] = RGFW_PageUp RGFW_NEXT
1365 RGFW_MAP [RGFW_OS_BASED_VALUE(117, 325, 122, DOM_VK_PAGE_DOWN, KEY_PAGEDOWN)] = RGFW_PageDown RGFW_NEXT
1366 RGFW_MAP [RGFW_OS_BASED_VALUE(9, 0x1B, 53, DOM_VK_ESCAPE, KEY_ESC)] = RGFW_Escape RGFW_NEXT
1367 RGFW_MAP [RGFW_OS_BASED_VALUE(110, 0x24, 116, DOM_VK_HOME, KEY_HOME)] = RGFW_Home RGFW_NEXT
1368#ifndef __cplusplus
1369};
1370#else
1371}
1372#endif
1373
1374#undef RGFW_NEXT
1375#undef RGFW_MAP
1376
1377typedef struct {
1378 b8 current : 1;
1379 b8 prev : 1;
1380} RGFW_keyState;
1381
1382RGFW_keyState RGFW_keyboard[final_key] = { {0, 0} };
1383
1384RGFWDEF u32 RGFW_apiKeyCodeToRGFW(u32 keycode);
1385
1386u32 RGFW_apiKeyCodeToRGFW(u32 keycode) {
1387 #ifdef __cplusplus
1388 if (RGFW_OS_BASED_VALUE(49, 192, 50, DOM_VK_BACK_QUOTE, KEY_GRAVE) != RGFW_Backtick) {
1389 RGFW_init_keys();
1390 }
1391 #endif
1392
1393 /* make sure the key isn't out of bounds */
1394 if (keycode > sizeof(RGFW_keycodes) / sizeof(u8))
1395 return 0;
1396
1397 return RGFW_keycodes[keycode];
1398}
1399
1400RGFWDEF void RGFW_resetKey(void);
1401void RGFW_resetKey(void) {
1402 size_t len = final_key; /*!< last_key == length */
1403
1404 size_t i; /*!< reset each previous state */
1405 for (i = 0; i < len; i++)
1406 RGFW_keyboard[i].prev = 0;
1407}
1408
1409b8 RGFW_shouldShift(u32 keycode, u8 lockState) {
1410 #define RGFW_xor(x, y) (( (x) && (!(y)) ) || ((y) && (!(x)) ))
1411 b8 caps4caps = (lockState & RGFW_CAPSLOCK) && ((keycode >= RGFW_a) && (keycode <= RGFW_z));
1412 b8 shouldShift = RGFW_xor((RGFW_isPressed(NULL, RGFW_ShiftL) || RGFW_isPressed(NULL, RGFW_ShiftR)), caps4caps);
1413 #undef RGFW_xor
1414
1415 return shouldShift;
1416}
1417
1418char RGFW_keyCodeToChar(u32 keycode, b8 shift) {
1419 static const char map[] = {
1420 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '`', '0', '1', '2', '3', '4', '5', '6', '7', '8',
1421 '9', '-', '=', 0, '\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
1422 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '.', ',', '/', '[', ']', ';', '\n', '\'', '\\',
1423 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '/', '*', '-', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '\n'
1424 };
1425
1426 static const char mapCaps[] = {
1427 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '~', ')', '!', '@', '#', '$', '%', '^', '&', '*',
1428 '(', '_', '+', 0, '0', 0, 0, 0, 0, 0, 0, 0, 0, 0, ' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
1429 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
1430 'X', 'Y', 'Z', '>', '<', '?', '{', '}', ':', '\n', '"', '|',
1431 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '?', '*', '-', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1432 };
1433
1434 if (shift == RGFW_FALSE)
1435 return map[keycode];
1436 return mapCaps[keycode];
1437}
1438
1439char RGFW_keyCodeToCharAuto(u32 keycode, u8 lockState) { return RGFW_keyCodeToChar(keycode, RGFW_shouldShift(keycode, lockState)); }
1440
1441/*
1442 this is the end of keycode data
1443*/
1444
1445/* joystick data */
1446u8 RGFW_jsPressed[4][16]; /*!< if a key is currently pressed or not (per joystick) */
1447
1448i32 RGFW_joysticks[4]; /*!< limit of 4 joysticks at a time */
1449u16 RGFW_joystickCount; /*!< the actual amount of joysticks */
1450
1451/*
1452 event callback defines start here
1453*/
1454
1455
1456/*
1457 These exist to avoid the
1458 if (func == NULL) check
1459 for (allegedly) better performance
1460*/
1461void RGFW_windowmovefuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); }
1462void RGFW_windowresizefuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); }
1463void RGFW_windowquitfuncEMPTY(RGFW_window* win) { RGFW_UNUSED(win); }
1464void RGFW_focusfuncEMPTY(RGFW_window* win, b8 inFocus) {RGFW_UNUSED(win); RGFW_UNUSED(inFocus);}
1465void RGFW_mouseNotifyfuncEMPTY(RGFW_window* win, RGFW_point point, b8 status) {RGFW_UNUSED(win); RGFW_UNUSED(point); RGFW_UNUSED(status);}
1466void RGFW_mouseposfuncEMPTY(RGFW_window* win, RGFW_point point) {RGFW_UNUSED(win); RGFW_UNUSED(point);}
1467void RGFW_dndInitfuncEMPTY(RGFW_window* win, RGFW_point point) {RGFW_UNUSED(win); RGFW_UNUSED(point);}
1468void RGFW_windowrefreshfuncEMPTY(RGFW_window* win) {RGFW_UNUSED(win); }
1469void RGFW_keyfuncEMPTY(RGFW_window* win, u32 keycode, char keyName[16], u8 lockState, b8 pressed) {RGFW_UNUSED(win); RGFW_UNUSED(keycode); RGFW_UNUSED(keyName); RGFW_UNUSED(lockState); RGFW_UNUSED(pressed);}
1470void RGFW_mousebuttonfuncEMPTY(RGFW_window* win, u8 button, double scroll, b8 pressed) {RGFW_UNUSED(win); RGFW_UNUSED(button); RGFW_UNUSED(scroll); RGFW_UNUSED(pressed);}
1471void RGFW_jsButtonfuncEMPTY(RGFW_window* win, u16 joystick, u8 button, b8 pressed){RGFW_UNUSED(win); RGFW_UNUSED(joystick); RGFW_UNUSED(button); RGFW_UNUSED(pressed); }
1472void RGFW_jsAxisfuncEMPTY(RGFW_window* win, u16 joystick, RGFW_point axis[2], u8 axisesCount){RGFW_UNUSED(win); RGFW_UNUSED(joystick); RGFW_UNUSED(axis); RGFW_UNUSED(axisesCount); }
1473
1474#ifdef RGFW_ALLOC_DROPFILES
1475void RGFW_dndfuncEMPTY(RGFW_window* win, char** droppedFiles, u32 droppedFilesCount) {RGFW_UNUSED(win); RGFW_UNUSED(droppedFiles); RGFW_UNUSED(droppedFilesCount);}
1476#else
1477void RGFW_dndfuncEMPTY(RGFW_window* win, char droppedFiles[RGFW_MAX_DROPS][RGFW_MAX_PATH], u32 droppedFilesCount) {RGFW_UNUSED(win); RGFW_UNUSED(droppedFiles); RGFW_UNUSED(droppedFilesCount);}
1478#endif
1479
1480RGFW_windowmovefunc RGFW_windowMoveCallback = RGFW_windowmovefuncEMPTY;
1481RGFW_windowresizefunc RGFW_windowResizeCallback = RGFW_windowresizefuncEMPTY;
1482RGFW_windowquitfunc RGFW_windowQuitCallback = RGFW_windowquitfuncEMPTY;
1483RGFW_mouseposfunc RGFW_mousePosCallback = RGFW_mouseposfuncEMPTY;
1484RGFW_windowrefreshfunc RGFW_windowRefreshCallback = RGFW_windowrefreshfuncEMPTY;
1485RGFW_focusfunc RGFW_focusCallback = RGFW_focusfuncEMPTY;
1486RGFW_mouseNotifyfunc RGFW_mouseNotifyCallBack = RGFW_mouseNotifyfuncEMPTY;
1487RGFW_dndfunc RGFW_dndCallback = RGFW_dndfuncEMPTY;
1488RGFW_dndInitfunc RGFW_dndInitCallback = RGFW_dndInitfuncEMPTY;
1489RGFW_keyfunc RGFW_keyCallback = RGFW_keyfuncEMPTY;
1490RGFW_mousebuttonfunc RGFW_mouseButtonCallback = RGFW_mousebuttonfuncEMPTY;
1491RGFW_jsButtonfunc RGFW_jsButtonCallback = RGFW_jsButtonfuncEMPTY;
1492RGFW_jsAxisfunc RGFW_jsAxisCallback = RGFW_jsAxisfuncEMPTY;
1493
1494void RGFW_window_checkEvents(RGFW_window* win, i32 waitMS) {
1495 RGFW_window_eventWait(win, waitMS);
1496
1497 while (RGFW_window_checkEvent(win) != NULL && RGFW_window_shouldClose(win) == 0) {
1498 if (win->event.type == RGFW_quit) return;
1499 }
1500
1501 #ifdef RGFW_WEBASM /* webasm needs to run the sleep function for asyncify */
1502 RGFW_sleep(0);
1503 #endif
1504}
1505
1506RGFW_windowmovefunc RGFW_setWindowMoveCallback(RGFW_windowmovefunc func) {
1507 RGFW_windowmovefunc prev = (RGFW_windowMoveCallback == RGFW_windowmovefuncEMPTY) ? NULL : RGFW_windowMoveCallback;
1508 RGFW_windowMoveCallback = func;
1509 return prev;
1510}
1511RGFW_windowresizefunc RGFW_setWindowResizeCallback(RGFW_windowresizefunc func) {
1512 RGFW_windowresizefunc prev = (RGFW_windowResizeCallback == RGFW_windowresizefuncEMPTY) ? NULL : RGFW_windowResizeCallback;
1513 RGFW_windowResizeCallback = func;
1514 return prev;
1515}
1516RGFW_windowquitfunc RGFW_setWindowQuitCallback(RGFW_windowquitfunc func) {
1517 RGFW_windowquitfunc prev = (RGFW_windowQuitCallback == RGFW_windowquitfuncEMPTY) ? NULL : RGFW_windowQuitCallback;
1518 RGFW_windowQuitCallback = func;
1519 return prev;
1520}
1521
1522RGFW_mouseposfunc RGFW_setMousePosCallback(RGFW_mouseposfunc func) {
1523 RGFW_mouseposfunc prev = (RGFW_mousePosCallback == RGFW_mouseposfuncEMPTY) ? NULL : RGFW_mousePosCallback;
1524 RGFW_mousePosCallback = func;
1525 return prev;
1526}
1527RGFW_windowrefreshfunc RGFW_setWindowRefreshCallback(RGFW_windowrefreshfunc func) {
1528 RGFW_windowrefreshfunc prev = (RGFW_windowRefreshCallback == RGFW_windowrefreshfuncEMPTY) ? NULL : RGFW_windowRefreshCallback;
1529 RGFW_windowRefreshCallback = func;
1530 return prev;
1531}
1532RGFW_focusfunc RGFW_setFocusCallback(RGFW_focusfunc func) {
1533 RGFW_focusfunc prev = (RGFW_focusCallback == RGFW_focusfuncEMPTY) ? NULL : RGFW_focusCallback;
1534 RGFW_focusCallback = func;
1535 return prev;
1536}
1537
1538RGFW_mouseNotifyfunc RGFW_setMouseNotifyCallBack(RGFW_mouseNotifyfunc func) {
1539 RGFW_mouseNotifyfunc prev = (RGFW_mouseNotifyCallBack == RGFW_mouseNotifyfuncEMPTY) ? NULL : RGFW_mouseNotifyCallBack;
1540 RGFW_mouseNotifyCallBack = func;
1541 return prev;
1542}
1543RGFW_dndfunc RGFW_setDndCallback(RGFW_dndfunc func) {
1544 RGFW_dndfunc prev = (RGFW_dndCallback == RGFW_dndfuncEMPTY) ? NULL : RGFW_dndCallback;
1545 RGFW_dndCallback = func;
1546 return prev;
1547}
1548RGFW_dndInitfunc RGFW_setDndInitCallback(RGFW_dndInitfunc func) {
1549 RGFW_dndInitfunc prev = (RGFW_dndInitCallback == RGFW_dndInitfuncEMPTY) ? NULL : RGFW_dndInitCallback;
1550 RGFW_dndInitCallback = func;
1551 return prev;
1552}
1553RGFW_keyfunc RGFW_setKeyCallback(RGFW_keyfunc func) {
1554 RGFW_keyfunc prev = (RGFW_keyCallback == RGFW_keyfuncEMPTY) ? NULL : RGFW_keyCallback;
1555 RGFW_keyCallback = func;
1556 return prev;
1557}
1558RGFW_mousebuttonfunc RGFW_setMouseButtonCallback(RGFW_mousebuttonfunc func) {
1559 RGFW_mousebuttonfunc prev = (RGFW_mouseButtonCallback == RGFW_mousebuttonfuncEMPTY) ? NULL : RGFW_mouseButtonCallback;
1560 RGFW_mouseButtonCallback = func;
1561 return prev;
1562}
1563RGFW_jsButtonfunc RGFW_setjsButtonCallback(RGFW_jsButtonfunc func) {
1564 RGFW_jsButtonfunc prev = (RGFW_jsButtonCallback == RGFW_jsButtonfuncEMPTY) ? NULL : RGFW_jsButtonCallback;
1565 RGFW_jsButtonCallback = func;
1566 return prev;
1567}
1568RGFW_jsAxisfunc RGFW_setjsAxisCallback(RGFW_jsAxisfunc func) {
1569 RGFW_jsAxisfunc prev = (RGFW_jsAxisCallback == RGFW_jsAxisfuncEMPTY) ? NULL : RGFW_jsAxisCallback;
1570 RGFW_jsAxisCallback = func;
1571 return prev;
1572}
1573/*
1574no more event call back defines
1575*/
1576
1577#define RGFW_ASSERT(check, str) {\
1578 if (!(check)) { \
1579 printf(str); \
1580 assert(check); \
1581 } \
1582}
1583
1584b8 RGFW_error = 0;
1585b8 RGFW_Error(void) { return RGFW_error; }
1586
1587#define SET_ATTRIB(a, v) { \
1588 assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
1589 attribs[index++] = a; \
1590 attribs[index++] = v; \
1591}
1592
1593RGFW_area RGFW_bufferSize = {0, 0};
1594void RGFW_setBufferSize(RGFW_area size) {
1595 RGFW_bufferSize = size;
1596}
1597
1598
1599RGFWDEF RGFW_window* RGFW_window_basic_init(RGFW_rect rect, u16 args);
1600
1601/* do a basic initialization for RGFW_window, this is to standard it for each OS */
1602RGFW_window* RGFW_window_basic_init(RGFW_rect rect, u16 args) {
1603 RGFW_window* win = (RGFW_window*) RGFW_MALLOC(sizeof(RGFW_window)); /*!< make a new RGFW struct */
1604
1605 /* clear out dnd info */
1606#ifdef RGFW_ALLOC_DROPFILES
1607 win->event.droppedFiles = (char**) RGFW_MALLOC(sizeof(char*) * RGFW_MAX_DROPS);
1608 u32 i;
1609 for (i = 0; i < RGFW_MAX_DROPS; i++)
1610 win->event.droppedFiles[i] = (char*) RGFW_CALLOC(RGFW_MAX_PATH, sizeof(char));
1611#endif
1612
1613 /* X11 requires us to have a display to get the screen size */
1614 #ifndef RGFW_X11
1615 RGFW_area screenR = RGFW_getScreenSize();
1616 #else
1617 win->src.display = XOpenDisplay(NULL);
1618 assert(win->src.display != NULL);
1619
1620 Screen* scrn = DefaultScreenOfDisplay((Display*)win->src.display);
1621 RGFW_area screenR = RGFW_AREA((u32)scrn->width, (u32)scrn->height);
1622 #endif
1623
1624 /* rect based the requested args */
1625 if (args & RGFW_FULLSCREEN)
1626 rect = RGFW_RECT(0, 0, screenR.w, screenR.h);
1627
1628 /* set and init the new window's data */
1629 win->r = rect;
1630 win->event.inFocus = 1;
1631 win->event.droppedFilesCount = 0;
1632 RGFW_joystickCount = 0;
1633 win->_winArgs = 0;
1634 win->event.lockState = 0;
1635
1636 return win;
1637}
1638
1639#ifndef RGFW_NO_MONITOR
1640void RGFW_window_scaleToMonitor(RGFW_window* win) {
1641 RGFW_monitor monitor = RGFW_window_getMonitor(win);
1642
1643 RGFW_window_resize(win, RGFW_AREA((u32)(monitor.scaleX * (float)win->r.w), (u32)(monitor.scaleX * (float)win->r.h)));
1644}
1645#endif
1646
1647RGFW_window* RGFW_root = NULL;
1648
1649
1650#define RGFW_HOLD_MOUSE (1L<<2) /*!< hold the moues still */
1651#define RGFW_MOUSE_LEFT (1L<<3) /* if mouse left the window */
1652
1653#ifdef RGFW_MACOS
1654RGFWDEF void RGFW_window_cocoaSetLayer(RGFW_window* win, void* layer);
1655RGFWDEF void* RGFW_cocoaGetLayer(void);
1656#endif
1657
1658char* RGFW_className = NULL;
1659void RGFW_setClassName(char* name) {
1660 RGFW_className = name;
1661}
1662
1663void RGFW_clipboardFree(char* str) { RGFW_FREE(str); }
1664
1665RGFW_keyState RGFW_mouseButtons[5] = { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1666
1667b8 RGFW_isMousePressed(RGFW_window* win, u8 button) {
1668 assert(win != NULL);
1669 return RGFW_mouseButtons[button].current && (win != NULL) && win->event.inFocus;
1670}
1671b8 RGFW_wasMousePressed(RGFW_window* win, u8 button) {
1672 assert(win != NULL);
1673 return RGFW_mouseButtons[button].prev && (win != NULL) && win->event.inFocus;
1674}
1675b8 RGFW_isMouseHeld(RGFW_window* win, u8 button) {
1676 return (RGFW_isMousePressed(win, button) && RGFW_wasMousePressed(win, button));
1677}
1678b8 RGFW_isMouseReleased(RGFW_window* win, u8 button) {
1679 return (!RGFW_isMousePressed(win, button) && RGFW_wasMousePressed(win, button));
1680}
1681
1682b8 RGFW_isPressed(RGFW_window* win, u8 key) {
1683 return RGFW_keyboard[key].current && (win == NULL || win->event.inFocus);
1684}
1685
1686b8 RGFW_wasPressed(RGFW_window* win, u8 key) {
1687 return RGFW_keyboard[key].prev && (win == NULL || win->event.inFocus);
1688}
1689
1690b8 RGFW_isHeld(RGFW_window* win, u8 key) {
1691 return (RGFW_isPressed(win, key) && RGFW_wasPressed(win, key));
1692}
1693
1694b8 RGFW_isClicked(RGFW_window* win, u8 key) {
1695 return (RGFW_wasPressed(win, key) && !RGFW_isPressed(win, key));
1696}
1697
1698b8 RGFW_isReleased(RGFW_window* win, u8 key) {
1699 return (!RGFW_isPressed(win, key) && RGFW_wasPressed(win, key));
1700}
1701
1702#if defined(RGFW_WINDOWS) && defined(RGFW_DIRECTX) /* defines for directX context*/
1703 RGFW_directXinfo RGFW_dxInfo;
1704 RGFW_directXinfo* RGFW_getDirectXInfo(void) { return &RGFW_dxInfo; }
1705#endif
1706
1707void RGFW_window_makeCurrent(RGFW_window* win) {
1708#if defined(RGFW_WINDOWS) && defined(RGFW_DIRECTX)
1709 if (win == NULL)
1710 RGFW_dxInfo.pDeviceContext->lpVtbl->OMSetRenderTargets(RGFW_dxInfo.pDeviceContext, 1, NULL, NULL);
1711 else
1712 RGFW_dxInfo.pDeviceContext->lpVtbl->OMSetRenderTargets(RGFW_dxInfo.pDeviceContext, 1, &win->src.renderTargetView, NULL);
1713#elif defined(RGFW_OPENGL)
1714 RGFW_window_makeCurrent_OpenGL(win);
1715#else
1716 RGFW_UNUSED(win)
1717#endif
1718}
1719
1720void RGFW_window_setGPURender(RGFW_window* win, i8 set) {
1721 if (!set && !(win->_winArgs & RGFW_NO_GPU_RENDER))
1722 win->_winArgs |= RGFW_NO_GPU_RENDER;
1723
1724 else if (set && win->_winArgs & RGFW_NO_GPU_RENDER)
1725 win->_winArgs ^= RGFW_NO_GPU_RENDER;
1726}
1727
1728void RGFW_window_setCPURender(RGFW_window* win, i8 set) {
1729 if (!set && !(win->_winArgs & RGFW_NO_CPU_RENDER))
1730 win->_winArgs |= RGFW_NO_CPU_RENDER;
1731
1732 else if (set && win->_winArgs & RGFW_NO_CPU_RENDER)
1733 win->_winArgs ^= RGFW_NO_CPU_RENDER;
1734}
1735
1736void RGFW_window_maximize(RGFW_window* win) {
1737 assert(win != NULL);
1738
1739 RGFW_area screen = RGFW_getScreenSize();
1740
1741 RGFW_window_move(win, RGFW_POINT(0, 0));
1742 RGFW_window_resize(win, screen);
1743}
1744
1745b8 RGFW_window_shouldClose(RGFW_window* win) {
1746 assert(win != NULL);
1747 return (win->event.type == RGFW_quit || RGFW_isPressed(win, RGFW_Escape));
1748}
1749
1750void RGFW_window_setShouldClose(RGFW_window* win) { win->event.type = RGFW_quit; RGFW_windowQuitCallback(win); }
1751
1752#ifndef RGFW_NO_MONITOR
1753 void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m) {
1754 RGFW_window_move(win, RGFW_POINT(m.rect.x + win->r.x, m.rect.y + win->r.y));
1755 }
1756#endif
1757
1758RGFWDEF void RGFW_captureCursor(RGFW_window* win, RGFW_rect);
1759RGFWDEF void RGFW_releaseCursor(RGFW_window* win);
1760
1761void RGFW_window_mouseHold(RGFW_window* win, RGFW_area area) {
1762 if ((win->_winArgs & RGFW_HOLD_MOUSE))
1763 return;
1764
1765
1766 if (!area.w && !area.h)
1767 area = RGFW_AREA(win->r.w / 2, win->r.h / 2);
1768
1769 win->_winArgs |= RGFW_HOLD_MOUSE;
1770 RGFW_captureCursor(win, win->r);
1771 RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2)));
1772}
1773
1774void RGFW_window_mouseUnhold(RGFW_window* win) {
1775 if ((win->_winArgs & RGFW_HOLD_MOUSE)) {
1776 win->_winArgs ^= RGFW_HOLD_MOUSE;
1777
1778 RGFW_releaseCursor(win);
1779 }
1780}
1781
1782u32 RGFW_window_checkFPS(RGFW_window* win, u32 fpsCap) {
1783 u64 deltaTime = RGFW_getTimeNS() - win->event.frameTime;
1784
1785 u32 output_fps = 0;
1786 u64 fps = round(1e+9 / deltaTime);
1787 output_fps= fps;
1788
1789 if (fpsCap && fps > fpsCap) {
1790 u64 frameTimeNS = 1e+9 / fpsCap;
1791 u64 sleepTimeMS = (frameTimeNS - deltaTime) / 1e6;
1792
1793 if (sleepTimeMS > 0) {
1794 RGFW_sleep(sleepTimeMS);
1795 win->event.frameTime = 0;
1796 }
1797 }
1798
1799 win->event.frameTime = RGFW_getTimeNS();
1800
1801 if (fpsCap == 0)
1802 return (u32) output_fps;
1803
1804 deltaTime = RGFW_getTimeNS() - win->event.frameTime2;
1805 output_fps = round(1e+9 / deltaTime);
1806 win->event.frameTime2 = RGFW_getTimeNS();
1807
1808 return output_fps;
1809}
1810
1811u32 RGFW_isPressedJS(RGFW_window* win, u16 c, u8 button) {
1812 RGFW_UNUSED(win);
1813 return RGFW_jsPressed[c][button];
1814}
1815
1816#if defined(RGFW_X11) || defined(RGFW_WINDOWS)
1817 void RGFW_window_showMouse(RGFW_window* win, i8 show) {
1818 static u8 RGFW_blk[] = { 0, 0, 0, 0 };
1819 if (show == 0)
1820 RGFW_window_setMouse(win, RGFW_blk, RGFW_AREA(1, 1), 4);
1821 else
1822 RGFW_window_setMouseDefault(win);
1823 }
1824#endif
1825
1826RGFWDEF void RGFW_updateLockState(RGFW_window* win, b8 capital, b8 numlock);
1827void RGFW_updateLockState(RGFW_window* win, b8 capital, b8 numlock) {
1828 if (capital && !(win->event.lockState & RGFW_CAPSLOCK))
1829 win->event.lockState |= RGFW_CAPSLOCK;
1830 else if (!capital && (win->event.lockState & RGFW_CAPSLOCK))
1831 win->event.lockState ^= RGFW_CAPSLOCK;
1832
1833 if (numlock && !(win->event.lockState & RGFW_NUMLOCK))
1834 win->event.lockState |= RGFW_NUMLOCK;
1835 else if (!numlock && (win->event.lockState & RGFW_NUMLOCK))
1836 win->event.lockState ^= RGFW_NUMLOCK;
1837}
1838
1839#if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WEBASM) || defined(RGFW_WAYLAND)
1840 struct timespec;
1841
1842 int nanosleep(const struct timespec* duration, struct timespec* rem);
1843 int clock_gettime(clockid_t clk_id, struct timespec* tp);
1844 int setenv(const char *name, const char *value, int overwrite);
1845
1846 void RGFW_window_setDND(RGFW_window* win, b8 allow) {
1847 if (allow && !(win->_winArgs & RGFW_ALLOW_DND))
1848 win->_winArgs |= RGFW_ALLOW_DND;
1849
1850 else if (!allow && (win->_winArgs & RGFW_ALLOW_DND))
1851 win->_winArgs ^= RGFW_ALLOW_DND;
1852 }
1853#endif
1854
1855/*
1856 graphics API specific code (end of generic code)
1857 starts here
1858*/
1859
1860
1861/*
1862 OpenGL defines start here (Normal, EGL, OSMesa)
1863*/
1864
1865#if defined(RGFW_OPENGL) || defined(RGFW_EGL) || defined(RGFW_OSMESA)
1866 #ifdef RGFW_WINDOWS
1867 #define WIN32_LEAN_AND_MEAN
1868 #define OEMRESOURCE
1869 #include <windows.h>
1870 #endif
1871
1872 #if !defined(__APPLE__) && !defined(RGFW_NO_GL_HEADER)
1873 #include <GL/gl.h>
1874 #elif defined(__APPLE__)
1875 #ifndef GL_SILENCE_DEPRECATION
1876 #define GL_SILENCE_DEPRECATION
1877 #endif
1878 #include <OpenGL/gl.h>
1879 #include <OpenGL/OpenGL.h>
1880 #endif
1881
1882/* EGL, normal OpenGL only */
1883#if !defined(RGFW_OSMESA)
1884 i32 RGFW_majorVersion = 0, RGFW_minorVersion = 0;
1885 b8 RGFW_profile = RGFW_GL_CORE;
1886
1887 #ifndef RGFW_EGL
1888 i32 RGFW_STENCIL = 8, RGFW_SAMPLES = 4, RGFW_STEREO = 0, RGFW_AUX_BUFFERS = 0, RGFW_DOUBLE_BUFFER = 1;
1889 #else
1890 i32 RGFW_STENCIL = 0, RGFW_SAMPLES = 0, RGFW_STEREO = 0, RGFW_AUX_BUFFERS = 0, RGFW_DOUBLE_BUFFER = 1;
1891 #endif
1892
1893
1894 void RGFW_setGLStencil(i32 stencil) { RGFW_STENCIL = stencil; }
1895 void RGFW_setGLSamples(i32 samples) { RGFW_SAMPLES = samples; }
1896 void RGFW_setGLStereo(i32 stereo) { RGFW_STEREO = stereo; }
1897 void RGFW_setGLAuxBuffers(i32 auxBuffers) { RGFW_AUX_BUFFERS = auxBuffers; }
1898 void RGFW_setDoubleBuffer(b8 useDoubleBuffer) { RGFW_DOUBLE_BUFFER = useDoubleBuffer; }
1899
1900 void RGFW_setGLVersion(b8 profile, i32 major, i32 minor) {
1901 RGFW_profile = profile;
1902 RGFW_majorVersion = major;
1903 RGFW_minorVersion = minor;
1904 }
1905
1906/* OPENGL normal only (no EGL / OSMesa) */
1907#ifndef RGFW_EGL
1908
1909#define RGFW_GL_RENDER_TYPE RGFW_OS_BASED_VALUE(GLX_X_VISUAL_TYPE, 0x2003, 73, 0, 0)
1910 #define RGFW_GL_ALPHA_SIZE RGFW_OS_BASED_VALUE(GLX_ALPHA_SIZE, 0x201b, 11, 0, 0)
1911 #define RGFW_GL_DEPTH_SIZE RGFW_OS_BASED_VALUE(GLX_DEPTH_SIZE, 0x2022, 12, 0, 0)
1912 #define RGFW_GL_DOUBLEBUFFER RGFW_OS_BASED_VALUE(GLX_DOUBLEBUFFER, 0x2011, 5, 0, 0)
1913 #define RGFW_GL_STENCIL_SIZE RGFW_OS_BASED_VALUE(GLX_STENCIL_SIZE, 0x2023, 13, 0, 0)
1914 #define RGFW_GL_SAMPLES RGFW_OS_BASED_VALUE(GLX_SAMPLES, 0x2042, 55, 0, 0)
1915 #define RGFW_GL_STEREO RGFW_OS_BASED_VALUE(GLX_STEREO, 0x2012, 6, 0, 0)
1916 #define RGFW_GL_AUX_BUFFERS RGFW_OS_BASED_VALUE(GLX_AUX_BUFFERS, 0x2024, 7, 0, 0)
1917
1918#if defined(RGFW_X11) || defined(RGFW_WINDOWS)
1919 #define RGFW_GL_DRAW RGFW_OS_BASED_VALUE(GLX_X_RENDERABLE, 0x2001, 0, 0, 0)
1920 #define RGFW_GL_DRAW_TYPE RGFW_OS_BASED_VALUE(GLX_RENDER_TYPE, 0x2013, 0, 0, 0)
1921 #define RGFW_GL_FULL_FORMAT RGFW_OS_BASED_VALUE(GLX_TRUE_COLOR, 0x2027, 0, 0, 0)
1922 #define RGFW_GL_RED_SIZE RGFW_OS_BASED_VALUE(GLX_RED_SIZE, 0x2015, 0, 0, 0)
1923 #define RGFW_GL_GREEN_SIZE RGFW_OS_BASED_VALUE(GLX_GREEN_SIZE, 0x2017, 0, 0, 0)
1924 #define RGFW_GL_BLUE_SIZE RGFW_OS_BASED_VALUE(GLX_BLUE_SIZE, 0x2019, 0, 0, 0)
1925 #define RGFW_GL_USE_RGBA RGFW_OS_BASED_VALUE(GLX_RGBA_BIT, 0x202B, 0, 0, 0)
1926#endif
1927
1928#ifdef RGFW_WINDOWS
1929 #define WGL_SUPPORT_OPENGL_ARB 0x2010
1930 #define WGL_COLOR_BITS_ARB 0x2014
1931 #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
1932 #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
1933 #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
1934 #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
1935 #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
1936 #define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
1937 #define WGL_SAMPLE_BUFFERS_ARB 0x2041
1938 #define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9
1939 #define WGL_PIXEL_TYPE_ARB 0x2013
1940 #define WGL_TYPE_RGBA_ARB 0x202B
1941
1942 #define WGL_TRANSPARENT_ARB 0x200A
1943#endif
1944
1945/* The window'ing api needs to know how to render the data we (or opengl) give it
1946 MacOS and Windows do this using a structure called a "pixel format"
1947 X11 calls it a "Visual"
1948 This function returns the attributes for the format we want */
1949 static u32* RGFW_initFormatAttribs(u32 useSoftware) {
1950 RGFW_UNUSED(useSoftware);
1951 static u32 attribs[] = {
1952 #if defined(RGFW_X11) || defined(RGFW_WINDOWS)
1953 RGFW_GL_RENDER_TYPE,
1954 RGFW_GL_FULL_FORMAT,
1955 #endif
1956 RGFW_GL_ALPHA_SIZE , 8,
1957 RGFW_GL_DEPTH_SIZE , 24,
1958 #if defined(RGFW_X11) || defined(RGFW_WINDOWS)
1959 RGFW_GL_DRAW, 1,
1960 RGFW_GL_RED_SIZE , 8,
1961 RGFW_GL_GREEN_SIZE , 8,
1962 RGFW_GL_BLUE_SIZE , 8,
1963 RGFW_GL_DRAW_TYPE , RGFW_GL_USE_RGBA,
1964 #endif
1965
1966 #ifdef RGFW_X11
1967 GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT,
1968 #endif
1969
1970 #ifdef RGFW_MACOS
1971 72,
1972 8, 24,
1973 #endif
1974
1975 #ifdef RGFW_WINDOWS
1976 WGL_SUPPORT_OPENGL_ARB, 1,
1977 WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
1978 WGL_COLOR_BITS_ARB, 32,
1979 #endif
1980
1981 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1982 };
1983
1984 size_t index = (sizeof(attribs) / sizeof(attribs[0])) - 13;
1985
1986 #define RGFW_GL_ADD_ATTRIB(attrib, attVal) \
1987 if (attVal) { \
1988 attribs[index] = attrib;\
1989 attribs[index + 1] = attVal;\
1990 index += 2;\
1991 }
1992
1993 RGFW_GL_ADD_ATTRIB(RGFW_GL_DOUBLEBUFFER, 1);
1994
1995 RGFW_GL_ADD_ATTRIB(RGFW_GL_STENCIL_SIZE, RGFW_STENCIL);
1996 RGFW_GL_ADD_ATTRIB(RGFW_GL_STEREO, RGFW_STEREO);
1997 RGFW_GL_ADD_ATTRIB(RGFW_GL_AUX_BUFFERS, RGFW_AUX_BUFFERS);
1998
1999#ifndef RGFW_X11
2000 RGFW_GL_ADD_ATTRIB(RGFW_GL_SAMPLES, RGFW_SAMPLES);
2001#endif
2002
2003#ifdef RGFW_MACOS
2004 if (useSoftware) {
2005 RGFW_GL_ADD_ATTRIB(70, kCGLRendererGenericFloatID);
2006 } else {
2007 attribs[index] = RGFW_GL_RENDER_TYPE;
2008 index += 1;
2009 }
2010#endif
2011
2012#ifdef RGFW_MACOS
2013 /* macOS has the surface attribs and the opengl attribs connected for some reason
2014 maybe this is to give macOS more control to limit openGL/the opengl version? */
2015
2016 attribs[index] = 99;
2017 attribs[index + 1] = 0x1000;
2018
2019 if (RGFW_majorVersion >= 4 || RGFW_majorVersion >= 3) {
2020 attribs[index + 1] = (u32) ((RGFW_majorVersion >= 4) ? 0x4100 : 0x3200);
2021 }
2022#endif
2023
2024 RGFW_GL_ADD_ATTRIB(0, 0);
2025
2026 return attribs;
2027 }
2028
2029/* EGL only (no OSMesa nor normal OPENGL) */
2030#elif defined(RGFW_EGL)
2031
2032#include <EGL/egl.h>
2033
2034#if defined(RGFW_LINK_EGL)
2035 typedef EGLBoolean(EGLAPIENTRY* PFN_eglInitialize)(EGLDisplay, EGLint*, EGLint*);
2036
2037 PFNEGLINITIALIZEPROC eglInitializeSource;
2038 PFNEGLGETCONFIGSPROC eglGetConfigsSource;
2039 PFNEGLCHOOSECONFIGPROC eglChooseConfigSource;
2040 PFNEGLCREATEWINDOWSURFACEPROC eglCreateWindowSurfaceSource;
2041 PFNEGLCREATECONTEXTPROC eglCreateContextSource;
2042 PFNEGLMAKECURRENTPROC eglMakeCurrentSource;
2043 PFNEGLGETDISPLAYPROC eglGetDisplaySource;
2044 PFNEGLSWAPBUFFERSPROC eglSwapBuffersSource;
2045 PFNEGLSWAPINTERVALPROC eglSwapIntervalSource;
2046 PFNEGLBINDAPIPROC eglBindAPISource;
2047 PFNEGLDESTROYCONTEXTPROC eglDestroyContextSource;
2048 PFNEGLTERMINATEPROC eglTerminateSource;
2049 PFNEGLDESTROYSURFACEPROC eglDestroySurfaceSource;
2050
2051#define eglInitialize eglInitializeSource
2052#define eglGetConfigs eglGetConfigsSource
2053#define eglChooseConfig eglChooseConfigSource
2054#define eglCreateWindowSurface eglCreateWindowSurfaceSource
2055#define eglCreateContext eglCreateContextSource
2056#define eglMakeCurrent eglMakeCurrentSource
2057#define eglGetDisplay eglGetDisplaySource
2058#define eglSwapBuffers eglSwapBuffersSource
2059#define eglSwapInterval eglSwapIntervalSource
2060#define eglBindAPI eglBindAPISource
2061#define eglDestroyContext eglDestroyContextSource
2062#define eglTerminate eglTerminateSource
2063#define eglDestroySurface eglDestroySurfaceSource;
2064#endif
2065
2066
2067#define EGL_SURFACE_MAJOR_VERSION_KHR 0x3098
2068#define EGL_SURFACE_MINOR_VERSION_KHR 0x30fb
2069
2070#ifndef RGFW_GL_ADD_ATTRIB
2071#define RGFW_GL_ADD_ATTRIB(attrib, attVal) \
2072 if (attVal) { \
2073 attribs[index] = attrib;\
2074 attribs[index + 1] = attVal;\
2075 index += 2;\
2076 }
2077#endif
2078
2079
2080 void RGFW_createOpenGLContext(RGFW_window* win) {
2081#if defined(RGFW_LINK_EGL)
2082 eglInitializeSource = (PFNEGLINITIALIZEPROC) eglGetProcAddress("eglInitialize");
2083 eglGetConfigsSource = (PFNEGLGETCONFIGSPROC) eglGetProcAddress("eglGetConfigs");
2084 eglChooseConfigSource = (PFNEGLCHOOSECONFIGPROC) eglGetProcAddress("eglChooseConfig");
2085 eglCreateWindowSurfaceSource = (PFNEGLCREATEWINDOWSURFACEPROC) eglGetProcAddress("eglCreateWindowSurface");
2086 eglCreateContextSource = (PFNEGLCREATECONTEXTPROC) eglGetProcAddress("eglCreateContext");
2087 eglMakeCurrentSource = (PFNEGLMAKECURRENTPROC) eglGetProcAddress("eglMakeCurrent");
2088 eglGetDisplaySource = (PFNEGLGETDISPLAYPROC) eglGetProcAddress("eglGetDisplay");
2089 eglSwapBuffersSource = (PFNEGLSWAPBUFFERSPROC) eglGetProcAddress("eglSwapBuffers");
2090 eglSwapIntervalSource = (PFNEGLSWAPINTERVALPROC) eglGetProcAddress("eglSwapInterval");
2091 eglBindAPISource = (PFNEGLBINDAPIPROC) eglGetProcAddress("eglBindAPI");
2092 eglDestroyContextSource = (PFNEGLDESTROYCONTEXTPROC) eglGetProcAddress("eglDestroyContext");
2093 eglTerminateSource = (PFNEGLTERMINATEPROC) eglGetProcAddress("eglTerminate");
2094 eglDestroySurfaceSource = (PFNEGLDESTROYSURFACEPROC) eglGetProcAddress("eglDestroySurface");
2095#endif /* RGFW_LINK_EGL */
2096
2097 #ifdef RGFW_WINDOWS
2098 win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.hdc);
2099 #elif defined(RGFW_MACOS)
2100 win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType)0);
2101 #else
2102 win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.display);
2103 #endif
2104
2105 EGLint major, minor;
2106
2107 eglInitialize(win->src.EGL_display, &major, &minor);
2108
2109 #ifndef EGL_OPENGL_ES1_BIT
2110 #define EGL_OPENGL_ES1_BIT 0x1
2111 #endif
2112
2113 EGLint egl_config[] = {
2114 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
2115 EGL_RENDERABLE_TYPE,
2116 #ifdef RGFW_OPENGL_ES1
2117 EGL_OPENGL_ES1_BIT,
2118 #elif defined(RGFW_OPENGL_ES3)
2119 EGL_OPENGL_ES3_BIT,
2120 #elif defined(RGFW_OPENGL_ES2)
2121 EGL_OPENGL_ES2_BIT,
2122 #else
2123 EGL_OPENGL_BIT,
2124 #endif
2125 EGL_NONE, EGL_NONE
2126 };
2127
2128 EGLConfig config;
2129 EGLint numConfigs;
2130 eglChooseConfig(win->src.EGL_display, egl_config, &config, 1, &numConfigs);
2131
2132 #if defined(RGFW_MACOS)
2133 void* layer = RGFW_cocoaGetLayer();
2134
2135 RGFW_window_cocoaSetLayer(win, layer);
2136
2137 win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) layer, NULL);
2138 #else
2139 win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL);
2140 #endif
2141
2142 EGLint attribs[] = {
2143 EGL_CONTEXT_CLIENT_VERSION,
2144 #ifdef RGFW_OPENGL_ES1
2145 1,
2146 #else
2147 2,
2148 #endif
2149 EGL_NONE, EGL_NONE, EGL_NONE, EGL_NONE, EGL_NONE, EGL_NONE, EGL_NONE, EGL_NONE, EGL_NONE
2150 };
2151
2152 size_t index = 4;
2153 RGFW_GL_ADD_ATTRIB(EGL_STENCIL_SIZE, RGFW_STENCIL);
2154 RGFW_GL_ADD_ATTRIB(EGL_SAMPLES, RGFW_SAMPLES);
2155
2156 if (RGFW_DOUBLE_BUFFER)
2157 RGFW_GL_ADD_ATTRIB(EGL_RENDER_BUFFER, EGL_BACK_BUFFER);
2158
2159 if (RGFW_majorVersion) {
2160 attribs[1] = RGFW_majorVersion;
2161
2162 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_MAJOR_VERSION, RGFW_majorVersion);
2163 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_MINOR_VERSION, RGFW_minorVersion);
2164
2165 if (RGFW_profile == RGFW_GL_CORE) {
2166 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT);
2167 }
2168 else {
2169 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT);
2170 }
2171
2172 }
2173
2174 #if defined(RGFW_OPENGL_ES1) || defined(RGFW_OPENGL_ES2) || defined(RGFW_OPENGL_ES3)
2175 eglBindAPI(EGL_OPENGL_ES_API);
2176 #else
2177 eglBindAPI(EGL_OPENGL_API);
2178 #endif
2179
2180 win->src.EGL_context = eglCreateContext(win->src.EGL_display, config, EGL_NO_CONTEXT, attribs);
2181
2182 if (win->src.EGL_context == NULL)
2183 fprintf(stderr, "failed to create an EGL opengl context\n");
2184
2185 eglMakeCurrent(win->src.EGL_display, win->src.EGL_surface, win->src.EGL_surface, win->src.EGL_context);
2186 eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface);
2187 }
2188
2189 void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
2190 eglMakeCurrent(win->src.EGL_display, win->src.EGL_surface, win->src.EGL_surface, win->src.EGL_context);
2191 }
2192
2193 #ifdef RGFW_APPLE
2194 void* RGFWnsglFramework = NULL;
2195 #elif defined(RGFW_WINDOWS)
2196 static HMODULE wglinstance = NULL;
2197 #endif
2198
2199 void* RGFW_getProcAddress(const char* procname) {
2200 #if defined(RGFW_WINDOWS)
2201 void* proc = (void*) GetProcAddress(wglinstance, procname);
2202
2203 if (proc)
2204 return proc;
2205 #endif
2206
2207 return (void*) eglGetProcAddress(procname);
2208 }
2209
2210 void RGFW_closeEGL(RGFW_window* win) {
2211 eglDestroySurface(win->src.EGL_display, win->src.EGL_surface);
2212 eglDestroyContext(win->src.EGL_display, win->src.EGL_context);
2213
2214 eglTerminate(win->src.EGL_display);
2215 }
2216
2217 void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) {
2218 assert(win != NULL);
2219
2220 eglSwapInterval(win->src.EGL_display, swapInterval);
2221
2222 }
2223#endif /* RGFW_EGL */
2224
2225/*
2226 end of RGFW_EGL defines
2227*/
2228
2229/* OPENGL Normal / EGL defines only (no OS MESA) Ends here */
2230
2231#elif defined(RGFW_OSMESA) /* OSmesa only */
2232RGFWDEF void RGFW_OSMesa_reorganize(void);
2233
2234/* reorganize buffer for osmesa */
2235void RGFW_OSMesa_reorganize(void) {
2236 u8* row = (u8*) RGFW_MALLOC(win->r.w * 3);
2237
2238 i32 half_height = win->r.h / 2;
2239 i32 stride = win->r.w * 3;
2240
2241 i32 y;
2242 for (y = 0; y < half_height; ++y) {
2243 i32 top_offset = y * stride;
2244 i32 bottom_offset = (win->r.h - y - 1) * stride;
2245 memcpy(row, win->buffer + top_offset, stride);
2246 memcpy(win->buffer + top_offset, win->buffer + bottom_offset, stride);
2247 memcpy(win->buffer + bottom_offset, row, stride);
2248 }
2249
2250 RGFW_FREE(row);
2251}
2252#endif /* RGFW_OSMesa */
2253
2254#endif /* RGFW_GL (OpenGL, EGL, OSMesa )*/
2255
2256/*
2257This is where OS specific stuff starts
2258*/
2259
2260
2261#if defined(RGFW_WAYLAND) || defined(RGFW_X11)
2262 int RGFW_eventWait_forceStop[] = {0, 0, 0}; /* for wait events */
2263
2264 #ifdef __linux__
2265 #include <linux/joystick.h>
2266 #include <fcntl.h>
2267 #include <unistd.h>
2268
2269 RGFW_Event* RGFW_linux_updateJoystick(RGFW_window* win) {
2270 static int xAxis = 0, yAxis = 0;
2271 u8 i;
2272 for (i = 0; i < RGFW_joystickCount; i++) {
2273 struct js_event e;
2274
2275
2276 if (RGFW_joysticks[i] == 0)
2277 continue;
2278
2279 i32 flags = fcntl(RGFW_joysticks[i], F_GETFL, 0);
2280 fcntl(RGFW_joysticks[i], F_SETFL, flags | O_NONBLOCK);
2281
2282 ssize_t bytes;
2283 while ((bytes = read(RGFW_joysticks[i], &e, sizeof(e))) > 0) {
2284 switch (e.type) {
2285 case JS_EVENT_BUTTON:
2286 win->event.type = e.value ? RGFW_jsButtonPressed : RGFW_jsButtonReleased;
2287 win->event.button = e.number;
2288 RGFW_jsPressed[i][e.number] = e.value;
2289 RGFW_jsButtonCallback(win, i, e.number, e.value);
2290 return &win->event;
2291 case JS_EVENT_AXIS:
2292 ioctl(RGFW_joysticks[i], JSIOCGAXES, &win->event.axisesCount);
2293
2294 if ((e.number == 0 || e.number % 2) && e.number != 1)
2295 xAxis = e.value;
2296 else
2297 yAxis = e.value;
2298
2299 win->event.axis[e.number / 2].x = xAxis;
2300 win->event.axis[e.number / 2].y = yAxis;
2301 win->event.type = RGFW_jsAxisMove;
2302 win->event.joystick = i;
2303 RGFW_jsAxisCallback(win, i, win->event.axis, win->event.axisesCount);
2304 return &win->event;
2305
2306 default: break;
2307 }
2308 }
2309 }
2310
2311 return NULL;
2312 }
2313
2314 #endif
2315#endif
2316
2317/*
2318
2319
2320Start of Linux / Unix defines
2321
2322
2323*/
2324
2325#ifdef RGFW_X11
2326#ifndef RGFW_NO_X11_CURSOR
2327#include <X11/Xcursor/Xcursor.h>
2328#endif
2329#include <dlfcn.h>
2330
2331#ifndef RGFW_NO_DPI
2332#include <X11/extensions/Xrandr.h>
2333#include <X11/Xresource.h>
2334#endif
2335
2336#include <X11/Xutil.h>
2337#include <X11/Xatom.h>
2338#include <X11/keysymdef.h>
2339#include <unistd.h>
2340
2341#include <X11/XKBlib.h> /* for converting keycode to string */
2342#include <X11/cursorfont.h> /* for hiding */
2343#include <X11/extensions/shapeconst.h>
2344#include <X11/extensions/shape.h>
2345#include <X11/extensions/XInput2.h>
2346
2347#include <limits.h> /* for data limits (mainly used in drag and drop functions) */
2348#include <poll.h>
2349
2350
2351#ifdef __linux__
2352#include <linux/joystick.h>
2353#endif
2354
2355 u8 RGFW_mouseIconSrc[] = { 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};
2356 /*atoms needed for drag and drop*/
2357 Atom XdndAware, XdndTypeList, XdndSelection, XdndEnter, XdndPosition, XdndStatus, XdndLeave, XdndDrop, XdndFinished, XdndActionCopy, XtextPlain, XtextUriList;
2358
2359 Atom wm_delete_window = 0;
2360
2361#if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD)
2362 typedef XcursorImage* (*PFN_XcursorImageCreate)(int, int);
2363 typedef void (*PFN_XcursorImageDestroy)(XcursorImage*);
2364 typedef Cursor(*PFN_XcursorImageLoadCursor)(Display*, const XcursorImage*);
2365#endif
2366#ifdef RGFW_OPENGL
2367 typedef GLXContext(*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
2368#endif
2369
2370#if !defined(RGFW_NO_X11_XI_PRELOAD)
2371 typedef int (* PFN_XISelectEvents)(Display*,Window,XIEventMask*,int);
2372 PFN_XISelectEvents XISelectEventsSrc = NULL;
2373 #define XISelectEvents XISelectEventsSrc
2374
2375 void* X11Xihandle = NULL;
2376#endif
2377
2378#if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD)
2379 PFN_XcursorImageLoadCursor XcursorImageLoadCursorSrc = NULL;
2380 PFN_XcursorImageCreate XcursorImageCreateSrc = NULL;
2381 PFN_XcursorImageDestroy XcursorImageDestroySrc = NULL;
2382
2383#define XcursorImageLoadCursor XcursorImageLoadCursorSrc
2384#define XcursorImageCreate XcursorImageCreateSrc
2385#define XcursorImageDestroy XcursorImageDestroySrc
2386
2387 void* X11Cursorhandle = NULL;
2388#endif
2389
2390 u32 RGFW_windowsOpen = 0;
2391
2392#ifdef RGFW_OPENGL
2393 void* RGFW_getProcAddress(const char* procname) { return (void*) glXGetProcAddress((GLubyte*) procname); }
2394#endif
2395
2396 RGFWDEF void RGFW_init_buffer(RGFW_window* win, XVisualInfo* vi);
2397 void RGFW_init_buffer(RGFW_window* win, XVisualInfo* vi) {
2398#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
2399 if (RGFW_bufferSize.w == 0 && RGFW_bufferSize.h == 0)
2400 RGFW_bufferSize = RGFW_getScreenSize();
2401
2402 win->buffer = (u8*)RGFW_MALLOC(RGFW_bufferSize.w * RGFW_bufferSize.h * 4);
2403
2404 #ifdef RGFW_OSMESA
2405 win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL);
2406 OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, win->r.w, win->r.h);
2407 #endif
2408
2409 win->src.bitmap = XCreateImage(
2410 win->src.display, XDefaultVisual(win->src.display, vi->screen),
2411 vi->depth,
2412 ZPixmap, 0, NULL, RGFW_bufferSize.w, RGFW_bufferSize.h,
2413 32, 0
2414 );
2415
2416 win->src.gc = XCreateGC(win->src.display, win->src.window, 0, NULL);
2417
2418 #else
2419 RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
2420 RGFW_UNUSED(vi)
2421 #endif
2422 }
2423
2424
2425
2426 void RGFW_window_setBorder(RGFW_window* win, u8 border) {
2427 static Atom _MOTIF_WM_HINTS = 0;
2428 if (_MOTIF_WM_HINTS == 0 )
2429 _MOTIF_WM_HINTS = XInternAtom(win->src.display, "_MOTIF_WM_HINTS", False);
2430
2431 struct __x11WindowHints {
2432 unsigned long flags, functions, decorations, status;
2433 long input_mode;
2434 } hints;
2435 hints.flags = (1L << 1);
2436 hints.decorations = border;
2437
2438 XChangeProperty(
2439 win->src.display, win->src.window,
2440 _MOTIF_WM_HINTS, _MOTIF_WM_HINTS,
2441 32, PropModeReplace, (u8*)&hints, 5
2442 );
2443 }
2444
2445 void RGFW_releaseCursor(RGFW_window* win) {
2446 XUngrabPointer(win->src.display, CurrentTime);
2447
2448 /* disable raw input */
2449 unsigned char mask[] = { 0 };
2450 XIEventMask em;
2451 em.deviceid = XIAllMasterDevices;
2452 em.mask_len = sizeof(mask);
2453 em.mask = mask;
2454
2455 XISelectEvents(win->src.display, XDefaultRootWindow(win->src.display), &em, 1);
2456 }
2457
2458 void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) {
2459 /* enable raw input */
2460 unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 };
2461 XISetMask(mask, XI_RawMotion);
2462
2463 XIEventMask em;
2464 em.deviceid = XIAllMasterDevices;
2465 em.mask_len = sizeof(mask);
2466 em.mask = mask;
2467
2468 XISelectEvents(win->src.display, XDefaultRootWindow(win->src.display), &em, 1);
2469
2470 XGrabPointer(win->src.display, win->src.window, True, PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
2471
2472 RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (i32)(r.w / 2), win->r.y + (i32)(r.h / 2)));
2473 }
2474
2475 RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, u16 args) {
2476#if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD)
2477 if (X11Cursorhandle == NULL) {
2478#if defined(__CYGWIN__)
2479 X11Cursorhandle = dlopen("libXcursor-1.so", RTLD_LAZY | RTLD_LOCAL);
2480#elif defined(__OpenBSD__) || defined(__NetBSD__)
2481 X11Cursorhandle = dlopen("libXcursor.so", RTLD_LAZY | RTLD_LOCAL);
2482#else
2483 X11Cursorhandle = dlopen("libXcursor.so.1", RTLD_LAZY | RTLD_LOCAL);
2484#endif
2485
2486 XcursorImageCreateSrc = (PFN_XcursorImageCreate) dlsym(X11Cursorhandle, "XcursorImageCreate");
2487 XcursorImageDestroySrc = (PFN_XcursorImageDestroy) dlsym(X11Cursorhandle, "XcursorImageDestroy");
2488 XcursorImageLoadCursorSrc = (PFN_XcursorImageLoadCursor) dlsym(X11Cursorhandle, "XcursorImageLoadCursor");
2489 }
2490#endif
2491
2492#if !defined(RGFW_NO_X11_XI_PRELOAD)
2493 if (X11Xihandle == NULL) {
2494#if defined(__CYGWIN__)
2495 X11Xihandle = dlopen("libXi-6.so", RTLD_LAZY | RTLD_LOCAL);
2496#elif defined(__OpenBSD__) || defined(__NetBSD__)
2497 X11Xihandle = dlopen("libXi.so", RTLD_LAZY | RTLD_LOCAL);
2498#else
2499 X11Xihandle = dlopen("libXi.so.6", RTLD_LAZY | RTLD_LOCAL);
2500#endif
2501
2502 XISelectEventsSrc = (PFN_XISelectEvents) dlsym(X11Xihandle, "XISelectEvents");
2503 }
2504#endif
2505
2506 XInitThreads(); /*!< init X11 threading*/
2507
2508 if (args & RGFW_OPENGL_SOFTWARE)
2509 setenv("LIBGL_ALWAYS_SOFTWARE", "1", 1);
2510
2511 RGFW_window* win = RGFW_window_basic_init(rect, args);
2512
2513 u64 event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | FocusChangeMask | LeaveWindowMask | EnterWindowMask | ExposureMask; /*!< X11 events accepted*/
2514
2515#ifdef RGFW_OPENGL
2516 u32* visual_attribs = RGFW_initFormatAttribs(args & RGFW_OPENGL_SOFTWARE);
2517 i32 fbcount;
2518 GLXFBConfig* fbc = glXChooseFBConfig((Display*) win->src.display, DefaultScreen(win->src.display), (i32*) visual_attribs, &fbcount);
2519
2520 i32 best_fbc = -1;
2521
2522 if (fbcount == 0) {
2523 printf("Failed to find any valid GLX visual configs\n");
2524 return NULL;
2525 }
2526
2527 u32 i;
2528 for (i = 0; i < (u32)fbcount; i++) {
2529 XVisualInfo* vi = glXGetVisualFromFBConfig((Display*) win->src.display, fbc[i]);
2530 if (vi == NULL)
2531 continue;
2532
2533 XFree(vi);
2534
2535 i32 samp_buf, samples;
2536 glXGetFBConfigAttrib((Display*) win->src.display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf);
2537 glXGetFBConfigAttrib((Display*) win->src.display, fbc[i], GLX_SAMPLES, &samples);
2538
2539 if ((!(args & RGFW_TRANSPARENT_WINDOW) || vi->depth == 32) &&
2540 (best_fbc < 0 || samp_buf) && (samples == RGFW_SAMPLES || best_fbc == -1)) {
2541 best_fbc = i;
2542 }
2543 }
2544
2545 if (best_fbc == -1) {
2546 printf("Failed to get a valid GLX visual\n");
2547 return NULL;
2548 }
2549
2550 GLXFBConfig bestFbc = fbc[best_fbc];
2551
2552 /* Get a visual */
2553 XVisualInfo* vi = glXGetVisualFromFBConfig((Display*) win->src.display, bestFbc);
2554
2555 XFree(fbc);
2556#else
2557 XVisualInfo viNorm;
2558
2559 viNorm.visual = DefaultVisual((Display*) win->src.display, DefaultScreen((Display*) win->src.display));
2560
2561 viNorm.depth = 0;
2562 XVisualInfo* vi = &viNorm;
2563
2564 XMatchVisualInfo((Display*) win->src.display, DefaultScreen((Display*) win->src.display), 32, TrueColor, vi); /*!< for RGBA backgrounds*/
2565#endif
2566 /* make X window attrubutes*/
2567 XSetWindowAttributes swa;
2568 Colormap cmap;
2569
2570 swa.colormap = cmap = XCreateColormap((Display*) win->src.display,
2571 DefaultRootWindow(win->src.display),
2572 vi->visual, AllocNone);
2573
2574 swa.background_pixmap = None;
2575 swa.border_pixel = 0;
2576 swa.event_mask = event_mask;
2577
2578 swa.background_pixel = 0;
2579
2580 /* create the window*/
2581 win->src.window = XCreateWindow((Display*) win->src.display, DefaultRootWindow((Display*) win->src.display), win->r.x, win->r.y, win->r.w, win->r.h,
2582 0, vi->depth, InputOutput, vi->visual,
2583 CWColormap | CWBorderPixel | CWBackPixel | CWEventMask, &swa);
2584
2585 XFreeColors((Display*) win->src.display, cmap, NULL, 0, 0);
2586
2587 #ifdef RGFW_OPENGL
2588 XFree(vi);
2589 #endif
2590
2591 // In your .desktop app, if you set the property
2592 // StartupWMClass=RGFW that will assoicate the launcher icon
2593 // with your application - robrohan
2594
2595 if (RGFW_className == NULL)
2596 RGFW_className = (char*)name;
2597
2598 XClassHint *hint = XAllocClassHint();
2599 assert(hint != NULL);
2600 hint->res_class = (char*)RGFW_className;
2601 hint->res_name = (char*)name; // just use the window name as the app name
2602 XSetClassHint((Display*) win->src.display, win->src.window, hint);
2603 XFree(hint);
2604
2605 if ((args & RGFW_NO_INIT_API) == 0) {
2606#ifdef RGFW_OPENGL /* This is the second part of setting up opengl. This is where we ask OpenGL for a specific version. */
2607 i32 context_attribs[7] = { 0, 0, 0, 0, 0, 0, 0 };
2608 context_attribs[0] = GLX_CONTEXT_PROFILE_MASK_ARB;
2609 if (RGFW_profile == RGFW_GL_CORE)
2610 context_attribs[1] = GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
2611 else
2612 context_attribs[1] = GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
2613
2614 if (RGFW_majorVersion || RGFW_minorVersion) {
2615 context_attribs[2] = GLX_CONTEXT_MAJOR_VERSION_ARB;
2616 context_attribs[3] = RGFW_majorVersion;
2617 context_attribs[4] = GLX_CONTEXT_MINOR_VERSION_ARB;
2618 context_attribs[5] = RGFW_minorVersion;
2619 }
2620
2621 glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
2622 glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)
2623 glXGetProcAddressARB((GLubyte*) "glXCreateContextAttribsARB");
2624
2625 GLXContext ctx = NULL;
2626
2627 if (RGFW_root != NULL)
2628 ctx = RGFW_root->src.ctx;
2629
2630 win->src.ctx = glXCreateContextAttribsARB((Display*) win->src.display, bestFbc, ctx, True, context_attribs);
2631#endif
2632 if (RGFW_root == NULL)
2633 RGFW_root = win;
2634
2635 RGFW_init_buffer(win, vi);
2636 }
2637
2638
2639 #ifndef RGFW_NO_MONITOR
2640 if (args & RGFW_SCALE_TO_MONITOR)
2641 RGFW_window_scaleToMonitor(win);
2642 #endif
2643
2644 if (args & RGFW_CENTER) {
2645 RGFW_area screenR = RGFW_getScreenSize();
2646 RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2));
2647 }
2648
2649 if (args & RGFW_NO_RESIZE) { /* make it so the user can't resize the window*/
2650 XSizeHints* sh = XAllocSizeHints();
2651 sh->flags = (1L << 4) | (1L << 5);
2652 sh->min_width = sh->max_width = win->r.w;
2653 sh->min_height = sh->max_height = win->r.h;
2654
2655 XSetWMSizeHints((Display*) win->src.display, (Drawable) win->src.window, sh, XA_WM_NORMAL_HINTS);
2656 XFree(sh);
2657 }
2658
2659 if (args & RGFW_NO_BORDER) {
2660 RGFW_window_setBorder(win, 0);
2661 }
2662
2663 XSelectInput((Display*) win->src.display, (Drawable) win->src.window, event_mask); /*!< tell X11 what events we want*/
2664
2665 /* make it so the user can't close the window until the program does*/
2666 if (wm_delete_window == 0)
2667 wm_delete_window = XInternAtom((Display*) win->src.display, "WM_DELETE_WINDOW", False);
2668
2669 XSetWMProtocols((Display*) win->src.display, (Drawable) win->src.window, &wm_delete_window, 1);
2670
2671 /* connect the context to the window*/
2672#ifdef RGFW_OPENGL
2673 if ((args & RGFW_NO_INIT_API) == 0)
2674 glXMakeCurrent((Display*) win->src.display, (Drawable) win->src.window, (GLXContext) win->src.ctx);
2675#endif
2676
2677 /* set the background*/
2678 XStoreName((Display*) win->src.display, (Drawable) win->src.window, name); /*!< set the name*/
2679
2680 XMapWindow((Display*) win->src.display, (Drawable) win->src.window); /* draw the window*/
2681 XMoveWindow((Display*) win->src.display, (Drawable) win->src.window, win->r.x, win->r.y); /*!< move the window to it's proper cords*/
2682
2683 if (args & RGFW_ALLOW_DND) { /* init drag and drop atoms and turn on drag and drop for this window */
2684 win->_winArgs |= RGFW_ALLOW_DND;
2685
2686 XdndTypeList = XInternAtom((Display*) win->src.display, "XdndTypeList", False);
2687 XdndSelection = XInternAtom((Display*) win->src.display, "XdndSelection", False);
2688
2689 /* client messages */
2690 XdndEnter = XInternAtom((Display*) win->src.display, "XdndEnter", False);
2691 XdndPosition = XInternAtom((Display*) win->src.display, "XdndPosition", False);
2692 XdndStatus = XInternAtom((Display*) win->src.display, "XdndStatus", False);
2693 XdndLeave = XInternAtom((Display*) win->src.display, "XdndLeave", False);
2694 XdndDrop = XInternAtom((Display*) win->src.display, "XdndDrop", False);
2695 XdndFinished = XInternAtom((Display*) win->src.display, "XdndFinished", False);
2696
2697 /* actions */
2698 XdndActionCopy = XInternAtom((Display*) win->src.display, "XdndActionCopy", False);
2699
2700 XtextUriList = XInternAtom((Display*) win->src.display, "text/uri-list", False);
2701 XtextPlain = XInternAtom((Display*) win->src.display, "text/plain", False);
2702
2703 XdndAware = XInternAtom((Display*) win->src.display, "XdndAware", False);
2704 const u8 version = 5;
2705
2706 XChangeProperty((Display*) win->src.display, (Window) win->src.window,
2707 XdndAware, 4, 32,
2708 PropModeReplace, &version, 1); /*!< turns on drag and drop */
2709 }
2710
2711 #ifdef RGFW_EGL
2712 if ((args & RGFW_NO_INIT_API) == 0)
2713 RGFW_createOpenGLContext(win);
2714 #endif
2715
2716 RGFW_window_setMouseDefault(win);
2717
2718 RGFW_windowsOpen++;
2719
2720 return win; /*return newly created window*/
2721 }
2722
2723 RGFW_area RGFW_getScreenSize(void) {
2724 assert(RGFW_root != NULL);
2725
2726 Screen* scrn = DefaultScreenOfDisplay((Display*) RGFW_root->src.display);
2727 return RGFW_AREA(scrn->width, scrn->height);
2728 }
2729
2730 RGFW_point RGFW_getGlobalMousePoint(void) {
2731 assert(RGFW_root != NULL);
2732
2733 RGFW_point RGFWMouse;
2734
2735 i32 x, y;
2736 u32 z;
2737 Window window1, window2;
2738 XQueryPointer((Display*) RGFW_root->src.display, XDefaultRootWindow((Display*) RGFW_root->src.display), &window1, &window2, &RGFWMouse.x, &RGFWMouse.y, &x, &y, &z);
2739
2740 return RGFWMouse;
2741 }
2742
2743 RGFW_point RGFW_window_getMousePoint(RGFW_window* win) {
2744 assert(win != NULL);
2745
2746 RGFW_point RGFWMouse;
2747
2748 i32 x, y;
2749 u32 z;
2750 Window window1, window2;
2751 XQueryPointer((Display*) win->src.display, win->src.window, &window1, &window2, &x, &y, &RGFWMouse.x, &RGFWMouse.y, &z);
2752
2753 return RGFWMouse;
2754 }
2755
2756 int xAxis = 0, yAxis = 0;
2757
2758 RGFW_Event* RGFW_window_checkEvent(RGFW_window* win) {
2759 assert(win != NULL);
2760
2761 static struct {
2762 long source, version;
2763 i32 format;
2764 } xdnd;
2765
2766 if (win->event.type == 0)
2767 RGFW_resetKey();
2768
2769 if (win->event.type == RGFW_quit) {
2770 return NULL;
2771 }
2772
2773 win->event.type = 0;
2774
2775#ifdef __linux__
2776 RGFW_Event* event = RGFW_linux_updateJoystick(win);
2777 if (event != NULL)
2778 return event;
2779#endif
2780
2781 XPending(win->src.display);
2782
2783 XEvent E; /*!< raw X11 event */
2784
2785 /* if there is no unread qued events, get a new one */
2786 if ((QLength(win->src.display) || XEventsQueued((Display*) win->src.display, QueuedAlready) + XEventsQueued((Display*) win->src.display, QueuedAfterReading))
2787 && win->event.type != RGFW_quit
2788 )
2789 XNextEvent((Display*) win->src.display, &E);
2790 else {
2791 return NULL;
2792 }
2793
2794 u32 i;
2795 win->event.type = 0;
2796
2797
2798 switch (E.type) {
2799 case KeyPress:
2800 case KeyRelease: {
2801 win->event.repeat = RGFW_FALSE;
2802 /* check if it's a real key release */
2803 if (E.type == KeyRelease && XEventsQueued((Display*) win->src.display, QueuedAfterReading)) { /* get next event if there is one*/
2804 XEvent NE;
2805 XPeekEvent((Display*) win->src.display, &NE);
2806
2807 if (E.xkey.time == NE.xkey.time && E.xkey.keycode == NE.xkey.keycode) /* check if the current and next are both the same*/
2808 win->event.repeat = RGFW_TRUE;
2809 }
2810
2811 /* set event key data */
2812 KeySym sym = (KeySym)XkbKeycodeToKeysym((Display*) win->src.display, E.xkey.keycode, 0, E.xkey.state & ShiftMask ? 1 : 0);
2813 win->event.keyCode = RGFW_apiKeyCodeToRGFW(E.xkey.keycode);
2814
2815 char* str = (char*)XKeysymToString(sym);
2816 if (str != NULL)
2817 strncpy(win->event.keyName, str, 16);
2818
2819 win->event.keyName[15] = '\0';
2820
2821 RGFW_keyboard[win->event.keyCode].prev = RGFW_isPressed(win, win->event.keyCode);
2822
2823 /* get keystate data */
2824 win->event.type = (E.type == KeyPress) ? RGFW_keyPressed : RGFW_keyReleased;
2825
2826 XKeyboardState keystate;
2827 XGetKeyboardControl((Display*) win->src.display, &keystate);
2828
2829 RGFW_updateLockState(win, (keystate.led_mask & 1), (keystate.led_mask & 2));
2830 RGFW_keyboard[win->event.keyCode].current = (E.type == KeyPress);
2831 RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, (E.type == KeyPress));
2832 break;
2833 }
2834 case ButtonPress:
2835 case ButtonRelease:
2836 win->event.type = RGFW_mouseButtonPressed + (E.type == ButtonRelease); // the events match
2837
2838 switch(win->event.button) {
2839 case RGFW_mouseScrollUp:
2840 win->event.scroll = 1;
2841 break;
2842 case RGFW_mouseScrollDown:
2843 win->event.scroll = -1;
2844 break;
2845 default: break;
2846 }
2847
2848 win->event.button = E.xbutton.button;
2849 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
2850
2851 if (win->event.repeat == RGFW_FALSE)
2852 win->event.repeat = RGFW_isPressed(win, win->event.keyCode);
2853
2854 RGFW_mouseButtons[win->event.button].current = (E.type == ButtonPress);
2855 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, (E.type == ButtonPress));
2856 break;
2857
2858 case MotionNotify:
2859 win->event.point.x = E.xmotion.x;
2860 win->event.point.y = E.xmotion.y;
2861
2862 if ((win->_winArgs & RGFW_HOLD_MOUSE)) {
2863 win->event.point.y = E.xmotion.y;
2864
2865 win->event.point.x = win->_lastMousePoint.x - abs(win->event.point.x);
2866 win->event.point.y = win->_lastMousePoint.y - abs(win->event.point.y);
2867 }
2868
2869 win->_lastMousePoint = RGFW_POINT(E.xmotion.x, E.xmotion.y);
2870
2871 win->event.type = RGFW_mousePosChanged;
2872 RGFW_mousePosCallback(win, win->event.point);
2873 break;
2874
2875 case GenericEvent: {
2876 /* MotionNotify is used for mouse events if the mouse isn't held */
2877 if (!(win->_winArgs & RGFW_HOLD_MOUSE)) {
2878 XFreeEventData(win->src.display, &E.xcookie);
2879 break;
2880 }
2881
2882 XGetEventData(win->src.display, &E.xcookie);
2883 if (E.xcookie.evtype == XI_RawMotion) {
2884 XIRawEvent *raw = (XIRawEvent *)E.xcookie.data;
2885 if (raw->valuators.mask_len == 0) {
2886 XFreeEventData(win->src.display, &E.xcookie);
2887 break;
2888 }
2889
2890 double deltaX = 0.0f;
2891 double deltaY = 0.0f;
2892
2893 /* check if relative motion data exists where we think it does */
2894 if (XIMaskIsSet(raw->valuators.mask, 0) != 0)
2895 deltaX += raw->raw_values[0];
2896 if (XIMaskIsSet(raw->valuators.mask, 1) != 0)
2897 deltaY += raw->raw_values[1];
2898
2899 win->event.point = RGFW_POINT((i32)deltaX, (i32)deltaY);
2900
2901 RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2)));
2902
2903 win->event.type = RGFW_mousePosChanged;
2904 RGFW_mousePosCallback(win, win->event.point);
2905 }
2906
2907 XFreeEventData(win->src.display, &E.xcookie);
2908 break;
2909 }
2910
2911 case Expose:
2912 win->event.type = RGFW_windowRefresh;
2913 RGFW_windowRefreshCallback(win);
2914 break;
2915
2916 case ClientMessage:
2917 /* if the client closed the window*/
2918 if (E.xclient.data.l[0] == (i64) wm_delete_window) {
2919 win->event.type = RGFW_quit;
2920 RGFW_windowQuitCallback(win);
2921 break;
2922 }
2923
2924 /* reset DND values */
2925 if (win->event.droppedFilesCount) {
2926 for (i = 0; i < win->event.droppedFilesCount; i++)
2927 win->event.droppedFiles[i][0] = '\0';
2928 }
2929
2930 win->event.droppedFilesCount = 0;
2931
2932 if ((win->_winArgs & RGFW_ALLOW_DND) == 0)
2933 break;
2934
2935 XEvent reply = { ClientMessage };
2936 reply.xclient.window = xdnd.source;
2937 reply.xclient.format = 32;
2938 reply.xclient.data.l[0] = (long) win->src.window;
2939 reply.xclient.data.l[1] = 0;
2940 reply.xclient.data.l[2] = None;
2941
2942 if (E.xclient.message_type == XdndEnter) {
2943 unsigned long count;
2944 Atom* formats;
2945 Atom real_formats[6];
2946
2947 Bool list = E.xclient.data.l[1] & 1;
2948
2949 xdnd.source = E.xclient.data.l[0];
2950 xdnd.version = E.xclient.data.l[1] >> 24;
2951 xdnd.format = None;
2952
2953 if (xdnd.version > 5)
2954 break;
2955
2956 if (list) {
2957 Atom actualType;
2958 i32 actualFormat;
2959 unsigned long bytesAfter;
2960
2961 XGetWindowProperty((Display*) win->src.display,
2962 xdnd.source,
2963 XdndTypeList,
2964 0,
2965 LONG_MAX,
2966 False,
2967 4,
2968 &actualType,
2969 &actualFormat,
2970 &count,
2971 &bytesAfter,
2972 (u8**) &formats);
2973 } else {
2974 count = 0;
2975
2976 if (E.xclient.data.l[2] != None)
2977 real_formats[count++] = E.xclient.data.l[2];
2978 if (E.xclient.data.l[3] != None)
2979 real_formats[count++] = E.xclient.data.l[3];
2980 if (E.xclient.data.l[4] != None)
2981 real_formats[count++] = E.xclient.data.l[4];
2982
2983 formats = real_formats;
2984 }
2985
2986 unsigned long i;
2987 for (i = 0; i < count; i++) {
2988 if (formats[i] == XtextUriList || formats[i] == XtextPlain) {
2989 xdnd.format = formats[i];
2990 break;
2991 }
2992 }
2993
2994 if (list) {
2995 XFree(formats);
2996 }
2997
2998 break;
2999 }
3000 if (E.xclient.message_type == XdndPosition) {
3001 const i32 xabs = (E.xclient.data.l[2] >> 16) & 0xffff;
3002 const i32 yabs = (E.xclient.data.l[2]) & 0xffff;
3003 Window dummy;
3004 i32 xpos, ypos;
3005
3006 if (xdnd.version > 5)
3007 break;
3008
3009 XTranslateCoordinates((Display*) win->src.display,
3010 XDefaultRootWindow((Display*) win->src.display),
3011 (Window) win->src.window,
3012 xabs, yabs,
3013 &xpos, &ypos,
3014 &dummy);
3015
3016 win->event.point.x = xpos;
3017 win->event.point.y = ypos;
3018
3019 reply.xclient.window = xdnd.source;
3020 reply.xclient.message_type = XdndStatus;
3021
3022 if (xdnd.format) {
3023 reply.xclient.data.l[1] = 1;
3024 if (xdnd.version >= 2)
3025 reply.xclient.data.l[4] = XdndActionCopy;
3026 }
3027
3028 XSendEvent((Display*) win->src.display, xdnd.source, False, NoEventMask, &reply);
3029 XFlush((Display*) win->src.display);
3030 break;
3031 }
3032
3033 if (E.xclient.message_type != XdndDrop)
3034 break;
3035
3036 if (xdnd.version > 5)
3037 break;
3038
3039 win->event.type = RGFW_dnd_init;
3040
3041 if (xdnd.format) {
3042 Time time = CurrentTime;
3043
3044 if (xdnd.version >= 1)
3045 time = E.xclient.data.l[2];
3046
3047 XConvertSelection((Display*) win->src.display,
3048 XdndSelection,
3049 xdnd.format,
3050 XdndSelection,
3051 (Window) win->src.window,
3052 time);
3053 } else if (xdnd.version >= 2) {
3054 XEvent reply = { ClientMessage };
3055
3056 XSendEvent((Display*) win->src.display, xdnd.source,
3057 False, NoEventMask, &reply);
3058 XFlush((Display*) win->src.display);
3059 }
3060
3061 RGFW_dndInitCallback(win, win->event.point);
3062 break;
3063 case SelectionNotify: {
3064 /* this is only for checking for xdnd drops */
3065 if (E.xselection.property != XdndSelection || !(win->_winArgs | RGFW_ALLOW_DND))
3066 break;
3067
3068 char* data;
3069 unsigned long result;
3070
3071 Atom actualType;
3072 i32 actualFormat;
3073 unsigned long bytesAfter;
3074
3075 XGetWindowProperty((Display*) win->src.display, E.xselection.requestor, E.xselection.property, 0, LONG_MAX, False, E.xselection.target, &actualType, &actualFormat, &result, &bytesAfter, (u8**) &data);
3076
3077 if (result == 0)
3078 break;
3079
3080 /*
3081 SOURCED FROM GLFW _glfwParseUriList
3082 Copyright (c) 2002-2006 Marcus Geelnard
3083 Copyright (c) 2006-2019 Camilla Löwy
3084 */
3085
3086 const char* prefix = (const char*)"file://";
3087
3088 char* line;
3089
3090 win->event.droppedFilesCount = 0;
3091
3092 win->event.type = RGFW_dnd;
3093
3094 while ((line = strtok(data, "\r\n"))) {
3095 char path[RGFW_MAX_PATH];
3096
3097 data = NULL;
3098
3099 if (line[0] == '#')
3100 continue;
3101
3102 char* l;
3103 for (l = line; 1; l++) {
3104 if ((l - line) > 7)
3105 break;
3106 else if (*l != prefix[(l - line)])
3107 break;
3108 else if (*l == '\0' && prefix[(l - line)] == '\0') {
3109 line += 7;
3110 while (*line != '/')
3111 line++;
3112 break;
3113 } else if (*l == '\0')
3114 break;
3115 }
3116
3117 win->event.droppedFilesCount++;
3118
3119 size_t index = 0;
3120 while (*line) {
3121 if (line[0] == '%' && line[1] && line[2]) {
3122 const char digits[3] = { line[1], line[2], '\0' };
3123 path[index] = (char) strtol(digits, NULL, 16);
3124 line += 2;
3125 } else
3126 path[index] = *line;
3127
3128 index++;
3129 line++;
3130 }
3131 path[index] = '\0';
3132 strncpy(win->event.droppedFiles[win->event.droppedFilesCount - 1], path, index + 1);
3133 }
3134
3135 if (data)
3136 XFree(data);
3137
3138 if (xdnd.version >= 2) {
3139 reply.xclient.message_type = XdndFinished;
3140 reply.xclient.data.l[1] = result;
3141 reply.xclient.data.l[2] = XdndActionCopy;
3142
3143 XSendEvent((Display*) win->src.display, xdnd.source, False, NoEventMask, &reply);
3144 XFlush((Display*) win->src.display);
3145 }
3146
3147 RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount);
3148 break;
3149 }
3150 case FocusIn:
3151 win->event.inFocus = 1;
3152 win->event.type = RGFW_focusIn;
3153 RGFW_focusCallback(win, 1);
3154 break;
3155
3156 break;
3157 case FocusOut:
3158 win->event.inFocus = 0;
3159 win->event.type = RGFW_focusOut;
3160 RGFW_focusCallback(win, 0);
3161 break;
3162
3163 case EnterNotify: {
3164 win->event.type = RGFW_mouseEnter;
3165 win->event.point.x = E.xcrossing.x;
3166 win->event.point.y = E.xcrossing.y;
3167 RGFW_mouseNotifyCallBack(win, win->event.point, 1);
3168 break;
3169 }
3170
3171 case LeaveNotify: {
3172 win->event.type = RGFW_mouseLeave;
3173 RGFW_mouseNotifyCallBack(win, win->event.point, 0);
3174 break;
3175 }
3176
3177 case ConfigureNotify: {
3178 /* detect resize */
3179 if (E.xconfigure.width != win->r.w || E.xconfigure.height != win->r.h) {
3180 win->event.type = RGFW_windowResized;
3181 win->r = RGFW_RECT(win->r.x, win->r.y, E.xconfigure.width, E.xconfigure.height);
3182 RGFW_windowResizeCallback(win, win->r);
3183 break;
3184 }
3185
3186 /* detect move */
3187 if (E.xconfigure.x != win->r.x || E.xconfigure.y != win->r.y) {
3188 win->event.type = RGFW_windowMoved;
3189 win->r = RGFW_RECT(E.xconfigure.x, E.xconfigure.y, win->r.w, win->r.h);
3190 RGFW_windowMoveCallback(win, win->r);
3191 break;
3192 }
3193
3194 break;
3195 }
3196 default: {
3197 break;
3198 }
3199 }
3200
3201 XFlush((Display*) win->src.display);
3202
3203 if (win->event.type)
3204 return &win->event;
3205 else
3206 return NULL;
3207 }
3208
3209 void RGFW_window_move(RGFW_window* win, RGFW_point v) {
3210 assert(win != NULL);
3211 win->r.x = v.x;
3212 win->r.y = v.y;
3213
3214 XMoveWindow((Display*) win->src.display, (Window) win->src.window, v.x, v.y);
3215 }
3216
3217
3218 void RGFW_window_resize(RGFW_window* win, RGFW_area a) {
3219 assert(win != NULL);
3220 win->r.w = a.w;
3221 win->r.h = a.h;
3222
3223 XResizeWindow((Display*) win->src.display, (Window) win->src.window, a.w, a.h);
3224 }
3225
3226 void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) {
3227 assert(win != NULL);
3228
3229 if (a.w == 0 && a.h == 0)
3230 return;
3231
3232 XSizeHints hints;
3233 long flags;
3234
3235 XGetWMNormalHints(win->src.display, (Window) win->src.window, &hints, &flags);
3236
3237 hints.flags |= PMinSize;
3238
3239 hints.min_width = a.w;
3240 hints.min_height = a.h;
3241
3242 XSetWMNormalHints(win->src.display, (Window) win->src.window, &hints);
3243 }
3244
3245 void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) {
3246 assert(win != NULL);
3247
3248 if (a.w == 0 && a.h == 0)
3249 return;
3250
3251 XSizeHints hints;
3252 long flags;
3253
3254 XGetWMNormalHints(win->src.display, (Window) win->src.window, &hints, &flags);
3255
3256 hints.flags |= PMaxSize;
3257
3258 hints.max_width = a.w;
3259 hints.max_height = a.h;
3260
3261 XSetWMNormalHints(win->src.display, (Window) win->src.window, &hints);
3262 }
3263
3264
3265 void RGFW_window_minimize(RGFW_window* win) {
3266 assert(win != NULL);
3267
3268 XIconifyWindow(win->src.display, (Window) win->src.window, DefaultScreen(win->src.display));
3269 XFlush(win->src.display);
3270 }
3271
3272 void RGFW_window_restore(RGFW_window* win) {
3273 assert(win != NULL);
3274
3275 XMapWindow(win->src.display, (Window) win->src.window);
3276 XFlush(win->src.display);
3277 }
3278
3279 void RGFW_window_setName(RGFW_window* win, char* name) {
3280 assert(win != NULL);
3281
3282 XStoreName((Display*) win->src.display, (Window) win->src.window, name);
3283 }
3284
3285 void* RGFW_libxshape = NULL;
3286
3287 #ifndef RGFW_NO_PASSTHROUGH
3288 void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough) {
3289 assert(win != NULL);
3290
3291 #if defined(__CYGWIN__)
3292 RGFW_libxshape = dlopen("libXext-6.so", RTLD_LAZY | RTLD_LOCAL);
3293 #elif defined(__OpenBSD__) || defined(__NetBSD__)
3294 RGFW_libxshape = dlopen("libXext.so", RTLD_LAZY | RTLD_LOCAL);
3295 #else
3296 RGFW_libxshape = dlopen("libXext.so.6", RTLD_LAZY | RTLD_LOCAL);
3297 #endif
3298
3299 typedef void (* PFN_XShapeCombineMask)(Display*,Window,int,int,int,Pixmap,int);
3300 static PFN_XShapeCombineMask XShapeCombineMask;
3301
3302 typedef void (* PFN_XShapeCombineRegion)(Display*,Window,int,int,int,Region,int);
3303 static PFN_XShapeCombineRegion XShapeCombineRegion;
3304
3305 if (XShapeCombineMask != NULL)
3306 XShapeCombineMask = (PFN_XShapeCombineMask) dlsym(RGFW_libxshape, "XShapeCombineMask");
3307
3308 if (XShapeCombineRegion != NULL)
3309 XShapeCombineRegion = (PFN_XShapeCombineRegion) dlsym(RGFW_libxshape, "XShapeCombineMask");
3310
3311 if (passthrough) {
3312 Region region = XCreateRegion();
3313 XShapeCombineRegion(win->src.display, win->src.window, ShapeInput, 0, 0, region, ShapeSet);
3314 XDestroyRegion(region);
3315
3316 return;
3317 }
3318
3319 XShapeCombineMask(win->src.display, win->src.window, ShapeInput, 0, 0, None, ShapeSet);
3320 }
3321 #endif
3322
3323 /*
3324 the majority function is sourced from GLFW
3325 */
3326
3327 void RGFW_window_setIcon(RGFW_window* win, u8* icon, RGFW_area a, i32 channels) {
3328 assert(win != NULL);
3329
3330 i32 longCount = 2 + a.w * a.h;
3331
3332 u64* X11Icon = (u64*) RGFW_MALLOC(longCount * sizeof(u64));
3333 u64* target = X11Icon;
3334
3335 *target++ = a.w;
3336 *target++ = a.h;
3337
3338 u32 i;
3339
3340 for (i = 0; i < a.w * a.h; i++) {
3341 if (channels == 3)
3342 *target++ = ((icon[i * 3 + 0]) << 16) |
3343 ((icon[i * 3 + 1]) << 8) |
3344 ((icon[i * 3 + 2]) << 0) |
3345 (0xFF << 24);
3346
3347 else if (channels == 4)
3348 *target++ = ((icon[i * 4 + 0]) << 16) |
3349 ((icon[i * 4 + 1]) << 8) |
3350 ((icon[i * 4 + 2]) << 0) |
3351 ((icon[i * 4 + 3]) << 24);
3352 }
3353
3354 static Atom NET_WM_ICON = 0;
3355 if (NET_WM_ICON == 0)
3356 NET_WM_ICON = XInternAtom((Display*) win->src.display, "_NET_WM_ICON", False);
3357
3358 XChangeProperty((Display*) win->src.display, (Window) win->src.window,
3359 NET_WM_ICON,
3360 6, 32,
3361 PropModeReplace,
3362 (u8*) X11Icon,
3363 longCount);
3364
3365 RGFW_FREE(X11Icon);
3366
3367 XFlush((Display*) win->src.display);
3368 }
3369
3370 void RGFW_window_setMouse(RGFW_window* win, u8* image, RGFW_area a, i32 channels) {
3371 assert(win != NULL);
3372
3373#ifndef RGFW_NO_X11_CURSOR
3374 XcursorImage* native = XcursorImageCreate(a.w, a.h);
3375 native->xhot = 0;
3376 native->yhot = 0;
3377
3378 u8* source = (u8*) image;
3379 XcursorPixel* target = native->pixels;
3380
3381 u32 i;
3382 for (i = 0; i < a.w * a.h; i++, target++, source += 4) {
3383 u8 alpha = 0xFF;
3384 if (channels == 4)
3385 alpha = source[3];
3386
3387 *target = (alpha << 24) | (((source[0] * alpha) / 255) << 16) | (((source[1] * alpha) / 255) << 8) | (((source[2] * alpha) / 255) << 0);
3388 }
3389
3390 Cursor cursor = XcursorImageLoadCursor((Display*) win->src.display, native);
3391 XDefineCursor((Display*) win->src.display, (Window) win->src.window, (Cursor) cursor);
3392
3393 XFreeCursor((Display*) win->src.display, (Cursor) cursor);
3394 XcursorImageDestroy(native);
3395#else
3396 RGFW_UNUSED(image) RGFW_UNUSED(a.w) RGFW_UNUSED(channels)
3397#endif
3398 }
3399
3400 void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) {
3401 assert(win != NULL);
3402
3403 XEvent event;
3404 XQueryPointer(win->src.display, DefaultRootWindow(win->src.display),
3405 &event.xbutton.root, &event.xbutton.window,
3406 &event.xbutton.x_root, &event.xbutton.y_root,
3407 &event.xbutton.x, &event.xbutton.y,
3408 &event.xbutton.state);
3409
3410 if (event.xbutton.x == v.x && event.xbutton.y == v.y)
3411 return;
3412
3413 XWarpPointer(win->src.display, None, win->src.window, 0, 0, 0, 0, (int) v.x - win->r.x, (int) v.y - win->r.y);
3414 }
3415
3416 RGFWDEF void RGFW_window_disableMouse(RGFW_window* win) {
3417 RGFW_UNUSED(win);
3418 }
3419
3420 void RGFW_window_setMouseDefault(RGFW_window* win) {
3421 RGFW_window_setMouseStandard(win, RGFW_MOUSE_ARROW);
3422 }
3423
3424 void RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) {
3425 assert(win != NULL);
3426
3427 if (mouse > (sizeof(RGFW_mouseIconSrc) / sizeof(u8)))
3428 return;
3429
3430 mouse = RGFW_mouseIconSrc[mouse];
3431
3432 Cursor cursor = XCreateFontCursor((Display*) win->src.display, mouse);
3433 XDefineCursor((Display*) win->src.display, (Window) win->src.window, (Cursor) cursor);
3434
3435 XFreeCursor((Display*) win->src.display, (Cursor) cursor);
3436 }
3437
3438 void RGFW_window_hide(RGFW_window* win) {
3439 XMapWindow(win->src.display, win->src.window);
3440 }
3441
3442 void RGFW_window_show(RGFW_window* win) {
3443 XUnmapWindow(win->src.display, win->src.window);
3444 }
3445
3446 /*
3447 the majority function is sourced from GLFW
3448 */
3449 char* RGFW_readClipboard(size_t* size) {
3450 static Atom UTF8 = 0;
3451 if (UTF8 == 0)
3452 UTF8 = XInternAtom(RGFW_root->src.display, "UTF8_STRING", True);
3453
3454 XEvent event;
3455 int format;
3456 unsigned long N, sizeN;
3457 char* data, * s = NULL;
3458 Atom target;
3459 Atom CLIPBOARD = 0, XSEL_DATA = 0;
3460
3461 if (CLIPBOARD == 0) {
3462 CLIPBOARD = XInternAtom(RGFW_root->src.display, "CLIPBOARD", 0);
3463 XSEL_DATA = XInternAtom(RGFW_root->src.display, "XSEL_DATA", 0);
3464 }
3465
3466 XConvertSelection(RGFW_root->src.display, CLIPBOARD, UTF8, XSEL_DATA, RGFW_root->src.window, CurrentTime);
3467 XSync(RGFW_root->src.display, 0);
3468 XNextEvent(RGFW_root->src.display, &event);
3469
3470 if (event.type != SelectionNotify || event.xselection.selection != CLIPBOARD || event.xselection.property == 0)
3471 return NULL;
3472
3473 XGetWindowProperty(event.xselection.display, event.xselection.requestor,
3474 event.xselection.property, 0L, (~0L), 0, AnyPropertyType, &target,
3475 &format, &sizeN, &N, (unsigned char**) &data);
3476
3477 if (target == UTF8 || target == XA_STRING) {
3478 s = (char*)RGFW_MALLOC(sizeof(char) * sizeN);
3479 strncpy(s, data, sizeN);
3480 s[sizeN] = '\0';
3481 XFree(data);
3482 }
3483
3484 XDeleteProperty(event.xselection.display, event.xselection.requestor, event.xselection.property);
3485
3486 if (s != NULL && size != NULL)
3487 *size = sizeN;
3488
3489 return s;
3490 }
3491
3492 /*
3493 almost all of this function is sourced from GLFW
3494 */
3495 void RGFW_writeClipboard(const char* text, u32 textLen) {
3496 static Atom CLIPBOARD = 0,
3497 UTF8_STRING = 0,
3498 SAVE_TARGETS = 0,
3499 TARGETS = 0,
3500 MULTIPLE = 0,
3501 ATOM_PAIR = 0,
3502 CLIPBOARD_MANAGER = 0;
3503
3504 if (CLIPBOARD == 0) {
3505 CLIPBOARD = XInternAtom((Display*) RGFW_root->src.display, "CLIPBOARD", False);
3506 UTF8_STRING = XInternAtom((Display*) RGFW_root->src.display, "UTF8_STRING", False);
3507 SAVE_TARGETS = XInternAtom((Display*) RGFW_root->src.display, "SAVE_TARGETS", False);
3508 TARGETS = XInternAtom((Display*) RGFW_root->src.display, "TARGETS", False);
3509 MULTIPLE = XInternAtom((Display*) RGFW_root->src.display, "MULTIPLE", False);
3510 ATOM_PAIR = XInternAtom((Display*) RGFW_root->src.display, "ATOM_PAIR", False);
3511 CLIPBOARD_MANAGER = XInternAtom((Display*) RGFW_root->src.display, "CLIPBOARD_MANAGER", False);
3512 }
3513
3514 XSetSelectionOwner((Display*) RGFW_root->src.display, CLIPBOARD, (Window) RGFW_root->src.window, CurrentTime);
3515
3516 XConvertSelection((Display*) RGFW_root->src.display, CLIPBOARD_MANAGER, SAVE_TARGETS, None, (Window) RGFW_root->src.window, CurrentTime);
3517 for (;;) {
3518 XEvent event;
3519
3520 XNextEvent((Display*) RGFW_root->src.display, &event);
3521 if (event.type != SelectionRequest) {
3522 break;
3523 }
3524
3525 const XSelectionRequestEvent* request = &event.xselectionrequest;
3526
3527 XEvent reply = { SelectionNotify };
3528 reply.xselection.property = 0;
3529
3530 if (request->target == TARGETS) {
3531 const Atom targets[] = { TARGETS,
3532 MULTIPLE,
3533 UTF8_STRING,
3534 XA_STRING };
3535
3536 XChangeProperty((Display*) RGFW_root->src.display,
3537 request->requestor,
3538 request->property,
3539 4,
3540 32,
3541 PropModeReplace,
3542 (u8*) targets,
3543 sizeof(targets) / sizeof(targets[0]));
3544
3545 reply.xselection.property = request->property;
3546 }
3547
3548 if (request->target == MULTIPLE) {
3549 Atom* targets = NULL;
3550
3551 Atom actualType = 0;
3552 int actualFormat = 0;
3553 unsigned long count = 0, bytesAfter = 0;
3554
3555 XGetWindowProperty((Display*) RGFW_root->src.display, request->requestor, request->property, 0, LONG_MAX, False, ATOM_PAIR, &actualType, &actualFormat, &count, &bytesAfter, (u8**) &targets);
3556
3557 unsigned long i;
3558 for (i = 0; i < (u32)count; i += 2) {
3559 if (targets[i] == UTF8_STRING || targets[i] == XA_STRING) {
3560 XChangeProperty((Display*) RGFW_root->src.display,
3561 request->requestor,
3562 targets[i + 1],
3563 targets[i],
3564 8,
3565 PropModeReplace,
3566 (u8*) text,
3567 textLen);
3568 XFlush(RGFW_root->src.display);
3569 } else {
3570 targets[i + 1] = None;
3571 }
3572 }
3573
3574 XChangeProperty((Display*) RGFW_root->src.display,
3575 request->requestor,
3576 request->property,
3577 ATOM_PAIR,
3578 32,
3579 PropModeReplace,
3580 (u8*) targets,
3581 count);
3582
3583 XFlush(RGFW_root->src.display);
3584 XFree(targets);
3585
3586 reply.xselection.property = request->property;
3587 }
3588
3589 reply.xselection.display = request->display;
3590 reply.xselection.requestor = request->requestor;
3591 reply.xselection.selection = request->selection;
3592 reply.xselection.target = request->target;
3593 reply.xselection.time = request->time;
3594
3595 XSendEvent((Display*) RGFW_root->src.display, request->requestor, False, 0, &reply);
3596 XFlush(RGFW_root->src.display);
3597 }
3598 }
3599
3600 u8 RGFW_window_isFullscreen(RGFW_window* win) {
3601 assert(win != NULL);
3602
3603 XWindowAttributes windowAttributes;
3604 XGetWindowAttributes(win->src.display, (Window) win->src.window, &windowAttributes);
3605
3606 /* check if the window is visable */
3607 if (windowAttributes.map_state != IsViewable)
3608 return 0;
3609
3610 /* check if the window covers the full screen */
3611 return (windowAttributes.x == 0 && windowAttributes.y == 0 &&
3612 windowAttributes.width == XDisplayWidth(win->src.display, DefaultScreen(win->src.display)) &&
3613 windowAttributes.height == XDisplayHeight(win->src.display, DefaultScreen(win->src.display)));
3614 }
3615
3616 u8 RGFW_window_isHidden(RGFW_window* win) {
3617 assert(win != NULL);
3618
3619 XWindowAttributes windowAttributes;
3620 XGetWindowAttributes(win->src.display, (Window) win->src.window, &windowAttributes);
3621
3622 return (windowAttributes.map_state == IsUnmapped && !RGFW_window_isMinimized(win));
3623 }
3624
3625 u8 RGFW_window_isMinimized(RGFW_window* win) {
3626 assert(win != NULL);
3627
3628 static Atom prop = 0;
3629 if (prop == 0)
3630 prop = XInternAtom(win->src.display, "WM_STATE", False);
3631
3632 Atom actual_type;
3633 i32 actual_format;
3634 unsigned long nitems, bytes_after;
3635 unsigned char* prop_data;
3636
3637 i16 status = XGetWindowProperty(win->src.display, (Window) win->src.window, prop, 0, 2, False,
3638 AnyPropertyType, &actual_type, &actual_format,
3639 &nitems, &bytes_after, &prop_data);
3640
3641 if (status == Success && nitems >= 1 && *((int*) prop_data) == IconicState) {
3642 XFree(prop_data);
3643 return 1;
3644 }
3645
3646 if (prop_data != NULL)
3647 XFree(prop_data);
3648
3649 return 0;
3650 }
3651
3652 u8 RGFW_window_isMaximized(RGFW_window* win) {
3653 assert(win != NULL);
3654
3655 static Atom net_wm_state = 0;
3656 static Atom net_wm_state_maximized_horz = 0;
3657 static Atom net_wm_state_maximized_vert = 0;
3658
3659 if (net_wm_state == 0) {
3660 net_wm_state = XInternAtom(win->src.display, "_NET_WM_STATE", False);
3661 net_wm_state_maximized_vert = XInternAtom(win->src.display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
3662 net_wm_state_maximized_horz = XInternAtom(win->src.display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
3663 }
3664
3665 Atom actual_type;
3666 i32 actual_format;
3667 unsigned long nitems, bytes_after;
3668 unsigned char* prop_data;
3669
3670 i16 status = XGetWindowProperty(win->src.display, (Window) win->src.window, net_wm_state, 0, 1024, False,
3671 XA_ATOM, &actual_type, &actual_format,
3672 &nitems, &bytes_after, &prop_data);
3673
3674 if (status != Success) {
3675 if (prop_data != NULL)
3676 XFree(prop_data);
3677
3678 return 0;
3679 }
3680
3681 Atom* atoms = (Atom*) prop_data;
3682 u64 i;
3683 for (i = 0; i < nitems; ++i) {
3684 if (atoms[i] == net_wm_state_maximized_horz ||
3685 atoms[i] == net_wm_state_maximized_vert) {
3686 XFree(prop_data);
3687 return 1;
3688 }
3689 }
3690
3691 return 0;
3692 }
3693
3694 static void XGetSystemContentScale(Display* display, float* xscale, float* yscale) {
3695 float xdpi = 96.f, ydpi = 96.f;
3696
3697#ifndef RGFW_NO_DPI
3698 char* rms = XResourceManagerString(display);
3699 XrmDatabase db = NULL;
3700
3701 if (rms && db)
3702 db = XrmGetStringDatabase(rms);
3703
3704 if (db == 0) {
3705 *xscale = xdpi / 96.f;
3706 *yscale = ydpi / 96.f;
3707 return;
3708 }
3709
3710 XrmValue value;
3711 char* type = NULL;
3712
3713 if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value) && type && strncmp(type, "String", 7) == 0)
3714 xdpi = ydpi = atof(value.addr);
3715 XrmDestroyDatabase(db);
3716#endif
3717
3718 * xscale = xdpi / 96.f;
3719 *yscale = ydpi / 96.f;
3720 }
3721
3722 RGFW_monitor RGFW_XCreateMonitor(i32 screen) {
3723 RGFW_monitor monitor;
3724
3725 Display* display = XOpenDisplay(NULL);
3726
3727 RGFW_area size = RGFW_getScreenSize();
3728
3729 monitor.rect = RGFW_RECT(0, 0, size.w, size.h);
3730 monitor.physW = DisplayWidthMM(display, screen);
3731 monitor.physH = DisplayHeightMM(display, screen);
3732
3733 XGetSystemContentScale(display, &monitor.scaleX, &monitor.scaleY);
3734 XRRScreenResources* sr = XRRGetScreenResourcesCurrent(display, RootWindow(display, screen));
3735
3736 XRRCrtcInfo* ci = NULL;
3737 int crtc = screen;
3738
3739 if (sr->ncrtc > crtc) {
3740 ci = XRRGetCrtcInfo(display, sr, sr->crtcs[crtc]);
3741 }
3742
3743 if (ci == NULL) {
3744 float dpi_width = round((double)monitor.rect.w/(((double)monitor.physW)/25.4));
3745 float dpi_height = round((double)monitor.rect.h/(((double)monitor.physH)/25.4));
3746
3747 monitor.scaleX = (float) (dpi_width) / (float) 96;
3748 monitor.scaleY = (float) (dpi_height) / (float) 96;
3749 XRRFreeScreenResources(sr);
3750 XCloseDisplay(display);
3751 return monitor;
3752 }
3753
3754 XRROutputInfo* info = XRRGetOutputInfo (display, sr, sr->outputs[screen]);
3755 monitor.physW = info->mm_width;
3756 monitor.physH = info->mm_height;
3757
3758 monitor.rect.x = ci->x;
3759 monitor.rect.y = ci->y;
3760 monitor.rect.w = ci->width;
3761 monitor.rect.h = ci->height;
3762
3763 float dpi_width = round((double)monitor.rect.w/(((double)monitor.physW)/25.4));
3764 float dpi_height = round((double)monitor.rect.h/(((double)monitor.physH)/25.4));
3765
3766 monitor.scaleX = (float) (dpi_width) / (float) 96;
3767 monitor.scaleY = (float) (dpi_height) / (float) 96;
3768
3769 if (monitor.scaleX > 1 && monitor.scaleX < 1.1)
3770 monitor.scaleX = 1;
3771
3772 if (monitor.scaleY > 1 && monitor.scaleY < 1.1)
3773 monitor.scaleY = 1;
3774
3775 XRRFreeCrtcInfo(ci);
3776 XRRFreeScreenResources(sr);
3777
3778 XCloseDisplay(display);
3779
3780 return monitor;
3781 }
3782
3783 RGFW_monitor RGFW_monitors[6];
3784 RGFW_monitor* RGFW_getMonitors(void) {
3785 size_t i;
3786 for (i = 0; i < (size_t)ScreenCount(RGFW_root->src.display) && i < 6; i++)
3787 RGFW_monitors[i] = RGFW_XCreateMonitor(i);
3788
3789 return RGFW_monitors;
3790 }
3791
3792 RGFW_monitor RGFW_getPrimaryMonitor(void) {
3793 assert(RGFW_root != NULL);
3794
3795 i32 primary = -1;
3796 Window root = DefaultRootWindow(RGFW_root->src.display);
3797 XRRScreenResources* res = XRRGetScreenResources(RGFW_root->src.display, root);
3798
3799 for (int i = 0; i < res->noutput; i++) {
3800 XRROutputInfo* output_info = XRRGetOutputInfo(RGFW_root->src.display, res, res->outputs[i]);
3801 if (output_info->connection == RR_Connected && output_info->crtc) {
3802 XRRCrtcInfo* crtc_info = XRRGetCrtcInfo(RGFW_root->src.display, res, output_info->crtc);
3803 if (crtc_info->mode != None && crtc_info->x == 0 && crtc_info->y == 0) {
3804 primary = i;
3805 XRRFreeCrtcInfo(crtc_info);
3806 XRRFreeOutputInfo(output_info);
3807 break;
3808 }
3809 XRRFreeCrtcInfo(crtc_info);
3810 }
3811 XRRFreeOutputInfo(output_info);
3812 }
3813
3814 XRRFreeScreenResources(res);
3815
3816 return RGFW_XCreateMonitor(primary);
3817 }
3818
3819 RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) {
3820 return RGFW_XCreateMonitor(DefaultScreen(win->src.display));
3821 }
3822
3823 #ifdef RGFW_OPENGL
3824 void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
3825 if (win == NULL)
3826 glXMakeCurrent((Display*) NULL, (Drawable)NULL, (GLXContext) NULL);
3827 else
3828 glXMakeCurrent((Display*) win->src.display, (Drawable) win->src.window, (GLXContext) win->src.ctx);
3829 }
3830 #endif
3831
3832
3833 void RGFW_window_swapBuffers(RGFW_window* win) {
3834 assert(win != NULL);
3835
3836 /* clear the window*/
3837 if (!(win->_winArgs & RGFW_NO_CPU_RENDER)) {
3838#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
3839 #ifdef RGFW_OSMESA
3840 RGFW_OSMesa_reorganize();
3841 #endif
3842 RGFW_area area = RGFW_bufferSize;
3843
3844#ifndef RGFW_X11_DONT_CONVERT_BGR
3845 win->src.bitmap->data = (char*) win->buffer;
3846 u32 x, y;
3847 for (y = 0; y < (u32)win->r.h; y++) {
3848 for (x = 0; x < (u32)win->r.w; x++) {
3849 u32 index = (y * 4 * area.w) + x * 4;
3850
3851 u8 red = win->src.bitmap->data[index];
3852 win->src.bitmap->data[index] = win->buffer[index + 2];
3853 win->src.bitmap->data[index + 2] = red;
3854
3855 }
3856 }
3857#endif
3858 XPutImage(win->src.display, (Window) win->src.window, win->src.gc, win->src.bitmap, 0, 0, 0, 0, RGFW_bufferSize.w, RGFW_bufferSize.h);
3859#endif
3860 }
3861
3862 if (!(win->_winArgs & RGFW_NO_GPU_RENDER)) {
3863 #ifdef RGFW_EGL
3864 eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface);
3865 #elif defined(RGFW_OPENGL)
3866 glXSwapBuffers((Display*) win->src.display, (Window) win->src.window);
3867 #endif
3868 }
3869 }
3870
3871 #if !defined(RGFW_EGL)
3872 void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) {
3873 assert(win != NULL);
3874
3875 #if defined(RGFW_OPENGL)
3876 ((PFNGLXSWAPINTERVALEXTPROC) glXGetProcAddress((GLubyte*) "glXSwapIntervalEXT"))((Display*) win->src.display, (Window) win->src.window, swapInterval);
3877 #else
3878 RGFW_UNUSED(swapInterval);
3879 #endif
3880 }
3881 #endif
3882
3883
3884 void RGFW_window_close(RGFW_window* win) {
3885 /* ungrab pointer if it was grabbed */
3886 if (win->_winArgs & RGFW_HOLD_MOUSE)
3887 XUngrabPointer(win->src.display, CurrentTime);
3888
3889 assert(win != NULL);
3890#ifdef RGFW_EGL
3891 RGFW_closeEGL(win);
3892#endif
3893
3894#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
3895 if (win->buffer != NULL) {
3896 XDestroyImage((XImage*) win->src.bitmap);
3897 XFreeGC(win->src.display, win->src.gc);
3898 }
3899#endif
3900
3901 if ((Display*) win->src.display) {
3902#ifdef RGFW_OPENGL
3903 glXDestroyContext((Display*) win->src.display, win->src.ctx);
3904#endif
3905
3906 if (win == RGFW_root)
3907 RGFW_root = NULL;
3908
3909 if ((Drawable) win->src.window)
3910 XDestroyWindow((Display*) win->src.display, (Drawable) win->src.window); /*!< close the window*/
3911
3912 XCloseDisplay((Display*) win->src.display); /*!< kill the display*/
3913 }
3914
3915#ifdef RGFW_ALLOC_DROPFILES
3916 {
3917 u32 i;
3918 for (i = 0; i < RGFW_MAX_DROPS; i++)
3919 RGFW_FREE(win->event.droppedFiles[i]);
3920
3921
3922 RGFW_FREE(win->event.droppedFiles);
3923 }
3924#endif
3925
3926 RGFW_windowsOpen--;
3927#if !defined(RGFW_NO_X11_CURSOR_PRELOAD) && !defined(RGFW_NO_X11_CURSOR)
3928 if (X11Cursorhandle != NULL && RGFW_windowsOpen <= 0) {
3929 dlclose(X11Cursorhandle);
3930
3931 X11Cursorhandle = NULL;
3932 }
3933#endif
3934#if !defined(RGFW_NO_X11_XI_PRELOAD)
3935 if (X11Xihandle != NULL && RGFW_windowsOpen <= 0) {
3936 dlclose(X11Xihandle);
3937
3938 X11Xihandle = NULL;
3939 }
3940#endif
3941
3942 if (RGFW_libxshape != NULL && RGFW_windowsOpen <= 0) {
3943 dlclose(RGFW_libxshape);
3944 RGFW_libxshape = NULL;
3945 }
3946
3947 if (RGFW_windowsOpen <= 0) {
3948 if (RGFW_eventWait_forceStop[0] || RGFW_eventWait_forceStop[1]){
3949 close(RGFW_eventWait_forceStop[0]);
3950 close(RGFW_eventWait_forceStop[1]);
3951 }
3952
3953 u8 i;
3954 for (i = 0; i < RGFW_joystickCount; i++)
3955 close(RGFW_joysticks[i]);
3956 }
3957
3958 /* set cleared display / window to NULL for error checking */
3959 win->src.display = (Display*) 0;
3960 win->src.window = (Window) 0;
3961
3962 RGFW_FREE(win); /*!< free collected window data */
3963 }
3964
3965
3966/*
3967 End of X11 linux / unix defines
3968*/
3969
3970#endif /* RGFW_X11 */
3971
3972
3973/* wayland or X11 defines*/
3974#if defined(RGFW_WAYLAND) || defined(RGFW_X11)
3975#include <fcntl.h>
3976#include <poll.h>
3977#include <unistd.h>
3978 u16 RGFW_registerJoystickF(RGFW_window* win, char* file) {
3979 assert(win != NULL);
3980
3981#ifdef __linux__
3982
3983 i32 js = open(file, O_RDONLY);
3984
3985 if (js && RGFW_joystickCount < 4) {
3986 RGFW_joystickCount++;
3987
3988 RGFW_joysticks[RGFW_joystickCount - 1] = open(file, O_RDONLY);
3989
3990 u8 i;
3991 for (i = 0; i < 16; i++)
3992 RGFW_jsPressed[RGFW_joystickCount - 1][i] = 0;
3993
3994 }
3995
3996 else {
3997#ifdef RGFW_PRINT_ERRORS
3998 RGFW_error = 1;
3999 fprintf(stderr, "Error RGFW_registerJoystickF : Cannot open file %s\n", file);
4000#endif
4001 }
4002
4003 return RGFW_joystickCount - 1;
4004#endif
4005 }
4006
4007 u16 RGFW_registerJoystick(RGFW_window* win, i32 jsNumber) {
4008 assert(win != NULL);
4009
4010#ifdef __linux__
4011 char file[15];
4012 sprintf(file, "/dev/input/js%i", jsNumber);
4013
4014 return RGFW_registerJoystickF(win, file);
4015#endif
4016 }
4017
4018 void RGFW_stopCheckEvents(void) {
4019 RGFW_eventWait_forceStop[2] = 1;
4020 while (1) {
4021 const char byte = 0;
4022 const ssize_t result = write(RGFW_eventWait_forceStop[1], &byte, 1);
4023 if (result == 1 || result == -1)
4024 break;
4025 }
4026 }
4027
4028 void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) {
4029 if (waitMS == 0)
4030 return;
4031
4032 u8 i;
4033
4034 if (RGFW_eventWait_forceStop[0] == 0 || RGFW_eventWait_forceStop[1] == 0) {
4035 if (pipe(RGFW_eventWait_forceStop) != -1) {
4036 fcntl(RGFW_eventWait_forceStop[0], F_GETFL, 0);
4037 fcntl(RGFW_eventWait_forceStop[0], F_GETFD, 0);
4038 fcntl(RGFW_eventWait_forceStop[1], F_GETFL, 0);
4039 fcntl(RGFW_eventWait_forceStop[1], F_GETFD, 0);
4040 }
4041 }
4042
4043 struct pollfd fds[] = {
4044 #ifdef RGFW_WAYLAND
4045 { wl_display_get_fd(win->src.display), POLLIN, 0 },
4046 #else
4047 { ConnectionNumber(win->src.display), POLLIN, 0 },
4048 #endif
4049 { RGFW_eventWait_forceStop[0], POLLIN, 0 },
4050 #ifdef __linux__ /* blank space for 4 joystick files*/
4051 { -1, POLLIN, 0 }, {-1, POLLIN, 0 }, {-1, POLLIN, 0 }, {-1, POLLIN, 0}
4052 #endif
4053 };
4054
4055 u8 index = 2;
4056
4057 #if defined(__linux__)
4058 for (i = 0; i < RGFW_joystickCount; i++) {
4059 if (RGFW_joysticks[i] == 0)
4060 continue;
4061
4062 fds[index].fd = RGFW_joysticks[i];
4063 index++;
4064 }
4065 #endif
4066
4067
4068 u64 start = RGFW_getTimeNS();
4069
4070 #ifdef RGFW_WAYLAND
4071 while (wl_display_dispatch(win->src.display) <= 0 && waitMS >= -1) {
4072 #else
4073 while (XPending(win->src.display) == 0 && waitMS >= -1) {
4074 #endif
4075 if (poll(fds, index, waitMS) <= 0)
4076 break;
4077
4078 if (waitMS > 0) {
4079 waitMS -= (RGFW_getTimeNS() - start) / 1e+6;
4080 }
4081 }
4082
4083 /* drain any data in the stop request */
4084 if (RGFW_eventWait_forceStop[2]) {
4085 char data[64];
4086 (void)!read(RGFW_eventWait_forceStop[0], data, sizeof(data));
4087
4088 RGFW_eventWait_forceStop[2] = 0;
4089 }
4090 }
4091
4092 u64 RGFW_getTimeNS(void) {
4093 struct timespec ts = { 0 };
4094 clock_gettime(1, &ts);
4095 unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec;
4096
4097 return nanoSeconds;
4098 }
4099
4100 u64 RGFW_getTime(void) {
4101 struct timespec ts = { 0 };
4102 clock_gettime(1, &ts);
4103 unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec;
4104
4105 return (double)(nanoSeconds) * 1e-9;
4106 }
4107#endif /* end of wayland or X11 time defines*/
4108
4109
4110/*
4111
4112 Start of Wayland defines
4113
4114
4115*/
4116
4117#ifdef RGFW_WAYLAND
4118/*
4119Wayland TODO:
4120- fix RGFW_keyPressed lock state
4121
4122 RGFW_windowMoved, the window was moved (by the user)
4123 RGFW_windowResized the window was resized (by the user), [on webASM this means the browser was resized]
4124 RGFW_windowRefresh The window content needs to be refreshed
4125
4126 RGFW_dnd a file has been dropped into the window
4127 RGFW_dnd_init
4128
4129- window args:
4130 #define RGFW_NO_RESIZE the window cannot be resized by the user
4131 #define RGFW_ALLOW_DND the window supports drag and drop
4132 #define RGFW_SCALE_TO_MONITOR scale the window to the screen
4133
4134- other missing functions functions ("TODO wayland") (~30 functions)
4135- fix buffer rendering weird behavior
4136*/
4137 #include <errno.h>
4138 #include <unistd.h>
4139 #include <sys/mman.h>
4140 #include <xkbcommon/xkbcommon.h>
4141 #include <xkbcommon/xkbcommon-keysyms.h>
4142 #include <dirent.h>
4143 #include <linux/kd.h>
4144 #include <wayland-cursor.h>
4145
4146RGFW_window* RGFW_key_win = NULL;
4147
4148void RGFW_eventPipe_push(RGFW_window* win, RGFW_Event event) {
4149 if (win == NULL) {
4150 win = RGFW_key_win;
4151
4152 if (win == NULL) return;
4153 }
4154
4155 if (win->src.eventLen >= (i32)(sizeof(win->src.events) / sizeof(win->src.events[0])))
4156 return;
4157
4158 win->src.events[win->src.eventLen] = event;
4159 win->src.eventLen += 1;
4160}
4161
4162RGFW_Event RGFW_eventPipe_pop(RGFW_window* win) {
4163 RGFW_Event ev;
4164 ev.type = 0;
4165
4166 if (win->src.eventLen > -1)
4167 win->src.eventLen -= 1;
4168
4169 if (win->src.eventLen >= 0)
4170 ev = win->src.events[win->src.eventLen];
4171
4172 return ev;
4173}
4174
4175/* wayland global garbage (wayland bad, X11 is fine (ish) (not really)) */
4176#include "xdg-shell.h"
4177#include "xdg-decoration-unstable-v1.h"
4178
4179struct xdg_wm_base *xdg_wm_base;
4180struct wl_compositor* RGFW_compositor = NULL;
4181struct wl_shm* shm = NULL;
4182struct wl_shell* RGFW_shell = NULL;
4183static struct wl_seat *seat = NULL;
4184static struct xkb_context *xkb_context;
4185static struct xkb_keymap *keymap = NULL;
4186static struct xkb_state *xkb_state = NULL;
4187enum zxdg_toplevel_decoration_v1_mode client_preferred_mode, RGFW_current_mode;
4188static struct zxdg_decoration_manager_v1 *decoration_manager = NULL;
4189
4190struct wl_cursor_theme* RGFW_wl_cursor_theme = NULL;
4191struct wl_surface* RGFW_cursor_surface = NULL;
4192struct wl_cursor_image* RGFW_cursor_image = NULL;
4193
4194static void xdg_wm_base_ping_handler(void *data,
4195 struct xdg_wm_base *wm_base, uint32_t serial)
4196{
4197 RGFW_UNUSED(data);
4198 xdg_wm_base_pong(wm_base, serial);
4199}
4200
4201static const struct xdg_wm_base_listener xdg_wm_base_listener = {
4202 .ping = xdg_wm_base_ping_handler,
4203};
4204
4205b8 RGFW_wl_configured = 0;
4206
4207static void xdg_surface_configure_handler(void *data,
4208 struct xdg_surface *xdg_surface, uint32_t serial)
4209{
4210 RGFW_UNUSED(data);
4211 xdg_surface_ack_configure(xdg_surface, serial);
4212 #ifdef RGFW_DEBUG
4213 printf("Surface configured\n");
4214 #endif
4215 RGFW_wl_configured = 1;
4216}
4217
4218static const struct xdg_surface_listener xdg_surface_listener = {
4219 .configure = xdg_surface_configure_handler,
4220};
4221
4222static void xdg_toplevel_configure_handler(void *data,
4223 struct xdg_toplevel *toplevel, int32_t width, int32_t height,
4224 struct wl_array *states)
4225{
4226 RGFW_UNUSED(data); RGFW_UNUSED(toplevel); RGFW_UNUSED(states)
4227 fprintf(stderr, "XDG toplevel configure: %dx%d\n", width, height);
4228}
4229
4230static void xdg_toplevel_close_handler(void *data,
4231 struct xdg_toplevel *toplevel)
4232{
4233 RGFW_UNUSED(data);
4234 RGFW_window* win = (RGFW_window*)xdg_toplevel_get_user_data(toplevel);
4235 if (win == NULL)
4236 win = RGFW_key_win;
4237
4238 RGFW_Event ev;
4239 ev.type = RGFW_quit;
4240
4241 RGFW_eventPipe_push(win, ev);
4242
4243 RGFW_windowQuitCallback(win);
4244}
4245
4246static void shm_format_handler(void *data,
4247 struct wl_shm *shm, uint32_t format)
4248{
4249 RGFW_UNUSED(data); RGFW_UNUSED(shm);
4250 fprintf(stderr, "Format %d\n", format);
4251}
4252
4253static const struct wl_shm_listener shm_listener = {
4254 .format = shm_format_handler,
4255};
4256
4257static const struct xdg_toplevel_listener xdg_toplevel_listener = {
4258 .configure = xdg_toplevel_configure_handler,
4259 .close = xdg_toplevel_close_handler,
4260};
4261
4262RGFW_window* RGFW_mouse_win = NULL;
4263
4264static void 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) {
4265 RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(serial); RGFW_UNUSED(surface_x); RGFW_UNUSED(surface_y);
4266 RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
4267 RGFW_mouse_win = win;
4268
4269 RGFW_Event ev;
4270 ev.type = RGFW_mouseEnter;
4271 ev.point = win->event.point;
4272
4273 RGFW_eventPipe_push(win, ev);
4274
4275 RGFW_mouseNotifyCallBack(win, win->event.point, RGFW_TRUE);
4276}
4277static void pointer_leave(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface) {
4278 RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(serial); RGFW_UNUSED(surface);
4279 RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
4280 if (RGFW_mouse_win == win)
4281 RGFW_mouse_win = NULL;
4282
4283 RGFW_Event ev;
4284 ev.type = RGFW_mouseLeave;
4285 ev.point = win->event.point;
4286 RGFW_eventPipe_push(win, ev);
4287
4288 RGFW_mouseNotifyCallBack(win, win->event.point, RGFW_FALSE);
4289}
4290static void pointer_motion(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t x, wl_fixed_t y) {
4291 RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(x); RGFW_UNUSED(y);
4292
4293 assert(RGFW_mouse_win != NULL);
4294
4295 RGFW_Event ev;
4296 ev.type = RGFW_mousePosChanged;
4297 ev.point = RGFW_POINT(wl_fixed_to_double(x), wl_fixed_to_double(y));
4298 RGFW_eventPipe_push(RGFW_mouse_win, ev);
4299
4300 RGFW_mousePosCallback(RGFW_mouse_win, RGFW_POINT(wl_fixed_to_double(x), wl_fixed_to_double(y)));
4301}
4302static void pointer_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) {
4303 RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(serial);
4304 assert(RGFW_mouse_win != NULL);
4305
4306 u32 b = (button - 0x110) + 1;
4307
4308 /* flip right and middle button codes */
4309 if (b == 2) b = 3;
4310 else if (b == 3) b = 2;
4311
4312 RGFW_mouseButtons[b].prev = RGFW_mouseButtons[b].current;
4313 RGFW_mouseButtons[b].current = state;
4314
4315 RGFW_Event ev;
4316 ev.type = RGFW_mouseButtonPressed + state;
4317 ev.button = b;
4318 RGFW_eventPipe_push(RGFW_mouse_win, ev);
4319
4320 RGFW_mouseButtonCallback(RGFW_mouse_win, b, 0, state);
4321}
4322static void pointer_axis(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value) {
4323 RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(axis);
4324 assert(RGFW_mouse_win != NULL);
4325
4326 double scroll = wl_fixed_to_double(value);
4327
4328 RGFW_Event ev;
4329 ev.type = RGFW_mouseButtonPressed;
4330 ev.button = RGFW_mouseScrollUp + (scroll < 0);
4331 RGFW_eventPipe_push(RGFW_mouse_win, ev);
4332
4333 RGFW_mouseButtonCallback(RGFW_mouse_win, RGFW_mouseScrollUp + (scroll < 0), scroll, 1);
4334}
4335
4336void RGFW_doNothing(void) { }
4337static struct wl_pointer_listener pointer_listener = (struct wl_pointer_listener){&pointer_enter, &pointer_leave, &pointer_motion, &pointer_button, &pointer_axis, (void*)&RGFW_doNothing, (void*)&RGFW_doNothing, (void*)&RGFW_doNothing, (void*)&RGFW_doNothing, (void*)&RGFW_doNothing, (void*)&RGFW_doNothing};
4338
4339static void keyboard_keymap (void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size) {
4340 RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(format);
4341
4342 char *keymap_string = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0);
4343 xkb_keymap_unref (keymap);
4344 keymap = xkb_keymap_new_from_string (xkb_context, keymap_string, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
4345
4346 munmap (keymap_string, size);
4347 close (fd);
4348 xkb_state_unref (xkb_state);
4349 xkb_state = xkb_state_new (keymap);
4350}
4351static void keyboard_enter (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) {
4352 RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(keys);
4353
4354 RGFW_key_win = (RGFW_window*)wl_surface_get_user_data(surface);
4355
4356 RGFW_Event ev;
4357 ev.type = RGFW_focusIn;
4358 ev.inFocus = RGFW_TRUE;
4359 RGFW_key_win->event.inFocus = RGFW_TRUE;
4360
4361 RGFW_eventPipe_push((RGFW_window*)RGFW_mouse_win, ev);
4362
4363 RGFW_focusCallback(RGFW_key_win, RGFW_TRUE);
4364}
4365static void keyboard_leave (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface) {
4366 RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial);
4367
4368 RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
4369 if (RGFW_key_win == win)
4370 RGFW_key_win = NULL;
4371
4372 RGFW_Event ev;
4373 ev.type = RGFW_focusOut;
4374 ev.inFocus = RGFW_FALSE;
4375 win->event.inFocus = RGFW_FALSE;
4376 RGFW_eventPipe_push(win, ev);
4377
4378 RGFW_focusCallback(win, RGFW_FALSE);
4379}
4380static void keyboard_key (void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) {
4381 RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time);
4382
4383 assert(RGFW_key_win != NULL);
4384
4385 xkb_keysym_t keysym = xkb_state_key_get_one_sym (xkb_state, key+8);
4386 char name[16];
4387 xkb_keysym_get_name(keysym, name, 16);
4388
4389 u32 RGFW_key = RGFW_apiKeyCodeToRGFW(key);
4390 RGFW_keyboard[RGFW_key].prev = RGFW_keyboard[RGFW_key].current;
4391 RGFW_keyboard[RGFW_key].current = state;
4392 RGFW_Event ev;
4393 ev.type = RGFW_keyPressed + state;
4394 ev.keyCode = RGFW_key;
4395 strcpy(ev.keyName, name);
4396 ev.repeat = RGFW_isHeld(RGFW_key_win, RGFW_key);
4397 RGFW_eventPipe_push(RGFW_key_win, ev);
4398
4399 RGFW_updateLockState(RGFW_key_win, xkb_keymap_mod_get_index(keymap, "Lock"), xkb_keymap_mod_get_index(keymap, "Mod2"));
4400
4401 RGFW_keyCallback(RGFW_key_win, RGFW_key, name, RGFW_key_win->event.lockState, state);
4402}
4403static void 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) {
4404 RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time);
4405 xkb_state_update_mask (xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
4406}
4407static struct wl_keyboard_listener keyboard_listener = {&keyboard_keymap, &keyboard_enter, &keyboard_leave, &keyboard_key, &keyboard_modifiers, (void*)&RGFW_doNothing};
4408
4409static void seat_capabilities (void *data, struct wl_seat *seat, uint32_t capabilities) {
4410 RGFW_UNUSED(data);
4411
4412 if (capabilities & WL_SEAT_CAPABILITY_POINTER) {
4413 struct wl_pointer *pointer = wl_seat_get_pointer (seat);
4414 wl_pointer_add_listener (pointer, &pointer_listener, NULL);
4415 }
4416 if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) {
4417 struct wl_keyboard *keyboard = wl_seat_get_keyboard (seat);
4418 wl_keyboard_add_listener (keyboard, &keyboard_listener, NULL);
4419 }
4420}
4421static struct wl_seat_listener seat_listener = {&seat_capabilities, (void*)&RGFW_doNothing};
4422
4423static void wl_global_registry_handler(void *data,
4424 struct wl_registry *registry, uint32_t id, const char *interface,
4425 uint32_t version)
4426{
4427 RGFW_UNUSED(data); RGFW_UNUSED(version);
4428
4429 if (strcmp(interface, "wl_compositor") == 0) {
4430 RGFW_compositor = wl_registry_bind(registry,
4431 id, &wl_compositor_interface, 4);
4432 } else if (strcmp(interface, "xdg_wm_base") == 0) {
4433 xdg_wm_base = wl_registry_bind(registry,
4434 id, &xdg_wm_base_interface, 1);
4435 } else if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) {
4436 decoration_manager = wl_registry_bind(registry, id, &zxdg_decoration_manager_v1_interface, 1);
4437 } else if (strcmp(interface, "wl_shm") == 0) {
4438 shm = wl_registry_bind(registry,
4439 id, &wl_shm_interface, 1);
4440 wl_shm_add_listener(shm, &shm_listener, NULL);
4441 } else if (strcmp(interface,"wl_seat") == 0) {
4442 seat = wl_registry_bind(registry, id, &wl_seat_interface, 1);
4443 wl_seat_add_listener(seat, &seat_listener, NULL);
4444 }
4445
4446 else {
4447 #ifdef RGFW_DEBUG
4448 printf("did not register %s\n", interface);
4449 return;
4450 #endif
4451 }
4452
4453 #ifdef RGFW_DEBUG
4454 printf("registered %s\n", interface);
4455 #endif
4456}
4457
4458static void wl_global_registry_remove(void *data, struct wl_registry *registry, uint32_t name) { RGFW_UNUSED(data); RGFW_UNUSED(registry); RGFW_UNUSED(name); }
4459static const struct wl_registry_listener registry_listener = {
4460 .global = wl_global_registry_handler,
4461 .global_remove = wl_global_registry_remove,
4462};
4463
4464static const char *get_mode_name(enum zxdg_toplevel_decoration_v1_mode mode) {
4465 switch (mode) {
4466 case ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE:
4467 return "client-side decorations";
4468 case ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE:
4469 return "server-side decorations";
4470 }
4471 abort();
4472}
4473
4474
4475static void decoration_handle_configure(void *data,
4476 struct zxdg_toplevel_decoration_v1 *decoration,
4477 enum zxdg_toplevel_decoration_v1_mode mode) {
4478 RGFW_UNUSED(data); RGFW_UNUSED(decoration);
4479 printf("Using %s\n", get_mode_name(mode));
4480 RGFW_current_mode = mode;
4481}
4482
4483static const struct zxdg_toplevel_decoration_v1_listener decoration_listener = {
4484 .configure = decoration_handle_configure,
4485};
4486
4487static void randname(char *buf) {
4488 struct timespec ts;
4489 clock_gettime(CLOCK_REALTIME, &ts);
4490 long r = ts.tv_nsec;
4491 for (int i = 0; i < 6; ++i) {
4492 buf[i] = 'A'+(r&15)+(r&16)*2;
4493 r >>= 5;
4494 }
4495}
4496
4497static int anonymous_shm_open(void) {
4498 char name[] = "/RGFW-wayland-XXXXXX";
4499 int retries = 100;
4500
4501 do {
4502 randname(name + strlen(name) - 6);
4503
4504 --retries;
4505 // shm_open guarantees that O_CLOEXEC is set
4506 int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
4507 if (fd >= 0) {
4508 shm_unlink(name);
4509 return fd;
4510 }
4511 } while (retries > 0 && errno == EEXIST);
4512
4513 return -1;
4514}
4515
4516int create_shm_file(off_t size) {
4517 int fd = anonymous_shm_open();
4518 if (fd < 0) {
4519 return fd;
4520 }
4521
4522 if (ftruncate(fd, size) < 0) {
4523 close(fd);
4524 return -1;
4525 }
4526
4527 return fd;
4528}
4529
4530static void wl_surface_frame_done(void *data, struct wl_callback *cb, uint32_t time) {
4531 #ifdef RGFW_BUFFER
4532 RGFW_window* win = (RGFW_window*)data;
4533 if ((win->_winArgs & RGFW_NO_CPU_RENDER))
4534 return;
4535
4536 #ifndef RGFW_X11_DONT_CONVERT_BGR
4537 u32 x, y;
4538 for (y = 0; y < (u32)win->r.h; y++) {
4539 for (x = 0; x < (u32)win->r.w; x++) {
4540 u32 index = (y * 4 * win->r.w) + x * 4;
4541
4542 u8 red = win->buffer[index];
4543 win->buffer[index] = win->buffer[index + 2];
4544 win->buffer[index + 2] = red;
4545
4546 }
4547 }
4548 #endif
4549
4550 wl_surface_attach(win->src.surface, win->src.wl_buffer, 0, 0);
4551 wl_surface_damage_buffer(win->src.surface, 0, 0, win->r.w, win->r.h);
4552 wl_surface_commit(win->src.surface);
4553 #endif
4554}
4555
4556static const struct wl_callback_listener wl_surface_frame_listener = {
4557 .done = wl_surface_frame_done,
4558};
4559
4560
4561 /* normal wayland RGFW stuff */
4562
4563 RGFW_area RGFW_getScreenSize(void) {
4564 RGFW_area area = {};
4565
4566 if (RGFW_root != NULL)
4567 /* this isn't right but it's here for buffers */
4568 area = RGFW_AREA(RGFW_root->r.w, RGFW_root->r.h);
4569
4570 /* TODO wayland */
4571 return area;
4572 }
4573
4574 void RGFW_releaseCursor(RGFW_window* win) {
4575 RGFW_UNUSED(win);
4576 }
4577
4578 void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) {
4579 RGFW_UNUSED(win); RGFW_UNUSED(r);
4580
4581 /* TODO wayland */
4582 }
4583
4584
4585 RGFWDEF void RGFW_init_buffer(RGFW_window* win);
4586 void RGFW_init_buffer(RGFW_window* win) {
4587 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
4588 size_t size = win->r.w * win->r.h * 4;
4589 int fd = create_shm_file(size);
4590 if (fd < 0) {
4591 fprintf(stderr, "Failed to create a buffer. size: %ld\n", size);
4592 exit(1);
4593 }
4594
4595 win->buffer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
4596 if (win->buffer == MAP_FAILED) {
4597 fprintf(stderr, "mmap failed!\n");
4598 close(fd);
4599 exit(1);
4600 }
4601
4602 struct wl_shm_pool* pool = wl_shm_create_pool(shm, fd, size);
4603 win->src.wl_buffer = wl_shm_pool_create_buffer(pool, 0, win->r.w, win->r.h, win->r.w * 4,
4604 WL_SHM_FORMAT_ARGB8888);
4605 wl_shm_pool_destroy(pool);
4606
4607 close(fd);
4608
4609 wl_surface_attach(win->src.surface, win->src.wl_buffer, 0, 0);
4610 wl_surface_commit(win->src.surface);
4611
4612 u8 color[] = {0x00, 0x00, 0x00, 0xFF};
4613
4614 size_t i;
4615 for (i = 0; i < size; i += 4) {
4616 memcpy(&win->buffer[i], color, 4);
4617 }
4618
4619 #if defined(RGFW_OSMESA)
4620 win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL);
4621 OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, win->r.w, win->r.h);
4622 #endif
4623 #else
4624 RGFW_UNUSED(win);
4625 #endif
4626 }
4627
4628
4629 RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, u16 args) {
4630 RGFW_window* win = RGFW_window_basic_init(rect, args);
4631
4632 fprintf(stderr, "Warning: RGFW Wayland support is experimental\n");
4633
4634 win->src.display = wl_display_connect(NULL);
4635 if (win->src.display == NULL) {
4636 #ifdef RGFW_DEBUG
4637 fprintf(stderr, "Failed to load Wayland display\n");
4638 #endif
4639 return NULL;
4640 }
4641
4642 struct wl_registry *registry = wl_display_get_registry(win->src.display);
4643 wl_registry_add_listener(registry, &registry_listener, NULL);
4644
4645 wl_display_dispatch(win->src.display);
4646 wl_display_roundtrip(win->src.display);
4647
4648 if (RGFW_compositor == NULL) {
4649 #ifdef RGFW_DEBUG
4650 fprintf(stderr, "Can't find compositor.\n");
4651 #endif
4652
4653 return NULL;
4654 }
4655
4656 if (RGFW_wl_cursor_theme == NULL) {
4657 RGFW_wl_cursor_theme = wl_cursor_theme_load(NULL, 24, shm);
4658 RGFW_cursor_surface = wl_compositor_create_surface(RGFW_compositor);
4659
4660 struct wl_cursor* cursor = wl_cursor_theme_get_cursor(RGFW_wl_cursor_theme, "left_ptr");
4661 RGFW_cursor_image = cursor->images[0];
4662 struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(RGFW_cursor_image);
4663
4664 wl_surface_attach(RGFW_cursor_surface, cursor_buffer, 0, 0);
4665 wl_surface_commit(RGFW_cursor_surface);
4666 }
4667
4668 if (RGFW_root == NULL)
4669 xdg_wm_base_add_listener(xdg_wm_base, &xdg_wm_base_listener, NULL);
4670
4671 xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
4672
4673 win->src.surface = wl_compositor_create_surface(RGFW_compositor);
4674 wl_surface_set_user_data(win->src.surface, win);
4675
4676 win->src.xdg_surface = xdg_wm_base_get_xdg_surface(xdg_wm_base, win->src.surface);
4677 xdg_surface_add_listener(win->src.xdg_surface, &xdg_surface_listener, NULL);
4678
4679 xdg_wm_base_set_user_data(xdg_wm_base, win);
4680
4681 win->src.xdg_toplevel = xdg_surface_get_toplevel(win->src.xdg_surface);
4682 xdg_toplevel_set_user_data(win->src.xdg_toplevel, win);
4683 xdg_toplevel_set_title(win->src.xdg_toplevel, name);
4684 xdg_toplevel_add_listener(win->src.xdg_toplevel, &xdg_toplevel_listener, NULL);
4685
4686 xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->r.w, win->r.h);
4687
4688 if (!(args & RGFW_NO_BORDER)) {
4689 win->src.decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(
4690 decoration_manager, win->src.xdg_toplevel);
4691 }
4692
4693 if (args & RGFW_CENTER) {
4694 RGFW_area screenR = RGFW_getScreenSize();
4695 RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2));
4696 }
4697
4698 if (args & RGFW_OPENGL_SOFTWARE)
4699 setenv("LIBGL_ALWAYS_SOFTWARE", "1", 1);
4700
4701 wl_display_roundtrip(win->src.display);
4702
4703 wl_surface_commit(win->src.surface);
4704
4705 /* wait for the surface to be configured */
4706 while (wl_display_dispatch(win->src.display) != -1 && !RGFW_wl_configured) { }
4707
4708
4709 #ifdef RGFW_OPENGL
4710 if ((args & RGFW_NO_INIT_API) == 0) {
4711 win->src.window = wl_egl_window_create(win->src.surface, win->r.w, win->r.h);
4712 RGFW_createOpenGLContext(win);
4713 }
4714 #endif
4715
4716 RGFW_init_buffer(win);
4717
4718 struct wl_callback* callback = wl_surface_frame(win->src.surface);
4719 wl_callback_add_listener(callback, &wl_surface_frame_listener, win);
4720 wl_surface_commit(win->src.surface);
4721
4722 if (args & RGFW_HIDE_MOUSE) {
4723 RGFW_window_showMouse(win, 0);
4724 }
4725
4726 if (RGFW_root == NULL) {
4727 RGFW_root = win;
4728 }
4729
4730 win->src.eventIndex = 0;
4731 win->src.eventLen = 0;
4732
4733 return win;
4734 }
4735
4736 RGFW_Event* RGFW_window_checkEvent(RGFW_window* win) {
4737 if (win->_winArgs & RGFW_WINDOW_HIDE)
4738 return NULL;
4739
4740 if (win->src.eventIndex == 0) {
4741 if (wl_display_roundtrip(win->src.display) == -1) {
4742 return NULL;
4743 }
4744 RGFW_resetKey();
4745 }
4746
4747 #ifdef __linux__
4748 RGFW_Event* event = RGFW_linux_updateJoystick(win);
4749 if (event != NULL)
4750 return event;
4751 #endif
4752
4753 if (win->src.eventLen == 0) {
4754 return NULL;
4755 }
4756
4757 RGFW_Event ev = RGFW_eventPipe_pop(win);
4758
4759 if (ev.type == 0 || win->event.type == RGFW_quit) {
4760 return NULL;
4761 }
4762
4763 ev.frameTime = win->event.frameTime;
4764 ev.frameTime2 = win->event.frameTime2;
4765 ev.inFocus = win->event.inFocus;
4766 win->event = ev;
4767
4768 return &win->event;
4769 }
4770
4771
4772 void RGFW_window_resize(RGFW_window* win, RGFW_area a) {
4773 RGFW_UNUSED(win); RGFW_UNUSED(a);
4774
4775 /* TODO wayland */
4776 }
4777
4778 void RGFW_window_move(RGFW_window* win, RGFW_point v) {
4779 RGFW_UNUSED(win); RGFW_UNUSED(v);
4780
4781 /* TODO wayland */
4782 }
4783
4784 void RGFW_window_setIcon(RGFW_window* win, u8* src, RGFW_area a, i32 channels) {
4785 RGFW_UNUSED(win); RGFW_UNUSED(src); RGFW_UNUSED(a); RGFW_UNUSED(channels)
4786 /* TODO wayland */
4787 }
4788
4789 void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) {
4790 RGFW_UNUSED(win); RGFW_UNUSED(v);
4791
4792 /* TODO wayland */
4793 }
4794
4795 void RGFW_window_showMouse(RGFW_window* win, i8 show) {
4796 RGFW_UNUSED(win);
4797
4798 if (show) {
4799
4800 }
4801 else {
4802
4803 }
4804
4805 /* TODO wayland */
4806 }
4807
4808 b8 RGFW_window_isMaximized(RGFW_window* win) {
4809 RGFW_UNUSED(win);
4810 /* TODO wayland */
4811 return 0;
4812 }
4813
4814 b8 RGFW_window_isMinimized(RGFW_window* win) {
4815 RGFW_UNUSED(win);
4816 /* TODO wayland */
4817 return 0;
4818 }
4819
4820 b8 RGFW_window_isHidden(RGFW_window* win) {
4821 RGFW_UNUSED(win);
4822 /* TODO wayland */
4823 return 0;
4824 }
4825
4826 b8 RGFW_window_isFullscreen(RGFW_window* win) {
4827 RGFW_UNUSED(win);
4828 /* TODO wayland */
4829 return 0;
4830 }
4831
4832 RGFW_point RGFW_window_getMousePoint(RGFW_window* win) {
4833 RGFW_UNUSED(win);
4834 /* TODO wayland */
4835 return RGFW_POINT(0, 0);
4836 }
4837
4838 RGFW_point RGFW_getGlobalMousePoint(void) {
4839 /* TODO wayland */
4840 return RGFW_POINT(0, 0);
4841 }
4842
4843 void RGFW_window_show(RGFW_window* win) {
4844 //wl_surface_attach(win->src.surface, win->rc., 0, 0);
4845 wl_surface_commit(win->src.surface);
4846
4847 if (win->_winArgs & RGFW_WINDOW_HIDE)
4848 win->_winArgs ^= RGFW_WINDOW_HIDE;
4849 }
4850
4851 void RGFW_window_hide(RGFW_window* win) {
4852 wl_surface_attach(win->src.surface, NULL, 0, 0);
4853 wl_surface_commit(win->src.surface);
4854 win->_winArgs |= RGFW_WINDOW_HIDE;
4855 }
4856
4857 void RGFW_window_setMouseDefault(RGFW_window* win) {
4858 RGFW_UNUSED(win);
4859
4860 RGFW_window_setMouseStandard(win, RGFW_MOUSE_NORMAL);
4861 }
4862
4863 void RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) {
4864 RGFW_UNUSED(win);
4865
4866 static const char* iconStrings[] = { "left_ptr", "left_ptr", "text", "cross", "pointer", "e-resize", "n-resize", "nw-resize", "ne-resize", "all-resize", "not-allowed" };
4867
4868 struct wl_cursor* cursor = wl_cursor_theme_get_cursor(RGFW_wl_cursor_theme, iconStrings[mouse]);
4869 RGFW_cursor_image = cursor->images[0];
4870 struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(RGFW_cursor_image);
4871
4872 wl_surface_attach(RGFW_cursor_surface, cursor_buffer, 0, 0);
4873 wl_surface_commit(RGFW_cursor_surface);
4874 }
4875
4876 void RGFW_window_setMouse(RGFW_window* win, u8* image, RGFW_area a, i32 channels) {
4877 RGFW_UNUSED(win); RGFW_UNUSED(image); RGFW_UNUSED(a); RGFW_UNUSED(channels)
4878 //struct wl_cursor* cursor = wl_cursor_theme_get_cursor(RGFW_wl_cursor_theme, iconStrings[mouse]);
4879 //RGFW_cursor_image = image;
4880 struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(RGFW_cursor_image);
4881
4882 wl_surface_attach(RGFW_cursor_surface, cursor_buffer, 0, 0);
4883 wl_surface_commit(RGFW_cursor_surface);
4884 }
4885
4886 void RGFW_window_setName(RGFW_window* win, char* name) {
4887 xdg_toplevel_set_title(win->src.xdg_toplevel, name);
4888 }
4889
4890 void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough) {
4891 RGFW_UNUSED(win); RGFW_UNUSED(passthrough);
4892
4893 /* TODO wayland */
4894 }
4895
4896 void RGFW_window_setBorder(RGFW_window* win, b8 border) {
4897 RGFW_UNUSED(win); RGFW_UNUSED(border);
4898
4899 /* TODO wayland */
4900 }
4901
4902 void RGFW_window_restore(RGFW_window* win) {
4903 RGFW_UNUSED(win);
4904
4905 /* TODO wayland */
4906 }
4907
4908 void RGFW_window_minimize(RGFW_window* win) {
4909 RGFW_UNUSED(win);
4910
4911 /* TODO wayland */
4912 }
4913
4914 void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) {
4915 RGFW_UNUSED(win); RGFW_UNUSED(a);
4916
4917 /* TODO wayland */
4918 }
4919
4920 void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) {
4921 RGFW_UNUSED(win); RGFW_UNUSED(a);
4922
4923 /* TODO wayland */
4924 }
4925
4926 RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) {
4927 RGFW_monitor m = {};
4928 RGFW_UNUSED(win);
4929 RGFW_UNUSED(m);
4930 /* TODO wayland */
4931
4932 return m;
4933 }
4934
4935
4936 #ifndef RGFW_EGL
4937 void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { RGFW_UNUSED(win); RGFW_UNUSED(swapInterval); }
4938 #endif
4939
4940 void RGFW_window_swapBuffers(RGFW_window* win) {
4941 assert(win != NULL);
4942
4943 /* clear the window*/
4944 #ifdef RGFW_BUFFER
4945 wl_surface_frame_done(win, NULL, 0);
4946 if (!(win->_winArgs & RGFW_NO_GPU_RENDER))
4947 #endif
4948 {
4949 #ifdef RGFW_OPENGL
4950 eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface);
4951 #endif
4952 }
4953
4954 wl_display_flush(win->src.display);
4955 }
4956
4957 void RGFW_window_close(RGFW_window* win) {
4958 #ifdef RGFW_EGL
4959 RGFW_closeEGL(win);
4960 #endif
4961
4962 if (RGFW_root == win) {
4963 RGFW_root = NULL;
4964 }
4965
4966 xdg_toplevel_destroy(win->src.xdg_toplevel);
4967 xdg_surface_destroy(win->src.xdg_surface);
4968 wl_surface_destroy(win->src.surface);
4969
4970 #ifdef RGFW_BUFFER
4971 wl_buffer_destroy(win->src.wl_buffer);
4972 #endif
4973
4974 wl_display_disconnect(win->src.display);
4975 RGFW_FREE(win);
4976 }
4977
4978 RGFW_monitor RGFW_getPrimaryMonitor(void) {
4979 /* TODO wayland */
4980
4981 return (RGFW_monitor){};
4982 }
4983
4984 RGFW_monitor* RGFW_getMonitors(void) {
4985 /* TODO wayland */
4986
4987 return NULL;
4988 }
4989
4990 void RGFW_writeClipboard(const char* text, u32 textLen) {
4991 RGFW_UNUSED(text); RGFW_UNUSED(textLen);
4992
4993 /* TODO wayland */
4994 }
4995
4996 char* RGFW_readClipboard(size_t* size) {
4997 RGFW_UNUSED(size);
4998
4999 /* TODO wayland */
5000
5001 return NULL;
5002 }
5003#endif /* RGFW_WAYLAND */
5004
5005/*
5006 End of Wayland defines
5007*/
5008
5009
5010/*
5011
5012 Start of Windows defines
5013
5014
5015*/
5016
5017#ifdef RGFW_WINDOWS
5018 #define WIN32_LEAN_AND_MEAN
5019 #define OEMRESOURCE
5020 #include <windows.h>
5021
5022 #include <processthreadsapi.h>
5023 #include <wchar.h>
5024 #include <locale.h>
5025 #include <windowsx.h>
5026 #include <shellapi.h>
5027 #include <shellscalingapi.h>
5028
5029 #include <winuser.h>
5030
5031 __declspec(dllimport) int __stdcall WideCharToMultiByte( UINT CodePage, DWORD dwFlags, const WCHAR* lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCCH lpDefaultChar, LPBOOL lpUsedDefaultChar);
5032
5033 #ifndef RGFW_NO_XINPUT
5034 typedef DWORD (WINAPI * PFN_XInputGetState)(DWORD,XINPUT_STATE*);
5035 PFN_XInputGetState XInputGetStateSRC = NULL;
5036 #define XInputGetState XInputGetStateSRC
5037
5038 typedef DWORD (WINAPI * PFN_XInputGetKeystroke)(DWORD, DWORD, PXINPUT_KEYSTROKE);
5039 PFN_XInputGetKeystroke XInputGetKeystrokeSRC = NULL;
5040 #define XInputGetKeystroke XInputGetKeystrokeSRC
5041
5042 static HMODULE RGFW_XInput_dll = NULL;
5043 #endif
5044
5045 u32 RGFW_mouseIconSrc[] = {OCR_NORMAL, OCR_NORMAL, OCR_IBEAM, OCR_CROSS, OCR_HAND, OCR_SIZEWE, OCR_SIZENS, OCR_SIZENWSE, OCR_SIZENESW, OCR_SIZEALL, OCR_NO};
5046
5047 char* createUTF8FromWideStringWin32(const WCHAR* source);
5048
5049#define GL_FRONT 0x0404
5050#define GL_BACK 0x0405
5051#define GL_LEFT 0x0406
5052#define GL_RIGHT 0x0407
5053
5054#if defined(RGFW_OSMESA) && defined(RGFW_LINK_OSMESA)
5055
5056 typedef void (GLAPIENTRY* PFN_OSMesaDestroyContext)(OSMesaContext);
5057 typedef i32(GLAPIENTRY* PFN_OSMesaMakeCurrent)(OSMesaContext, void*, int, int, int);
5058 typedef OSMesaContext(GLAPIENTRY* PFN_OSMesaCreateContext)(GLenum, OSMesaContext);
5059
5060 PFN_OSMesaMakeCurrent OSMesaMakeCurrentSource;
5061 PFN_OSMesaCreateContext OSMesaCreateContextSource;
5062 PFN_OSMesaDestroyContext OSMesaDestroyContextSource;
5063
5064#define OSMesaCreateContext OSMesaCreateContextSource
5065#define OSMesaMakeCurrent OSMesaMakeCurrentSource
5066#define OSMesaDestroyContext OSMesaDestroyContextSource
5067#endif
5068
5069 typedef int (*PFN_wglGetSwapIntervalEXT)(void);
5070 PFN_wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc = NULL;
5071#define wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc
5072
5073
5074 void* RGFWjoystickApi = NULL;
5075
5076 /* these two wgl functions need to be preloaded */
5077 typedef HGLRC (WINAPI *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC hdc, HGLRC hglrc, const int *attribList);
5078 PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL;
5079
5080 /* defines for creating ARB attributes */
5081#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
5082#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
5083#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
5084#define WGL_DRAW_TO_WINDOW_ARB 0x2001
5085#define WGL_ACCELERATION_ARB 0x2003
5086#define WGL_NO_ACCELERATION_ARB 0x2025
5087#define WGL_DOUBLE_BUFFER_ARB 0x2011
5088#define WGL_COLOR_BITS_ARB 0x2014
5089#define WGL_RED_BITS_ARB 0x2015
5090#define WGL_RED_SHIFT_ARB 0x2016
5091#define WGL_GREEN_BITS_ARB 0x2017
5092#define WGL_GREEN_SHIFT_ARB 0x2018
5093#define WGL_BLUE_BITS_ARB 0x2019
5094#define WGL_BLUE_SHIFT_ARB 0x201a
5095#define WGL_ALPHA_BITS_ARB 0x201b
5096#define WGL_ALPHA_SHIFT_ARB 0x201c
5097#define WGL_ACCUM_BITS_ARB 0x201d
5098#define WGL_ACCUM_RED_BITS_ARB 0x201e
5099#define WGL_ACCUM_GREEN_BITS_ARB 0x201f
5100#define WGL_ACCUM_BLUE_BITS_ARB 0x2020
5101#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021
5102#define WGL_DEPTH_BITS_ARB 0x2022
5103#define WGL_AUX_BUFFERS_ARB 0x2024
5104#define WGL_STEREO_ARB 0x2012
5105#define WGL_DEPTH_BITS_ARB 0x2022
5106#define WGL_STENCIL_BITS_ARB 0x2023
5107#define WGL_FULL_ACCELERATION_ARB 0x2027
5108#define WGL_CONTEXT_FLAGS_ARB 0x2094
5109#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
5110#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
5111#define WGL_SAMPLE_BUFFERS_ARB 0x2041
5112#define WGL_SAMPLES_ARB 0x2042
5113#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9
5114
5115#ifndef RGFW_EGL
5116static HMODULE wglinstance = NULL;
5117#endif
5118
5119#ifdef RGFW_WGL_LOAD
5120 typedef HGLRC(WINAPI* PFN_wglCreateContext)(HDC);
5121 typedef BOOL(WINAPI* PFN_wglDeleteContext)(HGLRC);
5122 typedef PROC(WINAPI* PFN_wglGetProcAddress)(LPCSTR);
5123 typedef BOOL(WINAPI* PFN_wglMakeCurrent)(HDC, HGLRC);
5124 typedef HDC(WINAPI* PFN_wglGetCurrentDC)();
5125 typedef HGLRC(WINAPI* PFN_wglGetCurrentContext)();
5126
5127 PFN_wglCreateContext wglCreateContextSRC;
5128 PFN_wglDeleteContext wglDeleteContextSRC;
5129 PFN_wglGetProcAddress wglGetProcAddressSRC;
5130 PFN_wglMakeCurrent wglMakeCurrentSRC;
5131 PFN_wglGetCurrentDC wglGetCurrentDCSRC;
5132 PFN_wglGetCurrentContext wglGetCurrentContextSRC;
5133
5134 #define wglCreateContext wglCreateContextSRC
5135 #define wglDeleteContext wglDeleteContextSRC
5136 #define wglGetProcAddress wglGetProcAddressSRC
5137 #define wglMakeCurrent wglMakeCurrentSRC
5138
5139 #define wglGetCurrentDC wglGetCurrentDCSRC
5140 #define wglGetCurrentContext wglGetCurrentContextSRC
5141#endif
5142
5143#ifdef RGFW_OPENGL
5144 void* RGFW_getProcAddress(const char* procname) {
5145 void* proc = (void*) wglGetProcAddress(procname);
5146 if (proc)
5147 return proc;
5148
5149 return (void*) GetProcAddress(wglinstance, procname);
5150 }
5151
5152 typedef HRESULT (APIENTRY* PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats);
5153 static PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL;
5154#endif
5155
5156 RGFW_window RGFW_eventWindow;
5157
5158 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
5159 switch (message) {
5160 case WM_MOVE:
5161 RGFW_eventWindow.r.x = LOWORD(lParam);
5162 RGFW_eventWindow.r.y = HIWORD(lParam);
5163 RGFW_eventWindow.src.window = hWnd;
5164 return DefWindowProcA(hWnd, message, wParam, lParam);
5165 case WM_SIZE:
5166 RGFW_eventWindow.r.w = LOWORD(lParam);
5167 RGFW_eventWindow.r.h = HIWORD(lParam);
5168 RGFW_eventWindow.src.window = hWnd;
5169 return DefWindowProcA(hWnd, message, wParam, lParam); // Call DefWindowProc after handling
5170 default:
5171 return DefWindowProcA(hWnd, message, wParam, lParam);
5172 }
5173 }
5174
5175 #ifndef RGFW_NO_DPI
5176 static HMODULE RGFW_Shcore_dll = NULL;
5177 typedef HRESULT (WINAPI * PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*,UINT*);
5178 PFN_GetDpiForMonitor GetDpiForMonitorSRC = NULL;
5179 #define GetDpiForMonitor GetDpiForMonitorSRC
5180 #endif
5181
5182 __declspec(dllimport) u32 __stdcall timeBeginPeriod(u32 uPeriod);
5183
5184 #ifndef RGFW_NO_XINPUT
5185 void RGFW_loadXInput(void) {
5186 u32 i;
5187 static const char* names[] = {
5188 "xinput1_4.dll",
5189 "xinput1_3.dll",
5190 "xinput9_1_0.dll",
5191 "xinput1_2.dll",
5192 "xinput1_1.dll"
5193 };
5194
5195 for (i = 0; i < sizeof(names) / sizeof(const char*); i++) {
5196 RGFW_XInput_dll = LoadLibraryA(names[i]);
5197
5198 if (RGFW_XInput_dll) {
5199 XInputGetStateSRC = (PFN_XInputGetState)(void*)GetProcAddress(RGFW_XInput_dll, "XInputGetState");
5200
5201 if (XInputGetStateSRC == NULL)
5202 printf("Failed to load XInputGetState");
5203 }
5204 }
5205 }
5206 #endif
5207
5208 RGFWDEF void RGFW_init_buffer(RGFW_window* win);
5209 void RGFW_init_buffer(RGFW_window* win) {
5210#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
5211 if (RGFW_bufferSize.w == 0 && RGFW_bufferSize.h == 0)
5212 RGFW_bufferSize = RGFW_getScreenSize();
5213
5214 BITMAPV5HEADER bi = { 0 };
5215 ZeroMemory(&bi, sizeof(bi));
5216 bi.bV5Size = sizeof(bi);
5217 bi.bV5Width = RGFW_bufferSize.w;
5218 bi.bV5Height = -((LONG) RGFW_bufferSize.h);
5219 bi.bV5Planes = 1;
5220 bi.bV5BitCount = 32;
5221 bi.bV5Compression = BI_BITFIELDS;
5222 bi.bV5BlueMask = 0x00ff0000;
5223 bi.bV5GreenMask = 0x0000ff00;
5224 bi.bV5RedMask = 0x000000ff;
5225 bi.bV5AlphaMask = 0xff000000;
5226
5227 win->src.bitmap = CreateDIBSection(win->src.hdc,
5228 (BITMAPINFO*) &bi,
5229 DIB_RGB_COLORS,
5230 (void**) &win->buffer,
5231 NULL,
5232 (DWORD) 0);
5233
5234 win->src.hdcMem = CreateCompatibleDC(win->src.hdc);
5235
5236 #if defined(RGFW_OSMESA)
5237 win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL);
5238 OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, win->r.w, win->r.h);
5239 #endif
5240#else
5241RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
5242#endif
5243 }
5244
5245 void RGFW_window_setDND(RGFW_window* win, b8 allow) {
5246 DragAcceptFiles(win->src.window, allow);
5247 }
5248
5249 void RGFW_releaseCursor(RGFW_window* win) {
5250 RGFW_UNUSED(win);
5251 ClipCursor(NULL);
5252 const RAWINPUTDEVICE id = { 0x01, 0x02, RIDEV_REMOVE, NULL };
5253 RegisterRawInputDevices(&id, 1, sizeof(id));
5254 }
5255
5256 void RGFW_captureCursor(RGFW_window* win, RGFW_rect rect) {
5257 RGFW_UNUSED(win); RGFW_UNUSED(rect);
5258
5259 RECT clipRect;
5260 GetClientRect(win->src.window, &clipRect);
5261 ClientToScreen(win->src.window, (POINT*) &clipRect.left);
5262 ClientToScreen(win->src.window, (POINT*) &clipRect.right);
5263 ClipCursor(&clipRect);
5264
5265 const RAWINPUTDEVICE id = { 0x01, 0x02, 0, win->src.window };
5266 RegisterRawInputDevices(&id, 1, sizeof(id));
5267 }
5268
5269 RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, u16 args) {
5270 #ifndef RGFW_NO_XINPUT
5271 if (RGFW_XInput_dll == NULL)
5272 RGFW_loadXInput();
5273 #endif
5274
5275 #ifndef RGFW_NO_DPI
5276 if (RGFW_Shcore_dll == NULL) {
5277 RGFW_Shcore_dll = LoadLibraryA("shcore.dll");
5278 GetDpiForMonitorSRC = (PFN_GetDpiForMonitor)(void*)GetProcAddress(RGFW_Shcore_dll, "GetDpiForMonitor");
5279 SetProcessDPIAware();
5280 }
5281 #endif
5282
5283 if (wglinstance == NULL) {
5284 wglinstance = LoadLibraryA("opengl32.dll");
5285#ifdef RGFW_WGL_LOAD
5286 wglCreateContextSRC = (PFN_wglCreateContext) GetProcAddress(wglinstance, "wglCreateContext");
5287 wglDeleteContextSRC = (PFN_wglDeleteContext) GetProcAddress(wglinstance, "wglDeleteContext");
5288 wglGetProcAddressSRC = (PFN_wglGetProcAddress) GetProcAddress(wglinstance, "wglGetProcAddress");
5289 wglMakeCurrentSRC = (PFN_wglMakeCurrent) GetProcAddress(wglinstance, "wglMakeCurrent");
5290 wglGetCurrentDCSRC = (PFN_wglGetCurrentDC) GetProcAddress(wglinstance, "wglGetCurrentDC");
5291 wglGetCurrentContextSRC = (PFN_wglGetCurrentContext) GetProcAddress(wglinstance, "wglGetCurrentContext");
5292#endif
5293 }
5294
5295 if (name[0] == 0) name = (char*) " ";
5296
5297 RGFW_eventWindow.r = RGFW_RECT(-1, -1, -1, -1);
5298 RGFW_eventWindow.src.window = NULL;
5299
5300 RGFW_window* win = RGFW_window_basic_init(rect, args);
5301
5302 win->src.maxSize = RGFW_AREA(0, 0);
5303 win->src.minSize = RGFW_AREA(0, 0);
5304
5305
5306 HINSTANCE inh = GetModuleHandleA(NULL);
5307
5308 #ifndef __cplusplus
5309 WNDCLASSA Class = { 0 }; /*!< Setup the Window class. */
5310 #else
5311 WNDCLASSA Class = { };
5312 #endif
5313
5314 if (RGFW_className == NULL)
5315 RGFW_className = (char*)name;
5316
5317 Class.lpszClassName = RGFW_className;
5318 Class.hInstance = inh;
5319 Class.hCursor = LoadCursor(NULL, IDC_ARROW);
5320 Class.lpfnWndProc = WndProc;
5321
5322 RegisterClassA(&Class);
5323
5324 DWORD window_style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
5325
5326 RECT windowRect, clientRect;
5327
5328 if (!(args & RGFW_NO_BORDER)) {
5329 window_style |= WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX;
5330
5331 if (!(args & RGFW_NO_RESIZE))
5332 window_style |= WS_SIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME;
5333 } else
5334 window_style |= WS_POPUP | WS_VISIBLE | WS_SYSMENU | WS_MINIMIZEBOX;
5335
5336 HWND dummyWin = CreateWindowA(Class.lpszClassName, name, window_style, win->r.x, win->r.y, win->r.w, win->r.h, 0, 0, inh, 0);
5337
5338 GetWindowRect(dummyWin, &windowRect);
5339 GetClientRect(dummyWin, &clientRect);
5340
5341 win->src.hOffset = (windowRect.bottom - windowRect.top) - (clientRect.bottom - clientRect.top);
5342 win->src.window = CreateWindowA(Class.lpszClassName, name, window_style, win->r.x, win->r.y, win->r.w, win->r.h + win->src.hOffset, 0, 0, inh, 0);
5343
5344 if (args & RGFW_ALLOW_DND) {
5345 win->_winArgs |= RGFW_ALLOW_DND;
5346 RGFW_window_setDND(win, 1);
5347 }
5348 win->src.hdc = GetDC(win->src.window);
5349
5350 if ((args & RGFW_NO_INIT_API) == 0) {
5351#ifdef RGFW_DIRECTX
5352 assert(FAILED(CreateDXGIFactory(&__uuidof(IDXGIFactory), (void**) &RGFW_dxInfo.pFactory)) == 0);
5353
5354 if (FAILED(RGFW_dxInfo.pFactory->lpVtbl->EnumAdapters(RGFW_dxInfo.pFactory, 0, &RGFW_dxInfo.pAdapter))) {
5355 fprintf(stderr, "Failed to enumerate DXGI adapters\n");
5356 RGFW_dxInfo.pFactory->lpVtbl->Release(RGFW_dxInfo.pFactory);
5357 return NULL;
5358 }
5359
5360 D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_0 };
5361
5362 if (FAILED(D3D11CreateDevice(RGFW_dxInfo.pAdapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, 0, featureLevels, 1, D3D11_SDK_VERSION, &RGFW_dxInfo.pDevice, NULL, &RGFW_dxInfo.pDeviceContext))) {
5363 fprintf(stderr, "Failed to create Direct3D device\n");
5364 RGFW_dxInfo.pAdapter->lpVtbl->Release(RGFW_dxInfo.pAdapter);
5365 RGFW_dxInfo.pFactory->lpVtbl->Release(RGFW_dxInfo.pFactory);
5366 return NULL;
5367 }
5368
5369 DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 };
5370 swapChainDesc.BufferCount = 1;
5371 swapChainDesc.BufferDesc.Width = win->r.w;
5372 swapChainDesc.BufferDesc.Height = win->r.h;
5373 swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
5374 swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
5375 swapChainDesc.OutputWindow = win->src.window;
5376 swapChainDesc.SampleDesc.Count = 1;
5377 swapChainDesc.SampleDesc.Quality = 0;
5378 swapChainDesc.Windowed = TRUE;
5379 RGFW_dxInfo.pFactory->lpVtbl->CreateSwapChain(RGFW_dxInfo.pFactory, (IUnknown*) RGFW_dxInfo.pDevice, &swapChainDesc, &win->src.swapchain);
5380
5381 ID3D11Texture2D* pBackBuffer;
5382 win->src.swapchain->lpVtbl->GetBuffer(win->src.swapchain, 0, &__uuidof(ID3D11Texture2D), (LPVOID*) &pBackBuffer);
5383 RGFW_dxInfo.pDevice->lpVtbl->CreateRenderTargetView(RGFW_dxInfo.pDevice, (ID3D11Resource*) pBackBuffer, NULL, &win->src.renderTargetView);
5384 pBackBuffer->lpVtbl->Release(pBackBuffer);
5385
5386 D3D11_TEXTURE2D_DESC depthStencilDesc = { 0 };
5387 depthStencilDesc.Width = win->r.w;
5388 depthStencilDesc.Height = win->r.h;
5389 depthStencilDesc.MipLevels = 1;
5390 depthStencilDesc.ArraySize = 1;
5391 depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
5392 depthStencilDesc.SampleDesc.Count = 1;
5393 depthStencilDesc.SampleDesc.Quality = 0;
5394 depthStencilDesc.Usage = D3D11_USAGE_DEFAULT;
5395 depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
5396
5397 ID3D11Texture2D* pDepthStencilTexture = NULL;
5398 RGFW_dxInfo.pDevice->lpVtbl->CreateTexture2D(RGFW_dxInfo.pDevice, &depthStencilDesc, NULL, &pDepthStencilTexture);
5399
5400 D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc = { 0 };
5401 depthStencilViewDesc.Format = depthStencilDesc.Format;
5402 depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
5403 depthStencilViewDesc.Texture2D.MipSlice = 0;
5404
5405 RGFW_dxInfo.pDevice->lpVtbl->CreateDepthStencilView(RGFW_dxInfo.pDevice, (ID3D11Resource*) pDepthStencilTexture, &depthStencilViewDesc, &win->src.pDepthStencilView);
5406
5407 pDepthStencilTexture->lpVtbl->Release(pDepthStencilTexture);
5408
5409 RGFW_dxInfo.pDeviceContext->lpVtbl->OMSetRenderTargets(RGFW_dxInfo.pDeviceContext, 1, &win->src.renderTargetView, win->src.pDepthStencilView);
5410#endif
5411
5412#ifdef RGFW_OPENGL
5413 HDC dummy_dc = GetDC(dummyWin);
5414
5415 u32 pfd_flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
5416
5417 //if (RGFW_DOUBLE_BUFFER)
5418 pfd_flags |= PFD_DOUBLEBUFFER;
5419
5420 PIXELFORMATDESCRIPTOR pfd = {
5421 sizeof(pfd),
5422 1, /* version */
5423 pfd_flags,
5424 PFD_TYPE_RGBA, /* ipixel type */
5425 24, /* color bits */
5426 0, 0, 0, 0, 0, 0,
5427 8, /* alpha bits */
5428 0, 0, 0, 0, 0, 0,
5429 32, /* depth bits */
5430 8, /* stencil bits */
5431 0,
5432 PFD_MAIN_PLANE, /* Layer type */
5433 0, 0, 0, 0
5434 };
5435
5436 int pixel_format = ChoosePixelFormat(dummy_dc, &pfd);
5437 SetPixelFormat(dummy_dc, pixel_format, &pfd);
5438
5439 HGLRC dummy_context = wglCreateContext(dummy_dc);
5440 wglMakeCurrent(dummy_dc, dummy_context);
5441
5442 if (wglChoosePixelFormatARB == NULL) {
5443 wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) (void*) wglGetProcAddress("wglCreateContextAttribsARB");
5444 wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC) (void*)wglGetProcAddress("wglChoosePixelFormatARB");
5445 }
5446
5447 wglMakeCurrent(dummy_dc, 0);
5448 wglDeleteContext(dummy_context);
5449 ReleaseDC(dummyWin, dummy_dc);
5450
5451 /* try to create the pixel format we want for opengl and then try to create an opengl context for the specified version */
5452 if (wglCreateContextAttribsARB != NULL) {
5453 PIXELFORMATDESCRIPTOR pfd = {sizeof(pfd), 1, pfd_flags, PFD_TYPE_RGBA, 32, 8, PFD_MAIN_PLANE, 24, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
5454
5455 if (args & RGFW_OPENGL_SOFTWARE)
5456 pfd.dwFlags |= PFD_GENERIC_FORMAT | PFD_GENERIC_ACCELERATED;
5457
5458 if (wglChoosePixelFormatARB != NULL) {
5459 i32* pixel_format_attribs = (i32*)RGFW_initFormatAttribs(args & RGFW_OPENGL_SOFTWARE);
5460
5461 int pixel_format;
5462 UINT num_formats;
5463 wglChoosePixelFormatARB(win->src.hdc, pixel_format_attribs, 0, 1, &pixel_format, &num_formats);
5464 if (!num_formats) {
5465 printf("Failed to create a pixel format for WGL.\n");
5466 }
5467
5468 DescribePixelFormat(win->src.hdc, pixel_format, sizeof(pfd), &pfd);
5469 if (!SetPixelFormat(win->src.hdc, pixel_format, &pfd)) {
5470 printf("Failed to set the WGL pixel format.\n");
5471 }
5472 }
5473
5474 /* create opengl/WGL context for the specified version */
5475 u32 index = 0;
5476 i32 attribs[40];
5477
5478 if (RGFW_profile == RGFW_GL_CORE) {
5479 SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB);
5480 }
5481 else {
5482 SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB);
5483 }
5484
5485 if (RGFW_majorVersion || RGFW_minorVersion) {
5486 SET_ATTRIB(WGL_CONTEXT_MAJOR_VERSION_ARB, RGFW_majorVersion);
5487 SET_ATTRIB(WGL_CONTEXT_MINOR_VERSION_ARB, RGFW_minorVersion);
5488 }
5489
5490 SET_ATTRIB(0, 0);
5491
5492 win->src.ctx = (HGLRC)wglCreateContextAttribsARB(win->src.hdc, NULL, attribs);
5493 } else { /* fall back to a default context (probably opengl 2 or something) */
5494 fprintf(stderr, "Failed to create an accelerated OpenGL Context\n");
5495
5496 int pixel_format = ChoosePixelFormat(win->src.hdc, &pfd);
5497 SetPixelFormat(win->src.hdc, pixel_format, &pfd);
5498
5499 win->src.ctx = wglCreateContext(win->src.hdc);
5500 }
5501
5502 wglMakeCurrent(win->src.hdc, win->src.ctx);
5503#endif
5504 }
5505
5506#ifdef RGFW_OSMESA
5507#ifdef RGFW_LINK_OSM ESA
5508 OSMesaMakeCurrentSource = (PFN_OSMesaMakeCurrent) GetProcAddress(win->src.hdc, "OSMesaMakeCurrent");
5509 OSMesaCreateContextSource = (PFN_OSMesaCreateContext) GetProcAddress(win->src.hdc, "OSMesaCreateContext");
5510 OSMesaDestroyContextSource = (PFN_OSMesaDestroyContext) GetProcAddress(win->src.hdc, "OSMesaDestroyContext");
5511#endif
5512#endif
5513
5514#ifdef RGFW_OPENGL
5515 if ((args & RGFW_NO_INIT_API) == 0) {
5516 ReleaseDC(win->src.window, win->src.hdc);
5517 win->src.hdc = GetDC(win->src.window);
5518 wglMakeCurrent(win->src.hdc, win->src.ctx);
5519 }
5520#endif
5521
5522 DestroyWindow(dummyWin);
5523 RGFW_init_buffer(win);
5524
5525
5526 #ifndef RGFW_NO_MONITOR
5527 if (args & RGFW_SCALE_TO_MONITOR)
5528 RGFW_window_scaleToMonitor(win);
5529 #endif
5530
5531 if (args & RGFW_CENTER) {
5532 RGFW_area screenR = RGFW_getScreenSize();
5533 RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2));
5534 }
5535
5536#ifdef RGFW_EGL
5537 if ((args & RGFW_NO_INIT_API) == 0)
5538 RGFW_createOpenGLContext(win);
5539#endif
5540
5541 if (args & RGFW_HIDE_MOUSE)
5542 RGFW_window_showMouse(win, 0);
5543
5544 if (args & RGFW_TRANSPARENT_WINDOW) {
5545 SetWindowLong(win->src.window, GWL_EXSTYLE, GetWindowLong(win->src.window, GWL_EXSTYLE) | WS_EX_LAYERED);
5546 SetLayeredWindowAttributes(win->src.window, RGB(255, 255, 255), RGFW_ALPHA, LWA_ALPHA);
5547 }
5548
5549 ShowWindow(win->src.window, SW_SHOWNORMAL);
5550
5551 if (RGFW_root == NULL)
5552 RGFW_root = win;
5553
5554 #ifdef RGFW_OPENGL
5555 else
5556 wglShareLists(RGFW_root->src.ctx, win->src.ctx);
5557 #endif
5558
5559 return win;
5560 }
5561
5562 void RGFW_window_setBorder(RGFW_window* win, u8 border) {
5563 DWORD style = GetWindowLong(win->src.window, GWL_STYLE);
5564
5565 if (border == 0) {
5566 SetWindowLong(win->src.window, GWL_STYLE, style & ~WS_OVERLAPPEDWINDOW);
5567 SetWindowPos(
5568 win->src.window, HWND_TOP, 0, 0, 0, 0,
5569 SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE
5570 );
5571 }
5572 else {
5573 SetWindowLong(win->src.window, GWL_STYLE, style | WS_OVERLAPPEDWINDOW);
5574 SetWindowPos(
5575 win->src.window, HWND_TOP, 0, 0, 0, 0,
5576 SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE
5577 );
5578 }
5579 }
5580
5581
5582 RGFW_area RGFW_getScreenSize(void) {
5583 return RGFW_AREA(GetDeviceCaps(GetDC(NULL), HORZRES), GetDeviceCaps(GetDC(NULL), VERTRES));
5584 }
5585
5586 RGFW_point RGFW_getGlobalMousePoint(void) {
5587 POINT p;
5588 GetCursorPos(&p);
5589
5590 return RGFW_POINT(p.x, p.y);
5591 }
5592
5593 RGFW_point RGFW_window_getMousePoint(RGFW_window* win) {
5594 POINT p;
5595 GetCursorPos(&p);
5596 ScreenToClient(win->src.window, &p);
5597
5598 return RGFW_POINT(p.x, p.y);
5599 }
5600
5601 void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) {
5602 assert(win != NULL);
5603 win->src.minSize = a;
5604 }
5605
5606 void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) {
5607 assert(win != NULL);
5608 win->src.maxSize = a;
5609 }
5610
5611
5612 void RGFW_window_minimize(RGFW_window* win) {
5613 assert(win != NULL);
5614
5615 ShowWindow(win->src.window, SW_MINIMIZE);
5616 }
5617
5618 void RGFW_window_restore(RGFW_window* win) {
5619 assert(win != NULL);
5620
5621 ShowWindow(win->src.window, SW_RESTORE);
5622 }
5623
5624
5625 u8 RGFW_xinput2RGFW[] = {
5626 RGFW_JS_A, /* or PS X button */
5627 RGFW_JS_B, /* or PS circle button */
5628 RGFW_JS_X, /* or PS square button */
5629 RGFW_JS_Y, /* or PS triangle button */
5630 RGFW_JS_R1, /* right bumper */
5631 RGFW_JS_L1, /* left bump */
5632 RGFW_JS_L2, /* left trigger*/
5633 RGFW_JS_R2, /* right trigger */
5634 0, 0, 0, 0, 0, 0, 0, 0,
5635 RGFW_JS_UP, /* dpad up */
5636 RGFW_JS_DOWN, /* dpad down*/
5637 RGFW_JS_LEFT, /* dpad left */
5638 RGFW_JS_RIGHT, /* dpad right */
5639 RGFW_JS_START, /* start button */
5640 RGFW_JS_SELECT/* select button */
5641 };
5642
5643 static i32 RGFW_checkXInput(RGFW_window* win, RGFW_Event* e) {
5644 RGFW_UNUSED(win)
5645
5646 size_t i;
5647 for (i = 0; i < 4; i++) {
5648 XINPUT_KEYSTROKE keystroke;
5649
5650 if (XInputGetKeystroke == NULL)
5651 return 0;
5652
5653 DWORD result = XInputGetKeystroke((DWORD)i, 0, &keystroke);
5654
5655 if ((keystroke.Flags & XINPUT_KEYSTROKE_REPEAT) == 0 && result != ERROR_EMPTY) {
5656 if (result != ERROR_SUCCESS)
5657 return 0;
5658
5659 if (keystroke.VirtualKey > VK_PAD_BACK)
5660 continue;
5661
5662 // RGFW_jsButtonPressed + 1 = RGFW_jsButtonReleased
5663 e->type = RGFW_jsButtonPressed + !(keystroke.Flags & XINPUT_KEYSTROKE_KEYDOWN);
5664 e->button = RGFW_xinput2RGFW[keystroke.VirtualKey - 0x5800];
5665 RGFW_jsPressed[i][e->button] = !(keystroke.Flags & XINPUT_KEYSTROKE_KEYDOWN);
5666
5667 return 1;
5668 }
5669
5670 XINPUT_STATE state;
5671 if (XInputGetState == NULL ||
5672 XInputGetState((DWORD) i, &state) == ERROR_DEVICE_NOT_CONNECTED
5673 )
5674 return 0;
5675#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.
5676
5677 if ((state.Gamepad.sThumbLX < INPUT_DEADZONE &&
5678 state.Gamepad.sThumbLX > -INPUT_DEADZONE) &&
5679 (state.Gamepad.sThumbLY < INPUT_DEADZONE &&
5680 state.Gamepad.sThumbLY > -INPUT_DEADZONE))
5681 {
5682 state.Gamepad.sThumbLX = 0;
5683 state.Gamepad.sThumbLY = 0;
5684 }
5685
5686 if ((state.Gamepad.sThumbRX < INPUT_DEADZONE &&
5687 state.Gamepad.sThumbRX > -INPUT_DEADZONE) &&
5688 (state.Gamepad.sThumbRY < INPUT_DEADZONE &&
5689 state.Gamepad.sThumbRY > -INPUT_DEADZONE))
5690 {
5691 state.Gamepad.sThumbRX = 0;
5692 state.Gamepad.sThumbRY = 0;
5693 }
5694
5695 e->axisesCount = 2;
5696 RGFW_point axis1 = RGFW_POINT(state.Gamepad.sThumbLX, state.Gamepad.sThumbLY);
5697 RGFW_point axis2 = RGFW_POINT(state.Gamepad.sThumbRX, state.Gamepad.sThumbRY);
5698
5699 if (axis1.x != e->axis[0].x || axis1.y != e->axis[0].y || axis2.x != e->axis[1].x || axis2.y != e->axis[1].y) {
5700 e->type = RGFW_jsAxisMove;
5701
5702 e->axis[0] = axis1;
5703 e->axis[1] = axis2;
5704
5705 return 1;
5706 }
5707
5708 e->axis[0] = axis1;
5709 e->axis[1] = axis2;
5710 }
5711
5712 return 0;
5713 }
5714
5715 void RGFW_stopCheckEvents(void) {
5716 PostMessageW(RGFW_root->src.window, WM_NULL, 0, 0);
5717 }
5718
5719 void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) {
5720 RGFW_UNUSED(win);
5721
5722 MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD) (waitMS * 1e3), QS_ALLINPUT);
5723 }
5724
5725 RGFW_Event* RGFW_window_checkEvent(RGFW_window* win) {
5726 assert(win != NULL);
5727
5728 if (win->event.type == RGFW_quit) {
5729 return NULL;
5730 }
5731
5732 MSG msg;
5733
5734 if (RGFW_eventWindow.src.window == win->src.window) {
5735 if (RGFW_eventWindow.r.x != -1) {
5736 win->r.x = RGFW_eventWindow.r.x;
5737 win->r.y = RGFW_eventWindow.r.y;
5738 win->event.type = RGFW_windowMoved;
5739 RGFW_windowMoveCallback(win, win->r);
5740 }
5741
5742 if (RGFW_eventWindow.r.w != -1) {
5743 win->r.w = RGFW_eventWindow.r.w;
5744 win->r.h = RGFW_eventWindow.r.h;
5745 win->event.type = RGFW_windowResized;
5746 RGFW_windowResizeCallback(win, win->r);
5747 }
5748
5749 RGFW_eventWindow.src.window = NULL;
5750 RGFW_eventWindow.r = RGFW_RECT(-1, -1, -1, -1);
5751
5752 return &win->event;
5753 }
5754
5755
5756 static HDROP drop;
5757
5758 if (win->event.type == RGFW_dnd_init) {
5759 if (win->event.droppedFilesCount) {
5760 u32 i;
5761 for (i = 0; i < win->event.droppedFilesCount; i++)
5762 win->event.droppedFiles[i][0] = '\0';
5763 }
5764
5765 win->event.droppedFilesCount = 0;
5766 win->event.droppedFilesCount = DragQueryFileW(drop, 0xffffffff, NULL, 0);
5767 //win->event.droppedFiles = (char**)RGFW_CALLOC(win->event.droppedFilesCount, sizeof(char*));
5768
5769 u32 i;
5770 for (i = 0; i < win->event.droppedFilesCount; i++) {
5771 const UINT length = DragQueryFileW(drop, i, NULL, 0);
5772 WCHAR* buffer = (WCHAR*) RGFW_CALLOC((size_t) length + 1, sizeof(WCHAR));
5773
5774 DragQueryFileW(drop, i, buffer, length + 1);
5775 strncpy(win->event.droppedFiles[i], createUTF8FromWideStringWin32(buffer), RGFW_MAX_PATH);
5776 win->event.droppedFiles[i][RGFW_MAX_PATH - 1] = '\0';
5777 RGFW_FREE(buffer);
5778 }
5779
5780 DragFinish(drop);
5781 RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount);
5782
5783 win->event.type = RGFW_dnd;
5784 return &win->event;
5785 }
5786
5787 win->event.inFocus = (GetForegroundWindow() == win->src.window);
5788
5789 if (RGFW_checkXInput(win, &win->event))
5790 return &win->event;
5791
5792 static BYTE keyboardState[256];
5793
5794 if (PeekMessageA(&msg, win->src.window, 0u, 0u, PM_REMOVE)) {
5795 switch (msg.message) {
5796 case WM_CLOSE:
5797 case WM_QUIT:
5798 RGFW_windowQuitCallback(win);
5799 win->event.type = RGFW_quit;
5800 break;
5801
5802 case WM_ACTIVATE:
5803 win->event.inFocus = (LOWORD(msg.wParam) == WA_INACTIVE);
5804
5805 if (win->event.inFocus) {
5806 win->event.type = RGFW_focusIn;
5807 RGFW_focusCallback(win, 1);
5808 }
5809 else {
5810 win->event.type = RGFW_focusOut;
5811 RGFW_focusCallback(win, 0);
5812 }
5813
5814 break;
5815
5816 case WM_PAINT:
5817 win->event.type = RGFW_windowRefresh;
5818 RGFW_windowRefreshCallback(win);
5819 break;
5820
5821 case WM_MOUSELEAVE:
5822 win->event.type = RGFW_mouseLeave;
5823 win->_winArgs |= RGFW_MOUSE_LEFT;
5824 RGFW_mouseNotifyCallBack(win, win->event.point, 0);
5825 break;
5826
5827 case WM_KEYUP: {
5828 win->event.keyCode = RGFW_apiKeyCodeToRGFW((u32) msg.wParam);
5829
5830 RGFW_keyboard[win->event.keyCode].prev = RGFW_isPressed(win, win->event.keyCode);
5831
5832 static char keyName[16];
5833
5834 {
5835 GetKeyNameTextA((LONG) msg.lParam, keyName, 16);
5836
5837 if ((!(GetKeyState(VK_CAPITAL) & 0x0001) && !(GetKeyState(VK_SHIFT) & 0x8000)) ||
5838 ((GetKeyState(VK_CAPITAL) & 0x0001) && (GetKeyState(VK_SHIFT) & 0x8000))) {
5839 CharLowerBuffA(keyName, 16);
5840 }
5841 }
5842
5843 RGFW_updateLockState(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001));
5844
5845 strncpy(win->event.keyName, keyName, 16);
5846
5847 if (RGFW_isPressed(win, RGFW_ShiftL)) {
5848 ToAscii((UINT) msg.wParam, MapVirtualKey((UINT) msg.wParam, MAPVK_VK_TO_CHAR),
5849 keyboardState, (LPWORD) win->event.keyName, 0);
5850 }
5851
5852 win->event.type = RGFW_keyReleased;
5853 RGFW_keyboard[win->event.keyCode].current = 0;
5854 RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, 0);
5855 break;
5856 }
5857 case WM_KEYDOWN: {
5858 win->event.keyCode = RGFW_apiKeyCodeToRGFW((u32) msg.wParam);
5859
5860 RGFW_keyboard[win->event.keyCode].prev = RGFW_isPressed(win, win->event.keyCode);
5861
5862 static char keyName[16];
5863
5864 {
5865 GetKeyNameTextA((LONG) msg.lParam, keyName, 16);
5866
5867 if ((!(GetKeyState(VK_CAPITAL) & 0x0001) && !(GetKeyState(VK_SHIFT) & 0x8000)) ||
5868 ((GetKeyState(VK_CAPITAL) & 0x0001) && (GetKeyState(VK_SHIFT) & 0x8000))) {
5869 CharLowerBuffA(keyName, 16);
5870 }
5871 }
5872
5873 RGFW_updateLockState(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001));
5874
5875 strncpy(win->event.keyName, keyName, 16);
5876
5877 if (RGFW_isPressed(win, RGFW_ShiftL) & 0x8000) {
5878 ToAscii((UINT) msg.wParam, MapVirtualKey((UINT) msg.wParam, MAPVK_VK_TO_CHAR),
5879 keyboardState, (LPWORD) win->event.keyName, 0);
5880 }
5881
5882 win->event.type = RGFW_keyPressed;
5883 win->event.repeat = RGFW_isPressed(win, win->event.keyCode);
5884 RGFW_keyboard[win->event.keyCode].current = 1;
5885 RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, 1);
5886 break;
5887 }
5888
5889 case WM_MOUSEMOVE:
5890 if ((win->_winArgs & RGFW_HOLD_MOUSE))
5891 break;
5892
5893 win->event.type = RGFW_mousePosChanged;
5894
5895 win->event.point.x = GET_X_LPARAM(msg.lParam);
5896 win->event.point.y = GET_Y_LPARAM(msg.lParam);
5897
5898 RGFW_mousePosCallback(win, win->event.point);
5899
5900 if (win->_winArgs & RGFW_MOUSE_LEFT) {
5901 win->_winArgs ^= RGFW_MOUSE_LEFT;
5902 win->event.type = RGFW_mouseEnter;
5903 RGFW_mouseNotifyCallBack(win, win->event.point, 1);
5904 }
5905
5906 break;
5907
5908 case WM_INPUT: {
5909 if (!(win->_winArgs & RGFW_HOLD_MOUSE))
5910 break;
5911
5912 unsigned size = sizeof(RAWINPUT);
5913 static RAWINPUT raw[sizeof(RAWINPUT)];
5914 GetRawInputData((HRAWINPUT)msg.lParam, RID_INPUT, raw, &size, sizeof(RAWINPUTHEADER));
5915
5916 if (raw->header.dwType != RIM_TYPEMOUSE || (raw->data.mouse.lLastX == 0 && raw->data.mouse.lLastY == 0) )
5917 break;
5918
5919 win->event.type = RGFW_mousePosChanged;
5920 win->event.point.x = raw->data.mouse.lLastX;
5921 win->event.point.y = raw->data.mouse.lLastY;
5922 break;
5923 }
5924
5925 case WM_LBUTTONDOWN:
5926 win->event.button = RGFW_mouseLeft;
5927 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
5928 RGFW_mouseButtons[win->event.button].current = 1;
5929 win->event.type = RGFW_mouseButtonPressed;
5930 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
5931 break;
5932 case WM_RBUTTONDOWN:
5933 win->event.button = RGFW_mouseRight;
5934 win->event.type = RGFW_mouseButtonPressed;
5935 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
5936 RGFW_mouseButtons[win->event.button].current = 1;
5937 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
5938 break;
5939 case WM_MBUTTONDOWN:
5940 win->event.button = RGFW_mouseMiddle;
5941 win->event.type = RGFW_mouseButtonPressed;
5942 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
5943 RGFW_mouseButtons[win->event.button].current = 1;
5944 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
5945 break;
5946
5947 case WM_MOUSEWHEEL:
5948 if (msg.wParam > 0)
5949 win->event.button = RGFW_mouseScrollUp;
5950 else
5951 win->event.button = RGFW_mouseScrollDown;
5952
5953 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
5954 RGFW_mouseButtons[win->event.button].current = 1;
5955
5956 win->event.scroll = (SHORT) HIWORD(msg.wParam) / (double) WHEEL_DELTA;
5957
5958 win->event.type = RGFW_mouseButtonPressed;
5959 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
5960 break;
5961
5962 case WM_LBUTTONUP:
5963
5964 win->event.button = RGFW_mouseLeft;
5965 win->event.type = RGFW_mouseButtonReleased;
5966
5967 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
5968 RGFW_mouseButtons[win->event.button].current = 0;
5969 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0);
5970 break;
5971 case WM_RBUTTONUP:
5972 win->event.button = RGFW_mouseRight;
5973 win->event.type = RGFW_mouseButtonReleased;
5974
5975 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
5976 RGFW_mouseButtons[win->event.button].current = 0;
5977 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0);
5978 break;
5979 case WM_MBUTTONUP:
5980 win->event.button = RGFW_mouseMiddle;
5981 win->event.type = RGFW_mouseButtonReleased;
5982
5983 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
5984 RGFW_mouseButtons[win->event.button].current = 0;
5985 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0);
5986 break;
5987
5988 /*
5989 much of this event is source from glfw
5990 */
5991 case WM_DROPFILES: {
5992 win->event.type = RGFW_dnd_init;
5993
5994 drop = (HDROP) msg.wParam;
5995 POINT pt;
5996
5997 /* Move the mouse to the position of the drop */
5998 DragQueryPoint(drop, &pt);
5999
6000 win->event.point.x = pt.x;
6001 win->event.point.y = pt.y;
6002
6003 RGFW_dndInitCallback(win, win->event.point);
6004 }
6005 break;
6006 case WM_GETMINMAXINFO:
6007 {
6008 if (win->src.maxSize.w == 0 && win->src.maxSize.h == 0)
6009 break;
6010
6011 MINMAXINFO* mmi = (MINMAXINFO*) msg.lParam;
6012 mmi->ptMinTrackSize.x = win->src.minSize.w;
6013 mmi->ptMinTrackSize.y = win->src.minSize.h;
6014 mmi->ptMaxTrackSize.x = win->src.maxSize.w;
6015 mmi->ptMaxTrackSize.y = win->src.maxSize.h;
6016 return 0;
6017 }
6018 default:
6019 win->event.type = 0;
6020 break;
6021 }
6022
6023 TranslateMessage(&msg);
6024 DispatchMessageA(&msg);
6025 }
6026
6027 else
6028 win->event.type = 0;
6029
6030 if (!IsWindow(win->src.window)) {
6031 win->event.type = RGFW_quit;
6032 RGFW_windowQuitCallback(win);
6033 }
6034
6035 if (win->event.type)
6036 return &win->event;
6037 else
6038 return NULL;
6039 }
6040
6041 u8 RGFW_window_isFullscreen(RGFW_window* win) {
6042 assert(win != NULL);
6043
6044 #ifndef __cplusplus
6045 WINDOWPLACEMENT placement = { 0 };
6046 #else
6047 WINDOWPLACEMENT placement = { };
6048 #endif
6049 GetWindowPlacement(win->src.window, &placement);
6050 return placement.showCmd == SW_SHOWMAXIMIZED;
6051 }
6052
6053 u8 RGFW_window_isHidden(RGFW_window* win) {
6054 assert(win != NULL);
6055
6056 return IsWindowVisible(win->src.window) == 0 && !RGFW_window_isMinimized(win);
6057 }
6058
6059 u8 RGFW_window_isMinimized(RGFW_window* win) {
6060 assert(win != NULL);
6061
6062 #ifndef __cplusplus
6063 WINDOWPLACEMENT placement = { 0 };
6064 #else
6065 WINDOWPLACEMENT placement = { };
6066 #endif
6067 GetWindowPlacement(win->src.window, &placement);
6068 return placement.showCmd == SW_SHOWMINIMIZED;
6069 }
6070
6071 u8 RGFW_window_isMaximized(RGFW_window* win) {
6072 assert(win != NULL);
6073
6074 #ifndef __cplusplus
6075 WINDOWPLACEMENT placement = { 0 };
6076 #else
6077 WINDOWPLACEMENT placement = { };
6078 #endif
6079 GetWindowPlacement(win->src.window, &placement);
6080 return placement.showCmd == SW_SHOWMAXIMIZED;
6081 }
6082
6083 typedef struct { int iIndex; HMONITOR hMonitor; } RGFW_mInfo;
6084 BOOL CALLBACK GetMonitorByHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
6085 RGFW_UNUSED(hdcMonitor)
6086 RGFW_UNUSED(lprcMonitor)
6087
6088 RGFW_mInfo* info = (RGFW_mInfo*) dwData;
6089 if (info->hMonitor == hMonitor)
6090 return FALSE;
6091
6092 info->iIndex++;
6093 return TRUE;
6094 }
6095
6096 #ifndef RGFW_NO_MONITOR
6097 RGFW_monitor win32CreateMonitor(HMONITOR src) {
6098 RGFW_monitor monitor;
6099 MONITORINFO monitorInfo;
6100
6101 monitorInfo.cbSize = sizeof(MONITORINFO);
6102 GetMonitorInfoA(src, &monitorInfo);
6103
6104 RGFW_mInfo info;
6105 info.iIndex = 0;
6106 info.hMonitor = src;
6107
6108 /* get the monitor's index */
6109 if (EnumDisplayMonitors(NULL, NULL, GetMonitorByHandle, (LPARAM) &info)) {
6110 DISPLAY_DEVICEA dd;
6111 dd.cb = sizeof(dd);
6112
6113 /* loop through the devices until you find a device with the monitor's index */
6114 size_t deviceIndex;
6115 for (deviceIndex = 0; EnumDisplayDevicesA(0, (DWORD) deviceIndex, &dd, 0); deviceIndex++) {
6116 char* deviceName = dd.DeviceName;
6117 if (EnumDisplayDevicesA(deviceName, info.iIndex, &dd, 0)) {
6118 strncpy(monitor.name, dd.DeviceString, 128); /*!< copy the monitor's name */
6119 break;
6120 }
6121 }
6122 }
6123
6124 monitor.rect.x = monitorInfo.rcWork.left;
6125 monitor.rect.y = monitorInfo.rcWork.top;
6126 monitor.rect.w = monitorInfo.rcWork.right - monitorInfo.rcWork.left;
6127 monitor.rect.h = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top;
6128
6129#ifndef RGFW_NO_DPI
6130 #ifndef USER_DEFAULT_SCREEN_DPI
6131 #define USER_DEFAULT_SCREEN_DPI 96
6132 #endif
6133
6134 if (GetDpiForMonitor != NULL) {
6135 u32 x, y;
6136 GetDpiForMonitor(src, MDT_EFFECTIVE_DPI, &x, &y);
6137
6138 monitor.scaleX = (float) (x) / (float) USER_DEFAULT_SCREEN_DPI;
6139 monitor.scaleY = (float) (y) / (float) USER_DEFAULT_SCREEN_DPI;
6140 }
6141#endif
6142
6143 HDC hdc = GetDC(NULL);
6144 /* get pixels per inch */
6145 i32 ppiX = GetDeviceCaps(hdc, LOGPIXELSX);
6146 i32 ppiY = GetDeviceCaps(hdc, LOGPIXELSY);
6147 ReleaseDC(NULL, hdc);
6148
6149 /* Calculate physical height in inches */
6150 monitor.physW = GetSystemMetrics(SM_CYSCREEN) / (float) ppiX;
6151 monitor.physH = GetSystemMetrics(SM_CXSCREEN) / (float) ppiY;
6152
6153 return monitor;
6154 }
6155 #endif /* RGFW_NO_MONITOR */
6156
6157
6158 #ifndef RGFW_NO_MONITOR
6159 RGFW_monitor RGFW_monitors[6];
6160 BOOL CALLBACK GetMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
6161 RGFW_UNUSED(hdcMonitor)
6162 RGFW_UNUSED(lprcMonitor)
6163
6164 RGFW_mInfo* info = (RGFW_mInfo*) dwData;
6165
6166 if (info->iIndex >= 6)
6167 return FALSE;
6168
6169 RGFW_monitors[info->iIndex] = win32CreateMonitor(hMonitor);
6170 info->iIndex++;
6171
6172 return TRUE;
6173 }
6174
6175 RGFW_monitor RGFW_getPrimaryMonitor(void) {
6176 #ifdef __cplusplus
6177 return win32CreateMonitor(MonitorFromPoint({ 0, 0 }, MONITOR_DEFAULTTOPRIMARY));
6178 #else
6179 return win32CreateMonitor(MonitorFromPoint((POINT) { 0, 0 }, MONITOR_DEFAULTTOPRIMARY));
6180 #endif
6181 }
6182
6183 RGFW_monitor* RGFW_getMonitors(void) {
6184 RGFW_mInfo info;
6185 info.iIndex = 0;
6186 while (EnumDisplayMonitors(NULL, NULL, GetMonitorHandle, (LPARAM) &info));
6187
6188 return RGFW_monitors;
6189 }
6190
6191 RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) {
6192 HMONITOR src = MonitorFromWindow(win->src.window, MONITOR_DEFAULTTOPRIMARY);
6193 return win32CreateMonitor(src);
6194 }
6195 #endif
6196
6197 HICON RGFW_loadHandleImage(RGFW_window* win, u8* src, RGFW_area a, BOOL icon) {
6198 assert(win != NULL);
6199
6200 u32 i;
6201 HDC dc;
6202 HICON handle;
6203 HBITMAP color, mask;
6204 BITMAPV5HEADER bi;
6205 ICONINFO ii;
6206 u8* target = NULL;
6207 u8* source = src;
6208
6209 ZeroMemory(&bi, sizeof(bi));
6210 bi.bV5Size = sizeof(bi);
6211 bi.bV5Width = a.w;
6212 bi.bV5Height = -((LONG) a.h);
6213 bi.bV5Planes = 1;
6214 bi.bV5BitCount = 32;
6215 bi.bV5Compression = BI_BITFIELDS;
6216 bi.bV5RedMask = 0x00ff0000;
6217 bi.bV5GreenMask = 0x0000ff00;
6218 bi.bV5BlueMask = 0x000000ff;
6219 bi.bV5AlphaMask = 0xff000000;
6220
6221 dc = GetDC(NULL);
6222 color = CreateDIBSection(dc,
6223 (BITMAPINFO*) &bi,
6224 DIB_RGB_COLORS,
6225 (void**) &target,
6226 NULL,
6227 (DWORD) 0);
6228 ReleaseDC(NULL, dc);
6229
6230 mask = CreateBitmap(a.w, a.h, 1, 1, NULL);
6231
6232 for (i = 0; i < a.w * a.h; i++) {
6233 target[0] = source[2];
6234 target[1] = source[1];
6235 target[2] = source[0];
6236 target[3] = source[3];
6237 target += 4;
6238 source += 4;
6239 }
6240
6241 ZeroMemory(&ii, sizeof(ii));
6242 ii.fIcon = icon;
6243 ii.xHotspot = 0;
6244 ii.yHotspot = 0;
6245 ii.hbmMask = mask;
6246 ii.hbmColor = color;
6247
6248 handle = CreateIconIndirect(&ii);
6249
6250 DeleteObject(color);
6251 DeleteObject(mask);
6252
6253 return handle;
6254 }
6255
6256 void RGFW_window_setMouse(RGFW_window* win, u8* image, RGFW_area a, i32 channels) {
6257 assert(win != NULL);
6258 RGFW_UNUSED(channels)
6259
6260 HCURSOR cursor = (HCURSOR) RGFW_loadHandleImage(win, image, a, FALSE);
6261 SetClassLongPtrA(win->src.window, GCLP_HCURSOR, (LPARAM) cursor);
6262 SetCursor(cursor);
6263 DestroyCursor(cursor);
6264 }
6265
6266 void RGFW_window_setMouseDefault(RGFW_window* win) {
6267 RGFW_window_setMouseStandard(win, RGFW_MOUSE_ARROW);
6268 }
6269
6270 void RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) {
6271 assert(win != NULL);
6272
6273 if (mouse > (sizeof(RGFW_mouseIconSrc) / sizeof(u32)))
6274 return;
6275
6276 char* icon = MAKEINTRESOURCEA(RGFW_mouseIconSrc[mouse]);
6277
6278 SetClassLongPtrA(win->src.window, GCLP_HCURSOR, (LPARAM) LoadCursorA(NULL, icon));
6279 SetCursor(LoadCursorA(NULL, icon));
6280 }
6281
6282 void RGFW_window_hide(RGFW_window* win) {
6283 ShowWindow(win->src.window, SW_HIDE);
6284 }
6285
6286 void RGFW_window_show(RGFW_window* win) {
6287 ShowWindow(win->src.window, SW_RESTORE);
6288 }
6289
6290 void RGFW_window_close(RGFW_window* win) {
6291 assert(win != NULL);
6292
6293#ifdef RGFW_EGL
6294 RGFW_closeEGL(win);
6295#endif
6296
6297 if (win == RGFW_root) {
6298#ifdef RGFW_DIRECTX
6299 RGFW_dxInfo.pDeviceContext->lpVtbl->Release(RGFW_dxInfo.pDeviceContext);
6300 RGFW_dxInfo.pDevice->lpVtbl->Release(RGFW_dxInfo.pDevice);
6301 RGFW_dxInfo.pAdapter->lpVtbl->Release(RGFW_dxInfo.pAdapter);
6302 RGFW_dxInfo.pFactory->lpVtbl->Release(RGFW_dxInfo.pFactory);
6303#endif
6304
6305 if (RGFW_XInput_dll != NULL) {
6306 FreeLibrary(RGFW_XInput_dll);
6307 RGFW_XInput_dll = NULL;
6308 }
6309
6310 #ifndef RGFW_NO_DPI
6311 if (RGFW_Shcore_dll != NULL) {
6312 FreeLibrary(RGFW_Shcore_dll);
6313 RGFW_Shcore_dll = NULL;
6314 }
6315 #endif
6316
6317 if (wglinstance != NULL) {
6318 FreeLibrary(wglinstance);
6319 wglinstance = NULL;
6320 }
6321
6322 RGFW_root = NULL;
6323 }
6324
6325#ifdef RGFW_DIRECTX
6326 win->src.swapchain->lpVtbl->Release(win->src.swapchain);
6327 win->src.renderTargetView->lpVtbl->Release(win->src.renderTargetView);
6328 win->src.pDepthStencilView->lpVtbl->Release(win->src.pDepthStencilView);
6329#endif
6330
6331#ifdef RGFW_BUFFER
6332 DeleteDC(win->src.hdcMem);
6333 DeleteObject(win->src.bitmap);
6334#endif
6335
6336#ifdef RGFW_OPENGL
6337 wglDeleteContext((HGLRC) win->src.ctx); /*!< delete opengl context */
6338#endif
6339 DeleteDC(win->src.hdc); /*!< delete device context */
6340 DestroyWindow(win->src.window); /*!< delete window */
6341
6342#if defined(RGFW_OSMESA)
6343 if (win->buffer != NULL)
6344 RGFW_FREE(win->buffer);
6345#endif
6346
6347#ifdef RGFW_ALLOC_DROPFILES
6348 {
6349 u32 i;
6350 for (i = 0; i < RGFW_MAX_DROPS; i++)
6351 RGFW_FREE(win->event.droppedFiles[i]);
6352
6353
6354 RGFW_FREE(win->event.droppedFiles);
6355 }
6356#endif
6357
6358 RGFW_FREE(win);
6359 }
6360
6361 void RGFW_window_move(RGFW_window* win, RGFW_point v) {
6362 assert(win != NULL);
6363
6364 win->r.x = v.x;
6365 win->r.y = v.y;
6366 SetWindowPos(win->src.window, HWND_TOP, win->r.x, win->r.y, 0, 0, SWP_NOSIZE);
6367 }
6368
6369 void RGFW_window_resize(RGFW_window* win, RGFW_area a) {
6370 assert(win != NULL);
6371
6372 win->r.w = a.w;
6373 win->r.h = a.h;
6374 SetWindowPos(win->src.window, HWND_TOP, 0, 0, win->r.w, win->r.h + win->src.hOffset, SWP_NOMOVE);
6375 }
6376
6377
6378 void RGFW_window_setName(RGFW_window* win, char* name) {
6379 assert(win != NULL);
6380
6381 SetWindowTextA(win->src.window, name);
6382 }
6383
6384 /* sourced from GLFW */
6385 #ifndef RGFW_NO_PASSTHROUGH
6386 void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough) {
6387 assert(win != NULL);
6388
6389 COLORREF key = 0;
6390 BYTE alpha = 0;
6391 DWORD flags = 0;
6392 DWORD exStyle = GetWindowLongW(win->src.window, GWL_EXSTYLE);
6393
6394 if (exStyle & WS_EX_LAYERED)
6395 GetLayeredWindowAttributes(win->src.window, &key, &alpha, &flags);
6396
6397 if (passthrough)
6398 exStyle |= (WS_EX_TRANSPARENT | WS_EX_LAYERED);
6399 else
6400 {
6401 exStyle &= ~WS_EX_TRANSPARENT;
6402 // NOTE: Window opacity also needs the layered window style so do not
6403 // remove it if the window is alpha blended
6404 if (exStyle & WS_EX_LAYERED)
6405 {
6406 if (!(flags & LWA_ALPHA))
6407 exStyle &= ~WS_EX_LAYERED;
6408 }
6409 }
6410
6411 SetWindowLongW(win->src.window, GWL_EXSTYLE, exStyle);
6412
6413 if (passthrough) {
6414 SetLayeredWindowAttributes(win->src.window, key, alpha, flags);
6415 }
6416 }
6417 #endif
6418
6419 /* much of this function is sourced from GLFW */
6420 void RGFW_window_setIcon(RGFW_window* win, u8* src, RGFW_area a, i32 channels) {
6421 assert(win != NULL);
6422 #ifndef RGFW_WIN95
6423 RGFW_UNUSED(channels)
6424
6425 HICON handle = RGFW_loadHandleImage(win, src, a, TRUE);
6426
6427 SetClassLongPtrA(win->src.window, GCLP_HICON, (LPARAM) handle);
6428
6429 DestroyIcon(handle);
6430 #else
6431 RGFW_UNUSED(src)
6432 RGFW_UNUSED(a)
6433 RGFW_UNUSED(channels)
6434 #endif
6435 }
6436
6437 char* RGFW_readClipboard(size_t* size) {
6438 /* Open the clipboard */
6439 if (OpenClipboard(NULL) == 0)
6440 return (char*) "";
6441
6442 /* Get the clipboard data as a Unicode string */
6443 HANDLE hData = GetClipboardData(CF_UNICODETEXT);
6444 if (hData == NULL) {
6445 CloseClipboard();
6446 return (char*) "";
6447 }
6448
6449 wchar_t* wstr = (wchar_t*) GlobalLock(hData);
6450
6451 char* text;
6452
6453 {
6454 setlocale(LC_ALL, "en_US.UTF-8");
6455
6456 size_t textLen = wcstombs(NULL, wstr, 0);
6457 if (textLen == 0)
6458 return (char*) "";
6459
6460 text = (char*) RGFW_MALLOC((textLen * sizeof(char)) + 1);
6461
6462 wcstombs(text, wstr, (textLen) +1);
6463
6464 if (size != NULL)
6465 *size = textLen + 1;
6466
6467 text[textLen] = '\0';
6468 }
6469
6470 /* Release the clipboard data */
6471 GlobalUnlock(hData);
6472 CloseClipboard();
6473
6474 return text;
6475 }
6476
6477 void RGFW_writeClipboard(const char* text, u32 textLen) {
6478 HANDLE object;
6479 WCHAR* buffer;
6480
6481 object = GlobalAlloc(GMEM_MOVEABLE, (1 + textLen) * sizeof(WCHAR));
6482 if (!object)
6483 return;
6484
6485 buffer = (WCHAR*) GlobalLock(object);
6486 if (!buffer) {
6487 GlobalFree(object);
6488 return;
6489 }
6490
6491 MultiByteToWideChar(CP_UTF8, 0, text, -1, buffer, textLen);
6492 GlobalUnlock(object);
6493
6494 if (!OpenClipboard(RGFW_root->src.window)) {
6495 GlobalFree(object);
6496 return;
6497 }
6498
6499 EmptyClipboard();
6500 SetClipboardData(CF_UNICODETEXT, object);
6501 CloseClipboard();
6502 }
6503
6504 u16 RGFW_registerJoystick(RGFW_window* win, i32 jsNumber) {
6505 assert(win != NULL);
6506
6507 RGFW_UNUSED(jsNumber)
6508
6509 return RGFW_registerJoystickF(win, (char*) "");
6510 }
6511
6512 u16 RGFW_registerJoystickF(RGFW_window* win, char* file) {
6513 assert(win != NULL);
6514 RGFW_UNUSED(file)
6515
6516 return RGFW_joystickCount - 1;
6517 }
6518
6519 void RGFW_window_moveMouse(RGFW_window* win, RGFW_point p) {
6520 assert(win != NULL);
6521
6522 SetCursorPos(p.x, p.y);
6523 }
6524
6525 #ifdef RGFW_OPENGL
6526 void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
6527 if (win == NULL)
6528 wglMakeCurrent(NULL, NULL);
6529 else
6530 wglMakeCurrent(win->src.hdc, (HGLRC) win->src.ctx);
6531 }
6532 #endif
6533
6534 #ifndef RGFW_EGL
6535 void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) {
6536 assert(win != NULL);
6537
6538 #if defined(RGFW_OPENGL)
6539 typedef BOOL(APIENTRY* PFNWGLSWAPINTERVALEXTPROC)(int interval);
6540 static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
6541 static void* loadSwapFunc = (void*) 1;
6542
6543 if (loadSwapFunc == NULL) {
6544 fprintf(stderr, "wglSwapIntervalEXT not supported\n");
6545 return;
6546 }
6547
6548 if (wglSwapIntervalEXT == NULL) {
6549 loadSwapFunc = (void*) wglGetProcAddress("wglSwapIntervalEXT");
6550 wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) loadSwapFunc;
6551 }
6552
6553 if (wglSwapIntervalEXT(swapInterval) == FALSE)
6554 fprintf(stderr, "Failed to set swap interval\n");
6555 #else
6556 RGFW_UNUSED(swapInterval);
6557 #endif
6558
6559 }
6560 #endif
6561
6562 void RGFW_window_swapBuffers(RGFW_window* win) {
6563 //assert(win != NULL);
6564 /* clear the window*/
6565
6566 if (!(win->_winArgs & RGFW_NO_CPU_RENDER)) {
6567#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
6568 #ifdef RGFW_OSMESA
6569 RGFW_OSMesa_reorganize();
6570 #endif
6571
6572 HGDIOBJ oldbmp = SelectObject(win->src.hdcMem, win->src.bitmap);
6573 BitBlt(win->src.hdc, 0, 0, win->r.w, win->r.h, win->src.hdcMem, 0, 0, SRCCOPY);
6574 SelectObject(win->src.hdcMem, oldbmp);
6575#endif
6576 }
6577
6578 if (!(win->_winArgs & RGFW_NO_GPU_RENDER)) {
6579 #ifdef RGFW_EGL
6580 eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface);
6581 #elif defined(RGFW_OPENGL)
6582 SwapBuffers(win->src.hdc);
6583 #endif
6584
6585 #if defined(RGFW_WINDOWS) && defined(RGFW_DIRECTX)
6586 win->src.swapchain->lpVtbl->Present(win->src.swapchain, 0, 0);
6587 #endif
6588 }
6589 }
6590
6591 char* createUTF8FromWideStringWin32(const WCHAR* source) {
6592 char* target;
6593 i32 size;
6594
6595 size = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL);
6596 if (!size) {
6597 return NULL;
6598 }
6599
6600 target = (char*) RGFW_CALLOC(size, 1);
6601
6602 if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, size, NULL, NULL)) {
6603 RGFW_FREE(target);
6604 return NULL;
6605 }
6606
6607 return target;
6608 }
6609
6610 static inline LARGE_INTEGER RGFW_win32_initTimer(void) {
6611 static LARGE_INTEGER frequency = {{0, 0}};
6612 if (frequency.QuadPart == 0) {
6613 timeBeginPeriod(1);
6614 QueryPerformanceFrequency(&frequency);
6615 }
6616
6617 return frequency;
6618 }
6619
6620 u64 RGFW_getTimeNS(void) {
6621 LARGE_INTEGER frequency = RGFW_win32_initTimer();
6622
6623 LARGE_INTEGER counter;
6624 QueryPerformanceCounter(&counter);
6625
6626 return (u64) ((counter.QuadPart * 1e9) / frequency.QuadPart);
6627 }
6628
6629 u64 RGFW_getTime(void) {
6630 LARGE_INTEGER frequency = RGFW_win32_initTimer();
6631
6632 LARGE_INTEGER counter;
6633 QueryPerformanceCounter(&counter);
6634 return (u64) (counter.QuadPart / (double) frequency.QuadPart);
6635 }
6636
6637 void RGFW_sleep(u64 ms) {
6638 Sleep(ms);
6639 }
6640
6641#ifndef RGFW_NO_THREADS
6642 RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args) { return CreateThread(NULL, 0, ptr, args, 0, NULL); }
6643 void RGFW_cancelThread(RGFW_thread thread) { CloseHandle((HANDLE) thread); }
6644 void RGFW_joinThread(RGFW_thread thread) { WaitForSingleObject((HANDLE) thread, INFINITE); }
6645 void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { SetThreadPriority((HANDLE) thread, priority); }
6646#endif
6647#endif /* RGFW_WINDOWS */
6648
6649/*
6650 End of Windows defines
6651*/
6652
6653
6654
6655/*
6656
6657 Start of MacOS defines
6658
6659
6660*/
6661
6662#if defined(RGFW_MACOS)
6663 /*
6664 based on silicon.h
6665 start of cocoa wrapper
6666 */
6667
6668#include <CoreVideo/CVDisplayLink.h>
6669#include <ApplicationServices/ApplicationServices.h>
6670#include <objc/runtime.h>
6671#include <objc/message.h>
6672#include <mach/mach_time.h>
6673
6674 typedef CGRect NSRect;
6675 typedef CGPoint NSPoint;
6676 typedef CGSize NSSize;
6677
6678 typedef void NSBitmapImageRep;
6679 typedef void NSCursor;
6680 typedef void NSDraggingInfo;
6681 typedef void NSWindow;
6682 typedef void NSApplication;
6683 typedef void NSScreen;
6684 typedef void NSEvent;
6685 typedef void NSString;
6686 typedef void NSOpenGLContext;
6687 typedef void NSPasteboard;
6688 typedef void NSColor;
6689 typedef void NSArray;
6690 typedef void NSImageRep;
6691 typedef void NSImage;
6692 typedef void NSOpenGLView;
6693
6694
6695 typedef const char* NSPasteboardType;
6696 typedef unsigned long NSUInteger;
6697 typedef long NSInteger;
6698 typedef NSInteger NSModalResponse;
6699
6700#ifdef __arm64__
6701 /* ARM just uses objc_msgSend */
6702#define abi_objc_msgSend_stret objc_msgSend
6703#define abi_objc_msgSend_fpret objc_msgSend
6704#else /* __i386__ */
6705 /* x86 just uses abi_objc_msgSend_fpret and (NSColor *)objc_msgSend_id respectively */
6706#define abi_objc_msgSend_stret objc_msgSend_stret
6707#define abi_objc_msgSend_fpret objc_msgSend_fpret
6708#endif
6709
6710#define NSAlloc(nsclass) objc_msgSend_id((id)nsclass, sel_registerName("alloc"))
6711#define objc_msgSend_bool ((BOOL (*)(id, SEL))objc_msgSend)
6712#define objc_msgSend_void ((void (*)(id, SEL))objc_msgSend)
6713#define objc_msgSend_void_id ((void (*)(id, SEL, id))objc_msgSend)
6714#define objc_msgSend_uint ((NSUInteger (*)(id, SEL))objc_msgSend)
6715#define objc_msgSend_void_bool ((void (*)(id, SEL, BOOL))objc_msgSend)
6716#define objc_msgSend_bool_void ((BOOL (*)(id, SEL))objc_msgSend)
6717#define objc_msgSend_void_SEL ((void (*)(id, SEL, SEL))objc_msgSend)
6718#define objc_msgSend_id ((id (*)(id, SEL))objc_msgSend)
6719#define objc_msgSend_id_id ((id (*)(id, SEL, id))objc_msgSend)
6720#define objc_msgSend_id_bool ((BOOL (*)(id, SEL, id))objc_msgSend)
6721#define objc_msgSend_int ((id (*)(id, SEL, int))objc_msgSend)
6722#define objc_msgSend_arr ((id (*)(id, SEL, int))objc_msgSend)
6723#define objc_msgSend_ptr ((id (*)(id, SEL, void*))objc_msgSend)
6724#define objc_msgSend_class ((id (*)(Class, SEL))objc_msgSend)
6725#define objc_msgSend_class_char ((id (*)(Class, SEL, char*))objc_msgSend)
6726
6727 NSApplication* NSApp = NULL;
6728
6729 void NSRelease(id obj) {
6730 objc_msgSend_void(obj, sel_registerName("release"));
6731 }
6732
6733 #define release NSRelease
6734
6735 NSString* NSString_stringWithUTF8String(const char* str) {
6736 return ((id(*)(id, SEL, const char*))objc_msgSend)
6737 ((id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), str);
6738 }
6739
6740 const char* NSString_to_char(NSString* str) {
6741 return ((const char* (*)(id, SEL)) objc_msgSend) (str, sel_registerName("UTF8String"));
6742 }
6743
6744 void si_impl_func_to_SEL_with_name(const char* class_name, const char* register_name, void* function) {
6745 Class selected_class;
6746
6747 if (strcmp(class_name, "NSView") == 0) {
6748 selected_class = objc_getClass("ViewClass");
6749 } else if (strcmp(class_name, "NSWindow") == 0) {
6750 selected_class = objc_getClass("WindowClass");
6751 } else {
6752 selected_class = objc_getClass(class_name);
6753 }
6754
6755 class_addMethod(selected_class, sel_registerName(register_name), (IMP) function, 0);
6756 }
6757
6758 /* Header for the array. */
6759 typedef struct siArrayHeader {
6760 size_t count;
6761 /* TODO(EimaMei): Add a `type_width` later on. */
6762 } siArrayHeader;
6763
6764 /* Gets the header of the siArray. */
6765#define SI_ARRAY_HEADER(s) ((siArrayHeader*)s - 1)
6766
6767 void* si_array_init_reserve(size_t sizeof_element, size_t count) {
6768 siArrayHeader* ptr = malloc(sizeof(siArrayHeader) + (sizeof_element * count));
6769 void* array = ptr + sizeof(siArrayHeader);
6770
6771 siArrayHeader* header = SI_ARRAY_HEADER(array);
6772 header->count = count;
6773
6774 return array;
6775 }
6776
6777#define si_array_len(array) (SI_ARRAY_HEADER(array)->count)
6778#define si_func_to_SEL(class_name, function) si_impl_func_to_SEL_with_name(class_name, #function":", function)
6779 /* Creates an Objective-C method (SEL) from a regular C function with the option to set the register name.*/
6780#define si_func_to_SEL_with_name(class_name, register_name, function) si_impl_func_to_SEL_with_name(class_name, register_name":", function)
6781
6782 unsigned char* NSBitmapImageRep_bitmapData(NSBitmapImageRep* imageRep) {
6783 return ((unsigned char* (*)(id, SEL))objc_msgSend)
6784 (imageRep, sel_registerName("bitmapData"));
6785 }
6786
6787#define NS_ENUM(type, name) type name; enum
6788
6789 typedef NS_ENUM(NSUInteger, NSBitmapFormat) {
6790 NSBitmapFormatAlphaFirst = 1 << 0, // 0 means is alpha last (RGBA, CMYKA, etc.)
6791 NSBitmapFormatAlphaNonpremultiplied = 1 << 1, // 0 means is premultiplied
6792 NSBitmapFormatFloatingPointSamples = 1 << 2, // 0 is integer
6793
6794 NSBitmapFormatSixteenBitLittleEndian API_AVAILABLE(macos(10.10)) = (1 << 8),
6795 NSBitmapFormatThirtyTwoBitLittleEndian API_AVAILABLE(macos(10.10)) = (1 << 9),
6796 NSBitmapFormatSixteenBitBigEndian API_AVAILABLE(macos(10.10)) = (1 << 10),
6797 NSBitmapFormatThirtyTwoBitBigEndian API_AVAILABLE(macos(10.10)) = (1 << 11)
6798 };
6799
6800 NSBitmapImageRep* 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) {
6801 void* func = sel_registerName("initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bitmapFormat:bytesPerRow:bitsPerPixel:");
6802
6803 return (NSBitmapImageRep*) ((id(*)(id, SEL, unsigned char**, NSInteger, NSInteger, NSInteger, NSInteger, bool, bool, const char*, NSBitmapFormat, NSInteger, NSInteger))objc_msgSend)
6804 (NSAlloc((id)objc_getClass("NSBitmapImageRep")), func, planes, width, height, bps, spp, alpha, isPlanar, NSString_stringWithUTF8String(colorSpaceName), bitmapFormat, rowBytes, pixelBits);
6805 }
6806
6807 NSColor* NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha) {
6808 void* nsclass = objc_getClass("NSColor");
6809 void* func = sel_registerName("colorWithSRGBRed:green:blue:alpha:");
6810 return ((id(*)(id, SEL, CGFloat, CGFloat, CGFloat, CGFloat))objc_msgSend)
6811 (nsclass, func, red, green, blue, alpha);
6812 }
6813
6814 NSCursor* NSCursor_initWithImage(NSImage* newImage, NSPoint aPoint) {
6815 void* func = sel_registerName("initWithImage:hotSpot:");
6816 void* nsclass = objc_getClass("NSCursor");
6817
6818 return (NSCursor*) ((id(*)(id, SEL, id, NSPoint))objc_msgSend)
6819 (NSAlloc(nsclass), func, newImage, aPoint);
6820 }
6821
6822 void NSImage_addRepresentation(NSImage* image, NSImageRep* imageRep) {
6823 void* func = sel_registerName("addRepresentation:");
6824 objc_msgSend_void_id(image, func, imageRep);
6825 }
6826
6827 NSImage* NSImage_initWithSize(NSSize size) {
6828 void* func = sel_registerName("initWithSize:");
6829 return ((id(*)(id, SEL, NSSize))objc_msgSend)
6830 (NSAlloc((id)objc_getClass("NSImage")), func, size);
6831 }
6832#define NS_OPENGL_ENUM_DEPRECATED(minVers, maxVers) API_AVAILABLE(macos(minVers))
6833 typedef NS_ENUM(NSInteger, NSOpenGLContextParameter) {
6834 NSOpenGLContextParameterSwapInterval NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 222, /* 1 param. 0 -> Don't sync, 1 -> Sync to vertical retrace */
6835 NSOpenGLContextParametectxaceOrder NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 235, /* 1 param. 1 -> Above Window (default), -1 -> Below Window */
6836 NSOpenGLContextParametectxaceOpacity NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 236, /* 1 param. 1-> Surface is opaque (default), 0 -> non-opaque */
6837 NSOpenGLContextParametectxaceBackingSize NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 304, /* 2 params. Width/height of surface backing size */
6838 NSOpenGLContextParameterReclaimResources NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 308, /* 0 params. */
6839 NSOpenGLContextParameterCurrentRendererID NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 309, /* 1 param. Retrieves the current renderer ID */
6840 NSOpenGLContextParameterGPUVertexProcessing NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 310, /* 1 param. Currently processing vertices with GPU (get) */
6841 NSOpenGLContextParameterGPUFragmentProcessing NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 311, /* 1 param. Currently processing fragments with GPU (get) */
6842 NSOpenGLContextParameterHasDrawable NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 314, /* 1 param. Boolean returned if drawable is attached */
6843 NSOpenGLContextParameterMPSwapsInFlight NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 315, /* 1 param. Max number of swaps queued by the MP GL engine */
6844
6845 NSOpenGLContextParameterSwapRectangle API_DEPRECATED("", macos(10.0, 10.14)) = 200, /* 4 params. Set or get the swap rectangle {x, y, w, h} */
6846 NSOpenGLContextParameterSwapRectangleEnable API_DEPRECATED("", macos(10.0, 10.14)) = 201, /* Enable or disable the swap rectangle */
6847 NSOpenGLContextParameterRasterizationEnable API_DEPRECATED("", macos(10.0, 10.14)) = 221, /* Enable or disable all rasterization */
6848 NSOpenGLContextParameterStateValidation API_DEPRECATED("", macos(10.0, 10.14)) = 301, /* Validate state for multi-screen functionality */
6849 NSOpenGLContextParametectxaceSurfaceVolatile API_DEPRECATED("", macos(10.0, 10.14)) = 306, /* 1 param. Surface volatile state */
6850 };
6851
6852
6853 void NSOpenGLContext_setValues(NSOpenGLContext* context, const int* vals, NSOpenGLContextParameter param) {
6854 void* func = sel_registerName("setValues:forParameter:");
6855 ((void (*)(id, SEL, const int*, NSOpenGLContextParameter))objc_msgSend)
6856 (context, func, vals, param);
6857 }
6858
6859 void* NSOpenGLPixelFormat_initWithAttributes(const uint32_t* attribs) {
6860 void* func = sel_registerName("initWithAttributes:");
6861 return (void*) ((id(*)(id, SEL, const uint32_t*))objc_msgSend)
6862 (NSAlloc((id)objc_getClass("NSOpenGLPixelFormat")), func, attribs);
6863 }
6864
6865 NSOpenGLView* NSOpenGLView_initWithFrame(NSRect frameRect, uint32_t* format) {
6866 void* func = sel_registerName("initWithFrame:pixelFormat:");
6867 return (NSOpenGLView*) ((id(*)(id, SEL, NSRect, uint32_t*))objc_msgSend)
6868 (NSAlloc((id)objc_getClass("NSOpenGLView")), func, frameRect, format);
6869 }
6870
6871 void NSCursor_performSelector(NSCursor* cursor, void* selector) {
6872 void* func = sel_registerName("performSelector:");
6873 objc_msgSend_void_SEL(cursor, func, selector);
6874 }
6875
6876 NSPasteboard* NSPasteboard_generalPasteboard(void) {
6877 return (NSPasteboard*) objc_msgSend_id((id)objc_getClass("NSPasteboard"), sel_registerName("generalPasteboard"));
6878 }
6879
6880 NSString** cstrToNSStringArray(char** strs, size_t len) {
6881 static NSString* nstrs[6];
6882 size_t i;
6883 for (i = 0; i < len; i++)
6884 nstrs[i] = NSString_stringWithUTF8String(strs[i]);
6885
6886 return nstrs;
6887 }
6888
6889 const char* NSPasteboard_stringForType(NSPasteboard* pasteboard, NSPasteboardType dataType) {
6890 void* func = sel_registerName("stringForType:");
6891 return (const char*) NSString_to_char(((id(*)(id, SEL, const char*))objc_msgSend)(pasteboard, func, NSString_stringWithUTF8String(dataType)));
6892 }
6893
6894 NSArray* c_array_to_NSArray(void* array, size_t len) {
6895 SEL func = sel_registerName("initWithObjects:count:");
6896 void* nsclass = objc_getClass("NSArray");
6897 return ((id (*)(id, SEL, void*, NSUInteger))objc_msgSend)
6898 (NSAlloc(nsclass), func, array, len);
6899 }
6900
6901 void NSregisterForDraggedTypes(void* view, NSPasteboardType* newTypes, size_t len) {
6902 NSString** ntypes = cstrToNSStringArray((char**)newTypes, len);
6903
6904 NSArray* array = c_array_to_NSArray(ntypes, len);
6905 objc_msgSend_void_id(view, sel_registerName("registerForDraggedTypes:"), array);
6906 NSRelease(array);
6907 }
6908
6909 NSInteger NSPasteBoard_declareTypes(NSPasteboard* pasteboard, NSPasteboardType* newTypes, size_t len, void* owner) {
6910 NSString** ntypes = cstrToNSStringArray((char**)newTypes, len);
6911
6912 void* func = sel_registerName("declareTypes:owner:");
6913
6914 NSArray* array = c_array_to_NSArray(ntypes, len);
6915
6916 NSInteger output = ((NSInteger(*)(id, SEL, id, void*))objc_msgSend)
6917 (pasteboard, func, array, owner);
6918 NSRelease(array);
6919
6920 return output;
6921 }
6922
6923 bool NSPasteBoard_setString(NSPasteboard* pasteboard, const char* stringToWrite, NSPasteboardType dataType) {
6924 void* func = sel_registerName("setString:forType:");
6925 return ((bool (*)(id, SEL, id, NSPasteboardType))objc_msgSend)
6926 (pasteboard, func, NSString_stringWithUTF8String(stringToWrite), NSString_stringWithUTF8String(dataType));
6927 }
6928
6929 void NSRetain(id obj) { objc_msgSend_void(obj, sel_registerName("retain")); }
6930
6931 typedef enum NSApplicationActivationPolicy {
6932 NSApplicationActivationPolicyRegular,
6933 NSApplicationActivationPolicyAccessory,
6934 NSApplicationActivationPolicyProhibited
6935 } NSApplicationActivationPolicy;
6936
6937 typedef NS_ENUM(u32, NSBackingStoreType) {
6938 NSBackingStoreRetained = 0,
6939 NSBackingStoreNonretained = 1,
6940 NSBackingStoreBuffered = 2
6941 };
6942
6943 typedef NS_ENUM(u32, NSWindowStyleMask) {
6944 NSWindowStyleMaskBorderless = 0,
6945 NSWindowStyleMaskTitled = 1 << 0,
6946 NSWindowStyleMaskClosable = 1 << 1,
6947 NSWindowStyleMaskMiniaturizable = 1 << 2,
6948 NSWindowStyleMaskResizable = 1 << 3,
6949 NSWindowStyleMaskTexturedBackground = 1 << 8, /* deprecated */
6950 NSWindowStyleMaskUnifiedTitleAndToolbar = 1 << 12,
6951 NSWindowStyleMaskFullScreen = 1 << 14,
6952 NSWindowStyleMaskFullSizeContentView = 1 << 15,
6953 NSWindowStyleMaskUtilityWindow = 1 << 4,
6954 NSWindowStyleMaskDocModalWindow = 1 << 6,
6955 NSWindowStyleMaskNonactivatingPanel = 1 << 7,
6956 NSWindowStyleMaskHUDWindow = 1 << 13
6957 };
6958
6959 NSPasteboardType const NSPasteboardTypeString = "public.utf8-plain-text"; // Replaces NSStringPboardType
6960
6961
6962 typedef NS_ENUM(i32, NSDragOperation) {
6963 NSDragOperationNone = 0,
6964 NSDragOperationCopy = 1,
6965 NSDragOperationLink = 2,
6966 NSDragOperationGeneric = 4,
6967 NSDragOperationPrivate = 8,
6968 NSDragOperationMove = 16,
6969 NSDragOperationDelete = 32,
6970 NSDragOperationEvery = ULONG_MAX,
6971
6972 //NSDragOperationAll_Obsolete API_DEPRECATED("", macos(10.0,10.10)) = 15, // Use NSDragOperationEvery
6973 //NSDragOperationAll API_DEPRECATED("", macos(10.0,10.10)) = NSDragOperationAll_Obsolete, // Use NSDragOperationEvery
6974 };
6975
6976 void* NSArray_objectAtIndex(NSArray* array, NSUInteger index) {
6977 void* func = sel_registerName("objectAtIndex:");
6978 return ((id(*)(id, SEL, NSUInteger))objc_msgSend)(array, func, index);
6979 }
6980
6981 const char** NSPasteboard_readObjectsForClasses(NSPasteboard* pasteboard, Class* classArray, size_t len, void* options) {
6982 void* func = sel_registerName("readObjectsForClasses:options:");
6983
6984 NSArray* array = c_array_to_NSArray(classArray, len);
6985
6986 NSArray* output = (NSArray*) ((id(*)(id, SEL, id, void*))objc_msgSend)
6987 (pasteboard, func, array, options);
6988
6989 NSRelease(array);
6990 NSUInteger count = ((NSUInteger(*)(id, SEL))objc_msgSend)(output, sel_registerName("count"));
6991
6992 const char** res = si_array_init_reserve(sizeof(const char*), count);
6993
6994 void* path_func = sel_registerName("path");
6995
6996 for (NSUInteger i = 0; i < count; i++) {
6997 void* url = NSArray_objectAtIndex(output, i);
6998 NSString* url_str = ((id(*)(id, SEL))objc_msgSend)(url, path_func);
6999 res[i] = NSString_to_char(url_str);
7000 }
7001
7002 return res;
7003 }
7004
7005 void* NSWindow_contentView(NSWindow* window) {
7006 void* func = sel_registerName("contentView");
7007 return objc_msgSend_id(window, func);
7008 }
7009
7010 /*
7011 End of cocoa wrapper
7012 */
7013
7014 char* RGFW_mouseIconSrc[] = {"arrowCursor", "arrowCursor", "IBeamCursor", "crosshairCursor", "pointingHandCursor", "resizeLeftRightCursor", "resizeUpDownCursor", "_windowResizeNorthWestSouthEastCursor", "_windowResizeNorthEastSouthWestCursor", "closedHandCursor", "operationNotAllowedCursor"};
7015
7016 void* RGFWnsglFramework = NULL;
7017
7018#ifdef RGFW_OPENGL
7019 void* RGFW_getProcAddress(const char* procname) {
7020 if (RGFWnsglFramework == NULL)
7021 RGFWnsglFramework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
7022
7023 CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault, procname, kCFStringEncodingASCII);
7024
7025 void* symbol = CFBundleGetFunctionPointerForName(RGFWnsglFramework, symbolName);
7026
7027 CFRelease(symbolName);
7028
7029 return symbol;
7030 }
7031#endif
7032
7033 CVReturn displayCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* inNow, const CVTimeStamp* inOutputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext) {
7034 RGFW_UNUSED(displayLink) RGFW_UNUSED(inNow) RGFW_UNUSED(inOutputTime) RGFW_UNUSED(flagsIn) RGFW_UNUSED(flagsOut) RGFW_UNUSED(displayLinkContext)
7035 return kCVReturnSuccess;
7036 }
7037
7038 id NSWindow_delegate(RGFW_window* win) {
7039 return (id) objc_msgSend_id(win->src.window, sel_registerName("delegate"));
7040 }
7041
7042 u32 RGFW_OnClose(void* self) {
7043 RGFW_window* win = NULL;
7044 object_getInstanceVariable(self, "RGFW_window", (void*)&win);
7045 if (win == NULL)
7046 return true;
7047
7048 win->event.type = RGFW_quit;
7049 RGFW_windowQuitCallback(win);
7050
7051 return true;
7052 }
7053
7054 /* NOTE(EimaMei): Fixes the constant clicking when the app is running under a terminal. */
7055 bool acceptsFirstResponder(void) { return true; }
7056 bool performKeyEquivalent(NSEvent* event) { RGFW_UNUSED(event); return true; }
7057
7058 NSDragOperation draggingEntered(id self, SEL sel, id sender) {
7059 RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel);
7060
7061 return NSDragOperationCopy;
7062 }
7063 NSDragOperation draggingUpdated(id self, SEL sel, id sender) {
7064 RGFW_UNUSED(sel);
7065
7066 RGFW_window* win = NULL;
7067 object_getInstanceVariable(self, "RGFW_window", (void*)&win);
7068 if (win == NULL)
7069 return 0;
7070
7071 if (!(win->_winArgs & RGFW_ALLOW_DND)) {
7072 return 0;
7073 }
7074
7075 win->event.type = RGFW_dnd_init;
7076 win->src.dndPassed = 0;
7077
7078 NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation"));
7079
7080 win->event.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y));
7081 RGFW_dndInitCallback(win, win->event.point);
7082
7083 return NSDragOperationCopy;
7084 }
7085 bool prepareForDragOperation(id self) {
7086 RGFW_window* win = NULL;
7087 object_getInstanceVariable(self, "RGFW_window", (void*)&win);
7088 if (win == NULL)
7089 return true;
7090
7091 if (!(win->_winArgs & RGFW_ALLOW_DND)) {
7092 return false;
7093 }
7094
7095 return true;
7096 }
7097
7098 void RGFW__osxDraggingEnded(id self, SEL sel, id sender) { RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel); return; }
7099
7100 /* NOTE(EimaMei): Usually, you never need 'id self, SEL cmd' for C -> Obj-C methods. This isn't the case. */
7101 bool performDragOperation(id self, SEL sel, id sender) {
7102 RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel);
7103
7104 RGFW_window* win = NULL;
7105 object_getInstanceVariable(self, "RGFW_window", (void*)&win);
7106
7107 if (win == NULL)
7108 return false;
7109
7110 // NSPasteboard* pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard"));
7111
7112 /////////////////////////////
7113 id pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard"));
7114
7115 // Get the types of data available on the pasteboard
7116 id types = objc_msgSend_id(pasteBoard, sel_registerName("types"));
7117
7118 // Get the string type for file URLs
7119 id fileURLsType = objc_msgSend_class_char(objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "NSFilenamesPboardType");
7120
7121 // Check if the pasteboard contains file URLs
7122 if (objc_msgSend_id_bool(types, sel_registerName("containsObject:"), fileURLsType) == 0) {
7123 #ifdef RGFW_DEBUG
7124 printf("No files found on the pasteboard.\n");
7125 #endif
7126
7127 return 0;
7128 }
7129
7130 id fileURLs = objc_msgSend_id_id(pasteBoard, sel_registerName("propertyListForType:"), fileURLsType);
7131 int count = ((int (*)(id, SEL))objc_msgSend)(fileURLs, sel_registerName("count"));
7132
7133 if (count == 0)
7134 return 0;
7135
7136 for (int i = 0; i < count; i++) {
7137 id fileURL = objc_msgSend_arr(fileURLs, sel_registerName("objectAtIndex:"), i);
7138 const char *filePath = ((const char* (*)(id, SEL))objc_msgSend)(fileURL, sel_registerName("UTF8String"));
7139 strncpy(win->event.droppedFiles[i], filePath, RGFW_MAX_PATH);
7140 win->event.droppedFiles[i][RGFW_MAX_PATH - 1] = '\0';
7141 }
7142 win->event.droppedFilesCount = count;
7143
7144 win->event.type = RGFW_dnd;
7145 win->src.dndPassed = 0;
7146
7147 NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation"));
7148 win->event.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y));
7149
7150 RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount);
7151
7152 return false;
7153 }
7154
7155 static void NSMoveToResourceDir(void) {
7156 /* sourced from glfw */
7157 char resourcesPath[255];
7158
7159 CFBundleRef bundle = CFBundleGetMainBundle();
7160 if (!bundle)
7161 return;
7162
7163 CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle);
7164 CFStringRef last = CFURLCopyLastPathComponent(resourcesURL);
7165
7166 if (
7167 CFStringCompare(CFSTR("Resources"), last, 0) != kCFCompareEqualTo ||
7168 CFURLGetFileSystemRepresentation(resourcesURL, true, (u8*) resourcesPath, 255) == 0
7169 ) {
7170 CFRelease(last);
7171 CFRelease(resourcesURL);
7172 return;
7173 }
7174
7175 CFRelease(last);
7176 CFRelease(resourcesURL);
7177
7178 chdir(resourcesPath);
7179 }
7180
7181
7182 NSSize RGFW__osxWindowResize(void* self, SEL sel, NSSize frameSize) {
7183 RGFW_UNUSED(sel);
7184
7185 RGFW_window* win = NULL;
7186 object_getInstanceVariable(self, "RGFW_window", (void*)&win);
7187 if (win == NULL)
7188 return frameSize;
7189
7190 win->r.w = frameSize.width;
7191 win->r.h = frameSize.height;
7192 win->event.type = RGFW_windowResized;
7193 RGFW_windowResizeCallback(win, win->r);
7194 return frameSize;
7195 }
7196
7197 void RGFW__osxWindowMove(void* self, SEL sel) {
7198 RGFW_UNUSED(sel);
7199
7200 RGFW_window* win = NULL;
7201 object_getInstanceVariable(self, "RGFW_window", (void*)&win);
7202 if (win == NULL)
7203 return;
7204
7205 NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)(win->src.window, sel_registerName("frame"));
7206 win->r.x = (i32) frame.origin.x;
7207 win->r.y = (i32) frame.origin.y;
7208
7209 win->event.type = RGFW_windowMoved;
7210 RGFW_windowMoveCallback(win, win->r);
7211 }
7212
7213 void RGFW__osxUpdateLayer(void* self, SEL sel) {
7214 RGFW_UNUSED(sel);
7215
7216 RGFW_window* win = NULL;
7217 object_getInstanceVariable(self, "RGFW_window", (void*)&win);
7218 if (win == NULL)
7219 return;
7220
7221 win->event.type = RGFW_windowRefresh;
7222 RGFW_windowRefreshCallback(win);
7223 }
7224
7225 RGFWDEF void RGFW_init_buffer(RGFW_window* win);
7226 void RGFW_init_buffer(RGFW_window* win) {
7227 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
7228 if (RGFW_bufferSize.w == 0 && RGFW_bufferSize.h == 0)
7229 RGFW_bufferSize = RGFW_getScreenSize();
7230
7231 win->buffer = RGFW_MALLOC(RGFW_bufferSize.w * RGFW_bufferSize.h * 4);
7232
7233 #ifdef RGFW_OSMESA
7234 win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL);
7235 OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, win->r.w, win->r.h);
7236 #endif
7237 #else
7238 RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
7239 #endif
7240 }
7241
7242
7243 void RGFW_window_cocoaSetLayer(RGFW_window* win, void* layer) {
7244 objc_msgSend_void_id(win->src.view, sel_registerName("setLayer"), layer);
7245 }
7246
7247 void* RGFW_cocoaGetLayer(void) {
7248 return objc_msgSend_class(objc_getClass("CAMetalLayer"), sel_registerName("layer"));
7249 }
7250
7251
7252 NSPasteboardType const NSPasteboardTypeURL = "public.url";
7253 NSPasteboardType const NSPasteboardTypeFileURL = "public.file-url";
7254
7255 RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, u16 args) {
7256 static u8 RGFW_loaded = 0;
7257
7258 /* NOTE(EimaMei): Why does Apple hate good code? Like wtf, who thought of methods being a great idea???
7259 Imagine a universe, where MacOS had a proper system API (we would probably have like 20% better performance).
7260 */
7261 si_func_to_SEL_with_name("NSObject", "windowShouldClose", RGFW_OnClose);
7262
7263 /* NOTE(EimaMei): Fixes the 'Boop' sfx from constantly playing each time you click a key. Only a problem when running in the terminal. */
7264 si_func_to_SEL("NSWindow", acceptsFirstResponder);
7265 si_func_to_SEL("NSWindow", performKeyEquivalent);
7266
7267 // RR Create an autorelease pool
7268 id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
7269 pool = objc_msgSend_id(pool, sel_registerName("init"));
7270
7271 if (NSApp == NULL) {
7272 NSApp = objc_msgSend_id((id)objc_getClass("NSApplication"), sel_registerName("sharedApplication"));
7273
7274 ((void (*)(id, SEL, NSUInteger))objc_msgSend)
7275 (NSApp, sel_registerName("setActivationPolicy:"), NSApplicationActivationPolicyRegular);
7276 }
7277
7278 RGFW_window* win = RGFW_window_basic_init(rect, args);
7279
7280 RGFW_window_setMouseDefault(win);
7281
7282 NSRect windowRect;
7283 windowRect.origin.x = win->r.x;
7284 windowRect.origin.y = win->r.y;
7285 windowRect.size.width = win->r.w;
7286 windowRect.size.height = win->r.h;
7287
7288 NSBackingStoreType macArgs = NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSBackingStoreBuffered | NSWindowStyleMaskTitled;
7289
7290 if (!(args & RGFW_NO_RESIZE))
7291 macArgs |= NSWindowStyleMaskResizable;
7292 if (!(args & RGFW_NO_BORDER))
7293 macArgs |= NSWindowStyleMaskTitled;
7294 else
7295 macArgs = NSWindowStyleMaskBorderless;
7296 {
7297 void* nsclass = objc_getClass("NSWindow");
7298 void* func = sel_registerName("initWithContentRect:styleMask:backing:defer:");
7299
7300 win->src.window = ((id(*)(id, SEL, NSRect, NSWindowStyleMask, NSBackingStoreType, bool))objc_msgSend)
7301 (NSAlloc(nsclass), func, windowRect, macArgs, macArgs, false);
7302 }
7303
7304 NSString* str = NSString_stringWithUTF8String(name);
7305 objc_msgSend_void_id(win->src.window, sel_registerName("setTitle:"), str);
7306
7307#ifdef RGFW_EGL
7308 if ((args & RGFW_NO_INIT_API) == 0)
7309 RGFW_createOpenGLContext(win);
7310#endif
7311
7312#ifdef RGFW_OPENGL
7313 if ((args & RGFW_NO_INIT_API) == 0) {
7314 void* attrs = RGFW_initFormatAttribs(args & RGFW_OPENGL_SOFTWARE);
7315 void* format = NSOpenGLPixelFormat_initWithAttributes(attrs);
7316
7317 if (format == NULL) {
7318 printf("Failed to load pixel format for OpenGL\n");
7319
7320 void* attrs = RGFW_initFormatAttribs(1);
7321 format = NSOpenGLPixelFormat_initWithAttributes(attrs);
7322 if (format == NULL)
7323 printf("and loading software rendering OpenGL failed\n");
7324 else
7325 printf("Switching to software rendering\n");
7326 }
7327
7328 /* the pixel format can be passed directly to opengl context creation to create a context
7329 this is because the format also includes information about the opengl version (which may be a bad thing) */
7330 win->src.view = NSOpenGLView_initWithFrame((NSRect){{0, 0}, {win->r.w, win->r.h}}, format);
7331 objc_msgSend_void(win->src.view, sel_registerName("prepareOpenGL"));
7332 win->src.ctx = objc_msgSend_id(win->src.view, sel_registerName("openGLContext"));
7333 } else
7334#endif
7335 {
7336 NSRect contentRect = (NSRect){{0, 0}, {win->r.w, win->r.h}};
7337 win->src.view = ((id(*)(id, SEL, NSRect))objc_msgSend)
7338 (NSAlloc((id)objc_getClass("NSView")), sel_registerName("initWithFrame:"),
7339 contentRect);
7340 }
7341
7342 void* contentView = NSWindow_contentView(win->src.window);
7343 objc_msgSend_void_bool(contentView, sel_registerName("setWantsLayer:"), true);
7344
7345 objc_msgSend_void_id(win->src.window, sel_registerName("setContentView:"), win->src.view);
7346
7347#ifdef RGFW_OPENGL
7348 if ((args & RGFW_NO_INIT_API) == 0)
7349 objc_msgSend_void(win->src.ctx, sel_registerName("makeCurrentContext"));
7350#endif
7351 if (args & RGFW_TRANSPARENT_WINDOW) {
7352#ifdef RGFW_OPENGL
7353 if ((args & RGFW_NO_INIT_API) == 0) {
7354 i32 opacity = 0;
7355 #define NSOpenGLCPSurfaceOpacity 236
7356 NSOpenGLContext_setValues(win->src.ctx, &opacity, NSOpenGLCPSurfaceOpacity);
7357 }
7358#endif
7359
7360 objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), false);
7361
7362 objc_msgSend_void_id(win->src.window, sel_registerName("setBackgroundColor:"),
7363 NSColor_colorWithSRGB(0, 0, 0, 0));
7364 }
7365
7366 win->src.display = CGMainDisplayID();
7367 CVDisplayLinkCreateWithCGDisplay(win->src.display, (CVDisplayLinkRef*)&win->src.displayLink);
7368 CVDisplayLinkSetOutputCallback(win->src.displayLink, displayCallback, win);
7369 CVDisplayLinkStart(win->src.displayLink);
7370
7371 RGFW_init_buffer(win);
7372
7373 #ifndef RGFW_NO_MONITOR
7374 if (args & RGFW_SCALE_TO_MONITOR)
7375 RGFW_window_scaleToMonitor(win);
7376 #endif
7377
7378 if (args & RGFW_CENTER) {
7379 RGFW_area screenR = RGFW_getScreenSize();
7380 RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2));
7381 }
7382
7383 if (args & RGFW_HIDE_MOUSE)
7384 RGFW_window_showMouse(win, 0);
7385
7386 if (args & RGFW_COCOA_MOVE_TO_RESOURCE_DIR)
7387 NSMoveToResourceDir();
7388
7389 Class delegateClass = objc_allocateClassPair(objc_getClass("NSObject"), "WindowDelegate", 0);
7390
7391 class_addIvar(
7392 delegateClass, "RGFW_window",
7393 sizeof(RGFW_window*), rint(log2(sizeof(RGFW_window*))),
7394 "L"
7395 );
7396
7397 class_addMethod(delegateClass, sel_registerName("windowWillResize:toSize:"), (IMP) RGFW__osxWindowResize, "{NSSize=ff}@:{NSSize=ff}");
7398 class_addMethod(delegateClass, sel_registerName("updateLayer:"), (IMP) RGFW__osxUpdateLayer, "");
7399 class_addMethod(delegateClass, sel_registerName("windowWillMove:"), (IMP) RGFW__osxWindowMove, "");
7400 class_addMethod(delegateClass, sel_registerName("windowDidMove:"), (IMP) RGFW__osxWindowMove, "");
7401 class_addMethod(delegateClass, sel_registerName("draggingEntered:"), (IMP)draggingEntered, "l@:@");
7402 class_addMethod(delegateClass, sel_registerName("draggingUpdated:"), (IMP)draggingUpdated, "l@:@");
7403 class_addMethod(delegateClass, sel_registerName("draggingExited:"), (IMP)RGFW__osxDraggingEnded, "v@:@");
7404 class_addMethod(delegateClass, sel_registerName("draggingEnded:"), (IMP)RGFW__osxDraggingEnded, "v@:@");
7405 class_addMethod(delegateClass, sel_registerName("prepareForDragOperation:"), (IMP)prepareForDragOperation, "B@:@");
7406 class_addMethod(delegateClass, sel_registerName("performDragOperation:"), (IMP)performDragOperation, "B@:@");
7407
7408 id delegate = objc_msgSend_id(NSAlloc(delegateClass), sel_registerName("init"));
7409
7410 object_setInstanceVariable(delegate, "RGFW_window", win);
7411
7412 objc_msgSend_void_id(win->src.window, sel_registerName("setDelegate:"), delegate);
7413
7414 if (args & RGFW_ALLOW_DND) {
7415 win->_winArgs |= RGFW_ALLOW_DND;
7416
7417 NSPasteboardType types[] = {NSPasteboardTypeURL, NSPasteboardTypeFileURL, NSPasteboardTypeString};
7418 NSregisterForDraggedTypes(win->src.window, types, 3);
7419 }
7420
7421 // Show the window
7422 objc_msgSend_void_bool(NSApp, sel_registerName("activateIgnoringOtherApps:"), true);
7423 ((id(*)(id, SEL, SEL))objc_msgSend)(win->src.window, sel_registerName("makeKeyAndOrderFront:"), NULL);
7424 objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), true);
7425
7426 if (!RGFW_loaded) {
7427 objc_msgSend_void(win->src.window, sel_registerName("makeMainWindow"));
7428
7429 RGFW_loaded = 1;
7430 }
7431
7432 objc_msgSend_void(win->src.window, sel_registerName("makeKeyWindow"));
7433
7434 objc_msgSend_void(NSApp, sel_registerName("finishLaunching"));
7435
7436 if (RGFW_root == NULL)
7437 RGFW_root = win;
7438
7439 NSRetain(win->src.window);
7440 NSRetain(NSApp);
7441
7442 return win;
7443 }
7444
7445 void RGFW_window_setBorder(RGFW_window* win, u8 border) {
7446 NSBackingStoreType storeType = NSWindowStyleMaskBorderless;
7447 if (!border) {
7448 storeType = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable;
7449 }
7450 if (!(win->_winArgs & RGFW_NO_RESIZE)) {
7451 storeType |= NSWindowStyleMaskResizable;
7452 }
7453
7454 ((void (*)(id, SEL, NSBackingStoreType))objc_msgSend)(win->src.window, sel_registerName("setStyleMask:"), storeType);
7455
7456 objc_msgSend_void_bool(win->src.window, sel_registerName("setHasShadow:"), border);
7457 }
7458
7459 RGFW_area RGFW_getScreenSize(void) {
7460 static CGDirectDisplayID display = 0;
7461
7462 if (display == 0)
7463 display = CGMainDisplayID();
7464
7465 return RGFW_AREA(CGDisplayPixelsWide(display), CGDisplayPixelsHigh(display));
7466 }
7467
7468 RGFW_point RGFW_getGlobalMousePoint(void) {
7469 assert(RGFW_root != NULL);
7470
7471 CGEventRef e = CGEventCreate(NULL);
7472 CGPoint point = CGEventGetLocation(e);
7473 CFRelease(e);
7474
7475 return RGFW_POINT((u32) point.x, (u32) point.y); /*!< the point is loaded during event checks */
7476 }
7477
7478 RGFW_point RGFW_window_getMousePoint(RGFW_window* win) {
7479 NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(win->src.window, sel_registerName("mouseLocationOutsideOfEventStream"));
7480
7481 return RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y));
7482 }
7483
7484 u32 RGFW_keysPressed[10]; /*10 keys at a time*/
7485 typedef NS_ENUM(u32, NSEventType) { /* various types of events */
7486 NSEventTypeLeftMouseDown = 1,
7487 NSEventTypeLeftMouseUp = 2,
7488 NSEventTypeRightMouseDown = 3,
7489 NSEventTypeRightMouseUp = 4,
7490 NSEventTypeMouseMoved = 5,
7491 NSEventTypeLeftMouseDragged = 6,
7492 NSEventTypeRightMouseDragged = 7,
7493 NSEventTypeMouseEntered = 8,
7494 NSEventTypeMouseExited = 9,
7495 NSEventTypeKeyDown = 10,
7496 NSEventTypeKeyUp = 11,
7497 NSEventTypeFlagsChanged = 12,
7498 NSEventTypeAppKitDefined = 13,
7499 NSEventTypeSystemDefined = 14,
7500 NSEventTypeApplicationDefined = 15,
7501 NSEventTypePeriodic = 16,
7502 NSEventTypeCursorUpdate = 17,
7503 NSEventTypeScrollWheel = 22,
7504 NSEventTypeTabletPoint = 23,
7505 NSEventTypeTabletProximity = 24,
7506 NSEventTypeOtherMouseDown = 25,
7507 NSEventTypeOtherMouseUp = 26,
7508 NSEventTypeOtherMouseDragged = 27,
7509 /* The following event types are available on some hardware on 10.5.2 and later */
7510 NSEventTypeGesture API_AVAILABLE(macos(10.5)) = 29,
7511 NSEventTypeMagnify API_AVAILABLE(macos(10.5)) = 30,
7512 NSEventTypeSwipe API_AVAILABLE(macos(10.5)) = 31,
7513 NSEventTypeRotate API_AVAILABLE(macos(10.5)) = 18,
7514 NSEventTypeBeginGesture API_AVAILABLE(macos(10.5)) = 19,
7515 NSEventTypeEndGesture API_AVAILABLE(macos(10.5)) = 20,
7516
7517 NSEventTypeSmartMagnify API_AVAILABLE(macos(10.8)) = 32,
7518 NSEventTypeQuickLook API_AVAILABLE(macos(10.8)) = 33,
7519
7520 NSEventTypePressure API_AVAILABLE(macos(10.10.3)) = 34,
7521 NSEventTypeDirectTouch API_AVAILABLE(macos(10.10)) = 37,
7522
7523 NSEventTypeChangeMode API_AVAILABLE(macos(10.15)) = 38,
7524 };
7525
7526 typedef NS_ENUM(unsigned long long, NSEventMask) { /* masks for the types of events */
7527 NSEventMaskLeftMouseDown = 1ULL << NSEventTypeLeftMouseDown,
7528 NSEventMaskLeftMouseUp = 1ULL << NSEventTypeLeftMouseUp,
7529 NSEventMaskRightMouseDown = 1ULL << NSEventTypeRightMouseDown,
7530 NSEventMaskRightMouseUp = 1ULL << NSEventTypeRightMouseUp,
7531 NSEventMaskMouseMoved = 1ULL << NSEventTypeMouseMoved,
7532 NSEventMaskLeftMouseDragged = 1ULL << NSEventTypeLeftMouseDragged,
7533 NSEventMaskRightMouseDragged = 1ULL << NSEventTypeRightMouseDragged,
7534 NSEventMaskMouseEntered = 1ULL << NSEventTypeMouseEntered,
7535 NSEventMaskMouseExited = 1ULL << NSEventTypeMouseExited,
7536 NSEventMaskKeyDown = 1ULL << NSEventTypeKeyDown,
7537 NSEventMaskKeyUp = 1ULL << NSEventTypeKeyUp,
7538 NSEventMaskFlagsChanged = 1ULL << NSEventTypeFlagsChanged,
7539 NSEventMaskAppKitDefined = 1ULL << NSEventTypeAppKitDefined,
7540 NSEventMaskSystemDefined = 1ULL << NSEventTypeSystemDefined,
7541 NSEventMaskApplicationDefined = 1ULL << NSEventTypeApplicationDefined,
7542 NSEventMaskPeriodic = 1ULL << NSEventTypePeriodic,
7543 NSEventMaskCursorUpdate = 1ULL << NSEventTypeCursorUpdate,
7544 NSEventMaskScrollWheel = 1ULL << NSEventTypeScrollWheel,
7545 NSEventMaskTabletPoint = 1ULL << NSEventTypeTabletPoint,
7546 NSEventMaskTabletProximity = 1ULL << NSEventTypeTabletProximity,
7547 NSEventMaskOtherMouseDown = 1ULL << NSEventTypeOtherMouseDown,
7548 NSEventMaskOtherMouseUp = 1ULL << NSEventTypeOtherMouseUp,
7549 NSEventMaskOtherMouseDragged = 1ULL << NSEventTypeOtherMouseDragged,
7550 /* The following event masks are available on some hardware on 10.5.2 and later */
7551 NSEventMaskGesture API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeGesture,
7552 NSEventMaskMagnify API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeMagnify,
7553 NSEventMaskSwipe API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeSwipe,
7554 NSEventMaskRotate API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeRotate,
7555 NSEventMaskBeginGesture API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeBeginGesture,
7556 NSEventMaskEndGesture API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeEndGesture,
7557
7558 /* Note: You can only use these event masks on 64 bit. In other words, you cannot setup a local, nor global, event monitor for these event types on 32 bit. Also, you cannot search the event queue for them (nextEventMatchingMask:...) on 32 bit.
7559 */
7560 NSEventMaskSmartMagnify API_AVAILABLE(macos(10.8)) = 1ULL << NSEventTypeSmartMagnify,
7561 NSEventMaskPressure API_AVAILABLE(macos(10.10.3)) = 1ULL << NSEventTypePressure,
7562 NSEventMaskDirectTouch API_AVAILABLE(macos(10.12.2)) = 1ULL << NSEventTypeDirectTouch,
7563
7564 NSEventMaskChangeMode API_AVAILABLE(macos(10.15)) = 1ULL << NSEventTypeChangeMode,
7565
7566 NSEventMaskAny = ULONG_MAX,
7567
7568 };
7569
7570 typedef enum NSEventModifierFlags {
7571 NSEventModifierFlagCapsLock = 1 << 16,
7572 NSEventModifierFlagShift = 1 << 17,
7573 NSEventModifierFlagControl = 1 << 18,
7574 NSEventModifierFlagOption = 1 << 19,
7575 NSEventModifierFlagCommand = 1 << 20,
7576 NSEventModifierFlagNumericPad = 1 << 21
7577 } NSEventModifierFlags;
7578
7579 void RGFW_stopCheckEvents(void) {
7580 id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
7581 eventPool = objc_msgSend_id(eventPool, sel_registerName("init"));
7582
7583 NSEvent* e = (NSEvent*) ((id(*)(id, SEL, NSEventType, NSPoint, NSEventModifierFlags, void*, NSInteger, void**, short, NSInteger, NSInteger))objc_msgSend)
7584 (NSApp, sel_registerName("otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:"),
7585 NSEventTypeApplicationDefined, (NSPoint){0, 0}, 0, 0, 0, NULL, 0, 0, 0);
7586
7587 ((void (*)(id, SEL, id, bool))objc_msgSend)
7588 (NSApp, sel_registerName("postEvent:atStart:"), e, 1);
7589
7590 objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
7591 }
7592
7593 void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) {
7594 RGFW_UNUSED(win);
7595
7596 id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
7597 eventPool = objc_msgSend_id(eventPool, sel_registerName("init"));
7598
7599 void* date = (void*) ((id(*)(Class, SEL, double))objc_msgSend)
7600 (objc_getClass("NSDate"), sel_registerName("dateWithTimeIntervalSinceNow:"), waitMS);
7601
7602 NSEvent* e = (NSEvent*) ((id(*)(id, SEL, NSEventMask, void*, NSString*, bool))objc_msgSend)
7603 (NSApp, sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"),
7604 ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true);
7605
7606
7607 if (e) {
7608 objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e);
7609 }
7610
7611 objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
7612 }
7613
7614 RGFW_Event* RGFW_window_checkEvent(RGFW_window* win) {
7615 assert(win != NULL);
7616
7617 if (win->event.type == RGFW_quit)
7618 return NULL;
7619
7620 if ((win->event.type == RGFW_dnd || win->event.type == RGFW_dnd_init) && win->src.dndPassed == 0) {
7621 win->src.dndPassed = 1;
7622 return &win->event;
7623 }
7624
7625 id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
7626 eventPool = objc_msgSend_id(eventPool, sel_registerName("init"));
7627
7628 static void* eventFunc = NULL;
7629 if (eventFunc == NULL)
7630 eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:");
7631
7632 if ((win->event.type == RGFW_windowMoved || win->event.type == RGFW_windowResized || win->event.type == RGFW_windowRefresh) && win->event.keyCode != 120) {
7633 win->event.keyCode = 120;
7634 objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
7635 return &win->event;
7636 }
7637
7638 void* date = NULL;
7639
7640 NSEvent* e = (NSEvent*) ((id(*)(id, SEL, NSEventMask, void*, NSString*, bool))objc_msgSend)
7641 (NSApp, eventFunc, ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true);
7642
7643 if (e == NULL) {
7644 objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
7645 return NULL;
7646 }
7647
7648 if (objc_msgSend_id(e, sel_registerName("window")) != win->src.window) {
7649 ((void (*)(id, SEL, id, bool))objc_msgSend)
7650 (NSApp, sel_registerName("postEvent:atStart:"), e, 0);
7651
7652 objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
7653 return NULL;
7654 }
7655
7656 if (win->event.droppedFilesCount) {
7657 u32 i;
7658 for (i = 0; i < win->event.droppedFilesCount; i++)
7659 win->event.droppedFiles[i][0] = '\0';
7660 }
7661
7662 win->event.droppedFilesCount = 0;
7663 win->event.type = 0;
7664
7665 switch (objc_msgSend_uint(e, sel_registerName("type"))) {
7666 case NSEventTypeMouseEntered: {
7667 win->event.type = RGFW_mouseEnter;
7668 NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow"));
7669
7670 win->event.point = RGFW_POINT((i32) p.x, (i32) (win->r.h - p.y));
7671 RGFW_mouseNotifyCallBack(win, win->event.point, 1);
7672 break;
7673 }
7674
7675 case NSEventTypeMouseExited:
7676 win->event.type = RGFW_mouseLeave;
7677 RGFW_mouseNotifyCallBack(win, win->event.point, 0);
7678 break;
7679
7680 case NSEventTypeKeyDown: {
7681 u32 key = (u16) objc_msgSend_uint(e, sel_registerName("keyCode"));
7682 win->event.keyCode = RGFW_apiKeyCodeToRGFW(key);
7683 RGFW_keyboard[win->event.keyCode].prev = RGFW_keyboard[win->event.keyCode].current;
7684
7685 win->event.type = RGFW_keyPressed;
7686 char* str = (char*)(const char*) NSString_to_char(objc_msgSend_id(e, sel_registerName("characters")));
7687 strncpy(win->event.keyName, str, 16);
7688 win->event.repeat = RGFW_isPressed(win, win->event.keyCode);
7689 RGFW_keyboard[win->event.keyCode].current = 1;
7690
7691 RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, 1);
7692 break;
7693 }
7694
7695 case NSEventTypeKeyUp: {
7696 u32 key = (u16) objc_msgSend_uint(e, sel_registerName("keyCode"));
7697 win->event.keyCode = RGFW_apiKeyCodeToRGFW(key);;
7698
7699 RGFW_keyboard[win->event.keyCode].prev = RGFW_keyboard[win->event.keyCode].current;
7700
7701 win->event.type = RGFW_keyReleased;
7702 char* str = (char*)(const char*) NSString_to_char(objc_msgSend_id(e, sel_registerName("characters")));
7703 strncpy(win->event.keyName, str, 16);
7704
7705 RGFW_keyboard[win->event.keyCode].current = 0;
7706 RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, 0);
7707 break;
7708 }
7709
7710 case NSEventTypeFlagsChanged: {
7711 u32 flags = objc_msgSend_uint(e, sel_registerName("modifierFlags"));
7712 RGFW_updateLockState(win, ((u32)(flags & NSEventModifierFlagCapsLock) % 255), ((flags & NSEventModifierFlagNumericPad) % 255));
7713
7714 u8 i;
7715 for (i = 0; i < 9; i++)
7716 RGFW_keyboard[i + RGFW_CapsLock].prev = 0;
7717
7718 for (i = 0; i < 5; i++) {
7719 u32 shift = (1 << (i + 16));
7720 u32 key = i + RGFW_CapsLock;
7721
7722 if ((flags & shift) && !RGFW_wasPressed(win, key)) {
7723 RGFW_keyboard[key].current = 1;
7724
7725 if (key != RGFW_CapsLock)
7726 RGFW_keyboard[key+ 4].current = 1;
7727
7728 win->event.type = RGFW_keyPressed;
7729 win->event.keyCode = key;
7730 break;
7731 }
7732
7733 if (!(flags & shift) && RGFW_wasPressed(win, key)) {
7734 RGFW_keyboard[key].current = 0;
7735
7736 if (key != RGFW_CapsLock)
7737 RGFW_keyboard[key + 4].current = 0;
7738
7739 win->event.type = RGFW_keyReleased;
7740 win->event.keyCode = key;
7741 break;
7742 }
7743 }
7744
7745 RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, win->event.type == RGFW_keyPressed);
7746
7747 break;
7748 }
7749 case NSEventTypeLeftMouseDragged:
7750 case NSEventTypeOtherMouseDragged:
7751 case NSEventTypeRightMouseDragged:
7752 case NSEventTypeMouseMoved:
7753 win->event.type = RGFW_mousePosChanged;
7754 NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow"));
7755 win->event.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y));
7756
7757 if ((win->_winArgs & RGFW_HOLD_MOUSE)) {
7758 p.x = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaX"));
7759 p.y = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaY"));
7760
7761 win->event.point = RGFW_POINT((i32)p.x, (i32)p.y);
7762 }
7763
7764 RGFW_mousePosCallback(win, win->event.point);
7765 break;
7766
7767 case NSEventTypeLeftMouseDown:
7768 win->event.button = RGFW_mouseLeft;
7769 win->event.type = RGFW_mouseButtonPressed;
7770 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
7771 RGFW_mouseButtons[win->event.button].current = 1;
7772 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
7773 break;
7774
7775 case NSEventTypeOtherMouseDown:
7776 win->event.button = RGFW_mouseMiddle;
7777 win->event.type = RGFW_mouseButtonPressed;
7778 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
7779 RGFW_mouseButtons[win->event.button].current = 1;
7780 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
7781 break;
7782
7783 case NSEventTypeRightMouseDown:
7784 win->event.button = RGFW_mouseRight;
7785 win->event.type = RGFW_mouseButtonPressed;
7786 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
7787 RGFW_mouseButtons[win->event.button].current = 1;
7788 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
7789 break;
7790
7791 case NSEventTypeLeftMouseUp:
7792 win->event.button = RGFW_mouseLeft;
7793 win->event.type = RGFW_mouseButtonReleased;
7794 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
7795 RGFW_mouseButtons[win->event.button].current = 0;
7796 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0);
7797 break;
7798
7799 case NSEventTypeOtherMouseUp:
7800 win->event.button = RGFW_mouseMiddle;
7801 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
7802 RGFW_mouseButtons[win->event.button].current = 0;
7803 win->event.type = RGFW_mouseButtonReleased;
7804 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0);
7805 break;
7806
7807 case NSEventTypeRightMouseUp:
7808 win->event.button = RGFW_mouseRight;
7809 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
7810 RGFW_mouseButtons[win->event.button].current = 0;
7811 win->event.type = RGFW_mouseButtonReleased;
7812 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0);
7813 break;
7814
7815 case NSEventTypeScrollWheel: {
7816 double deltaY = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaY"));
7817
7818 if (deltaY > 0) {
7819 win->event.button = RGFW_mouseScrollUp;
7820 }
7821 else if (deltaY < 0) {
7822 win->event.button = RGFW_mouseScrollDown;
7823 }
7824
7825 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
7826 RGFW_mouseButtons[win->event.button].current = 1;
7827
7828 win->event.scroll = deltaY;
7829
7830 win->event.type = RGFW_mouseButtonPressed;
7831 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
7832 break;
7833 }
7834
7835 default:
7836 break;
7837 }
7838
7839 objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e);
7840 ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows"));
7841
7842 objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
7843 return &win->event;
7844 }
7845
7846
7847 void RGFW_window_move(RGFW_window* win, RGFW_point v) {
7848 assert(win != NULL);
7849
7850 win->r.x = v.x;
7851 win->r.y = v.y;
7852 ((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend)
7853 (win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{win->r.x, win->r.y}, {win->r.w, win->r.h}}, true, true);
7854 }
7855
7856 void RGFW_window_resize(RGFW_window* win, RGFW_area a) {
7857 assert(win != NULL);
7858
7859 win->r.w = a.w;
7860 win->r.h = a.h;
7861 ((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend)
7862 (win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{win->r.x, win->r.y}, {win->r.w, win->r.h}}, true, true);
7863 }
7864
7865 void RGFW_window_minimize(RGFW_window* win) {
7866 assert(win != NULL);
7867
7868 objc_msgSend_void_SEL(win->src.window, sel_registerName("performMiniaturize:"), NULL);
7869 }
7870
7871 void RGFW_window_restore(RGFW_window* win) {
7872 assert(win != NULL);
7873
7874 objc_msgSend_void_SEL(win->src.window, sel_registerName("deminiaturize:"), NULL);
7875 }
7876
7877 void RGFW_window_setName(RGFW_window* win, char* name) {
7878 assert(win != NULL);
7879
7880 NSString* str = NSString_stringWithUTF8String(name);
7881 objc_msgSend_void_id(win->src.window, sel_registerName("setTitle:"), str);
7882 }
7883
7884 #ifndef RGFW_NO_PASSTHROUGH
7885 void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough) {
7886 objc_msgSend_void_bool(win->src.window, sel_registerName("setIgnoresMouseEvents:"), passthrough);
7887 }
7888 #endif
7889
7890 void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) {
7891 if (a.w == 0 && a.h == 0)
7892 return;
7893
7894 ((void (*)(id, SEL, NSSize))objc_msgSend)
7895 (win->src.window, sel_registerName("setMinSize:"), (NSSize){a.w, a.h});
7896 }
7897
7898 void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) {
7899 if (a.w == 0 && a.h == 0)
7900 return;
7901
7902 ((void (*)(id, SEL, NSSize))objc_msgSend)
7903 (win->src.window, sel_registerName("setMaxSize:"), (NSSize){a.w, a.h});
7904 }
7905
7906 void RGFW_window_setIcon(RGFW_window* win, u8* data, RGFW_area area, i32 channels) {
7907 assert(win != NULL);
7908
7909 /* code by EimaMei */
7910 // Make a bitmap representation, then copy the loaded image into it.
7911 void* representation = NSBitmapImageRep_initWithBitmapData(NULL, area.w, area.h, 8, channels, (channels == 4), false, "NSCalibratedRGBColorSpace", 1 << 1, area.w * channels, 8 * channels);
7912 memcpy(NSBitmapImageRep_bitmapData(representation), data, area.w * area.h * channels);
7913
7914 // Add ze representation.
7915 void* dock_image = NSImage_initWithSize((NSSize){area.w, area.h});
7916 NSImage_addRepresentation(dock_image, (void*) representation);
7917
7918 // Finally, set the dock image to it.
7919 objc_msgSend_void_id(NSApp, sel_registerName("setApplicationIconImage:"), dock_image);
7920 // Free the garbage.
7921 release(dock_image);
7922 release(representation);
7923 }
7924
7925 NSCursor* NSCursor_arrowStr(char* str) {
7926 void* nclass = objc_getClass("NSCursor");
7927 void* func = sel_registerName(str);
7928 return (NSCursor*) objc_msgSend_id(nclass, func);
7929 }
7930
7931 void RGFW_window_setMouse(RGFW_window* win, u8* image, RGFW_area a, i32 channels) {
7932 assert(win != NULL);
7933
7934 if (image == NULL) {
7935 objc_msgSend_void(NSCursor_arrowStr("arrowCursor"), sel_registerName("set"));
7936 return;
7937 }
7938
7939 /* NOTE(EimaMei): Code by yours truly. */
7940 // Make a bitmap representation, then copy the loaded image into it.
7941 void* representation = NSBitmapImageRep_initWithBitmapData(NULL, a.w, a.h, 8, channels, (channels == 4), false, "NSCalibratedRGBColorSpace", 1 << 1, a.w * channels, 8 * channels);
7942 memcpy(NSBitmapImageRep_bitmapData(representation), image, a.w * a.h * channels);
7943
7944 // Add ze representation.
7945 void* cursor_image = NSImage_initWithSize((NSSize){a.w, a.h});
7946 NSImage_addRepresentation(cursor_image, representation);
7947
7948 // Finally, set the cursor image.
7949 void* cursor = NSCursor_initWithImage(cursor_image, (NSPoint){0.0, 0.0});
7950
7951 objc_msgSend_void(cursor, sel_registerName("set"));
7952
7953 // Free the garbage.
7954 release(cursor_image);
7955 release(representation);
7956 }
7957
7958 void RGFW_window_setMouseDefault(RGFW_window* win) {
7959 RGFW_window_setMouseStandard(win, RGFW_MOUSE_ARROW);
7960 }
7961
7962 void RGFW_window_showMouse(RGFW_window* win, i8 show) {
7963 RGFW_UNUSED(win);
7964
7965 if (show) {
7966 CGDisplayShowCursor(kCGDirectMainDisplay);
7967 }
7968 else {
7969 CGDisplayHideCursor(kCGDirectMainDisplay);
7970 }
7971 }
7972
7973 void RGFW_window_setMouseStandard(RGFW_window* win, u8 stdMouses) {
7974 if (stdMouses > ((sizeof(RGFW_mouseIconSrc)) / (sizeof(char*))))
7975 return;
7976
7977 char* mouseStr = RGFW_mouseIconSrc[stdMouses];
7978 void* mouse = NSCursor_arrowStr(mouseStr);
7979
7980 if (mouse == NULL)
7981 return;
7982
7983 RGFW_UNUSED(win);
7984 CGDisplayShowCursor(kCGDirectMainDisplay);
7985 objc_msgSend_void(mouse, sel_registerName("set"));
7986 }
7987
7988 void RGFW_releaseCursor(RGFW_window* win) {
7989 RGFW_UNUSED(win);
7990 CGAssociateMouseAndMouseCursorPosition(1);
7991 }
7992
7993 void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) {
7994 RGFW_UNUSED(win)
7995
7996 CGWarpMouseCursorPosition(CGPointMake(r.x + (r.w / 2), r.y + (r.h / 2)));
7997 CGAssociateMouseAndMouseCursorPosition(0);
7998 }
7999
8000 void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) {
8001 RGFW_UNUSED(win);
8002
8003 CGWarpMouseCursorPosition(CGPointMake(v.x, v.y));
8004 }
8005
8006
8007 void RGFW_window_hide(RGFW_window* win) {
8008 objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), false);
8009 }
8010
8011 void RGFW_window_show(RGFW_window* win) {
8012 ((id(*)(id, SEL, SEL))objc_msgSend)(win->src.window, sel_registerName("makeKeyAndOrderFront:"), NULL);
8013 objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), true);
8014 }
8015
8016 u8 RGFW_window_isFullscreen(RGFW_window* win) {
8017 assert(win != NULL);
8018
8019 NSWindowStyleMask mask = (NSWindowStyleMask) objc_msgSend_uint(win->src.window, sel_registerName("styleMask"));
8020 return (mask & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen;
8021 }
8022
8023 u8 RGFW_window_isHidden(RGFW_window* win) {
8024 assert(win != NULL);
8025
8026 bool visible = objc_msgSend_bool(win->src.window, sel_registerName("isVisible"));
8027 return visible == NO && !RGFW_window_isMinimized(win);
8028 }
8029
8030 u8 RGFW_window_isMinimized(RGFW_window* win) {
8031 assert(win != NULL);
8032
8033 return objc_msgSend_bool(win->src.window, sel_registerName("isMiniaturized")) == YES;
8034 }
8035
8036 u8 RGFW_window_isMaximized(RGFW_window* win) {
8037 assert(win != NULL);
8038
8039 return objc_msgSend_bool(win->src.window, sel_registerName("isZoomed"));
8040 }
8041
8042 static RGFW_monitor RGFW_NSCreateMonitor(CGDirectDisplayID display) {
8043 RGFW_monitor monitor;
8044
8045 CGRect bounds = CGDisplayBounds(display);
8046 monitor.rect = RGFW_RECT((int) bounds.origin.x, (int) bounds.origin.y, (int) bounds.size.width, (int) bounds.size.height);
8047
8048 CGSize screenSizeMM = CGDisplayScreenSize(display);
8049 monitor.physW = screenSizeMM.width;
8050 monitor.physH = screenSizeMM.height;
8051
8052 monitor.scaleX = ((monitor.rect.w / (screenSizeMM.width / 25.4)) / 96) + 0.25;
8053 monitor.scaleY = ((monitor.rect.h / (screenSizeMM.height / 25.4)) / 96) + 0.25;
8054
8055 return monitor;
8056 }
8057
8058
8059 static RGFW_monitor RGFW_monitors[7];
8060
8061 RGFW_monitor* RGFW_getMonitors(void) {
8062 static CGDirectDisplayID displays[7];
8063 u32 count;
8064
8065 if (CGGetActiveDisplayList(6, displays, &count) != kCGErrorSuccess)
8066 return NULL;
8067
8068 for (u32 i = 0; i < count; i++)
8069 RGFW_monitors[i] = RGFW_NSCreateMonitor(displays[i]);
8070
8071 return RGFW_monitors;
8072 }
8073
8074 RGFW_monitor RGFW_getPrimaryMonitor(void) {
8075 CGDirectDisplayID primary = CGMainDisplayID();
8076 return RGFW_NSCreateMonitor(primary);
8077 }
8078
8079 RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) {
8080 return RGFW_NSCreateMonitor(win->src.display);
8081 }
8082
8083 char* RGFW_readClipboard(size_t* size) {
8084 char* clip = (char*)NSPasteboard_stringForType(NSPasteboard_generalPasteboard(), NSPasteboardTypeString);
8085
8086 size_t clip_len = 1;
8087
8088 if (clip != NULL) {
8089 clip_len = strlen(clip) + 1;
8090 }
8091
8092 char* str = (char*)RGFW_MALLOC(sizeof(char) * clip_len);
8093
8094 if (clip != NULL) {
8095 strncpy(str, clip, clip_len);
8096 }
8097
8098 str[clip_len] = '\0';
8099
8100 if (size != NULL)
8101 *size = clip_len;
8102 return str;
8103 }
8104
8105 void RGFW_writeClipboard(const char* text, u32 textLen) {
8106 RGFW_UNUSED(textLen);
8107
8108 NSPasteboardType array[] = { NSPasteboardTypeString, NULL };
8109 NSPasteBoard_declareTypes(NSPasteboard_generalPasteboard(), array, 1, NULL);
8110
8111 NSPasteBoard_setString(NSPasteboard_generalPasteboard(), text, NSPasteboardTypeString);
8112 }
8113
8114 u16 RGFW_registerJoystick(RGFW_window* win, i32 jsNumber) {
8115 RGFW_UNUSED(jsNumber);
8116
8117 assert(win != NULL);
8118
8119 return RGFW_registerJoystickF(win, (char*) "");
8120 }
8121
8122 u16 RGFW_registerJoystickF(RGFW_window* win, char* file) {
8123 RGFW_UNUSED(file);
8124
8125 assert(win != NULL);
8126
8127 return RGFW_joystickCount - 1;
8128 }
8129
8130 #ifdef RGFW_OPENGL
8131 void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
8132 assert(win != NULL);
8133 objc_msgSend_void(win->src.ctx, sel_registerName("makeCurrentContext"));
8134 }
8135 #endif
8136
8137 #if !defined(RGFW_EGL)
8138 void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) {
8139 assert(win != NULL);
8140 #if defined(RGFW_OPENGL)
8141
8142 NSOpenGLContext_setValues(win->src.ctx, &swapInterval, 222);
8143 #else
8144 RGFW_UNUSED(swapInterval);
8145 #endif
8146 }
8147 #endif
8148
8149 // Function to create a CGImageRef from an array of bytes
8150 CGImageRef createImageFromBytes(unsigned char *buffer, int width, int height)
8151 {
8152 // Define color space
8153 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
8154 // Create bitmap context
8155 CGContextRef context = CGBitmapContextCreate(
8156 buffer,
8157 width, height,
8158 8,
8159 RGFW_bufferSize.w * 4,
8160 colorSpace,
8161 kCGImageAlphaPremultipliedLast);
8162 // Create image from bitmap context
8163 CGImageRef image = CGBitmapContextCreateImage(context);
8164 // Release the color space and context
8165 CGColorSpaceRelease(colorSpace);
8166 CGContextRelease(context);
8167
8168 return image;
8169 }
8170
8171 void RGFW_window_swapBuffers(RGFW_window* win) {
8172 assert(win != NULL);
8173 /* clear the window*/
8174
8175 if (!(win->_winArgs & RGFW_NO_CPU_RENDER)) {
8176#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
8177 #ifdef RGFW_OSMESA
8178 RGFW_OSMesa_reorganize();
8179 #endif
8180
8181 void* view = NSWindow_contentView(win->src.window);
8182 void* layer = objc_msgSend_id(view, sel_registerName("layer"));
8183
8184 ((void(*)(id, SEL, NSRect))objc_msgSend)(layer,
8185 sel_registerName("setFrame:"),
8186 (NSRect){{0, 0}, {win->r.w, win->r.h}});
8187
8188 CGImageRef image = createImageFromBytes(win->buffer, win->r.w, win->r.h);
8189 // Get the current graphics context
8190 id graphicsContext = objc_msgSend_class(objc_getClass("NSGraphicsContext"), sel_registerName("currentContext"));
8191 // Get the CGContext from the current NSGraphicsContext
8192 id cgContext = objc_msgSend_id(graphicsContext, sel_registerName("graphicsPort"));
8193 // Draw the image in the context
8194 NSRect bounds = (NSRect){{0,0}, {win->r.w, win->r.h}};
8195 CGContextDrawImage((void*)cgContext, *(CGRect*)&bounds, image);
8196 // Flush the graphics context to ensure the drawing is displayed
8197 objc_msgSend_id(graphicsContext, sel_registerName("flushGraphics"));
8198
8199 objc_msgSend_void_id(layer, sel_registerName("setContents:"), (id)image);
8200 objc_msgSend_id(layer, sel_registerName("setNeedsDisplay"));
8201
8202 CGImageRelease(image);
8203#endif
8204 }
8205
8206 if (!(win->_winArgs & RGFW_NO_GPU_RENDER)) {
8207 #ifdef RGFW_EGL
8208 eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface);
8209 #elif defined(RGFW_OPENGL)
8210 objc_msgSend_void(win->src.ctx, sel_registerName("flushBuffer"));
8211 #endif
8212 }
8213 }
8214
8215 void RGFW_window_close(RGFW_window* win) {
8216 assert(win != NULL);
8217 release(win->src.view);
8218
8219#ifdef RGFW_ALLOC_DROPFILES
8220 {
8221 u32 i;
8222 for (i = 0; i < RGFW_MAX_DROPS; i++)
8223 RGFW_FREE(win->event.droppedFiles[i]);
8224
8225
8226 RGFW_FREE(win->event.droppedFiles);
8227 }
8228#endif
8229
8230#ifdef RGFW_BUFFER
8231 release(win->src.bitmap);
8232 release(win->src.image);
8233#endif
8234
8235 CVDisplayLinkStop(win->src.displayLink);
8236 CVDisplayLinkRelease(win->src.displayLink);
8237
8238 RGFW_FREE(win);
8239 }
8240
8241 u64 RGFW_getTimeNS(void) {
8242 static mach_timebase_info_data_t timebase_info;
8243 if (timebase_info.denom == 0) {
8244 mach_timebase_info(&timebase_info);
8245 }
8246 return mach_absolute_time() * timebase_info.numer / timebase_info.denom;
8247 }
8248
8249 u64 RGFW_getTime(void) {
8250 static mach_timebase_info_data_t timebase_info;
8251 if (timebase_info.denom == 0) {
8252 mach_timebase_info(&timebase_info);
8253 }
8254 return (double) mach_absolute_time() * (double) timebase_info.numer / ((double) timebase_info.denom * 1e9);
8255 }
8256#endif /* RGFW_MACOS */
8257
8258/*
8259 End of MaOS defines
8260*/
8261
8262/*
8263 WEBASM defines
8264*/
8265
8266#ifdef RGFW_WEBASM
8267RGFW_Event RGFW_events[20];
8268size_t RGFW_eventLen = 0;
8269
8270EM_BOOL Emscripten_on_keydown(int eventType, const EmscriptenKeyboardEvent* e, void* userData) {
8271 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
8272
8273 RGFW_events[RGFW_eventLen].type = RGFW_keyPressed;
8274 memcpy(RGFW_events[RGFW_eventLen].keyName, e->key, 16);
8275 RGFW_events[RGFW_eventLen].keyCode = RGFW_apiKeyCodeToRGFW(e->keyCode);
8276 RGFW_events[RGFW_eventLen].lockState = 0;
8277 RGFW_eventLen++;
8278
8279 RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].prev = RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].current;
8280 RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].current = 1;
8281 RGFW_keyCallback(RGFW_root, RGFW_apiKeyCodeToRGFW(e->keyCode), RGFW_events[RGFW_eventLen].keyName, 0, 1);
8282
8283 return EM_TRUE;
8284}
8285
8286EM_BOOL Emscripten_on_keyup(int eventType, const EmscriptenKeyboardEvent* e, void* userData) {
8287 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
8288
8289 RGFW_events[RGFW_eventLen].type = RGFW_keyReleased;
8290 memcpy(RGFW_events[RGFW_eventLen].keyName, e->key, 16);
8291 RGFW_events[RGFW_eventLen].keyCode = RGFW_apiKeyCodeToRGFW(e->keyCode);
8292 RGFW_events[RGFW_eventLen].lockState = 0;
8293 RGFW_eventLen++;
8294
8295 RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].prev = RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].current;
8296 RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].current = 0;
8297
8298 RGFW_keyCallback(RGFW_root, RGFW_apiKeyCodeToRGFW(e->keyCode), RGFW_events[RGFW_eventLen].keyName, 0, 0);
8299
8300 return EM_TRUE;
8301}
8302
8303EM_BOOL Emscripten_on_resize(int eventType, const EmscriptenUiEvent* e, void* userData) {
8304 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
8305
8306 RGFW_events[RGFW_eventLen].type = RGFW_windowResized;
8307 RGFW_eventLen++;
8308
8309 RGFW_windowResizeCallback(RGFW_root, RGFW_RECT(0, 0, e->windowInnerWidth, e->windowInnerHeight));
8310 return EM_TRUE;
8311}
8312
8313EM_BOOL Emscripten_on_fullscreenchange(int eventType, const EmscriptenFullscreenChangeEvent* e, void* userData) {
8314 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
8315
8316 RGFW_events[RGFW_eventLen].type = RGFW_windowResized;
8317 RGFW_eventLen++;
8318
8319 RGFW_root->r = RGFW_RECT(0, 0, e->elementWidth, e->elementHeight);
8320 RGFW_windowResizeCallback(RGFW_root, RGFW_root->r);
8321 return EM_TRUE;
8322}
8323
8324EM_BOOL Emscripten_on_focusin(int eventType, const EmscriptenFocusEvent* e, void* userData) {
8325 RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(e);
8326
8327 RGFW_events[RGFW_eventLen].type = RGFW_focusIn;
8328 RGFW_eventLen++;
8329
8330 RGFW_root->event.inFocus = 1;
8331 RGFW_focusCallback(RGFW_root, 1);
8332 return EM_TRUE;
8333}
8334
8335EM_BOOL Emscripten_on_focusout(int eventType, const EmscriptenFocusEvent* e, void* userData) {
8336 RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(e);
8337
8338 RGFW_events[RGFW_eventLen].type = RGFW_focusOut;
8339 RGFW_eventLen++;
8340
8341 RGFW_root->event.inFocus = 0;
8342 RGFW_focusCallback(RGFW_root, 0);
8343 return EM_TRUE;
8344}
8345
8346EM_BOOL Emscripten_on_mousemove(int eventType, const EmscriptenMouseEvent* e, void* userData) {
8347 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
8348
8349 RGFW_events[RGFW_eventLen].type = RGFW_mousePosChanged;
8350
8351 if ((RGFW_root->_winArgs & RGFW_HOLD_MOUSE)) {
8352 RGFW_point p = RGFW_POINT(e->movementX, e->movementY);
8353 RGFW_events[RGFW_eventLen].point = p;
8354 }
8355 else
8356 RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->targetX, e->targetY);
8357 RGFW_eventLen++;
8358
8359 RGFW_mousePosCallback(RGFW_root, RGFW_events[RGFW_eventLen].point);
8360 return EM_TRUE;
8361}
8362
8363EM_BOOL Emscripten_on_mousedown(int eventType, const EmscriptenMouseEvent* e, void* userData) {
8364 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
8365
8366 RGFW_events[RGFW_eventLen].type = RGFW_mouseButtonPressed;
8367 RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->targetX, e->targetY);
8368 RGFW_events[RGFW_eventLen].button = e->button + 1;
8369 RGFW_events[RGFW_eventLen].scroll = 0;
8370
8371 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].prev = RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current;
8372 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current = 1;
8373
8374 RGFW_mouseButtonCallback(RGFW_root, RGFW_events[RGFW_eventLen].button, RGFW_events[RGFW_eventLen].scroll, 1);
8375 RGFW_eventLen++;
8376
8377 return EM_TRUE;
8378}
8379
8380EM_BOOL Emscripten_on_mouseup(int eventType, const EmscriptenMouseEvent* e, void* userData) {
8381 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
8382
8383 RGFW_events[RGFW_eventLen].type = RGFW_mouseButtonReleased;
8384 RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->targetX, e->targetY);
8385 RGFW_events[RGFW_eventLen].button = e->button + 1;
8386 RGFW_events[RGFW_eventLen].scroll = 0;
8387
8388 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].prev = RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current;
8389 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current = 0;
8390
8391 RGFW_mouseButtonCallback(RGFW_root, RGFW_events[RGFW_eventLen].button, RGFW_events[RGFW_eventLen].scroll, 0);
8392 RGFW_eventLen++;
8393 return EM_TRUE;
8394}
8395
8396EM_BOOL Emscripten_on_wheel(int eventType, const EmscriptenWheelEvent* e, void* userData) {
8397 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
8398
8399 RGFW_events[RGFW_eventLen].type = RGFW_mouseButtonPressed;
8400 RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->mouse.targetX, e->mouse.targetY);
8401 RGFW_events[RGFW_eventLen].button = RGFW_mouseScrollUp + (e->deltaY < 0);
8402 RGFW_events[RGFW_eventLen].scroll = e->deltaY;
8403
8404 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].prev = RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current;
8405 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current = 1;
8406
8407 RGFW_mouseButtonCallback(RGFW_root, RGFW_events[RGFW_eventLen].button, RGFW_events[RGFW_eventLen].scroll, 1);
8408 RGFW_eventLen++;
8409
8410 return EM_TRUE;
8411}
8412
8413EM_BOOL Emscripten_on_touchstart(int eventType, const EmscriptenTouchEvent* e, void* userData) {
8414 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
8415
8416 size_t i;
8417 for (i = 0; i < (size_t)e->numTouches; i++) {
8418 RGFW_events[RGFW_eventLen].type = RGFW_mouseButtonPressed;
8419 RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->touches[i].targetX, e->touches[i].targetY);
8420 RGFW_events[RGFW_eventLen].button = 1;
8421 RGFW_events[RGFW_eventLen].scroll = 0;
8422
8423
8424 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].prev = RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current;
8425 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current = 1;
8426
8427 RGFW_mousePosCallback(RGFW_root, RGFW_events[RGFW_eventLen].point);
8428
8429 RGFW_mouseButtonCallback(RGFW_root, RGFW_events[RGFW_eventLen].button, RGFW_events[RGFW_eventLen].scroll, 1);
8430 RGFW_eventLen++;
8431 }
8432
8433 return EM_TRUE;
8434}
8435EM_BOOL Emscripten_on_touchmove(int eventType, const EmscriptenTouchEvent* e, void* userData) {
8436 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
8437
8438 size_t i;
8439 for (i = 0; i < (size_t)e->numTouches; i++) {
8440 RGFW_events[RGFW_eventLen].type = RGFW_mousePosChanged;
8441 RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->touches[i].targetX, e->touches[i].targetY);
8442
8443 RGFW_mousePosCallback(RGFW_root, RGFW_events[RGFW_eventLen].point);
8444 RGFW_eventLen++;
8445 }
8446 return EM_TRUE;
8447}
8448
8449EM_BOOL Emscripten_on_touchend(int eventType, const EmscriptenTouchEvent* e, void* userData) {
8450 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
8451
8452 size_t i;
8453 for (i = 0; i < (size_t)e->numTouches; i++) {
8454 RGFW_events[RGFW_eventLen].type = RGFW_mouseButtonReleased;
8455 RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->touches[i].targetX, e->touches[i].targetY);
8456 RGFW_events[RGFW_eventLen].button = 1;
8457 RGFW_events[RGFW_eventLen].scroll = 0;
8458
8459 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].prev = RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current;
8460 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current = 0;
8461
8462 RGFW_mouseButtonCallback(RGFW_root, RGFW_events[RGFW_eventLen].button, RGFW_events[RGFW_eventLen].scroll, 0);
8463 RGFW_eventLen++;
8464 }
8465 return EM_TRUE;
8466}
8467
8468EM_BOOL Emscripten_on_touchcancel(int eventType, const EmscriptenTouchEvent* e, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(e); return EM_TRUE; }
8469
8470EM_BOOL Emscripten_on_gamepad(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData) {
8471 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
8472
8473 if (gamepadEvent->index >= 4)
8474 return 0;
8475
8476 RGFW_joysticks[gamepadEvent->index] = gamepadEvent->connected;
8477
8478 return 1; // The event was consumed by the callback handler
8479}
8480
8481void EMSCRIPTEN_KEEPALIVE Emscripten_onDrop(size_t count) {
8482 if (!(RGFW_root->_winArgs & RGFW_ALLOW_DND))
8483 return;
8484
8485 RGFW_events[RGFW_eventLen].droppedFilesCount = count;
8486 RGFW_dndCallback(RGFW_root, RGFW_events[RGFW_eventLen].droppedFiles, count);
8487 RGFW_eventLen++;
8488}
8489
8490b8 RGFW_stopCheckEvents_bool = RGFW_FALSE;
8491void RGFW_stopCheckEvents(void) {
8492 RGFW_stopCheckEvents_bool = RGFW_TRUE;
8493}
8494
8495void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) {
8496 RGFW_UNUSED(win);
8497
8498 if (waitMS == 0)
8499 return;
8500
8501 u32 start = (u32)(((u64)RGFW_getTimeNS()) / 1e+6);
8502
8503 while ((RGFW_eventLen == 0) && RGFW_stopCheckEvents_bool == RGFW_FALSE &&
8504 (waitMS < 0 || (RGFW_getTimeNS() / 1e+6) - start < waitMS)
8505 ) {
8506 emscripten_sleep(0);
8507 }
8508
8509 RGFW_stopCheckEvents_bool = RGFW_FALSE;
8510}
8511
8512RGFWDEF void RGFW_init_buffer(RGFW_window* win);
8513void RGFW_init_buffer(RGFW_window* win) {
8514 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
8515 if (RGFW_bufferSize.w == 0 && RGFW_bufferSize.h == 0)
8516 RGFW_bufferSize = RGFW_getScreenSize();
8517
8518 win->buffer = RGFW_MALLOC(RGFW_bufferSize.w * RGFW_bufferSize.h * 4);
8519 #ifdef RGFW_OSMESA
8520 win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL);
8521 OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, win->r.w, win->r.h);
8522 #endif
8523 #else
8524 RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
8525 #endif
8526}
8527
8528void EMSCRIPTEN_KEEPALIVE RGFW_makeSetValue(size_t index, char* file) {
8529 /* This seems like a terrible idea, don't replicate this unless you hate yourself or the OS */
8530 /* TODO: find a better way to do this,
8531 strcpy doesn't seem to work, maybe because of asyncio
8532 */
8533
8534 RGFW_events[RGFW_eventLen].type = RGFW_dnd;
8535 char** arr = (char**)&RGFW_events[RGFW_eventLen].droppedFiles[index];
8536 *arr = file;
8537}
8538
8539#include <sys/stat.h>
8540#include <sys/types.h>
8541#include <errno.h>
8542
8543void EMSCRIPTEN_KEEPALIVE RGFW_mkdir(char* name) { mkdir(name, 0755); }
8544
8545void EMSCRIPTEN_KEEPALIVE RGFW_writeFile(const char *path, const char *data, size_t len) {
8546 FILE* file = fopen(path, "w+");
8547 if (file == NULL)
8548 return;
8549
8550 fwrite(data, sizeof(char), len, file);
8551 fclose(file);
8552}
8553
8554RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, u16 args) {
8555 RGFW_UNUSED(name)
8556
8557 RGFW_UNUSED(RGFW_initFormatAttribs);
8558
8559 RGFW_window* win = RGFW_window_basic_init(rect, args);
8560
8561#ifndef RGFW_WEBGPU
8562 EmscriptenWebGLContextAttributes attrs;
8563 attrs.alpha = EM_TRUE;
8564 attrs.depth = EM_TRUE;
8565 attrs.alpha = EM_TRUE;
8566 attrs.stencil = RGFW_STENCIL;
8567 attrs.antialias = RGFW_SAMPLES;
8568 attrs.premultipliedAlpha = EM_TRUE;
8569 attrs.preserveDrawingBuffer = EM_FALSE;
8570
8571 if (RGFW_DOUBLE_BUFFER == 0)
8572 attrs.renderViaOffscreenBackBuffer = 0;
8573 else
8574 attrs.renderViaOffscreenBackBuffer = RGFW_AUX_BUFFERS;
8575
8576 attrs.failIfMajorPerformanceCaveat = EM_FALSE;
8577 attrs.majorVersion = (RGFW_majorVersion == 0) ? 1 : RGFW_majorVersion;
8578 attrs.minorVersion = RGFW_minorVersion;
8579
8580 attrs.enableExtensionsByDefault = EM_TRUE;
8581 attrs.explicitSwapControl = EM_TRUE;
8582
8583 emscripten_webgl_init_context_attributes(&attrs);
8584 win->src.ctx = emscripten_webgl_create_context("#canvas", &attrs);
8585 emscripten_webgl_make_context_current(win->src.ctx);
8586
8587 #ifdef LEGACY_GL_EMULATION
8588 EM_ASM("Module.useWebGL = true; GLImmediate.init();");
8589 #endif
8590#else
8591 win->src.ctx = wgpuCreateInstance(NULL);
8592 win->src.device = emscripten_webgpu_get_device();
8593 win->src.queue = wgpuDeviceGetQueue(win->src.device);
8594#endif
8595
8596 emscripten_set_canvas_element_size("#canvas", rect.w, rect.h);
8597 emscripten_set_window_title(name);
8598
8599 /* load callbacks */
8600 emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_keydown);
8601 emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_keyup);
8602 emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_resize);
8603 emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, NULL, EM_FALSE, Emscripten_on_fullscreenchange);
8604 emscripten_set_mousemove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousemove);
8605 emscripten_set_touchstart_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchstart);
8606 emscripten_set_touchend_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchend);
8607 emscripten_set_touchmove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchmove);
8608 emscripten_set_touchcancel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchcancel);
8609 emscripten_set_mousedown_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousedown);
8610 emscripten_set_mouseup_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mouseup);
8611 emscripten_set_wheel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_wheel);
8612 emscripten_set_focusin_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusin);
8613 emscripten_set_focusout_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusout);
8614 emscripten_set_gamepadconnected_callback(NULL, 1, Emscripten_on_gamepad);
8615 emscripten_set_gamepaddisconnected_callback(NULL, 1, Emscripten_on_gamepad);
8616
8617 if (args & RGFW_ALLOW_DND) {
8618 win->_winArgs |= RGFW_ALLOW_DND;
8619 }
8620
8621 EM_ASM({
8622 var canvas = document.getElementById('canvas');
8623 canvas.addEventListener('drop', function(e) {
8624 e.preventDefault();
8625 if (e.dataTransfer.file < 0)
8626 return;
8627
8628 var filenamesArray = [];
8629 var count = e.dataTransfer.files.length;
8630
8631 /* Read and save the files to emscripten's files */
8632 var drop_dir = '.rgfw_dropped_files';
8633 Module._RGFW_mkdir(drop_dir);
8634
8635 for (var i = 0; i < count; i++) {
8636 var file = e.dataTransfer.files[i];
8637
8638 var path = '/' + drop_dir + '/' + file.name.replace("//", '_');
8639 var reader = new FileReader();
8640
8641 reader.onloadend = (e) => {
8642 if (reader.readyState != 2) {
8643 out('failed to read dropped file: '+file.name+': '+reader.error);
8644 }
8645 else {
8646 var data = e.target.result;
8647
8648 _RGFW_writeFile(path, new Uint8Array(data), file.size);
8649 }
8650 };
8651
8652 reader.readAsArrayBuffer(file);
8653 // This works weird on modern opengl
8654 var filename = stringToNewUTF8(path);
8655
8656 filenamesArray.push(filename);
8657
8658 Module._RGFW_makeSetValue(i, filename);
8659 }
8660
8661 Module._Emscripten_onDrop(count);
8662
8663 for (var i = 0; i < count; ++i) {
8664 _free(filenamesArray[i]);
8665 }
8666 }, true);
8667
8668 canvas.addEventListener('dragover', function(e) { e.preventDefault(); return false; }, true);
8669 });
8670
8671 RGFW_init_buffer(win);
8672 glViewport(0, 0, rect.w, rect.h);
8673
8674 RGFW_root = win;
8675
8676 if (args & RGFW_HIDE_MOUSE) {
8677 RGFW_window_showMouse(win, 0);
8678 }
8679
8680 if (args & RGFW_FULLSCREEN) {
8681 RGFW_window_resize(win, RGFW_getScreenSize());
8682 }
8683
8684 return win;
8685}
8686
8687RGFW_Event* RGFW_window_checkEvent(RGFW_window* win) {
8688 static u8 index = 0;
8689
8690 if (index == 0)
8691 RGFW_resetKey();
8692
8693 /* check gamepads */
8694 for (int i = 0; (i < emscripten_get_num_gamepads()) && (i < 4); i++) {
8695 if (RGFW_joysticks[i] == 0)
8696 continue;;
8697
8698 EmscriptenGamepadEvent gamepadState;
8699
8700 if (emscripten_get_gamepad_status(i, &gamepadState) != EMSCRIPTEN_RESULT_SUCCESS)
8701 break;
8702
8703 // Register buttons data for every connected gamepad
8704 for (int j = 0; (j < gamepadState.numButtons) && (j < 16); j++) {
8705 u32 map[] = {
8706 RGFW_JS_A, RGFW_JS_X, RGFW_JS_B, RGFW_JS_Y,
8707 RGFW_JS_L1, RGFW_JS_R1, RGFW_JS_L2, RGFW_JS_R2,
8708 RGFW_JS_SELECT, RGFW_JS_START,
8709 0, 0,
8710 RGFW_JS_UP, RGFW_JS_DOWN, RGFW_JS_LEFT, RGFW_JS_RIGHT
8711 };
8712
8713 u32 button = map[j];
8714 if (RGFW_jsPressed[i][button] != gamepadState.digitalButton[j]) {
8715 win->event.type = RGFW_jsButtonPressed;
8716 win->event.joystick = i;
8717 win->event.button = map[j];
8718 return &win->event;
8719 }
8720
8721 RGFW_jsPressed[i][button] = gamepadState.digitalButton[j];
8722 }
8723
8724 for (int j = 0; (j < gamepadState.numAxes) && (j < 4); j += 2) {
8725 win->event.axisesCount = gamepadState.numAxes;
8726 if (win->event.axis[j].x != gamepadState.axis[j] ||
8727 win->event.axis[j].y != gamepadState.axis[j + 1]
8728 ) {
8729 win->event.axis[j].x = gamepadState.axis[j];
8730 win->event.axis[j].y = gamepadState.axis[j + 1];
8731 win->event.type = RGFW_jsAxisMove;
8732 win->event.joystick = i;
8733 return &win->event;
8734 }
8735 }
8736 }
8737
8738 /* check queued events */
8739 if (RGFW_eventLen == 0)
8740 return NULL;
8741
8742 RGFW_events[index].frameTime = win->event.frameTime;
8743 RGFW_events[index].frameTime2 = win->event.frameTime2;
8744 RGFW_events[index].inFocus = win->event.inFocus;
8745
8746 win->event = RGFW_events[index];
8747
8748 RGFW_eventLen--;
8749
8750 if (RGFW_eventLen)
8751 index++;
8752 else
8753 index = 0;
8754
8755 return &win->event;
8756}
8757
8758void RGFW_window_resize(RGFW_window* win, RGFW_area a) {
8759 RGFW_UNUSED(win)
8760 emscripten_set_canvas_element_size("#canvas", a.w, a.h);
8761}
8762
8763/* NOTE: I don't know if this is possible */
8764void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) { RGFW_UNUSED(win); RGFW_UNUSED(v); }
8765/* this one might be possible but it looks iffy */
8766void RGFW_window_setMouse(RGFW_window* win, u8* image, RGFW_area a, i32 channels) { RGFW_UNUSED(win); RGFW_UNUSED(channels) RGFW_UNUSED(a) RGFW_UNUSED(image) }
8767
8768const char RGFW_CURSORS[11][12] = {
8769 "default",
8770 "default",
8771 "text",
8772 "crosshair",
8773 "pointer",
8774 "ew-resize",
8775 "ns-resize",
8776 "nwse-resize",
8777 "nesw-resize",
8778 "move",
8779 "not-allowed"
8780};
8781
8782void RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) {
8783 RGFW_UNUSED(win)
8784 EM_ASM( { document.getElementById("canvas").style.cursor = UTF8ToString($0); }, RGFW_CURSORS[mouse]);
8785}
8786
8787void RGFW_window_setMouseDefault(RGFW_window* win) {
8788 RGFW_window_setMouseStandard(win, RGFW_MOUSE_NORMAL);
8789}
8790
8791void RGFW_window_showMouse(RGFW_window* win, i8 show) {
8792 if (show)
8793 RGFW_window_setMouseDefault(win);
8794 else
8795 EM_ASM(document.getElementById('canvas').style.cursor = 'none';);
8796}
8797
8798RGFW_point RGFW_getGlobalMousePoint(void) {
8799 RGFW_point point;
8800 point.x = EM_ASM_INT({
8801 return window.mouseX || 0;
8802 });
8803 point.y = EM_ASM_INT({
8804 return window.mouseY || 0;
8805 });
8806 return point;
8807}
8808
8809RGFW_point RGFW_window_getMousePoint(RGFW_window* win) {
8810 RGFW_UNUSED(win);
8811
8812 EmscriptenMouseEvent mouseEvent;
8813 emscripten_get_mouse_status(&mouseEvent);
8814 return RGFW_POINT( mouseEvent.targetX, mouseEvent.targetY);
8815}
8816
8817void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough) {
8818 RGFW_UNUSED(win);
8819
8820 EM_ASM_({
8821 var canvas = document.getElementById('canvas');
8822 if ($0) {
8823 canvas.style.pointerEvents = 'none';
8824 } else {
8825 canvas.style.pointerEvents = 'auto';
8826 }
8827 }, passthrough);
8828}
8829
8830void RGFW_writeClipboard(const char* text, u32 textLen) {
8831 RGFW_UNUSED(textLen)
8832 EM_ASM({ navigator.clipboard.writeText(UTF8ToString($0)); }, text);
8833}
8834
8835
8836char* RGFW_readClipboard(size_t* size) {
8837 /*
8838 placeholder code for later
8839 I'm not sure if this is possible do the the async stuff
8840 */
8841
8842 if (size != NULL)
8843 *size = 0;
8844
8845 char* str = (char*)malloc(1);
8846 str[0] = '\0';
8847
8848 return str;
8849}
8850
8851void RGFW_window_swapBuffers(RGFW_window* win) {
8852 RGFW_UNUSED(win);
8853
8854 #ifdef RGFW_BUFFER
8855 if (!(win->_winArgs & RGFW_NO_CPU_RENDER)) {
8856 glEnable(GL_TEXTURE_2D);
8857
8858 GLuint texture;
8859 glGenTextures(1,&texture);
8860
8861 glBindTexture(GL_TEXTURE_2D,texture);
8862
8863 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
8864 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
8865 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
8866 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
8867
8868 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, RGFW_bufferSize.w, RGFW_bufferSize.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, win->buffer);
8869
8870 float ratioX = ((float)win->r.w / (float)RGFW_bufferSize.w);
8871 float ratioY = ((float)win->r.h / (float)RGFW_bufferSize.h);
8872
8873 // Set up the viewport
8874 glClear(GL_COLOR_BUFFER_BIT);
8875
8876 glBegin(GL_TRIANGLES);
8877 glTexCoord2f(0, ratioY); glColor3f(1, 1, 1); glVertex2f(-1, -1);
8878 glTexCoord2f(0, 0); glColor3f(1, 1, 1); glVertex2f(-1, 1);
8879 glTexCoord2f(ratioX, ratioY); glColor3f(1, 1, 1); glVertex2f(1, -1);
8880
8881 glTexCoord2f(ratioX, 0); glColor3f(1, 1, 1); glVertex2f(1, 1);
8882 glTexCoord2f(ratioX, ratioY); glColor3f(1, 1, 1); glVertex2f(1, -1);
8883 glTexCoord2f(0, 0); glColor3f(1, 1, 1); glVertex2f(-1, 1);
8884 glEnd();
8885
8886 glDeleteTextures(1, &texture);
8887 }
8888 #endif
8889
8890#ifndef RGFW_WEBGPU
8891 emscripten_webgl_commit_frame();
8892#endif
8893 emscripten_sleep(0);
8894}
8895
8896
8897void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
8898#ifndef RGFW_WEBGPU
8899 if (win == NULL)
8900 emscripten_webgl_make_context_current(0);
8901 else
8902 emscripten_webgl_make_context_current(win->src.ctx);
8903#endif
8904}
8905
8906#ifndef RGFW_EGL
8907void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { RGFW_UNUSED(win); RGFW_UNUSED(swapInterval); }
8908#endif
8909
8910void RGFW_window_close(RGFW_window* win) {
8911#ifndef RGFW_WEBGPU
8912 emscripten_webgl_destroy_context(win->src.ctx);
8913#endif
8914
8915 free(win);
8916}
8917
8918int RGFW_innerWidth(void) { return EM_ASM_INT({ return window.innerWidth; }); }
8919int RGFW_innerHeight(void) { return EM_ASM_INT({ return window.innerHeight; }); }
8920
8921RGFW_area RGFW_getScreenSize(void) {
8922 return RGFW_AREA(RGFW_innerWidth(), RGFW_innerHeight());
8923}
8924
8925void* RGFW_getProcAddress(const char* procname) {
8926 return emscripten_webgl_get_proc_address(procname);
8927}
8928
8929void RGFW_sleep(u64 milisecond) {
8930 emscripten_sleep(milisecond);
8931}
8932
8933u64 RGFW_getTimeNS(void) {
8934 return emscripten_get_now() * 1e+6;
8935}
8936
8937u64 RGFW_getTime(void) {
8938 return emscripten_get_now() * 1000;
8939}
8940
8941void RGFW_releaseCursor(RGFW_window* win) {
8942 RGFW_UNUSED(win);
8943 emscripten_exit_pointerlock();
8944}
8945
8946void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) {
8947 RGFW_UNUSED(win); RGFW_UNUSED(r);
8948
8949 emscripten_request_pointerlock("#canvas", 1);
8950}
8951
8952
8953void RGFW_window_setName(RGFW_window* win, char* name) {
8954 RGFW_UNUSED(win);
8955 emscripten_set_window_title(name);
8956}
8957
8958/* unsupported functions */
8959RGFW_monitor* RGFW_getMonitors(void) { return NULL; }
8960RGFW_monitor RGFW_getPrimaryMonitor(void) { return (RGFW_monitor){}; }
8961void RGFW_window_move(RGFW_window* win, RGFW_point v) { RGFW_UNUSED(win) RGFW_UNUSED(v) }
8962void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win) RGFW_UNUSED(a) }
8963void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win) RGFW_UNUSED(a) }
8964void RGFW_window_minimize(RGFW_window* win) { RGFW_UNUSED(win)}
8965void RGFW_window_restore(RGFW_window* win) { RGFW_UNUSED(win) }
8966void RGFW_window_setBorder(RGFW_window* win, b8 border) { RGFW_UNUSED(win) RGFW_UNUSED(border) }
8967void RGFW_window_setIcon(RGFW_window* win, u8* icon, RGFW_area a, i32 channels) { RGFW_UNUSED(win) RGFW_UNUSED(icon) RGFW_UNUSED(a) RGFW_UNUSED(channels) }
8968void RGFW_window_hide(RGFW_window* win) { RGFW_UNUSED(win) }
8969void RGFW_window_show(RGFW_window* win) {RGFW_UNUSED(win) }
8970b8 RGFW_window_isHidden(RGFW_window* win) { RGFW_UNUSED(win) return 0; }
8971b8 RGFW_window_isMinimized(RGFW_window* win) { RGFW_UNUSED(win) return 0; }
8972b8 RGFW_window_isMaximized(RGFW_window* win) { RGFW_UNUSED(win) return 0; }
8973RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { RGFW_UNUSED(win) return (RGFW_monitor){}; }
8974
8975#endif
8976
8977/* end of web asm defines */
8978
8979/* unix (macOS, linux, web asm) only stuff */
8980#if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WEBASM) || defined(RGFW_WAYLAND)
8981/* unix threading */
8982#ifndef RGFW_NO_THREADS
8983#include <pthread.h>
8984
8985 RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args) {
8986 RGFW_UNUSED(args);
8987
8988 RGFW_thread t;
8989 pthread_create((pthread_t*) &t, NULL, *ptr, NULL);
8990 return t;
8991 }
8992 void RGFW_cancelThread(RGFW_thread thread) { pthread_cancel((pthread_t) thread); }
8993 void RGFW_joinThread(RGFW_thread thread) { pthread_join((pthread_t) thread, NULL); }
8994#ifdef __linux__
8995 void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { pthread_setschedprio((pthread_t)thread, priority); }
8996#endif
8997#endif
8998
8999#ifndef RGFW_WEBASM
9000/* unix sleep */
9001 void RGFW_sleep(u64 ms) {
9002 struct timespec time;
9003 time.tv_sec = 0;
9004 time.tv_nsec = ms * 1e+6;
9005
9006 nanosleep(&time, NULL);
9007 }
9008#endif
9009
9010#endif /* end of unix / mac stuff*/
9011#endif /*RGFW_IMPLEMENTATION*/
9012
9013#if defined(__cplusplus) && !defined(__EMSCRIPTEN__)
9014}
9015#endif

Generated with cgit - Back to sebastiano.tronto.net