/* * * RGFW 1.8.0 pre-release * * Copyright (C) 2022-25 Riley Mabb (@ColleagueRiley) * * libpng license * * This software is provided 'as-is', without any express or implied warranty. * In no event will the authors be held liable for any damages arising from the * use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software in a * product, an acknowledgment in the product documentation would be appreciated * but is not required. 2. Altered source versions must be plainly marked as * such, and must not be misrepresented as being the original software. 3. This * notice may not be removed or altered from any source distribution. * * */ /* * (MAKE SURE RGFW_IMPLEMENTATION is in exactly one header or you use -D * RGFW_IMPLEMENTATION) #define RGFW_IMPLEMENTATION - makes it so source code * is included with header */ /* * #define RGFW_IMPLEMENTATION - (required) makes it so the source code is * included #define RGFW_DEBUG - (optional) makes it so RGFW prints debug * messages and errors when they're found #define RGFW_EGL - (optional) compile * with OpenGL functions, allowing you to use to use EGL instead of the native * OpenGL functions #define RGFW_DIRECTX - (optional) include integration * directX functions (windows only) #define RGFW_VULKAN - (optional) include * helpful vulkan integration functions and macros #define RGFW_WEBGPU - * (optional) use WebGPU for rendering #define RGFW_NATIVE - (optional) define * native RGFW types that use native API structures * * #define RGFW_X11 (optional) (unix only) if X11 should be used. This option * is turned on by default by unix systems except for MacOS #define * RGFW_WAYLAND (optional) (unix only) use Wayland. (This can be used with X11) * #define RGFW_NO_X11 (optional) (unix only) don't fallback to X11 when using * Wayland #define RGFW_NO_LOAD_WGL (optional) (windows only) if WGL should be * loaded dynamically during runtime #define RGFW_NO_X11_CURSOR (optional) * (unix only) don't use XCursor #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) #define RGFW_NO_X11_EXT_PRELOAD (optional) (unix only) use * Xext, but don't link it in code, (you'll have to link it with -lXext) * #define RGFW_NO_LOAD_WINMM (optional) (windows only) use winmm * (timeBeginPeriod), but don't link it in code, (you'll have to link it with * -lwinmm) #define RGFW_NO_WINMM (optional) (windows only) don't use winmm * #define RGFW_NO_IOKIT (optional) (macOS) don't use IOKit #define * RGFW_NO_UNIX_CLOCK (optional) (unix) don't link unix clock functions #define * RGFW_NO_DWM (windows only) - do not use or link dwmapi #define RGFW_USE_XDL * (optional) (X11) if XDL (XLib Dynamic Loader) should be used to load X11 * dynamically during runtime (must include XDL.h along with RGFW) #define * RGFW_COCOA_GRAPHICS_SWITCHING - (optional) (cocoa) use automatic graphics * switching (allow the system to choose to use GPU or iGPU) #define * RGFW_COCOA_FRAME_NAME (optional) (cocoa) set frame name #define RGFW_NO_DPI * - do not calculate DPI (no XRM nor libShcore included) #define * RGFW_ADVANCED_SMOOTH_RESIZE - use advanced methods for smooth resizing (may * result in a spike in memory usage or worse performance) (eg. WM_TIMER and * XSyncValue) #define RGFW_NO_INFO - do not define the RGFW_info struct * (without RGFW_IMPLEMENTATION) * * #define RGFW_ALLOC x - choose the default allocation function (defaults to * standard malloc) #define RGFW_FREE x - choose the default deallocation * function (defaults to standard free) #define RGFW_USERPTR x - choose the * default userptr sent to the malloc call, (NULL by default) * * #define RGFW_EXPORT - use when building RGFW #define RGFW_IMPORT - use when * linking with RGFW (not as a single-header) * * #define RGFW_USE_INT - force the use c-types rather than stdint.h (for * systems that might not have stdint.h (msvc)) #define RGFW_bool x - choose * what type to use for bool, by default u32 is used */ /* * Example to get you started : * * linux : gcc main.c -lX11 -lXrandr -lGL windows : gcc main.c -lopengl32 * -lgdi32 macos : gcc main.c -framework Cocoa -framework CoreVideo -framework * OpenGL -framework IOKit * * #define RGFW_IMPLEMENTATION #include "RGFW.h" * * u8 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}; * * int main() { RGFW_window* win = RGFW_createWindow("name", 100, 100, 500, * 500, (u64)0); RGFW_event event; * * RGFW_window_setExitKey(win, RGFW_escape); RGFW_window_setIcon(win, icon, 3, * 3, RGFW_formatRGBA8); * * while (RGFW_window_shouldClose(win) == RGFW_FALSE) { while * (RGFW_window_checkEvent(win, &event)) { if (event.type == RGFW_quit) break; * } } * * RGFW_window_close(win); } * * compiling : * * if you wish to compile the library all you have to do is create a new file * with this in it * * rgfw.c #define RGFW_IMPLEMENTATION #include "RGFW.h" * * You may also want to add `#define RGFW_EXPORT` when compiling and `#define * RGFW_IMPORT`when linking RGFW on it's own: this reduces inline functions and * prevents bloat in the object file * * then you can use gcc (or whatever compile you wish to use) to compile the * library into object file * * ex. gcc -c RGFW.c -fPIC * * after you compile the library into an object file, you can also turn the * object file into an static or shared library * * (commands ar and gcc can be replaced with whatever equivalent your system * uses) * * static : ar rcs RGFW.a RGFW.o shared : windows: gcc -shared RGFW.o * -lopengl32 -lgdi32 -o RGFW.dll linux: gcc -shared RGFW.o -lX11 -lGL -lXrandr * -o RGFW.so macos: gcc -shared RGFW.o -framework CoreVideo -framework Cocoa * -framework OpenGL -framework IOKit */ /* * Credits : EimaMei/Sacode : Code review, helped with X11, MacOS and Windows * support, Silicon, siliapp.h -> referencing * * stb : This project is heavily inspired by the stb single header files * * SDL, GLFW and other online resources : reference implementations * * contributors : (feel free to put yourself here if you contribute) krisvers * (@krisvers) -> code review EimaMei (@SaCode) -> code review Nycticebus * (@Code-Nycticebus) -> bug fixes Rob Rohan (@robrohan) -> X11 bugs and * missing features, MacOS/Cocoa fixing memory issues/bugs AICDG * (@THISISAGOODNAME) -> vulkan support (example) @Easymode -> support, * testing/debugging, bug fixes and reviews Joshua Rowe (omnisci3nce) - bug * fix, review (macOS) @lesleyrs -> bug fix, review (OpenGL) Nick Porcino * (@meshula) - testing, organization, review (MacOS, examples) * @therealmarrakesh -> documentation @DarekParodia -> code review (X11) (C++) * @NishiOwO -> fix BSD support, fix OSMesa example @BaynariKattu -> code * review and documentation Miguel Pinto (@konopimi) -> code review, fix vulkan * example @m-doescode -> code review (wayland) Robert Gonzalez (@uni-dos) -> * code review (wayland) @TheLastVoyager -> code review @yehoravramenko -> code * review (winapi) @halocupcake -> code review (OpenGL) @GideonSerf -> * documentation Alexandre Almeida (@M374LX) -> code review (keycodes) Vũ * Xuân Trường (@wanwanvxt) -> code review (winapi) Lucas * (@lightspeedlucas) -> code review (msvc++) Jeffery Myers (@JeffM2501) -> * code review (msvc) Zeni (@zenitsuyo) -> documentation TheYahton (@TheYahton) * -> documentation nonexistant_object (@DiarrheaMcgee */ #if _MSC_VER #pragma comment(lib, "gdi32") #pragma comment(lib, "shell32") #pragma comment(lib, "User32") #pragma warning( push ) #pragma warning( disable : 4996 4191 4127) #if _MSC_VER < 600 #define RGFW_C89 #endif #else #if defined(__STDC__) && !defined(__STDC_VERSION__) #define RGFW_C89 #endif #endif #if defined(RGFW_EGL) && !defined(RGFW_OPENGL) #define RGFW_OPENGL #endif /* these OS macros look better & are standardized */ /* plus it helps with cross-compiling */ #ifdef __EMSCRIPTEN__ #define RGFW_WASM #endif #if defined(RGFW_X11) && defined(__APPLE__) && !defined(RGFW_CUSTOM_BACKEND) #define RGFW_MACOS_X11 #define RGFW_UNIX #endif #if defined(_WIN32) && !defined(RGFW_X11) && !defined(RGFW_UNIX) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND) /* (if you're using X11 * on windows some how) */ #define RGFW_WINDOWS #endif #if defined(RGFW_WAYLAND) #define RGFW_DEBUG /* wayland will be in debug mode by default for * now */ #define RGFW_UNIX #ifdef RGFW_OPENGL #define RGFW_EGL #endif #ifdef RGFW_X11 #define RGFW_DYNAMIC #endif #endif #if (!defined(RGFW_WAYLAND) && !defined(RGFW_X11)) && (defined(__unix__) || defined(RGFW_MACOS_X11) || defined(RGFW_X11)) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND) #define RGFW_MACOS_X11 #define RGFW_X11 #define RGFW_UNIX #elif defined(__APPLE__) && !defined(RGFW_MACOS_X11) && !defined(RGFW_X11) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND) #define RGFW_MACOS #endif #if !defined(RGFW_SNPRINTF) && (defined(RGFW_X11) || defined(RGFW_WAYLAND)) /* required for X11 errors */ #include #define RGFW_SNPRINTF snprintf #endif #ifndef RGFW_USERPTR #define RGFW_USERPTR NULL #endif #ifndef RGFW_UNUSED #define RGFW_UNUSED(x) (void)(x) #endif #ifndef RGFW_ROUND #define RGFW_ROUND(x) (i32)((x) >= 0 ? (x) + 0.5f : (x) - 0.5f) #endif #ifndef RGFW_MIN #define RGFW_MIN(x, y) ((x < y) ? x : y) #endif #ifndef RGFW_ALLOC #include #define RGFW_ALLOC malloc #define RGFW_FREE free #endif #ifndef RGFW_ASSERT #include #define RGFW_ASSERT assert #endif #if !defined(RGFW_MEMCPY) || !defined(RGFW_STRNCMP) || !defined(RGFW_STRNCPY) || !defined(RGFW_MEMSET) #include #endif #ifndef RGFW_MEMSET #define RGFW_MEMSET(ptr, value, num) memset(ptr, value, num) #endif #ifndef RGFW_MEMCPY #define RGFW_MEMCPY(dist, src, len) memcpy(dist, src, len) #endif #ifndef RGFW_STRNCMP #define RGFW_STRNCMP(s1, s2, max) strncmp(s1, s2, max) #endif #ifndef RGFW_STRNCPY #define RGFW_STRNCPY(dist, src, len) strncpy(dist, src, len) #endif #ifndef RGFW_STRSTR #define RGFW_STRSTR(str, substr) strstr(str, substr) #endif #ifndef RGFW_STRTOL /* required for X11 XDnD and X11 Monitor DPI */ #include #define RGFW_STRTOL(str, endptr, base) strtol(str, endptr, base) #define RGFW_ATOF(num) atof(num) #endif #if !defined(RGFW_PRINTF) && ( defined(RGFW_DEBUG) || defined(RGFW_WAYLAND) ) /* required when using RGFW_DEBUG */ #include #define RGFW_PRINTF printf #endif #ifndef RGFW_MAX_PATH #define RGFW_MAX_PATH 260 /* max length of a path (for drag andn drop) */ #endif #ifndef RGFW_MAX_DROPS #define RGFW_MAX_DROPS 260 /* max items you can drop at once */ #endif #ifndef RGFW_MAX_EVENTS #define RGFW_MAX_EVENTS 32 #endif #ifndef RGFW_MAX_MONITORS #define RGFW_MAX_MONITORS 6 #endif #ifndef RGFW_COCOA_FRAME_NAME #define RGFW_COCOA_FRAME_NAME NULL #endif #ifdef RGFW_WIN95 /* for windows 95 testing (not that it really * works) */ #define RGFW_NO_MONITOR #define RGFW_NO_PASSTHROUGH #endif #if defined(RGFW_EXPORT) || defined(RGFW_IMPORT) #if defined(_WIN32) #if defined(__TINYC__) && (defined(RGFW_EXPORT) || defined(RGFW_IMPORT)) #define __declspec(x) __attribute__((x)) #endif #if defined(RGFW_EXPORT) #define RGFWDEF __declspec(dllexport) #else #define RGFWDEF __declspec(dllimport) #endif #else #if defined(RGFW_EXPORT) #define RGFWDEF __attribute__((visibility("default"))) #endif #endif #ifndef RGFWDEF #define RGFWDEF #endif #endif #ifndef RGFWDEF #ifdef RGFW_C89 #define RGFWDEF __inline #else #define RGFWDEF inline #endif #endif #if defined(__cplusplus) && !defined(__EMSCRIPTEN__) extern "C" { #endif /* makes sure the header file part is only defined once by default */ #ifndef RGFW_HEADER #define RGFW_HEADER #include "core/types.h" typedef ptrdiff_t RGFW_ssize_t; #ifndef RGFW_BOOL_DEFINED #define RGFW_BOOL_DEFINED typedef u8 RGFW_bool; #endif #define RGFW_BOOL(x) (RGFW_bool)((x) != 0) /* force a value to be 0 or 1 */ #define RGFW_TRUE (RGFW_bool)1 #define RGFW_FALSE (RGFW_bool)0 #define RGFW_ENUM(type, name) type name; enum #define RGFW_BIT(x) (1 << (x)) #ifdef RGFW_VULKAN #if defined(RGFW_WAYLAND) && defined(RGFW_X11) #define VK_USE_PLATFORM_WAYLAND_KHR #define VK_USE_PLATFORM_XLIB_KHR #define RGFW_VK_SURFACE ((RGFW_usingWayland()) ? ("VK_KHR_wayland_surface") : ("VK_KHR_xlib_surface")) #elif defined(RGFW_WAYLAND) #define VK_USE_PLATFORM_WAYLAND_KHR #define VK_USE_PLATFORM_XLIB_KHR #define RGFW_VK_SURFACE "VK_KHR_wayland_surface" #elif defined(RGFW_X11) #define VK_USE_PLATFORM_XLIB_KHR #define RGFW_VK_SURFACE "VK_KHR_xlib_surface" #elif defined(RGFW_WINDOWS) #define VK_USE_PLATFORM_WIN32_KHR #define OEMRESOURCE #define RGFW_VK_SURFACE "VK_KHR_win32_surface" #elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11) #define VK_USE_PLATFORM_MACOS_MVK #define RGFW_VK_SURFACE "VK_MVK_macos_surface" #else #define RGFW_VK_SURFACE NULL #endif #endif /* * ! @brief The stucture that contains information about the current * RGFW instance */ typedef struct RGFW_info RGFW_info; /* ! @brief The window stucture for interfacing with the window */ typedef struct RGFW_window RGFW_window; /* * ! @brief The source window stucture for interfacing with the * underlying windowing API (e.g. winapi, wayland, cocoa, etc) */ typedef struct RGFW_window_src RGFW_window_src; /* ! @brief The color format for pixel data */ typedef RGFW_ENUM(u8, RGFW_format) { RGFW_formatRGB8 = 0, /* !< 8-bit RGB (3 channels) */ RGFW_formatBGR8, /* !< 8-bit BGR (3 channels) */ RGFW_formatRGBA8, /* !< 8-bit RGBA (4 channels) */ RGFW_formatARGB8, /* !< 8-bit RGBA (4 channels) */ RGFW_formatBGRA8, /* !< 8-bit BGRA (4 channels) */ RGFW_formatABGR8, /* !< 8-bit BGRA (4 channels) */ RGFW_formatCount }; /* * ! @brief a stucture for interfacing with the underlying native image * (e.g. XImage, HBITMAP, etc) */ typedef struct RGFW_nativeImage RGFW_nativeImage; /* * ! @brief a stucture for interfacing with pixel data as a renderable * surface */ typedef struct RGFW_surface RGFW_surface; /* * ! a raw pointer to the underlying mouse handle for setting and * creating custom mouse icons */ typedef void RGFW_mouse; /* ! @brief RGFW's abstract keycodes */ typedef RGFW_ENUM(u8, RGFW_key) { RGFW_keyNULL = 0, RGFW_escape = '\033', RGFW_backtick = '`', RGFW_0 = '0', RGFW_1 = '1', RGFW_2 = '2', RGFW_3 = '3', RGFW_4 = '4', RGFW_5 = '5', RGFW_6 = '6', RGFW_7 = '7', RGFW_8 = '8', RGFW_9 = '9', RGFW_minus = '-', RGFW_equals = '=', RGFW_backSpace = '\b', RGFW_tab = '\t', RGFW_space = ' ', RGFW_a = 'a', RGFW_b = 'b', RGFW_c = 'c', RGFW_d = 'd', RGFW_e = 'e', RGFW_f = 'f', RGFW_g = 'g', RGFW_h = 'h', RGFW_i = 'i', RGFW_j = 'j', RGFW_k = 'k', RGFW_l = 'l', RGFW_m = 'm', RGFW_n = 'n', RGFW_o = 'o', RGFW_p = 'p', RGFW_q = 'q', RGFW_r = 'r', RGFW_s = 's', RGFW_t = 't', RGFW_u = 'u', RGFW_v = 'v', RGFW_w = 'w', RGFW_x = 'x', RGFW_y = 'y', RGFW_z = 'z', RGFW_period = '.', RGFW_comma = ',', RGFW_slash = '/', RGFW_bracket = '[', RGFW_closeBracket = ']', RGFW_semicolon = ';', RGFW_apostrophe = '\'', RGFW_backSlash = '\\', RGFW_return = '\n', RGFW_enter = RGFW_return, RGFW_delete = '\177', /* 127 */ RGFW_F1, RGFW_F2, RGFW_F3, RGFW_F4, RGFW_F5, RGFW_F6, RGFW_F7, RGFW_F8, RGFW_F9, RGFW_F10, RGFW_F11, RGFW_F12, RGFW_F13, RGFW_F14, RGFW_F15, RGFW_F16, RGFW_F17, RGFW_F18, RGFW_F19, RGFW_F20, RGFW_F21, RGFW_F22, RGFW_F23, RGFW_F24, RGFW_F25, RGFW_capsLock, RGFW_shiftL, RGFW_controlL, RGFW_altL, RGFW_superL, RGFW_shiftR, RGFW_controlR, RGFW_altR, RGFW_superR, RGFW_up, RGFW_down, RGFW_left, RGFW_right, RGFW_insert, RGFW_menu, RGFW_end, RGFW_home, RGFW_pageUp, RGFW_pageDown, RGFW_numLock, RGFW_kpSlash, RGFW_kpMultiply, RGFW_kpPlus, RGFW_kpMinus, RGFW_kpEqual, RGFW_kp1, RGFW_kp2, RGFW_kp3, RGFW_kp4, RGFW_kp5, RGFW_kp6, RGFW_kp7, RGFW_kp8, RGFW_kp9, RGFW_kp0, RGFW_kpPeriod, RGFW_kpReturn, RGFW_scrollLock, RGFW_printScreen, RGFW_pause, RGFW_world1, RGFW_world2, RGFW_keyLast = 256 /* padding for alignment ~(175 * by default) */ }; /* ! @brief abstract mouse button codes */ typedef RGFW_ENUM(u8, RGFW_mouseButton) { RGFW_mouseLeft = 0, /* !< left mouse button is pressed */ RGFW_mouseMiddle, /* !< mouse-wheel-button is * pressed */ RGFW_mouseRight, /* !< right mouse button is * pressed */ RGFW_mouseMisc1, RGFW_mouseMisc2, RGFW_mouseMisc3, RGFW_mouseMisc4, RGFW_mouseMisc5, RGFW_mouseFinal }; /* ! abstract key modifier codes */ typedef RGFW_ENUM(u8, RGFW_keymod) { RGFW_modCapsLock = RGFW_BIT(0), RGFW_modNumLock = RGFW_BIT(1), RGFW_modControl = RGFW_BIT(2), RGFW_modAlt = RGFW_BIT(3), RGFW_modShift = RGFW_BIT(4), RGFW_modSuper = RGFW_BIT(5), RGFW_modScrollLock = RGFW_BIT(6) }; /* ! @brief codes for the event types that can be sent */ typedef RGFW_ENUM(u8, RGFW_eventType) { RGFW_eventNone = 0, /* !< no event has been sent */ RGFW_keyPressed, /* a key has been pressed */ RGFW_keyReleased, /* !< a key has been released */ /* * ! key event note the code of the key pressed is stored in * RGFW_event.key.value !!Keycodes defined at the bottom of the * RGFW_HEADER part of this file!! * * while a string version is stored in * RGFW_event.key.valueString * * RGFW_event.key.mod holds the current mod this means if * CapsLock, NumLock are active or not */ RGFW_mouseButtonPressed, /* !< a mouse button has * been pressed * (left,middle,right) */ RGFW_mouseButtonReleased, /* !< a mouse button has * been released * (left,middle,right) */ RGFW_mouseScroll, /* !< a mouse scroll event */ RGFW_mousePosChanged, /* !< the position of the mouse * has been changed */ /* * ! mouse event note the x and y of the mouse can be found in * the vector, RGFW_x, y * * RGFW_event.button.value holds which mouse button was pressed */ RGFW_windowMoved, /* !< the window was moved (by * the user) */ RGFW_windowResized, /* !< the window was resized * (by the user), [on WASM this * means the browser was * resized] */ RGFW_focusIn, /* !< window is in focus now */ RGFW_focusOut, /* !< window is out of focus now */ RGFW_mouseEnter, /* mouse entered the window */ RGFW_mouseLeave, /* mouse left the window */ RGFW_windowRefresh, /* The window content needs to * be refreshed */ /* * attribs change event note The event data is sent straight to * the window structure with win->x, win->y, win->w and win->h */ RGFW_quit, /* !< the user clicked the quit button */ RGFW_dataDrop, /* !< a file has been dropped into the * window */ RGFW_dataDrag, /* !< the start of a drag and drop * event, when the file is being * dragged */ /* * drop data note The x and y coords of the drop are stored in * the vector RGFW_x, y * * RGFW_event.drop.count holds how many files were dropped * * This is also the size of the array which stores all the * dropped file string, RGFW_event.drop.files */ RGFW_windowMaximized, /* !< the window was maximized */ RGFW_windowMinimized, /* !< the window was minimized */ RGFW_windowRestored, /* !< the window was restored */ RGFW_scaleUpdated /* !< content scale factor * changed */ }; /* * ! @brief flags for toggling wether or not an event should be * processed */ typedef RGFW_ENUM(u32, RGFW_eventFlag) { RGFW_keyPressedFlag = RGFW_BIT(RGFW_keyPressed), RGFW_keyReleasedFlag = RGFW_BIT(RGFW_keyReleased), RGFW_mouseScrollFlag = RGFW_BIT(RGFW_mouseScroll), RGFW_mouseButtonPressedFlag = RGFW_BIT(RGFW_mouseButtonPressed), RGFW_mouseButtonReleasedFlag = RGFW_BIT(RGFW_mouseButtonReleased), RGFW_mousePosChangedFlag = RGFW_BIT(RGFW_mousePosChanged), RGFW_mouseEnterFlag = RGFW_BIT(RGFW_mouseEnter), RGFW_mouseLeaveFlag = RGFW_BIT(RGFW_mouseLeave), RGFW_windowMovedFlag = RGFW_BIT(RGFW_windowMoved), RGFW_windowResizedFlag = RGFW_BIT(RGFW_windowResized), RGFW_focusInFlag = RGFW_BIT(RGFW_focusIn), RGFW_focusOutFlag = RGFW_BIT(RGFW_focusOut), RGFW_windowRefreshFlag = RGFW_BIT(RGFW_windowRefresh), RGFW_windowMaximizedFlag = RGFW_BIT(RGFW_windowMaximized), RGFW_windowMinimizedFlag = RGFW_BIT(RGFW_windowMinimized), RGFW_windowRestoredFlag = RGFW_BIT(RGFW_windowRestored), RGFW_scaleUpdatedFlag = RGFW_BIT(RGFW_scaleUpdated), RGFW_quitFlag = RGFW_BIT(RGFW_quit), RGFW_dataDropFlag = RGFW_BIT(RGFW_dataDrop), RGFW_dataDragFlag = RGFW_BIT(RGFW_dataDrag), RGFW_keyEventsFlag = RGFW_keyPressedFlag | RGFW_keyReleasedFlag, RGFW_mouseEventsFlag = RGFW_mouseButtonPressedFlag | RGFW_mouseButtonReleasedFlag | RGFW_mousePosChangedFlag | RGFW_mouseEnterFlag | RGFW_mouseLeaveFlag | RGFW_mouseScrollFlag, RGFW_windowEventsFlag = RGFW_windowMovedFlag | RGFW_windowResizedFlag | RGFW_windowRefreshFlag | RGFW_windowMaximizedFlag | RGFW_windowMinimizedFlag | RGFW_windowRestoredFlag | RGFW_scaleUpdatedFlag, RGFW_focusEventsFlag = RGFW_focusInFlag | RGFW_focusOutFlag, RGFW_dataDropEventsFlag = RGFW_dataDropFlag | RGFW_dataDragFlag, RGFW_allEventFlags = RGFW_keyEventsFlag | RGFW_mouseEventsFlag | RGFW_windowEventsFlag | RGFW_focusEventsFlag | RGFW_dataDropEventsFlag | RGFW_quitFlag }; /* ! Event structure(s) and union for checking/getting events */ /* ! @brief common event data across all events */ typedef struct RGFW_commonEvent { RGFW_eventType type; /* !< which event has been sent? */ RGFW_window *win; /* !< the window this event applies too * (for event queue events) */ } RGFW_commonEvent; /* ! @brief event data for any mouse button event (press/release) */ typedef struct RGFW_mouseButtonEvent { RGFW_eventType type; /* !< which event has been sent? */ RGFW_window *win; /* !< the window this event applies too * (for event queue events) */ u8 value; /* !< which mouse button was pressed */ } RGFW_mouseButtonEvent; /* ! @brief event data for any mouse scroll event */ typedef struct RGFW_mouseScrollEvent { RGFW_eventType type; /* !< which event has been sent? */ RGFW_window *win; /* !< the window this event applies too * (for event queue events) */ float x, y; /* !< the raw mouse scroll value */ } RGFW_mouseScrollEvent; /* * ! @brief event data for any mouse position event * (RGFW_mousePosChanged) */ typedef struct RGFW_mousePosEvent { RGFW_eventType type; /* !< which event has been sent? */ RGFW_window *win; /* !< the window this event applies too * (for event queue events) */ i32 x, y; /* !< mouse x, y of event (or drop point) */ float vecX, vecY; /* !< raw mouse movement */ } RGFW_mousePosEvent; /* ! @brief event data for any key event (press/release) */ typedef struct RGFW_keyEvent { RGFW_eventType type; /* !< which event has been sent? */ RGFW_window *win; /* !< the window this event applies too * (for event queue events) */ RGFW_key value; /* !< the physical key of the event, refers to * where key is physically !!Keycodes defined * at the bottom of the RGFW_HEADER part of * this file!! */ u8 sym; /* !< mapped key char of the event */ RGFW_bool repeat; /* !< key press event repeated (the key * is being held) */ RGFW_keymod mod; } RGFW_keyEvent; /* ! @brief event data for any data drop event */ typedef struct RGFW_dataDropEvent { RGFW_eventType type; /* !< which event has been sent? */ RGFW_window *win; /* !< the window this event applies too * (for event queue events) */ /* 260 max paths with a max length of 260 */ char **files; /* !< dropped files */ size_t count; /* !< how many files were dropped */ } RGFW_dataDropEvent; /* ! @brief event data for any data drag event */ typedef struct RGFW_dataDragEvent { RGFW_eventType type; /* !< which event has been sent? */ RGFW_window *win; /* !< the window this event applies too * (for event queue events) */ i32 x, y; /* !< mouse x, y of event (or drop point) */ } RGFW_dataDragEvent; /* ! @brief event data for when the window scale (DPI) is updated */ typedef struct RGFW_scaleUpdatedEvent { RGFW_eventType type; /* !< which event has been sent? */ RGFW_window *win; /* !< the window this event applies too * (for event queue events) */ float x, y; /* !< DPI scaling */ } RGFW_scaleUpdatedEvent; /* ! @brief union for all of the event stucture types */ typedef union RGFW_event { RGFW_eventType type; /* !< which event has been sent? */ RGFW_commonEvent common; /* !< common event data (e.g.) * type and win */ RGFW_mouseButtonEvent button; /* !< data for a button * press/release */ RGFW_mouseScrollEvent scroll; /* !< data for a mouse scroll */ RGFW_mousePosEvent mouse; /* !< data for mouse motion * events */ RGFW_keyEvent key; /* !< data for key press/release/hold * events */ RGFW_dataDropEvent drop; /* !< dropping a file events */ RGFW_dataDragEvent drag; /* data for dragging a file * events */ RGFW_scaleUpdatedEvent scale; /* data for monitor scaling * events */ } RGFW_event; /* * ! @!brief codes for for RGFW_the code is stupid and C++ waitForEvent * waitMS -> Allows the function to keep checking for events even after * there are no more events if waitMS == 0, the loop will not wait for * events if waitMS > 0, the loop will wait that many miliseconds after * there are no more events until it returns if waitMS == -1 or waitMS * == the max size of an unsigned 32-bit int, the loop will not return * until it gets another event */ typedef RGFW_ENUM(i32, RGFW_eventWait) { RGFW_eventNoWait = 0, RGFW_eventWaitNext = -1 }; /* * ! @brief optional bitwise arguments for making a windows, these can * be OR'd together */ typedef RGFW_ENUM(u32, RGFW_windowFlags) { RGFW_windowNoBorder = RGFW_BIT(0), /* !< the window doesn't * have a border */ RGFW_windowNoResize = RGFW_BIT(1), /* !< the window cannot * be resized by the * user */ RGFW_windowAllowDND = RGFW_BIT(2), /* !< the window * supports drag and * drop */ RGFW_windowHideMouse = RGFW_BIT(3), /* ! the window should * hide the mouse (can * be toggled later on * using * `RGFW_window_showMouse`) */ RGFW_windowFullscreen = RGFW_BIT(4), /* !< the window is * fullscreen by default */ RGFW_windowTransparent = RGFW_BIT(5), /* !< the window is * transparent (only * properly works on X11 * and MacOS, although * it's meant for for * windows) */ RGFW_windowCenter = RGFW_BIT(6), /* ! center the window * on the screen */ RGFW_windowScaleToMonitor = RGFW_BIT(8), /* ! scale the window to * the screen */ RGFW_windowHide = RGFW_BIT(9), /* ! the window is * hidden */ RGFW_windowMaximize = RGFW_BIT(10), /* !< maximize the * window on creation */ RGFW_windowCenterCursor = RGFW_BIT(11), /* !< center the cursor * to the window on * creation */ RGFW_windowFloating = RGFW_BIT(12), /* !< create a floating * window */ RGFW_windowFocusOnShow = RGFW_BIT(13), /* !< focus the window * when it's shown */ RGFW_windowMinimize = RGFW_BIT(14), /* !< focus the window * when it's shown */ RGFW_windowFocus = RGFW_BIT(15), /* !< if the window is * in focus */ RGFW_windowOpenGL = RGFW_BIT(17), /* !< create an OpenGL * context (you can also * do this manually with * RGFW_window_createContext_OpenGL) */ RGFW_windowEGL = RGFW_BIT(18), /* !< create an EGL * context (you can also * do this manually with * RGFW_window_createContext_EGL) */ RGFW_windowedFullscreen = RGFW_windowNoBorder | RGFW_windowMaximize }; /* ! @brief the types of icon to set */ typedef RGFW_ENUM(u8, RGFW_icon) { RGFW_iconTaskbar = RGFW_BIT(0), RGFW_iconWindow = RGFW_BIT(1), RGFW_iconBoth = RGFW_iconTaskbar | RGFW_iconWindow }; /* ! @brief standard mouse icons */ typedef RGFW_ENUM(u8, RGFW_mouseIcons) { RGFW_mouseNormal = 0, RGFW_mouseArrow, RGFW_mouseIbeam, RGFW_mouseCrosshair, RGFW_mousePointingHand, RGFW_mouseResizeEW, RGFW_mouseResizeNS, RGFW_mouseResizeNWSE, RGFW_mouseResizeNESW, RGFW_mouseResizeAll, RGFW_mouseNotAllowed, RGFW_mouseIconCount, RGFW_mouseIconFinal = 16 /* padding for alignment */ }; /* ! @brief the type of debug message */ typedef RGFW_ENUM(u8, RGFW_debugType) { RGFW_typeError = 0, RGFW_typeWarning, RGFW_typeInfo }; /* ! @brief error codes for known failure types */ typedef RGFW_ENUM(u8, RGFW_errorCode) { RGFW_noError = 0, /* !< no error */ RGFW_errOutOfMemory, RGFW_errOpenGLContext, RGFW_errEGLContext, /* !< error with the * OpenGL context */ RGFW_errWayland, RGFW_errX11, RGFW_errDirectXContext, RGFW_errIOKit, RGFW_errClipboard, RGFW_errFailedFuncLoad, RGFW_errBuffer, RGFW_errEventQueue, RGFW_infoMonitor, RGFW_infoWindow, RGFW_infoBuffer, RGFW_infoGlobal, RGFW_infoOpenGL, RGFW_warningWayland, RGFW_warningOpenGL }; /* ! @brief callback function type for debug messags */ typedef void (*RGFW_debugfunc) (RGFW_debugType type, RGFW_errorCode err, const char *msg); /* ! @brief RGFW_windowMoved, the window and its new rect value */ typedef void (*RGFW_windowMovedfunc) (RGFW_window * win, i32 x, i32 y); /* ! @brief RGFW_windowResized, the window and its new rect value */ typedef void (*RGFW_windowResizedfunc) (RGFW_window * win, i32 w, i32 h); /* ! @brief RGFW_windowRestored, the window and its new rect value */ typedef void (*RGFW_windowRestoredfunc) (RGFW_window * win, i32 x, i32 y, i32 w, i32 h); /* ! @brief RGFW_windowMaximized, the window and its new rect value */ typedef void (*RGFW_windowMaximizedfunc) (RGFW_window * win, i32 x, i32 y, i32 w, i32 h); /* ! @brief RGFW_windowMinimized, the window and its new rect value */ typedef void (*RGFW_windowMinimizedfunc) (RGFW_window * win); /* ! @brief RGFW_quit, the window that was closed */ typedef void (*RGFW_windowQuitfunc) (RGFW_window * win); /* * ! @brief RGFW_focusIn / RGFW_focusOut, the window who's focus has * changed and if its in focus */ typedef void (*RGFW_focusfunc) (RGFW_window * win, RGFW_bool inFocus); /* * ! @brief RGFW_mouseEnter / RGFW_mouseLeave, the window that changed, * the point of the mouse (enter only) and if the mouse has entered */ typedef void (*RGFW_mouseNotifyfunc) (RGFW_window * win, i32 x, i32 y, RGFW_bool status); /* * ! @brief RGFW_mousePosChanged, the window that the move happened on, * and the new point of the mouse */ typedef void (*RGFW_mousePosfunc) (RGFW_window * win, i32 x, i32 y, float vecX, float vecY); /* * ! @brief RGFW_dataDrag, the window, the point of the drop on the * windows */ typedef void (*RGFW_dataDragfunc) (RGFW_window * win, i32 x, i32 y); /* ! @brief RGFW_windowRefresh, the window that needs to be refreshed */ typedef void (*RGFW_windowRefreshfunc) (RGFW_window * win); /* * ! @brief RGFW_keyPressed / RGFW_keyReleased, the window that got the * event, the mapped key, the physical key, the string version, the * state of the mod keys, if it was a press (else it's a release) */ typedef void (*RGFW_keyfunc) (RGFW_window * win, u8 key, u8 sym, RGFW_keymod mod, RGFW_bool repeat, RGFW_bool pressed); /* * ! @brief RGFW_mouseButtonPressed / RGFW_mouseButtonReleased, the * window that got the event, the button that was pressed, the scroll * value, if it was a press (else it's a release) */ typedef void (*RGFW_mouseButtonfunc) (RGFW_window * win, RGFW_mouseButton button, RGFW_bool pressed); /* * ! @brief RGFW_mouseScroll, the window that got the event, the x * scroll value, the y scroll value */ typedef void (*RGFW_mouseScrollfunc) (RGFW_window * win, float x, float y); /* * ! @brief RGFW_dataDrop the window that had the drop, the drop data * and the number of files dropped */ typedef void (*RGFW_dataDropfunc) (RGFW_window * win, char **files, size_t count); /* * ! @brief RGFW_scaleUpdated, the window the event was sent to, * content scaleX, content scaleY */ typedef void (*RGFW_scaleUpdatedfunc) (RGFW_window * win, float scaleX, float scaleY); /* ! @brief function pointer equivalent of void* */ typedef void (*RGFW_proc) (void); #ifndef RGFW_NO_MONITOR /* * ! @brief monitor mode data | can be changed by the user (with * functions) */ typedef struct RGFW_monitorMode { i32 w, h; /* !< monitor workarea size */ u32 refreshRate; /* !< monitor refresh rate */ u8 red, blue, green; } RGFW_monitorMode; /* ! @brief structure for monitor data */ typedef struct RGFW_monitor { i32 x, y; /* !< x - y of the monitor workarea */ char name[128]; /* !< monitor name */ float scaleX, scaleY; /* !< monitor content scale */ float pixelRatio; /* !< pixel ratio for monitor (1.0 for * regular, 2.0 for hiDPI) */ float physW, physH; /* !< monitor physical size in inches */ RGFW_monitorMode mode; } RGFW_monitor; /* ! @brief what type of request you are making for the monitor */ typedef RGFW_ENUM(u8, RGFW_modeRequest) { RGFW_monitorScale = RGFW_BIT(0), /* !< scale the monitor * size */ RGFW_monitorRefresh = RGFW_BIT(1), /* !< change the refresh * rate */ RGFW_monitorRGB = RGFW_BIT(2), /* !< change the monitor * RGB bits size */ RGFW_monitorAll = RGFW_monitorScale | RGFW_monitorRefresh | RGFW_monitorRGB }; #endif #if defined(RGFW_OPENGL) /* * ! @brief abstract structure for interfacing with the underlying * OpenGL API */ typedef struct RGFW_glContext RGFW_glContext; /* * ! @brief abstract structure for interfacing with the underlying EGL * API */ typedef struct RGFW_eglContext RGFW_eglContext; /* ! values for the releaseBehavior hint */ typedef RGFW_ENUM(i32, RGFW_glReleaseBehavior) { RGFW_glReleaseFlush = 0, /* !< flush the pipeline will * be flushed when the context * is release */ RGFW_glReleaseNone /* !< do nothing on release */ }; /* ! values for the profile hint */ typedef RGFW_ENUM(i32, RGFW_glProfile) { RGFW_glCore = 0, /* !< the core OpenGL version, e.g. * just support for that version */ RGFW_glCompatibility, /* !< allow compatibility for * older versions of RGFW as * well as the requested * version */ RGFW_glES /* !< use OpenGL ES */ }; /* ! values for the renderer hint */ typedef RGFW_ENUM(i32, RGFW_glRenderer) { RGFW_glAccelerated = 0, /* !< hardware accelerated (GPU) */ RGFW_glSoftware /* !< software rendered (CPU) */ }; /* ! OpenGL initalization hints */ typedef struct RGFW_glHints { i32 stencil; /* !< set stencil buffer bit size (0 by * default) */ i32 samples; /* !< set number of sample buffers (0 by * default) */ i32 stereo; /* !< hint the context to use stereoscopic * frame buffers for 3D (false by default) */ i32 auxBuffers; /* !< number of aux buffers (0 by default) */ i32 doubleBuffer; /* !< request double buffering (true by * default) */ i32 red, green, blue, alpha; /* !< set color bit sizes (all * 8 by default) */ i32 depth; /* !< set depth buffer bit size (24 by default) */ i32 accumRed, accumGreen, accumBlue, accumAlpha; /* !< set accumulated * RGBA bit sizes (all 0 * by default) */ RGFW_bool sRGB; /* !< request sRGA format (false by default) */ RGFW_bool robustness; /* !< request a "robust" (as in * memory-safe) context (false by * default). For more information check * the overview section: * https://registry.khronos.org/OpenGL/extensions/EXT/EXT_robustness.txt */ RGFW_bool debug; /* !< request OpenGL debugging (false * by default). */ RGFW_bool noError; /* !< request no OpenGL errors (false * by default). This causes OpenGL * errors to be undefined behavior. For * more information check the overview * section: * https://registry.khronos.org/OpenGL/extensions/KHR/KHR_no_error.txt */ RGFW_glReleaseBehavior releaseBehavior; /* !< hint how the * OpenGL driver should * behave when changing * contexts * (RGFW_glReleaseNone * by default). For more * information check the * overview section: * https://registry.khronos.org/OpenGL/extensions/KHR/KHR_context_flush_control.txt */ RGFW_glProfile profile; /* !< set OpenGL API profile * (RGFW_glCore by default) */ i32 major, minor; /* !< set the OpenGL API profile * version (by default RGFW_glMajor is * 1, RGFW_glMinor is 0) */ RGFW_glContext *share; /* !< Share this OpenGL context with * newly created OpenGL contexts; * defaults to NULL. */ RGFW_eglContext *shareEGL; /* !< Share this EGL context * with newly created OpenGL * contexts; defaults to NULL. */ RGFW_glRenderer renderer; /* !< renderer to use e.g. * accelerated or software * defaults to accelerated */ } RGFW_glHints; #endif /**! * @brief Allocates memory using the allocator defined by RGFW_ALLOC at compile time. * @param size The size (in bytes) of the memory block to allocate. * @return A pointer to the allocated memory block. */ RGFWDEF void *RGFW_alloc(size_t size); /**! * @brief Frees memory using the deallocator defined by RGFW_FREE at compile time. * @param ptr A pointer to the memory block to free. */ RGFWDEF void RGFW_free(void *ptr); /**! * @brief Returns the size (in bytes) of the RGFW_window structure. * @return The size of the RGFW_window structure. */ RGFWDEF size_t RGFW_sizeofWindow(void); /**! * @brief Returns the size (in bytes) of the RGFW_window_src structure. * @return The size of the RGFW_window_src structure. */ RGFWDEF size_t RGFW_sizeofWindowSrc(void); /**! * @brief (Unix) Toggles the use of Wayland. * This is enabled by default when compiled with `RGFW_WAYLAND`. * If not using `RGFW_WAYLAND`, Wayland functions are not exposed. * This function can be used to force the use of XWayland. * @param wayland A boolean value indicating whether to use Wayland (true) or not (false). */ RGFWDEF void RGFW_useWayland(RGFW_bool wayland); /**! * @brief Checks if Wayland is currently being used. * @return RGFW_TRUE if using Wayland, RGFW_FALSE otherwise. */ RGFWDEF RGFW_bool RGFW_usingWayland(void); /**! * @brief Retrieves the current Cocoa layer (macOS only). * @return A pointer to the Cocoa layer, or NULL if the platform is not in use. */ RGFWDEF void *RGFW_getLayer_OSX(void); /**! * @brief Retrieves the current X11 display connection. * @return A pointer to the X11 display, or NULL if the platform is not in use. */ RGFWDEF void *RGFW_getDisplay_X11(void); /**! * @brief Retrieves the current Wayland display connection. * @return A pointer to the Wayland display (`struct wl_display*`), or NULL if the platform is not in use. */ RGFWDEF struct wl_display *RGFW_getDisplay_Wayland(void); /**! * @brief Sets the class name for X11 and WinAPI windows. * Windows with the same class name will be grouped by the window manager. * By default, the class name matches the root window’s name. * @param name The class name to assign. */ RGFWDEF void RGFW_setClassName(const char *name); /**! * @brief Sets the X11 instance name. * By default, the window name will be used as the instance name. * @param name The X11 instance name to set. */ RGFWDEF void RGFW_setXInstName(const char *name); /**! * @brief (macOS only) Changes the current working directory to the application’s resource folder. */ RGFWDEF void RGFW_moveToMacOSResourceDir(void); /* ! copy image to another image, respecting each image's format */ RGFWDEF void RGFW_copyImageData(u8 * dest_data, i32 w, i32 h, RGFW_format dest_format, u8 * src_data, RGFW_format src_format); /**! * @brief Returns the size (in bytes) of the RGFW_nativeImage structure. * @return The size of the RGFW_nativeImage structure. */ RGFWDEF size_t RGFW_sizeofNativeImage(void); /**! * @brief Returns the size (in bytes) of the RGFW_surface structure. * @return The size of the RGFW_surface structure. */ RGFWDEF size_t RGFW_sizeofSurface(void); /**! * @brief Creates a new surface from raw pixel data. * @param data A pointer to the pixel data buffer. * @param w The width of the surface in pixels. * @param h The height of the surface in pixels. * @param format The pixel format of the data. * @return A pointer to the newly created RGFW_surface. * * NOTE: when you create a surface using RGFW_createSurface / ptr, on X11 it uses the root window's visual * this means it may fail to render on any other window if the visual does not match * RGFW_window_createSurface and RGFW_window_createSurfacePtr exist only for X11 to address this issues * Of course, you can also manually set the root window with RGFW_setRootWindow */ RGFWDEF RGFW_surface *RGFW_createSurface(u8 * data, i32 w, i32 h, RGFW_format format); /**! * @brief Creates a surface using a pre-allocated RGFW_surface structure. * @param data A pointer to the pixel data buffer. * @param w The width of the surface in pixels. * @param h The height of the surface in pixels. * @param format The pixel format of the data. * @param surface A pointer to a pre-allocated RGFW_surface structure. * @return RGFW_TRUE if successful, RGFW_FALSE otherwise. */ RGFWDEF RGFW_bool RGFW_createSurfacePtr(u8 * data, i32 w, i32 h, RGFW_format format, RGFW_surface * surface); /**! * @brief Retrieves the native image associated with a surface. * @param surface A pointer to the RGFW_surface. * @return A pointer to the native RGFW_nativeImage associated with the surface. */ RGFWDEF RGFW_nativeImage *RGFW_surface_getNativeImage(RGFW_surface * surface); /**! * @brief Frees the surface pointer and any buffers used for software rendering. * @param surface A pointer to the RGFW_surface to free. */ RGFWDEF void RGFW_surface_free(RGFW_surface * surface); /**! * @brief Frees only the internal buffers used for software rendering, leaving the surface struct intact. * @param surface A pointer to the RGFW_surface whose buffers should be freed. */ RGFWDEF void RGFW_surface_freePtr(RGFW_surface * surface); /**! * @brief Loads a mouse icon from bitmap data (similar to RGFW_window_setIcon). * @param data A pointer to the bitmap pixel data. * @param w The width of the mouse icon in pixels. * @param h The height of the mouse icon in pixels. * @param format The pixel format of the data. * @return A pointer to the newly loaded RGFW_mouse structure. * * @note The icon is not resized by default. */ RGFWDEF RGFW_mouse *RGFW_loadMouse(u8 * data, i32 w, i32 h, RGFW_format format); /**! * @brief Frees the data associated with an RGFW_mouse structure. * @param mouse A pointer to the RGFW_mouse to free. */ RGFWDEF void RGFW_freeMouse(RGFW_mouse * mouse); #ifndef RGFW_NO_MONITOR /**! * @brief Retrieves an array of all available monitors. * @param len [OUTPUT] A pointer to store the number of monitors found (maximum of 6). * @return A pointer to an array of RGFW_monitor structures. */ RGFWDEF RGFW_monitor *RGFW_getMonitors(size_t * len); /**! * @brief Retrieves the primary monitor. * @return The RGFW_monitor structure representing the primary monitor. */ RGFWDEF RGFW_monitor RGFW_getPrimaryMonitor(void); /**! * @brief Requests a specific display mode for a monitor. * @param mon The monitor to apply the mode change to. * @param mode The desired RGFW_monitorMode. * @param request The RGFW_modeRequest describing how to handle the mode change. * @return RGFW_TRUE if the mode was successfully applied, otherwise RGFW_FALSE. */ RGFWDEF RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request); /**! * @brief Compares two monitor modes to check if they are equivalent. * @param mon The first monitor mode. * @param mon2 The second monitor mode. * @param request The RGFW_modeRequest that defines the comparison parameters. * @return RGFW_TRUE if both modes are equivalent, otherwise RGFW_FALSE. */ RGFWDEF RGFW_bool RGFW_monitorModeCompare(RGFW_monitorMode mon, RGFW_monitorMode mon2, RGFW_modeRequest request); /**! * @brief Scales a monitor’s mode to match a window’s size. * @param mon The monitor to be scaled. * @param win The window whose size should be used as a reference. * @return RGFW_TRUE if the scaling was successful, otherwise RGFW_FALSE. */ RGFWDEF RGFW_bool RGFW_monitor_scaleToWindow(RGFW_monitor mon, struct RGFW_window *win); #endif /**! * @brief sleep until RGFW gets an event or the timer ends (defined by OS) * @param waitMS how long to wait for the next event (in miliseconds) */ RGFWDEF void RGFW_waitForEvent(i32 waitMS); /**! * @brief Set if events should be queued or not (enabled by default if the event queue is checked) * @param queue boolean value if RGFW should queue events or not */ RGFWDEF void RGFW_setQueueEvents(RGFW_bool queue); /**! * @brief check all the events until there are none left and updates window structure attributes */ RGFWDEF void RGFW_pollEvents(void); /**! * @brief check all the events until there are none left and updates window structure attributes * queues events if the queue is checked and/or requested */ RGFWDEF void RGFW_stopCheckEvents(void); /** * @defgroup Input * @{ */ /**! * @brief returns true if the key is pressed during the current frame * @param key the key code of the key you want to check * @return The boolean value if the key is pressed or not */ RGFWDEF RGFW_bool RGFW_isKeyPressed(RGFW_key key); /**! * @brief returns true if the key was released during the current frame * @param key the key code of the key you want to check * @return The boolean value if the key is released or not */ RGFWDEF RGFW_bool RGFW_isKeyReleased(RGFW_key key); /**! * @brief returns true if the key is down * @param key the key code of the key you want to check * @return The boolean value if the key is down or not */ RGFWDEF RGFW_bool RGFW_isKeyDown(RGFW_key key); /**! * @brief returns true if the mouse button is pressed during the current frame * @param button the mouse button code of the button you want to check * @return The boolean value if the button is pressed or not */ RGFWDEF RGFW_bool RGFW_isMousePressed(RGFW_mouseButton button); /**! * @brief returns true if the mouse button is released during the current frame * @param button the mouse button code of the button you want to check * @return The boolean value if the button is released or not */ RGFWDEF RGFW_bool RGFW_isMouseReleased(RGFW_mouseButton button); /**! * @brief returns true if the mouse button is down * @param button the mouse button code of the button you want to check * @return The boolean value if the button is down or not */ RGFWDEF RGFW_bool RGFW_isMouseDown(RGFW_mouseButton button); /**! * @brief outputs the current x, y position of the mouse * @param X [OUTPUT] a pointer for the output X value * @param Y [OUTPUT] a pointer for the output Y value */ RGFWDEF void RGFW_getMouseScroll(float *x, float *y); /**! * @brief outputs the current x, y movement vector of the mouse * @param X [OUTPUT] a pointer for the output X vector value * @param Y [OUTPUT] a pointer for the output Y vector value */ RGFWDEF void RGFW_getMouseVector(float *x, float *y); /** @} */ /**! * @brief creates a new window * @param name the requested title of the window * @param x the requested x position of the window * @param y the requested y position of the window * @param w the requested width of the window * @param h the requested height of the window * @param flags extra arguments ((u32)0 means no flags used) * @return A pointer to the newly created window structure * * NOTE: (windows) if the executable has an icon resource named RGFW_ICON, it will be set as the initial icon for the window */ RGFWDEF RGFW_window *RGFW_createWindow(const char *name, i32 x, i32 y, i32 w, i32 h, RGFW_windowFlags flags); /**! * @brief creates a new window using a pre-allocated window structure * @param name the requested title of the window * @param x the requested x position of the window * @param y the requested y position of the window * @param w the requested width of the window * @param h the requested height of the window * @param flags extra arguments ((u32)0 means no flags used) * @param win a pointer the pre-allocated window structure * @return A pointer to the newly created window structure */ RGFWDEF RGFW_window *RGFW_createWindowPtr(const char *name, i32 x, i32 y, i32 w, i32 h, RGFW_windowFlags flags, RGFW_window * win); /**! * @brief creates a new surface structure * @param win the source window of the surface * @param data a pointer to the raw data of the structure (you allocate this) * @param w the width the data * @param h the height of the data * @return A pointer to the newly created surface structure * * NOTE: when you create a surface using RGFW_createSurface / ptr, on X11 it uses the root window's visual * this means it may fail to render on any other window if the visual does not match * RGFW_window_createSurface and RGFW_window_createSurfacePtr exist only for X11 to address this issues * Of course, you can also manually set the root window with RGFW_setRootWindow */ RGFWDEF RGFW_surface *RGFW_window_createSurface(RGFW_window * win, u8 * data, i32 w, i32 h, RGFW_format format); /**! * @brief creates a new surface structure using a pre-allocated surface structure * @param win the source window of the surface * @param data a pointer to the raw data of the structure (you allocate this) * @param w the width the data * @param h the height of the data * @param a pointer to the pre-allocated surface structure * @return a bool if the creation was successful or not */ RGFWDEF RGFW_bool RGFW_window_createSurfacePtr(RGFW_window * win, u8 * data, i32 w, i32 h, RGFW_format format, RGFW_surface * surface); /**! * @brief blits a surface stucture to the window * @param win a pointer the window to blit to * @param surface a pointer to the surface */ RGFWDEF void RGFW_window_blitSurface(RGFW_window * win, RGFW_surface * surface); /**! * @brief gets the position of the window | with RGFW_window.x and window.y * @param x [OUTPUT] the x position of the window * @param y [OUTPUT] the y position of the window * @return a bool if the function was successful */ RGFWDEF RGFW_bool RGFW_window_getPosition(RGFW_window * win, i32 * x, i32 * y); /* !< */ /**! * @brief gets the size of the window | with RGFW_window.w and window.h * @param win a pointer to the window * @param w [OUTPUT] the width of the window * @param h [OUTPUT] the height of the window * @return a bool if the function was successful */ RGFWDEF RGFW_bool RGFW_window_getSize(RGFW_window * win, i32 * w, i32 * h); /**! * @brief gets the flags of the window | returns RGFW_window._flags * @param win a pointer to the window * @return the window flags */ RGFWDEF u32 RGFW_window_getFlags(RGFW_window * win); /**! * @brief returns the exit key assigned to the window * @param win a pointer to the target window * @return The key code assigned as the exit key */ RGFWDEF RGFW_key RGFW_window_getExitKey(RGFW_window * win); /**! * @brief sets the exit key for the window * @param win a pointer to the target window * @param key the key code to assign as the exit key */ RGFWDEF void RGFW_window_setExitKey(RGFW_window * win, RGFW_key key); /**! * @brief sets the types of events you want the window to receive * @param win a pointer to the target window * @param events the event flags to enable (use RGFW_allEventFlags for all) */ RGFWDEF void RGFW_window_setEnabledEvents(RGFW_window * win, RGFW_eventFlag events); /**! * @brief gets the currently enabled events for the window * @param win a pointer to the target window * @return The enabled event flags for the window */ RGFWDEF RGFW_eventFlag RGFW_window_getEnabledEvents(RGFW_window * win); /**! * @brief enables all events and disables selected ones * @param win a pointer to the target window * @param events the event flags to disable */ RGFWDEF void RGFW_window_setDisabledEvents(RGFW_window * win, RGFW_eventFlag events); /**! * @brief directly enables or disables a specific event or group of events * @param win a pointer to the target window * @param event the event flag or group of flags to modify * @param state RGFW_TRUE to enable, RGFW_FALSE to disable */ RGFWDEF void RGFW_window_setEventState(RGFW_window * win, RGFW_eventFlag event, RGFW_bool state); /**! * @brief gets the user pointer associated with the window * @param win a pointer to the target window * @return The user-defined pointer stored in the window */ RGFWDEF void *RGFW_window_getUserPtr(RGFW_window * win); /**! * @brief sets a user pointer for the window * @param win a pointer to the target window * @param ptr a pointer to associate with the window */ RGFWDEF void RGFW_window_setUserPtr(RGFW_window * win, void *ptr); /**! * @brief retrieves the platform-specific window source pointer * @param win a pointer to the target window * @return A pointer to the internal RGFW_window_src structure */ RGFWDEF RGFW_window_src *RGFW_window_getSrc(RGFW_window * win); /**! * @brief sets the macOS layer object associated with the window * @param win a pointer to the target window * @param layer a pointer to the macOS layer object * @note Only available on macOS platforms */ RGFWDEF void RGFW_window_setLayer_OSX(RGFW_window * win, void *layer); /**! * @brief retrieves the macOS view object associated with the window * @param win a pointer to the target window * @return A pointer to the macOS view object, or NULL if not on macOS */ void *RGFW_window_getView_OSX(RGFW_window * win); /**! * @brief retrieves the macOS window object * @param win a pointer to the target window * @return A pointer to the macOS window object, or NULL if not on macOS */ RGFWDEF void *RGFW_window_getWindow_OSX(RGFW_window * win); /**! * @brief retrieves the HWND handle for the window * @param win a pointer to the target window * @return A pointer to the Windows HWND handle, or NULL if not on Windows */ RGFWDEF void *RGFW_window_getHWND(RGFW_window * win); /**! * @brief retrieves the HDC handle for the window * @param win a pointer to the target window * @return A pointer to the Windows HDC handle, or NULL if not on Windows */ RGFWDEF void *RGFW_window_getHDC(RGFW_window * win); /**! * @brief retrieves the X11 Window handle for the window * @param win a pointer to the target window * @return The X11 Window handle, or 0 if not on X11 */ RGFWDEF u64 RGFW_window_getWindow_X11(RGFW_window * win); /**! * @brief retrieves the Wayland surface handle for the window * @param win a pointer to the target window * @return A pointer to the Wayland wl_surface, or NULL if not on Wayland */ RGFWDEF struct wl_surface *RGFW_window_getWindow_Wayland(RGFW_window * win); /** * @defgroup Window_management * @{ */ /* * ! set the window flags (will undo flags if they don't match the old * ones) */ RGFWDEF void RGFW_window_setFlags(RGFW_window * win, RGFW_windowFlags); /**! * @brief polls and pops the next event from the window's event queue * @param win a pointer to the target window * @param event [OUTPUT] a pointer to store the retrieved event * @return RGFW_TRUE if an event was found, RGFW_FALSE otherwise * * NOTE: Using this function without a loop may cause event lag. * For multi-threaded systems, use RGFW_pollEvents combined with RGFW_window_checkQueuedEvent. * * Example: * RGFW_event event; * while (RGFW_window_checkEvent(win, &event)) { * // handle event * } */ RGFWDEF RGFW_bool RGFW_window_checkEvent(RGFW_window * win, RGFW_event * event); /**! * @brief pops the first queued event for the window * @param win a pointer to the target window * @param event [OUTPUT] a pointer to store the retrieved event * @return RGFW_TRUE if an event was found, RGFW_FALSE otherwise */ RGFWDEF RGFW_bool RGFW_window_checkQueuedEvent(RGFW_window * win, RGFW_event * event); /**! * @brief checks if a key was pressed while the window is in focus * @param win a pointer to the target window * @param key the key code to check * @return RGFW_TRUE if the key was pressed, RGFW_FALSE otherwise */ RGFWDEF RGFW_bool RGFW_window_isKeyPressed(RGFW_window * win, RGFW_key key); /**! * @brief checks if a key is currently being held down * @param win a pointer to the target window * @param key the key code to check * @return RGFW_TRUE if the key is held down, RGFW_FALSE otherwise */ RGFWDEF RGFW_bool RGFW_window_isKeyDown(RGFW_window * win, RGFW_key key); /**! * @brief checks if a key was released * @param win a pointer to the target window * @param key the key code to check * @return RGFW_TRUE if the key was released, RGFW_FALSE otherwise */ RGFWDEF RGFW_bool RGFW_window_isKeyReleased(RGFW_window * win, RGFW_key key); /**! * @brief checks if a mouse button was pressed * @param win a pointer to the target window * @param button the mouse button code to check * @return RGFW_TRUE if the mouse button was pressed, RGFW_FALSE otherwise */ RGFWDEF RGFW_bool RGFW_window_isMousePressed(RGFW_window * win, RGFW_mouseButton button); /**! * @brief checks if a mouse button is currently held down * @param win a pointer to the target window * @param button the mouse button code to check * @return RGFW_TRUE if the mouse button is down, RGFW_FALSE otherwise */ RGFWDEF RGFW_bool RGFW_window_isMouseDown(RGFW_window * win, RGFW_mouseButton button); /**! * @brief checks if a mouse button was released * @param win a pointer to the target window * @param button the mouse button code to check * @return RGFW_TRUE if the mouse button was released, RGFW_FALSE otherwise */ RGFWDEF RGFW_bool RGFW_window_isMouseReleased(RGFW_window * win, RGFW_mouseButton button); /**! * @brief checks if the mouse left the window (true only for the first frame) * @param win a pointer to the target window * @return RGFW_TRUE if the mouse left, RGFW_FALSE otherwise */ RGFWDEF RGFW_bool RGFW_window_didMouseLeave(RGFW_window * win); /**! * @brief checks if the mouse entered the window (true only for the first frame) * @param win a pointer to the target window * @return RGFW_TRUE if the mouse entered, RGFW_FALSE otherwise */ RGFWDEF RGFW_bool RGFW_window_didMouseEnter(RGFW_window * win); /**! * @brief checks if the mouse is currently inside the window bounds * @param win a pointer to the target window * @return RGFW_TRUE if the mouse is inside, RGFW_FALSE otherwise */ RGFWDEF RGFW_bool RGFW_window_isMouseInside(RGFW_window * win); /**! * @brief checks if there is data being dragged into or within the window * @param win a pointer to the target window * @return RGFW_TRUE if data is being dragged, RGFW_FALSE otherwise */ RGFWDEF RGFW_bool RGFW_window_isDataDragging(RGFW_window * win); /**! * @brief gets the position of a data drag * @param win a pointer to the target window * @param x [OUTPUT] pointer to store the x position * @param y [OUTPUT] pointer to store the y position * @return RGFW_TRUE if there is an active drag, RGFW_FALSE otherwise */ RGFWDEF RGFW_bool RGFW_window_getDataDrag(RGFW_window * win, i32 * x, i32 * y); /**! * @brief checks if a data drop occurred in the window (first frame only) * @param win a pointer to the target window * @return RGFW_TRUE if data was dropped, RGFW_FALSE otherwise */ RGFWDEF RGFW_bool RGFW_window_didDataDrop(RGFW_window * win); /**! * @brief retrieves files from a data drop (drag and drop) * @param win a pointer to the target window * @param files [OUTPUT] a pointer to the array of file paths * @param count [OUTPUT] the number of dropped files * @return RGFW_TRUE if a data drop occurred, RGFW_FALSE otherwise */ RGFWDEF RGFW_bool RGFW_window_getDataDrop(RGFW_window * win, const char ***files, size_t * count); /**! * @brief closes the window and frees its associated structure * @param win a pointer to the target window */ RGFWDEF void RGFW_window_close(RGFW_window * win); /**! * @brief closes the window without freeing its structure * @param win a pointer to the target window */ RGFWDEF void RGFW_window_closePtr(RGFW_window * win); /**! * @brief moves the window to a new position on the screen * @param win a pointer to the target window * @param x the new x position * @param y the new y position */ RGFWDEF void RGFW_window_move(RGFW_window * win, i32 x, i32 y); #ifndef RGFW_NO_MONITOR /**! * @brief moves the window to a specific monitor * @param win a pointer to the target window * @param m the target monitor */ RGFWDEF void RGFW_window_moveToMonitor(RGFW_window * win, RGFW_monitor m); #endif /**! * @brief resizes the window to the given dimensions * @param win a pointer to the target window * @param w the new width * @param h the new height */ RGFWDEF void RGFW_window_resize(RGFW_window * win, i32 w, i32 h); /**! * @brief sets the aspect ratio of the window * @param win a pointer to the target window * @param w the width ratio * @param h the height ratio */ RGFWDEF void RGFW_window_setAspectRatio(RGFW_window * win, i32 w, i32 h); /**! * @brief sets the minimum size of the window * @param win a pointer to the target window * @param w the minimum width * @param h the minimum height */ RGFWDEF void RGFW_window_setMinSize(RGFW_window * win, i32 w, i32 h); /**! * @brief sets the maximum size of the window * @param win a pointer to the target window * @param w the maximum width * @param h the maximum height */ RGFWDEF void RGFW_window_setMaxSize(RGFW_window * win, i32 w, i32 h); /**! * @brief sets focus to the window * @param win a pointer to the target window */ RGFWDEF void RGFW_window_focus(RGFW_window * win); /**! * @brief checks if the window is currently in focus * @param win a pointer to the target window * @return RGFW_TRUE if the window is in focus, RGFW_FALSE otherwise */ RGFWDEF RGFW_bool RGFW_window_isInFocus(RGFW_window * win); /**! * @brief raises the window to the top of the stack * @param win a pointer to the target window */ RGFWDEF void RGFW_window_raise(RGFW_window * win); /**! * @brief maximizes the window * @param win a pointer to the target window */ RGFWDEF void RGFW_window_maximize(RGFW_window * win); /**! * @brief toggles fullscreen mode for the window * @param win a pointer to the target window * @param fullscreen RGFW_TRUE to enable fullscreen, RGFW_FALSE to disable */ RGFWDEF void RGFW_window_setFullscreen(RGFW_window * win, RGFW_bool fullscreen); /**! * @brief centers the window on the screen * @param win a pointer to the target window */ RGFWDEF void RGFW_window_center(RGFW_window * win); /**! * @brief minimizes the window * @param win a pointer to the target window */ RGFWDEF void RGFW_window_minimize(RGFW_window * win); /**! * @brief restores the window from minimized state * @param win a pointer to the target window */ RGFWDEF void RGFW_window_restore(RGFW_window * win); /**! * @brief makes the window a floating window * @param win a pointer to the target window * @param floating RGFW_TRUE to float, RGFW_FALSE to disable */ RGFWDEF void RGFW_window_setFloating(RGFW_window * win, RGFW_bool floating); /**! * @brief sets the opacity level of the window * @param win a pointer to the target window * @param opacity the opacity level (0–255) */ RGFWDEF void RGFW_window_setOpacity(RGFW_window * win, u8 opacity); /**! * @brief toggles window borders * @param win a pointer to the target window * @param border RGFW_TRUE for bordered, RGFW_FALSE for borderless */ RGFWDEF void RGFW_window_setBorder(RGFW_window * win, RGFW_bool border); /**! * @brief checks if the window is borderless * @param win a pointer to the target window * @return RGFW_TRUE if borderless, RGFW_FALSE otherwise */ RGFWDEF RGFW_bool RGFW_window_borderless(RGFW_window * win); /**! * @brief toggles drag-and-drop (DND) support for the window * @param win a pointer to the target window * @param allow RGFW_TRUE to allow DND, RGFW_FALSE to disable * @note RGFW_windowAllowDND must still be passed when creating the window */ RGFWDEF void RGFW_window_setDND(RGFW_window * win, RGFW_bool allow); /**! * @brief checks if drag-and-drop (DND) is allowed * @param win a pointer to the target window * @return RGFW_TRUE if DND is enabled, RGFW_FALSE otherwise */ RGFWDEF RGFW_bool RGFW_window_allowsDND(RGFW_window * win); #ifndef RGFW_NO_PASSTHROUGH /**! * @brief toggles mouse passthrough for the window * @param win a pointer to the target window * @param passthrough RGFW_TRUE to enable passthrough, RGFW_FALSE to disable */ RGFWDEF void RGFW_window_setMousePassthrough(RGFW_window * win, RGFW_bool passthrough); #endif /**! * @brief renames the window * @param win a pointer to the target window * @param name the new title string for the window */ RGFWDEF void RGFW_window_setName(RGFW_window * win, const char *name); /**! * @brief sets the icon for the window and taskbar * @param win a pointer to the target window * @param data the image data * @param w the width of the icon * @param h the height of the icon * @param format the image format * @return RGFW_TRUE if successful, RGFW_FALSE otherwise * * NOTE: The image may be resized by default. */ RGFWDEF RGFW_bool RGFW_window_setIcon(RGFW_window * win, u8 * data, i32 w, i32 h, RGFW_format format); /**! * @brief sets the icon for the window and/or taskbar * @param win a pointer to the target window * @param data the image data * @param w the width of the icon * @param h the height of the icon * @param format the image format * @param type the target icon type (taskbar, window, or both) * @return RGFW_TRUE if successful, RGFW_FALSE otherwise */ RGFWDEF RGFW_bool RGFW_window_setIconEx(RGFW_window * win, u8 * data, i32 w, i32 h, RGFW_format format, RGFW_icon type); /**! * @brief sets the mouse icon for the window using a loaded bitmap * @param win a pointer to the target window * @param mouse a pointer to the RGFW_mouse struct containing the icon */ RGFWDEF void RGFW_window_setMouse(RGFW_window * win, RGFW_mouse * mouse); /**! * @brief Sets the mouse to a standard system cursor. * @param win The target window. * @param mouse The standard cursor type (see RGFW_MOUSE enum). * @return True if the standard cursor was successfully applied. */ RGFWDEF RGFW_bool RGFW_window_setMouseStandard(RGFW_window * win, RGFW_mouseIcons mouse); /**! * @brief Sets the mouse to the default cursor icon. * @param win The target window. * @return True if the default cursor was successfully set. */ RGFWDEF RGFW_bool RGFW_window_setMouseDefault(RGFW_window * win); /**! * @brief Locks the cursor to the center of the window. * @param win The target window. * * While the cursor is held, X and Y report raw mouse movement data. * Useful for 3D camera or first-person movement systems. */ RGFWDEF void RGFW_window_holdMouse(RGFW_window * win); /**! * @brief Returns true if the mouse is currently held by RGFW. * @param win The target window. * @return True if the mouse is being held. */ RGFWDEF RGFW_bool RGFW_window_isHoldingMouse(RGFW_window * win); /**! * @brief Releases the mouse so it can move freely again. * @param win The target window. */ RGFWDEF void RGFW_window_unholdMouse(RGFW_window * win); /**! * @brief Hides the window from view. * @param win The target window. */ RGFWDEF void RGFW_window_hide(RGFW_window * win); /**! * @brief Shows the window if it was hidden. * @param win The target window. */ RGFWDEF void RGFW_window_show(RGFW_window * win); /**! * @brief Sets whether the window should close. * @param win The target window. * @param shouldClose True to signal the window should close, false to keep it open. * * This can override or trigger the `RGFW_window_shouldClose` state by modifying window flags. */ RGFWDEF void RGFW_window_setShouldClose(RGFW_window * win, RGFW_bool shouldClose); /**! * @brief Retrieves the current global mouse position. * @param x [OUTPUT] Pointer to store the X position of the mouse on the screen. * @param y [OUTPUT] Pointer to store the Y position of the mouse on the screen. * @return True if the position was successfully retrieved. */ RGFWDEF RGFW_bool RGFW_getGlobalMouse(i32 * x, i32 * y); /**! * @brief Retrieves the mouse position relative to the window. * @param win The target window. * @param x [OUTPUT] Pointer to store the X position within the window. * @param y [OUTPUT] Pointer to store the Y position within the window. * @return True if the position was successfully retrieved. */ RGFWDEF RGFW_bool RGFW_window_getMouse(RGFW_window * win, i32 * x, i32 * y); /**! * @brief Shows or hides the mouse cursor for the window. * @param win The target window. * @param show True to show the mouse, false to hide it. */ RGFWDEF void RGFW_window_showMouse(RGFW_window * win, RGFW_bool show); /**! * @brief Checks if the mouse is currently hidden in the window. * @param win The target window. * @return True if the mouse is hidden. */ RGFWDEF RGFW_bool RGFW_window_isMouseHidden(RGFW_window * win); /**! * @brief Moves the mouse to the specified position within the window. * @param win The target window. * @param x The new X position. * @param y The new Y position. */ RGFWDEF void RGFW_window_moveMouse(RGFW_window * win, i32 x, i32 y); /**! * @brief Checks if the window should close. * @param win The target window. * @return True if the window should close (for example, if ESC was pressed or a close event occurred). */ RGFWDEF RGFW_bool RGFW_window_shouldClose(RGFW_window * win); /**! * @brief Checks if the window is currently fullscreen. * @param win The target window. * @return True if the window is fullscreen. */ RGFWDEF RGFW_bool RGFW_window_isFullscreen(RGFW_window * win); /**! * @brief Checks if the window is currently hidden. * @param win The target window. * @return True if the window is hidden. */ RGFWDEF RGFW_bool RGFW_window_isHidden(RGFW_window * win); /**! * @brief Checks if the window is minimized. * @param win The target window. * @return True if the window is minimized. */ RGFWDEF RGFW_bool RGFW_window_isMinimized(RGFW_window * win); /**! * @brief Checks if the window is maximized. * @param win The target window. * @return True if the window is maximized. */ RGFWDEF RGFW_bool RGFW_window_isMaximized(RGFW_window * win); /**! * @brief Checks if the window is floating. * @param win The target window. * @return True if the window is floating. */ RGFWDEF RGFW_bool RGFW_window_isFloating(RGFW_window * win); /** @} */ /** * @defgroup Monitor * @{ */ #ifndef RGFW_NO_MONITOR /**! * @brief Scales the window to match its monitor’s resolution. * @param win The target window. * * This function is automatically called when the flag `RGFW_scaleToMonitor` * is used during window creation. */ RGFWDEF void RGFW_window_scaleToMonitor(RGFW_window * win); /**! * @brief Retrieves the monitor structure associated with the window. * @param win The target window. * @return The monitor structure of the window. */ RGFWDEF RGFW_monitor RGFW_window_getMonitor(RGFW_window * win); #endif /** @} */ /** * @defgroup Clipboard * @{ */ /**! * @brief Reads clipboard data. * @param size [OUTPUT] A pointer that will be filled with the size of the clipboard data. * @return A pointer to the clipboard data as a string. */ RGFWDEF const char *RGFW_readClipboard(size_t * size); /**! * @brief Reads clipboard data into a provided buffer, or returns the required length if str is NULL. * @param str [OUTPUT] A pointer to the buffer that will receive the clipboard data (or NULL to get required size). * @param strCapacity The capacity of the provided buffer. * @return The number of bytes read or required length of clipboard data. */ RGFWDEF RGFW_ssize_t RGFW_readClipboardPtr(char *str, size_t strCapacity); /**! * @brief Writes text to the clipboard. * @param text The text to be written to the clipboard. * @param textLen The length of the text being written. */ RGFWDEF void RGFW_writeClipboard(const char *text, u32 textLen); /** @} */ /** * @defgroup error handling * @{ */ /**! * @brief Sets the callback function to handle debug messages from RGFW. * @param func The function pointer to be used as the debug callback. * @return The previously set debug callback function. */ RGFWDEF RGFW_debugfunc RGFW_setDebugCallback(RGFW_debugfunc func); /**! * @brief Sends a debug message manually through the currently set debug callback. * @param type The type of debug message being sent. * @param err The associated error code. * @param msg The debug message text. */ RGFWDEF void RGFW_sendDebugInfo(RGFW_debugType type, RGFW_errorCode err, const char *msg); /** @} */ /** event callbacks. These are completely optional, so you can use the normal RGFW_checkEvent() method if you prefer that * @defgroup Callbacks * @{ */ /**! * @brief Sets the callback function for window move events. * @param func The function to be called when the window is moved. * @return The previously set callback function, if any. */ RGFWDEF RGFW_windowMovedfunc RGFW_setWindowMovedCallback(RGFW_windowMovedfunc func); /**! * @brief Sets the callback function for window resize events. * @param func The function to be called when the window is resized. * @return The previously set callback function, if any. */ RGFWDEF RGFW_windowResizedfunc RGFW_setWindowResizedCallback(RGFW_windowResizedfunc func); /**! * @brief Sets the callback function for window quit events. * @param func The function to be called when the window receives a quit signal. * @return The previously set callback function, if any. */ RGFWDEF RGFW_windowQuitfunc RGFW_setWindowQuitCallback(RGFW_windowQuitfunc func); /**! * @brief Sets the callback function for mouse move events. * @param func The function to be called when the mouse moves within the window. * @return The previously set callback function, if any. */ RGFWDEF RGFW_mousePosfunc RGFW_setMousePosCallback(RGFW_mousePosfunc func); /**! * @brief Sets the callback function for window refresh events. * @param func The function to be called when the window needs to be refreshed. * @return The previously set callback function, if any. */ RGFWDEF RGFW_windowRefreshfunc RGFW_setWindowRefreshCallback(RGFW_windowRefreshfunc func); /**! * @brief Sets the callback function for focus change events. * @param func The function to be called when the window gains or loses focus. * @return The previously set callback function, if any. */ RGFWDEF RGFW_focusfunc RGFW_setFocusCallback(RGFW_focusfunc func); /**! * @brief Sets the callback function for mouse notification events. * @param func The function to be called when a mouse notification event occurs. * @return The previously set callback function, if any. */ RGFWDEF RGFW_mouseNotifyfunc RGFW_setMouseNotifyCallback(RGFW_mouseNotifyfunc func); /**! * @brief Sets the callback function for data drop events. * @param func The function to be called when data is dropped into the window. * @return The previously set callback function, if any. */ RGFWDEF RGFW_dataDropfunc RGFW_setDataDropCallback(RGFW_dataDropfunc func); /**! * @brief Sets the callback function for the start of a data drag event. * @param func The function to be called when data dragging begins. * @return The previously set callback function, if any. */ RGFWDEF RGFW_dataDragfunc RGFW_setDataDragCallback(RGFW_dataDragfunc func); /**! * @brief Sets the callback function for key press and release events. * @param func The function to be called when a key is pressed or released. * @return The previously set callback function, if any. */ RGFWDEF RGFW_keyfunc RGFW_setKeyCallback(RGFW_keyfunc func); /**! * @brief Sets the callback function for mouse button press and release events. * @param func The function to be called when a mouse button is pressed or released. * @return The previously set callback function, if any. */ RGFWDEF RGFW_mouseButtonfunc RGFW_setMouseButtonCallback(RGFW_mouseButtonfunc func); /**! * @brief Sets the callback function for mouse scroll events. * @param func The function to be called when the mouse wheel is scrolled. * @return The previously set callback function, if any. */ RGFWDEF RGFW_mouseScrollfunc RGFW_setMouseScrollCallback(RGFW_mouseScrollfunc func); /**! * @brief Sets the callback function for window maximize events. * @param func The function to be called when the window is maximized. * @return The previously set callback function, if any. */ RGFWDEF RGFW_windowMaximizedfunc RGFW_setWindowMaximizedCallback(RGFW_windowMaximizedfunc func); /**! * @brief Sets the callback function for window minimize events. * @param func The function to be called when the window is minimized. * @return The previously set callback function, if any. */ RGFWDEF RGFW_windowMinimizedfunc RGFW_setWindowMinimizedCallback(RGFW_windowMinimizedfunc func); /**! * @brief Sets the callback function for window restore events. * @param func The function to be called when the window is restored from a minimized or maximized state. * @return The previously set callback function, if any. */ RGFWDEF RGFW_windowRestoredfunc RGFW_setWindowRestoredCallback(RGFW_windowRestoredfunc func); /**! * @brief Sets the callback function for DPI (scale) update events. * @param func The function to be called when the window’s DPI or scale changes. * @return The previously set callback function, if any. */ RGFWDEF RGFW_scaleUpdatedfunc RGFW_setScaleUpdatedCallback(RGFW_scaleUpdatedfunc func); /** @} */ /** * @defgroup graphics_API * @{ */ /* ! native rendering API functions */ #if defined(RGFW_OPENGL) /* * these are native opengl specific functions and will NOT work with * EGL */ /* * !< make the window the current OpenGL drawing context * * NOTE: if you want to switch the graphics context's thread, you have * to run RGFW_window_makeCurrentContext_OpenGL(NULL); on the old * thread then RGFW_window_makeCurrentContext_OpenGL(valid_window) on * the new thread */ /**! * @brief Sets the global OpenGL hints to the specified pointer. * @param hints A pointer to the RGFW_glHints structure containing the desired OpenGL settings. */ RGFWDEF void RGFW_setGlobalHints_OpenGL(RGFW_glHints * hints); /**! * @brief Resets the global OpenGL hints to their default values. */ RGFWDEF void RGFW_resetGlobalHints_OpenGL(void); /**! * @brief Gets the current global OpenGL hints pointer. * @return A pointer to the currently active RGFW_glHints structure. */ RGFWDEF RGFW_glHints *RGFW_getGlobalHints_OpenGL(void); /**! * @brief Creates and allocates an OpenGL context for the specified window. * @param win A pointer to the target RGFW_window. * @param hints A pointer to an RGFW_glHints structure defining context creation parameters. * @return A pointer to the newly created RGFW_glContext. */ RGFWDEF RGFW_glContext *RGFW_window_createContext_OpenGL(RGFW_window * win, RGFW_glHints * hints); /**! * @brief Creates an OpenGL context for the specified window using a preallocated context structure. * @param win A pointer to the target RGFW_window. * @param ctx A pointer to an already allocated RGFW_glContext structure. * @param hints A pointer to an RGFW_glHints structure defining context creation parameters. * @return RGFW_TRUE on success, RGFW_FALSE on failure. */ RGFWDEF RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window * win, RGFW_glContext * ctx, RGFW_glHints * hints); /**! * @brief Retrieves the OpenGL context associated with a window. * @param win A pointer to the RGFW_window. * @return A pointer to the associated RGFW_glContext, or NULL if none exists or if the context is EGL-based. */ RGFWDEF RGFW_glContext *RGFW_window_getContext_OpenGL(RGFW_window * win); /**! * @brief Deletes and frees the OpenGL context. * @param win A pointer to the RGFW_window. * @param ctx A pointer to the RGFW_glContext to delete. * * @note This is automatically called by RGFW_window_close if the window’s context is not NULL. */ RGFWDEF void RGFW_window_deleteContext_OpenGL(RGFW_window * win, RGFW_glContext * ctx); /**! * @brief Deletes the OpenGL context without freeing its memory. * @param win A pointer to the RGFW_window. * @param ctx A pointer to the RGFW_glContext to delete. * * @note This is automatically called by RGFW_window_close if the window’s context is not NULL. */ RGFWDEF void RGFW_window_deleteContextPtr_OpenGL(RGFW_window * win, RGFW_glContext * ctx); /**! * @brief Retrieves the native source context from an RGFW_glContext. * @param ctx A pointer to the RGFW_glContext. * @return A pointer to the native OpenGL context handle. */ RGFWDEF void *RGFW_glContext_getSourceContext(RGFW_glContext * ctx); /**! * @brief Makes the specified window the current OpenGL rendering target. * @param win A pointer to the RGFW_window to make current. * * @note This is typically called internally by RGFW_window_makeCurrent. */ RGFWDEF void RGFW_window_makeCurrentWindow_OpenGL(RGFW_window * win); /**! * @brief Makes the OpenGL context of the specified window current. * @param win A pointer to the RGFW_window whose context should be made current. * * @note To move a context between threads, call RGFW_window_makeCurrentContext_OpenGL(NULL) * on the old thread before making it current on the new one. */ RGFWDEF void RGFW_window_makeCurrentContext_OpenGL(RGFW_window * win); /**! * @brief Swaps the OpenGL buffers for the specified window. * @param win A pointer to the RGFW_window whose buffers should be swapped. * * @note Typically called by RGFW_window_swapInterval. */ RGFWDEF void RGFW_window_swapBuffers_OpenGL(RGFW_window * win); /**! * @brief Retrieves the current OpenGL context. * @return A pointer to the currently active OpenGL context (GLX, WGL, Cocoa, or WebGL backend). */ RGFWDEF void *RGFW_getCurrentContext_OpenGL(void); /**! * @brief Retrieves the current OpenGL window. * @return A pointer to the RGFW_window currently bound as the OpenGL context target. */ RGFWDEF RGFW_window *RGFW_getCurrentWindow_OpenGL(void); /**! * @brief Sets the OpenGL swap interval (vsync). * @param win A pointer to the RGFW_window. * @param swapInterval The desired swap interval value (0 to disable vsync, 1 to enable). */ RGFWDEF void RGFW_window_swapInterval_OpenGL(RGFW_window * win, i32 swapInterval); /**! * @brief Retrieves the address of a native OpenGL procedure. * @param procname The name of the OpenGL function to look up. * @return A pointer to the function, or NULL if not found. */ RGFWDEF RGFW_proc RGFW_getProcAddress_OpenGL(const char *procname); /**! * @brief Checks whether a specific OpenGL or OpenGL ES API extension is supported. * @param extension The name of the extension to check. * @param len The length of the extension string. * @return RGFW_TRUE if supported, RGFW_FALSE otherwise. */ RGFWDEF RGFW_bool RGFW_extensionSupported_OpenGL(const char *extension, size_t len); /**! * @brief Checks whether a specific platform-dependent OpenGL extension is supported. * @param extension The name of the extension to check. * @param len The length of the extension string. * @return RGFW_TRUE if supported, RGFW_FALSE otherwise. */ RGFWDEF RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char *extension, size_t len); /* these are EGL specific functions, they may fallback to OpenGL */ #ifdef RGFW_EGL /**! * @brief Creates and allocates an OpenGL/EGL context for the specified window. * @param win A pointer to the target RGFW_window. * @param hints A pointer to an RGFW_glHints structure defining context creation parameters. * @return A pointer to the newly created RGFW_eglContext. */ RGFWDEF RGFW_eglContext *RGFW_window_createContext_EGL(RGFW_window * win, RGFW_glHints * hints); /**! * @brief Creates an OpenGL/EGL context for the specified window using a preallocated context structure. * @param win A pointer to the target RGFW_window. * @param ctx A pointer to an already allocated RGFW_eglContext structure. * @param hints A pointer to an RGFW_glHints structure defining context creation parameters. * @return RGFW_TRUE on success, RGFW_FALSE on failure. */ RGFWDEF RGFW_bool RGFW_window_createContextPtr_EGL(RGFW_window * win, RGFW_eglContext * ctx, RGFW_glHints * hints); /**! * @brief Frees and deletes an OpenGL/EGL context. * @param win A pointer to the RGFW_window. * @param ctx A pointer to the RGFW_eglContext to delete. * * @note Automatically called by RGFW_window_close if RGFW owns the context. */ RGFWDEF void RGFW_window_deleteContext_EGL(RGFW_window * win, RGFW_eglContext * ctx); /**! * @brief Deletes an OpenGL/EGL context without freeing its memory. * @param win A pointer to the RGFW_window. * @param ctx A pointer to the RGFW_eglContext to delete. * * @note Automatically called by RGFW_window_close if RGFW owns the context. */ RGFWDEF void RGFW_window_deleteContextPtr_EGL(RGFW_window * win, RGFW_eglContext * ctx); /**! * @brief Retrieves the OpenGL/EGL context associated with a window. * @param win A pointer to the RGFW_window. * @return A pointer to the associated RGFW_eglContext, or NULL if none exists or if the context is a native OpenGL context. */ RGFWDEF RGFW_eglContext *RGFW_window_getContext_EGL(RGFW_window * win); /**! * @brief Retrieves the EGL display handle. * @return A pointer to the native EGLDisplay. */ RGFWDEF void *RGFW_getDisplay_EGL(void); /**! * @brief Retrieves the native source context from an RGFW_eglContext. * @param ctx A pointer to the RGFW_eglContext. * @return A pointer to the native EGLContext handle. */ RGFWDEF void *RGFW_eglContext_getSourceContext(RGFW_eglContext * ctx); /**! * @brief Retrieves the EGL surface handle from an RGFW_eglContext. * @param ctx A pointer to the RGFW_eglContext. * @return A pointer to the EGLSurface associated with the context. */ RGFWDEF void *RGFW_eglContext_getSurface(RGFW_eglContext * ctx); /**! * @brief Retrieves the Wayland EGL window handle from an RGFW_eglContext. * @param ctx A pointer to the RGFW_eglContext. * @return A pointer to the wl_egl_window associated with the EGL context. */ RGFWDEF struct wl_egl_window *RGFW_eglContext_wlEGLWindow(RGFW_eglContext * ctx); /**! * @brief Swaps the EGL buffers for the specified window. * @param win A pointer to the RGFW_window whose buffers should be swapped. * * @note Typically called by RGFW_window_swapInterval. */ RGFWDEF void RGFW_window_swapBuffers_EGL(RGFW_window * win); /**! * @brief Makes the specified window the current EGL rendering target. * @param win A pointer to the RGFW_window to make current. * * @note This is typically called internally by RGFW_window_makeCurrent. */ RGFWDEF void RGFW_window_makeCurrentWindow_EGL(RGFW_window * win); /**! * @brief Makes the EGL context of the specified window current. * @param win A pointer to the RGFW_window whose context should be made current. * * @note To move a context between threads, call RGFW_window_makeCurrentContext_EGL(NULL) * on the old thread before making it current on the new one. */ RGFWDEF void RGFW_window_makeCurrentContext_EGL(RGFW_window * win); /**! * @brief Retrieves the current EGL context. * @return A pointer to the currently active EGLContext. */ RGFWDEF void *RGFW_getCurrentContext_EGL(void); /**! * @brief Retrieves the current EGL window. * @return A pointer to the RGFW_window currently bound as the EGL context target. */ RGFWDEF RGFW_window *RGFW_getCurrentWindow_EGL(void); /**! * @brief Sets the EGL swap interval (vsync). * @param win A pointer to the RGFW_window. * @param swapInterval The desired swap interval value (0 to disable vsync, 1 to enable). */ RGFWDEF void RGFW_window_swapInterval_EGL(RGFW_window * win, i32 swapInterval); /**! * @brief Retrieves the address of a native OpenGL or OpenGL ES procedure in an EGL context. * @param procname The name of the OpenGL function to look up. * @return A pointer to the function, or NULL if not found. */ RGFWDEF RGFW_proc RGFW_getProcAddress_EGL(const char *procname); /**! * @brief Checks whether a specific OpenGL or OpenGL ES API extension is supported in the current EGL context. * @param extension The name of the extension to check. * @param len The length of the extension string. * @return RGFW_TRUE if supported, RGFW_FALSE otherwise. */ RGFWDEF RGFW_bool RGFW_extensionSupported_EGL(const char *extension, size_t len); /**! * @brief Checks whether a specific platform-dependent EGL extension is supported in the current context. * @param extension The name of the extension to check. * @param len The length of the extension string. * @return RGFW_TRUE if supported, RGFW_FALSE otherwise. */ RGFWDEF RGFW_bool RGFW_extensionSupportedPlatform_EGL(const char *extension, size_t len); #endif #endif #ifdef RGFW_VULKAN #include /* if you don't want to use the above macros */ /**! * @brief Retrieves the Vulkan instance extensions required by RGFW. * @param count [OUTPUT] A pointer that will receive the number of required extensions (typically 2). * @return A pointer to a static array of required Vulkan instance extension names. */ const char **RGFW_getRequiredInstanceExtensions_Vulkan(size_t * count); /**! * @brief Creates a Vulkan surface for the specified window. * @param win A pointer to the RGFW_window for which to create the Vulkan surface. * @param instance The Vulkan instance used to create the surface. * @param surface [OUTPUT] A pointer to a VkSurfaceKHR handle that will receive the created surface. * @return A VkResult indicating success or failure. */ RGFWDEF VkResult RGFW_window_createSurface_Vulkan(RGFW_window * win, VkInstance instance, VkSurfaceKHR * surface); /**! * @brief Checks whether the specified Vulkan physical device and queue family support presentation for RGFW. * @param instance The Vulkan instance. * @param physicalDevice The Vulkan physical device to check. * @param queueFamilyIndex The index of the queue family to query for presentation support. * @return RGFW_TRUE if presentation is supported, RGFW_FALSE otherwise. */ RGFWDEF RGFW_bool RGFW_getPresentationSupport_Vulkan(VkInstance instance, VkPhysicalDevice physicalDevice, u32 queueFamilyIndex); #endif #ifdef RGFW_DIRECTX #ifndef RGFW_WINDOWS #undef RGFW_DIRECTX #else #define OEMRESOURCE #include #ifndef __cplusplus #define __uuidof(T) IID_##T #endif /**! * @brief Creates a DirectX swap chain for the specified RGFW window. * @param win A pointer to the RGFW_window for which to create the swap chain. * @param pFactory A pointer to the IDXGIFactory used to create the swap chain. * @param pDevice A pointer to the DirectX device (e.g., ID3D11Device or ID3D12Device). * @param swapchain [OUTPUT] A pointer to an IDXGISwapChain pointer that will receive the created swap chain. * @return An integer result code (0 on success, or a DirectX error code on failure). */ RGFWDEF int RGFW_window_createSwapChain_DirectX(RGFW_window * win, IDXGIFactory * pFactory, IUnknown * pDevice, IDXGISwapChain * *swapchain); #endif #endif #ifdef RGFW_WEBGPU #include /**! * @brief Creates a WebGPU surface for the specified RGFW window. * @param window A pointer to the RGFW_window for which to create the surface. * @param instance The WebGPU instance used to create the surface. * @return The created WGPUSurface handle. */ RGFWDEF WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window * window, WGPUInstance instance); #endif /** @} */ /** * @defgroup Supporting * @{ */ /**! * @brief Sets the root (main) RGFW window. * @param win A pointer to the RGFW_window to set as the root window. */ RGFWDEF void RGFW_setRootWindow(RGFW_window * win); /**! * @brief Retrieves the current root RGFW window. * @return A pointer to the current root RGFW_window. */ RGFWDEF RGFW_window *RGFW_getRootWindow(void); /**! * @brief Pushes an event into the standard RGFW event queue. * @param event A pointer to the RGFW_event to be added to the queue. */ RGFWDEF void RGFW_eventQueuePush(const RGFW_event * event); /**! * @brief Clears all events from the RGFW event queue without processing them. */ RGFWDEF void RGFW_eventQueueFlush(void); /**! * @brief Pops the next event from the RGFW event queue for the specified window. * @param win A pointer to the RGFW_window to retrieve an event for. * @return A pointer to the popped RGFW_event, or NULL if the queue is empty. */ RGFWDEF RGFW_event *RGFW_eventQueuePop(RGFW_window * win); /**! * @brief Converts an API keycode to the RGFW unmapped (physical) key. * @param keycode The platform-specific keycode. * @return The corresponding RGFW keycode. */ RGFWDEF u32 RGFW_apiKeyToRGFW(u32 keycode); /**! * @brief Converts an RGFW keycode to the unmapped (physical) API key. * @param keycode The RGFW keycode. * @return The corresponding platform-specific keycode. */ RGFWDEF u32 RGFW_rgfwToApiKey(u32 keycode); /**! * @brief Converts an RGFW keycode to the mapped character representation. * @param keycode The RGFW keycode. * @return The corresponding key character. */ RGFWDEF u8 RGFW_rgfwToKeyChar(u32 keycode); /**! * @brief Retrieves the size of the RGFW_info structure. * @return The size (in bytes) of RGFW_info. */ RGFWDEF size_t RGFW_sizeofInfo(void); /**! * @brief Initializes the RGFW library. * @return 0 on success, or a negative error code on failure. * @note This is automatically called when the first window is created. */ RGFWDEF i32 RGFW_init(void); /**! * @brief Deinitializes the RGFW library. * @note This is automatically called when the last open window is closed. */ RGFWDEF void RGFW_deinit(void); /**! * @brief Initializes RGFW using a user-provided RGFW_info structure. * @param info A pointer to an RGFW_info structure to be used for initialization. * @return 0 on success, or a negative error code on failure. */ RGFWDEF i32 RGFW_init_ptr(RGFW_info * info); /**! * @brief Deinitializes a specific RGFW instance stored in the provided RGFW_info pointer. * @param info A pointer to the RGFW_info structure representing the instance to deinitialize. */ RGFWDEF void RGFW_deinit_ptr(RGFW_info * info); /**! * @brief Sets the global RGFW_info structure pointer. * @param info A pointer to the RGFW_info structure to set. */ RGFWDEF void RGFW_setInfo(RGFW_info * info); /**! * @brief Retrieves the global RGFW_info structure pointer. * @return A pointer to the current RGFW_info structure. */ RGFWDEF RGFW_info *RGFW_getInfo(void); /** @} */ #endif /* RGFW_HEADER */ #if !defined(RGFW_NATIVE_HEADER) && (defined(RGFW_NATIVE) || defined(RGFW_IMPLEMENTATION)) #define RGFW_NATIVE_HEADER #if (defined(RGFW_OPENGL) || defined(RGFW_WEGL)) && defined(_MSC_VER) #pragma comment(lib, "opengl32") #endif #ifdef RGFW_OPENGL struct RGFW_eglContext { void *ctx; void *surface; struct wl_egl_window *eglWindow; }; typedef union RGFW_gfxContext { RGFW_glContext *native; RGFW_eglContext *egl; } RGFW_gfxContext; typedef RGFW_ENUM(u32, RGFW_gfxContextType) { RGFW_gfxNativeOpenGL = RGFW_BIT(0), RGFW_gfxEGL = RGFW_BIT(1), RGFW_gfxOwnedByRGFW = RGFW_BIT(2) }; #endif /* ! source data for the window (used by the APIs) */ #ifdef RGFW_WINDOWS #define WIN32_LEAN_AND_MEAN #define OEMRESOURCE #include struct RGFW_nativeImage { HBITMAP bitmap; u8 *bitmapBits; RGFW_format format; HDC hdcMem; }; #ifdef RGFW_OPENGL struct RGFW_glContext { HGLRC ctx; }; #endif struct RGFW_window_src { HWND window; /* !< source window */ HDC hdc; /* !< source HDC */ i32 offsetW, offsetH; /* !< width and height offset for * window */ HICON hIconSmall, hIconBig; /* !< source window icons */ i32 maxSizeW, maxSizeH, minSizeW, minSizeH, aspectRatioW, aspectRatioH; /* !< for setting max/min resize (RGFW_WINDOWS) */ #ifdef RGFW_OPENGL RGFW_gfxContext ctx; RGFW_gfxContextType gfxType; #endif }; #elif defined(RGFW_UNIX) #ifdef RGFW_X11 #include #include #endif #ifdef RGFW_WAYLAND #ifdef RGFW_LIBDECOR #include #endif #include #include #endif struct RGFW_nativeImage { #ifdef RGFW_X11 XImage *bitmap; #endif #ifdef RGFW_WAYLAND struct wl_buffer *wl_buffer; u8 *buffer; #endif RGFW_format format; }; #ifdef RGFW_OPENGL struct RGFW_glContext { #ifdef RGFW_X11 struct __GLXcontextRec *ctx; /* !< source graphics context */ Window window; #endif #ifdef RGFW_WAYLAND RGFW_eglContext egl; #endif }; #endif struct RGFW_window_src { i32 x, y, w, h; #ifdef RGFW_OPENGL RGFW_gfxContext ctx; RGFW_gfxContextType gfxType; #endif #ifdef RGFW_X11 Window window; /* !< source window */ GC gc; #ifdef RGFW_ADVANCED_SMOOTH_RESIZE i64 counter_value; XID counter; #endif #endif /* RGFW_X11 */ #if defined(RGFW_WAYLAND) struct wl_surface *surface; struct xdg_surface *xdg_surface; struct xdg_toplevel *xdg_toplevel; struct zxdg_toplevel_decoration_v1 *decoration; struct zwp_locked_pointer_v1 *locked_pointer; struct xdg_toplevel_icon_v1 *icon; u32 decoration_mode; /* State flags to configure the window */ RGFW_bool pending_activated; RGFW_bool activated; RGFW_bool resizing; RGFW_bool pending_maximized; RGFW_bool maximized; RGFW_bool minimized; RGFW_bool using_custom_cursor; struct wl_surface *custom_cursor_surface; RGFW_monitor active_monitor; #ifdef RGFW_LIBDECOR struct libdecor *decorContext; #endif #endif /* RGFW_WAYLAND */ }; #elif defined(RGFW_MACOS) struct RGFW_nativeImage { RGFW_format format; }; #ifdef RGFW_OPENGL struct RGFW_glContext { void *ctx; }; #endif struct RGFW_window_src { void *window; void *view; /* apple viewpoint thingy */ void *mouse; #ifdef RGFW_OPENGL RGFW_gfxContext ctx; RGFW_gfxContextType gfxType; #endif }; #elif defined(RGFW_WASM) #include #include struct RGFW_nativeImage { RGFW_format format; }; #ifdef RGFW_OPENGL struct RGFW_glContext { EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx; }; #endif struct RGFW_window_src { #ifdef RGFW_OPENGL RGFW_gfxContext ctx; RGFW_gfxContextType gfxType; #endif }; #endif struct RGFW_surface { u8 *data; i32 w, h; RGFW_format format; RGFW_nativeImage native; }; /* ! internal window data that is not specific to the OS */ typedef struct RGFW_windowInternal { /* * ! which key RGFW_window_shouldClose checks. Settting this to * RGFW_keyNULL disables the feature. */ RGFW_key exitKey; i32 lastMouseX, lastMouseY; /* !< last cusor point (for raw * mouse data) */ RGFW_bool shouldClose; RGFW_bool holdMouse; RGFW_bool inFocus; RGFW_bool mouseInside; RGFW_keymod mod; RGFW_eventFlag enabledEvents; u32 flags; /* !< windows flags (for RGFW to check and * modify) */ i32 oldX, oldY, oldW, oldH; } RGFW_windowInternal; struct RGFW_window { RGFW_window_src src; /* !< src window data */ RGFW_windowInternal internal; /* !< internal window data that * is not specific to the OS */ void *userPtr; /* ptr for usr data */ i32 x, y, w, h; /* !< position and size of the window */ }; /* !< window structure for the window */ typedef struct RGFW_windowState { RGFW_bool mouseEnter; RGFW_bool dataDragging; RGFW_bool dataDrop; size_t filesCount; i32 dropX, dropY; RGFW_window *win; /* !< it's not possible for one of * these events to happen in the frame * that the other event happened */ RGFW_bool mouseLeave; RGFW_window *winLeave; /* !< if a mouse leaves one widow and * enters the next */ } RGFW_windowState; typedef struct { RGFW_bool current; RGFW_bool prev; } RGFW_keyState; #ifndef RGFW_NO_MONITOR typedef struct RGFW_monitorNode { RGFW_monitor mon; struct RGFW_monitorNode *next; #ifdef RGFW_WAYLAND u32 id; /* Add id so wl_outputs can be removed */ struct wl_output *output; struct zxdg_output_v1 *xdg_output; #endif } RGFW_monitorNode; typedef struct RGFW_monitorList { RGFW_monitorNode *head; RGFW_monitorNode *cur; } RGFW_monitorList; typedef struct RGFW_monitors { RGFW_monitorList list; RGFW_monitorList freeList; size_t count; RGFW_monitorNode data[RGFW_MAX_MONITORS]; } RGFW_monitors; RGFWDEF RGFW_monitorNode *RGFW_monitors_add(RGFW_monitor mon); RGFWDEF void RGFW_monitors_remove(RGFW_monitorNode * node, RGFW_monitorNode * prev); #endif struct RGFW_info { RGFW_window *root; i32 windowCount; RGFW_mouse *hiddenMouse; RGFW_event events[RGFW_MAX_EVENTS]; /* A circular buffer * (FIFO), using * eventBottom/Len */ i32 eventBottom; i32 eventLen; RGFW_bool queueEvents; RGFW_bool polledEvents; u32 apiKeycodes[RGFW_keyLast]; #if defined(RGFW_X11) || defined(RGFW_WAYLAND) u8 keycodes[256]; #elif defined(RGFW_WINDOWS) u8 keycodes[512]; #elif defined(RGFW_MACOS) u8 keycodes[128]; #elif defined(RGFW_WASM) u8 keycodes[256]; #endif const char *className; RGFW_bool useWaylandBool; RGFW_bool stopCheckEvents_bool; u64 timerOffset; char *clipboard_data; char filesSrc[RGFW_MAX_PATH * RGFW_MAX_DROPS]; char **files; #ifdef RGFW_X11 Display *display; XContext context; Window helperWindow; char *clipboard; /* for writing to the clipboard * selection */ size_t clipboard_len; const char *instName; XErrorEvent *x11Error; #endif #ifdef RGFW_WAYLAND struct wl_display *wl_display; struct xkb_context *xkb_context; struct xkb_keymap *keymap; struct xkb_state *xkb_state; struct zxdg_decoration_manager_v1 *decoration_manager; struct zwp_relative_pointer_manager_v1 *relative_pointer_manager; struct zwp_relative_pointer_v1 *relative_pointer; struct zwp_pointer_constraints_v1 *constraint_manager; struct xdg_toplevel_icon_manager_v1 *icon_manager; struct zxdg_output_manager_v1 *xdg_output_manager; struct wl_keyboard *wl_keyboard; struct wl_pointer *wl_pointer; struct wl_compositor *compositor; struct xdg_wm_base *xdg_wm_base; struct wl_shm *shm; struct wl_seat *seat; struct wl_registry *registry; u32 mouse_enter_serial; struct wl_cursor_theme *wl_cursor_theme; struct wl_surface *cursor_surface; RGFW_window *kbOwner; #endif RGFW_monitors monitors; #ifdef __linux__ int eventWait_forceStop[3]; #endif #ifdef RGFW_MACOS void *NSApp; void *customViewClasses[2]; /* NSView and NSOpenGLView */ void *customWindowDelegateClass; #endif #ifdef RGFW_OPENGL RGFW_window *current; #endif #ifdef RGFW_EGL void *EGL_display; #endif RGFW_window *mouseOwner; RGFW_windowState windowState; /* ! for checking window state * events */ RGFW_keyState mouseButtons[RGFW_mouseFinal]; RGFW_keyState keyboard[RGFW_keyLast]; float scrollX, scrollY; float vectorX, vectorY; }; #endif /* RGFW_NATIVE_HEADER */ #ifdef RGFW_IMPLEMENTATION /* global private API */ /* for C++ / C89 */ #define RGFW_eventQueuePushEx(eventInit) { RGFW_event e; eventInit; RGFW_eventQueuePush(&e); } RGFWDEF RGFW_window *RGFW_createWindowPlatform(const char *name, RGFW_windowFlags flags, RGFW_window * win); RGFWDEF void RGFW_window_closePlatform(RGFW_window * win); RGFWDEF void RGFW_window_focusLost(RGFW_window * win); RGFWDEF void RGFW_window_setFlagsInternal(RGFW_window * win, RGFW_windowFlags flags, RGFW_windowFlags cmpFlags); RGFWDEF void RGFW_initKeycodes(void); RGFWDEF void RGFW_initKeycodesPlatform(void); RGFWDEF void RGFW_resetPrevState(void); RGFWDEF void RGFW_resetKey(void); RGFWDEF void RGFW_unloadEGL(void); RGFWDEF void RGFW_updateKeyModsEx(RGFW_window * win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll); RGFWDEF void RGFW_updateKeyMods(RGFW_window * win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool scroll); RGFWDEF void RGFW_window_showMouseFlags(RGFW_window * win, RGFW_bool show); RGFWDEF void RGFW_updateKeyMod(RGFW_window * win, RGFW_keymod mod, RGFW_bool value); RGFWDEF void RGFW_setBit(u32 * var, u32 mask, RGFW_bool set); RGFWDEF void RGFW_splitBPP(u32 bpp, RGFW_monitorMode * mode); RGFWDEF void RGFW_captureCursor(RGFW_window * win); RGFWDEF void RGFW_releaseCursor(RGFW_window * win); RGFWDEF void RGFW_copyImageData64(u8 * dest_data, i32 w, i32 h, RGFW_format dest_format, u8 * src_data, RGFW_format src_format, RGFW_bool is64bit); RGFWDEF RGFW_bool RGFW_loadEGL(void); #ifdef RGFW_OPENGL typedef struct RGFW_attribStack { i32 *attribs; size_t count; size_t max; } RGFW_attribStack; RGFWDEF void RGFW_attribStack_init(RGFW_attribStack * stack, i32 * attribs, size_t max); RGFWDEF void RGFW_attribStack_pushAttrib(RGFW_attribStack * stack, i32 attrib); RGFWDEF void RGFW_attribStack_pushAttribs(RGFW_attribStack * stack, i32 attrib1, i32 attrib2); RGFWDEF RGFW_bool RGFW_extensionSupportedStr(const char *extensions, const char *ext, size_t len); #endif typedef struct RGFW_colorLayout { i32 r, g, b, a; } RGFW_colorLayout; #ifdef RGFW_X11 RGFWDEF void RGFW_XCreateWindow(XVisualInfo visual, const char *name, RGFW_windowFlags flags, RGFW_window * win); #endif #ifdef RGFW_MACOS RGFWDEF void RGFW_osx_initView(RGFW_window * win); #endif /* end of global private API defs */ RGFW_info *_RGFW = NULL; void RGFW_setInfo(RGFW_info * info) { _RGFW = info; } RGFW_info *RGFW_getInfo(void){ return _RGFW; } void *RGFW_alloc(size_t size) { return RGFW_ALLOC(size); } void RGFW_free(void *ptr){ RGFW_FREE(ptr); } void RGFW_useWayland(RGFW_bool wayland) { RGFW_init(); _RGFW->useWaylandBool = RGFW_BOOL(wayland); } RGFW_bool RGFW_usingWayland(void){ return _RGFW->useWaylandBool; } void RGFW_clipboard_switch(char *newstr); void RGFW_clipboard_switch(char *newstr){ if (_RGFW->clipboard_data != NULL) RGFW_FREE(_RGFW->clipboard_data); _RGFW->clipboard_data = newstr; } #define RGFW_CHECK_CLIPBOARD() \ if (size <= 0 && _RGFW->clipboard_data != NULL) \ return (const char*)_RGFW->clipboard_data; \ else if (size <= 0) \ return "\0"; const char *RGFW_readClipboard(size_t * len) { RGFW_ssize_t size = RGFW_readClipboardPtr(NULL, 0); RGFW_CHECK_CLIPBOARD(); char *str = (char *)RGFW_ALLOC((size_t) size); RGFW_ASSERT(str != NULL); str[0] = '\0'; size = RGFW_readClipboardPtr(str, (size_t) size); RGFW_CHECK_CLIPBOARD(); if (len != NULL) *len = (size_t) size; RGFW_clipboard_switch(str); return (const char *)str; } /* * RGFW_IMPLEMENTATION starts with generic RGFW defines * * This is the start of keycode data */ void RGFW_initKeycodes(void){ RGFW_MEMSET(_RGFW->keycodes, 0, sizeof(_RGFW->keycodes)); RGFW_initKeycodesPlatform(); u32 i, y; for (i = 0; i < RGFW_keyLast; i++) { for (y = 0; y < sizeof(_RGFW->keycodes); y++) { if (_RGFW->keycodes[y] == i) { _RGFW->apiKeycodes[i] = y; break; } } } RGFW_resetKey(); } u32 RGFW_apiKeyToRGFW(u32 keycode) { /* make sure the key isn't out of bounds */ if (keycode > sizeof(_RGFW->keycodes) / sizeof(u8)) return 0; return _RGFW->keycodes[keycode]; } u32 RGFW_rgfwToApiKey(u32 keycode) { /* make sure the key isn't out of bounds */ if (keycode > sizeof(_RGFW->apiKeycodes) / sizeof(u32)) return 0; return _RGFW->apiKeycodes[keycode]; } void RGFW_resetKey(void){ RGFW_MEMSET(_RGFW->keyboard, 0, sizeof(_RGFW->keyboard)); } /* * this is the end of keycode data */ /* * event callback defines start here */ /* * These exist to avoid the if (func == NULL) check for (allegedly) * better performance * * RGFW_EMPTY_DEF exists to prevent the missing-prototypes warning */ #define RGFW_CALLBACK_DEFINE(x, x2) \ RGFW_##x##func RGFW_##x##CallbackSrc = NULL; \ RGFW_##x##func RGFW_set##x2##Callback(RGFW_##x##func func) { \ RGFW_##x##func prev = RGFW_##x##CallbackSrc; \ RGFW_##x##CallbackSrc = func; \ return prev; \ } RGFW_CALLBACK_DEFINE(windowMaximized, WindowMaximized) #define RGFW_windowMaximizedCallback(win, x, y, w, h) if (RGFW_windowMaximizedCallbackSrc) RGFW_windowMaximizedCallbackSrc(win, x, y, w, h); RGFW_CALLBACK_DEFINE(windowMinimized, WindowMinimized) #define RGFW_windowMinimizedCallback(w) if (RGFW_windowMinimizedCallbackSrc) RGFW_windowMinimizedCallbackSrc(w); RGFW_CALLBACK_DEFINE(windowRestored, WindowRestored) #define RGFW_windowRestoredCallback(win, x, y, w, h) if (RGFW_windowRestoredCallbackSrc) RGFW_windowRestoredCallbackSrc(win, x, y, w, h); RGFW_CALLBACK_DEFINE(windowMoved, WindowMoved) #define RGFW_windowMovedCallback(w, x, y) if (RGFW_windowMovedCallbackSrc) RGFW_windowMovedCallbackSrc(w, x, y); RGFW_CALLBACK_DEFINE(windowResized, WindowResized) #define RGFW_windowResizedCallback(win, w, h) if (RGFW_windowResizedCallbackSrc) RGFW_windowResizedCallbackSrc(win, w, h); RGFW_CALLBACK_DEFINE(windowQuit, WindowQuit) #define RGFW_windowQuitCallback(w) if (RGFW_windowQuitCallbackSrc) RGFW_windowQuitCallbackSrc(w); RGFW_CALLBACK_DEFINE(mousePos, MousePos) #define RGFW_mousePosCallback(w, x, y, vecX, vecY) if (RGFW_mousePosCallbackSrc) RGFW_mousePosCallbackSrc(w, x, y, vecX, vecY); RGFW_CALLBACK_DEFINE(windowRefresh, WindowRefresh) #define RGFW_windowRefreshCallback(w) if (RGFW_windowRefreshCallbackSrc) RGFW_windowRefreshCallbackSrc(w); RGFW_CALLBACK_DEFINE(focus, Focus) #define RGFW_focusCallback(w, inFocus) if (RGFW_focusCallbackSrc) RGFW_focusCallbackSrc(w, inFocus); RGFW_CALLBACK_DEFINE(mouseNotify, MouseNotify) #define RGFW_mouseNotifyCallback(w, x, y, status) if (RGFW_mouseNotifyCallbackSrc) RGFW_mouseNotifyCallbackSrc(w, x, y, status); RGFW_CALLBACK_DEFINE(dataDrop, DataDrop) #define RGFW_dataDropCallback(w, files, count) if (RGFW_dataDropCallbackSrc) RGFW_dataDropCallbackSrc(w, files, count); RGFW_CALLBACK_DEFINE(dataDrag, DataDrag) #define RGFW_dataDragCallback(w, x, y) if (RGFW_dataDragCallbackSrc) RGFW_dataDragCallbackSrc(w, x, y); RGFW_CALLBACK_DEFINE(key, Key) #define RGFW_keyCallback(w, key, sym, mod, repeat, press) if (RGFW_keyCallbackSrc) RGFW_keyCallbackSrc(w, key, sym, mod, repeat, press); RGFW_CALLBACK_DEFINE(mouseButton, MouseButton) #define RGFW_mouseButtonCallback(w, button, press) if (RGFW_mouseButtonCallbackSrc) RGFW_mouseButtonCallbackSrc(w, button, press); RGFW_CALLBACK_DEFINE(mouseScroll, MouseScroll) #define RGFW_mouseScrollCallback(w, x, y) if (RGFW_mouseScrollCallbackSrc) RGFW_mouseScrollCallbackSrc(w, x, y); RGFW_CALLBACK_DEFINE(scaleUpdated, ScaleUpdated) #define RGFW_scaleUpdatedCallback(w, scaleX, scaleY) if (RGFW_scaleUpdatedCallbackSrc) RGFW_scaleUpdatedCallbackSrc(w, scaleX, scaleY); RGFW_CALLBACK_DEFINE(debug, Debug) #define RGFW_debugCallback(type, err, msg) if (RGFW_debugCallbackSrc) RGFW_debugCallbackSrc(type, err, msg); #undef RGFW_CALLBACK_DEFINE #ifdef RGFW_DEBUG #include #endif void RGFW_sendDebugInfo(RGFW_debugType type, RGFW_errorCode err, const char *msg){ RGFW_debugCallback(type, err, msg); #ifdef RGFW_DEBUG switch (type) { case RGFW_typeInfo:RGFW_PRINTF("RGFW INFO (%i %i): %s", type, err, msg); break; case RGFW_typeError:RGFW_PRINTF("RGFW DEBUG (%i %i): %s", type, err, msg); break; case RGFW_typeWarning:RGFW_PRINTF("RGFW WARNING (%i %i): %s", type, err, msg); break; default:break; } RGFW_PRINTF("\n"); #endif } void RGFW_window_checkMode(RGFW_window * win); void RGFW_window_checkMode(RGFW_window * win) { if (RGFW_window_isMinimized(win) && (win->internal.enabledEvents & RGFW_windowMinimizedFlag)) { win->internal.flags |= RGFW_windowMinimize; RGFW_eventQueuePushEx(e.type = RGFW_windowMinimized; e.common.win = win); RGFW_windowMinimizedCallback(win); } else if (RGFW_window_isMaximized(win) && (win->internal.enabledEvents & RGFW_windowMaximizedFlag)) { win->internal.flags |= RGFW_windowMaximize; RGFW_eventQueuePushEx(e.type = RGFW_windowMaximized; e.common.win = win); RGFW_windowMaximizedCallback(win, win->x, win->y, win->w, win->h); } else if ((((win->internal.flags & RGFW_windowMinimize) && !RGFW_window_isMaximized(win)) || (win->internal.flags & RGFW_windowMaximize && !RGFW_window_isMaximized(win))) && (win->internal.enabledEvents & RGFW_windowRestoredFlag)) { win->internal.flags &= ~(u32) RGFW_windowMinimize; if (RGFW_window_isMaximized(win) == RGFW_FALSE) win->internal.flags &= ~(u32) RGFW_windowMaximize; RGFW_eventQueuePushEx(e.type = RGFW_windowRestored; e.common.win = win); RGFW_windowRestoredCallback(win, win->x, win->y, win->w, win->h); } } /* * no more event call back defines */ size_t RGFW_sizeofInfo(void){ return sizeof(RGFW_info); } size_t RGFW_sizeofNativeImage(void){ return sizeof(RGFW_nativeImage); } size_t RGFW_sizeofSurface(void){ return sizeof(RGFW_surface); } size_t RGFW_sizeofWindow(void){ return sizeof(RGFW_window); } size_t RGFW_sizeofWindowSrc(void){ return sizeof(RGFW_window_src); } RGFW_window_src *RGFW_window_getSrc(RGFW_window * win) { return &win->src; } RGFW_bool RGFW_window_getPosition(RGFW_window * win, i32 * x, i32 * y) { if (x) *x = win->x; if (y) *y = win->y; return RGFW_TRUE; } RGFW_bool RGFW_window_getSize(RGFW_window * win, i32 * w, i32 * h) { if (w) *w = win->w; if (h) *h = win->h; return RGFW_TRUE; } u32 RGFW_window_getFlags(RGFW_window * win) { return win->internal.flags; } RGFW_key RGFW_window_getExitKey(RGFW_window * win) { return win->internal.exitKey; } void RGFW_window_setExitKey(RGFW_window * win, RGFW_key key) { win->internal.exitKey = key; } void RGFW_window_setEnabledEvents(RGFW_window * win, RGFW_eventFlag events) { win->internal.enabledEvents = events; } RGFW_eventFlag RGFW_window_getEnabledEvents(RGFW_window * win) { return win->internal.enabledEvents; } void RGFW_window_setDisabledEvents(RGFW_window * win, RGFW_eventFlag events) { RGFW_window_setEnabledEvents(win, (RGFW_allEventFlags) & ~(u32) events); } void RGFW_window_setEventState(RGFW_window * win, RGFW_eventFlag event, RGFW_bool state) { RGFW_setBit(&win->internal.enabledEvents, event, state); } void *RGFW_window_getUserPtr(RGFW_window * win) { return win->userPtr; } void RGFW_window_setUserPtr(RGFW_window * win, void *ptr){ win->userPtr = ptr; } #if defined(RGFW_USE_XDL) && defined(RGFW_X11) #define XDL_IMPLEMENTATION #include "XDL.h" #endif #ifndef RGFW_FORCE_INIT RGFW_info _rgfwGlobal; #endif i32 RGFW_init(void){ return RGFW_init_ptr(&_rgfwGlobal); } void RGFW_deinit(void){ RGFW_deinit_ptr(&_rgfwGlobal); } i32 RGFW_initPlatform(void); void RGFW_deinitPlatform(void); i32 RGFW_init_ptr(RGFW_info * info) { if (info == _RGFW || info == NULL) return 1; RGFW_setInfo(info); RGFW_MEMSET(_RGFW, 0, sizeof(RGFW_info)); _RGFW->queueEvents = RGFW_FALSE; _RGFW->polledEvents = RGFW_FALSE; #ifdef RGFW_WAYLAND _RGFW->useWaylandBool = RGFW_TRUE; #endif _RGFW->files = (char **)(void *)_RGFW->filesSrc; u32 i; for (i = 0; i < RGFW_MAX_DROPS; i++) _RGFW->files[i] = (char *)(_RGFW->filesSrc + RGFW_MAX_DROPS + (i * RGFW_MAX_PATH)); _RGFW->monitors.freeList.head = &_RGFW->monitors.data[0]; _RGFW->monitors.freeList.cur = _RGFW->monitors.freeList.head; for (i = 1; i < RGFW_MAX_MONITORS; i++) { RGFW_monitorNode *newNode = &_RGFW->monitors.data[i]; _RGFW->monitors.freeList.cur->next = newNode; _RGFW->monitors.freeList.cur = _RGFW->monitors.freeList.cur->next; } RGFW_initKeycodes(); i32 out = RGFW_initPlatform(); RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, "global context initialized"); return out; } #ifndef RGFW_EGL void RGFW_unloadEGL(void){ } #endif void RGFW_deinit_ptr(RGFW_info * info) { if (info == NULL) return; RGFW_setInfo(info); RGFW_unloadEGL(); RGFW_deinitPlatform(); _RGFW->root = NULL; _RGFW->windowCount = 0; RGFW_setInfo(NULL); RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, "global context deinitialized"); } RGFW_window *RGFW_createWindow(const char *name, i32 x, i32 y, i32 w, i32 h, RGFW_windowFlags flags){ RGFW_window *win = (RGFW_window *) RGFW_ALLOC(sizeof(RGFW_window)); RGFW_ASSERT(win != NULL); return RGFW_createWindowPtr(name, x, y, w, h, flags, win); } void RGFW_window_close(RGFW_window * win) { RGFW_ASSERT(win != NULL); RGFW_window_closePtr(win); RGFW_FREE(win); } RGFW_window *RGFW_createWindowPtr(const char *name, i32 x, i32 y, i32 w, i32 h, RGFW_windowFlags flags, RGFW_window * win){ RGFW_ASSERT(win != NULL); RGFW_MEMSET(win, 0, sizeof(RGFW_window)); if (_RGFW == NULL) RGFW_init(); _RGFW->windowCount++; /* rect based the requested flags */ if (_RGFW->root == NULL) { RGFW_setRootWindow(win); } /* set and init the new window's data */ win->x = x; win->y = y; win->w = w; win->h = h; win->internal.flags = flags; win->internal.enabledEvents = RGFW_allEventFlags; RGFW_window *ret = RGFW_createWindowPlatform(name, flags, win); #ifndef RGFW_X11 RGFW_window_setFlagsInternal(win, flags, 0); #endif #ifdef RGFW_OPENGL win->src.gfxType = 0; if (flags & RGFW_windowOpenGL) RGFW_window_createContext_OpenGL(win, RGFW_getGlobalHints_OpenGL()); #endif #ifdef RGFW_EGL if (flags & RGFW_windowEGL) RGFW_window_createContext_EGL(win, RGFW_getGlobalHints_OpenGL()); #endif /* * X11 creates the window after the OpenGL context is created * (because of visual garbage), so we have to wait to set the * flags This is required so that way the user can create their * own OpenGL context after RGFW_createWindow is used if a * window is crated, CreateContext will delete the window and * create a new one */ #ifdef RGFW_X11 RGFW_window_setFlagsInternal(win, flags, 0); #endif #ifdef RGFW_MACOS /* * NOTE: another OpenGL/setFlags related hack, this because OSX * the 'view' class must be setup after the NSOpenGL view is * made AND after setFlags happens */ RGFW_osx_initView(win); #endif #ifdef RGFW_WAYLAND //recieve all events needed to configure the surface // also gets the wl_outputs if (RGFW_usingWayland()) { wl_display_roundtrip(_RGFW->wl_display); /* * NOTE: this is a hack so that way wayland spawns a * window, even if nothing is drawn */ if (!(flags & RGFW_windowOpenGL) && !(flags & RGFW_windowEGL)) { u8 *data = (u8 *) RGFW_ALLOC((u32) (win->w * win->h * 3)); RGFW_MEMSET(data, 0, (u32) (win->w * win->h * 3) * sizeof(u8)); RGFW_surface *surface = RGFW_createSurface(data, win->w, win->h, RGFW_formatBGR8); RGFW_window_blitSurface(win, surface); RGFW_FREE(data); RGFW_surface_free(surface); } } #endif RGFW_window_setMouseDefault(win); RGFW_window_setName(win, name); if (!(flags & RGFW_windowHide)) { RGFW_window_show(win); } RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, "a new window was created"); return ret; } void RGFW_window_closePtr(RGFW_window * win) { RGFW_ASSERT(win != NULL); #ifdef RGFW_EGL if ((win->src.gfxType & RGFW_gfxEGL) && win->src.ctx.egl) { RGFW_window_deleteContext_EGL(win, win->src.ctx.egl); win->src.ctx.egl = NULL; } #endif #ifdef RGFW_OPENGL if ((win->src.gfxType & RGFW_gfxNativeOpenGL) && win->src.ctx.native) { RGFW_window_deleteContext_OpenGL(win, win->src.ctx.native); win->src.ctx.native = NULL; } #endif RGFW_window_closePlatform(win); RGFW_clipboard_switch(NULL); _RGFW->windowCount--; if (_RGFW->windowCount == 0) RGFW_deinit(); RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, "a window was freed"); } void RGFW_setQueueEvents(RGFW_bool queue) { _RGFW->queueEvents = RGFW_BOOL(queue); } void RGFW_eventQueueFlush(void){ _RGFW->eventLen = 0; } void RGFW_eventQueuePush(const RGFW_event * event){ if (_RGFW->queueEvents == RGFW_FALSE) return; RGFW_ASSERT(_RGFW->eventLen >= 0); if (_RGFW->eventLen >= RGFW_MAX_EVENTS) { RGFW_sendDebugInfo(RGFW_typeError, RGFW_errEventQueue, "Event queue limit 'RGFW_MAX_EVENTS' has been reached automatically flushing queue."); RGFW_eventQueueFlush(); return; } i32 eventTop = (_RGFW->eventBottom + _RGFW->eventLen) % RGFW_MAX_EVENTS; _RGFW->eventLen += 1; _RGFW->events[eventTop] = *event; } RGFW_event *RGFW_eventQueuePop(RGFW_window * win) { RGFW_ASSERT(_RGFW->eventLen >= 0 && _RGFW->eventLen <= RGFW_MAX_EVENTS); RGFW_event *ev; if (_RGFW->eventLen == 0) { return NULL; } ev = &_RGFW->events[_RGFW->eventBottom]; _RGFW->eventLen -= 1; _RGFW->eventBottom = (_RGFW->eventBottom + 1) % RGFW_MAX_EVENTS; if (ev->common.win != win && ev->common.win != NULL) { RGFW_eventQueuePush(ev); return NULL; } return ev; } void RGFW_resetPrevState(void){ size_t i; /* !< reset each previous state */ for (i = 0; i < RGFW_keyLast; i++) _RGFW->keyboard[i].prev = _RGFW->keyboard[i].current; for (i = 0; i < RGFW_mouseFinal; i++) _RGFW->mouseButtons[i].prev = _RGFW->mouseButtons[i].current; _RGFW->scrollX = 0.0f; _RGFW->scrollY = 0.0f; _RGFW->vectorX = (float)0.0f; _RGFW->vectorY = (float)0.0f; RGFW_MEMSET(&_RGFW->windowState, 0, sizeof(_RGFW->windowState)); } RGFW_bool RGFW_isKeyPressed(RGFW_key key) { return _RGFW != NULL && _RGFW->keyboard[key].current && !_RGFW->keyboard[key].prev; } RGFW_bool RGFW_isKeyDown(RGFW_key key) { return _RGFW != NULL && _RGFW->keyboard[key].current; } RGFW_bool RGFW_isKeyReleased(RGFW_key key) { return _RGFW != NULL && !_RGFW->keyboard[key].current && _RGFW->keyboard[key].prev; } RGFW_bool RGFW_isMousePressed(RGFW_mouseButton button) { return _RGFW != NULL && _RGFW->mouseButtons[button].current && !_RGFW->mouseButtons[button].prev; } RGFW_bool RGFW_isMouseDown(RGFW_mouseButton button) { return _RGFW != NULL && _RGFW->mouseButtons[button].current; } RGFW_bool RGFW_isMouseReleased(RGFW_mouseButton button) { return _RGFW != NULL && !_RGFW->mouseButtons[button].current && _RGFW->mouseButtons[button].prev; } void RGFW_getMouseScroll(float *x, float *y){ RGFW_ASSERT(_RGFW != NULL); if (x) *x = _RGFW->scrollX; if (y) *y = _RGFW->scrollY; } void RGFW_getMouseVector(float *x, float *y){ RGFW_ASSERT(_RGFW != NULL); if (x) *x = _RGFW->vectorX; if (y) *y = _RGFW->vectorY; } RGFW_bool RGFW_window_didMouseLeave(RGFW_window * win) { return _RGFW->windowState.winLeave == win && _RGFW->windowState.mouseLeave; } RGFW_bool RGFW_window_didMouseEnter(RGFW_window * win) { return _RGFW->windowState.win == win && _RGFW->windowState.mouseEnter; } RGFW_bool RGFW_window_isMouseInside(RGFW_window * win) { return win->internal.mouseInside; } RGFW_bool RGFW_window_isDataDragging(RGFW_window * win) { return RGFW_window_getDataDrag(win, (i32 *) NULL, (i32 *) NULL); } RGFW_bool RGFW_window_didDataDrop(RGFW_window * win) { return RGFW_window_getDataDrop(win, (const char ***)NULL, (size_t *) NULL); } RGFW_bool RGFW_window_getDataDrag(RGFW_window * win, i32 * x, i32 * y) { if (_RGFW->windowState.win != win || _RGFW->windowState.dataDragging == RGFW_FALSE) return RGFW_FALSE; if (x) *x = _RGFW->windowState.dropX; if (y) *y = _RGFW->windowState.dropY; return RGFW_TRUE; } RGFW_bool RGFW_window_getDataDrop(RGFW_window * win, const char ***files, size_t * count){ if (_RGFW->windowState.win != win || _RGFW->windowState.dataDrop == RGFW_FALSE) return RGFW_FALSE; if (files) *files = (const char **)_RGFW->files; if (count) *count = _RGFW->windowState.filesCount; return RGFW_TRUE; } RGFW_bool RGFW_window_checkEvent(RGFW_window * win, RGFW_event * event) { if (_RGFW->eventLen == 0 && _RGFW->polledEvents == RGFW_FALSE) { _RGFW->queueEvents = RGFW_TRUE; RGFW_pollEvents(); _RGFW->polledEvents = RGFW_TRUE; } if (RGFW_window_checkQueuedEvent(win, event) == RGFW_FALSE) { _RGFW->polledEvents = RGFW_FALSE; return RGFW_FALSE; } return RGFW_TRUE; } RGFW_bool RGFW_window_checkQueuedEvent(RGFW_window * win, RGFW_event * event) { RGFW_event *ev; RGFW_ASSERT(win != NULL); _RGFW->queueEvents = RGFW_TRUE; /* check queued events */ ev = RGFW_eventQueuePop(win); if (ev != NULL) { if (ev->type == RGFW_quit) RGFW_window_setShouldClose(win, RGFW_TRUE); *event = *ev; return RGFW_TRUE; } return RGFW_FALSE; } void RGFW_setRootWindow(RGFW_window * win) { _RGFW->root = win; } RGFW_window *RGFW_getRootWindow(void){ return _RGFW->root; } #ifndef RGFW_EGL RGFW_bool RGFW_loadEGL(void){ return RGFW_FALSE; } #endif void RGFW_window_setFlagsInternal(RGFW_window * win, RGFW_windowFlags flags, RGFW_windowFlags cmpFlags) { #ifndef RGFW_NO_MONITOR if (flags & RGFW_windowScaleToMonitor) RGFW_window_scaleToMonitor(win); #endif if (flags & RGFW_windowCenter) RGFW_window_center(win); if (flags & RGFW_windowCenterCursor) RGFW_window_moveMouse(win, win->x + (win->w / 2), win->y + (win->h / 2)); if (flags & RGFW_windowNoBorder) RGFW_window_setBorder(win, 0); else if (cmpFlags & RGFW_windowNoBorder) RGFW_window_setBorder(win, 1); if (flags & RGFW_windowFullscreen) RGFW_window_setFullscreen(win, RGFW_TRUE); else if (cmpFlags & RGFW_windowFullscreen) RGFW_window_setFullscreen(win, 0); if (flags & RGFW_windowMaximize) RGFW_window_maximize(win); else if (cmpFlags & RGFW_windowMaximize) RGFW_window_restore(win); if (flags & RGFW_windowMinimize) RGFW_window_minimize(win); else if (cmpFlags & RGFW_windowMinimize) RGFW_window_restore(win); if (flags & RGFW_windowHideMouse) RGFW_window_showMouse(win, 0); else if (cmpFlags & RGFW_windowHideMouse) RGFW_window_showMouse(win, 1); if (flags & RGFW_windowHide) RGFW_window_hide(win); else if (cmpFlags & RGFW_windowHide) RGFW_window_show(win); if (flags & RGFW_windowFloating) RGFW_window_setFloating(win, 1); else if (cmpFlags & RGFW_windowFloating) RGFW_window_setFloating(win, 0); if (flags & RGFW_windowFocus) RGFW_window_focus(win); if (flags & RGFW_windowNoResize) { RGFW_window_setMaxSize(win, win->w, win->h); RGFW_window_setMinSize(win, win->w, win->h); } else if (cmpFlags & RGFW_windowNoResize) { RGFW_window_setMaxSize(win, 0, 0); RGFW_window_setMinSize(win, 0, 0); } win->internal.flags = flags; } void RGFW_window_setFlags(RGFW_window * win, RGFW_windowFlags flags) { RGFW_window_setFlagsInternal(win, flags, win->internal.flags); } RGFW_bool RGFW_window_isInFocus(RGFW_window * win) { #ifdef RGFW_WASM return RGFW_TRUE; #else return RGFW_BOOL(win->internal.inFocus); #endif } void RGFW_setClassName(const char *name){ RGFW_init(); _RGFW->className = name; } #ifndef RGFW_X11 void RGFW_setXInstName(const char *name){ RGFW_UNUSED(name); } #endif RGFW_bool RGFW_window_getMouse(RGFW_window * win, i32 * x, i32 * y) { RGFW_ASSERT(win != NULL); if (x) *x = win->internal.lastMouseX; if (y) *y = win->internal.lastMouseY; return RGFW_TRUE; } RGFW_bool RGFW_window_isKeyPressed(RGFW_window * win, RGFW_key key) { return RGFW_isKeyPressed(key) && RGFW_window_isInFocus(win); } RGFW_bool RGFW_window_isKeyDown(RGFW_window * win, RGFW_key key) { return RGFW_isKeyDown(key) && RGFW_window_isInFocus(win); } RGFW_bool RGFW_window_isKeyReleased(RGFW_window * win, RGFW_key key) { return RGFW_isKeyReleased(key) && RGFW_window_isInFocus(win); } RGFW_bool RGFW_window_isMousePressed(RGFW_window * win, RGFW_mouseButton button) { return RGFW_isMousePressed(button) && RGFW_window_isInFocus(win); } RGFW_bool RGFW_window_isMouseDown(RGFW_window * win, RGFW_mouseButton button) { return RGFW_isMouseDown(button) && RGFW_window_isInFocus(win); } RGFW_bool RGFW_window_isMouseReleased(RGFW_window * win, RGFW_mouseButton button) { return RGFW_isMouseReleased(button) && RGFW_window_isInFocus(win); } #ifndef RGFW_X11 void *RGFW_getDisplay_X11(void){ return NULL; } u64 RGFW_window_getWindow_X11(RGFW_window * win) { RGFW_UNUSED(win); return 0; } #endif #ifndef RGFW_WAYLAND struct wl_display *RGFW_getDisplay_Wayland(void){ return NULL; } struct wl_surface *RGFW_window_getWindow_Wayland(RGFW_window * win) { RGFW_UNUSED(win); return NULL; } #endif #ifndef RGFW_WINDOWS void *RGFW_window_getHWND(RGFW_window * win) { RGFW_UNUSED(win); return NULL; } void *RGFW_window_getHDC(RGFW_window * win) { RGFW_UNUSED(win); return NULL; } #endif #ifndef RGFW_MACOS void *RGFW_window_getView_OSX(RGFW_window * win) { RGFW_UNUSED(win); return NULL; } void RGFW_window_setLayer_OSX(RGFW_window * win, void *layer){ RGFW_UNUSED(win); RGFW_UNUSED(layer); } void *RGFW_getLayer_OSX(void){ return NULL; } void *RGFW_window_getWindow_OSX(RGFW_window * win) { RGFW_UNUSED(win); return NULL; } #endif void RGFW_setBit(u32 * var, u32 mask, RGFW_bool set) { if (set) *var |= mask; else *var &= ~mask; } void RGFW_window_center(RGFW_window * win) { RGFW_ASSERT(win != NULL); RGFW_monitor mon = RGFW_window_getMonitor(win); RGFW_window_move(win, (i32) (mon.mode.w - win->w) / 2, (mon.mode.h - win->h) / 2); } RGFW_bool RGFW_monitor_scaleToWindow(RGFW_monitor mon, RGFW_window * win) { RGFW_monitorMode mode; RGFW_ASSERT(win != NULL); mode.w = win->w; mode.h = win->h; return RGFW_monitor_requestMode(mon, mode, RGFW_monitorScale); } void RGFW_splitBPP(u32 bpp, RGFW_monitorMode * mode) { if (bpp == 32) bpp = 24; mode->red = mode->green = mode->blue = (u8) (bpp / 3); u32 delta = bpp - (mode->red * 3); /* handle leftovers */ if (delta >= 1) mode->green = mode->green + 1; if (delta == 2) mode->red = mode->red + 1; } RGFW_bool RGFW_monitorModeCompare(RGFW_monitorMode mon, RGFW_monitorMode mon2, RGFW_modeRequest request) { return (((mon.w == mon2.w && mon.h == mon2.h) || !(request & RGFW_monitorScale)) && ((mon.refreshRate == mon2.refreshRate) || !(request & RGFW_monitorRefresh)) && ((mon.red == mon2.red && mon.green == mon2.green && mon.blue == mon2.blue) || !(request & RGFW_monitorRGB))); } RGFW_bool RGFW_window_shouldClose(RGFW_window * win) { return (win == NULL || win->internal.shouldClose || (win->internal.exitKey && RGFW_window_isKeyPressed(win, win->internal.exitKey))); } void RGFW_window_setShouldClose(RGFW_window * win, RGFW_bool shouldClose) { if (shouldClose) { win->internal.shouldClose = RGFW_TRUE; RGFW_windowQuitCallback(win); } else { win->internal.shouldClose = RGFW_FALSE; } } #ifndef RGFW_NO_MONITOR void RGFW_window_scaleToMonitor(RGFW_window * win) { RGFW_monitor monitor = RGFW_window_getMonitor(win); if (monitor.scaleX == 0 && monitor.scaleY == 0) return; RGFW_window_resize(win, (i32) (monitor.scaleX * (float)win->w), (i32) (monitor.scaleY * (float)win->h)); } void RGFW_window_moveToMonitor(RGFW_window * win, RGFW_monitor m) { RGFW_window_move(win, m.x + win->x, m.y + win->y); } #endif RGFW_surface *RGFW_createSurface(u8 * data, i32 w, i32 h, RGFW_format format) { RGFW_surface *surface = (RGFW_surface *) RGFW_ALLOC(sizeof(RGFW_surface)); RGFW_MEMSET(surface, 0, sizeof(RGFW_surface)); RGFW_createSurfacePtr(data, w, h, format, surface); return surface; } void RGFW_surface_free(RGFW_surface * surface) { RGFW_surface_freePtr(surface); RGFW_FREE(surface); } RGFW_nativeImage *RGFW_surface_getNativeImage(RGFW_surface * surface) { return &surface->native; } RGFW_surface *RGFW_window_createSurface(RGFW_window * win, u8 * data, i32 w, i32 h, RGFW_format format) { RGFW_surface *surface = (RGFW_surface *) RGFW_ALLOC(sizeof(RGFW_surface)); RGFW_MEMSET(surface, 0, sizeof(RGFW_surface)); RGFW_window_createSurfacePtr(win, data, w, h, format, surface); return surface; } #ifndef RGFW_X11 RGFW_bool RGFW_window_createSurfacePtr(RGFW_window * win, u8 * data, i32 w, i32 h, RGFW_format format, RGFW_surface * surface) { RGFW_UNUSED(win); return RGFW_createSurfacePtr(data, w, h, format, surface); } #endif const RGFW_colorLayout RGFW_layouts[RGFW_formatCount] = { {0, 1, 2, 3}, /* RGFW_formatRGB8 */ {2, 1, 0, 3}, /* RGFW_formatBGR8 */ {0, 1, 2, 3}, /* RGFW_formatRGBA8 */ {1, 2, 3, 0}, /* RGFW_formatARGB8 */ {2, 1, 0, 3}, /* RGFW_formatBGRA8 */ {3, 2, 1, 0}, /* RGFW_formatABGR8 */ }; void RGFW_copyImageData(u8 * dest_data, i32 w, i32 h, RGFW_format dest_format, u8 * src_data, RGFW_format src_format) { RGFW_copyImageData64(dest_data, w, h, dest_format, src_data, src_format, RGFW_FALSE); } void RGFW_copyImageData64(u8 * dest_data, i32 dest_w, i32 dest_h, RGFW_format dest_format, u8 * src_data, RGFW_format src_format, RGFW_bool is64bit) { RGFW_ASSERT(dest_data && src_data); u32 src_channels = (src_format >= RGFW_formatRGBA8) ? 4 : 3; u32 dest_channels = (dest_format >= RGFW_formatRGBA8) ? 4 : 3; u32 pixel_count = (u32) (dest_w * dest_h); if (src_format == dest_format) { RGFW_MEMCPY(dest_data, src_data, pixel_count * dest_channels); return; } const RGFW_colorLayout *src_layout = &RGFW_layouts[src_format]; const RGFW_colorLayout *dest_layout = &RGFW_layouts[dest_format]; u32 i, i2 = 0; for (i = 0; i < pixel_count; i++) { const u8 *src_px = &src_data[i * src_channels]; u8 *dst_px = &dest_data[i2 * dest_channels]; u8 rgba[4] = {src_px[src_layout->r], src_px[src_layout->g], src_px[src_layout->b], 255}; if (src_channels == 4) rgba[3] = src_px[src_layout->a]; dst_px[dest_layout->r] = rgba[0]; dst_px[dest_layout->g] = rgba[1]; dst_px[dest_layout->b] = rgba[2]; if (dest_channels == 4) dst_px[dest_layout->a] = rgba[3]; i2 += 1 + is64bit; } } RGFW_monitorNode *RGFW_monitors_add(RGFW_monitor mon) { RGFW_monitorNode *node = NULL; if (_RGFW->monitors.freeList.head == NULL) return node; node = _RGFW->monitors.freeList.head; mon = node->mon; _RGFW->monitors.freeList.head = node->next; if (_RGFW->monitors.freeList.head == NULL) { _RGFW->monitors.freeList.cur = NULL; } node->next = NULL; if (_RGFW->monitors.list.head == NULL) { _RGFW->monitors.list.head = node; } else { _RGFW->monitors.list.cur->next = node; } _RGFW->monitors.list.cur = node; node->mon = mon; _RGFW->monitors.count += 1; return node; } void RGFW_monitors_remove(RGFW_monitorNode * node, RGFW_monitorNode * prev) { _RGFW->monitors.count -= 1; /* remove node from the list */ if (prev != node) { prev->next = node->next; } else { /* node is the head */ _RGFW->monitors.list.head = NULL; } node->next = NULL; /* move node to the free list */ if (_RGFW->monitors.freeList.head == NULL) { _RGFW->monitors.freeList.head = node; } else { _RGFW->monitors.freeList.cur->next = node; } _RGFW->monitors.freeList.cur = node; } RGFW_bool RGFW_window_setIcon(RGFW_window * win, u8 * data, i32 w, i32 h, RGFW_format format) { return RGFW_window_setIconEx(win, data, w, h, format, RGFW_iconBoth); } void RGFW_window_holdMouse(RGFW_window * win) { win->internal.holdMouse = RGFW_TRUE; _RGFW->mouseOwner = win; RGFW_captureCursor(win); RGFW_window_moveMouse(win, win->x + (win->w / 2), win->y + (win->h / 2)); } RGFW_bool RGFW_window_isHoldingMouse(RGFW_window * win) { return RGFW_BOOL(win->internal.holdMouse); } void RGFW_window_unholdMouse(RGFW_window * win) { win->internal.holdMouse = RGFW_FALSE; _RGFW->mouseOwner = NULL; RGFW_releaseCursor(win); } void RGFW_updateKeyMod(RGFW_window * win, RGFW_keymod mod, RGFW_bool value) { if (value) win->internal.mod |= mod; else win->internal.mod &= ~mod; } void RGFW_updateKeyModsEx(RGFW_window * win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll) { RGFW_updateKeyMod(win, RGFW_modCapsLock, capital); RGFW_updateKeyMod(win, RGFW_modNumLock, numlock); RGFW_updateKeyMod(win, RGFW_modControl, control); RGFW_updateKeyMod(win, RGFW_modAlt, alt); RGFW_updateKeyMod(win, RGFW_modShift, shift); RGFW_updateKeyMod(win, RGFW_modSuper, super); RGFW_updateKeyMod(win, RGFW_modScrollLock, scroll); } void RGFW_updateKeyMods(RGFW_window * win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool scroll) { RGFW_updateKeyModsEx(win, capital, numlock, RGFW_window_isKeyDown(win, RGFW_controlL) || RGFW_window_isKeyDown(win, RGFW_controlR), RGFW_window_isKeyDown(win, RGFW_altL) || RGFW_window_isKeyDown(win, RGFW_altR), RGFW_window_isKeyDown(win, RGFW_shiftL) || RGFW_window_isKeyDown(win, RGFW_shiftR), RGFW_window_isKeyDown(win, RGFW_superL) || RGFW_window_isKeyDown(win, RGFW_superR), scroll); } void RGFW_window_showMouseFlags(RGFW_window * win, RGFW_bool show) { if (show && (win->internal.flags & RGFW_windowHideMouse)) win->internal.flags ^= RGFW_windowHideMouse; else if (!show && !(win->internal.flags & RGFW_windowHideMouse)) win->internal.flags |= RGFW_windowHideMouse; } RGFW_bool RGFW_window_isMouseHidden(RGFW_window * win) { return (RGFW_bool) RGFW_BOOL(((RGFW_window *) win)->internal.flags & RGFW_windowHideMouse); } RGFW_bool RGFW_window_borderless(RGFW_window * win) { return (RGFW_bool) RGFW_BOOL(win->internal.flags & RGFW_windowNoBorder); } RGFW_bool RGFW_window_isFullscreen(RGFW_window * win) { return RGFW_BOOL(win->internal.flags & RGFW_windowFullscreen); } RGFW_bool RGFW_window_allowsDND(RGFW_window * win) { return RGFW_BOOL(win->internal.flags & RGFW_windowAllowDND); } void RGFW_window_focusLost(RGFW_window * win) { /* standard routines for when a window looses focus */ win->internal.inFocus = RGFW_FALSE; if ((win->internal.flags & RGFW_windowFullscreen)) RGFW_window_minimize(win); size_t key; for (key = 0; key < RGFW_keyLast; key++) { if (RGFW_isKeyDown((u8) key) == RGFW_FALSE) continue; _RGFW->keyboard[key].current = RGFW_FALSE; u8 sym = RGFW_rgfwToKeyChar((u32) key); if ((win->internal.enabledEvents & RGFW_BIT(RGFW_keyReleased))) { RGFW_keyCallback(win, (u8) key, sym, win->internal.mod, RGFW_FALSE, RGFW_FALSE); RGFW_eventQueuePushEx(e.type = RGFW_keyReleased; e.key.value = (u8) key; e.key.sym = sym; e.key.repeat = RGFW_FALSE; e.key.mod = win->internal.mod; e.common.win = win); } } RGFW_resetKey(); } #ifndef RGFW_WINDOWS void RGFW_window_setDND(RGFW_window * win, RGFW_bool allow) { RGFW_setBit(&win->internal.flags, RGFW_windowAllowDND, allow); } #endif #if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WASM) || defined(RGFW_WAYLAND) #ifndef __USE_POSIX199309 #define __USE_POSIX199309 #endif #include struct timespec; #endif #if defined(RGFW_WAYLAND) || defined(RGFW_X11) || defined(RGFW_WINDOWS) void RGFW_window_showMouse(RGFW_window * win, RGFW_bool show) { RGFW_window_showMouseFlags(win, show); if (show == RGFW_FALSE) RGFW_window_setMouse(win, _RGFW->hiddenMouse); else RGFW_window_setMouseDefault(win); } #endif #ifndef RGFW_MACOS void RGFW_moveToMacOSResourceDir(void){ } #endif /* * graphics API specific code (end of generic code) starts here */ /* * OpenGL defines start here (Normal, EGL, OSMesa) */ #if defined(RGFW_OPENGL) /* EGL, OpenGL */ #define RGFW_DEFAULT_GL_HINTS { \ /* Stencil */ 0, \ /* Samples */ 0, \ /* Stereo */ RGFW_FALSE, \ /* AuxBuffers */ 0, \ /* DoubleBuffer */ RGFW_TRUE, \ /* Red */ 8, \ /* Green */ 8, \ /* Blue */ 8, \ /* Alpha */ 8, \ /* Depth */ 24, \ /* AccumRed */ 0, \ /* AccumGreen */ 0, \ /* AccumBlue */ 0, \ /* AccumAlpha */ 0, \ /* SRGB */ RGFW_FALSE, \ /* Robustness */ RGFW_FALSE, \ /* Debug */ RGFW_FALSE, \ /* NoError */ RGFW_FALSE, \ /* ReleaseBehavior */ RGFW_glReleaseNone, \ /* Profile */ RGFW_glCore, \ /* Major */ 1, \ /* Minor */ 0, \ /* Share */ NULL, \ /* Share_EGL */ NULL, \ /* renderer */ RGFW_glAccelerated \ } RGFW_glHints RGFW_globalHints_OpenGL_SRC = RGFW_DEFAULT_GL_HINTS; RGFW_glHints *RGFW_globalHints_OpenGL = &RGFW_globalHints_OpenGL_SRC; void RGFW_resetGlobalHints_OpenGL(void){ #if !defined(__cplusplus) || defined(RGFW_MACOS) RGFW_globalHints_OpenGL_SRC = (RGFW_glHints) RGFW_DEFAULT_GL_HINTS; #else RGFW_globalHints_OpenGL_SRC = RGFW_DEFAULT_GL_HINTS; #endif } void RGFW_setGlobalHints_OpenGL(RGFW_glHints * hints) { RGFW_globalHints_OpenGL = hints; } RGFW_glHints *RGFW_getGlobalHints_OpenGL(void){ RGFW_init(); return RGFW_globalHints_OpenGL; } void *RGFW_glContext_getSourceContext(RGFW_glContext * ctx) { RGFW_UNUSED(ctx); #ifdef RGFW_WAYLAND if (RGFW_usingWayland()) return (void *)ctx->egl.ctx; #endif #if defined(RGFW_X11) return (void *)ctx->ctx; #else return NULL; #endif } RGFW_glContext *RGFW_window_createContext_OpenGL(RGFW_window * win, RGFW_glHints * hints) { #ifdef RGFW_WAYLAND if (RGFW_usingWayland()) { return (RGFW_glContext *) RGFW_window_createContext_EGL(win, hints); } #endif RGFW_glContext *ctx = (RGFW_glContext *) RGFW_ALLOC(sizeof(RGFW_glContext)); if (RGFW_window_createContextPtr_OpenGL(win, ctx, hints) == RGFW_FALSE) { RGFW_FREE(ctx); win->src.ctx.native = NULL; return NULL; } win->src.gfxType |= RGFW_gfxOwnedByRGFW; return ctx; } RGFW_glContext *RGFW_window_getContext_OpenGL(RGFW_window * win) { if (win->src.gfxType & RGFW_windowEGL) return NULL; return win->src.ctx.native; } void RGFW_window_deleteContext_OpenGL(RGFW_window * win, RGFW_glContext * ctx) { RGFW_window_deleteContextPtr_OpenGL(win, ctx); if (win->src.gfxType & RGFW_gfxOwnedByRGFW) RGFW_FREE(ctx); } RGFW_bool RGFW_extensionSupportedStr(const char *extensions, const char *ext, size_t len){ const char *start = extensions; const char *where; const char *terminator; if (extensions == NULL || ext == NULL) { return RGFW_FALSE; } while (ext[len - 1] == '\0' && len > 3) { len--; } where = RGFW_STRSTR(extensions, ext); while (where) { terminator = where + len; if ((where == start || *(where - 1) == ' ') && (*terminator == ' ' || *terminator == '\0')) { return RGFW_TRUE; } where = RGFW_STRSTR(terminator, ext); } return RGFW_FALSE; } RGFWDEF RGFW_bool RGFW_extensionSupported_base(const char *extension, size_t len); RGFW_bool RGFW_extensionSupported_base(const char *extension, size_t len){ #ifdef GL_NUM_EXTENSIONS if (RGFW_globalHints_OpenGL->major >= 3) { i32 i; GLint count = 0; RGFW_proc RGFW_glGetStringi = RGFW_getProcAddress_OpenGL("glGetStringi"); RGFW_proc RGFW_glGetIntegerv = RGFW_getProcAddress_OpenGL("glGetIntegerv"); if (RGFW_glGetIntegerv) ((void (*) (GLenum, GLint *))RGFW_glGetIntegerv) (GL_NUM_EXTENSIONS, &count); for (i = 0; RGFW_glGetStringi && i < count; i++) { const char *en = ((const char *(*) (u32, u32))RGFW_glGetStringi) (GL_EXTENSIONS, (u32) i); if (en && RGFW_STRNCMP(en, extension, len) == 0) { return RGFW_TRUE; } } } else #endif { RGFW_proc RGFW_glGetString = RGFW_getProcAddress_OpenGL("glGetString"); #define RGFW_GL_EXTENSIONS 0x1F03 if (RGFW_glGetString) { const char *extensions = ((const char *(*) (u32))RGFW_glGetString) (RGFW_GL_EXTENSIONS); if ((extensions != NULL) && RGFW_extensionSupportedStr(extensions, extension, len)) { return RGFW_TRUE; } } } return RGFW_FALSE; } RGFW_bool RGFW_extensionSupported_OpenGL(const char *extension, size_t len){ if (RGFW_extensionSupported_base(extension, len)) return RGFW_TRUE; return RGFW_extensionSupportedPlatform_OpenGL(extension, len); } void RGFW_window_makeCurrentWindow_OpenGL(RGFW_window * win) { if (win) { _RGFW->current = win; } RGFW_window_makeCurrentContext_OpenGL(win); } RGFW_window *RGFW_getCurrentWindow_OpenGL(void){ return _RGFW->current; } void RGFW_attribStack_init(RGFW_attribStack * stack, i32 * attribs, size_t max) { stack->attribs = attribs; stack->count = 0; stack->max = max; } void RGFW_attribStack_pushAttrib(RGFW_attribStack * stack, i32 attrib) { RGFW_ASSERT(stack->count < stack->max); stack->attribs[stack->count] = attrib; stack->count += 1; } void RGFW_attribStack_pushAttribs(RGFW_attribStack * stack, i32 attrib1, i32 attrib2) { RGFW_attribStack_pushAttrib(stack, attrib1); RGFW_attribStack_pushAttrib(stack, attrib2); } /* EGL */ #ifdef RGFW_EGL #include PFNEGLINITIALIZEPROC RGFW_eglInitialize; PFNEGLGETCONFIGSPROC RGFW_eglGetConfigs; PFNEGLCHOOSECONFIGPROC RGFW_eglChooseConfig; PFNEGLCREATEWINDOWSURFACEPROC RGFW_eglCreateWindowSurface; PFNEGLCREATECONTEXTPROC RGFW_eglCreateContext; PFNEGLMAKECURRENTPROC RGFW_eglMakeCurrent; PFNEGLGETDISPLAYPROC RGFW_eglGetDisplay; PFNEGLSWAPBUFFERSPROC RGFW_eglSwapBuffers; PFNEGLSWAPINTERVALPROC RGFW_eglSwapInterval; PFNEGLBINDAPIPROC RGFW_eglBindAPI; PFNEGLDESTROYCONTEXTPROC RGFW_eglDestroyContext; PFNEGLTERMINATEPROC RGFW_eglTerminate; PFNEGLDESTROYSURFACEPROC RGFW_eglDestroySurface; PFNEGLGETCURRENTCONTEXTPROC RGFW_eglGetCurrentContext; PFNEGLGETPROCADDRESSPROC RGFW_eglGetProcAddress = NULL; PFNEGLQUERYSTRINGPROC RGFW_eglQueryString; PFNEGLGETCONFIGATTRIBPROC RGFW_eglGetConfigAttrib; #define EGL_SURFACE_MAJOR_VERSION_KHR 0x3098 #define EGL_SURFACE_MINOR_VERSION_KHR 0x30fb #ifdef RGFW_WINDOWS #include #elif defined(RGFW_MACOS) || defined(RGFW_UNIX) #include #endif #ifdef RGFW_WAYLAND #include #endif void *RGFW_eglLibHandle = NULL; void *RGFW_getDisplay_EGL(void){ return _RGFW->EGL_display; } void *RGFW_eglContext_getSourceContext(RGFW_eglContext * ctx) { return ctx->ctx; } void *RGFW_eglContext_getSurface(RGFW_eglContext * ctx) { return ctx->surface; } struct wl_egl_window *RGFW_eglContext_wlEGLWindow(RGFW_eglContext * ctx) { return ctx->eglWindow; } RGFW_bool RGFW_loadEGL(void){ RGFW_init(); if (RGFW_eglGetProcAddress != NULL) { return RGFW_TRUE; } #ifndef RGFW_WASM #ifdef RGFW_WINDOWS const char *libNames[] = {"libEGL.dll", "EGL.dll"}; #elif defined(RGFW_MACOS) || defined(RGFW_UNIX) //Linux and macOS const char *libNames[] = { "libEGL.so.1", //most common "libEGL.so", //fallback "/System/Library/Frameworks/OpenGL.framework/OpenGL" // fallback for older macOS EGL - like systems }; #endif for (size_t i = 0; i < sizeof(libNames) / sizeof(libNames[0]); ++i) { #ifdef RGFW_WINDOWS RGFW_eglLibHandle = (void *)LoadLibraryA(libNames[i]); if (RGFW_eglLibHandle) { RGFW_eglGetProcAddress = (PFNEGLGETPROCADDRESSPROC) (RGFW_proc) GetProcAddress((HMODULE) RGFW_eglLibHandle, "eglGetProcAddress"); break; } #elif defined(RGFW_MACOS) || defined(RGFW_UNIX) RGFW_eglLibHandle = dlopen(libNames[i], RTLD_LAZY | RTLD_GLOBAL); if (RGFW_eglLibHandle) { void *lib = dlsym(RGFW_eglLibHandle, "eglGetProcAddress"); if (lib != NULL) RGFW_MEMCPY(&RGFW_eglGetProcAddress, &lib, sizeof(PFNEGLGETPROCADDRESSPROC)); break; } #endif } if (!RGFW_eglLibHandle || !RGFW_eglGetProcAddress) { return RGFW_FALSE; } RGFW_eglInitialize = (PFNEGLINITIALIZEPROC) RGFW_eglGetProcAddress("eglInitialize"); RGFW_eglGetConfigs = (PFNEGLGETCONFIGSPROC) RGFW_eglGetProcAddress("eglGetConfigs"); RGFW_eglChooseConfig = (PFNEGLCHOOSECONFIGPROC) RGFW_eglGetProcAddress("eglChooseConfig"); RGFW_eglCreateWindowSurface = (PFNEGLCREATEWINDOWSURFACEPROC) RGFW_eglGetProcAddress("eglCreateWindowSurface"); RGFW_eglCreateContext = (PFNEGLCREATECONTEXTPROC) RGFW_eglGetProcAddress("eglCreateContext"); RGFW_eglMakeCurrent = (PFNEGLMAKECURRENTPROC) RGFW_eglGetProcAddress("eglMakeCurrent"); RGFW_eglGetDisplay = (PFNEGLGETDISPLAYPROC) RGFW_eglGetProcAddress("eglGetDisplay"); RGFW_eglSwapBuffers = (PFNEGLSWAPBUFFERSPROC) RGFW_eglGetProcAddress("eglSwapBuffers"); RGFW_eglSwapInterval = (PFNEGLSWAPINTERVALPROC) RGFW_eglGetProcAddress("eglSwapInterval"); RGFW_eglBindAPI = (PFNEGLBINDAPIPROC) RGFW_eglGetProcAddress("eglBindAPI"); RGFW_eglDestroyContext = (PFNEGLDESTROYCONTEXTPROC) RGFW_eglGetProcAddress("eglDestroyContext"); RGFW_eglTerminate = (PFNEGLTERMINATEPROC) RGFW_eglGetProcAddress("eglTerminate"); RGFW_eglDestroySurface = (PFNEGLDESTROYSURFACEPROC) RGFW_eglGetProcAddress("eglDestroySurface"); RGFW_eglQueryString = (PFNEGLQUERYSTRINGPROC) RGFW_eglGetProcAddress("eglQueryString"); RGFW_eglGetCurrentContext = (PFNEGLGETCURRENTCONTEXTPROC) RGFW_eglGetProcAddress("eglGetCurrentContext"); RGFW_eglGetConfigAttrib = (PFNEGLGETCONFIGATTRIBPROC) RGFW_eglGetProcAddress("eglGetConfigAttrib"); #else RGFW_eglGetProcAddress = eglGetProcAddress; RGFW_eglInitialize = (PFNEGLINITIALIZEPROC) eglInitialize; RGFW_eglGetConfigs = (PFNEGLGETCONFIGSPROC) eglGetConfigs; RGFW_eglChooseConfig = (PFNEGLCHOOSECONFIGPROC) eglChooseConfig; RGFW_eglCreateWindowSurface = (PFNEGLCREATEWINDOWSURFACEPROC) eglCreateWindowSurface; RGFW_eglCreateContext = (PFNEGLCREATECONTEXTPROC) eglCreateContext; RGFW_eglMakeCurrent = (PFNEGLMAKECURRENTPROC) eglMakeCurrent; RGFW_eglGetDisplay = (PFNEGLGETDISPLAYPROC) eglGetDisplay; RGFW_eglSwapBuffers = (PFNEGLSWAPBUFFERSPROC) eglSwapBuffers; RGFW_eglSwapInterval = (PFNEGLSWAPINTERVALPROC) eglSwapInterval; RGFW_eglBindAPI = (PFNEGLBINDAPIPROC) eglBindAPI; RGFW_eglDestroyContext = (PFNEGLDESTROYCONTEXTPROC) eglDestroyContext; RGFW_eglTerminate = (PFNEGLTERMINATEPROC) eglTerminate; RGFW_eglDestroySurface = (PFNEGLDESTROYSURFACEPROC) eglDestroySurface; RGFW_eglQueryString = (PFNEGLQUERYSTRINGPROC) eglQueryString; RGFW_eglGetCurrentContext = (PFNEGLGETCURRENTCONTEXTPROC) eglGetCurrentContext; RGFW_eglGetConfigAttrib = (PFNEGLGETCONFIGATTRIBPROC) eglGetConfigAttrib; #endif RGFW_bool out = RGFW_BOOL(RGFW_eglInitialize != NULL && RGFW_eglGetConfigs != NULL && RGFW_eglChooseConfig != NULL && RGFW_eglCreateWindowSurface != NULL && RGFW_eglCreateContext != NULL && RGFW_eglMakeCurrent != NULL && RGFW_eglGetDisplay != NULL && RGFW_eglSwapBuffers != NULL && RGFW_eglSwapInterval != NULL && RGFW_eglBindAPI != NULL && RGFW_eglDestroyContext != NULL && RGFW_eglTerminate != NULL && RGFW_eglDestroySurface != NULL && RGFW_eglQueryString != NULL && RGFW_eglGetCurrentContext != NULL && RGFW_eglGetConfigAttrib != NULL); if (out) { #ifdef RGFW_WINDOWS HDC dc = GetDC(NULL); _RGFW->EGL_display = RGFW_eglGetDisplay((EGLNativeDisplayType) dc); ReleaseDC(NULL, dc); #elif defined(RGFW_WAYLAND) if (_RGFW->useWaylandBool) _RGFW->EGL_display = RGFW_eglGetDisplay((EGLNativeDisplayType) _RGFW->wl_display); else #endif #ifdef RGFW_X11 _RGFW->EGL_display = RGFW_eglGetDisplay((EGLNativeDisplayType) _RGFW->display); #else { } #endif #if !defined(RGFW_WAYLAND) && !defined(RGFW_WINDOWS) && !defined(RGFW_X11) _RGFW->EGL_display = RGFW_eglGetDisplay(EGL_DEFAULT_DISPLAY); #endif } RGFW_eglInitialize(_RGFW->EGL_display, NULL, NULL); return out; } void RGFW_unloadEGL(void){ if (!RGFW_eglLibHandle) return; RGFW_eglTerminate(_RGFW->EGL_display); #ifdef RGFW_WINDOWS FreeLibrary((HMODULE) RGFW_eglLibHandle); #elif defined(RGFW_MACOS) || defined(RGFW_UNIX) dlclose(RGFW_eglLibHandle); #endif RGFW_eglLibHandle = NULL; RGFW_eglGetProcAddress = NULL; } RGFW_bool RGFW_window_createContextPtr_EGL(RGFW_window * win, RGFW_eglContext * ctx, RGFW_glHints * hints) { if (RGFW_loadEGL() == RGFW_FALSE) return RGFW_FALSE; win->src.ctx.egl = ctx; win->src.gfxType = RGFW_gfxEGL; #ifdef RGFW_WAYLAND if (_RGFW->useWaylandBool) win->src.ctx.egl->eglWindow = wl_egl_window_create(win->src.surface, win->w, win->h); #endif #ifndef EGL_OPENGL_ES1_BIT #define EGL_OPENGL_ES1_BIT 0x1 #endif EGLint egl_config[24]; { RGFW_attribStack stack; RGFW_attribStack_init(&stack, egl_config, 24); RGFW_attribStack_pushAttribs(&stack, EGL_SURFACE_TYPE, EGL_WINDOW_BIT); RGFW_attribStack_pushAttrib(&stack, EGL_RENDERABLE_TYPE); if (hints->profile == RGFW_glES) { switch (hints->major) { case 1:RGFW_attribStack_pushAttrib(&stack, EGL_OPENGL_ES1_BIT); break; case 2:RGFW_attribStack_pushAttrib(&stack, EGL_OPENGL_ES2_BIT); break; case 3:RGFW_attribStack_pushAttrib(&stack, EGL_OPENGL_ES3_BIT); break; default:break; } } else { RGFW_attribStack_pushAttrib(&stack, EGL_OPENGL_BIT); } RGFW_attribStack_pushAttribs(&stack, EGL_RED_SIZE, hints->red); RGFW_attribStack_pushAttribs(&stack, EGL_GREEN_SIZE, hints->green); RGFW_attribStack_pushAttribs(&stack, EGL_BLUE_SIZE, hints->blue); RGFW_attribStack_pushAttribs(&stack, EGL_ALPHA_SIZE, hints->alpha); RGFW_attribStack_pushAttribs(&stack, EGL_DEPTH_SIZE, hints->depth); RGFW_attribStack_pushAttribs(&stack, EGL_STENCIL_SIZE, hints->stencil); if (hints->samples) { RGFW_attribStack_pushAttribs(&stack, EGL_SAMPLE_BUFFERS, 1); RGFW_attribStack_pushAttribs(&stack, EGL_SAMPLES, hints->samples); } RGFW_attribStack_pushAttribs(&stack, EGL_NONE, EGL_NONE); } EGLint numConfigs, best_config = -1, best_samples = 0; RGFW_eglChooseConfig(_RGFW->EGL_display, egl_config, NULL, 0, &numConfigs); EGLConfig *configs = (EGLConfig *) RGFW_ALLOC(sizeof(EGLConfig) * (u32) numConfigs); RGFW_eglChooseConfig(_RGFW->EGL_display, egl_config, configs, numConfigs, &numConfigs); #ifdef RGFW_X11 RGFW_bool transparent = (win->internal.flags & RGFW_windowTransparent); EGLint best_depth = 0; #endif for (EGLint i = 0; i < numConfigs; i++) { EGLint visual_id = 0; EGLint samples = 0; RGFW_eglGetConfigAttrib(_RGFW->EGL_display, configs[i], EGL_NATIVE_VISUAL_ID, &visual_id); RGFW_eglGetConfigAttrib(_RGFW->EGL_display, configs[i], EGL_SAMPLES, &samples); if (best_config == -1) best_config = i; #ifdef RGFW_X11 if (_RGFW->useWaylandBool == RGFW_FALSE) { XVisualInfo vinfo_template; vinfo_template.visualid = (VisualID) visual_id; int num_visuals = 0; XVisualInfo *vi = XGetVisualInfo(_RGFW->display, VisualIDMask, &vinfo_template, &num_visuals); if (!vi) continue; if ((!transparent || vi->depth == 32) && best_depth == 0) { best_config = i; best_depth = vi->depth; } if ((!(transparent) || vi->depth == 32) && (samples <= hints->samples && samples > best_samples)) { best_depth = vi->depth; best_config = i; best_samples = samples; XFree(vi); continue; } } #endif if (samples <= hints->samples && samples > best_samples) { best_config = i; best_samples = samples; } } EGLConfig config = configs[best_config]; RGFW_FREE(configs); #ifdef RGFW_X11 if (_RGFW->useWaylandBool == RGFW_FALSE) { /* * This is required so that way the user can create * their own OpenGL context after RGFW_createWindow is * used */ XVisualInfo * result; XVisualInfo desired; EGLint visualID = 0, count = 0; RGFW_eglGetConfigAttrib(_RGFW->EGL_display, config, EGL_NATIVE_VISUAL_ID, &visualID); if (visualID) { desired.visualid = (VisualID) visualID; result = XGetVisualInfo(_RGFW->display, VisualIDMask, &desired, &count); } else RGFW_sendDebugInfo(RGFW_typeError, RGFW_errEGLContext, "Failed to fetch a valid EGL VisualID"); if (result == NULL || count == 0) { if (win->src.window == 0) { /* * try to create a EGL context anyway * (this will work if you're not using * a NVidia driver) */ win->internal.flags &= ~(u32) RGFW_windowEGL; RGFW_createWindowPlatform("", win->internal.flags, win); } RGFW_sendDebugInfo(RGFW_typeError, RGFW_errEGLContext, "Failed to find a valid visual for the EGL config"); } else { if (win->src.window) RGFW_window_closePlatform(win); RGFW_XCreateWindow(*result, "", win->internal.flags, win); XFree(result); } } #endif EGLint surf_attribs[9]; { RGFW_attribStack stack; RGFW_attribStack_init(&stack, surf_attribs, 9); const char present_opaque_str[] = "EGL_EXT_present_opaque"; RGFW_bool opaque_extension_Found = RGFW_extensionSupportedPlatform_EGL(present_opaque_str, sizeof(present_opaque_str)); #ifndef EGL_PRESENT_OPAQUE_EXT #define EGL_PRESENT_OPAQUE_EXT 0x31df #endif #ifndef EGL_GL_COLORSPACE_KHR #define EGL_GL_COLORSPACE_KHR 0x309D #ifndef EGL_GL_COLORSPACE_SRGB_KHR #define EGL_GL_COLORSPACE_SRGB_KHR 0x3089 #endif #endif const char gl_colorspace_str[] = "EGL_KHR_gl_colorspace"; RGFW_bool gl_colorspace_Found = RGFW_extensionSupportedPlatform_EGL(gl_colorspace_str, sizeof(gl_colorspace_str)); if (hints->sRGB && gl_colorspace_Found) { RGFW_attribStack_pushAttribs(&stack, EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR); } if (!(win->internal.flags & RGFW_windowTransparent) && opaque_extension_Found) RGFW_attribStack_pushAttribs(&stack, EGL_PRESENT_OPAQUE_EXT, EGL_TRUE); if (hints->doubleBuffer == 0) { RGFW_attribStack_pushAttribs(&stack, EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER); } RGFW_attribStack_pushAttribs(&stack, EGL_NONE, EGL_NONE); } #if defined(RGFW_MACOS) void *layer = RGFW_getLayer_OSX(); RGFW_window_setLayer_OSX(win, layer); win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, config, (EGLNativeWindowType) layer, surf_attribs); #elif defined(RGFW_WINDOWS) win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, config, (EGLNativeWindowType) win->src.window, surf_attribs); #elif defined(RGFW_WAYLAND) if (_RGFW->useWaylandBool) win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, config, (EGLNativeWindowType) win->src.ctx.egl->eglWindow, surf_attribs); else #endif #ifdef RGFW_X11 win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, config, (EGLNativeWindowType) win->src.window, surf_attribs); #else { } #endif #ifdef RGFW_WASM win->src.ctx.egl->surface = eglCreateWindowSurface(_RGFW->EGL_display, config, 0, 0); #endif if (win->src.ctx.egl->surface == NULL) { RGFW_sendDebugInfo(RGFW_typeError, RGFW_errEGLContext, "Failed to create an EGL surface."); return RGFW_FALSE; } EGLint attribs[20]; { RGFW_attribStack stack; RGFW_attribStack_init(&stack, attribs, 20); if (hints->major || hints->minor) { RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_MAJOR_VERSION, hints->major); RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_MINOR_VERSION, hints->minor); } if (hints->profile == RGFW_glCore) { RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT); } else if (hints->profile == RGFW_glCompatibility) { RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT); } RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_ROBUST_ACCESS, hints->robustness); RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_DEBUG, hints->debug); #ifndef EGL_CONTEXT_RELEASE_BEHAVIOR_KHR #define EGL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x2097 #endif #ifndef EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR #define EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x2098 #endif if (hints->releaseBehavior == RGFW_glReleaseFlush) { RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR); } else { RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, 0x0000); } RGFW_attribStack_pushAttribs(&stack, EGL_NONE, EGL_NONE); } if (hints->profile == RGFW_glES) RGFW_eglBindAPI(EGL_OPENGL_ES_API); else RGFW_eglBindAPI(EGL_OPENGL_API); win->src.ctx.egl->ctx = RGFW_eglCreateContext(_RGFW->EGL_display, config, hints->shareEGL, attribs); if (win->src.ctx.egl->ctx == NULL) { RGFW_sendDebugInfo(RGFW_typeError, RGFW_errEGLContext, "Failed to create an EGL context."); return RGFW_FALSE; } RGFW_eglMakeCurrent(_RGFW->EGL_display, win->src.ctx.egl->surface, win->src.ctx.egl->surface, win->src.ctx.egl->ctx); RGFW_eglSwapBuffers(_RGFW->EGL_display, win->src.ctx.egl->surface); RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "EGL context initalized."); return RGFW_TRUE; } RGFW_eglContext *RGFW_window_getContext_EGL(RGFW_window * win) { if (win->src.gfxType == RGFW_windowOpenGL) return NULL; return win->src.ctx.egl; } void RGFW_window_deleteContextPtr_EGL(RGFW_window * win, RGFW_eglContext * ctx) { if (_RGFW->EGL_display == NULL) return; RGFW_eglDestroySurface(_RGFW->EGL_display, ctx->surface); RGFW_eglDestroyContext(_RGFW->EGL_display, ctx->ctx); RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "EGL context freed"); #ifdef RGFW_WAYLAND if (_RGFW->useWaylandBool == RGFW_FALSE) return; wl_egl_window_destroy(win->src.ctx.egl->eglWindow); RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "EGL window context freed"); #endif win->src.ctx.egl = NULL; } void RGFW_window_makeCurrentContext_EGL(RGFW_window * win) { if (win) RGFW_ASSERT(win->src.ctx.egl); if (win == NULL) RGFW_eglMakeCurrent(_RGFW->EGL_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); else { RGFW_eglMakeCurrent(_RGFW->EGL_display, win->src.ctx.egl->surface, win->src.ctx.egl->surface, win->src.ctx.egl->ctx); } } void RGFW_window_swapBuffers_EGL(RGFW_window * win) { if (RGFW_eglSwapBuffers) RGFW_eglSwapBuffers(_RGFW->EGL_display, win->src.ctx.egl->surface); else RGFW_window_swapBuffers_OpenGL(win); } void *RGFW_getCurrentContext_EGL(void){ return RGFW_eglGetCurrentContext(); } RGFW_proc RGFW_getProcAddress_EGL(const char *procname){ #if defined(RGFW_WINDOWS) RGFW_proc proc = (RGFW_proc) GetProcAddress(RGFW_wgl_dll, procname); if (proc) return proc; #endif return (RGFW_proc) RGFW_eglGetProcAddress(procname); } RGFW_bool RGFW_extensionSupportedPlatform_EGL(const char *extension, size_t len){ if (RGFW_loadEGL() == RGFW_FALSE) return RGFW_FALSE; const char *extensions = RGFW_eglQueryString(_RGFW->EGL_display, EGL_EXTENSIONS); return extensions != NULL && RGFW_extensionSupportedStr(extensions, extension, len); } void RGFW_window_swapInterval_EGL(RGFW_window * win, i32 swapInterval) { RGFW_ASSERT(win != NULL); RGFW_eglSwapInterval(_RGFW->EGL_display, swapInterval); } RGFW_bool RGFW_extensionSupported_EGL(const char *extension, size_t len){ if (RGFW_extensionSupported_base(extension, len)) return RGFW_TRUE; return RGFW_extensionSupportedPlatform_EGL(extension, len); } void RGFW_window_makeCurrentWindow_EGL(RGFW_window * win) { _RGFW->current = win; RGFW_window_makeCurrentContext_EGL(win); } RGFW_window *RGFW_getCurrentWindow_EGL(void){ return _RGFW->current; } RGFW_eglContext *RGFW_window_createContext_EGL(RGFW_window * win, RGFW_glHints * hints) { RGFW_eglContext *ctx = (RGFW_eglContext *) RGFW_ALLOC(sizeof(RGFW_eglContext)); if (RGFW_window_createContextPtr_EGL(win, ctx, hints) == RGFW_FALSE) { RGFW_FREE(ctx); win->src.ctx.egl = NULL; return NULL; } win->src.gfxType |= RGFW_gfxOwnedByRGFW; return ctx; } void RGFW_window_deleteContext_EGL(RGFW_window * win, RGFW_eglContext * ctx) { RGFW_window_deleteContextPtr_EGL(win, ctx); if (win->src.gfxType & RGFW_gfxOwnedByRGFW) RGFW_FREE(ctx); } #endif /* RGFW_EGL */ /* * end of RGFW_EGL defines */ #endif /* end of RGFW_GL (OpenGL, EGL, OSMesa ) */ /* * RGFW_VULKAN defines */ #ifdef RGFW_VULKAN #ifdef RGFW_MACOS #include #endif const char **RGFW_getRequiredInstanceExtensions_Vulkan(size_t * count) { static const char *arr[2] = {VK_KHR_SURFACE_EXTENSION_NAME}; arr[1] = RGFW_VK_SURFACE; if (count != NULL) *count = 2; return (const char **)arr; } VkResult RGFW_window_createSurface_Vulkan(RGFW_window * win, VkInstance instance, VkSurfaceKHR * surface) { RGFW_ASSERT(win != NULL); RGFW_ASSERT(instance); RGFW_ASSERT(surface != NULL); *surface = VK_NULL_HANDLE; #ifdef RGFW_X11 #include VkXlibSurfaceCreateInfoKHR x11 = {VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, 0, 0, (Display *) _RGFW->display, (Window) win->src.window}; return vkCreateXlibSurfaceKHR(instance, &x11, NULL, surface); #endif #if defined(RGFW_WAYLAND) VkWaylandSurfaceCreateInfoKHR wayland = {VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, 0, 0, (struct wl_display *)_RGFW->wl_display, (struct wl_surface *)win->src.surface}; return vkCreateWaylandSurfaceKHR(instance, &wayland, NULL, surface); #elif defined(RGFW_WINDOWS) VkWin32SurfaceCreateInfoKHR win32 = {VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, 0, 0, GetModuleHandle(NULL), (HWND) win->src.window}; return vkCreateWin32SurfaceKHR(instance, &win32, NULL, surface); #elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-local-typedef" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-local-typedef" #include #include #pragma GCC diagnostic pop #pragma clang diagnostic pop void *contentView = ((void *(*) (id, SEL))objc_msgSend) ((id) win->src.window, sel_getUid("contentView")); VkMacOSSurfaceCreateInfoMVK macos = {VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK, 0, 0, (void *)contentView}; return vkCreateMacOSSurfaceMVK(instance, &macos, NULL, surface); #endif } /* RGFW_bool RGFW_getPresentationSupport_Vulkan(VkInstance instance, VkPhysicalDevice physicalDevice, u32 queueFamilyIndex) { RGFW_ASSERT(instance); if (_RGFW == NULL) RGFW_init(); #ifdef RGFW_X11 #include Visual *visual = DefaultVisual(_RGFW->display, DefaultScreen(_RGFW->display)); RGFW_bool out = vkGetPhysicalDeviceXlibPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW->display, XVisualIDFromVisual(visual)); return out; #endif #if defined(RGFW_WAYLAND) RGFW_bool wlout = vkGetPhysicalDeviceWaylandPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW->wl_display); return wlout; #elif defined(RGFW_WINDOWS) #elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11) (void)physicalDevice; (void)queueFamilyIndex; return RGFW_FALSE; #endif } */ #endif /* * This is where OS specific stuff starts */ /* start of unix (wayland or X11 (unix) ) defines */ #ifdef RGFW_UNIX #include #include #include void RGFW_stopCheckEvents(void){ _RGFW->eventWait_forceStop[2] = 1; while (1) { const char byte = 0; const ssize_t result = write(_RGFW->eventWait_forceStop[1], &byte, 1); if (result == 1 || result == -1) break; } } RGFWDEF u64 RGFW_linux_getTimeNS(i32 clock); u64 RGFW_linux_getTimeNS(i32 clock) { struct timespec ts; clock_gettime(clock, &ts); return (u64) ts.tv_sec * 1000000000ull + (u64) ts.tv_nsec; } void RGFW_waitForEvent(i32 waitMS) { if (waitMS == 0) return; if (_RGFW->eventWait_forceStop[0] == 0 || _RGFW->eventWait_forceStop[1] == 0) { if (pipe(_RGFW->eventWait_forceStop) != -1) { fcntl(_RGFW->eventWait_forceStop[0], F_GETFL, 0); fcntl(_RGFW->eventWait_forceStop[0], F_GETFD, 0); fcntl(_RGFW->eventWait_forceStop[1], F_GETFL, 0); fcntl(_RGFW->eventWait_forceStop[1], F_GETFD, 0); } } struct pollfd fds[] = { {0, POLLIN, 0}, {_RGFW->eventWait_forceStop[0], POLLIN, 0}, }; if (RGFW_usingWayland()) { #ifdef RGFW_WAYLAND fds[0].fd = wl_display_get_fd(_RGFW->wl_display); /* empty the queue */ while (wl_display_prepare_read(_RGFW->wl_display) != 0) { /* error occured when dispatching the queue */ if (wl_display_dispatch_pending(_RGFW->wl_display) == -1) { return; } } /* send any pending requests to the compositor */ while (wl_display_flush(_RGFW->wl_display) == -1) { /* queue is full dispatch them */ if (errno == EAGAIN) { if (wl_display_dispatch_pending(_RGFW->wl_display) == -1) { return; } } else { return; } } #endif } else { #ifdef RGFW_X11 fds[0].fd = ConnectionNumber(_RGFW->display); #endif } i32 clock = 0; #if defined(_POSIX_MONOTONIC_CLOCK) struct timespec ts; RGFW_MEMSET(&ts, 0, sizeof(struct timespec)); if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) clock = CLOCK_MONOTONIC; #else clock = CLOCK_REALTIME; #endif u64 start = RGFW_linux_getTimeNS(clock); if (RGFW_usingWayland()) { #ifdef RGFW_WAYLAND while (wl_display_dispatch_pending(_RGFW->wl_display) == 0) { if (poll(fds, 1, waitMS) <= 0) { wl_display_cancel_read(_RGFW->wl_display); break; } else { if (wl_display_read_events(_RGFW->wl_display) == -1) return; } if (waitMS != RGFW_eventWaitNext) { waitMS -= (i32) (RGFW_linux_getTimeNS(clock) - start) / (i32) 1e+6; } } //queue contains events from read, dispatch them if (wl_display_dispatch_pending(_RGFW->wl_display) == -1) { return; } #endif } else { #ifdef RGFW_X11 while (XPending(_RGFW->display) == 0) { if (poll(fds, 1, waitMS) <= 0) break; if (waitMS != RGFW_eventWaitNext) { waitMS -= (i32) (RGFW_linux_getTimeNS(clock) - start) / (i32) 1e+6; } } #endif } /* drain any data in the stop request */ if (_RGFW->eventWait_forceStop[2]) { char data[64]; RGFW_MEMSET(data, 0, sizeof(data)); (void)!read(_RGFW->eventWait_forceStop[0], data, sizeof(data)); _RGFW->eventWait_forceStop[2] = 0; } } char *RGFW_strtok(char *str, const char *delimStr); char *RGFW_strtok(char *str, const char *delimStr){ static char *static_str = NULL; if (str != NULL) static_str = str; if (static_str == NULL) { return NULL; } while (*static_str != '\0') { RGFW_bool delim = 0; const char *d; for (d = delimStr; *d != '\0'; d++) { if (*static_str == *d) { delim = 1; break; } } if (!delim) break; static_str++; } if (*static_str == '\0') return NULL; char *token_start = static_str; while (*static_str != '\0') { int delim = 0; const char *d; for (d = delimStr; *d != '\0'; d++) { if (*static_str == *d) { delim = 1; break; } } if (delim) { *static_str = '\0'; static_str++; break; } static_str++; } return token_start; } #ifdef RGFW_X11 RGFWDEF i32 RGFW_initPlatform_X11(void); RGFWDEF void RGFW_deinitPlatform_X11(void); #endif #ifdef RGFW_WAYLAND RGFWDEF i32 RGFW_initPlatform_Wayland(void); RGFWDEF void RGFW_deinitPlatform_Wayland(void); #endif RGFWDEF void RGFW_load_X11(void); RGFWDEF void RGFW_load_Wayland(void); #if !defined(RGFW_X11) || !defined(RGFW_WAYLAND) void RGFW_load_X11(void){ } void RGFW_load_Wayland(void){ } #endif /* * Sadly we have to use magic linux keycodes We can't use X11 * functions, because that breaks Wayland, but they use the same * keycodes so there's no use redeffing them We can't use linux enums, * because the headers don't exist on BSD */ void RGFW_initKeycodesPlatform(void){ _RGFW->keycodes[49] = RGFW_backtick; _RGFW->keycodes[19] = RGFW_0; _RGFW->keycodes[10] = RGFW_1; _RGFW->keycodes[11] = RGFW_2; _RGFW->keycodes[12] = RGFW_3; _RGFW->keycodes[13] = RGFW_4; _RGFW->keycodes[14] = RGFW_5; _RGFW->keycodes[15] = RGFW_6; _RGFW->keycodes[16] = RGFW_7; _RGFW->keycodes[17] = RGFW_8; _RGFW->keycodes[18] = RGFW_9; _RGFW->keycodes[65] = RGFW_space; _RGFW->keycodes[38] = RGFW_a; _RGFW->keycodes[56] = RGFW_b; _RGFW->keycodes[54] = RGFW_c; _RGFW->keycodes[40] = RGFW_d; _RGFW->keycodes[26] = RGFW_e; _RGFW->keycodes[41] = RGFW_f; _RGFW->keycodes[42] = RGFW_g; _RGFW->keycodes[43] = RGFW_h; _RGFW->keycodes[31] = RGFW_i; _RGFW->keycodes[44] = RGFW_j; _RGFW->keycodes[45] = RGFW_k; _RGFW->keycodes[46] = RGFW_l; _RGFW->keycodes[58] = RGFW_m; _RGFW->keycodes[57] = RGFW_n; _RGFW->keycodes[32] = RGFW_o; _RGFW->keycodes[33] = RGFW_p; _RGFW->keycodes[24] = RGFW_q; _RGFW->keycodes[27] = RGFW_r; _RGFW->keycodes[39] = RGFW_s; _RGFW->keycodes[28] = RGFW_t; _RGFW->keycodes[30] = RGFW_u; _RGFW->keycodes[55] = RGFW_v; _RGFW->keycodes[25] = RGFW_w; _RGFW->keycodes[53] = RGFW_x; _RGFW->keycodes[29] = RGFW_y; _RGFW->keycodes[52] = RGFW_z; _RGFW->keycodes[60] = RGFW_period; _RGFW->keycodes[59] = RGFW_comma; _RGFW->keycodes[61] = RGFW_slash; _RGFW->keycodes[34] = RGFW_bracket; _RGFW->keycodes[35] = RGFW_closeBracket; _RGFW->keycodes[47] = RGFW_semicolon; _RGFW->keycodes[48] = RGFW_apostrophe; _RGFW->keycodes[51] = RGFW_backSlash; _RGFW->keycodes[36] = RGFW_return; _RGFW->keycodes[119] = RGFW_delete; _RGFW->keycodes[77] = RGFW_numLock; _RGFW->keycodes[106] = RGFW_kpSlash; _RGFW->keycodes[63] = RGFW_kpMultiply; _RGFW->keycodes[86] = RGFW_kpPlus; _RGFW->keycodes[82] = RGFW_kpMinus; _RGFW->keycodes[87] = RGFW_kp1; _RGFW->keycodes[88] = RGFW_kp2; _RGFW->keycodes[89] = RGFW_kp3; _RGFW->keycodes[83] = RGFW_kp4; _RGFW->keycodes[84] = RGFW_kp5; _RGFW->keycodes[85] = RGFW_kp6; _RGFW->keycodes[81] = RGFW_kp9; _RGFW->keycodes[90] = RGFW_kp0; _RGFW->keycodes[91] = RGFW_kpPeriod; _RGFW->keycodes[104] = RGFW_kpReturn; _RGFW->keycodes[20] = RGFW_minus; _RGFW->keycodes[21] = RGFW_equals; _RGFW->keycodes[22] = RGFW_backSpace; _RGFW->keycodes[23] = RGFW_tab; _RGFW->keycodes[66] = RGFW_capsLock; _RGFW->keycodes[50] = RGFW_shiftL; _RGFW->keycodes[37] = RGFW_controlL; _RGFW->keycodes[64] = RGFW_altL; _RGFW->keycodes[133] = RGFW_superL; _RGFW->keycodes[105] = RGFW_controlR; _RGFW->keycodes[134] = RGFW_superR; _RGFW->keycodes[62] = RGFW_shiftR; _RGFW->keycodes[108] = RGFW_altR; _RGFW->keycodes[67] = RGFW_F1; _RGFW->keycodes[68] = RGFW_F2; _RGFW->keycodes[69] = RGFW_F3; _RGFW->keycodes[70] = RGFW_F4; _RGFW->keycodes[71] = RGFW_F5; _RGFW->keycodes[72] = RGFW_F6; _RGFW->keycodes[73] = RGFW_F7; _RGFW->keycodes[74] = RGFW_F8; _RGFW->keycodes[75] = RGFW_F9; _RGFW->keycodes[76] = RGFW_F10; _RGFW->keycodes[95] = RGFW_F11; _RGFW->keycodes[96] = RGFW_F12; _RGFW->keycodes[111] = RGFW_up; _RGFW->keycodes[116] = RGFW_down; _RGFW->keycodes[113] = RGFW_left; _RGFW->keycodes[114] = RGFW_right; _RGFW->keycodes[118] = RGFW_insert; _RGFW->keycodes[115] = RGFW_end; _RGFW->keycodes[112] = RGFW_pageUp; _RGFW->keycodes[117] = RGFW_pageDown; _RGFW->keycodes[9] = RGFW_escape; _RGFW->keycodes[110] = RGFW_home; _RGFW->keycodes[78] = RGFW_scrollLock; _RGFW->keycodes[107] = RGFW_printScreen; _RGFW->keycodes[128] = RGFW_pause; _RGFW->keycodes[191] = RGFW_F13; _RGFW->keycodes[192] = RGFW_F14; _RGFW->keycodes[193] = RGFW_F15; _RGFW->keycodes[194] = RGFW_F16; _RGFW->keycodes[195] = RGFW_F17; _RGFW->keycodes[196] = RGFW_F18; _RGFW->keycodes[197] = RGFW_F19; _RGFW->keycodes[198] = RGFW_F20; _RGFW->keycodes[199] = RGFW_F21; _RGFW->keycodes[200] = RGFW_F22; _RGFW->keycodes[201] = RGFW_F23; _RGFW->keycodes[202] = RGFW_F24; _RGFW->keycodes[203] = RGFW_F25; _RGFW->keycodes[142] = RGFW_kpEqual; _RGFW->keycodes[161] = RGFW_world1; /* non-US key #1 */ _RGFW->keycodes[162] = RGFW_world2; /* non-US key #2 */ } i32 RGFW_initPlatform(void){ #ifdef RGFW_WAYLAND RGFW_load_Wayland(); i32 ret = RGFW_initPlatform_Wayland(); if (ret == 0) { return 0; } else { #ifdef RGFW_X11 RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningWayland, "Falling back to X11"); RGFW_useWayland(0); #else return ret; #endif } #endif #ifdef RGFW_X11 RGFW_load_X11(); return RGFW_initPlatform_X11(); #else return 0; #endif } void RGFW_deinitPlatform(void){ #ifndef RGFW_NO_LINUX if (_RGFW->eventWait_forceStop[0] || _RGFW->eventWait_forceStop[1]) { close(_RGFW->eventWait_forceStop[0]); close(_RGFW->eventWait_forceStop[1]); } #endif #ifdef RGFW_WAYLAND if (_RGFW->useWaylandBool) { RGFW_deinitPlatform_Wayland(); return; } #endif #ifdef RGFW_X11 RGFW_deinitPlatform_X11(); #endif } #endif /* end of wayland or X11 defines */ /* * * * Start of Linux / Unix defines * * */ #ifdef RGFW_X11 #ifdef RGFW_WAYLAND #define RGFW_FUNC(func) func##_X11 #else #define RGFW_FUNC(func) func #endif #include #include #include /* for data limits (mainly used in drag and * drop functions) */ #include void RGFW_setXInstName(const char *name){ _RGFW->instName = name; } #if !defined(RGFW_NO_X11_CURSOR) && defined(RGFW_X11) #include #endif #ifndef RGFW_NO_DPI #include #include #endif #include #include #include #include /* for converting keycode to string */ #include /* for hiding */ #include #include #include #ifdef RGFW_OPENGL #ifndef __gl_h_ #define __gl_h_ #define RGFW_gl_ndef #define GLubyte unsigned char #define GLenum unsigned int #define GLint int #define GLuint unsigned int #define GLsizei int #define GLfloat float #define GLvoid void #define GLbitfield unsigned int #define GLintptr ptrdiff_t #define GLsizeiptr ptrdiff_t #define GLboolean unsigned char #endif #include /* GLX defs, xlib.h, gl.h */ #ifndef GLX_MESA_swap_control #define GLX_MESA_swap_control #endif #ifdef RGFW_gl_ndef #undef __gl_h_ #undef GLubyte #undef GLenum #undef GLint #undef GLuint #undef GLsizei #undef GLfloat #undef GLvoid #undef GLbitfield #undef GLintptr #undef GLsizeiptr #undef GLboolean #endif typedef GLXContext(*glXCreateContextAttribsARBProc) (Display *, GLXFBConfig, GLXContext, Bool, const int *); #endif /* atoms needed for drag and drop */ #if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD) typedef XcursorImage * (*PFN_XcursorImageCreate) (int, int); typedef void (*PFN_XcursorImageDestroy) (XcursorImage *); typedef Cursor(*PFN_XcursorImageLoadCursor) (Display *, const XcursorImage *); #endif #if !defined(RGFW_NO_X11_XI_PRELOAD) typedef int (*PFN_XISelectEvents) (Display *, Window, XIEventMask *, int); PFN_XISelectEvents XISelectEventsSRC = NULL; #define XISelectEvents XISelectEventsSRC void *X11Xihandle = NULL; #endif #if !defined(RGFW_NO_X11_EXT_PRELOAD) typedef void (*PFN_XSyncIntToValue) (XSyncValue *, int); PFN_XSyncIntToValue XSyncIntToValueSRC = NULL; #define XSyncIntToValue XSyncIntToValueSRC typedef Status(*PFN_XSyncSetCounter) (Display *, XSyncCounter, XSyncValue); PFN_XSyncSetCounter XSyncSetCounterSRC = NULL; #define XSyncSetCounter XSyncSetCounterSRC typedef XSyncCounter(*PFN_XSyncCreateCounter) (Display *, XSyncValue); PFN_XSyncCreateCounter XSyncCreateCounterSRC = NULL; #define XSyncCreateCounter XSyncCreateCounterSRC typedef void (*PFN_XShapeCombineMask) (Display *, Window, int, int, int, Pixmap, int); PFN_XShapeCombineMask XShapeCombineMaskSRC; #define XShapeCombineMask XShapeCombineMaskSRC typedef void (*PFN_XShapeCombineRegion) (Display *, Window, int, int, int, Region, int); PFN_XShapeCombineRegion XShapeCombineRegionSRC; #define XShapeCombineRegion XShapeCombineRegionSRC void *X11XEXThandle = NULL; #endif #if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD) PFN_XcursorImageLoadCursor XcursorImageLoadCursorSRC = NULL; PFN_XcursorImageCreate XcursorImageCreateSRC = NULL; PFN_XcursorImageDestroy XcursorImageDestroySRC = NULL; #define XcursorImageLoadCursor XcursorImageLoadCursorSRC #define XcursorImageCreate XcursorImageCreateSRC #define XcursorImageDestroy XcursorImageDestroySRC void *X11Cursorhandle = NULL; #endif void *RGFW_getDisplay_X11(void){ return _RGFW->display; } u64 RGFW_window_getWindow_X11(RGFW_window * win) { return (u64) win->src.window; } RGFWDEF RGFW_format RGFW_XImage_getFormat(XImage * image); RGFW_format RGFW_XImage_getFormat(XImage * image) { switch (image->bits_per_pixel) { case 24: if (image->red_mask == 0xFF0000 && image->green_mask == 0x00FF00 && image->blue_mask == 0x0000FF) return RGFW_formatRGB8; if (image->red_mask == 0x0000FF && image->green_mask == 0x00FF00 && image->blue_mask == 0xFF0000) return RGFW_formatBGR8; break; case 32: if (image->red_mask == 0x00FF0000 && image->green_mask == 0x0000FF00 && image->blue_mask == 0x000000FF) return RGFW_formatBGRA8; if (image->red_mask == 0x000000FF && image->green_mask == 0x0000FF00 && image->blue_mask == 0x00FF0000) return RGFW_formatRGBA8; if (image->red_mask == 0x0000FF00 && image->green_mask == 0x00FF0000 && image->blue_mask == 0xFF000000) return RGFW_formatABGR8; if (image->red_mask == 0x00FF0000 && image->green_mask == 0x0000FF00 && image->blue_mask == 0x000000FF) return RGFW_formatARGB8; /* ambiguous without * alpha */ break; } return RGFW_formatARGB8; } RGFW_bool RGFW_window_createSurfacePtr(RGFW_window * win, u8 * data, i32 w, i32 h, RGFW_format format, RGFW_surface * surface) { RGFW_ASSERT(surface != NULL); surface->data = data; surface->w = w; surface->h = h; surface->format = format; XWindowAttributes attrs; if (XGetWindowAttributes(_RGFW->display, win->src.window, &attrs) == 0) { RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, "Failed to get window attributes."); return RGFW_FALSE; } surface->native.bitmap = XCreateImage(_RGFW->display, attrs.visual, (u32) attrs.depth, ZPixmap, 0, NULL, (u32) surface->w, (u32) surface->h, 32, 0); surface->native.format = RGFW_XImage_getFormat(surface->native.bitmap); if (surface->native.bitmap == NULL) { RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, "Failed to create XImage."); return RGFW_FALSE; } surface->native.format = RGFW_formatBGRA8; return RGFW_TRUE; } RGFW_bool RGFW_FUNC(RGFW_createSurfacePtr) (u8 * data, i32 w, i32 h, RGFW_format format, RGFW_surface * surface) { return RGFW_window_createSurfacePtr(_RGFW->root, data, w, h, format, surface); } void RGFW_FUNC(RGFW_window_blitSurface) (RGFW_window * win, RGFW_surface * surface) { RGFW_ASSERT(surface != NULL); surface->native.bitmap->data = (char *)surface->data; RGFW_copyImageData((u8 *) surface->native.bitmap->data, surface->w, RGFW_MIN(win->h, surface->h), surface->native.format, surface->data, surface->format); XPutImage(_RGFW->display, win->src.window, win->src.gc, surface->native.bitmap, 0, 0, 0, 0, (u32) RGFW_MIN(win->w, surface->w), (u32) RGFW_MIN(win->h, surface->h)); surface->native.bitmap->data = NULL; return; } void RGFW_FUNC(RGFW_surface_freePtr) (RGFW_surface * surface) { RGFW_ASSERT(surface != NULL); XDestroyImage(surface->native.bitmap); return; } #define RGFW_LOAD_ATOM(name) \ static Atom name = 0; \ if (name == 0) name = XInternAtom(_RGFW->display, #name, False); void RGFW_FUNC(RGFW_window_setBorder) (RGFW_window * win, RGFW_bool border) { RGFW_setBit(&win->internal.flags, RGFW_windowNoBorder, !border); RGFW_LOAD_ATOM(_MOTIF_WM_HINTS); struct __x11WindowHints { unsigned long flags, functions, decorations, status; long input_mode; } hints; hints.flags = 2; hints.decorations = border; XChangeProperty(_RGFW->display, win->src.window, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 32, PropModeReplace, (u8 *) & hints, 5); if (RGFW_window_isHidden(win) == 0) { RGFW_window_hide(win); RGFW_window_show(win); } } void RGFW_FUNC(RGFW_releaseCursor) (RGFW_window * win) { RGFW_UNUSED(win); XUngrabPointer(_RGFW->display, CurrentTime); /* disable raw input */ unsigned char mask[] = {0}; XIEventMask em; em.deviceid = XIAllMasterDevices; em.mask_len = sizeof(mask); em.mask = mask; XISelectEvents(_RGFW->display, XDefaultRootWindow(_RGFW->display), &em, 1); } void RGFW_FUNC(RGFW_captureCursor) (RGFW_window * win) { /* enable raw input */ unsigned char mask[XIMaskLen(XI_RawMotion)] = {0}; XISetMask(mask, XI_RawMotion); XIEventMask em; em.deviceid = XIAllMasterDevices; em.mask_len = sizeof(mask); em.mask = mask; XISelectEvents(_RGFW->display, XDefaultRootWindow(_RGFW->display), &em, 1); unsigned int event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask; XGrabPointer(_RGFW->display, win->src.window, False, event_mask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); RGFW_window_moveMouse(win, win->x + (i32) (win->w / 2), win->y + (i32) (win->h / 2)); } #define RGFW_LOAD_LIBRARY(x, lib) if (x == NULL) x = dlopen(lib, RTLD_LAZY | RTLD_LOCAL) #define RGFW_PROC_DEF(proc, name) if (name##SRC == NULL && proc != NULL) { \ void* ptr = dlsym(proc, #name); \ if (ptr != NULL) RGFW_MEMCPY(&name##SRC, &ptr, sizeof(PFN_##name)); \ } RGFWDEF void RGFW_window_getVisual(XVisualInfo * visual, RGFW_bool transparent); void RGFW_window_getVisual(XVisualInfo * visual, RGFW_bool transparent) { visual->visual = DefaultVisual(_RGFW->display, DefaultScreen(_RGFW->display)); visual->depth = DefaultDepth(_RGFW->display, DefaultScreen(_RGFW->display)); if (transparent) { XMatchVisualInfo(_RGFW->display, DefaultScreen(_RGFW->display), 32, TrueColor, visual); /* !< for RGBA * backgrounds */ if (visual->depth != 32) RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, "Failed to load a 32-bit depth."); } } RGFWDEF int RGFW_XErrorHandler(Display * display, XErrorEvent * ev); int RGFW_XErrorHandler(Display * display, XErrorEvent * ev) { char errorText[512]; XGetErrorText(display, ev->error_code, errorText, sizeof(errorText)); char buf[1024]; RGFW_SNPRINTF(buf, sizeof(buf), "[X Error] %s\n Error code: %d\n Request code: %d\n Minor code: %d\n Serial: %lu\n", errorText, ev->error_code, ev->request_code, ev->minor_code, ev->serial); RGFW_sendDebugInfo(RGFW_typeError, RGFW_errX11, buf); _RGFW->x11Error = ev; return 0; } void RGFW_XCreateWindow(XVisualInfo visual, const char *name, RGFW_windowFlags flags, RGFW_window * win){ i64 event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | FocusChangeMask | LeaveWindowMask | EnterWindowMask | ExposureMask | VisibilityChangeMask | PropertyChangeMask; /* make X window attrubutes */ XSetWindowAttributes swa; RGFW_MEMSET(&swa, 0, sizeof(swa)); Colormap cmap; swa.colormap = cmap = XCreateColormap(_RGFW->display, DefaultRootWindow(_RGFW->display), visual.visual, AllocNone); swa.event_mask = event_mask; swa.background_pixmap = None; /* create the window */ win->src.window = XCreateWindow(_RGFW->display, DefaultRootWindow(_RGFW->display), win->x, win->y, (u32) win->w, (u32) win->h, 0, visual.depth, InputOutput, visual.visual, CWBorderPixel | CWColormap | CWEventMask, &swa); XFreeColors(_RGFW->display, cmap, NULL, 0, 0); XSaveContext(_RGFW->display, win->src.window, _RGFW->context, (XPointer) win); win->src.gc = XCreateGC(_RGFW->display, win->src.window, 0, NULL); /* * In your .desktop app, if you set the property * StartupWMClass=RGFW that will assoicate the launcher icon * with your application - robrohan */ if (_RGFW->className == NULL) _RGFW->className = (char *)name; XClassHint hint; hint.res_class = (char *)_RGFW->className; if (_RGFW->instName == NULL) hint.res_name = (char *)name; else hint.res_name = (char *)_RGFW->instName; XSetClassHint(_RGFW->display, win->src.window, &hint); #ifndef RGFW_NO_MONITOR if (flags & RGFW_windowScaleToMonitor) RGFW_window_scaleToMonitor(win); #endif XSelectInput(_RGFW->display, (Drawable) win->src.window, event_mask); /* !< tell X11 what * events we want */ /* * make it so the user can't close the window until the program * does */ RGFW_LOAD_ATOM(WM_DELETE_WINDOW); XSetWMProtocols(_RGFW->display, (Drawable) win->src.window, &WM_DELETE_WINDOW, 1); /* set the background */ RGFW_window_setName(win, name); XMoveWindow(_RGFW->display, (Drawable) win->src.window, win->x, win->y); /* !< move the window to * it's proper cords */ if (flags & RGFW_windowAllowDND) { /* init drag and drop * atoms and turn on * drag and drop for * this window */ win->internal.flags |= RGFW_windowAllowDND; /* actions */ Atom XdndAware = XInternAtom(_RGFW->display, "XdndAware", False); const u8 version = 5; XChangeProperty(_RGFW->display, win->src.window, XdndAware, 4, 32, PropModeReplace, &version, 1); /* !< turns on drag and * drop */ } #ifdef RGFW_ADVANCED_SMOOTH_RESIZE RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST_COUNTER) RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST) Atom protcols[2] = {_NET_WM_SYNC_REQUEST, WM_DELETE_WINDOW}; XSetWMProtocols(_RGFW->display, win->src.window, protcols, 2); XSyncValue initial_value; XSyncIntToValue(&initial_value, 0); win->src.counter = XSyncCreateCounter(_RGFW->display, initial_value); XChangeProperty(_RGFW->display, win->src.window, _NET_WM_SYNC_REQUEST_COUNTER, XA_CARDINAL, 32, PropModeReplace, (uint8_t *) & win->src.counter, 1); #endif win->src.x = win->x; win->src.y = win->y; win->src.w = win->w; win->src.h = win->h; XSetWindowBackground(_RGFW->display, win->src.window, None); XClearWindow(_RGFW->display, win->src.window); /* stupid hack to make resizing the window less bad */ XSetWindowBackgroundPixmap(_RGFW->display, win->src.window, None); } RGFW_window *RGFW_FUNC(RGFW_createWindowPlatform) (const char *name, RGFW_windowFlags flags, RGFW_window * win){ if ((flags & RGFW_windowOpenGL) || (flags & RGFW_windowEGL)) { win->src.window = 0; return win; } XVisualInfo visual; RGFW_window_getVisual(&visual, RGFW_BOOL(win->internal.flags & RGFW_windowTransparent)); RGFW_XCreateWindow(visual, name, flags, win); return win; /* return newly created window */ } RGFW_bool RGFW_FUNC(RGFW_getGlobalMouse) (i32 * fX, i32 * fY) { RGFW_init(); i32 x, y; u32 z; Window window1, window2; XQueryPointer(_RGFW->display, XDefaultRootWindow(_RGFW->display), &window1, &window2, fX, fY, &x, &y, &z); return RGFW_TRUE; } RGFWDEF void RGFW_XHandleClipboardSelection(XEvent * event); void RGFW_XHandleClipboardSelection(XEvent * event) { RGFW_UNUSED(event); RGFW_LOAD_ATOM(ATOM_PAIR); RGFW_LOAD_ATOM(MULTIPLE); RGFW_LOAD_ATOM(TARGETS); RGFW_LOAD_ATOM(SAVE_TARGETS); RGFW_LOAD_ATOM(UTF8_STRING); const XSelectionRequestEvent *request = &event->xselectionrequest; const Atom formats[] = {UTF8_STRING, XA_STRING}; const int formatCount = sizeof(formats) / sizeof(formats[0]); if (request->target == TARGETS) { const Atom targets[] = {TARGETS, MULTIPLE, UTF8_STRING, XA_STRING}; XChangeProperty(_RGFW->display, request->requestor, request->property, XA_ATOM, 32, PropModeReplace, (u8 *) targets, sizeof(targets) / sizeof(Atom)); } else if (request->target == MULTIPLE) { Atom * targets = NULL; Atom actualType = 0; int actualFormat = 0; unsigned long count = 0, bytesAfter = 0; XGetWindowProperty(_RGFW->display, request->requestor, request->property, 0, LONG_MAX, False, ATOM_PAIR, &actualType, &actualFormat, &count, &bytesAfter, (u8 * *) & targets); unsigned long i; for (i = 0; i < (u32) count; i += 2) { if (targets[i] == UTF8_STRING || targets[i] == XA_STRING) XChangeProperty(_RGFW->display, request->requestor, targets[i + 1], targets[i], 8, PropModeReplace, (const unsigned char *)_RGFW->clipboard, (i32) _RGFW->clipboard_len); else targets[i + 1] = None; } XChangeProperty(_RGFW->display, request->requestor, request->property, ATOM_PAIR, 32, PropModeReplace, (u8 *) targets, (i32) count); XFlush(_RGFW->display); XFree(targets); } else if (request->target == SAVE_TARGETS) XChangeProperty(_RGFW->display, request->requestor, request->property, 0, 32, PropModeReplace, NULL, 0); else { int i; for (i = 0; i < formatCount; i++) { if (request->target != formats[i]) continue; XChangeProperty(_RGFW->display, request->requestor, request->property, request->target, 8, PropModeReplace, (u8 *) _RGFW->clipboard, (i32) _RGFW->clipboard_len); } } XEvent reply = {SelectionNotify}; reply.xselection.property = request->property; reply.xselection.display = request->display; reply.xselection.requestor = request->requestor; reply.xselection.selection = request->selection; reply.xselection.target = request->target; reply.xselection.time = request->time; XSendEvent(_RGFW->display, request->requestor, False, 0, &reply); XFlush(_RGFW->display); } i32 RGFW_XHandleClipboardSelectionHelper(void); u8 RGFW_FUNC(RGFW_rgfwToKeyChar) (u32 key) { u32 keycode = RGFW_rgfwToApiKey(key); Window root = DefaultRootWindow(_RGFW->display); Window ret_root, ret_child; int root_x, root_y, win_x, win_y; unsigned int mask; XQueryPointer(_RGFW->display, root, &ret_root, &ret_child, &root_x, &root_y, &win_x, &win_y, &mask); KeySym sym = (KeySym) XkbKeycodeToKeysym(_RGFW->display, (KeyCode) keycode, 0, (KeyCode) mask & ShiftMask ? 1 : 0); if ((mask & LockMask) && sym >= XK_a && sym <= XK_z) sym = (mask & ShiftMask) ? sym + 32 : sym - 32; if ((u8) sym != (u32) sym) sym = 0; return (u8) sym; } RGFWDEF void RGFW_XHandleEvent(void); void RGFW_XHandleEvent(void){ RGFW_LOAD_ATOM(XdndTypeList); RGFW_LOAD_ATOM(XdndSelection); RGFW_LOAD_ATOM(XdndEnter); RGFW_LOAD_ATOM(XdndPosition); RGFW_LOAD_ATOM(XdndStatus); RGFW_LOAD_ATOM(XdndLeave); RGFW_LOAD_ATOM(XdndDrop); RGFW_LOAD_ATOM(XdndFinished); RGFW_LOAD_ATOM(XdndActionCopy); RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST); RGFW_LOAD_ATOM(WM_PROTOCOLS); RGFW_LOAD_ATOM(WM_STATE); RGFW_LOAD_ATOM(_NET_WM_STATE); /* xdnd data */ static Window source = 0; static long version = 0; static i32 format = 0; XEvent reply = {ClientMessage}; XEvent E; RGFW_event event; RGFW_MEMSET(&event, 0, sizeof(event)); XNextEvent(_RGFW->display, &E); switch (E.type) { case SelectionRequest: RGFW_XHandleClipboardSelection(&E); return; case GenericEvent:{ RGFW_window *win = _RGFW->mouseOwner; if (win == NULL) return; if (!(win->internal.enabledEvents & RGFW_BIT(RGFW_mousePosChanged))) return; /* * MotionNotify is used for mouse events if the * mouse isn't held */ if (!(win->internal.holdMouse)) { XFreeEventData(_RGFW->display, &E.xcookie); return; } XGetEventData(_RGFW->display, &E.xcookie); if (E.xcookie.evtype == XI_RawMotion) { XIRawEvent * raw = (XIRawEvent *) E.xcookie.data; if (raw->valuators.mask_len == 0) { XFreeEventData(_RGFW->display, &E.xcookie); return; } double deltaX = 0.0f; double deltaY = 0.0f; /* * check if relative motion data exists * where we think it does */ if (XIMaskIsSet(raw->valuators.mask, 0) != 0) deltaX += raw->raw_values[0]; if (XIMaskIsSet(raw->valuators.mask, 1) != 0) deltaY += raw->raw_values[1]; event.mouse.vecX = (float)deltaX; event.mouse.vecY = (float)deltaY; _RGFW->vectorX = (float)event.mouse.vecX; _RGFW->vectorY = (float)event.mouse.vecY; event.mouse.x = win->internal.lastMouseX + (i32) event.mouse.vecX; event.mouse.y = win->internal.lastMouseY + (i32) event.mouse.vecY; win->internal.lastMouseX = event.mouse.x; win->internal.lastMouseY = event.mouse.y; RGFW_window_moveMouse(win, win->x + (win->w / 2), win->y + (win->h / 2)); event.type = RGFW_mousePosChanged; RGFW_mousePosCallback(win, event.mouse.x, event.mouse.y, (float)event.mouse.vecX, (float)event.mouse.vecY); } XFreeEventData(_RGFW->display, &E.xcookie); if (event.type) RGFW_eventQueuePush(&event); return; } } RGFW_window *win = NULL; if (XFindContext(_RGFW->display, E.xany.window, _RGFW->context, (XPointer *) & win) != 0) { return; } event.common.win = win; /* * Repeated key presses are sent as a release followed by * another press at the same time. We want to convert that into * a single key press event with the repeat flag set */ if (E.type == KeyRelease && XEventsQueued(_RGFW->display, QueuedAfterReading)) { XEvent NE; XPeekEvent(_RGFW->display, &NE); if (NE.type == KeyPress && E.xkey.time == NE.xkey.time && E.xkey.keycode == NE.xkey.keycode) { /* Use the next KeyPress event */ XNextEvent(_RGFW->display, &E); event.key.repeat = RGFW_TRUE; } } switch (E.type) { case KeyPress:{ if (!(win->internal.enabledEvents & RGFW_keyPressedFlag)) return; event.type = RGFW_keyPressed; event.key.value = (u8) RGFW_apiKeyToRGFW(E.xkey.keycode); event.key.sym = (u8) RGFW_rgfwToKeyChar(event.key.value); _RGFW->keyboard[event.key.value].prev = _RGFW->keyboard[event.key.value].current; _RGFW->keyboard[event.key.value].current = RGFW_TRUE; XkbStateRec state; XkbGetState(_RGFW->display, XkbUseCoreKbd, &state); RGFW_updateKeyMods(win, (state.locked_mods & LockMask), (state.locked_mods & Mod2Mask), (state.locked_mods & Mod3Mask)); RGFW_keyCallback(win, event.key.value, event.key.sym, win->internal.mod, event.key.repeat, RGFW_TRUE); break; } case KeyRelease:{ if (!(win->internal.enabledEvents & RGFW_keyReleasedFlag)) return; event.type = RGFW_keyReleased; event.key.value = (u8) RGFW_apiKeyToRGFW(E.xkey.keycode); event.key.sym = (u8) RGFW_rgfwToKeyChar(event.key.value); /* get keystate data */ _RGFW->keyboard[event.key.value].prev = _RGFW->keyboard[event.key.value].current; _RGFW->keyboard[event.key.value].current = RGFW_FALSE; XkbStateRec state; XkbGetState(_RGFW->display, XkbUseCoreKbd, &state); RGFW_updateKeyMods(win, (state.locked_mods & LockMask), (state.locked_mods & Mod2Mask), (state.locked_mods & Mod3Mask)); RGFW_keyCallback(win, event.key.value, event.key.sym, win->internal.mod, event.key.repeat, RGFW_FALSE); break; } case ButtonPress: if (E.xbutton.button >= Button4 && E.xbutton.button <= 7) { if (!(win->internal.enabledEvents & RGFW_mouseScrollFlag)) return; event.type = RGFW_mouseScroll; } else { if (!(win->internal.enabledEvents & RGFW_mouseButtonPressedFlag) || E.xbutton.button > RGFW_mouseFinal) return; event.type = RGFW_mouseButtonPressed; } switch (E.xbutton.button) { case Button1:event.button.value = RGFW_mouseLeft; break; case Button2:event.button.value = RGFW_mouseMiddle; break; case Button3:event.button.value = RGFW_mouseRight; break; case Button4:event.scroll.y = 1.0; break; case Button5:event.scroll.y = -1.0; break; case 6:event.scroll.x = 1.0f; break; case 7:event.scroll.x = -1.0f; break; default: event.button.value = (u8) E.xbutton.button - Button1 - 4; break; } if (event.type == RGFW_mouseScroll) { _RGFW->scrollX = event.scroll.x; _RGFW->scrollY = event.scroll.y; RGFW_mouseScrollCallback(win, event.scroll.x, event.scroll.y); break; } _RGFW->mouseButtons[event.button.value].prev = _RGFW->mouseButtons[event.button.value].current; _RGFW->mouseButtons[event.button.value].current = RGFW_TRUE; RGFW_mouseButtonCallback(win, event.button.value, RGFW_TRUE); break; case ButtonRelease: if (E.xbutton.button >= Button4 && E.xbutton.button <= 7) break; if (!(win->internal.enabledEvents & RGFW_mouseButtonReleasedFlag) || E.xbutton.button > RGFW_mouseFinal) return; event.type = RGFW_mouseButtonReleased; switch (E.xbutton.button) { case Button1:event.button.value = RGFW_mouseLeft; break; case Button2:event.button.value = RGFW_mouseMiddle; break; case Button3:event.button.value = RGFW_mouseRight; break; default: event.button.value = (u8) E.xbutton.button - Button1 - 4; break; } _RGFW->mouseButtons[event.button.value].prev = _RGFW->mouseButtons[event.button.value].current; _RGFW->mouseButtons[event.button.value].current = RGFW_FALSE; RGFW_mouseButtonCallback(win, event.button.value, RGFW_FALSE); break; case MotionNotify: if (win->internal.holdMouse) return; if (!(win->internal.enabledEvents & RGFW_mousePosChangedFlag)) return; event.mouse.x = E.xmotion.x; event.mouse.y = E.xmotion.y; event.mouse.vecX = (float)(event.mouse.x - win->internal.lastMouseX); event.mouse.vecY = (float)(event.mouse.y - win->internal.lastMouseY); _RGFW->vectorX = event.mouse.vecX; _RGFW->vectorY = event.mouse.vecY; win->internal.lastMouseX = event.mouse.x; win->internal.lastMouseY = event.mouse.y; event.type = RGFW_mousePosChanged; RGFW_mousePosCallback(win, event.mouse.x, event.mouse.y, (float)event.mouse.vecX, (float)event.mouse.vecY); break; case Expose:{ if (!(win->internal.enabledEvents & RGFW_windowRefreshFlag)) return; event.type = RGFW_windowRefresh; RGFW_windowRefreshCallback(win); #ifdef RGFW_ADVANCED_SMOOTH_RESIZE XSyncValue value; XSyncIntToValue(&value, (i32) win->src.counter_value); XSyncSetCounter(_RGFW->display, win->src.counter, value); #endif break; } case PropertyNotify: if (E.xproperty.state != PropertyNewValue) break; if (E.xproperty.atom == WM_STATE) { if (RGFW_window_isMinimized(win) && !(win->internal.flags & RGFW_windowMinimized)) { win->internal.flags |= RGFW_windowMinimize; RGFW_eventQueuePushEx(e.type = RGFW_windowMinimized; e.common.win = win); RGFW_windowMinimizedCallback(win); break; } } else if (E.xproperty.atom == _NET_WM_STATE) { if (!(win->internal.flags & RGFW_windowMaximize)) { win->internal.flags |= RGFW_windowMaximize; RGFW_eventQueuePushEx(e.type = RGFW_windowMaximized; e.common.win = win); RGFW_windowMaximizedCallback(win, win->x, win->y, win->w, win->h); break; } } RGFW_window_checkMode(win); break; case MapNotify:case UnmapNotify:RGFW_window_checkMode(win); break; case ClientMessage:{ RGFW_LOAD_ATOM(WM_DELETE_WINDOW); /* if the client closed the window */ if (E.xclient.data.l[0] == (long)WM_DELETE_WINDOW) { event.type = RGFW_quit; RGFW_window_setShouldClose(win, RGFW_TRUE); RGFW_windowQuitCallback(win); break; } #ifdef RGFW_ADVANCED_SMOOTH_RESIZE if (E.xclient.message_type == WM_PROTOCOLS && (Atom) E.xclient.data.l[0] == _NET_WM_SYNC_REQUEST) { RGFW_windowRefreshCallback(win); win->src.counter_value = 0; win->src.counter_value |= E.xclient.data.l[2]; win->src.counter_value |= (E.xclient.data.l[3] << 32); XSyncValue value; XSyncIntToValue(&value, (i32) win->src.counter_value); XSyncSetCounter(_RGFW->display, win->src.counter, value); break; } #endif if ((win->internal.flags & RGFW_windowAllowDND) == 0) return; reply.xclient.window = source; reply.xclient.format = 32; reply.xclient.data.l[0] = (long)win->src.window; reply.xclient.data.l[1] = 0; reply.xclient.data.l[2] = None; if (E.xclient.message_type == XdndEnter) { if (version > 5) break; unsigned long count; Atom *formats; Atom real_formats[6]; Bool list = E.xclient.data.l[1] & 1; source = (unsigned long int)E.xclient.data.l[0]; version = E.xclient.data.l[1] >> 24; format = None; if (list) { Atom actualType; i32 actualFormat; unsigned long bytesAfter; XGetWindowProperty( _RGFW->display, source, XdndTypeList, 0, LONG_MAX, False, 4, &actualType, &actualFormat, &count, &bytesAfter, (u8 * *) & formats ); } else { count = 0; size_t i; for (i = 2; i < 5; i++) { if (E.xclient.data.l[i] != None) { real_formats[count] = (unsigned long int)E.xclient.data.l[i]; count += 1; } } formats = real_formats; } Atom XtextPlain = XInternAtom(_RGFW->display, "text/plain", False); Atom XtextUriList = XInternAtom(_RGFW->display, "text/uri-list", False); size_t i; for (i = 0; i < count; i++) { if (formats[i] == XtextUriList || formats[i] == XtextPlain) { format = (int)formats[i]; break; } } if (list) { XFree(formats); } break; } if (E.xclient.message_type == XdndPosition) { const i32 xabs = (E.xclient.data.l[2] >> 16) & 0xffff; const i32 yabs = (E.xclient.data.l[2]) & 0xffff; Window dummy; i32 xpos, ypos; if (version > 5) break; XTranslateCoordinates( _RGFW->display, XDefaultRootWindow(_RGFW->display), win->src.window, xabs, yabs, &xpos, &ypos, &dummy ); event.drag.x = xpos; event.drag.y = ypos; reply.xclient.window = source; reply.xclient.message_type = XdndStatus; if (format) { reply.xclient.data.l[1] = 1; if (version >= 2) reply.xclient.data.l[4] = (long)XdndActionCopy; } XSendEvent(_RGFW->display, source, False, NoEventMask, &reply); XFlush(_RGFW->display); break; } if (E.xclient.message_type != XdndDrop) break; if (version > 5) break; event.type = RGFW_dataDrag; if (format) { Time time = (version >= 1) ? (Time) E.xclient.data.l[2] : CurrentTime; XConvertSelection( _RGFW->display, XdndSelection, (Atom) format, XdndSelection, win->src.window, time ); } else if (version >= 2) { XEvent new_reply = {ClientMessage}; XSendEvent(_RGFW->display, source, False, NoEventMask, &new_reply); XFlush(_RGFW->display); } _RGFW->windowState.win = win; _RGFW->windowState.dataDragging = RGFW_TRUE; _RGFW->windowState.dropX = event.drag.x; _RGFW->windowState.dropY = event.drag.y; if (win->internal.enabledEvents & RGFW_dataDragFlag) return; RGFW_dataDragCallback(win, event.drag.x, event.drag.y); } break; case SelectionNotify:{ /* this is only for checking for xdnd drops */ if (!(win->internal.enabledEvents & RGFW_dataDropFlag) || E.xselection.property != XdndSelection || !(win->internal.flags & RGFW_windowAllowDND)) return; char *data; unsigned long result; Atom actualType; i32 actualFormat; unsigned long bytesAfter; XGetWindowProperty(_RGFW->display, E.xselection.requestor, E.xselection.property, 0, LONG_MAX, False, E.xselection.target, &actualType, &actualFormat, &result, &bytesAfter, (u8 * *) & data); if (result == 0) break; const char *prefix = (const char *)"file://"; char *line; event.drop.files = _RGFW->files; event.drop.count = 0; event.type = RGFW_dataDrop; while ((line = (char *)RGFW_strtok(data, "\r\n"))) { char path[RGFW_MAX_PATH]; data = NULL; if (line[0] == '#') continue; char *l; for (l = line; 1; l++) { if ((l - line) > 7) break; else if (*l != prefix[(l - line)]) break; else if (*l == '\0' && prefix[(l - line)] == '\0') { line += 7; while (*line != '/') line++; break; } else if (*l == '\0') break; } event.drop.count++; size_t index = 0; while (*line) { if (line[0] == '%' && line[1] && line[2]) { const char digits[3] = {line[1], line[2], '\0'}; path[index] = (char)RGFW_STRTOL(digits, NULL, 16); line += 2; } else path[index] = *line; index++; line++; } path[index] = '\0'; RGFW_MEMCPY(event.drop.files[event.drop.count - 1], path, index + 1); } _RGFW->windowState.win = win; _RGFW->windowState.dataDrop = RGFW_TRUE; _RGFW->windowState.filesCount = event.drop.count; RGFW_dataDropCallback(win, event.drop.files, event.drop.count); if (data) XFree(data); if (version >= 2) { XEvent new_reply = {ClientMessage}; new_reply.xclient.window = source; new_reply.xclient.message_type = XdndFinished; new_reply.xclient.format = 32; new_reply.xclient.data.l[1] = (long int)result; new_reply.xclient.data.l[2] = (long int)XdndActionCopy; XSendEvent(_RGFW->display, source, False, NoEventMask, &new_reply); XFlush(_RGFW->display); } break; } case FocusIn: if ((win->internal.flags & RGFW_windowFullscreen)) XMapRaised(_RGFW->display, win->src.window); if ((win->internal.holdMouse)) RGFW_window_holdMouse(win); if (!(win->internal.enabledEvents & RGFW_focusInFlag)) return; win->internal.inFocus = RGFW_TRUE; event.type = RGFW_focusIn; RGFW_focusCallback(win, 1); break; case FocusOut: if (!(win->internal.enabledEvents & RGFW_focusOutFlag)) return; event.type = RGFW_focusOut; RGFW_focusCallback(win, 0); RGFW_window_focusLost(win); break; case EnterNotify:{ win->internal.mouseInside = RGFW_TRUE; _RGFW->windowState.win = win; _RGFW->windowState.mouseEnter = RGFW_TRUE; if (!(win->internal.enabledEvents & RGFW_mouseEnterFlag)) return; event.type = RGFW_mouseEnter; event.mouse.x = E.xcrossing.x; event.mouse.y = E.xcrossing.y; RGFW_mouseNotifyCallback(win, event.mouse.x, event.mouse.y, 1); break; } case LeaveNotify:{ win->internal.mouseInside = RGFW_FALSE; _RGFW->windowState.winLeave = win; _RGFW->windowState.mouseLeave = RGFW_TRUE; if (!(win->internal.enabledEvents & RGFW_mouseLeaveFlag)) return; event.type = RGFW_mouseLeave; RGFW_mouseNotifyCallback(win, event.mouse.x, event.mouse.y, 0); break; } case ConfigureNotify:{ /* detect resize */ RGFW_window_checkMode(win); if (E.xconfigure.width != win->src.w || E.xconfigure.height != win->src.h) { win->src.w = win->w = E.xconfigure.width; win->src.h = win->h = E.xconfigure.height; if (!(win->internal.enabledEvents & RGFW_windowResizedFlag)) return; event.type = RGFW_windowResized; RGFW_windowResizedCallback(win, win->w, win->h); RGFW_eventQueuePush(&event); } /* detect move */ if (E.xconfigure.x != win->src.x || E.xconfigure.y != win->src.y) { win->src.x = win->x = E.xconfigure.x; win->src.y = win->y = E.xconfigure.y; if (!(win->internal.enabledEvents & RGFW_windowMovedFlag)) return; event.type = RGFW_windowMoved; RGFW_windowMovedCallback(win, win->x, win->y); RGFW_eventQueuePush(&event); } return; } default: break; } if (event.type) { RGFW_eventQueuePush(&event); } XFlush(_RGFW->display); } void RGFW_FUNC(RGFW_pollEvents) (void){ RGFW_resetPrevState(); XPending(_RGFW->display); /* if there is no unread queued events, get a new one */ while ((QLength(_RGFW->display) || XEventsQueued(_RGFW->display, QueuedAlready) + XEventsQueued(_RGFW->display, QueuedAfterReading))) { RGFW_XHandleEvent(); } } void RGFW_FUNC(RGFW_window_move) (RGFW_window * win, i32 x, i32 y) { RGFW_ASSERT(win != NULL); win->x = x; win->y = y; XMoveWindow(_RGFW->display, win->src.window, x, y); return; } void RGFW_FUNC(RGFW_window_resize) (RGFW_window * win, i32 w, i32 h) { RGFW_ASSERT(win != NULL); win->w = (i32) w; win->h = (i32) h; XResizeWindow(_RGFW->display, win->src.window, (u32) w, (u32) h); if ((win->internal.flags & RGFW_windowNoResize)) { XSizeHints sh; sh.flags = (1L << 4) | (1L << 5); sh.min_width = sh.max_width = (i32) w; sh.min_height = sh.max_height = (i32) h; XSetWMSizeHints(_RGFW->display, (Drawable) win->src.window, &sh, XA_WM_NORMAL_HINTS); } return; } void RGFW_FUNC(RGFW_window_setAspectRatio) (RGFW_window * win, i32 w, i32 h) { RGFW_ASSERT(win != NULL); if (w == 0 && h == 0) return; XSizeHints hints; long flags; XGetWMNormalHints(_RGFW->display, win->src.window, &hints, &flags); hints.flags |= PAspect; hints.min_aspect.x = hints.max_aspect.x = (i32) w; hints.min_aspect.y = hints.max_aspect.y = (i32) h; XSetWMNormalHints(_RGFW->display, win->src.window, &hints); return; } void RGFW_FUNC(RGFW_window_setMinSize) (RGFW_window * win, i32 w, i32 h) { RGFW_ASSERT(win != NULL); long flags; XSizeHints hints; RGFW_MEMSET(&hints, 0, sizeof(XSizeHints)); XGetWMNormalHints(_RGFW->display, win->src.window, &hints, &flags); hints.flags |= PMinSize; hints.min_width = (i32) w; hints.min_height = (i32) h; XSetWMNormalHints(_RGFW->display, win->src.window, &hints); return; } void RGFW_FUNC(RGFW_window_setMaxSize) (RGFW_window * win, i32 w, i32 h) { RGFW_ASSERT(win != NULL); long flags; XSizeHints hints; RGFW_MEMSET(&hints, 0, sizeof(XSizeHints)); XGetWMNormalHints(_RGFW->display, win->src.window, &hints, &flags); hints.flags |= PMaxSize; hints.max_width = (i32) w; hints.max_height = (i32) h; XSetWMNormalHints(_RGFW->display, win->src.window, &hints); return; } void RGFW_toggleXMaximized(RGFW_window * win, RGFW_bool maximized); void RGFW_toggleXMaximized(RGFW_window * win, RGFW_bool maximized) { RGFW_ASSERT(win != NULL); RGFW_LOAD_ATOM(_NET_WM_STATE); RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_VERT); RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ); XEvent xev = {0}; xev.type = ClientMessage; xev.xclient.window = win->src.window; xev.xclient.message_type = _NET_WM_STATE; xev.xclient.format = 32; xev.xclient.data.l[0] = maximized; xev.xclient.data.l[1] = (long int)_NET_WM_STATE_MAXIMIZED_HORZ; xev.xclient.data.l[2] = (long int)_NET_WM_STATE_MAXIMIZED_VERT; xev.xclient.data.l[3] = 0; xev.xclient.data.l[4] = 0; XSendEvent(_RGFW->display, DefaultRootWindow(_RGFW->display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); } void RGFW_FUNC(RGFW_window_maximize) (RGFW_window * win) { win->internal.oldX = win->x; win->internal.oldY = win->y; win->internal.oldW = win->w; win->internal.oldH = win->h; RGFW_toggleXMaximized(win, 1); return; } void RGFW_FUNC(RGFW_window_focus) (RGFW_window * win) { RGFW_ASSERT(win); XWindowAttributes attr; XGetWindowAttributes(_RGFW->display, win->src.window, &attr); if (attr.map_state != IsViewable) return; XSetInputFocus(_RGFW->display, win->src.window, RevertToPointerRoot, CurrentTime); XFlush(_RGFW->display); } void RGFW_FUNC(RGFW_window_raise) (RGFW_window * win) { RGFW_ASSERT(win); XRaiseWindow(_RGFW->display, win->src.window); XMapRaised(_RGFW->display, win->src.window); } void RGFW_window_setXAtom(RGFW_window * win, Atom netAtom, RGFW_bool fullscreen); void RGFW_window_setXAtom(RGFW_window * win, Atom netAtom, RGFW_bool fullscreen) { RGFW_ASSERT(win != NULL); RGFW_LOAD_ATOM(_NET_WM_STATE); XEvent xev = {0}; xev.xclient.type = ClientMessage; xev.xclient.serial = 0; xev.xclient.send_event = True; xev.xclient.message_type = _NET_WM_STATE; xev.xclient.window = win->src.window; xev.xclient.format = 32; xev.xclient.data.l[0] = fullscreen; xev.xclient.data.l[1] = (long int)netAtom; xev.xclient.data.l[2] = 0; XSendEvent(_RGFW->display, DefaultRootWindow(_RGFW->display), False, SubstructureNotifyMask | SubstructureRedirectMask, &xev); } void RGFW_FUNC(RGFW_window_setFullscreen) (RGFW_window * win, RGFW_bool fullscreen) { RGFW_ASSERT(win != NULL); if (fullscreen) { win->internal.flags |= RGFW_windowFullscreen; win->internal.oldX = win->x; win->internal.oldY = win->y; win->internal.oldW = win->w; win->internal.oldH = win->h; } else win->internal.flags &= ~(u32) RGFW_windowFullscreen; RGFW_LOAD_ATOM(_NET_WM_STATE_FULLSCREEN); RGFW_window_setXAtom(win, _NET_WM_STATE_FULLSCREEN, fullscreen); XRaiseWindow(_RGFW->display, win->src.window); XMapRaised(_RGFW->display, win->src.window); } void RGFW_FUNC(RGFW_window_setFloating) (RGFW_window * win, RGFW_bool floating) { RGFW_ASSERT(win != NULL); RGFW_LOAD_ATOM(_NET_WM_STATE_ABOVE); RGFW_window_setXAtom(win, _NET_WM_STATE_ABOVE, floating); } void RGFW_FUNC(RGFW_window_setOpacity) (RGFW_window * win, u8 opacity) { RGFW_ASSERT(win != NULL); const u32 value = (u32) (0xffffffffu * (double)opacity); RGFW_LOAD_ATOM(NET_WM_WINDOW_OPACITY); XChangeProperty(_RGFW->display, win->src.window, NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&value, 1); } void RGFW_FUNC(RGFW_window_minimize) (RGFW_window * win) { RGFW_ASSERT(win != NULL); if (RGFW_window_isMaximized(win)) return; win->internal.oldX = win->x; win->internal.oldY = win->y; win->internal.oldW = win->w; win->internal.oldH = win->h; XIconifyWindow(_RGFW->display, win->src.window, DefaultScreen(_RGFW->display)); XFlush(_RGFW->display); } void RGFW_FUNC(RGFW_window_restore) (RGFW_window * win) { RGFW_ASSERT(win != NULL); RGFW_toggleXMaximized(win, RGFW_FALSE); RGFW_window_move(win, win->internal.oldX, win->internal.oldY); RGFW_window_resize(win, win->internal.oldW, win->internal.oldH); RGFW_window_show(win); XFlush(_RGFW->display); } RGFW_bool RGFW_FUNC(RGFW_window_isFloating) (RGFW_window * win) { RGFW_LOAD_ATOM(_NET_WM_STATE); RGFW_LOAD_ATOM(_NET_WM_STATE_ABOVE); Atom actual_type; int actual_format; unsigned long nitems, bytes_after; Atom *prop_return = NULL; int status = XGetWindowProperty(_RGFW->display, win->src.window, _NET_WM_STATE, 0, (~0L), False, XA_ATOM, &actual_type, &actual_format, &nitems, &bytes_after, (unsigned char **)&prop_return); if (status != Success || actual_type != XA_ATOM) return RGFW_FALSE; unsigned long i; for (i = 0; i < nitems; i++) if (prop_return[i] == _NET_WM_STATE_ABOVE) return RGFW_TRUE; if (prop_return) XFree(prop_return); return RGFW_FALSE; } void RGFW_FUNC(RGFW_window_setName) (RGFW_window * win, const char *name){ RGFW_ASSERT(win != NULL); XStoreName(_RGFW->display, win->src.window, name); RGFW_LOAD_ATOM(_NET_WM_NAME); RGFW_LOAD_ATOM(UTF8_STRING); char buf[256]; RGFW_MEMSET(buf, 0, sizeof(buf)); RGFW_STRNCPY(buf, name, sizeof(buf) - 1); XChangeProperty( _RGFW->display, win->src.window, _NET_WM_NAME, UTF8_STRING, 8, PropModeReplace, (u8 *) buf, sizeof(buf) ); } #ifndef RGFW_NO_PASSTHROUGH void RGFW_FUNC(RGFW_window_setMousePassthrough) (RGFW_window * win, RGFW_bool passthrough) { RGFW_ASSERT(win != NULL); if (passthrough) { Region region = XCreateRegion(); XShapeCombineRegion(_RGFW->display, win->src.window, ShapeInput, 0, 0, region, ShapeSet); XDestroyRegion(region); return; } XShapeCombineMask(_RGFW->display, win->src.window, ShapeInput, 0, 0, None, ShapeSet); } #endif /* RGFW_NO_PASSTHROUGH */ RGFW_bool RGFW_FUNC(RGFW_window_setIconEx) (RGFW_window * win, u8 * data_src, i32 w, i32 h, RGFW_format format, RGFW_icon type) { Atom _NET_WM_ICON = XInternAtom(_RGFW->display, "_NET_WM_ICON", False); RGFW_ASSERT(win != NULL); if (data_src == NULL) { RGFW_bool res = (RGFW_bool) XChangeProperty( _RGFW->display, win->src.window, _NET_WM_ICON, XA_CARDINAL, 32, PropModeReplace, (u8 *) NULL, 0 ); return res; } i32 count = (i32) (2 + (w * h)); unsigned long *data = (unsigned long *)RGFW_ALLOC((u32) count * sizeof(unsigned long)); RGFW_ASSERT(data != NULL); RGFW_MEMSET(data, 0, (u32) count * sizeof(unsigned long)); data[0] = (unsigned long)w; data[1] = (unsigned long)h; RGFW_copyImageData64((u8 *) & data[2], w, h, RGFW_formatBGRA8, data_src, format, RGFW_TRUE); RGFW_bool res = RGFW_TRUE; if (type & RGFW_iconTaskbar) { res = (RGFW_bool) XChangeProperty( _RGFW->display, win->src.window, _NET_WM_ICON, XA_CARDINAL, 32, PropModeReplace, (u8 *) data, count ); } RGFW_copyImageData64((u8 *) & data[2], w, h, RGFW_formatBGRA8, data_src, format, RGFW_FALSE); if (type & RGFW_iconWindow) { XWMHints wm_hints; wm_hints.flags = IconPixmapHint; i32 depth = DefaultDepth(_RGFW->display, DefaultScreen(_RGFW->display)); XImage *image = XCreateImage(_RGFW->display, DefaultVisual(_RGFW->display, DefaultScreen(_RGFW->display)), (u32) depth, ZPixmap, 0, (char *)&data[2], (u32) w, (u32) h, 32, 0); wm_hints.icon_pixmap = XCreatePixmap(_RGFW->display, win->src.window, (u32) w, (u32) h, (u32) depth); XPutImage(_RGFW->display, wm_hints.icon_pixmap, DefaultGC(_RGFW->display, DefaultScreen(_RGFW->display)), image, 0, 0, 0, 0, (u32) w, (u32) h); image->data = NULL; XDestroyImage(image); XSetWMHints(_RGFW->display, win->src.window, &wm_hints); } RGFW_FREE(data); XFlush(_RGFW->display); return RGFW_BOOL(res); } RGFW_mouse *RGFW_FUNC(RGFW_loadMouse) (u8 * data, i32 w, i32 h, RGFW_format format) { RGFW_ASSERT(data); #ifndef RGFW_NO_X11_CURSOR RGFW_init(); XcursorImage *native = XcursorImageCreate((i32) w, (i32) h); native->xhot = 0; native->yhot = 0; RGFW_MEMSET(native->pixels, 0, (u32) (w * h * 4)); RGFW_copyImageData((u8 *) native->pixels, w, h, RGFW_formatBGRA8, data, format); Cursor cursor = XcursorImageLoadCursor(_RGFW->display, native); XcursorImageDestroy(native); return (void *)cursor; #else RGFW_UNUSED(data); RGFW_UNUSED(w); RGFW_UNUSED(h); RGFW_UNUSED(format); return NULL; #endif } void RGFW_FUNC(RGFW_window_setMouse) (RGFW_window * win, RGFW_mouse * mouse) { RGFW_ASSERT(win && mouse); XDefineCursor(_RGFW->display, win->src.window, (Cursor) mouse); } void RGFW_FUNC(RGFW_freeMouse) (RGFW_mouse * mouse) { RGFW_ASSERT(mouse); XFreeCursor(_RGFW->display, (Cursor) mouse); } void RGFW_FUNC(RGFW_window_moveMouse) (RGFW_window * win, i32 x, i32 y) { RGFW_ASSERT(win != NULL); XEvent event; XQueryPointer(_RGFW->display, DefaultRootWindow(_RGFW->display), &event.xbutton.root, &event.xbutton.window, &event.xbutton.x_root, &event.xbutton.y_root, &event.xbutton.x, &event.xbutton.y, &event.xbutton.state); win->internal.lastMouseX = x - win->x; win->internal.lastMouseY = y - win->y; if (event.xbutton.x == x && event.xbutton.y == y) return; XWarpPointer(_RGFW->display, None, win->src.window, 0, 0, 0, 0, (int)x - win->x, (int)y - win->y); } RGFW_bool RGFW_FUNC(RGFW_window_setMouseDefault) (RGFW_window * win) { return RGFW_window_setMouseStandard(win, RGFW_mouseArrow); } RGFW_bool RGFW_FUNC(RGFW_window_setMouseStandard) (RGFW_window * win, u8 mouse) { RGFW_ASSERT(win != NULL); static const u8 mouseIconSrc[16] = {XC_arrow, XC_left_ptr, XC_xterm, XC_crosshair, XC_hand2, XC_sb_h_double_arrow, XC_sb_v_double_arrow, XC_bottom_left_corner, XC_bottom_right_corner, XC_fleur, XC_X_cursor}; if (mouse > (sizeof(mouseIconSrc) / sizeof(u8))) return RGFW_FALSE; mouse = mouseIconSrc[mouse]; Cursor cursor = XCreateFontCursor(_RGFW->display, mouse); XDefineCursor(_RGFW->display, win->src.window, (Cursor) cursor); XFreeCursor(_RGFW->display, (Cursor) cursor); return RGFW_TRUE; } void RGFW_FUNC(RGFW_window_hide) (RGFW_window * win) { XUnmapWindow(_RGFW->display, win->src.window); } void RGFW_FUNC(RGFW_window_show) (RGFW_window * win) { win->internal.flags &= ~(u32) RGFW_windowHide; if (win->internal.flags & RGFW_windowFocusOnShow) RGFW_window_focus(win); XMapWindow(_RGFW->display, win->src.window); RGFW_window_move(win, win->x, win->y); return; } RGFW_ssize_t RGFW_FUNC(RGFW_readClipboardPtr) (char *str, size_t strCapacity){ RGFW_init(); RGFW_LOAD_ATOM(XSEL_DATA); RGFW_LOAD_ATOM(UTF8_STRING); RGFW_LOAD_ATOM(CLIPBOARD); if (XGetSelectionOwner(_RGFW->display, CLIPBOARD) == _RGFW->helperWindow) { if (str != NULL) RGFW_STRNCPY(str, _RGFW->clipboard, _RGFW->clipboard_len - 1); _RGFW->clipboard[_RGFW->clipboard_len - 1] = '\0'; return (RGFW_ssize_t) _RGFW->clipboard_len - 1; } XEvent event; int format; unsigned long N, sizeN; char *data; Atom target; XConvertSelection(_RGFW->display, CLIPBOARD, UTF8_STRING, XSEL_DATA, _RGFW->helperWindow, CurrentTime); XSync(_RGFW->display, 0); while (1) { XNextEvent(_RGFW->display, &event); if (event.type != SelectionNotify) continue; if (event.xselection.selection != CLIPBOARD || event.xselection.property == 0) return -1; break; } XGetWindowProperty(event.xselection.display, event.xselection.requestor, event.xselection.property, 0L, (~0L), 0, AnyPropertyType, &target, &format, &sizeN, &N, (u8 * *) & data); RGFW_ssize_t size; if (sizeN > strCapacity && str != NULL) size = -1; if ((target == UTF8_STRING || target == XA_STRING) && str != NULL) { RGFW_MEMCPY(str, data, sizeN); str[sizeN] = '\0'; XFree(data); } else if (str != NULL) size = -1; XDeleteProperty(event.xselection.display, event.xselection.requestor, event.xselection.property); size = (RGFW_ssize_t) sizeN; return size; } i32 RGFW_XHandleClipboardSelectionHelper(void){ RGFW_LOAD_ATOM(SAVE_TARGETS); XEvent event; XPending(_RGFW->display); if (QLength(_RGFW->display) || XEventsQueued(_RGFW->display, QueuedAlready) + XEventsQueued(_RGFW->display, QueuedAfterReading)) XNextEvent(_RGFW->display, &event); else return 0; switch (event.type) { case SelectionRequest: RGFW_XHandleClipboardSelection(&event); return 0; case SelectionNotify: if (event.xselection.target == SAVE_TARGETS) return 0; break; default:break; } return 0; } void RGFW_FUNC(RGFW_writeClipboard) (const char *text, u32 textLen){ RGFW_LOAD_ATOM(SAVE_TARGETS); RGFW_LOAD_ATOM(CLIPBOARD); RGFW_init(); /* * request ownership of the clipboard section and request to * convert it, this means its our job to convert it */ XSetSelectionOwner(_RGFW->display, CLIPBOARD, _RGFW->helperWindow, CurrentTime); if (XGetSelectionOwner(_RGFW->display, CLIPBOARD) != _RGFW->helperWindow) { RGFW_sendDebugInfo(RGFW_typeError, RGFW_errClipboard, "X11 failed to become owner of clipboard selection"); return; } if (_RGFW->clipboard) RGFW_FREE(_RGFW->clipboard); _RGFW->clipboard = (char *)RGFW_ALLOC(textLen); RGFW_ASSERT(_RGFW->clipboard != NULL); RGFW_STRNCPY(_RGFW->clipboard, text, textLen - 1); _RGFW->clipboard[textLen - 1] = '\0'; _RGFW->clipboard_len = textLen; return; } RGFW_bool RGFW_FUNC(RGFW_window_isHidden) (RGFW_window * win) { RGFW_ASSERT(win != NULL); XWindowAttributes windowAttributes; XGetWindowAttributes(_RGFW->display, win->src.window, &windowAttributes); return (windowAttributes.map_state == IsUnmapped && !RGFW_window_isMinimized(win)); } RGFW_bool RGFW_FUNC(RGFW_window_isMinimized) (RGFW_window * win) { RGFW_ASSERT(win != NULL); RGFW_LOAD_ATOM(WM_STATE); Atom actual_type; i32 actual_format; unsigned long nitems, bytes_after; unsigned char *prop_data; i32 status = XGetWindowProperty(_RGFW->display, win->src.window, WM_STATE, 0, 2, False, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop_data); if (status == Success && nitems >= 1 && prop_data == (unsigned char *)IconicState) { XFree(prop_data); return RGFW_TRUE; } if (prop_data != NULL) XFree(prop_data); XWindowAttributes windowAttributes; XGetWindowAttributes(_RGFW->display, win->src.window, &windowAttributes); return windowAttributes.map_state != IsViewable; } RGFW_bool RGFW_FUNC(RGFW_window_isMaximized) (RGFW_window * win) { RGFW_ASSERT(win != NULL); RGFW_LOAD_ATOM(_NET_WM_STATE); RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_VERT); RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ); Atom actual_type; i32 actual_format; unsigned long nitems, bytes_after; unsigned char *prop_data; i32 status = XGetWindowProperty(_RGFW->display, win->src.window, _NET_WM_STATE, 0, 1024, False, XA_ATOM, &actual_type, &actual_format, &nitems, &bytes_after, &prop_data); if (status != Success) { if (prop_data != NULL) XFree(prop_data); return RGFW_FALSE; } u64 i; for (i = 0; i < nitems; ++i) { if (prop_data[i] == _NET_WM_STATE_MAXIMIZED_VERT || prop_data[i] == _NET_WM_STATE_MAXIMIZED_HORZ) { XFree(prop_data); return RGFW_TRUE; } } if (prop_data != NULL) XFree(prop_data); return RGFW_FALSE; } static float XGetSystemContentDPI(Display * display, i32 screen) { float dpi = 96.0f; #ifndef RGFW_NO_DPI RGFW_UNUSED(screen); char *rms = XResourceManagerString(display); XrmDatabase db = NULL; if (rms) db = XrmGetStringDatabase(rms); if (rms && db) { XrmValue value; char *type = NULL; if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value) && type && RGFW_STRNCMP(type, "String", 7) == 0) dpi = (float)RGFW_ATOF(value.addr); XrmDestroyDatabase(db); } #else dpi = RGFW_ROUND(DisplayWidth(display, screen) / (DisplayWidthMM(display, screen) / 25.4)); #endif return dpi; } RGFW_monitor RGFW_XCreateMonitor(i32 screen); RGFW_monitor RGFW_XCreateMonitor(i32 screen) { RGFW_monitor monitor; RGFW_init(); Display *display = _RGFW->display; if (screen == -1) screen = DefaultScreen(display); Screen *scrn = DefaultScreenOfDisplay(display); monitor.x = 0; monitor.y = 0; monitor.mode.w = scrn->width; monitor.mode.h = scrn->height; monitor.physW = (float)DisplayWidthMM(display, screen) / 25.4f; monitor.physH = (float)DisplayHeightMM(display, screen) / 25.4f; RGFW_splitBPP((u32) DefaultDepth(display, screen), &monitor.mode); char *name = XDisplayName((const char *)display); RGFW_STRNCPY(monitor.name, name, sizeof(monitor.name) - 1); monitor.name[sizeof(monitor.name) - 1] = '\0'; float dpi = XGetSystemContentDPI(display, screen); monitor.pixelRatio = dpi >= 192.0f ? 2 : 1.0f; monitor.scaleX = (float)(dpi) / 96.0f; monitor.scaleY = (float)(dpi) / 96.0f; #ifndef RGFW_NO_DPI XRRCrtcInfo *ci = NULL; XRRScreenResources *sr = NULL; { XRRScreenConfiguration *conf = XRRGetScreenInfo(display, RootWindow(display, screen)); monitor.mode.refreshRate = (u32) XRRConfigCurrentRate(conf); sr = XRRGetScreenResourcesCurrent(display, RootWindow(display, screen)); int crtc = screen; if (sr->ncrtc > crtc) { ci = XRRGetCrtcInfo(display, sr, sr->crtcs[crtc]); } XRRFreeScreenConfigInfo(conf); } #endif #ifndef RGFW_NO_DPI XRROutputInfo *info = XRRGetOutputInfo(display, sr, sr->outputs[screen]); if (info == NULL || ci == NULL) { XRRFreeScreenResources(sr); RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, "monitor found"); return monitor; } float physW = (float)info->mm_width / 25.4f; float physH = (float)info->mm_height / 25.4f; RGFW_STRNCPY(monitor.name, info->name, sizeof(monitor.name) - 1); monitor.name[sizeof(monitor.name) - 1] = '\0'; XRRFreeOutputInfo(info); info = NULL; if (physW > 0.0f && physH > 0.0f) { monitor.physW = physW; monitor.physH = physH; } monitor.x = ci->x; monitor.y = ci->y; if (ci->width && ci->height) { monitor.mode.w = (i32) ci->width; monitor.mode.h = (i32) ci->height; } #endif #ifndef RGFW_NO_DPI XRRFreeCrtcInfo(ci); XRRFreeScreenResources(sr); #endif RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, "monitor found"); return monitor; } RGFW_monitor *RGFW_FUNC(RGFW_getMonitors) (size_t * len) { static RGFW_monitor monitors[7]; RGFW_init(); Display *display = _RGFW->display; i32 max = ScreenCount(display); i32 i; for (i = 0; i < max && i < 6; i++) monitors[i] = RGFW_XCreateMonitor(i); if (len != NULL) *len = (size_t) ((max <= 6) ? (max) : (6)); return monitors; } RGFW_monitor RGFW_FUNC(RGFW_getPrimaryMonitor) (void){ return RGFW_XCreateMonitor(-1); } RGFW_bool RGFW_FUNC(RGFW_monitor_requestMode) (RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { #ifndef RGFW_NO_DPI RGFW_init(); XRRScreenConfiguration *conf = XRRGetScreenInfo(_RGFW->display, DefaultRootWindow(_RGFW->display)); XRRScreenResources *screenRes = XRRGetScreenResources(_RGFW->display, DefaultRootWindow(_RGFW->display)); if (screenRes == NULL) return RGFW_FALSE; int i; for (i = 0; i < screenRes->ncrtc; i++) { XRRCrtcInfo *crtcInfo = XRRGetCrtcInfo(_RGFW->display, screenRes, screenRes->crtcs[i]); if (!crtcInfo) continue; if (mon.x == crtcInfo->x && mon.y == crtcInfo->y && (u32) mon.mode.w == crtcInfo->width && (u32) mon.mode.h == crtcInfo->height) { RRMode rmode = None; int index; for (index = 0; index < screenRes->nmode; index++) { RGFW_monitorMode foundMode; foundMode.w = (i32) screenRes->modes[index].width; foundMode.h = (i32) screenRes->modes[index].height; foundMode.refreshRate = (u32) XRRConfigCurrentRate(conf); RGFW_splitBPP((u32) DefaultDepth(_RGFW->display, DefaultScreen(_RGFW->display)), &foundMode); if (RGFW_monitorModeCompare(mode, foundMode, request)) { rmode = screenRes->modes[index].id; RROutput output = screenRes->outputs[i]; XRROutputInfo *info = XRRGetOutputInfo(_RGFW->display, screenRes, output); if (info) { XRRSetCrtcConfig(_RGFW->display, screenRes, screenRes->crtcs[i], CurrentTime, 0, 0, rmode, RR_Rotate_0, &output, 1); XRRFreeOutputInfo(info); XRRFreeCrtcInfo(crtcInfo); XRRFreeScreenResources(screenRes); return RGFW_TRUE; } } } XRRFreeCrtcInfo(crtcInfo); XRRFreeScreenResources(screenRes); return RGFW_FALSE; } XRRFreeCrtcInfo(crtcInfo); } XRRFreeScreenResources(screenRes); XRRFreeScreenConfigInfo(conf); #endif return RGFW_FALSE; } RGFW_monitor RGFW_FUNC(RGFW_window_getMonitor) (RGFW_window * win) { RGFW_monitor mon; RGFW_MEMSET(&mon, 0, sizeof(mon)); RGFW_ASSERT(win != NULL); XWindowAttributes attrs; if (!XGetWindowAttributes(_RGFW->display, win->src.window, &attrs)) { return mon; } i32 i; for (i = 0; i < ScreenCount(_RGFW->display) && i < 6; i++) { Screen *screen = ScreenOfDisplay(_RGFW->display, i); if (attrs.x >= 0 && attrs.x < XWidthOfScreen(screen) && attrs.y >= 0 && attrs.y < XHeightOfScreen(screen)) return RGFW_XCreateMonitor(i); } return mon; } #ifdef RGFW_OPENGL RGFW_bool RGFW_FUNC(RGFW_window_createContextPtr_OpenGL) (RGFW_window * win, RGFW_glContext * context, RGFW_glHints * hints) { /* for checking extensions later */ const char sRGBARBstr[] = "GLX_ARB_framebuffer_sRGB"; const char sRGBEXTstr[] = "GLX_EXT_framebuffer_sRGB"; const char noErorrStr[] = "GLX_ARB_create_context_no_error"; const char flushStr[] = "GLX_ARB_context_flush_control"; const char robustStr[] = "GLX_ARB_create_context_robustness"; /* basic RGFW int */ win->src.ctx.native = context; win->src.gfxType = RGFW_gfxNativeOpenGL; /* * This is required so that way the user can create their own * OpenGL context after RGFW_createWindow is used */ if (win->src.window) RGFW_window_closePlatform(win); RGFW_bool transparent = (win->internal.flags & RGFW_windowTransparent); /* start by creating a GLX config / X11 Viusal */ XVisualInfo visual; GLXFBConfig bestFbc; i32 visual_attribs[40]; RGFW_attribStack stack; RGFW_attribStack_init(&stack, visual_attribs, 40); RGFW_attribStack_pushAttribs(&stack, GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR); RGFW_attribStack_pushAttribs(&stack, GLX_X_RENDERABLE, 1); RGFW_attribStack_pushAttribs(&stack, GLX_RENDER_TYPE, GLX_RGBA_BIT); RGFW_attribStack_pushAttribs(&stack, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT); RGFW_attribStack_pushAttribs(&stack, GLX_DOUBLEBUFFER, 1); RGFW_attribStack_pushAttribs(&stack, GLX_ALPHA_SIZE, hints->alpha); RGFW_attribStack_pushAttribs(&stack, GLX_DEPTH_SIZE, hints->depth); RGFW_attribStack_pushAttribs(&stack, GLX_STENCIL_SIZE, hints->stencil); RGFW_attribStack_pushAttribs(&stack, GLX_STEREO, hints->stereo); RGFW_attribStack_pushAttribs(&stack, GLX_AUX_BUFFERS, hints->auxBuffers); RGFW_attribStack_pushAttribs(&stack, GLX_RED_SIZE, hints->red); RGFW_attribStack_pushAttribs(&stack, GLX_GREEN_SIZE, hints->green); RGFW_attribStack_pushAttribs(&stack, GLX_BLUE_SIZE, hints->blue); RGFW_attribStack_pushAttribs(&stack, GLX_ACCUM_RED_SIZE, hints->accumRed); RGFW_attribStack_pushAttribs(&stack, GLX_ACCUM_GREEN_SIZE, hints->accumGreen); RGFW_attribStack_pushAttribs(&stack, GLX_ACCUM_BLUE_SIZE, hints->accumBlue); RGFW_attribStack_pushAttribs(&stack, GLX_ACCUM_ALPHA_SIZE, hints->accumAlpha); if (hints->sRGB) { if (RGFW_extensionSupportedPlatform_OpenGL(sRGBARBstr, sizeof(sRGBARBstr))) RGFW_attribStack_pushAttribs(&stack, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, hints->sRGB); if (RGFW_extensionSupportedPlatform_OpenGL(sRGBEXTstr, sizeof(sRGBEXTstr))) RGFW_attribStack_pushAttribs(&stack, GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, hints->sRGB); } RGFW_attribStack_pushAttribs(&stack, 0, 0); /* find the configs */ i32 fbcount; GLXFBConfig *fbc = glXChooseFBConfig(_RGFW->display, DefaultScreen(_RGFW->display), visual_attribs, &fbcount); i32 best_fbc = -1; i32 best_depth = 0; i32 best_samples = 0; if (fbcount == 0) { RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to find any valid GLX visual configs."); return 0; } /* search through all found configs to find the best match */ i32 i; for (i = 0; i < fbcount; i++) { XVisualInfo *vi = glXGetVisualFromFBConfig(_RGFW->display, fbc[i]); if (vi == NULL) continue; i32 samp_buf, samples; glXGetFBConfigAttrib(_RGFW->display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf); glXGetFBConfigAttrib(_RGFW->display, fbc[i], GLX_SAMPLES, &samples); if (best_fbc == -1) best_fbc = i; if ((!(transparent) || vi->depth == 32) && best_depth == 0) { best_fbc = i; best_depth = vi->depth; } if ((!(transparent) || vi->depth == 32) && samples <= hints->samples && samples > best_samples) { best_fbc = i; best_depth = vi->depth; best_samples = samples; } XFree(vi); } if (best_fbc == -1) { RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to get a valid GLX visual."); return 0; } /* we found a config */ bestFbc = fbc[best_fbc]; XVisualInfo *vi = glXGetVisualFromFBConfig(_RGFW->display, bestFbc); if (vi->depth != 32 && transparent) RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, "Failed to to find a matching visual with a 32-bit depth."); if (best_samples < hints->samples) RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, "Failed to load a matching sample count."); XFree(fbc); visual = *vi; XFree(vi); /* use the visual to create a new window */ RGFW_XCreateWindow(visual, "", win->internal.flags, win); /* create the actual OpenGL context */ i32 context_attribs[40]; RGFW_attribStack_init(&stack, context_attribs, 40); i32 mask = 0; switch (hints->profile) { case RGFW_glES:mask |= GLX_CONTEXT_ES_PROFILE_BIT_EXT; break; case RGFW_glCompatibility:mask |= GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; break; case RGFW_glCore:mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; break; default:mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; break; } RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_PROFILE_MASK_ARB, mask); if (hints->minor || hints->major) { RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_MAJOR_VERSION_ARB, hints->major); RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_MINOR_VERSION_ARB, hints->minor); } if (RGFW_extensionSupportedPlatform_OpenGL(flushStr, sizeof(flushStr))) { if (hints->releaseBehavior == RGFW_glReleaseFlush) { RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); } else if (hints->releaseBehavior == RGFW_glReleaseNone) { RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); } } i32 flags = 0; if (hints->debug) flags |= GLX_CONTEXT_FLAGS_ARB; if (hints->robustness && RGFW_extensionSupportedPlatform_OpenGL(robustStr, sizeof(robustStr))) flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB; if (flags) { RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_FLAGS_ARB, flags); } if (RGFW_extensionSupportedPlatform_OpenGL(noErorrStr, sizeof(noErorrStr))) { RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_OPENGL_NO_ERROR_ARB, hints->noError); } RGFW_attribStack_pushAttribs(&stack, 0, 0); /* create the context */ glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0; char str[] = "glXCreateContextAttribsARB"; glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) glXGetProcAddressARB((u8 *) str); GLXContext ctx = NULL; if (hints->share) { ctx = hints->share->ctx; } if (glXCreateContextAttribsARB == NULL) { RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load proc address 'glXCreateContextAttribsARB', loading a generic OpenGL context."); win->src.ctx.native->ctx = glXCreateContext(_RGFW->display, &visual, ctx, True); } else { _RGFW->x11Error = NULL; win->src.ctx.native->ctx = glXCreateContextAttribsARB(_RGFW->display, bestFbc, ctx, True, context_attribs); if (_RGFW->x11Error || win->src.ctx.native->ctx == NULL) { RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to create an OpenGL context with AttribsARB, loading a generic OpenGL context."); win->src.ctx.native->ctx = glXCreateContext(_RGFW->display, &visual, ctx, True); } } win->src.ctx.native->window = glXCreateWindow(_RGFW->display, bestFbc, win->src.window, NULL); glXMakeCurrent(_RGFW->display, (Drawable) win->src.ctx.native->window, (GLXContext) win->src.ctx.native->ctx); RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized."); return RGFW_TRUE; } void RGFW_FUNC(RGFW_window_deleteContextPtr_OpenGL) (RGFW_window * win, RGFW_glContext * ctx) { glXDestroyWindow(_RGFW->display, win->src.ctx.native->window); glXDestroyContext(_RGFW->display, ctx->ctx); win->src.ctx.native = NULL; RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context freed."); } RGFW_bool RGFW_FUNC(RGFW_extensionSupportedPlatform_OpenGL) (const char *extension, size_t len){ RGFW_init(); const char *extensions = glXQueryExtensionsString(_RGFW->display, XDefaultScreen(_RGFW->display)); return (extensions != NULL) && RGFW_extensionSupportedStr(extensions, extension, len); } RGFW_proc RGFW_FUNC(RGFW_getProcAddress_OpenGL) (const char *procname){ return glXGetProcAddress((u8 *) procname); } void RGFW_FUNC(RGFW_window_makeCurrentContext_OpenGL) (RGFW_window * win) { if (win) RGFW_ASSERT(win->src.ctx.native); if (win == NULL) glXMakeCurrent(NULL, (Drawable) NULL, (GLXContext) NULL); else glXMakeCurrent(_RGFW->display, (Drawable) win->src.ctx.native->window, (GLXContext) win->src.ctx.native->ctx); return; } void *RGFW_FUNC(RGFW_getCurrentContext_OpenGL) (void){ return glXGetCurrentContext(); } void RGFW_FUNC(RGFW_window_swapBuffers_OpenGL) (RGFW_window * win) { RGFW_ASSERT(win->src.ctx.native); glXSwapBuffers(_RGFW->display, win->src.ctx.native->window); } void RGFW_FUNC(RGFW_window_swapInterval_OpenGL) (RGFW_window * win, i32 swapInterval) { RGFW_ASSERT(win != NULL); /* cached pfn to avoid calling glXGetProcAddress more than once */ static PFNGLXSWAPINTERVALEXTPROC pfn = NULL; static int (*pfn2) (int)= NULL; if (pfn == NULL) { u8 str[] = "glXSwapIntervalEXT"; pfn = (PFNGLXSWAPINTERVALEXTPROC) glXGetProcAddress(str); if (pfn == NULL) { pfn = (PFNGLXSWAPINTERVALEXTPROC) 1; const char *array[] = {"GLX_MESA_swap_control", "GLX_SGI_swap_control"}; size_t i; for (i = 0; i < sizeof(array) / sizeof(char *) && pfn2 == NULL; i++) { pfn2 = (int (*) (int))glXGetProcAddress((u8 *) array[i]); } if (pfn2 != NULL) { RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load swap interval function, fallingback to the native swapinterval function"); } else { RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load swap interval function"); } } } if (pfn != (PFNGLXSWAPINTERVALEXTPROC) 1) { pfn(_RGFW->display, win->src.window, swapInterval); } else if (pfn2 != NULL) { pfn2(swapInterval); } } #endif /* RGFW_OPENGL */ i32 RGFW_initPlatform_X11(void){ #ifdef RGFW_USE_XDL XDL_init(); #endif #if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD) #if defined(__CYGWIN__) RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor-1.so"); #elif defined(__OpenBSD__) || defined(__NetBSD__) RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor.so"); #else RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor.so.1"); #endif RGFW_PROC_DEF(X11Cursorhandle, XcursorImageCreate); RGFW_PROC_DEF(X11Cursorhandle, XcursorImageDestroy); RGFW_PROC_DEF(X11Cursorhandle, XcursorImageLoadCursor); #endif #if !defined(RGFW_NO_X11_XI_PRELOAD) #if defined(__CYGWIN__) RGFW_LOAD_LIBRARY(X11Xihandle, "libXi-6.so"); #elif defined(__OpenBSD__) || defined(__NetBSD__) RGFW_LOAD_LIBRARY(X11Xihandle, "libXi.so"); #else RGFW_LOAD_LIBRARY(X11Xihandle, "libXi.so.6"); #endif RGFW_PROC_DEF(X11Xihandle, XISelectEvents); #endif #if !defined(RGFW_NO_X11_EXT_PRELOAD) #if defined(__CYGWIN__) RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext-6.so"); #elif defined(__OpenBSD__) || defined(__NetBSD__) RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext.so"); #else RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext.so.6"); #endif RGFW_PROC_DEF(X11XEXThandle, XSyncCreateCounter); RGFW_PROC_DEF(X11XEXThandle, XSyncIntToValue); RGFW_PROC_DEF(X11XEXThandle, XSyncSetCounter); RGFW_PROC_DEF(X11XEXThandle, XShapeCombineRegion); RGFW_PROC_DEF(X11XEXThandle, XShapeCombineMask); #endif XInitThreads(); /* !< init X11 threading */ _RGFW->display = XOpenDisplay(0); _RGFW->context = XUniqueContext(); XSetWindowAttributes wa; RGFW_MEMSET(&wa, 0, sizeof(wa)); wa.event_mask = PropertyChangeMask; _RGFW->helperWindow = XCreateWindow(_RGFW->display, XDefaultRootWindow(_RGFW->display), 0, 0, 1, 1, 0, 0, InputOnly, DefaultVisual(_RGFW->display, DefaultScreen(_RGFW->display)), CWEventMask, &wa); u8 RGFW_blk[] = {0, 0, 0, 0}; _RGFW->hiddenMouse = RGFW_loadMouse(RGFW_blk, 1, 1, RGFW_formatRGBA8); _RGFW->clipboard = NULL; XkbComponentNamesRec rec; XkbDescPtr desc = XkbGetMap(_RGFW->display, 0, XkbUseCoreKbd); XkbDescPtr evdesc; XSetErrorHandler(RGFW_XErrorHandler); u8 old[256]; XkbGetNames(_RGFW->display, XkbKeyNamesMask, desc); RGFW_MEMSET(&rec, 0, sizeof(rec)); char evdev[] = "evdev"; rec.keycodes = evdev; evdesc = XkbGetKeyboardByName(_RGFW->display, XkbUseCoreKbd, &rec, XkbGBN_KeyNamesMask, XkbGBN_KeyNamesMask, False); /* memo: RGFW_keycodes[x11 keycode] = rgfw keycode */ if (evdesc != NULL && desc != NULL) { int i, j; for (i = 0; i < (int)sizeof(old); i++) { old[i] = _RGFW->keycodes[i]; _RGFW->keycodes[i] = 0; } for (i = evdesc->min_key_code; i <= evdesc->max_key_code; i++) { for (j = desc->min_key_code; j <= desc->max_key_code; j++) { if (RGFW_STRNCMP(evdesc->names->keys[i].name, desc->names->keys[j].name, XkbKeyNameLength) == 0) { _RGFW->keycodes[j] = old[i]; break; } } } XkbFreeKeyboard(desc, 0, True); XkbFreeKeyboard(evdesc, 0, True); } return 0; } void RGFW_deinitPlatform_X11(void){ #define RGFW_FREE_LIBRARY(x) if (x != NULL) dlclose(x); x = NULL; /* * to save the clipboard on the x server after the window is * closed */ RGFW_LOAD_ATOM(CLIPBOARD_MANAGER); RGFW_LOAD_ATOM(CLIPBOARD); RGFW_LOAD_ATOM(SAVE_TARGETS); if (XGetSelectionOwner(_RGFW->display, CLIPBOARD) == _RGFW->helperWindow) { XConvertSelection(_RGFW->display, CLIPBOARD_MANAGER, SAVE_TARGETS, None, _RGFW->helperWindow, CurrentTime); while (RGFW_XHandleClipboardSelectionHelper()); } if (_RGFW->clipboard) { RGFW_FREE(_RGFW->clipboard); _RGFW->clipboard = NULL; } if (_RGFW->hiddenMouse) { RGFW_freeMouse(_RGFW->hiddenMouse); _RGFW->hiddenMouse = NULL; } XDestroyWindow(_RGFW->display, (Drawable) _RGFW->helperWindow); /* !< close the window */ XCloseDisplay(_RGFW->display); /* !< kill connection to the x * server */ #if !defined(RGFW_NO_X11_CURSOR_PRELOAD) && !defined(RGFW_NO_X11_CURSOR) RGFW_FREE_LIBRARY(X11Cursorhandle); #endif #if !defined(RGFW_NO_X11_XI_PRELOAD) RGFW_FREE_LIBRARY(X11Xihandle); #endif #ifdef RGFW_USE_XDL XDL_close(); #endif #if !defined(RGFW_NO_X11_EXT_PRELOAD) RGFW_FREE_LIBRARY(X11XEXThandle); #endif } void RGFW_FUNC(RGFW_window_closePlatform) (RGFW_window * win) { if (win->internal.holdMouse) XUngrabPointer(_RGFW->display, CurrentTime); XFreeGC(_RGFW->display, win->src.gc); XDeleteContext(_RGFW->display, win->src.window, _RGFW->context); XDestroyWindow(_RGFW->display, (Drawable) win->src.window); /* !< close the window */ return; } #ifdef RGFW_WEBGPU WGPUSurface RGFW_FUNC(RGFW_window_createSurface_WebGPU) (RGFW_window * window, WGPUInstance instance) { WGPUSurfaceDescriptor surfaceDesc = {0}; WGPUSurfaceSourceXlibWindow fromXlib = {0}; fromXlib.chain.sType = WGPUSType_SurfaceSourceXlibWindow; fromXlib.display = _RGFW->display; fromXlib.window = window->src.window; surfaceDesc.nextInChain = (WGPUChainedStruct *) & fromXlib.chain; return wgpuInstanceCreateSurface(instance, &surfaceDesc); } #endif #endif /* * End of X11 linux / wayland / unix defines */ /* * * Start of Wayland defayland */ #ifdef RGFW_WAYLAND #ifdef RGFW_X11 #undef RGFW_FUNC /* remove previous define */ #define RGFW_FUNC(func) func##_Wayland #else #define RGFW_FUNC(func) func #endif /* * Wayland TODO: (out of date) - fix RGFW_keyPressed lock state * * RGFW_windowMoved, the window was moved (by the user) * RGFW_windowRefresh The window content needs to be refreshed * * RGFW_dataDrop a file has been dropped into * the window RGFW_dataDrag * * - window args: #define RGFW_windowNoResize the * window cannot be resized by the user #define RGFW_windowAllowDND * the window supports drag and drop #define RGFW_scaleToMonitor * scale the window to the screen * * - other missing functions functions ("TODO wayland") (~30 functions) * - fix buffer rendering weird behavior */ #include #include #include #include #include #include #include #include #include struct wl_display *RGFW_getDisplay_Wayland(void){ return _RGFW->wl_display; } struct wl_surface *RGFW_window_getWindow_Wayland(RGFW_window * win) { return win->src.surface; } /* wayland global garbage (wayland bad, X11 is fine (ish) (not really)) */ #include "xdg-shell.h" #include "xdg-toplevel-icon-v1.h" #include "xdg-decoration-unstable-v1.h" #include "relative-pointer-unstable-v1.h" #include "pointer-constraints-unstable-v1.h" #include "xdg-output-unstable-v1.h" void RGFW_toggleWaylandMaximized(RGFW_window * win, RGFW_bool maximized); static void RGFW_wl_setOpaque(RGFW_window * win) { struct wl_region *wl_region = wl_compositor_create_region(_RGFW->compositor); if (!wl_region) return; //return if no region was created wl_region_add(wl_region, 0, 0, win->w, win->h); wl_surface_set_opaque_region(win->src.surface, wl_region); wl_region_destroy(wl_region); } static void RGFW_wl_xdg_wm_base_ping_handler(void *data, struct xdg_wm_base *wm_base, u32 serial){ RGFW_UNUSED(data); xdg_wm_base_pong(wm_base, serial); } static void RGFW_wl_xdg_surface_configure_handler(void *data, struct xdg_surface *xdg_surface, u32 serial){ xdg_surface_ack_configure(xdg_surface, serial); RGFW_window *win = (RGFW_window *) data; if (win == NULL) { win = _RGFW->kbOwner; if (win == NULL) return; } //useful for libdecor if (win->src.activated != win->src.pending_activated) { win->src.activated = win->src.pending_activated; } if (win->src.maximized != win->src.pending_maximized) { RGFW_toggleWaylandMaximized(win, win->src.pending_maximized); RGFW_window_checkMode(win); } if (win->src.resizing) { //Do not create a resize event if the window is maximized if (!win->src.maximized && win->internal.enabledEvents & RGFW_windowResizedFlag) { RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e.common.win = win); RGFW_windowResizedCallback(win, win->w, win->h); } RGFW_window_resize(win, win->w, win->h); if (!(win->internal.flags & RGFW_windowTransparent)) { RGFW_wl_setOpaque(win); } } } static void RGFW_wl_xdg_toplevel_configure_handler(void *data, struct xdg_toplevel *toplevel, i32 width, i32 height, struct wl_array *states){ RGFW_UNUSED(toplevel); RGFW_window *win = (RGFW_window *) data; win->src.pending_activated = RGFW_FALSE; win->src.pending_maximized = RGFW_FALSE; win->src.resizing = RGFW_FALSE; enum xdg_toplevel_state *state; wl_array_for_each(state, states) { switch (*state) { case XDG_TOPLEVEL_STATE_ACTIVATED: win->src.pending_activated = RGFW_TRUE; break; case XDG_TOPLEVEL_STATE_MAXIMIZED: win->src.pending_maximized = RGFW_TRUE; break; default: break; } } //if width and height are not zero and are not the same as the window // the window is resizing so update the values if ((width && height) && (win->w != width || win->h != height)) { win->src.resizing = RGFW_TRUE; win->src.w = win->w = width; win->src.h = win->h = height; } } static void RGFW_wl_xdg_toplevel_close_handler(void *data, struct xdg_toplevel *toplevel){ RGFW_UNUSED(toplevel); RGFW_window *win = (RGFW_window *) data; if (!win->internal.shouldClose) { RGFW_eventQueuePushEx(e.type = RGFW_quit; e.common.win = win); RGFW_window_setShouldClose(win, RGFW_TRUE); RGFW_windowQuitCallback(win); } } static void RGFW_wl_xdg_decoration_configure_handler(void *data, struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, u32 mode){ RGFW_window *win = (RGFW_window *) data; RGFW_UNUSED(zxdg_toplevel_decoration_v1); //this is expected to run once // set the decoration mode set by earlier request if (mode != win->src.decoration_mode) { win->src.decoration_mode = mode; } } static void RGFW_wl_shm_format_handler(void *data, struct wl_shm *shm, u32 format){ RGFW_UNUSED(data); RGFW_UNUSED(shm); RGFW_UNUSED(format); } static void RGFW_wl_relative_pointer_motion(void *data, struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1, u32 time_hi, u32 time_lo, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t dx_unaccel, wl_fixed_t dy_unaccel){ RGFW_UNUSED(zwp_relative_pointer_v1); RGFW_UNUSED(time_hi); RGFW_UNUSED(time_lo); RGFW_UNUSED(dx_unaccel); RGFW_UNUSED(dy_unaccel); RGFW_info *RGFW = (RGFW_info *) data; RGFW_window *win = RGFW->mouseOwner; RGFW_ASSERT(win); float vecX = (float)wl_fixed_to_double(dx); float vecY = (float)wl_fixed_to_double(dy); RGFW_eventQueuePushEx(e.type = RGFW_mousePosChanged; e.mouse.x = win->internal.lastMouseX; e.mouse.y = win->internal.lastMouseY; e.mouse.vecX = vecX; e.mouse.vecY = vecY; e.common.win = win); RGFW->vectorX = vecX; RGFW->vectorY = vecY; RGFW_mousePosCallback(win, win->internal.lastMouseX, win->internal.lastMouseY, vecX, vecY); } static void RGFW_wl_pointer_locked(void *data, struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1){ RGFW_UNUSED(zwp_locked_pointer_v1); RGFW_info *RGFW = (RGFW_info *) data; RGFW_window *win = RGFW->mouseOwner; win->internal.lastMouseX = win->w / 2; win->internal.lastMouseY = win->h / 2; zwp_locked_pointer_v1_set_cursor_position_hint(win->src.locked_pointer, wl_fixed_from_int((win->w / 2)), wl_fixed_from_int((win->h / 2))); wl_pointer_set_cursor(RGFW->wl_pointer, RGFW->mouse_enter_serial, NULL, 0, 0); //draw no cursor } static void RGFW_wl_pointer_enter(void *data, struct wl_pointer *pointer, u32 serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y){ RGFW_info *RGFW = (RGFW_info *) data; RGFW_window *win = (RGFW_window *) wl_surface_get_user_data(surface); //save when the pointer is locked or using default cursor RGFW->mouse_enter_serial = serial; win->internal.mouseInside = RGFW_TRUE; RGFW->windowState.win = win; RGFW->windowState.mouseEnter = RGFW_TRUE; RGFW->mouseOwner = win; //set the cursor if (win->src.using_custom_cursor) { wl_pointer_set_cursor(pointer, serial, win->src.custom_cursor_surface, 0, 0); } else { RGFW_window_setMouseDefault(win); } if (!(win->internal.enabledEvents & RGFW_mouseEnterFlag)) return; i32 x = (i32) wl_fixed_to_double(surface_x); i32 y = (i32) wl_fixed_to_double(surface_y); RGFW_eventQueuePushEx(e.type = RGFW_mouseEnter; e.mouse.x = x; e.mouse.y = y; e.common.win = win); win->internal.lastMouseX = x; win->internal.lastMouseY = y; RGFW_mouseNotifyCallback(win, x, y, RGFW_TRUE); } static void RGFW_wl_pointer_leave(void *data, struct wl_pointer *pointer, u32 serial, struct wl_surface *surface){ RGFW_UNUSED(pointer); RGFW_UNUSED(serial); RGFW_window *win = (RGFW_window *) wl_surface_get_user_data(surface); RGFW_info *RGFW = (RGFW_info *) data; if (RGFW->mouseOwner == win) RGFW->mouseOwner = NULL; win->internal.mouseInside = RGFW_FALSE; RGFW->windowState.winLeave = win; RGFW->windowState.mouseLeave = RGFW_TRUE; if (!(win->internal.enabledEvents & RGFW_mouseLeaveFlag)) return; RGFW_eventQueuePushEx(e.type = RGFW_mouseLeave; e.mouse.x = win->internal.lastMouseX; e.mouse.y = win->internal.lastMouseY; e.common.win = win); RGFW_mouseNotifyCallback(win, win->internal.lastMouseX, win->internal.lastMouseY, RGFW_FALSE); } static void RGFW_wl_pointer_motion(void *data, struct wl_pointer *pointer, u32 time, wl_fixed_t x, wl_fixed_t y){ RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_info *RGFW = (RGFW_info *) data; RGFW_ASSERT(RGFW->mouseOwner != NULL); RGFW_window *win = RGFW->mouseOwner; if (!(win->internal.enabledEvents & RGFW_mousePosChangedFlag)) return; i32 convertedX = (i32) wl_fixed_to_double(x); i32 convertedY = (i32) wl_fixed_to_double(y); float newVecX = (float)(convertedX - win->internal.lastMouseX); float newVecY = (float)(convertedY - win->internal.lastMouseY); RGFW_eventQueuePushEx(e.type = RGFW_mousePosChanged; e.mouse.x = convertedX; e.mouse.y = convertedY; e.mouse.vecX = newVecX; e.mouse.vecY = newVecY; e.common.win = win); RGFW->vectorX = newVecX; RGFW->vectorY = newVecY; win->internal.lastMouseX = convertedX; win->internal.lastMouseY = convertedY; RGFW_mousePosCallback(win, convertedX, convertedY, newVecX, newVecY); } static void RGFW_wl_pointer_button(void *data, struct wl_pointer *pointer, u32 serial, u32 time, u32 button, u32 state){ RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(serial); RGFW_info *RGFW = (RGFW_info *) data; RGFW_ASSERT(RGFW->mouseOwner != NULL); RGFW_window *win = RGFW->mouseOwner; if (!(win->internal.enabledEvents & (RGFW_BIT(RGFW_mouseButtonReleased - RGFW_BOOL(state))))) return; u32 b = (button - 0x110); /* flip right and middle button codes */ if (b == 1) b = 2; else if (b == 2) b = 1; RGFW->mouseButtons[b].prev = RGFW->mouseButtons[b].current; RGFW->mouseButtons[b].current = RGFW_BOOL(state); RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonReleased - RGFW_BOOL(state); e.button.value = (u8) b; e.common.win = win); RGFW_mouseButtonCallback(win, (u8) b, RGFW_BOOL(state)); } static void RGFW_wl_pointer_axis(void *data, struct wl_pointer *pointer, u32 time, u32 axis, wl_fixed_t value){ RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(axis); RGFW_info *RGFW = (RGFW_info *) data; RGFW_ASSERT(RGFW->mouseOwner != NULL); RGFW_window *win = RGFW->mouseOwner; float scrollX = 0.0; float scrollY = 0.0; if (!(win->internal.enabledEvents & (RGFW_BIT(RGFW_mouseScroll)))) return; if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) scrollX = (float)(-wl_fixed_to_double(value) / 10.0); else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) scrollY = (float)(-wl_fixed_to_double(value) / 10.0); RGFW->scrollX = (float)scrollX; RGFW->scrollY = (float)scrollY; RGFW_mouseScrollCallback(win, scrollX, scrollY); RGFW_eventQueuePushEx(e.type = RGFW_mouseScroll; e.scroll.x = scrollX; e.scroll.y = scrollY; e.common.win = win); } static void RGFW_doNothing(void){ } static void RGFW_wl_keyboard_keymap(void *data, struct wl_keyboard *keyboard, u32 format, i32 fd, u32 size){ RGFW_UNUSED(keyboard); RGFW_UNUSED(format); RGFW_info *RGFW = (RGFW_info *) data; char *keymap_string = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); xkb_keymap_unref(RGFW->keymap); RGFW->keymap = xkb_keymap_new_from_string(RGFW->xkb_context, keymap_string, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); munmap(keymap_string, size); close(fd); xkb_state_unref(RGFW->xkb_state); RGFW->xkb_state = xkb_state_new(RGFW->keymap); } static void RGFW_wl_keyboard_enter(void *data, struct wl_keyboard *keyboard, u32 serial, struct wl_surface *surface, struct wl_array *keys){ RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(keys); RGFW_info *RGFW = (RGFW_info *) data; RGFW_window *win = (RGFW_window *) wl_surface_get_user_data(surface); RGFW->kbOwner = win; if (!(win->internal.enabledEvents & RGFW_focusInFlag)) return; //is set when RGFW_window_minimize is called; if the minimize button is // pressed this flag is not set since there is no event to listen for if (win->src.minimized == RGFW_TRUE) win->src.minimized = RGFW_FALSE; win->internal.inFocus = RGFW_TRUE; RGFW_eventQueuePushEx(e.type = RGFW_focusIn; e.common.win = win); RGFW_focusCallback(win, RGFW_TRUE); if ((win->internal.holdMouse)) RGFW_window_holdMouse(win); } static void RGFW_wl_keyboard_leave(void *data, struct wl_keyboard *keyboard, u32 serial, struct wl_surface *surface){ RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_info *RGFW = (RGFW_info *) data; RGFW_window *win = (RGFW_window *) wl_surface_get_user_data(surface); if (RGFW->kbOwner == win) RGFW->kbOwner = NULL; if (!(win->internal.enabledEvents & RGFW_focusOutFlag)) return; RGFW_eventQueuePushEx(e.type = RGFW_focusOut; e.common.win = win); RGFW_focusCallback(win, RGFW_FALSE); RGFW_window_focusLost(win); } static void RGFW_wl_keyboard_key(void *data, struct wl_keyboard *keyboard, u32 serial, u32 time, u32 key, u32 state){ RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time); RGFW_info *RGFW = (RGFW_info *) data; if (RGFW->kbOwner == NULL) return; RGFW_window *RGFW_key_win = RGFW->kbOwner; if (!(RGFW_key_win->internal.enabledEvents & (RGFW_BIT(RGFW_keyPressed + state)))) return; xkb_keysym_t keysym = xkb_state_key_get_one_sym(RGFW->xkb_state, key + 8); u32 RGFWkey = RGFW_apiKeyToRGFW(key + 8); RGFW->keyboard[RGFWkey].prev = RGFW->keyboard[RGFWkey].current; RGFW->keyboard[RGFWkey].current = RGFW_BOOL(state); RGFW_eventQueuePushEx(e.type = (u8) (RGFW_keyPressed + state); e.key.value = (u8) RGFWkey; e.key.sym = (u8) keysym; e.key.repeat = RGFW_window_isKeyDown(RGFW_key_win, (u8) RGFWkey); e.common.win = RGFW_key_win); RGFW_updateKeyMods(RGFW_key_win, RGFW_BOOL(xkb_keymap_mod_get_index(RGFW->keymap, "Lock")), RGFW_BOOL(xkb_keymap_mod_get_index(RGFW->keymap, "Mod2")), RGFW_BOOL(xkb_keymap_mod_get_index(RGFW->keymap, "ScrollLock"))); RGFW_keyCallback(RGFW_key_win, (u8) RGFWkey, (u8) keysym, RGFW_key_win->internal.mod, RGFW_window_isKeyDown(RGFW_key_win, (u8) RGFWkey), RGFW_BOOL(state)); } static void RGFW_wl_keyboard_modifiers(void *data, struct wl_keyboard *keyboard, u32 serial, u32 mods_depressed, u32 mods_latched, u32 mods_locked, u32 group){ RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time); RGFW_info *RGFW = (RGFW_info *) data; xkb_state_update_mask(RGFW->xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group); } static void RGFW_wl_seat_capabilities(void *data, struct wl_seat *seat, u32 capabilities){ RGFW_info *RGFW = (RGFW_info *) data; static struct wl_pointer_listener pointer_listener; RGFW_MEMSET(&pointer_listener, 0, sizeof(pointer_listener)); pointer_listener.enter = &RGFW_wl_pointer_enter; pointer_listener.leave = &RGFW_wl_pointer_leave; pointer_listener.motion = &RGFW_wl_pointer_motion; pointer_listener.button = &RGFW_wl_pointer_button; pointer_listener.axis = &RGFW_wl_pointer_axis; static struct wl_keyboard_listener keyboard_listener; RGFW_MEMSET(&keyboard_listener, 0, sizeof(keyboard_listener)); keyboard_listener.keymap = &RGFW_wl_keyboard_keymap; keyboard_listener.enter = &RGFW_wl_keyboard_enter; keyboard_listener.leave = &RGFW_wl_keyboard_leave; keyboard_listener.key = &RGFW_wl_keyboard_key; keyboard_listener.modifiers = &RGFW_wl_keyboard_modifiers; if ((capabilities & WL_SEAT_CAPABILITY_POINTER) && !RGFW->wl_pointer) { RGFW->wl_pointer = wl_seat_get_pointer(seat); wl_pointer_add_listener(RGFW->wl_pointer, &pointer_listener, RGFW); } if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && !RGFW->wl_keyboard) { RGFW->wl_keyboard = wl_seat_get_keyboard(seat); wl_keyboard_add_listener(RGFW->wl_keyboard, &keyboard_listener, RGFW); } if (!(capabilities & WL_SEAT_CAPABILITY_POINTER) && RGFW->wl_pointer) { wl_pointer_destroy(RGFW->wl_pointer); } if (!(capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && RGFW->wl_keyboard) { wl_keyboard_destroy(RGFW->wl_keyboard); } } static void RGFW_wl_output_set_geometry(void *data, struct wl_output *wl_output, int32_t x, int32_t y, int32_t physical_width, int32_t physical_height, int32_t subpixel, const char *make, const char *model, int32_t transform){ RGFW_monitor *monitor = &((RGFW_monitorNode *) data)->mon; monitor->x = x; monitor->y = y; monitor->physW = (float)physical_width / 25.4f; monitor->physH = (float)physical_height / 25.4f; RGFW_UNUSED(wl_output); RGFW_UNUSED(subpixel); RGFW_UNUSED(make); RGFW_UNUSED(model); RGFW_UNUSED(transform); } static void RGFW_wl_output_set_mode(void *data, struct wl_output *wl_output, uint32_t flags, int32_t width, int32_t height, int32_t refresh){ RGFW_monitor *monitor = &((RGFW_monitorNode *) data)->mon; monitor->mode.w = width; monitor->mode.h = height; monitor->mode.refreshRate = (u32) RGFW_ROUND(((float)refresh / 1000)); RGFW_UNUSED(width); RGFW_UNUSED(height); RGFW_UNUSED(wl_output); RGFW_UNUSED(flags); } static void RGFW_wl_output_set_scale(void *data, struct wl_output *wl_output, int32_t factor){ //this is for pixelRatio RGFW_monitor * monitor = &((RGFW_monitorNode *) data) ->mon; monitor->pixelRatio = (float)factor; RGFW_UNUSED(wl_output); } static void RGFW_wl_output_set_name(void *data, struct wl_output *wl_output, const char *name){ RGFW_monitor *monitor = &((RGFW_monitorNode *) data)->mon; RGFW_STRNCPY(monitor->name, name, sizeof(monitor->name) - 1); monitor->name[sizeof(monitor->name) - 1] = '\0'; RGFW_UNUSED(wl_output); } static void RGFW_xdg_output_logical_pos(void *data, struct zxdg_output_v1 *zxdg_output_v1, int32_t x, int32_t y){ RGFW_monitor *monitor = &((RGFW_monitorNode *) data)->mon; monitor->x = x; monitor->y = y; RGFW_UNUSED(zxdg_output_v1); } static void RGFW_xdg_output_logical_size(void *data, struct zxdg_output_v1 *zxdg_output_v1, int32_t width, int32_t height){ RGFW_monitor *monitor = &((RGFW_monitorNode *) data)->mon; float mon_float_width = (float)monitor->mode.w; float mon_float_height = (float)monitor->mode.h; monitor->scaleX = (mon_float_width / (float)width); monitor->scaleY = (mon_float_height / (float)height); //under xwayland the monitor changes w & h when compositor scales it monitor->mode.w = width; monitor->mode.h = height; RGFW_UNUSED(zxdg_output_v1); } static void RGFW_wl_create_outputs(struct wl_registry *const registry, uint32_t id){ struct wl_output *output = wl_registry_bind(registry, id, &wl_output_interface, wl_display_get_version(_RGFW->wl_display) < 4 ? 3 : 4); RGFW_monitorNode *node; RGFW_monitor mon; if (!output) return; char RGFW_mon_default_name[10]; RGFW_SNPRINTF(RGFW_mon_default_name, sizeof(RGFW_mon_default_name), "monitor-%li", _RGFW->monitors.count); RGFW_STRNCPY(mon.name, RGFW_mon_default_name, sizeof(mon.name) - 1); mon.name[sizeof(mon.name) - 1] = '\0'; //set in case compositor does not send one // or no xdg_output support mon.scaleY = mon.scaleX = mon.pixelRatio = 1.0f; node = RGFW_monitors_add(mon); if (node == NULL) return; node->id = id; node->output = output; static const struct wl_output_listener wl_output_listener = { .geometry = RGFW_wl_output_set_geometry, .mode = RGFW_wl_output_set_mode, .done = (void (*) (void *, struct wl_output *))&RGFW_doNothing, .scale = RGFW_wl_output_set_scale, .name = RGFW_wl_output_set_name, .description = (void (*) (void *, struct wl_output *, const char *))&RGFW_doNothing }; //the wl_output will have a reference to the node wl_output_set_user_data(output, node); //pass the monitor so we can access it in the callback functions wl_output_add_listener(output, &wl_output_listener, node); if (!_RGFW->xdg_output_manager) return; //compositor does not support it static const struct zxdg_output_v1_listener xdg_output_listener = { .name = (void (*) (void *, struct zxdg_output_v1 *, const char *))&RGFW_doNothing, .done = (void (*) (void *, struct zxdg_output_v1 *))&RGFW_doNothing, .description = (void (*) (void *, struct zxdg_output_v1 *, const char *))&RGFW_doNothing, .logical_position = RGFW_xdg_output_logical_pos, .logical_size = RGFW_xdg_output_logical_size }; node->xdg_output = zxdg_output_manager_v1_get_xdg_output(_RGFW->xdg_output_manager, node->output); zxdg_output_v1_add_listener(node->xdg_output, &xdg_output_listener, node); } static void RGFW_wl_surface_enter(void *data, struct wl_surface *wl_surface, struct wl_output *output){ RGFW_UNUSED(wl_surface); RGFW_window *win = (RGFW_window *) data; RGFW_monitorNode *node = wl_output_get_user_data(output); win->src.active_monitor = node->mon; #ifndef RGFW_NO_MONITOR if (win->internal.flags & RGFW_windowScaleToMonitor) RGFW_window_scaleToMonitor(win); #endif } static void RGFW_wl_global_registry_handler(void *data, struct wl_registry *registry, u32 id, const char *interface, u32 version){ static struct wl_seat_listener seat_listener = {&RGFW_wl_seat_capabilities, (void (*) (void *, struct wl_seat *, const char *))&RGFW_doNothing}; static const struct wl_shm_listener shm_listener = {.format = RGFW_wl_shm_format_handler}; RGFW_info *RGFW = (RGFW_info *) data; RGFW_UNUSED(version); if (RGFW_STRNCMP(interface, "wl_compositor", 16) == 0) { RGFW->compositor = wl_registry_bind(registry, id, &wl_compositor_interface, 4); } else if (RGFW_STRNCMP(interface, "xdg_wm_base", 12) == 0) { RGFW->xdg_wm_base = wl_registry_bind(registry, id, &xdg_wm_base_interface, 1); } else if (RGFW_STRNCMP(interface, zxdg_decoration_manager_v1_interface.name, 255) == 0) { RGFW->decoration_manager = wl_registry_bind(registry, id, &zxdg_decoration_manager_v1_interface, 1); } else if (RGFW_STRNCMP(interface, zwp_pointer_constraints_v1_interface.name, 255) == 0) { RGFW->constraint_manager = wl_registry_bind(registry, id, &zwp_pointer_constraints_v1_interface, 1); } else if (RGFW_STRNCMP(interface, zwp_relative_pointer_manager_v1_interface.name, 255) == 0) { RGFW->relative_pointer_manager = wl_registry_bind(registry, id, &zwp_relative_pointer_manager_v1_interface, 1); } else if (RGFW_STRNCMP(interface, xdg_toplevel_icon_manager_v1_interface.name, 255) == 0) { RGFW->icon_manager = wl_registry_bind(registry, id, &xdg_toplevel_icon_manager_v1_interface, 1); } else if (RGFW_STRNCMP(interface, "wl_shm", 7) == 0) { RGFW->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1); wl_shm_add_listener(RGFW->shm, &shm_listener, RGFW); } else if (RGFW_STRNCMP(interface, "wl_seat", 8) == 0) { RGFW->seat = wl_registry_bind(registry, id, &wl_seat_interface, 1); wl_seat_add_listener(RGFW->seat, &seat_listener, RGFW); } else if (RGFW_STRNCMP(interface, zxdg_output_manager_v1_interface.name, 255) == 0) { RGFW->xdg_output_manager = wl_registry_bind(registry, id, &zxdg_output_manager_v1_interface, 1); } else if (RGFW_STRNCMP(interface, "wl_output", 10) == 0) { RGFW_wl_create_outputs(registry, id); } } static void RGFW_wl_global_registry_remove(void *data, struct wl_registry *registry, u32 id){ RGFW_UNUSED(data); RGFW_UNUSED(registry); RGFW_info *RGFW = (RGFW_info *) data; RGFW_monitorNode *prev = RGFW->monitors.list.head; RGFW_monitorNode *node = NULL; if (prev == NULL) return; if (prev->id != id) { /* find the first node that has a matching id */ while (prev->next != NULL && prev->next->id != id) { prev = prev->next; } if (prev->next == NULL) return; node = prev->next; } else { node = prev; } if (node->output) { wl_output_destroy(node->output); } if (node->xdg_output) { zxdg_output_v1_destroy(node->xdg_output); } RGFW_monitors_remove(node, prev); } static void RGFW_wl_randname(char *buf){ struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); long r = ts.tv_nsec; int i; for (i = 0; i < 6; ++i) { buf[i] = (char)('A' + (r & 15) + (r & 16) * 2); r >>= 5; } } static size_t RGFW_wl_stringlen(char *name){ size_t i = 0; while (name[i]) { i++; } return i; } static int RGFW_wl_anonymous_shm_open(void){ char name[] = "/RGFW-wayland-XXXXXX"; int retries = 100; do { RGFW_wl_randname(name + RGFW_wl_stringlen(name) - 6); --retries; /* shm_open guarantees that O_CLOEXEC is set */ int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); if (fd >= 0) { shm_unlink(name); return fd; } } while (retries > 0 && errno == EEXIST); return -1; } static int RGFW_wl_create_shm_file(off_t size) { int fd = RGFW_wl_anonymous_shm_open(); if (fd < 0) { return fd; } if (ftruncate(fd, size) < 0) { close(fd); return -1; } return fd; } i32 RGFW_initPlatform_Wayland(void){ _RGFW->wl_display = wl_display_connect(NULL); if (_RGFW->wl_display == NULL) { RGFW_sendDebugInfo(RGFW_typeError, RGFW_errWayland, "Failed to load Wayland display"); return -1; } _RGFW->compositor = NULL; static const struct wl_registry_listener registry_listener = { .global = RGFW_wl_global_registry_handler, .global_remove = RGFW_wl_global_registry_remove, }; _RGFW->registry = wl_display_get_registry(_RGFW->wl_display); wl_registry_add_listener(_RGFW->registry, ®istry_listener, _RGFW); wl_display_roundtrip(_RGFW->wl_display); //bind to globals if (_RGFW->compositor == NULL) { RGFW_sendDebugInfo(RGFW_typeError, RGFW_errWayland, "Can't find compositor."); return 1; } if (_RGFW->wl_cursor_theme == NULL) { _RGFW->wl_cursor_theme = wl_cursor_theme_load(NULL, 24, _RGFW->shm); _RGFW->cursor_surface = wl_compositor_create_surface(_RGFW->compositor); } u8 RGFW_blk[] = {0, 0, 0, 0}; _RGFW->hiddenMouse = RGFW_loadMouse(RGFW_blk, 1, 1, RGFW_formatRGBA8); static const struct xdg_wm_base_listener xdg_wm_base_listener = { .ping = RGFW_wl_xdg_wm_base_ping_handler, }; xdg_wm_base_add_listener(_RGFW->xdg_wm_base, &xdg_wm_base_listener, NULL); _RGFW->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); return 0; } void RGFW_deinitPlatform_Wayland(void){ if (_RGFW->wl_pointer) { wl_pointer_destroy(_RGFW->wl_pointer); } if (_RGFW->wl_keyboard) { wl_keyboard_destroy(_RGFW->wl_keyboard); } wl_registry_destroy(_RGFW->registry); if (_RGFW->decoration_manager != NULL) zxdg_decoration_manager_v1_destroy(_RGFW->decoration_manager); if (_RGFW->relative_pointer_manager != NULL) { zwp_relative_pointer_manager_v1_destroy(_RGFW->relative_pointer_manager); } if (_RGFW->relative_pointer) { zwp_relative_pointer_v1_destroy(_RGFW->relative_pointer); } if (_RGFW->constraint_manager != NULL) { zwp_pointer_constraints_v1_destroy(_RGFW->constraint_manager); } if (_RGFW->xdg_output_manager != NULL) if (_RGFW->icon_manager != NULL) { xdg_toplevel_icon_manager_v1_destroy(_RGFW->icon_manager); } if (_RGFW->xdg_output_manager) { zxdg_output_manager_v1_destroy(_RGFW->xdg_output_manager); } if (_RGFW->wl_cursor_theme != NULL) { wl_cursor_theme_destroy(_RGFW->wl_cursor_theme); } RGFW_freeMouse(_RGFW->hiddenMouse); RGFW_monitorNode *node = _RGFW->monitors.list.head; while (node != NULL) { if (node->output) { wl_output_destroy(node->output); } if (node->xdg_output) { zxdg_output_v1_destroy(node->xdg_output); } _RGFW->monitors.count -= 1; node = node->next; } wl_surface_destroy(_RGFW->cursor_surface); wl_shm_destroy(_RGFW->shm); wl_seat_release(_RGFW->seat); xdg_wm_base_destroy(_RGFW->xdg_wm_base); wl_compositor_destroy(_RGFW->compositor); wl_display_disconnect(_RGFW->wl_display); } RGFW_bool RGFW_FUNC(RGFW_createSurfacePtr) (u8 * data, i32 w, i32 h, RGFW_format format, RGFW_surface * surface) { RGFW_ASSERT(surface != NULL); surface->data = data; surface->w = w; surface->h = h; surface->format = format; RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoBuffer, "Creating a 4 channel buffer"); u32 size = (u32) (surface->w * surface->h * 4); int fd = RGFW_wl_create_shm_file(size); if (fd < 0) { RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, "Failed to create a buffer."); return RGFW_FALSE; } surface->native.buffer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (surface->native.buffer == MAP_FAILED) { RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, "mmap failed."); return RGFW_FALSE; } struct wl_shm_pool *pool = wl_shm_create_pool(_RGFW->shm, fd, (i32) size); surface->native.wl_buffer = wl_shm_pool_create_buffer(pool, 0, (i32) surface->w, (i32) surface->h, (i32) surface->w * 4, WL_SHM_FORMAT_ARGB8888); wl_shm_pool_destroy(pool); close(fd); surface->native.format = RGFW_formatBGRA8; return RGFW_TRUE; } void RGFW_FUNC(RGFW_window_blitSurface) (RGFW_window * win, RGFW_surface * surface) { RGFW_ASSERT(surface != NULL); RGFW_copyImageData(surface->native.buffer, win->w, RGFW_MIN(win->h, surface->h), surface->native.format, surface->data, surface->format); wl_surface_attach(win->src.surface, surface->native.wl_buffer, 0, 0); wl_surface_damage(win->src.surface, 0, 0, RGFW_MIN(win->w, surface->w), RGFW_MIN(win->h, surface->h)); wl_surface_commit(win->src.surface); } void RGFW_FUNC(RGFW_surface_freePtr) (RGFW_surface * surface) { RGFW_ASSERT(surface != NULL); wl_buffer_destroy(surface->native.wl_buffer); munmap(surface->native.buffer, (size_t) (surface->w * surface->h * 4)); } void RGFW_FUNC(RGFW_window_setBorder) (RGFW_window * win, RGFW_bool border) { RGFW_setBit(&win->internal.flags, RGFW_windowNoBorder, !border); //for now just toggle between SSD & CSD depending on the bool if (_RGFW->decoration_manager != NULL) { zxdg_toplevel_decoration_v1_set_mode(win->src.decoration, (border ? ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE : ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE)); } } void RGFW_FUNC(RGFW_releaseCursor) (RGFW_window * win) { RGFW_ASSERT(win); //compositor has no support or window is not locked do nothing if (_RGFW->constraint_manager == NULL || _RGFW->relative_pointer_manager == NULL) return; if (win->src.locked_pointer != NULL) { zwp_locked_pointer_v1_destroy(win->src.locked_pointer); win->src.locked_pointer = NULL; } if (_RGFW->relative_pointer != NULL) { zwp_relative_pointer_v1_destroy(_RGFW->relative_pointer); _RGFW->relative_pointer = NULL; } _RGFW->mouseOwner = win; //unhold mouse sets this to null; set it back } void RGFW_FUNC(RGFW_captureCursor) (RGFW_window * win) { RGFW_ASSERT(win); //compositor has no support or window already is locked do nothing if (_RGFW->constraint_manager == NULL || _RGFW->relative_pointer_manager == NULL) return; if (_RGFW->relative_pointer == NULL) { _RGFW->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(_RGFW->relative_pointer_manager, _RGFW->wl_pointer); static const struct zwp_relative_pointer_v1_listener relative_motion_listener = { .relative_motion = RGFW_wl_relative_pointer_motion }; zwp_relative_pointer_v1_add_listener(_RGFW->relative_pointer, &relative_motion_listener, _RGFW); } if (win->src.locked_pointer == NULL) { win->src.locked_pointer = zwp_pointer_constraints_v1_lock_pointer(_RGFW->constraint_manager, win->src.surface, _RGFW->wl_pointer, NULL, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); static const struct zwp_locked_pointer_v1_listener locked_listener = { .locked = RGFW_wl_pointer_locked, .unlocked = (void (*) (void *, struct zwp_locked_pointer_v1 *))RGFW_doNothing }; zwp_locked_pointer_v1_add_listener(win->src.locked_pointer, &locked_listener, _RGFW); } } RGFW_window *RGFW_FUNC(RGFW_createWindowPlatform) (const char *name, RGFW_windowFlags flags, RGFW_window * win){ RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningWayland, "RGFW Wayland support is experimental"); static const struct xdg_surface_listener xdg_surface_listener = { .configure = RGFW_wl_xdg_surface_configure_handler, }; static const struct wl_surface_listener wl_surface_listener = { .enter = RGFW_wl_surface_enter, .leave = (void (*) (void *, struct wl_surface *, struct wl_output *))RGFW_doNothing, .preferred_buffer_scale = (void (*) (void *, struct wl_surface *, i32))RGFW_doNothing, .preferred_buffer_transform = (void (*) (void *, struct wl_surface *, u32))RGFW_doNothing }; win->src.surface = wl_compositor_create_surface(_RGFW->compositor); wl_surface_add_listener(win->src.surface, &wl_surface_listener, win); //create a surface for a custom cursor win->src.custom_cursor_surface = wl_compositor_create_surface(_RGFW->compositor); win->src.xdg_surface = xdg_wm_base_get_xdg_surface(_RGFW->xdg_wm_base, win->src.surface); xdg_surface_add_listener(win->src.xdg_surface, &xdg_surface_listener, win); xdg_wm_base_set_user_data(_RGFW->xdg_wm_base, win); win->src.xdg_toplevel = xdg_surface_get_toplevel(win->src.xdg_surface); xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->w, win->h); if (!(win->internal.flags & RGFW_windowTransparent)) { //no transparency RGFW_wl_setOpaque(win); } static const struct xdg_toplevel_listener xdg_toplevel_listener = { .configure = RGFW_wl_xdg_toplevel_configure_handler, .close = RGFW_wl_xdg_toplevel_close_handler, }; xdg_toplevel_add_listener(win->src.xdg_toplevel, &xdg_toplevel_listener, win); /* * compositor supports both SSD & CSD So choose * accordingly */ if (_RGFW->decoration_manager) { u32 decoration_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; win->src.decoration = zxdg_decoration_manager_v1_get_toplevel_decoration( _RGFW->decoration_manager, win->src.xdg_toplevel); static const struct zxdg_toplevel_decoration_v1_listener xdg_decoration_listener = { .configure = RGFW_wl_xdg_decoration_configure_handler }; zxdg_toplevel_decoration_v1_add_listener(win->src.decoration, &xdg_decoration_listener, win); //we want no decorations if ((flags & RGFW_windowNoBorder)) { decoration_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; } zxdg_toplevel_decoration_v1_set_mode(win->src.decoration, decoration_mode); //no xdg_decoration support } else if (!(flags & RGFW_windowNoBorder)) { /* TODO, some fallback */ #ifdef RGFW_LIBDECOR static struct libdecor_interface interface = { .error = NULL, }; static struct libdecor_frame_interface frameInterface = {0}; /* = { * RGFW_wl_handle_configure, * RGFW_wl_handle_close, * RGFW_wl_handle_commit, * * RGFW_wl_handle_dismiss_popup, * }; */ win->src.decorContext = libdecor_new(_RGFW->wl_display, &interface); if (win->src.decorContext) { struct libdecor_frame *frame = libdecor_decorate(win->src.decorContext, win->src.surface, &frameInterface, win); if (!frame) { libdecor_unref(win->src.decorContext); win->src.decorContext = NULL; } else { libdecor_frame_set_app_id(frame, "my-libdecor-app"); libdecor_frame_set_title(frame, "My Libdecor Window"); } } #endif } if (_RGFW->icon_manager != NULL) { //set the default wayland icon xdg_toplevel_icon_manager_v1_set_icon(_RGFW->icon_manager, win->src.xdg_toplevel, NULL); } wl_surface_commit(win->src.surface); wl_display_dispatch(_RGFW->wl_display); RGFW_UNUSED(name); return win; } RGFW_bool RGFW_FUNC(RGFW_getGlobalMouse) (i32 * x, i32 * y) { RGFW_init(); if (x) *x = 0; if (y) *y = 0; return RGFW_FALSE; } u8 RGFW_FUNC(RGFW_rgfwToKeyChar) (u32 key) { return (u8) key; } void RGFW_FUNC(RGFW_pollEvents) (void){ RGFW_resetPrevState(); //send buffered requests to compositor while (wl_display_flush(_RGFW->wl_display) == -1) { //compositor not responding to new requests // so let 's dispatch some events so the compositor responds if (errno == EAGAIN) { if (wl_display_dispatch_pending(_RGFW->wl_display) == -1) { return; } } else { return; } } //read the events; if empty this reads from the // wayland file descriptor if (wl_display_dispatch(_RGFW->wl_display) == -1) { return; } } void RGFW_FUNC(RGFW_window_move) (RGFW_window * win, i32 x, i32 y) { RGFW_ASSERT(win != NULL); win->x = x; win->y = y; } void RGFW_FUNC(RGFW_window_resize) (RGFW_window * win, i32 w, i32 h) { RGFW_ASSERT(win != NULL); win->w = w; win->h = h; if (_RGFW->compositor) { xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->w, win->h); #ifdef RGFW_OPENGL if (win->src.ctx.egl) wl_egl_window_resize(win->src.ctx.egl->eglWindow, (i32) w, (i32) h, 0, 0); #endif } } void RGFW_FUNC(RGFW_window_setAspectRatio) (RGFW_window * win, i32 w, i32 h) { RGFW_ASSERT(win != NULL); if (w == 0 && h == 0) return; xdg_toplevel_set_max_size(win->src.xdg_toplevel, (i32) w, (i32) h); } void RGFW_FUNC(RGFW_window_setMinSize) (RGFW_window * win, i32 w, i32 h) { RGFW_ASSERT(win != NULL); xdg_toplevel_set_min_size(win->src.xdg_toplevel, w, h); } void RGFW_FUNC(RGFW_window_setMaxSize) (RGFW_window * win, i32 w, i32 h) { RGFW_ASSERT(win != NULL); xdg_toplevel_set_max_size(win->src.xdg_toplevel, w, h); } void RGFW_toggleWaylandMaximized(RGFW_window * win, RGFW_bool maximized) { win->src.maximized = maximized; if (maximized) { xdg_toplevel_set_maximized(win->src.xdg_toplevel); } else { xdg_toplevel_unset_maximized(win->src.xdg_toplevel); } } void RGFW_FUNC(RGFW_window_maximize) (RGFW_window * win) { win->internal.oldX = win->x; win->internal.oldY = win->y; win->internal.oldW = win->w; win->internal.oldH = win->h; RGFW_toggleWaylandMaximized(win, 1); return; } void RGFW_FUNC(RGFW_window_focus) (RGFW_window * win) { RGFW_ASSERT(win); } void RGFW_FUNC(RGFW_window_raise) (RGFW_window * win) { RGFW_ASSERT(win); } void RGFW_FUNC(RGFW_window_setFullscreen) (RGFW_window * win, RGFW_bool fullscreen) { RGFW_ASSERT(win != NULL); if (fullscreen) { win->internal.flags |= RGFW_windowFullscreen; win->internal.oldX = win->x; win->internal.oldY = win->y; win->internal.oldW = win->w; win->internal.oldH = win->h; xdg_toplevel_set_fullscreen(win->src.xdg_toplevel, NULL); //let the compositor decide } else { win->internal.flags &= ~(u32) RGFW_windowFullscreen; xdg_toplevel_unset_fullscreen(win->src.xdg_toplevel); } } void RGFW_FUNC(RGFW_window_setFloating) (RGFW_window * win, RGFW_bool floating) { RGFW_ASSERT(win != NULL); RGFW_UNUSED(floating); } void RGFW_FUNC(RGFW_window_setOpacity) (RGFW_window * win, u8 opacity) { RGFW_ASSERT(win != NULL); RGFW_UNUSED(opacity); } void RGFW_FUNC(RGFW_window_minimize) (RGFW_window * win) { RGFW_ASSERT(win != NULL); if (RGFW_window_isMaximized(win)) return; win->internal.oldX = win->x; win->internal.oldY = win->y; win->internal.oldW = win->w; win->internal.oldH = win->h; win->src.minimized = RGFW_TRUE; xdg_toplevel_set_minimized(win->src.xdg_toplevel); } void RGFW_FUNC(RGFW_window_restore) (RGFW_window * win) { RGFW_ASSERT(win != NULL); RGFW_toggleWaylandMaximized(win, RGFW_FALSE); RGFW_window_move(win, win->internal.oldX, win->internal.oldY); RGFW_window_resize(win, win->internal.oldW, win->internal.oldH); RGFW_window_show(win); RGFW_window_move(win, win->internal.oldX, win->internal.oldY); RGFW_window_resize(win, win->internal.oldW, win->internal.oldH); RGFW_window_show(win); } RGFW_bool RGFW_FUNC(RGFW_window_isFloating) (RGFW_window * win) { return (!RGFW_window_isFullscreen(win) && !RGFW_window_isMaximized(win)); } void RGFW_FUNC(RGFW_window_setName) (RGFW_window * win, const char *name){ RGFW_ASSERT(win != NULL); if (_RGFW->compositor) xdg_toplevel_set_title(win->src.xdg_toplevel, name); } #ifndef RGFW_NO_PASSTHROUGH void RGFW_FUNC(RGFW_window_setMousePassthrough) (RGFW_window * win, RGFW_bool passthrough) { RGFW_ASSERT(win != NULL); RGFW_UNUSED(passthrough); } #endif /* RGFW_NO_PASSTHROUGH */ RGFW_bool RGFW_FUNC(RGFW_window_setIconEx) (RGFW_window * win, u8 * data, i32 w, i32 h, RGFW_format format, RGFW_icon type) { RGFW_ASSERT(win != NULL); RGFW_UNUSED(type); if (_RGFW->icon_manager == NULL || w != h) return RGFW_FALSE; if (win->src.icon) { xdg_toplevel_icon_v1_destroy(win->src.icon); win->src.icon = NULL; } RGFW_surface *surface = RGFW_createSurface(data, w, h, format); if (surface == NULL) return RGFW_FALSE; RGFW_copyImageData(surface->native.buffer, RGFW_MIN(w, surface->w), RGFW_MIN(h, surface->h), surface->native.format, surface->data, surface->format); win->src.icon = xdg_toplevel_icon_manager_v1_create_icon(_RGFW->icon_manager); xdg_toplevel_icon_v1_add_buffer(win->src.icon, surface->native.wl_buffer, 1); xdg_toplevel_icon_manager_v1_set_icon(_RGFW->icon_manager, win->src.xdg_toplevel, win->src.icon); RGFW_surface_free(surface); return RGFW_TRUE; } RGFW_mouse *RGFW_FUNC(RGFW_loadMouse) (u8 * data, i32 w, i32 h, RGFW_format format) { RGFW_surface *mouse_surface = RGFW_createSurface(data, w, h, format); if (mouse_surface == NULL) return NULL; RGFW_copyImageData(mouse_surface->native.buffer, RGFW_MIN(w, mouse_surface->w), RGFW_MIN(h, mouse_surface->h), mouse_surface->native.format, mouse_surface->data, mouse_surface->format); return (void *)mouse_surface; } void RGFW_FUNC(RGFW_window_setMouse) (RGFW_window * win, RGFW_mouse * mouse) { RGFW_ASSERT(win); RGFW_ASSERT(mouse); RGFW_surface *mouse_surface = (RGFW_surface *) mouse; win->src.using_custom_cursor = RGFW_TRUE; struct wl_buffer *mouse_buffer = mouse_surface->native.wl_buffer; wl_surface_attach(win->src.custom_cursor_surface, mouse_buffer, 0, 0); wl_surface_damage(win->src.custom_cursor_surface, 0, 0, mouse_surface->w, mouse_surface->h); wl_surface_commit(win->src.custom_cursor_surface); } void RGFW_FUNC(RGFW_freeMouse) (RGFW_mouse * mouse) { if (mouse != NULL) { RGFW_surface_free((RGFW_surface *) mouse); } } void RGFW_FUNC(RGFW_window_moveMouse) (RGFW_window * win, i32 x, i32 y) { RGFW_UNUSED(win); RGFW_UNUSED(x); RGFW_UNUSED(y); } RGFW_bool RGFW_FUNC(RGFW_window_setMouseDefault) (RGFW_window * win) { return RGFW_window_setMouseStandard(win, RGFW_mouseArrow); } RGFW_bool RGFW_FUNC(RGFW_window_setMouseStandard) (RGFW_window * win, u8 mouse) { RGFW_ASSERT(win != NULL); static const char *iconStrings[16] = {"arrow", "left_ptr", "xterm", "crosshair", "hand2", "sb_h_double_arrow", "sb_v_double_arrow", "bottom_left_corner", "bottom_right_corner", "fleur", "forbidden"}; win->src.using_custom_cursor = RGFW_FALSE; if (mouse > RGFW_mouseIconCount - 1) return RGFW_FALSE; struct wl_cursor *wlcursor = wl_cursor_theme_get_cursor(_RGFW->wl_cursor_theme, iconStrings[mouse]); struct wl_cursor_image *cursor_image = wlcursor->images[0]; struct wl_buffer *cursor_buffer = wl_cursor_image_get_buffer(cursor_image); wl_pointer_set_cursor(_RGFW->wl_pointer, _RGFW->mouse_enter_serial, _RGFW->cursor_surface, (i32) cursor_image->hotspot_x, (i32) cursor_image->hotspot_y); wl_surface_attach(_RGFW->cursor_surface, cursor_buffer, 0, 0); wl_surface_damage(_RGFW->cursor_surface, 0, 0, (i32) cursor_image->width, (i32) cursor_image->height); wl_surface_commit(_RGFW->cursor_surface); return RGFW_TRUE; } void RGFW_FUNC(RGFW_window_hide) (RGFW_window * win) { wl_surface_attach(win->src.surface, NULL, 0, 0); wl_surface_commit(win->src.surface); win->internal.flags |= RGFW_windowHide; } void RGFW_FUNC(RGFW_window_show) (RGFW_window * win) { win->internal.flags &= ~(u32) RGFW_windowHide; if (win->internal.flags & RGFW_windowFocusOnShow) RGFW_window_focus(win); /* * wl_surface_attach(win->src.surface, win->x, * win->y, win->w, win->h, 0, 0); */ wl_surface_commit(win->src.surface); } RGFW_ssize_t RGFW_FUNC(RGFW_readClipboardPtr) (char *str, size_t strCapacity){ RGFW_UNUSED(str); RGFW_UNUSED(strCapacity); return 0; } void RGFW_FUNC(RGFW_writeClipboard) (const char *text, u32 textLen){ RGFW_UNUSED(text); RGFW_UNUSED(textLen); } RGFW_bool RGFW_FUNC(RGFW_window_isHidden) (RGFW_window * win) { RGFW_ASSERT(win != NULL); return RGFW_FALSE; } RGFW_bool RGFW_FUNC(RGFW_window_isMinimized) (RGFW_window * win) { RGFW_ASSERT(win != NULL); return win->src.minimized; } RGFW_bool RGFW_FUNC(RGFW_window_isMaximized) (RGFW_window * win) { RGFW_ASSERT(win != NULL); return win->src.maximized; } RGFW_monitor *RGFW_FUNC(RGFW_getMonitors) (size_t * len) { static RGFW_monitor monitors[RGFW_MAX_MONITORS]; RGFW_init(); if (len != NULL) { *len = _RGFW->monitors.count; } u8 i = 0; RGFW_monitorNode *cur_node = _RGFW->monitors.list.head; while (cur_node != NULL) { monitors[i] = cur_node->mon; ++i; cur_node = cur_node->next; } return monitors; } RGFW_monitor RGFW_FUNC(RGFW_getPrimaryMonitor) (void){ return _RGFW->monitors.list.head->mon; } RGFW_bool RGFW_FUNC(RGFW_monitor_requestMode) (RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { RGFW_UNUSED(mon); RGFW_UNUSED(mode); RGFW_UNUSED(request); return RGFW_FALSE; } RGFW_monitor RGFW_FUNC(RGFW_window_getMonitor) (RGFW_window * win) { RGFW_ASSERT(win); return win->src.active_monitor; } #ifdef RGFW_OPENGL RGFW_bool RGFW_FUNC(RGFW_extensionSupportedPlatform_OpenGL) (const char *extension, size_t len){ return RGFW_extensionSupportedPlatform_EGL(extension, len); } RGFW_proc RGFW_FUNC(RGFW_getProcAddress_OpenGL) (const char *procname){ return RGFW_getProcAddress_EGL(procname); } RGFW_bool RGFW_FUNC(RGFW_window_createContextPtr_OpenGL) (RGFW_window * win, RGFW_glContext * ctx, RGFW_glHints * hints) { RGFW_bool out = RGFW_window_createContextPtr_EGL(win, &ctx->egl, hints); win->src.gfxType = RGFW_gfxNativeOpenGL; return out; } void RGFW_FUNC(RGFW_window_deleteContextPtr_OpenGL) (RGFW_window * win, RGFW_glContext * ctx) { RGFW_window_deleteContextPtr_EGL(win, &ctx->egl); win->src.ctx.native = NULL; } void RGFW_FUNC(RGFW_window_makeCurrentContext_OpenGL) (RGFW_window * win) { RGFW_window_makeCurrentContext_EGL(win); } void *RGFW_FUNC(RGFW_getCurrentContext_OpenGL) (void){ return RGFW_getCurrentContext_EGL(); } void RGFW_FUNC(RGFW_window_swapBuffers_OpenGL) (RGFW_window * win) { RGFW_window_swapBuffers_EGL(win); } void RGFW_FUNC(RGFW_window_swapInterval_OpenGL) (RGFW_window * win, i32 swapInterval) { RGFW_window_swapInterval_EGL(win, swapInterval); } #endif /* RGFW_OPENGL */ void RGFW_FUNC(RGFW_window_closePlatform) (RGFW_window * win) { RGFW_ASSERT(win != NULL); RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, "a window was freed"); #ifdef RGFW_LIBDECOR if (win->src.decorContext) libdecor_unref(win->src.decorContext); #endif if (win->src.decoration) { zxdg_toplevel_decoration_v1_destroy(win->src.decoration); } if (win->src.xdg_toplevel) { xdg_toplevel_destroy(win->src.xdg_toplevel); } wl_surface_destroy(win->src.custom_cursor_surface); if (win->src.locked_pointer) { zwp_locked_pointer_v1_destroy(win->src.locked_pointer); } if (win->src.icon) { xdg_toplevel_icon_v1_destroy(win->src.icon); } xdg_surface_destroy(win->src.xdg_surface); wl_surface_destroy(win->src.surface); } #ifdef RGFW_WEBGPU WGPUSurface RGFW_FUNC(RGFW_window_createSurface_WebGPU) (RGFW_window * window, WGPUInstance instance) { WGPUSurfaceDescriptor surfaceDesc = {0}; WGPUSurfaceSourceWaylandSurface fromWl = {0}; fromWl.chain.sType = WGPUSType_SurfaceSourceWaylandSurface; fromWl.display = _RGFW->wl_display; fromWl.surface = window->src.surface; surfaceDesc.nextInChain = (WGPUChainedStruct *) & fromWl.chain; return wgpuInstanceCreateSurface(instance, &surfaceDesc); } #endif #endif /* RGFW_WAYLAND */ /* * End of Wayland defines */ /* * * Start of Windows defines * * */ #ifdef RGFW_WINDOWS #define WIN32_LEAN_AND_MEAN #define OEMRESOURCE #include #ifndef OCR_NORMAL #define OCR_NORMAL 32512 #define OCR_IBEAM 32513 #define OCR_WAIT 32514 #define OCR_CROSS 32515 #define OCR_UP 32516 #define OCR_SIZENWSE 32642 #define OCR_SIZENESW 32643 #define OCR_SIZEWE 32644 #define OCR_SIZENS 32645 #define OCR_SIZEALL 32646 #define OCR_NO 32648 #define OCR_HAND 32649 #define OCR_APPSTARTING 32650 #endif #include #include #include #include #include #include #ifndef WM_DPICHANGED #define WM_DPICHANGED 0x02E0 #endif RGFW_bool RGFW_createUTF8FromWideStringWin32(const WCHAR * source, char *out, size_t max); #define GL_FRONT 0x0404 #define GL_BACK 0x0405 #define GL_LEFT 0x0406 #define GL_RIGHT 0x0407 typedef int (*PFN_wglGetSwapIntervalEXT) (void); PFN_wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc = NULL; #define wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc /* these two wgl functions need to be preloaded */ typedef HGLRC(WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hdc, HGLRC hglrc, const int *attribList); PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL; HMODULE RGFW_wgl_dll = NULL; #ifndef RGFW_NO_LOAD_WGL typedef HGLRC(WINAPI * PFN_wglCreateContext) (HDC); typedef BOOL(WINAPI * PFN_wglDeleteContext) (HGLRC); typedef PROC(WINAPI * PFN_wglGetProcAddress) (LPCSTR); typedef BOOL(WINAPI * PFN_wglMakeCurrent) (HDC, HGLRC); typedef HDC(WINAPI * PFN_wglGetCurrentDC) (void); typedef HGLRC(WINAPI * PFN_wglGetCurrentContext) (void); typedef BOOL(WINAPI * PFN_wglShareLists) (HGLRC, HGLRC); PFN_wglCreateContext wglCreateContextSRC; PFN_wglDeleteContext wglDeleteContextSRC; PFN_wglGetProcAddress wglGetProcAddressSRC; PFN_wglMakeCurrent wglMakeCurrentSRC; PFN_wglGetCurrentDC wglGetCurrentDCSRC; PFN_wglGetCurrentContext wglGetCurrentContextSRC; PFN_wglShareLists wglShareListsSRC; #define wglCreateContext wglCreateContextSRC #define wglDeleteContext wglDeleteContextSRC #define wglGetProcAddress wglGetProcAddressSRC #define wglMakeCurrent wglMakeCurrentSRC #define wglGetCurrentDC wglGetCurrentDCSRC #define wglGetCurrentContext wglGetCurrentContextSRC #define wglShareLists wglShareListsSRC #endif void *RGFW_window_getHWND(RGFW_window * win) { return win->src.window; } void *RGFW_window_getHDC(RGFW_window * win) { return win->src.hdc; } #ifdef RGFW_OPENGL RGFWDEF void RGFW_win32_loadOpenGLFuncs(HWND dummyWin); typedef HRESULT(APIENTRY * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT * pfAttribFList, UINT nMaxFormats, int *piFormats, UINT * nNumFormats); PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL; typedef BOOL(APIENTRY * PFNWGLSWAPINTERVALEXTPROC) (int interval); PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL; #endif #ifndef RGFW_NO_DWM HMODULE RGFW_dwm_dll = NULL; #ifndef _DWMAPI_H_ typedef struct { DWORD dwFlags; int fEnable; HRGN hRgnBlur; int fTransitionOnMaximized; } DWM_BLURBEHIND; #endif typedef HRESULT(WINAPI * PFN_DwmEnableBlurBehindWindow) (HWND, const DWM_BLURBEHIND *); PFN_DwmEnableBlurBehindWindow DwmEnableBlurBehindWindowSRC = NULL; #endif void RGFW_win32_makeWindowTransparent(RGFW_window * win); void RGFW_win32_makeWindowTransparent(RGFW_window * win) { if (!(win->internal.flags & RGFW_windowTransparent)) return; #ifndef RGFW_NO_DWM if (DwmEnableBlurBehindWindowSRC != NULL) { DWM_BLURBEHIND bb = {0, 0, 0, 0}; bb.dwFlags = 0x1; bb.fEnable = TRUE; bb.hRgnBlur = NULL; DwmEnableBlurBehindWindowSRC(win->src.window, &bb); } else #endif { SetWindowLong(win->src.window, GWL_EXSTYLE, WS_EX_LAYERED); SetLayeredWindowAttributes(win->src.window, 0, 128, LWA_ALPHA); } } LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { RGFW_window *win = (RGFW_window *) GetPropW(hWnd, L"RGFW"); if (win == NULL) return DefWindowProcW(hWnd, message, wParam, lParam); static BYTE keyboardState[256]; GetKeyboardState(keyboardState); RGFW_event event; RGFW_MEMSET(&event, 0, sizeof(event)); event.common.win = win; RECT windowRect; GetWindowRect(hWnd, &windowRect); switch (message) { case WM_CLOSE: case WM_QUIT: RGFW_window_setShouldClose(win, RGFW_TRUE); RGFW_windowQuitCallback(win); RGFW_eventQueuePushEx(e.type = RGFW_quit; e.common.win = win); return 0; case WM_ACTIVATE:{ RGFW_bool inFocus = RGFW_BOOL(LOWORD(wParam) != WA_INACTIVE); win->internal.inFocus = RGFW_BOOL(inFocus); if ((win->internal.enabledEvents & (RGFW_BIT(RGFW_focusIn - inFocus)))) { RGFW_eventQueuePushEx(e.type = (RGFW_eventType) ((u8) RGFW_focusOut - inFocus); e.common.win = win); RGFW_focusCallback(win, inFocus); } if (inFocus == RGFW_FALSE) RGFW_window_focusLost(win); if ((win->internal.flags & RGFW_windowFullscreen) && inFocus == RGFW_TRUE) RGFW_window_setFullscreen(win, 1); return DefWindowProcW(hWnd, message, wParam, lParam); } case WM_MOVE: win->x = windowRect.left; win->y = windowRect.top; if (!(win->internal.enabledEvents & RGFW_windowMovedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam);; RGFW_eventQueuePushEx(e.type = RGFW_windowMoved; e.common.win = win); RGFW_windowMovedCallback(win, win->x, win->y); return DefWindowProcW(hWnd, message, wParam, lParam); case WM_SIZE:{ if (win->src.aspectRatioW != 0 && win->src.aspectRatioH != 0) { double aspectRatio = (double)win->src.aspectRatioW / win->src.aspectRatioH; int width = windowRect.right - windowRect.left; int height = windowRect.bottom - windowRect.top; int newHeight = (int)(width / aspectRatio); int newWidth = (int)(height * aspectRatio); if (win->w > (i32) ((windowRect.right - windowRect.left) - win->src.offsetW) || win->h > (i32) ((windowRect.bottom - windowRect.top) - win->src.offsetH)) { if (newHeight > height) windowRect.right = windowRect.left + newWidth; else windowRect.bottom = windowRect.top + newHeight; } else { if (newHeight < height) windowRect.right = windowRect.left + newWidth; else windowRect.bottom = windowRect.top + newHeight; } RGFW_window_resize(win, (windowRect.right - windowRect.left) - win->src.offsetW, (windowRect.bottom - windowRect.top) - win->src.offsetH); } win->w = (windowRect.right - windowRect.left) - (i32) win->src.offsetW; win->h = (windowRect.bottom - windowRect.top) - (i32) win->src.offsetH; if (!(win->internal.enabledEvents & RGFW_windowResizedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam);; RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e.common.win = win); RGFW_windowResizedCallback(win, win->w, win->h); RGFW_window_checkMode(win); return DefWindowProcW(hWnd, message, wParam, lParam); } #ifndef RGFW_NO_MONITOR case WM_DPICHANGED:{ if (win->internal.flags & RGFW_windowScaleToMonitor) RGFW_window_scaleToMonitor(win); const float scaleX = HIWORD(wParam) / (float)96; const float scaleY = LOWORD(wParam) / (float)96; if (!(win->internal.enabledEvents & RGFW_scaleUpdatedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam);; RGFW_scaleUpdatedCallback(win, scaleX, scaleY); RGFW_eventQueuePushEx(e.type = RGFW_scaleUpdated; e.scale.x = scaleX; e.scale.y = scaleY; e.common.win = win); return DefWindowProcW(hWnd, message, wParam, lParam); } #endif case WM_GETMINMAXINFO:{ MINMAXINFO *mmi = (MINMAXINFO *) lParam; mmi->ptMinTrackSize.x = (LONG) (win->src.minSizeW + win->src.offsetW); mmi->ptMinTrackSize.y = (LONG) (win->src.minSizeH + win->src.offsetH); if (win->src.maxSizeW == 0 && win->src.maxSizeH == 0) return DefWindowProcW(hWnd, message, wParam, lParam); mmi->ptMaxTrackSize.x = (LONG) (win->src.maxSizeW + win->src.offsetW); mmi->ptMaxTrackSize.y = (LONG) (win->src.maxSizeH + win->src.offsetH); return DefWindowProcW(hWnd, message, wParam, lParam); } case WM_PAINT:{ if (!(win->internal.enabledEvents & RGFW_windowRefreshFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); PAINTSTRUCT ps; BeginPaint(hWnd, &ps); RGFW_eventQueuePushEx(e.type = RGFW_windowRefresh; e.common.win = win); RGFW_windowRefreshCallback(win); EndPaint(hWnd, &ps); return DefWindowProcW(hWnd, message, wParam, lParam); } #if(_WIN32_WINNT >= 0x0600) case WM_DWMCOMPOSITIONCHANGED: case WM_DWMCOLORIZATIONCOLORCHANGED: RGFW_win32_makeWindowTransparent(win); break; #endif /* based on sokol_app.h */ #ifdef RGFW_ADVANCED_SMOOTH_RESIZE case WM_ENTERSIZEMOVE:SetTimer(win->src.window, 1, USER_TIMER_MINIMUM, NULL); break; case WM_EXITSIZEMOVE:KillTimer(win->src.window, 1); break; case WM_TIMER: if (!(win->internal.enabledEvents & RGFW_windowRefreshFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); RGFW_windowRefreshCallback(win); break; #endif case WM_NCLBUTTONDOWN:{ /* * workaround for half-second * pause when starting to move * window see: * https://gamedev.net/forums/topic/672094-keeping-things-moving-during-win32-moveresize-events/5254386/ */ POINT point = {0, 0}; if (SendMessage(win->src.window, WM_NCHITTEST, wParam, lParam) != HTCAPTION || GetCursorPos(&point) == FALSE) break; ScreenToClient(win->src.window, &point); PostMessage(win->src.window, WM_MOUSEMOVE, 0, (u32) (point.x) | ((u32) (point.y) << 16)); break; } case WM_MOUSELEAVE: win->internal.mouseInside = RGFW_FALSE; _RGFW->windowState.winLeave = win; _RGFW->windowState.mouseLeave = RGFW_TRUE; if (!(win->internal.enabledEvents & RGFW_mouseLeaveFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); event.type = RGFW_mouseLeave; RGFW_window_getMouse(win, &event.mouse.x, &event.mouse.y); RGFW_mouseNotifyCallback(win, event.mouse.x, event.mouse.y, 0); break; case WM_SYSKEYUP:case WM_KEYUP:{ if (!(win->internal.enabledEvents & RGFW_keyReleasedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); i32 scancode = (HIWORD(lParam) & (KF_EXTENDED | 0xff)); if (scancode == 0) scancode = (i32) MapVirtualKeyW((UINT) wParam, MAPVK_VK_TO_VSC); switch (scancode) { case 0x54:scancode = 0x137; break; /* Alt+PrtS */ case 0x146:scancode = 0x45; break; /* Ctrl+Pause */ case 0x136:scancode = 0x36; break; /* CJK IME sets the * extended bit for * right Shift */ default:break; } event.key.value = (u8) RGFW_apiKeyToRGFW((u32) scancode); if (wParam == VK_CONTROL) { if (HIWORD(lParam) & KF_EXTENDED) event.key.value = RGFW_controlR; else event.key.value = RGFW_controlL; } wchar_t charBuffer; ToUnicodeEx((UINT) wParam, (UINT) scancode, keyboardState, (wchar_t *) & charBuffer, 1, 0, NULL); event.key.sym = (u8) charBuffer; _RGFW->keyboard[event.key.value].prev = _RGFW->keyboard[event.key.value].current; event.type = RGFW_keyReleased; event.key.repeat = ((lParam & 0x40000000) != 0) || RGFW_window_isKeyDown(win, event.key.value); _RGFW->keyboard[event.key.value].current = 0; RGFW_updateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001), (GetKeyState(VK_SCROLL) & 0x0001)); event.key.mod = win->internal.mod; RGFW_keyCallback(win, event.key.value, event.key.sym, event.key.mod, event.key.repeat, 0); break; } case WM_SYSKEYDOWN:case WM_KEYDOWN:{ if (!(win->internal.enabledEvents & RGFW_keyPressedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); i32 scancode = (HIWORD(lParam) & (KF_EXTENDED | 0xff)); if (scancode == 0) scancode = (i32) MapVirtualKeyW((u32) wParam, MAPVK_VK_TO_VSC); switch (scancode) { case 0x54:scancode = 0x137; break; /* Alt+PrtS */ case 0x146:scancode = 0x45; break; /* Ctrl+Pause */ case 0x136:scancode = 0x36; break; /* CJK IME sets the * extended bit for * right Shift */ default:break; } event.key.value = (u8) RGFW_apiKeyToRGFW((u32) scancode); if (wParam == VK_CONTROL) { if (HIWORD(lParam) & KF_EXTENDED) event.key.value = RGFW_controlR; else event.key.value = RGFW_controlL; } wchar_t charBuffer; ToUnicodeEx((UINT) wParam, (UINT) scancode, keyboardState, &charBuffer, 1, 0, NULL); event.key.sym = (u8) charBuffer; _RGFW->keyboard[event.key.value].prev = _RGFW->keyboard[event.key.value].current; event.type = RGFW_keyPressed; event.key.repeat = ((lParam & 0x40000000) != 0) || RGFW_window_isKeyDown(win, event.key.value); _RGFW->keyboard[event.key.value].current = 1; RGFW_updateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001), (GetKeyState(VK_SCROLL) & 0x0001)); event.key.mod = win->internal.mod; RGFW_keyCallback(win, event.key.value, event.key.sym, event.key.mod, event.key.repeat, 1); break; } case WM_MOUSEMOVE:{ if (!(win->internal.enabledEvents & RGFW_mousePosChangedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); if ((win->internal.holdMouse)) break; event.mouse.x = GET_X_LPARAM(lParam); event.mouse.y = GET_Y_LPARAM(lParam); event.mouse.vecX = (float)(event.mouse.x - win->internal.lastMouseX); event.mouse.vecY = (float)(event.mouse.y - win->internal.lastMouseY); _RGFW->vectorX = event.mouse.vecX; _RGFW->vectorY = event.mouse.vecY; RGFW_mousePosCallback(win, event.mouse.x, event.mouse.y, event.mouse.vecX, event.mouse.vecY); if (win->internal.mouseInside == RGFW_FALSE) { win->internal.mouseInside = RGFW_TRUE; _RGFW->windowState.win = win; _RGFW->windowState.mouseEnter = RGFW_TRUE; event.type = RGFW_mouseEnter; RGFW_mouseNotifyCallback(win, event.mouse.x, event.mouse.y, 1); RGFW_eventQueuePush(&event); } event.type = RGFW_mousePosChanged; win->internal.lastMouseX = event.mouse.x; win->internal.lastMouseY = event.mouse.y; break; } case WM_INPUT:{ if (!(win->internal.enabledEvents & RGFW_mousePosChangedFlag) || !(win->internal.holdMouse)) return DefWindowProcW(hWnd, message, wParam, lParam); unsigned size = sizeof(RAWINPUT); static RAWINPUT raw; GetRawInputData((HRAWINPUT) lParam, RID_INPUT, &raw, &size, sizeof(RAWINPUTHEADER)); if (raw.header.dwType != RIM_TYPEMOUSE || (raw.data.mouse.lLastX == 0 && raw.data.mouse.lLastY == 0)) break; if (raw.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) { POINT pos = {0, 0}; int width, height; if (raw.data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP) { pos.x += GetSystemMetrics(SM_XVIRTUALSCREEN); pos.y += GetSystemMetrics(SM_YVIRTUALSCREEN); width = GetSystemMetrics(SM_CXVIRTUALSCREEN); height = GetSystemMetrics(SM_CYVIRTUALSCREEN); } else { width = GetSystemMetrics(SM_CXSCREEN); height = GetSystemMetrics(SM_CYSCREEN); } pos.x += (int)(((float)raw.data.mouse.lLastX / 65535.f) * (float)width); pos.y += (int)(((float)raw.data.mouse.lLastY / 65535.f) * (float)height); ScreenToClient(win->src.window, &pos); event.mouse.vecX = (float)(pos.x - win->internal.lastMouseX); event.mouse.vecY = (float)(pos.y - win->internal.lastMouseY); } else { event.mouse.vecX = (float)(raw.data.mouse.lLastX); event.mouse.vecY = (float)(raw.data.mouse.lLastY); } event.type = RGFW_mousePosChanged; win->internal.lastMouseX += (i32) event.mouse.vecX; win->internal.lastMouseY += (i32) event.mouse.vecY; _RGFW->vectorX = event.mouse.vecX; _RGFW->vectorY = event.mouse.vecY; event.mouse.x = win->internal.lastMouseX; event.mouse.y = win->internal.lastMouseY; RGFW_mousePosCallback(win, event.mouse.x, event.mouse.y, event.mouse.vecX, event.mouse.vecY); break; } case WM_LBUTTONDOWN:case WM_RBUTTONDOWN:case WM_MBUTTONDOWN:case WM_XBUTTONDOWN: if (!(win->internal.enabledEvents & RGFW_mouseButtonPressedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); if (message == WM_XBUTTONDOWN) event.button.value = RGFW_mouseMisc1 + (GET_XBUTTON_WPARAM(wParam) == XBUTTON2); else event.button.value = (message == WM_LBUTTONDOWN) ? (u8) RGFW_mouseLeft : (message == WM_RBUTTONDOWN) ? (u8) RGFW_mouseRight : (u8) RGFW_mouseMiddle; event.type = RGFW_mouseButtonPressed; _RGFW->mouseButtons[event.button.value].prev = _RGFW->mouseButtons[event.button.value].current; _RGFW->mouseButtons[event.button.value].current = 1; RGFW_mouseButtonCallback(win, event.button.value, 1); break; case WM_LBUTTONUP:case WM_RBUTTONUP:case WM_MBUTTONUP:case WM_XBUTTONUP: if (!(win->internal.enabledEvents & RGFW_mouseButtonReleasedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); if (message == WM_XBUTTONUP) event.button.value = RGFW_mouseMisc1 + (GET_XBUTTON_WPARAM(wParam) == XBUTTON2); else event.button.value = (message == WM_LBUTTONUP) ? (u8) RGFW_mouseLeft : (message == WM_RBUTTONUP) ? (u8) RGFW_mouseRight : (u8) RGFW_mouseMiddle; event.type = RGFW_mouseButtonReleased; _RGFW->mouseButtons[event.button.value].prev = _RGFW->mouseButtons[event.button.value].current; _RGFW->mouseButtons[event.button.value].current = 0; RGFW_mouseButtonCallback(win, event.button.value, 0); break; case WM_MOUSEWHEEL: if (!(win->internal.enabledEvents & RGFW_mouseScrollFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); event.type = RGFW_mouseScroll; event.scroll.x = 0.0f; event.scroll.y = (float)((i16) HIWORD(wParam) / (double)WHEEL_DELTA); _RGFW->scrollX = event.scroll.x; _RGFW->scrollY = event.scroll.y; RGFW_mouseScrollCallback(win, event.scroll.x, event.scroll.y); break; case 0x020E: /* WM_MOUSEHWHEEL */ if (!(win->internal.enabledEvents & RGFW_mouseScrollFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); event.type = RGFW_mouseScroll; event.scroll.x = -(float)((i16) HIWORD(wParam) / (double)WHEEL_DELTA); event.scroll.y = (float)0.0f; _RGFW->scrollX = event.scroll.x; _RGFW->scrollY = event.scroll.y; RGFW_mouseScrollCallback(win, event.scroll.x, event.scroll.y); break; case WM_DROPFILES:{ event.type = RGFW_dataDrag; HDROP drop = (HDROP) wParam; POINT pt; /* * Move the mouse to the * position of the drop */ DragQueryPoint(drop, &pt); event.drag.x = pt.x; event.drag.y = pt.y; _RGFW->windowState.win = win; _RGFW->windowState.dataDragging = RGFW_TRUE; _RGFW->windowState.dropX = event.drag.x; _RGFW->windowState.dropY = event.drag.y; if ((win->internal.enabledEvents & RGFW_dataDrag)) { RGFW_dataDragCallback(win, event.drag.x, event.drag.y); RGFW_eventQueuePush(&event); } if (!(win->internal.enabledEvents & RGFW_dataDrop)) return DefWindowProcW(hWnd, message, wParam, lParam); event.type = 0; event.type = RGFW_dataDrop; event.drop.files = _RGFW->files; event.drop.count = 0; event.drop.count = DragQueryFileW(drop, 0xffffffff, NULL, 0); u32 i; for (i = 0; i < event.drop.count; i++) { UINT length = DragQueryFileW(drop, i, NULL, 0); if (length == 0) continue; WCHAR buffer[RGFW_MAX_PATH * 2]; if (length > (RGFW_MAX_PATH * 2) - 1) length = RGFW_MAX_PATH * 2; DragQueryFileW(drop, i, buffer, length + 1); RGFW_createUTF8FromWideStringWin32(buffer, event.drop.files[i], RGFW_MAX_PATH); event.drop.files[i][RGFW_MAX_PATH - 1] = '\0'; event.common.win = win; } DragFinish(drop); _RGFW->windowState.win = win; _RGFW->windowState.dataDrop = RGFW_TRUE; _RGFW->windowState.filesCount = event.drop.count; RGFW_dataDropCallback(win, event.drop.files, event.drop.count); break; } default:break; } if (event.type) { RGFW_eventQueuePush(&event); } return DefWindowProcW(hWnd, message, wParam, lParam); } #ifndef RGFW_NO_DPI HMODULE RGFW_Shcore_dll = NULL; typedef HRESULT(WINAPI * PFN_GetDpiForMonitor) (HMONITOR, MONITOR_DPI_TYPE, UINT *, UINT *); PFN_GetDpiForMonitor GetDpiForMonitorSRC = NULL; #define GetDpiForMonitor GetDpiForMonitorSRC #endif #if !defined(RGFW_NO_LOAD_WINMM) && !defined(RGFW_NO_WINMM) HMODULE RGFW_winmm_dll = NULL; typedef u32(WINAPI * PFN_timeBeginPeriod) (u32); typedef PFN_timeBeginPeriod PFN_timeEndPeriod; PFN_timeBeginPeriod timeBeginPeriodSRC, timeEndPeriodSRC; #define timeBeginPeriod timeBeginPeriodSRC #define timeEndPeriod timeEndPeriodSRC #elif !defined(RGFW_NO_WINMM) __declspec(dllimport) u32 __stdcall timeBeginPeriod(u32 uPeriod); __declspec(dllimport) u32 __stdcall timeEndPeriod(u32 uPeriod); #endif #define RGFW_PROC_DEF(proc, name) if (name##SRC == NULL && proc != NULL) { \ name##SRC = (PFN_##name)(RGFW_proc)GetProcAddress((proc), (#name)); \ RGFW_ASSERT(name##SRC != NULL); \ } RGFW_bool RGFW_createSurfacePtr(u8 * data, i32 w, i32 h, RGFW_format format, RGFW_surface * surface) { RGFW_ASSERT(surface != NULL); surface->data = data; surface->w = w; surface->h = h; surface->format = format; BITMAPV5HEADER bi; ZeroMemory(&bi, sizeof(bi)); bi.bV5Size = sizeof(bi); bi.bV5Width = (i32) w; bi.bV5Height = -((LONG) h); bi.bV5Planes = 1; bi.bV5BitCount = (format >= RGFW_formatRGBA8) ? 32 : 24; bi.bV5Compression = BI_RGB; surface->native.bitmap = CreateDIBSection(_RGFW->root->src.hdc, (BITMAPINFO *) & bi, DIB_RGB_COLORS, (void **)&surface->native.bitmapBits, NULL, (DWORD) 0); surface->native.format = (format >= RGFW_formatRGBA8) ? RGFW_formatBGRA8 : RGFW_formatBGR8; if (surface->native.bitmap == NULL) { RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, "Failed to create DIB section."); return RGFW_FALSE; } surface->native.hdcMem = CreateCompatibleDC(_RGFW->root->src.hdc); SelectObject(surface->native.hdcMem, surface->native.bitmap); return RGFW_TRUE; } void RGFW_surface_freePtr(RGFW_surface * surface) { RGFW_ASSERT(surface != NULL); DeleteDC(surface->native.hdcMem); DeleteObject(surface->native.bitmap); } void RGFW_window_blitSurface(RGFW_window * win, RGFW_surface * surface) { RGFW_copyImageData(surface->native.bitmapBits, surface->w, RGFW_MIN(win->h, surface->h), surface->native.format, surface->data, surface->format); BitBlt(win->src.hdc, 0, 0, RGFW_MIN(win->w, surface->w), RGFW_MIN(win->h, surface->h), surface->native.hdcMem, 0, 0, SRCCOPY); } void RGFW_releaseCursor(RGFW_window * win) { RGFW_UNUSED(win); ClipCursor(NULL); const RAWINPUTDEVICE id = {0x01, 0x02, RIDEV_REMOVE, NULL}; RegisterRawInputDevices(&id, 1, sizeof(id)); } void RGFW_captureCursor(RGFW_window * win) { RGFW_UNUSED(win); RECT clipRect; GetClientRect(win->src.window, &clipRect); ClientToScreen(win->src.window, (POINT *) & clipRect.left); ClientToScreen(win->src.window, (POINT *) & clipRect.right); ClipCursor(&clipRect); const RAWINPUTDEVICE id = {0x01, 0x02, 0, win->src.window}; RegisterRawInputDevices(&id, 1, sizeof(id)); } #define RGFW_LOAD_LIBRARY(x, lib) if (x == NULL) { x = LoadLibraryA(lib); RGFW_ASSERT(x != NULL); } #ifdef RGFW_DIRECTX int RGFW_window_createSwapChain_DirectX(RGFW_window * win, IDXGIFactory * pFactory, IUnknown * pDevice, IDXGISwapChain * *swapchain) { RGFW_ASSERT(win && pFactory && pDevice && swapchain); static DXGI_SWAP_CHAIN_DESC swapChainDesc = {0}; swapChainDesc.BufferCount = 2; swapChainDesc.BufferDesc.Width = win->w; swapChainDesc.BufferDesc.Height = win->h; swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.OutputWindow = (HWND) win->src.window; swapChainDesc.SampleDesc.Count = 1; swapChainDesc.SampleDesc.Quality = 0; swapChainDesc.Windowed = TRUE; swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; HRESULT hr = pFactory->lpVtbl->CreateSwapChain(pFactory, (IUnknown *) pDevice, &swapChainDesc, swapchain); if (FAILED(hr)) { RGFW_sendDebugInfo(RGFW_typeError, RGFW_errDirectXContext, "Failed to create DirectX swap chain!"); return -2; } return 0; } #endif /* * we're doing it with magic numbers because some keys * are missing */ void RGFW_initKeycodesPlatform(void){ _RGFW->keycodes[0x00B] = RGFW_0; _RGFW->keycodes[0x002] = RGFW_1; _RGFW->keycodes[0x003] = RGFW_2; _RGFW->keycodes[0x004] = RGFW_3; _RGFW->keycodes[0x005] = RGFW_4; _RGFW->keycodes[0x006] = RGFW_5; _RGFW->keycodes[0x007] = RGFW_6; _RGFW->keycodes[0x008] = RGFW_7; _RGFW->keycodes[0x009] = RGFW_8; _RGFW->keycodes[0x00A] = RGFW_9; _RGFW->keycodes[0x01E] = RGFW_a; _RGFW->keycodes[0x030] = RGFW_b; _RGFW->keycodes[0x02E] = RGFW_c; _RGFW->keycodes[0x020] = RGFW_d; _RGFW->keycodes[0x012] = RGFW_e; _RGFW->keycodes[0x021] = RGFW_f; _RGFW->keycodes[0x022] = RGFW_g; _RGFW->keycodes[0x023] = RGFW_h; _RGFW->keycodes[0x017] = RGFW_i; _RGFW->keycodes[0x024] = RGFW_j; _RGFW->keycodes[0x025] = RGFW_k; _RGFW->keycodes[0x026] = RGFW_l; _RGFW->keycodes[0x032] = RGFW_m; _RGFW->keycodes[0x031] = RGFW_n; _RGFW->keycodes[0x018] = RGFW_o; _RGFW->keycodes[0x019] = RGFW_p; _RGFW->keycodes[0x010] = RGFW_q; _RGFW->keycodes[0x013] = RGFW_r; _RGFW->keycodes[0x01F] = RGFW_s; _RGFW->keycodes[0x014] = RGFW_t; _RGFW->keycodes[0x016] = RGFW_u; _RGFW->keycodes[0x02F] = RGFW_v; _RGFW->keycodes[0x011] = RGFW_w; _RGFW->keycodes[0x02D] = RGFW_x; _RGFW->keycodes[0x015] = RGFW_y; _RGFW->keycodes[0x02C] = RGFW_z; _RGFW->keycodes[0x028] = RGFW_apostrophe; _RGFW->keycodes[0x02B] = RGFW_backSlash; _RGFW->keycodes[0x033] = RGFW_comma; _RGFW->keycodes[0x00D] = RGFW_equals; _RGFW->keycodes[0x029] = RGFW_backtick; _RGFW->keycodes[0x01A] = RGFW_bracket; _RGFW->keycodes[0x00C] = RGFW_minus; _RGFW->keycodes[0x034] = RGFW_period; _RGFW->keycodes[0x01B] = RGFW_closeBracket; _RGFW->keycodes[0x027] = RGFW_semicolon; _RGFW->keycodes[0x035] = RGFW_slash; _RGFW->keycodes[0x056] = RGFW_world2; _RGFW->keycodes[0x00E] = RGFW_backSpace; _RGFW->keycodes[0x153] = RGFW_delete; _RGFW->keycodes[0x14F] = RGFW_end; _RGFW->keycodes[0x01C] = RGFW_enter; _RGFW->keycodes[0x001] = RGFW_escape; _RGFW->keycodes[0x147] = RGFW_home; _RGFW->keycodes[0x152] = RGFW_insert; _RGFW->keycodes[0x15D] = RGFW_menu; _RGFW->keycodes[0x151] = RGFW_pageDown; _RGFW->keycodes[0x149] = RGFW_pageUp; _RGFW->keycodes[0x045] = RGFW_pause; _RGFW->keycodes[0x039] = RGFW_space; _RGFW->keycodes[0x00F] = RGFW_tab; _RGFW->keycodes[0x03A] = RGFW_capsLock; _RGFW->keycodes[0x145] = RGFW_numLock; _RGFW->keycodes[0x046] = RGFW_scrollLock; _RGFW->keycodes[0x03B] = RGFW_F1; _RGFW->keycodes[0x03C] = RGFW_F2; _RGFW->keycodes[0x03D] = RGFW_F3; _RGFW->keycodes[0x03E] = RGFW_F4; _RGFW->keycodes[0x03F] = RGFW_F5; _RGFW->keycodes[0x040] = RGFW_F6; _RGFW->keycodes[0x041] = RGFW_F7; _RGFW->keycodes[0x042] = RGFW_F8; _RGFW->keycodes[0x043] = RGFW_F9; _RGFW->keycodes[0x044] = RGFW_F10; _RGFW->keycodes[0x057] = RGFW_F11; _RGFW->keycodes[0x058] = RGFW_F12; _RGFW->keycodes[0x064] = RGFW_F13; _RGFW->keycodes[0x065] = RGFW_F14; _RGFW->keycodes[0x066] = RGFW_F15; _RGFW->keycodes[0x067] = RGFW_F16; _RGFW->keycodes[0x068] = RGFW_F17; _RGFW->keycodes[0x069] = RGFW_F18; _RGFW->keycodes[0x06A] = RGFW_F19; _RGFW->keycodes[0x06B] = RGFW_F20; _RGFW->keycodes[0x06C] = RGFW_F21; _RGFW->keycodes[0x06D] = RGFW_F22; _RGFW->keycodes[0x06E] = RGFW_F23; _RGFW->keycodes[0x076] = RGFW_F24; _RGFW->keycodes[0x038] = RGFW_altL; _RGFW->keycodes[0x01D] = RGFW_controlL; _RGFW->keycodes[0x02A] = RGFW_shiftL; _RGFW->keycodes[0x15B] = RGFW_superL; _RGFW->keycodes[0x137] = RGFW_printScreen; _RGFW->keycodes[0x138] = RGFW_altR; _RGFW->keycodes[0x11D] = RGFW_controlR; _RGFW->keycodes[0x036] = RGFW_shiftR; _RGFW->keycodes[0x15C] = RGFW_superR; _RGFW->keycodes[0x150] = RGFW_down; _RGFW->keycodes[0x14B] = RGFW_left; _RGFW->keycodes[0x14D] = RGFW_right; _RGFW->keycodes[0x148] = RGFW_up; _RGFW->keycodes[0x052] = RGFW_kp0; _RGFW->keycodes[0x04F] = RGFW_kp1; _RGFW->keycodes[0x050] = RGFW_kp2; _RGFW->keycodes[0x051] = RGFW_kp3; _RGFW->keycodes[0x04B] = RGFW_kp4; _RGFW->keycodes[0x04C] = RGFW_kp5; _RGFW->keycodes[0x04D] = RGFW_kp6; _RGFW->keycodes[0x047] = RGFW_kp7; _RGFW->keycodes[0x048] = RGFW_kp8; _RGFW->keycodes[0x049] = RGFW_kp9; _RGFW->keycodes[0x04E] = RGFW_kpPlus; _RGFW->keycodes[0x053] = RGFW_kpPeriod; _RGFW->keycodes[0x135] = RGFW_kpSlash; _RGFW->keycodes[0x11C] = RGFW_kpReturn; _RGFW->keycodes[0x059] = RGFW_kpEqual; _RGFW->keycodes[0x037] = RGFW_kpMultiply; _RGFW->keycodes[0x04A] = RGFW_kpMinus; } i32 RGFW_initPlatform(void){ #ifndef RGFW_NO_DPI #if (_WIN32_WINNT >= 0x0600) SetProcessDPIAware(); #endif #endif #ifndef RGFW_NO_WINMM #ifndef RGFW_NO_LOAD_WINMM RGFW_LOAD_LIBRARY(RGFW_winmm_dll, "winmm.dll"); RGFW_PROC_DEF(RGFW_winmm_dll, timeBeginPeriod); RGFW_PROC_DEF(RGFW_winmm_dll, timeEndPeriod); #endif timeBeginPeriod(1); #endif #ifndef RGFW_NO_DWM RGFW_LOAD_LIBRARY(RGFW_dwm_dll, "dwmapi.dll"); RGFW_PROC_DEF(RGFW_dwm_dll, DwmEnableBlurBehindWindow); #endif RGFW_LOAD_LIBRARY(RGFW_wgl_dll, "opengl32.dll"); #ifndef RGFW_NO_LOAD_WGL RGFW_PROC_DEF(RGFW_wgl_dll, wglCreateContext); RGFW_PROC_DEF(RGFW_wgl_dll, wglDeleteContext); RGFW_PROC_DEF(RGFW_wgl_dll, wglGetProcAddress); RGFW_PROC_DEF(RGFW_wgl_dll, wglMakeCurrent); RGFW_PROC_DEF(RGFW_wgl_dll, wglGetCurrentDC); RGFW_PROC_DEF(RGFW_wgl_dll, wglGetCurrentContext); RGFW_PROC_DEF(RGFW_wgl_dll, wglShareLists); #endif u8 RGFW_blk[] = {0, 0, 0, 0}; _RGFW->hiddenMouse = RGFW_loadMouse(RGFW_blk, 1, 1, RGFW_formatRGBA8); return 1; } RGFW_window *RGFW_createWindowPlatform(const char *name, RGFW_windowFlags flags, RGFW_window * win){ if (name[0] == 0) name = (char *)" "; win->src.hIconSmall = win->src.hIconBig = NULL; win->src.maxSizeW = 0; win->src.maxSizeH = 0; win->src.minSizeW = 0; win->src.minSizeH = 0; win->src.aspectRatioW = 0; win->src.aspectRatioH = 0; HINSTANCE inh = GetModuleHandleA(NULL); #ifndef __cplusplus WNDCLASSW Class = {0}; /* !< Setup the Window * class. */ #else WNDCLASSW Class = {}; #endif if (_RGFW->className == NULL) _RGFW->className = (char *)name; wchar_t wide_class[256]; MultiByteToWideChar(CP_UTF8, 0, _RGFW->className, -1, wide_class, 255); Class.lpszClassName = wide_class; Class.hInstance = inh; Class.hCursor = LoadCursor(NULL, IDC_ARROW); Class.lpfnWndProc = WndProcW; Class.cbClsExtra = sizeof(RGFW_window *); Class.hIcon = (HICON) LoadImageA(GetModuleHandleW(NULL), "RGFW_ICON", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED); if (Class.hIcon == NULL) Class.hIcon = (HICON) LoadImageA(NULL, (LPCSTR) IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED); RegisterClassW(&Class); DWORD window_style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; RECT windowRect, clientRect; if (!(flags & RGFW_windowNoBorder)) { window_style |= WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX; if (!(flags & RGFW_windowNoResize)) window_style |= WS_SIZEBOX | WS_MAXIMIZEBOX; } else window_style |= WS_POPUP | WS_VISIBLE | WS_SYSMENU; wchar_t wide_name[256]; MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_name, 255); HWND dummyWin = CreateWindowW(Class.lpszClassName, (wchar_t *) wide_name, window_style, win->x, win->y, win->w, win->h, 0, 0, inh, 0); GetWindowRect(dummyWin, &windowRect); GetClientRect(dummyWin, &clientRect); #ifdef RGFW_OPENGL RGFW_win32_loadOpenGLFuncs(dummyWin); #endif DestroyWindow(dummyWin); win->src.offsetW = (i32) (windowRect.right - windowRect.left) - (i32) (clientRect.right - clientRect.left); win->src.offsetH = (i32) (windowRect.bottom - windowRect.top) - (i32) (clientRect.bottom - clientRect.top); win->src.window = CreateWindowW(Class.lpszClassName, (wchar_t *) wide_name, window_style, win->x, win->y, win->w + (i32) win->src.offsetW, win->h + (i32) win->src.offsetH, 0, 0, inh, 0); SetPropW(win->src.window, L"RGFW", win); RGFW_window_resize(win, win->w, win->h); /* so WM_GETMINMAXINFO * gets called again */ if (flags & RGFW_windowAllowDND) { win->internal.flags |= RGFW_windowAllowDND; RGFW_window_setDND(win, 1); } win->src.hdc = GetDC(win->src.window); RGFW_win32_makeWindowTransparent(win); return win; } void RGFW_window_setBorder(RGFW_window * win, RGFW_bool border) { RGFW_setBit(&win->internal.flags, RGFW_windowNoBorder, !border); LONG style = GetWindowLong(win->src.window, GWL_STYLE); if (border == 0) { SetWindowLong(win->src.window, GWL_STYLE, style & ~WS_OVERLAPPEDWINDOW); SetWindowPos( win->src.window, HWND_TOP, 0, 0, 0, 0, SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE ); } else { if (win->internal.flags & RGFW_windowNoResize) style &= ~WS_MAXIMIZEBOX; SetWindowLong(win->src.window, GWL_STYLE, style | WS_OVERLAPPEDWINDOW); SetWindowPos( win->src.window, HWND_TOP, 0, 0, 0, 0, SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE ); } } void RGFW_window_setDND(RGFW_window * win, RGFW_bool allow) { RGFW_setBit(&win->internal.flags, RGFW_windowAllowDND, allow); DragAcceptFiles(win->src.window, allow); } RGFW_bool RGFW_getGlobalMouse(i32 * x, i32 * y) { POINT p; GetCursorPos(&p); if (x) *x = p.x; if (y) *y = p.y; return RGFW_TRUE; } void RGFW_window_setAspectRatio(RGFW_window * win, i32 w, i32 h) { RGFW_ASSERT(win != NULL); win->src.aspectRatioW = w; win->src.aspectRatioH = h; } void RGFW_window_setMinSize(RGFW_window * win, i32 w, i32 h) { RGFW_ASSERT(win != NULL); win->src.minSizeW = w; win->src.minSizeH = h; } void RGFW_window_setMaxSize(RGFW_window * win, i32 w, i32 h) { RGFW_ASSERT(win != NULL); win->src.maxSizeW = w; win->src.maxSizeH = h; } void RGFW_window_focus(RGFW_window * win) { RGFW_ASSERT(win); SetForegroundWindow(win->src.window); SetFocus(win->src.window); } void RGFW_window_raise(RGFW_window * win) { RGFW_ASSERT(win); BringWindowToTop(win->src.window); SetWindowPos(win->src.window, HWND_TOP, win->x, win->y, win->w, win->h, SWP_NOSIZE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_FRAMECHANGED); } void RGFW_window_setFullscreen(RGFW_window * win, RGFW_bool fullscreen) { RGFW_ASSERT(win != NULL); if (fullscreen == RGFW_FALSE) { RGFW_window_setBorder(win, 1); SetWindowPos(win->src.window, HWND_NOTOPMOST, win->internal.oldX, win->internal.oldY, win->internal.oldW + (i32) win->src.offsetW, win->internal.oldH + (i32) win->src.offsetH, SWP_NOOWNERZORDER | SWP_FRAMECHANGED); win->internal.flags &= ~(u32) RGFW_windowFullscreen; win->x = win->internal.oldX; win->y = win->internal.oldY; win->w = win->internal.oldW; win->h = win->internal.oldH; return; } win->internal.oldX = win->x; win->internal.oldY = win->y; win->internal.oldW = win->w; win->internal.oldH = win->h; win->internal.flags |= RGFW_windowFullscreen; RGFW_monitor mon = RGFW_window_getMonitor(win); RGFW_window_setBorder(win, 0); SetWindowPos(win->src.window, HWND_TOPMOST, (i32) mon.x, (i32) mon.x, (i32) mon.mode.w, (i32) mon.mode.h, SWP_NOOWNERZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW); RGFW_monitor_scaleToWindow(mon, win); win->x = mon.x; win->y = mon.x; win->w = mon.mode.w; win->h = mon.mode.h; } void RGFW_window_maximize(RGFW_window * win) { RGFW_ASSERT(win != NULL); RGFW_window_hide(win); ShowWindow(win->src.window, SW_MAXIMIZE); } void RGFW_window_minimize(RGFW_window * win) { RGFW_ASSERT(win != NULL); ShowWindow(win->src.window, SW_MINIMIZE); } void RGFW_window_setFloating(RGFW_window * win, RGFW_bool floating) { RGFW_ASSERT(win != NULL); if (floating) SetWindowPos(win->src.window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); else SetWindowPos(win->src.window, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); } void RGFW_window_setOpacity(RGFW_window * win, u8 opacity) { SetWindowLong(win->src.window, GWL_EXSTYLE, WS_EX_LAYERED); SetLayeredWindowAttributes(win->src.window, 0, opacity, LWA_ALPHA); } void RGFW_window_restore(RGFW_window * win) { RGFW_window_show(win); } RGFW_bool RGFW_window_isFloating(RGFW_window * win) { return (GetWindowLongPtr(win->src.window, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0; } void RGFW_stopCheckEvents(void){ PostMessageW(_RGFW->root->src.window, WM_NULL, 0, 0); } void RGFW_waitForEvent(i32 waitMS) { MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD) waitMS, QS_ALLINPUT); } u8 RGFW_rgfwToKeyChar(u32 rgfw_keycode) { UINT vsc = RGFW_rgfwToApiKey(rgfw_keycode); /* Should return a * Windows VK_* code */ BYTE keyboardState[256] = {0}; if (!GetKeyboardState(keyboardState)) return (u8) rgfw_keycode; UINT vk = MapVirtualKeyW(vsc, MAPVK_VSC_TO_VK); HKL layout = GetKeyboardLayout(0); wchar_t charBuffer[2] = {0}; int result = ToUnicodeEx(vk, vsc, keyboardState, charBuffer, 1, 0, layout); if (result <= 0) return (u8) rgfw_keycode; return (u8) charBuffer[0]; } void RGFW_pollEvents(void){ RGFW_resetPrevState(); MSG msg; while (PeekMessageA(&msg, NULL, 0u, 0u, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessageA(&msg); } } RGFW_bool RGFW_window_isHidden(RGFW_window * win) { RGFW_ASSERT(win != NULL); return IsWindowVisible(win->src.window) == 0 && !RGFW_window_isMinimized(win); } RGFW_bool RGFW_window_isMinimized(RGFW_window * win) { RGFW_ASSERT(win != NULL); #ifndef __cplusplus WINDOWPLACEMENT placement = {0}; #else WINDOWPLACEMENT placement = {}; #endif GetWindowPlacement(win->src.window, &placement); return placement.showCmd == SW_SHOWMINIMIZED; } RGFW_bool RGFW_window_isMaximized(RGFW_window * win) { RGFW_ASSERT(win != NULL); #ifndef __cplusplus WINDOWPLACEMENT placement = {0}; #else WINDOWPLACEMENT placement = {}; #endif GetWindowPlacement(win->src.window, &placement); return placement.showCmd == SW_SHOWMAXIMIZED || IsZoomed(win->src.window); } typedef struct { int iIndex; HMONITOR hMonitor; RGFW_monitor *monitors; } RGFW_mInfo; #ifndef RGFW_NO_MONITOR RGFW_monitor RGFW_win32_createMonitor(HMONITOR src); RGFW_monitor RGFW_win32_createMonitor(HMONITOR src) { RGFW_monitor monitor; RGFW_MEMSET(&monitor, 0, sizeof(monitor)); MONITORINFOEXW monitorInfo; monitorInfo.cbSize = sizeof(MONITORINFOEXW); GetMonitorInfoW(src, (LPMONITORINFO) & monitorInfo); /* get the monitor's index */ DISPLAY_DEVICEW dd; dd.cb = sizeof(dd); DWORD deviceNum; for (deviceNum = 0; EnumDisplayDevicesW(NULL, deviceNum, &dd, 0); deviceNum++) { if (!(dd.StateFlags & DISPLAY_DEVICE_ACTIVE)) continue; DEVMODEW dm; ZeroMemory(&dm, sizeof(dm)); dm.dmSize = sizeof(dm); if (EnumDisplaySettingsW(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) { monitor.mode.refreshRate = dm.dmDisplayFrequency; RGFW_splitBPP(dm.dmBitsPerPel, &monitor.mode); } DISPLAY_DEVICEW mdd; mdd.cb = sizeof(mdd); if (EnumDisplayDevicesW(dd.DeviceName, (DWORD) deviceNum, &mdd, 0)) { RGFW_createUTF8FromWideStringWin32(mdd.DeviceString, monitor.name, sizeof(monitor.name)); monitor.name[sizeof(monitor.name) - 1] = '\0'; break; } } monitor.x = monitorInfo.rcWork.left; monitor.y = monitorInfo.rcWork.top; monitor.mode.w = (i32) (monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left); monitor.mode.h = (i32) (monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top); HDC hdc = CreateDCW(monitorInfo.szDevice, NULL, NULL, NULL); /* get pixels per inch */ float dpiX = (float)GetDeviceCaps(hdc, LOGPIXELSX); float dpiY = (float)GetDeviceCaps(hdc, LOGPIXELSX); monitor.scaleX = dpiX / 96.0f; monitor.scaleY = dpiY / 96.0f; monitor.pixelRatio = dpiX >= 192.0f ? 2.0f : 1.0f; monitor.physW = (float)GetDeviceCaps(hdc, HORZSIZE) / 25.4f; monitor.physH = (float)GetDeviceCaps(hdc, VERTSIZE) / 25.4f; DeleteDC(hdc); #ifndef RGFW_NO_DPI RGFW_LOAD_LIBRARY(RGFW_Shcore_dll, "shcore.dll"); RGFW_PROC_DEF(RGFW_Shcore_dll, GetDpiForMonitor); if (GetDpiForMonitor != NULL) { u32 x, y; GetDpiForMonitor(src, MDT_EFFECTIVE_DPI, &x, &y); monitor.scaleX = (float)(x) / (float)96.0f; monitor.scaleY = (float)(y) / (float)96.0f; monitor.pixelRatio = dpiX >= 192.0f ? 2.0f : 1.0f; } #endif RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, "monitor found"); return monitor; } #endif /* RGFW_NO_MONITOR */ #ifndef RGFW_NO_MONITOR BOOL CALLBACK GetMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData); BOOL CALLBACK GetMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) { RGFW_UNUSED(hdcMonitor); RGFW_UNUSED(lprcMonitor); RGFW_mInfo *info = (RGFW_mInfo *) dwData; if (info->iIndex >= 6) return FALSE; info->monitors[info->iIndex] = RGFW_win32_createMonitor(hMonitor); info->iIndex++; return TRUE; } RGFW_monitor RGFW_getPrimaryMonitor(void){ #ifdef __cplusplus return RGFW_win32_createMonitor(MonitorFromPoint({ 0, 0 } ,MONITOR_DEFAULTTOPRIMARY)); #else return RGFW_win32_createMonitor(MonitorFromPoint((POINT) { 0, 0 } ,MONITOR_DEFAULTTOPRIMARY)); #endif } RGFW_monitor *RGFW_getMonitors(size_t * len) { static RGFW_monitor monitors[6]; RGFW_mInfo info; info.iIndex = 0; info.monitors = monitors; EnumDisplayMonitors(NULL, NULL, GetMonitorHandle, (LPARAM) & info); if (len != NULL) *len = (size_t) info.iIndex; return monitors; } RGFW_monitor RGFW_window_getMonitor(RGFW_window * win) { HMONITOR src = MonitorFromWindow(win->src.window, MONITOR_DEFAULTTOPRIMARY); return RGFW_win32_createMonitor(src); } RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { POINT p = {mon.x, mon.y}; HMONITOR src = MonitorFromPoint(p, MONITOR_DEFAULTTOPRIMARY); MONITORINFOEX monitorInfo; monitorInfo.cbSize = sizeof(MONITORINFOEX); GetMonitorInfoA(src, (LPMONITORINFO) & monitorInfo); DISPLAY_DEVICEA dd; dd.cb = sizeof(dd); /* Enumerate display devices */ DWORD deviceNum; for (deviceNum = 0; EnumDisplayDevicesA(NULL, deviceNum, &dd, 0); deviceNum++) { if (!(dd.StateFlags & DISPLAY_DEVICE_ACTIVE)) continue; if (strcmp(dd.DeviceName, (const char *)monitorInfo.szDevice) != 0) continue; DEVMODEA dm; ZeroMemory(&dm, sizeof(dm)); dm.dmSize = sizeof(dm); if (EnumDisplaySettingsA(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) { if (request & RGFW_monitorScale) { dm.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT; dm.dmPelsWidth = (u32) mode.w; dm.dmPelsHeight = (u32) mode.h; } if (request & RGFW_monitorRefresh) { dm.dmFields |= DM_DISPLAYFREQUENCY; dm.dmDisplayFrequency = mode.refreshRate; } if (request & RGFW_monitorRGB) { dm.dmFields |= DM_BITSPERPEL; dm.dmBitsPerPel = (DWORD) (mode.red + mode.green + mode.blue); } if (ChangeDisplaySettingsExA(dd.DeviceName, &dm, NULL, CDS_TEST, NULL) == DISP_CHANGE_SUCCESSFUL) { if (ChangeDisplaySettingsExA(dd.DeviceName, &dm, NULL, CDS_UPDATEREGISTRY, NULL) == DISP_CHANGE_SUCCESSFUL) return RGFW_TRUE; return RGFW_FALSE; } else return RGFW_FALSE; } } return RGFW_FALSE; } #endif HICON RGFW_loadHandleImage(u8 * data, i32 w, i32 h, RGFW_format format, BOOL icon); HICON RGFW_loadHandleImage(u8 * data, i32 w, i32 h, RGFW_format format, BOOL icon) { BITMAPV5HEADER bi; ZeroMemory(&bi, sizeof(bi)); bi.bV5Size = sizeof(bi); bi.bV5Width = (i32) w; bi.bV5Height = -((LONG) h); bi.bV5Planes = 1; bi.bV5BitCount = (WORD) 32; bi.bV5Compression = BI_RGB; HDC dc = GetDC(NULL); u8 *target = NULL; HBITMAP color = CreateDIBSection(dc, (BITMAPINFO *) & bi, DIB_RGB_COLORS, (void **)&target, NULL, (DWORD) 0); RGFW_copyImageData(target, w, h, RGFW_formatBGRA8, data, format); ReleaseDC(NULL, dc); HBITMAP mask = CreateBitmap((i32) w, (i32) h, 1, 1, NULL); ICONINFO ii; ZeroMemory(&ii, sizeof(ii)); ii.fIcon = icon; ii.xHotspot = (u32) w / 2; ii.yHotspot = (u32) h / 2; ii.hbmMask = mask; ii.hbmColor = color; HICON handle = CreateIconIndirect(&ii); DeleteObject(color); DeleteObject(mask); return handle; } RGFW_mouse *RGFW_loadMouse(u8 * data, i32 w, i32 h, RGFW_format format) { HCURSOR cursor = (HCURSOR) RGFW_loadHandleImage(data, w, h, format, FALSE); return cursor; } void RGFW_window_setMouse(RGFW_window * win, RGFW_mouse * mouse) { RGFW_ASSERT(win && mouse); SetClassLongPtrA(win->src.window, GCLP_HCURSOR, (LPARAM) mouse); SetCursor((HCURSOR) mouse); } void RGFW_freeMouse(RGFW_mouse * mouse) { RGFW_ASSERT(mouse); DestroyCursor((HCURSOR) mouse); } RGFW_bool RGFW_window_setMouseDefault(RGFW_window * win) { return RGFW_window_setMouseStandard(win, RGFW_mouseArrow); } RGFW_bool RGFW_window_setMouseStandard(RGFW_window * win, u8 mouse) { RGFW_ASSERT(win != NULL); static const u32 mouseIconSrc[16] = {OCR_NORMAL, OCR_NORMAL, OCR_IBEAM, OCR_CROSS, OCR_HAND, OCR_SIZEWE, OCR_SIZENS, OCR_SIZENWSE, OCR_SIZENESW, OCR_SIZEALL, OCR_NO}; if (mouse > (sizeof(mouseIconSrc) / sizeof(u32))) return RGFW_FALSE; char *icon = MAKEINTRESOURCEA(mouseIconSrc[mouse]); SetClassLongPtrA(win->src.window, GCLP_HCURSOR, (LPARAM) LoadCursorA(NULL, icon)); SetCursor(LoadCursorA(NULL, icon)); return RGFW_TRUE; } void RGFW_window_hide(RGFW_window * win) { ShowWindow(win->src.window, SW_HIDE); } void RGFW_window_show(RGFW_window * win) { if (win->internal.flags & RGFW_windowFocusOnShow) RGFW_window_focus(win); ShowWindow(win->src.window, SW_RESTORE); } #define RGFW_FREE_LIBRARY(x) if (x != NULL) FreeLibrary(x); x = NULL; void RGFW_deinitPlatform(void){ #ifndef RGFW_NO_DPI RGFW_FREE_LIBRARY(RGFW_Shcore_dll); #endif #ifndef RGFW_NO_WINMM timeEndPeriod(1); #ifndef RGFW_NO_LOAD_WINMM RGFW_FREE_LIBRARY(RGFW_winmm_dll); #endif #endif RGFW_FREE_LIBRARY(RGFW_wgl_dll); RGFW_freeMouse(_RGFW->hiddenMouse); RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, "global context deinitialized"); } void RGFW_window_closePlatform(RGFW_window * win) { RemovePropW(win->src.window, L"RGFW"); ReleaseDC(win->src.window, win->src.hdc); /* !< delete device * context */ DestroyWindow(win->src.window); /* !< delete window */ if (win->src.hIconSmall) DestroyIcon(win->src.hIconSmall); if (win->src.hIconBig) DestroyIcon(win->src.hIconBig); } void RGFW_window_move(RGFW_window * win, i32 x, i32 y) { RGFW_ASSERT(win != NULL); win->x = x; win->y = y; SetWindowPos(win->src.window, HWND_TOP, win->x, win->y, 0, 0, SWP_NOSIZE); } void RGFW_window_resize(RGFW_window * win, i32 w, i32 h) { RGFW_ASSERT(win != NULL); win->w = w; win->h = h; SetWindowPos(win->src.window, HWND_TOP, 0, 0, win->w + (i32) win->src.offsetW, win->h + (i32) win->src.offsetH, SWP_NOMOVE); } void RGFW_window_setName(RGFW_window * win, const char *name){ RGFW_ASSERT(win != NULL); wchar_t wide_name[256]; MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_name, 256); SetWindowTextW(win->src.window, wide_name); } #ifndef RGFW_NO_PASSTHROUGH void RGFW_window_setMousePassthrough(RGFW_window * win, RGFW_bool passthrough) { RGFW_ASSERT(win != NULL); COLORREF key = 0; BYTE alpha = 0; DWORD flags = 0; i32 exStyle = GetWindowLongW(win->src.window, GWL_EXSTYLE); if (exStyle & WS_EX_LAYERED) GetLayeredWindowAttributes(win->src.window, &key, &alpha, &flags); if (passthrough) exStyle |= (WS_EX_TRANSPARENT | WS_EX_LAYERED); else { exStyle &= ~WS_EX_TRANSPARENT; if (exStyle & WS_EX_LAYERED && !(flags & LWA_ALPHA)) exStyle &= ~WS_EX_LAYERED; } SetWindowLongW(win->src.window, GWL_EXSTYLE, exStyle); if (passthrough) SetLayeredWindowAttributes(win->src.window, key, alpha, flags); } #endif RGFW_bool RGFW_window_setIconEx(RGFW_window * win, u8 * data, i32 w, i32 h, RGFW_format format, RGFW_icon type) { RGFW_ASSERT(win != NULL); #ifndef RGFW_WIN95 if (win->src.hIconSmall && (type & RGFW_iconWindow)) DestroyIcon(win->src.hIconSmall); if (win->src.hIconBig && (type & RGFW_iconTaskbar)) DestroyIcon(win->src.hIconBig); if (data == NULL) { HICON defaultIcon = LoadIcon(NULL, IDI_APPLICATION); if (type & RGFW_iconWindow) SendMessage(win->src.window, WM_SETICON, (WPARAM) ICON_SMALL, (LPARAM) defaultIcon); if (type & RGFW_iconTaskbar) SendMessage(win->src.window, WM_SETICON, (WPARAM) ICON_BIG, (LPARAM) defaultIcon); return RGFW_TRUE; } if (type & RGFW_iconWindow) { win->src.hIconSmall = RGFW_loadHandleImage(data, w, h, format, TRUE); SendMessage(win->src.window, WM_SETICON, (WPARAM) ICON_SMALL, (LPARAM) win->src.hIconSmall); } if (type & RGFW_iconTaskbar) { win->src.hIconBig = RGFW_loadHandleImage(data, w, h, format, TRUE); SendMessage(win->src.window, WM_SETICON, (WPARAM) ICON_BIG, (LPARAM) win->src.hIconBig); } return RGFW_TRUE; #else RGFW_UNUSED(img); RGFW_UNUSED(type); return RGFW_FALSE; #endif } RGFW_ssize_t RGFW_readClipboardPtr(char *str, size_t strCapacity){ /* Open the clipboard */ if (OpenClipboard(NULL) == 0) return -1; /* Get the clipboard data as a Unicode string */ HANDLE hData = GetClipboardData(CF_UNICODETEXT); if (hData == NULL) { CloseClipboard(); return -1; } wchar_t *wstr = (wchar_t *) GlobalLock(hData); RGFW_ssize_t textLen = 0; { setlocale(LC_ALL, "en_US.UTF-8"); textLen = (RGFW_ssize_t) wcstombs(NULL, wstr, 0) + 1; if (str != NULL && (RGFW_ssize_t) strCapacity <= textLen - 1) textLen = 0; if (str != NULL && textLen) { if (textLen > 1) wcstombs(str, wstr, (size_t) (textLen)); str[textLen - 1] = '\0'; } } /* Release the clipboard data */ GlobalUnlock(hData); CloseClipboard(); return textLen; } void RGFW_writeClipboard(const char *text, u32 textLen){ HANDLE object; WCHAR *buffer; object = GlobalAlloc(GMEM_MOVEABLE, (1 + textLen) * sizeof(WCHAR)); if (!object) return; buffer = (WCHAR *) GlobalLock(object); if (!buffer) { GlobalFree(object); return; } MultiByteToWideChar(CP_UTF8, 0, text, -1, buffer, (i32) textLen); GlobalUnlock(object); if (!OpenClipboard(_RGFW->root->src.window)) { GlobalFree(object); return; } EmptyClipboard(); SetClipboardData(CF_UNICODETEXT, object); CloseClipboard(); } void RGFW_window_moveMouse(RGFW_window * win, i32 x, i32 y) { RGFW_ASSERT(win != NULL); win->internal.lastMouseX = x - win->x; win->internal.lastMouseX = y - win->y; SetCursorPos(x, y); } #ifdef RGFW_OPENGL RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char *extension, size_t len){ const char *extensions = NULL; RGFW_proc proc = RGFW_getProcAddress_OpenGL("wglGetExtensionsStringARB"); RGFW_proc proc2 = RGFW_getProcAddress_OpenGL("wglGetExtensionsStringEXT"); if (proc) extensions = ((const char *(*) (HDC))proc) (wglGetCurrentDC()); else if (proc2) extensions = ((const char *(*) (void))proc2) (); return extensions != NULL && RGFW_extensionSupportedStr(extensions, extension, len); } RGFW_proc RGFW_getProcAddress_OpenGL(const char *procname){ RGFW_proc proc = (RGFW_proc) wglGetProcAddress(procname); if (proc) return proc; return (RGFW_proc) GetProcAddress(RGFW_wgl_dll, procname); } void RGFW_win32_loadOpenGLFuncs(HWND dummyWin) { if (wglSwapIntervalEXT != NULL && wglChoosePixelFormatARB != NULL && wglChoosePixelFormatARB != NULL) return; HDC dummy_dc = GetDC(dummyWin); u32 pfd_flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; PIXELFORMATDESCRIPTOR pfd = {sizeof(pfd), 1, pfd_flags, PFD_TYPE_RGBA, 32, 8, PFD_MAIN_PLANE, 32, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 32, 8, 0, PFD_MAIN_PLANE, 0, 0, 0, 0}; int dummy_pixel_format = ChoosePixelFormat(dummy_dc, &pfd); SetPixelFormat(dummy_dc, dummy_pixel_format, &pfd); HGLRC dummy_context = wglCreateContext(dummy_dc); HGLRC cur = wglGetCurrentContext(); wglMakeCurrent(dummy_dc, dummy_context); wglCreateContextAttribsARB = ((PFNWGLCREATECONTEXTATTRIBSARBPROC(WINAPI *) (const char *)) wglGetProcAddress) ("wglCreateContextAttribsARB"); wglChoosePixelFormatARB = ((PFNWGLCHOOSEPIXELFORMATARBPROC(WINAPI *) (const char *)) wglGetProcAddress) ("wglChoosePixelFormatARB"); wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) (RGFW_proc) wglGetProcAddress("wglSwapIntervalEXT"); if (wglSwapIntervalEXT == NULL) { RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load swap interval function"); } wglMakeCurrent(dummy_dc, cur); wglDeleteContext(dummy_context); ReleaseDC(dummyWin, dummy_dc); } #define WGL_ACCELERATION_ARB 0x2003 #define WGL_FULL_ACCELERATION_ARB 0x2027 #define WGL_DRAW_TO_WINDOW_ARB 0x2001 #define WGL_PIXEL_TYPE_ARB 0x2013 #define WGL_TYPE_RGBA_ARB 0x202b #define WGL_SUPPORT_OPENGL_ARB 0x2010 #define WGL_COLOR_BITS_ARB 0x2014 #define WGL_DOUBLE_BUFFER_ARB 0x2011 #define WGL_ALPHA_BITS_ARB 0x201b #define WGL_DEPTH_BITS_ARB 0x2022 #define WGL_STENCIL_BITS_ARB 0x2023 #define WGL_STEREO_ARB 0x2012 #define WGL_AUX_BUFFERS_ARB 0x2024 #define WGL_RED_BITS_ARB 0x2015 #define WGL_GREEN_BITS_ARB 0x2017 #define WGL_BLUE_BITS_ARB 0x2019 #define WGL_ACCUM_RED_BITS_ARB 0x201e #define WGL_ACCUM_GREEN_BITS_ARB 0x201f #define WGL_ACCUM_BLUE_BITS_ARB 0x2020 #define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 #define WGL_COLORSPACE_SRGB_EXT 0x3089 #define WGL_CONTEXT_OPENGL_NO_ERROR_ARB 0x31b3 #define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 #define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0x0000 #define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 #define WGL_CONTEXT_FLAGS_ARB 0x2094 #define WGL_ACCESS_READ_WRITE_NV 0x00000001 #define WGL_COVERAGE_SAMPLES_NV 0x2042 #define WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004 #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 #define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 #define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9 #define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 #define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 #define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window * win, RGFW_glContext * ctx, RGFW_glHints * hints) { const char flushControl[] = "WGL_ARB_context_flush_control"; const char noError[] = "WGL_ARB_create_context_no_error"; const char robustness[] = "WGL_ARB_create_context_robustness"; win->src.ctx.native = ctx; win->src.gfxType = RGFW_gfxNativeOpenGL; PIXELFORMATDESCRIPTOR pfd; pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pfd.iPixelType = PFD_TYPE_RGBA; pfd.iLayerType = PFD_MAIN_PLANE; pfd.cColorBits = 32; pfd.cAlphaBits = 8; pfd.cDepthBits = 24; pfd.cStencilBits = (BYTE) hints->stencil; pfd.cAuxBuffers = (BYTE) hints->auxBuffers; if (hints->stereo) pfd.dwFlags |= PFD_STEREO; /* * try to create the pixel format we want for * OpenGL and then try to create an OpenGL * context for the specified version */ if (hints->renderer == RGFW_glSoftware) pfd.dwFlags |= PFD_GENERIC_FORMAT | PFD_GENERIC_ACCELERATED; /* * get pixel format, default to a basic pixel * format */ int pixel_format = ChoosePixelFormat(win->src.hdc, &pfd); if (wglChoosePixelFormatARB != NULL) { i32 pixel_format_attribs[50]; RGFW_attribStack stack; RGFW_attribStack_init(&stack, pixel_format_attribs, 50); RGFW_attribStack_pushAttribs(&stack, WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB); RGFW_attribStack_pushAttribs(&stack, WGL_DRAW_TO_WINDOW_ARB, 1); RGFW_attribStack_pushAttribs(&stack, WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB); RGFW_attribStack_pushAttribs(&stack, WGL_SUPPORT_OPENGL_ARB, 1); RGFW_attribStack_pushAttribs(&stack, WGL_COLOR_BITS_ARB, 32); RGFW_attribStack_pushAttribs(&stack, WGL_DOUBLE_BUFFER_ARB, 1); RGFW_attribStack_pushAttribs(&stack, WGL_ALPHA_BITS_ARB, hints->alpha); RGFW_attribStack_pushAttribs(&stack, WGL_DEPTH_BITS_ARB, hints->depth); RGFW_attribStack_pushAttribs(&stack, WGL_STENCIL_BITS_ARB, hints->stencil); RGFW_attribStack_pushAttribs(&stack, WGL_STEREO_ARB, hints->stereo); RGFW_attribStack_pushAttribs(&stack, WGL_AUX_BUFFERS_ARB, hints->auxBuffers); RGFW_attribStack_pushAttribs(&stack, WGL_RED_BITS_ARB, hints->red); RGFW_attribStack_pushAttribs(&stack, WGL_GREEN_BITS_ARB, hints->blue); RGFW_attribStack_pushAttribs(&stack, WGL_BLUE_BITS_ARB, hints->green); RGFW_attribStack_pushAttribs(&stack, WGL_ACCUM_RED_BITS_ARB, hints->accumRed); RGFW_attribStack_pushAttribs(&stack, WGL_ACCUM_GREEN_BITS_ARB, hints->accumGreen); RGFW_attribStack_pushAttribs(&stack, WGL_ACCUM_BLUE_BITS_ARB, hints->accumBlue); RGFW_attribStack_pushAttribs(&stack, WGL_ACCUM_ALPHA_BITS_ARB, hints->accumAlpha); if (hints->sRGB) { if (hints->profile != RGFW_glES) RGFW_attribStack_pushAttribs(&stack, WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, 1); else RGFW_attribStack_pushAttribs(&stack, WGL_COLORSPACE_SRGB_EXT, hints->sRGB); } RGFW_attribStack_pushAttribs(&stack, WGL_COVERAGE_SAMPLES_NV, hints->samples); RGFW_attribStack_pushAttribs(&stack, 0, 0); int new_pixel_format; UINT num_formats; wglChoosePixelFormatARB(win->src.hdc, pixel_format_attribs, 0, 1, &new_pixel_format, &num_formats); if (!num_formats) RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to create a pixel format for WGL"); else pixel_format = new_pixel_format; } PIXELFORMATDESCRIPTOR suggested; if (!DescribePixelFormat(win->src.hdc, pixel_format, sizeof(suggested), &suggested) || !SetPixelFormat(win->src.hdc, pixel_format, &pfd)) RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to set the WGL pixel format"); if (wglCreateContextAttribsARB != NULL) { /* * create OpenGL/WGL context for the * specified version */ i32 attribs[40]; RGFW_attribStack stack; RGFW_attribStack_init(&stack, attribs, 50); i32 mask = 0; switch (hints->profile) { case RGFW_glES:mask |= WGL_CONTEXT_ES_PROFILE_BIT_EXT; break; case RGFW_glCompatibility:mask |= WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; break; case RGFW_glCore:mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB; break; default:mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB; break; } RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_PROFILE_MASK_ARB, mask); if (hints->minor || hints->major) { RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_MAJOR_VERSION_ARB, hints->major); RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_MINOR_VERSION_ARB, hints->minor); } if (RGFW_extensionSupportedPlatform_OpenGL(noError, sizeof(noError))) RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_OPENGL_NO_ERROR_ARB, hints->noError); if (RGFW_extensionSupportedPlatform_OpenGL(flushControl, sizeof(flushControl))) { if (hints->releaseBehavior == RGFW_glReleaseFlush) { RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); //WGL_CONTEXT_RELEASE_BEHAVIOR_ARB } else if (hints->releaseBehavior == RGFW_glReleaseNone) { RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); } } i32 flags = 0; if (hints->debug) flags |= WGL_CONTEXT_DEBUG_BIT_ARB; if (hints->robustness && RGFW_extensionSupportedPlatform_OpenGL(robustness, sizeof(robustness))) flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB; if (flags) { RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_FLAGS_ARB, flags); } RGFW_attribStack_pushAttribs(&stack, 0, 0); win->src.ctx.native->ctx = (HGLRC) wglCreateContextAttribsARB(win->src.hdc, NULL, attribs); } if (wglCreateContextAttribsARB == NULL || win->src.ctx.native->ctx == NULL) { /* fall back to a * default context * (probably OpenGL 2 or * something) */ RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to create an accelerated OpenGL Context."); win->src.ctx.native->ctx = wglCreateContext(win->src.hdc); } ReleaseDC(win->src.window, win->src.hdc); win->src.hdc = GetDC(win->src.window); if (hints->share) { wglShareLists((HGLRC) RGFW_getCurrentContext_OpenGL(), hints->share->ctx); } wglMakeCurrent(win->src.hdc, win->src.ctx.native->ctx); RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized."); return RGFW_TRUE; } void RGFW_window_deleteContextPtr_OpenGL(RGFW_window * win, RGFW_glContext * ctx) { wglDeleteContext((HGLRC) ctx->ctx); /* !< delete OpenGL * context */ win->src.ctx.native->ctx = NULL; RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context freed."); } void RGFW_window_makeCurrentContext_OpenGL(RGFW_window * win) { if (win == NULL) wglMakeCurrent(NULL, NULL); else wglMakeCurrent(win->src.hdc, (HGLRC) win->src.ctx.native->ctx); } void *RGFW_getCurrentContext_OpenGL(void){ return wglGetCurrentContext(); } void RGFW_window_swapBuffers_OpenGL(RGFW_window * win) { RGFW_ASSERT(win->src.ctx.native); SwapBuffers(win->src.hdc); } void RGFW_window_swapInterval_OpenGL(RGFW_window * win, i32 swapInterval) { RGFW_ASSERT(win != NULL); if (wglSwapIntervalEXT == NULL || wglSwapIntervalEXT(swapInterval) == FALSE) RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to set swap interval"); } #endif RGFW_bool RGFW_createUTF8FromWideStringWin32(const WCHAR * source, char *output, size_t max){ i32 size = 0; if (source == NULL) { return RGFW_FALSE; } size = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL); if (!size) { return RGFW_FALSE; } if (size > (i32) max) size = (i32) max; if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, output, size, NULL, NULL)) { return RGFW_FALSE; } output[size] = 0; return RGFW_TRUE; } #ifdef RGFW_WEBGPU WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window * window, WGPUInstance instance) { WGPUSurfaceDescriptor surfaceDesc = {0}; WGPUSurfaceSourceWindowsHWND fromHwnd = {0}; fromHwnd.chain.sType = WGPUSType_SurfaceSourceWindowsHWND; fromHwnd.hwnd = window->src.window; //Get HWND from RGFW window source if (!fromHwnd.hwnd) { fprintf(stderr, "RGFW Error: HWND is NULL for Windows window.\n"); return NULL; } fromHwnd.hinstance = GetModuleHandle(NULL); //Get current process HINSTANCE surfaceDesc.nextInChain = (WGPUChainedStruct *) & fromHwnd.chain; return wgpuInstanceCreateSurface(instance, &surfaceDesc); } #endif #endif /* RGFW_WINDOWS */ /* * End of Windows defines */ /* * * Start of MacOS defines * * */ #if defined(RGFW_MACOS) /* * based on silicon.h start of cocoa wrapper */ #include #include #include #include #include #include #ifndef __OBJC__ typedef CGRect NSRect; typedef CGPoint NSPoint; typedef CGSize NSSize; typedef const char *NSPasteboardType; typedef unsigned long NSUInteger; typedef long NSInteger; typedef NSInteger NSModalResponse; typedef enum NSApplicationActivationPolicy { NSApplicationActivationPolicyRegular, NSApplicationActivationPolicyAccessory, NSApplicationActivationPolicyProhibited } NSApplicationActivationPolicy; typedef RGFW_ENUM(u32, NSBackingStoreType) { NSBackingStoreRetained = 0, NSBackingStoreNonretained = 1, NSBackingStoreBuffered = 2 }; typedef RGFW_ENUM(u32, NSWindowStyleMask) { NSWindowStyleMaskBorderless = 0, NSWindowStyleMaskTitled = 1 << 0, NSWindowStyleMaskClosable = 1 << 1, NSWindowStyleMaskMiniaturizable = 1 << 2, NSWindowStyleMaskResizable = 1 << 3, NSWindowStyleMaskTexturedBackground = 1 << 8, /* deprecated */ NSWindowStyleMaskUnifiedTitleAndToolbar = 1 << 12, NSWindowStyleMaskFullScreen = 1 << 14, NSWindowStyleMaskFullSizeContentView = 1 << 15, NSWindowStyleMaskUtilityWindow = 1 << 4, NSWindowStyleMaskDocModalWindow = 1 << 6, NSWindowStyleMaskNonactivatingpanel = 1 << 7, NSWindowStyleMaskHUDWindow = 1 << 13 }; #define NSPasteboardTypeString "public.utf8-plain-text" typedef RGFW_ENUM(i32, NSDragOperation) { NSDragOperationNone = 0, NSDragOperationCopy = 1, NSDragOperationLink = 2, NSDragOperationGeneric = 4, NSDragOperationPrivate = 8, NSDragOperationMove = 16, NSDragOperationDelete = 32, NSDragOperationEvery = (int)ULONG_MAX }; typedef RGFW_ENUM(NSInteger, NSOpenGLContextParameter) { NSOpenGLContextParameterSwapInterval = 222, /* 1 param. 0 -> Don't * sync, 1 -> Sync to * vertical retrace */ NSOpenGLContextParametectxaceOrder = 235, /* 1 param. 1 -> Above * Window (default), -1 * -> Below Window */ NSOpenGLContextParametectxaceOpacity = 236, /* 1 param. 1-> Surface * is opaque (default), * 0 -> non-opaque */ NSOpenGLContextParametectxaceBackingSize = 304, /* 2 params. * Width/height of * surface backing size */ NSOpenGLContextParameterReclaimResources = 308, /* 0 params. */ NSOpenGLContextParameterCurrentRendererID = 309, /* 1 param. Retrieves * the current renderer * ID */ NSOpenGLContextParameterGPUVertexProcessing = 310, /* 1 param. Currently * processing vertices * with GPU (get) */ NSOpenGLContextParameterGPUFragmentProcessing = 311, /* 1 param. Currently * processing fragments * with GPU (get) */ NSOpenGLContextParameterHasDrawable = 314, /* 1 param. Boolean * returned if drawable * is attached */ NSOpenGLContextParameterMPSwapsInFlight = 315, /* 1 param. Max number * of swaps queued by * the MP GL engine */ NSOpenGLContextParameterSwapRectangle API_DEPRECATED("", macos(10.0, 10.14)) = 200, /* 4 params. Set or get * the swap rectangle * {x, y, w, h} */ NSOpenGLContextParameterSwapRectangleEnable API_DEPRECATED("", macos(10.0, 10.14)) = 201, /* Enable or disable the * swap rectangle */ NSOpenGLContextParameterRasterizationEnable API_DEPRECATED("", macos(10.0, 10.14)) = 221, /* Enable or disable all * rasterization */ NSOpenGLContextParameterStateValidation API_DEPRECATED("", macos(10.0, 10.14)) = 301, /* Validate state for * multi-screen * functionality */ NSOpenGLContextParametectxaceSurfaceVolatile API_DEPRECATED("", macos(10.0, 10.14)) = 306, /* 1 param. Surface * volatile state */ }; typedef RGFW_ENUM(NSInteger, NSWindowButton) { NSWindowCloseButton = 0, NSWindowMiniaturizeButton = 1, NSWindowZoomButton = 2, NSWindowToolbarButton = 3, NSWindowDocumentIconButton = 4, NSWindowDocumentVersionsButton = 6, NSWindowFullScreenButton = 7, }; #define NSPasteboardTypeURL "public.url" #define NSPasteboardTypeFileURL "public.file-url" #define NSTrackingMouseEnteredAndExited 0x01 #define NSTrackingMouseMoved 0x02 #define NSTrackingCursorUpdate 0x04 #define NSTrackingActiveWhenFirstResponder 0x10 #define NSTrackingActiveInKeyWindow 0x20 #define NSTrackingActiveInActiveApp 0x40 #define NSTrackingActiveAlways 0x80 #define NSTrackingAssumeInside 0x100 #define NSTrackingInVisibleRect 0x200 #define NSTrackingEnabledDuringMouseDrag 0x400 enum { NSOpenGLPFAAllRenderers = 1, /* choose from all * available renderers */ NSOpenGLPFATripleBuffer = 3, /* choose a triple * buffered pixel format */ NSOpenGLPFADoubleBuffer = 5, /* choose a double * buffered pixel format */ NSOpenGLPFAAuxBuffers = 7, /* number of aux buffers */ NSOpenGLPFAColorSize = 8, /* number of color * buffer bits */ NSOpenGLPFAAlphaSize = 11, /* number of alpha * component bits */ NSOpenGLPFADepthSize = 12, /* number of depth * buffer bits */ NSOpenGLPFAStencilSize = 13, /* number of stencil * buffer bits */ NSOpenGLPFAAccumSize = 14, /* number of accum * buffer bits */ NSOpenGLPFAMinimumPolicy = 51, /* never choose smaller * buffers than * requested */ NSOpenGLPFAMaximumPolicy = 52, /* choose largest * buffers of type * requested */ NSOpenGLPFASampleBuffers = 55, /* number of multi * sample buffers */ NSOpenGLPFASamples = 56, /* number of samples per * multi sample buffer */ NSOpenGLPFAAuxDepthStencil = 57, /* each aux buffer has * its own depth stencil */ NSOpenGLPFAColorFloat = 58, /* color buffers store * floating point pixels */ NSOpenGLPFAMultisample = 59, /* choose multisampling */ NSOpenGLPFASupersample = 60, /* choose supersampling */ NSOpenGLPFASampleAlpha = 61, /* request alpha * filtering */ NSOpenGLPFARendererID = 70, /* request renderer by * ID */ NSOpenGLPFANoRecovery = 72, /* disable all failure * recovery systems */ NSOpenGLPFAAccelerated = 73, /* choose a hardware * accelerated renderer */ NSOpenGLPFAClosestPolicy = 74, /* choose the closest * color buffer to * request */ NSOpenGLPFABackingStore = 76, /* back buffer contents * are valid after swap */ NSOpenGLPFAScreenMask = 84, /* bit mask of supported * physical screens */ NSOpenGLPFAAllowOfflineRenderers = 96, /* allow use of offline * renderers */ NSOpenGLPFAAcceleratedCompute = 97, /* choose a hardware * accelerated compute * device */ NSOpenGLPFAOpenGLProfile = 99, /* specify an OpenGL * Profile to use */ NSOpenGLProfileVersionLegacy = 0x1000, /* The requested profile * is a legacy * (pre-OpenGL 3.0) * profile. */ NSOpenGLProfileVersion3_2Core = 0x3200, /* The 3.2 Profile of * OpenGL */ NSOpenGLProfileVersion4_1Core = 0x3200, /* The 4.1 profile of * OpenGL */ NSOpenGLPFAVirtualScreenCount = 128, /* number of virtual * screens in this * format */ NSOpenGLPFAStereo = 6, NSOpenGLPFAOffScreen = 53, NSOpenGLPFAFullScreen = 54, NSOpenGLPFASingleRenderer = 71, NSOpenGLPFARobust = 75, NSOpenGLPFAMPSafe = 78, NSOpenGLPFAWindow = 80, NSOpenGLPFAMultiScreen = 81, NSOpenGLPFACompliant = 83, NSOpenGLPFAPixelBuffer = 90, NSOpenGLPFARemotePixelBuffer = 91, }; typedef RGFW_ENUM(u32, NSEventType) { /* various types of * events */ NSEventTypeApplicationDefined = 15, }; typedef unsigned long long NSEventMask; typedef enum NSEventModifierFlags { NSEventModifierFlagCapsLock = 1 << 16, NSEventModifierFlagShift = 1 << 17, NSEventModifierFlagControl = 1 << 18, NSEventModifierFlagOption = 1 << 19, NSEventModifierFlagCommand = 1 << 20, NSEventModifierFlagNumericPad = 1 << 21 } NSEventModifierFlags; typedef RGFW_ENUM(NSUInteger, NSBitmapFormat) { NSBitmapFormatAlphaFirst = 1 << 0, /* 0 means is alpha last * (RGBA, CMYKA, etc.) */ NSBitmapFormatAlphaNonpremultiplied = 1 << 1, /* 0 means is * premultiplied */ NSBitmapFormatFloatingpointSamples = 1 << 2, /* 0 is integer */ NSBitmapFormatSixteenBitLittleEndian = (1 << 8), NSBitmapFormatThirtyTwoBitLittleEndian = (1 << 9), NSBitmapFormatSixteenBitBigEndian = (1 << 10), NSBitmapFormatThirtyTwoBitBigEndian = (1 << 11) }; #else #import #include #endif /* notdef __OBJC__ */ #ifdef __arm64__ /* ARM just uses objc_msgSend */ #define abi_objc_msgSend_stret objc_msgSend #define abi_objc_msgSend_fpret objc_msgSend #else /* __i386__ */ /* * x86 just uses abi_objc_msgSend_fpret and (NSColor * *)objc_msgSend_id respectively */ #define abi_objc_msgSend_stret objc_msgSend_stret #define abi_objc_msgSend_fpret objc_msgSend_fpret #endif #define NSAlloc(nsclass) objc_msgSend_id((id)nsclass, sel_registerName("alloc")) #define objc_msgSend_bool(x, y) ((BOOL (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) #define objc_msgSend_void(x, y) ((void (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) #define objc_msgSend_void_id(x, y, z) ((void (*)(id, SEL, id))objc_msgSend) ((id)x, (SEL)y, (id)z) #define objc_msgSend_uint(x, y) ((NSUInteger (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) #define objc_msgSend_void_bool(x, y, z) ((void (*)(id, SEL, BOOL))objc_msgSend) ((id)(x), (SEL)y, (BOOL)z) #define objc_msgSend_bool_void(x, y) ((BOOL (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) #define objc_msgSend_void_SEL(x, y, z) ((void (*)(id, SEL, SEL))objc_msgSend) ((id)(x), (SEL)y, (SEL)z) #define objc_msgSend_id(x, y) ((id (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) #define objc_msgSend_id_id(x, y, z) ((id (*)(id, SEL, id))objc_msgSend) ((id)(x), (SEL)y, (id)z) #define objc_msgSend_id_bool(x, y, z) ((BOOL (*)(id, SEL, id))objc_msgSend) ((id)(x), (SEL)y, (id)z) #define objc_msgSend_int(x, y, z) ((id (*)(id, SEL, int))objc_msgSend) ((id)(x), (SEL)y, (int)z) #define objc_msgSend_arr(x, y, z) ((id (*)(id, SEL, int))objc_msgSend) ((id)(x), (SEL)y, (int)z) #define objc_msgSend_ptr(x, y, z) ((id (*)(id, SEL, void*))objc_msgSend) ((id)(x), (SEL)y, (void*)z) #define objc_msgSend_class(x, y) ((id (*)(Class, SEL))objc_msgSend) ((Class)(x), (SEL)y) #define objc_msgSend_class_char(x, y, z) ((id (*)(Class, SEL, char*))objc_msgSend) ((Class)(x), (SEL)y, (char*)z) #define NSRelease(obj) objc_msgSend_void((id)obj, sel_registerName("release")) RGFWDEF id NSString_stringWithUTF8String(const char *str); id NSString_stringWithUTF8String(const char *str){ return ((id(*) (id, SEL, const char *)) objc_msgSend) ((id) objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), str); } const char *NSString_to_char(id str); const char *NSString_to_char(id str) { return ((const char *(*) (id, SEL))objc_msgSend) ((id) (id) str, sel_registerName("UTF8String")); } unsigned char *NSBitmapImageRep_bitmapData(id imageRep); unsigned char *NSBitmapImageRep_bitmapData(id imageRep) { return ((unsigned char *(*) (id, SEL))objc_msgSend) ((id) imageRep, sel_registerName("bitmapData")); } id 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); id 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){ SEL func = sel_registerName("initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bitmapFormat:bytesPerRow:bitsPerPixel:"); return (id) ((id(*) (id, SEL, unsigned char **, NSInteger, NSInteger, NSInteger, NSInteger, bool, bool, id, NSBitmapFormat, NSInteger, NSInteger)) objc_msgSend) (NSAlloc((id) objc_getClass("NSBitmapImageRep")), func, planes, width, height, bps, spp, alpha, isPlanar, NSString_stringWithUTF8String(colorSpaceName), bitmapFormat, rowBytes, pixelBits); } id NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha); id NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha) { Class nsclass = objc_getClass("NSColor"); SEL func = sel_registerName("colorWithSRGBRed:green:blue:alpha:"); return ((id(*) (id, SEL, CGFloat, CGFloat, CGFloat, CGFloat)) objc_msgSend) ((id) nsclass, func, red, green, blue, alpha); } id NSPasteboard_generalPasteboard(void); id NSPasteboard_generalPasteboard(void){ return (id) objc_msgSend_id((id) objc_getClass("NSPasteboard"), sel_registerName("generalPasteboard")); } id *cstrToNSStringArray(char **strs, size_t len); id *cstrToNSStringArray(char **strs, size_t len){ static id nstrs[6]; size_t i; for (i = 0; i < len; i++) nstrs[i] = NSString_stringWithUTF8String(strs[i]); return nstrs; } const char *NSPasteboard_stringForType(id pasteboard, NSPasteboardType dataType, size_t * len); const char *NSPasteboard_stringForType(id pasteboard, NSPasteboardType dataType, size_t * len) { SEL func = sel_registerName("stringForType:"); id nsstr = NSString_stringWithUTF8String((const char *)dataType); id nsString = ((id(*) (id, SEL, id)) objc_msgSend) (pasteboard, func, nsstr); const char *str = NSString_to_char(nsString); if (len != NULL) *len = (size_t) ((NSUInteger(*) (id, SEL, int)) objc_msgSend) (nsString, sel_registerName("maximumLengthOfBytesUsingEncoding:"), 4); return str; } id c_array_to_NSArray(void *array, size_t len); id c_array_to_NSArray(void *array, size_t len){ return ((id(*) (id, SEL, void *, NSUInteger)) objc_msgSend) (NSAlloc(objc_getClass("NSArray")), sel_registerName("initWithObjects:count:"), array, len); } void NSregisterForDraggedTypes(id view, NSPasteboardType * newTypes, size_t len); void NSregisterForDraggedTypes(id view, NSPasteboardType * newTypes, size_t len) { id *ntypes = cstrToNSStringArray((char **)newTypes, len); id array = c_array_to_NSArray(ntypes, len); objc_msgSend_void_id(view, sel_registerName("registerForDraggedTypes:"), array); NSRelease(array); } NSInteger NSPasteBoard_declareTypes(id pasteboard, NSPasteboardType * newTypes, size_t len, void *owner); NSInteger NSPasteBoard_declareTypes(id pasteboard, NSPasteboardType * newTypes, size_t len, void *owner){ id *ntypes = cstrToNSStringArray((char **)newTypes, len); SEL func = sel_registerName("declareTypes:owner:"); id array = c_array_to_NSArray(ntypes, len); NSInteger output = ((NSInteger(*) (id, SEL, id, void *)) objc_msgSend) (pasteboard, func, array, owner); NSRelease(array); return output; } #define NSRetain(obj) objc_msgSend_void((id)obj, sel_registerName("retain")) void *NSArray_objectAtIndex(id array, NSUInteger index) { SEL func = sel_registerName("objectAtIndex:"); return ((id(*) (id, SEL, NSUInteger)) objc_msgSend) (array, func, index); } id NSWindow_contentView(id window) { SEL func = sel_registerName("contentView"); return objc_msgSend_id(window, func); } /* * End of cocoa wrapper */ id NSWindow_delegate(RGFW_window * win) { return (id) objc_msgSend_id((id) win->src.window, sel_registerName("delegate")); } id RGFW__osxCustomInitWithRGFWWindow(id self, SEL _cmd, RGFW_window * win) { RGFW_UNUSED(_cmd); struct objc_super s = {self, class_getSuperclass(object_getClass(self))}; self = ((id(*) (struct objc_super *, SEL)) objc_msgSendSuper) (&s, sel_registerName("init")); if (self != nil) { object_setInstanceVariable(self, "RGFW_window", win); object_setInstanceVariable(self, "trackingArea", nil); object_setInstanceVariable( self, "markedText", ((id(*) (id, SEL)) objc_msgSend) ( ((id(*) (Class, SEL)) objc_msgSend) (objc_getClass("NSMutableAttributedString"), sel_registerName("alloc")), sel_registerName("init") ) ); ((void (*) (id, SEL))objc_msgSend) (self, sel_registerName("updateTrackingAreas")); ((void (*) (id, SEL, id))objc_msgSend) ( self, sel_registerName("registerForDraggedTypes:"), ((id(*) (Class, SEL, id)) objc_msgSend) ( objc_getClass("NSArray"), sel_registerName("arrayWithObject:"), ((id(*) (Class, SEL, const char *)) objc_msgSend) ( objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "public.url" ) ) ); } return self; } u32 RGFW_OnClose(id self) { RGFW_window *win = NULL; object_getInstanceVariable(self, (const char *)"RGFW_window", (void **)&win); if (win == NULL) return true; RGFW_window_setShouldClose(win, RGFW_TRUE); RGFW_eventQueuePushEx(e.type = RGFW_quit; e.common.win = win); RGFW_windowQuitCallback(win); return false; } /* * NOTE(EimaMei): Fixes the constant clicking when the * app is running under a terminal. */ bool acceptsFirstResponder(void){ return true; } bool performKeyEquivalent(id event) { RGFW_UNUSED(event); return true; } NSDragOperation draggingEntered(id self, SEL sel, id sender) { RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel); return NSDragOperationCopy; } NSDragOperation draggingUpdated(id self, SEL sel, id sender) { RGFW_UNUSED(sel); RGFW_window *win = NULL; object_getInstanceVariable(self, "RGFW_window", (void **)&win); if (win == NULL || (!(win->internal.flags & RGFW_windowAllowDND))) return 0; if (!(win->internal.enabledEvents & RGFW_dataDragFlag)) return NSDragOperationCopy; NSPoint p = ((NSPoint(*) (id, SEL)) objc_msgSend) (sender, sel_registerName("draggingLocation")); RGFW_eventQueuePushEx(e.type = RGFW_dataDrag; e.mouse.x = (i32) p.x; e.mouse.y = (i32) (win->h - p.y); e.common.win = win); _RGFW->windowState.win = win; _RGFW->windowState.dataDragging = RGFW_TRUE; _RGFW->windowState.dropX = (i32) p.x; _RGFW->windowState.dropY = (i32) (win->h - p.y); RGFW_dataDragCallback(win, (i32) p.x, (i32) (win->h - p.y)); return NSDragOperationCopy; } bool prepareForDragOperation(id self) { RGFW_window *win = NULL; object_getInstanceVariable(self, "RGFW_window", (void **)&win); if (win == NULL || (!(win->internal.enabledEvents & RGFW_dataDropFlag))) return true; if (!(win->internal.flags & RGFW_windowAllowDND)) { return false; } return true; } void RGFW__osxDraggingEnded(id self, SEL sel, id sender); void RGFW__osxDraggingEnded(id self, SEL sel, id sender) { RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel); return; } bool performDragOperation(id self, SEL sel, id sender) { RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel); RGFW_window *win = NULL; object_getInstanceVariable(self, "RGFW_window", (void **)&win); if (win == NULL || (!(win->internal.enabledEvents & RGFW_dataDropFlag))) return false; /* * id pasteBoard = objc_msgSend_id(sender, * sel_registerName("draggingPasteboard")); */ id pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard")); /* * Get the types of data available on the * pasteboard */ id types = objc_msgSend_id(pasteBoard, sel_registerName("types")); /* Get the string type for file URLs */ id fileURLsType = objc_msgSend_class_char(objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "NSFilenamesPboardType"); /* Check if the pasteboard contains file URLs */ if (objc_msgSend_id_bool(types, sel_registerName("containsObject:"), fileURLsType) == 0) { RGFW_sendDebugInfo(RGFW_typeError, RGFW_errClipboard, "No files found on the pasteboard."); return 0; } id fileURLs = objc_msgSend_id_id(pasteBoard, sel_registerName("propertyListForType:"), fileURLsType); int count = ((int (*) (id, SEL))objc_msgSend) (fileURLs, sel_registerName("count")); if (count == 0) return 0; RGFW_event event; event.drop.files = (char **)(void *)_RGFW->files; u32 i; for (i = 0; i < (u32) count; i++) { id fileURL = objc_msgSend_arr(fileURLs, sel_registerName("objectAtIndex:"), i); const char *filePath = ((const char *(*) (id, SEL))objc_msgSend) (fileURL, sel_registerName("UTF8String")); RGFW_STRNCPY(event.drop.files[i], filePath, RGFW_MAX_PATH - 1); event.drop.files[i][RGFW_MAX_PATH - 1] = '\0'; } event.drop.count = (size_t) count; RGFW_eventQueuePushEx(e.type = RGFW_dataDrop; e.drop.count = (size_t) count; e.drop.files = event.drop.files; e.common.win = win); _RGFW->windowState.win = win; _RGFW->windowState.dataDrop = RGFW_TRUE; _RGFW->windowState.filesCount = event.drop.count; RGFW_dataDropCallback(win, event.drop.files, event.drop.count); return false; } #ifndef RGFW_NO_IOKIT #include u32 RGFW_osx_getFallbackRefreshRate(CGDirectDisplayID displayID) { u32 refreshRate = 0; io_iterator_t it; io_service_t service; CFNumberRef indexRef, clockRef, countRef; u32 clock, count; #ifdef kIOMainPortDefault if (IOServiceGetMatchingServices(kIOMainPortDefault, IOServiceMatching("IOFramebuffer"), &it) != 0) #elif defined(kIOMasterPortDefault) if (IOServiceGetMatchingServices(kIOMainPortDefault, IOServiceMatching("IOFramebuffer"), &it) != 0) #endif return RGFW_FALSE; while ((service = IOIteratorNext(it)) != 0) { u32 index; indexRef = (CFNumberRef) IORegistryEntryCreateCFProperty(service, CFSTR("IOFramebufferOpenGLIndex"), kCFAllocatorDefault, kNilOptions); if (indexRef == 0) continue; if (CFNumberGetValue(indexRef, kCFNumberIntType, &index) && CGOpenGLDisplayMaskToDisplayID(1 << index) == displayID) { CFRelease(indexRef); break; } CFRelease(indexRef); } if (service) { clockRef = (CFNumberRef) IORegistryEntryCreateCFProperty(service, CFSTR("IOFBCurrentPixelClock"), kCFAllocatorDefault, kNilOptions); if (clockRef) { if (CFNumberGetValue(clockRef, kCFNumberIntType, &clock) && clock) { countRef = (CFNumberRef) IORegistryEntryCreateCFProperty(service, CFSTR("IOFBCurrentPixelCount"), kCFAllocatorDefault, kNilOptions); if (countRef && CFNumberGetValue(countRef, kCFNumberIntType, &count) && count) { float rate = (float)((double)clock / (double)count); refreshRate = (u32) RGFW_ROUND(rate); CFRelease(countRef); } } CFRelease(clockRef); } } IOObjectRelease(it); return refreshRate; } #endif void RGFW_moveToMacOSResourceDir(void){ char resourcesPath[256]; CFBundleRef bundle = CFBundleGetMainBundle(); if (!bundle) return; CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle); CFStringRef last = CFURLCopyLastPathComponent(resourcesURL); if ( CFStringCompare(CFSTR("Resources"), last, 0) != kCFCompareEqualTo || CFURLGetFileSystemRepresentation(resourcesURL, true, (u8 *) resourcesPath, 255) == 0 ) { CFRelease(last); CFRelease(resourcesURL); return; } CFRelease(last); CFRelease(resourcesURL); chdir(resourcesPath); } static void RGFW__osxWindowDeminiaturize(id self, SEL sel) { RGFW_UNUSED(sel); RGFW_window *win = NULL; object_getInstanceVariable(self, "RGFW_window", (void **)&win); if (win == NULL) return; win->internal.flags |= RGFW_windowMinimize; if (!(win->internal.enabledEvents & RGFW_windowMinimizedFlag)) return; RGFW_eventQueuePushEx(e.type = RGFW_windowRestored; e.common.win = win); RGFW_windowRestoredCallback(win, win->x, win->y, win->w, win->h); } static void RGFW__osxWindowMiniaturize(id self, SEL sel) { RGFW_UNUSED(sel); RGFW_window *win = NULL; object_getInstanceVariable(self, "RGFW_window", (void **)&win); if (win == NULL) return; win->internal.flags &= ~(u32) RGFW_windowMinimize; if (!(win->internal.enabledEvents & RGFW_windowMinimizedFlag)) return; RGFW_eventQueuePushEx(e.type = RGFW_windowMinimized; e.common.win = win); RGFW_windowMinimizedCallback(win); } static void RGFW__osxWindowBecameKey(id self, SEL sel) { RGFW_UNUSED(sel); RGFW_window *win = NULL; object_getInstanceVariable(self, "RGFW_window", (void **)&win); if (win == NULL) return; win->internal.inFocus = RGFW_TRUE; if ((win->internal.holdMouse)) RGFW_window_holdMouse(win); if (!(win->internal.enabledEvents & RGFW_focusInFlag)) return; RGFW_eventQueuePushEx(e.type = RGFW_focusIn; e.common.win = win); RGFW_focusCallback(win, RGFW_TRUE); } static void RGFW__osxWindowResignKey(id self, SEL sel) { RGFW_UNUSED(sel); RGFW_window *win = NULL; object_getInstanceVariable(self, "RGFW_window", (void **)&win); if (win == NULL) return; RGFW_window_focusLost(win); if (!(win->internal.enabledEvents & RGFW_focusOutFlag)) return; RGFW_eventQueuePushEx(e.type = RGFW_focusOut; e.common.win = win); RGFW_focusCallback(win, RGFW_FALSE); } static void RGFW__osxDidWindowResize(id self, SEL _cmd, id notification) { RGFW_UNUSED(_cmd); RGFW_UNUSED(notification); RGFW_window *win = NULL; object_getInstanceVariable(self, "RGFW_window", (void **)&win); if (win == NULL) return; NSRect frame; if (win->src.view) frame = ((NSRect(*) (id, SEL)) abi_objc_msgSend_stret) ((id) win->src.view, sel_registerName("frame")); else return; if (frame.size.width == 0 || frame.size.height == 0) return; win->w = (i32) frame.size.width; win->h = (i32) frame.size.height; RGFW_monitor mon = RGFW_window_getMonitor(win); if ((i32) mon.mode.w == win->w && (i32) mon.mode.h - 102 <= win->h) { win->internal.flags |= RGFW_windowMaximize; if (!(win->internal.enabledEvents & RGFW_windowMaximizedFlag)) return; RGFW_eventQueuePushEx(e.type = RGFW_windowMaximized; e.common.win = win); RGFW_windowMaximizedCallback(win, 0, 0, win->w, win->h); } else if (win->internal.flags & RGFW_windowMaximize) { win->internal.flags &= ~(u32) RGFW_windowMaximize; if (!(win->internal.enabledEvents & RGFW_windowRestoredFlag)) return; RGFW_eventQueuePushEx(e.type = RGFW_windowRestored; e.common.win = win); RGFW_windowRestoredCallback(win, win->x, win->y, win->w, win->h); } if (!(win->internal.enabledEvents & RGFW_windowResizedFlag)) return; RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e.common.win = win); RGFW_windowResizedCallback(win, win->w, win->h); } static void RGFW__osxWindowMove(id self, SEL sel) { RGFW_UNUSED(sel); RGFW_window *win = NULL; object_getInstanceVariable(self, "RGFW_window", (void **)&win); if (win == NULL) return; NSRect frame = ((NSRect(*) (id, SEL)) abi_objc_msgSend_stret) ((id) win->src.window, sel_registerName("frame")); win->x = (i32) frame.origin.x; win->y = (i32) frame.origin.y; if (!(win->internal.enabledEvents & RGFW_windowMovedFlag)) return; RGFW_eventQueuePushEx(e.type = RGFW_windowMoved; e.common.win = win); RGFW_windowMovedCallback(win, win->x, win->y); } static void RGFW__osxViewDidChangeBackingProperties(id self, SEL _cmd) { RGFW_UNUSED(_cmd); RGFW_window *win = NULL; object_getInstanceVariable(self, "RGFW_window", (void **)&win); if (win == NULL || !(win->internal.enabledEvents & RGFW_scaleUpdatedFlag)) return; RGFW_monitor mon = RGFW_window_getMonitor(win); RGFW_scaleUpdatedCallback(win, mon.scaleX, mon.scaleY); RGFW_eventQueuePushEx(e.type = RGFW_scaleUpdated; e.scale.x = mon.scaleX; e.scale.y = mon.scaleY; e.common.win = win); } static BOOL RGFW__osxWantsUpdateLayer(id self, SEL _cmd) { RGFW_UNUSED(self); RGFW_UNUSED(_cmd); return YES; } static void RGFW__osxUpdateLayer(id self, SEL _cmd) { RGFW_UNUSED(self); RGFW_UNUSED(_cmd); RGFW_window *win = NULL; object_getInstanceVariable(self, "RGFW_window", (void **)&win); if (win == NULL || !(win->internal.enabledEvents & RGFW_windowRefreshFlag)) return; RGFW_windowRefreshCallback(win); } static void RGFW__osxDrawRect(id self, SEL _cmd, CGRect rect) { RGFW_UNUSED(rect); RGFW_UNUSED(_cmd); RGFW_window *win = NULL; object_getInstanceVariable(self, "RGFW_window", (void **)&win); if (win == NULL || !(win->internal.enabledEvents & RGFW_scaleUpdatedFlag)) return; RGFW_eventQueuePushEx(e.type = RGFW_windowRefresh; e.common.win = win); RGFW_windowRefreshCallback(win); } static void RGFW__osxMouseEntered(id self, SEL _cmd, id event) { RGFW_UNUSED(_cmd); RGFW_window *win = NULL; object_getInstanceVariable(self, "RGFW_window", (void **)&win); if (win == NULL || !(win->internal.enabledEvents & RGFW_mouseEnterFlag)) return; win->internal.mouseInside = RGFW_TRUE; _RGFW->windowState.win = win; _RGFW->windowState.mouseEnter = RGFW_TRUE; RGFW_event e; e.type = RGFW_mouseEnter; NSPoint p = ((NSPoint(*) (id, SEL)) objc_msgSend) (event, sel_registerName("locationInWindow")); e.mouse.x = (i32) p.x; e.mouse.y = (i32) (win->h - p.y); e.common.win = win; RGFW_eventQueuePush(&e); RGFW_mouseNotifyCallback(win, e.mouse.x, e.mouse.y, 1); } void RGFW__osxMouseExited(id self, SEL _cmd, id event) { RGFW_UNUSED(_cmd); RGFW_UNUSED(event); RGFW_window *win = NULL; object_getInstanceVariable(self, "RGFW_window", (void **)&win); if (win == NULL || !(win->internal.enabledEvents & RGFW_mouseLeaveFlag)) return; win->internal.mouseInside = RGFW_FALSE; _RGFW->windowState.winLeave = win; _RGFW->windowState.mouseLeave = RGFW_TRUE; RGFW_event e; e.type = RGFW_mouseLeave; e.mouse.x = 0; e.mouse.y = 0; e.common.win = win; RGFW_eventQueuePush(&e); RGFW_mouseNotifyCallback(win, e.mouse.x, e.mouse.y, 0); } void RGFW__osxKeyDown(id self, SEL _cmd, id event) { RGFW_UNUSED(_cmd); RGFW_window *win = NULL; object_getInstanceVariable(self, "RGFW_window", (void **)&win); if (win == NULL || !(win->internal.enabledEvents & RGFW_keyPressedFlag)) return; RGFW_event e; u32 key = (u16) ((u32(*) (id, SEL)) objc_msgSend) (event, sel_registerName("keyCode")); u32 mappedKey = (u32) * (((char *)(const char *)NSString_to_char(((id(*) (id, SEL)) objc_msgSend) (event, sel_registerName("charactersIgnoringModifiers"))))); if ((u8) mappedKey == 239) mappedKey = 0; e.key.sym = (u8) mappedKey; e.key.value = (u8) RGFW_apiKeyToRGFW(key); _RGFW->keyboard[e.key.value].prev = _RGFW->keyboard[e.key.value].current; e.type = RGFW_keyPressed; e.key.repeat = RGFW_window_isKeyPressed(win, e.key.value); _RGFW->keyboard[e.key.value].current = 1; e.common.win = win; RGFW_eventQueuePush(&e); RGFW_keyCallback(win, e.key.value, e.key.sym, win->internal.mod, e.key.repeat, 1); } void RGFW__osxKeyUp(id self, SEL _cmd, id event) { RGFW_UNUSED(_cmd); RGFW_window *win = NULL; object_getInstanceVariable(self, "RGFW_window", (void **)&win); if (win == NULL || !(win->internal.enabledEvents & RGFW_keyReleasedFlag)) return; RGFW_event e; u32 key = (u16) ((u32(*) (id, SEL)) objc_msgSend) (event, sel_registerName("keyCode")); u32 mappedKey = (u32) * (((char *)(const char *)NSString_to_char(((id(*) (id, SEL)) objc_msgSend) (event, sel_registerName("charactersIgnoringModifiers"))))); if ((u8) mappedKey == 239) mappedKey = 0; e.key.sym = (u8) mappedKey; e.key.value = (u8) RGFW_apiKeyToRGFW(key); _RGFW->keyboard[e.key.value].prev = _RGFW->keyboard[e.key.value].current; e.type = RGFW_keyReleased; e.key.repeat = RGFW_window_isKeyDown(win, (u8) e.key.value); _RGFW->keyboard[e.key.value].current = 0; e.common.win = win; RGFW_eventQueuePush(&e); RGFW_keyCallback(win, e.key.value, e.key.sym, win->internal.mod, e.key.repeat, 0); } void RGFW__osxFlagsChanged(id self, SEL _cmd, id event) { RGFW_UNUSED(_cmd); RGFW_window *win = NULL; object_getInstanceVariable(self, "RGFW_window", (void **)&win); if (win == NULL) return; RGFW_event e; u32 flags = (u32) ((u32(*) (id, SEL)) objc_msgSend) (event, sel_registerName("modifierFlags")); RGFW_updateKeyModsEx(win, ((u32) (flags & NSEventModifierFlagCapsLock) % 255), ((flags & NSEventModifierFlagNumericPad) % 255), ((flags & NSEventModifierFlagControl) % 255), ((flags & NSEventModifierFlagOption) % 255), ((flags & NSEventModifierFlagShift) % 255), ((flags & NSEventModifierFlagCommand) % 255), 0); u8 i; for (i = 0; i < 9; i++) _RGFW->keyboard[i + RGFW_capsLock].prev = _RGFW->keyboard[i + RGFW_capsLock].current; for (i = 0; i < 5; i++) { u32 shift = (1 << (i + 16)); u32 key = i + RGFW_capsLock; if ((flags & shift) && !RGFW_window_isKeyDown(win, (u8) key)) { _RGFW->keyboard[key].current = 1; if (key != RGFW_capsLock) _RGFW->keyboard[key + 4].current = 1; e.type = RGFW_keyPressed; e.key.value = (u8) key; break; } if (!(flags & shift) && RGFW_window_isKeyDown(win, (u8) key)) { _RGFW->keyboard[key].current = 0; if (key != RGFW_capsLock) _RGFW->keyboard[key + 4].current = 0; e.type = RGFW_keyReleased; e.key.value = (u8) key; break; } } e.key.repeat = RGFW_window_isKeyDown(win, (u8) e.key.value); e.common.win = win; if (!(win->internal.enabledEvents & (RGFW_BIT(e.type)))) return; RGFW_eventQueuePush(&e); RGFW_keyCallback(win, e.key.value, e.key.sym, win->internal.mod, e.key.repeat, e.type == RGFW_keyPressed); } void RGFW__osxMouseMoved(id self, SEL _cmd, id event) { RGFW_UNUSED(_cmd); RGFW_window *win = NULL; object_getInstanceVariable(self, "RGFW_window", (void **)&win); if (win == NULL || !(win->internal.enabledEvents & RGFW_windowMovedFlag)) return; RGFW_event e; e.type = RGFW_mousePosChanged; NSPoint p = ((NSPoint(*) (id, SEL)) objc_msgSend) (event, sel_registerName("locationInWindow")); e.mouse.x = (i32) p.x; e.mouse.y = (i32) (win->h - p.y); p.x = ((CGFloat(*) (id, SEL)) abi_objc_msgSend_fpret) (event, sel_registerName("deltaX")); p.y = ((CGFloat(*) (id, SEL)) abi_objc_msgSend_fpret) (event, sel_registerName("deltaY")); e.mouse.vecX = (float)p.x; e.mouse.vecY = (float)p.y; _RGFW->vectorX = e.mouse.vecX; _RGFW->vectorY = e.mouse.vecY; win->internal.lastMouseX = e.mouse.x; win->internal.lastMouseY = e.mouse.y; e.common.win = win; RGFW_eventQueuePush(&e); RGFW_mousePosCallback(win, e.mouse.x, e.mouse.y, e.mouse.vecX, e.mouse.vecY); } void RGFW__osxMouseDown(id self, SEL _cmd, id event) { RGFW_UNUSED(_cmd); RGFW_window *win = NULL; object_getInstanceVariable(self, "RGFW_window", (void **)&win); if (win == NULL || !(win->internal.enabledEvents & RGFW_mouseButtonPressedFlag)) return; RGFW_event e; u32 buttonNumber = (u32) ((u32(*) (id, SEL)) objc_msgSend) (event, sel_registerName("buttonNumber")); switch (buttonNumber) { case 0:e.button.value = RGFW_mouseLeft; break; case 1:e.button.value = RGFW_mouseRight; break; case 2:e.button.value = RGFW_mouseMiddle; break; default:e.button.value = (u8) buttonNumber; } e.type = RGFW_mouseButtonPressed; _RGFW->mouseButtons[e.button.value].prev = _RGFW->mouseButtons[e.button.value].current; _RGFW->mouseButtons[e.button.value].current = 1; e.common.win = win; RGFW_eventQueuePush(&e); RGFW_mouseButtonCallback(win, e.button.value, 1); } void RGFW__osxMouseUp(id self, SEL _cmd, id event) { RGFW_UNUSED(_cmd); RGFW_window *win = NULL; object_getInstanceVariable(self, "RGFW_window", (void **)&win); if (win == NULL || !(win->internal.enabledEvents & RGFW_mouseButtonReleasedFlag)) return; RGFW_event e; u32 buttonNumber = (u32) ((u32(*) (id, SEL)) objc_msgSend) (event, sel_registerName("buttonNumber")); switch (buttonNumber) { case 0:e.button.value = RGFW_mouseLeft; break; case 1:e.button.value = RGFW_mouseRight; break; case 2:e.button.value = RGFW_mouseMiddle; break; default:e.button.value = (u8) buttonNumber; } e.type = RGFW_mouseButtonReleased; _RGFW->mouseButtons[e.button.value].prev = _RGFW->mouseButtons[e.button.value].current; _RGFW->mouseButtons[e.button.value].current = 0; e.common.win = win; RGFW_eventQueuePush(&e); RGFW_mouseButtonCallback(win, e.button.value, 0); } void RGFW__osxScrollWheel(id self, SEL _cmd, id event) { RGFW_UNUSED(_cmd); RGFW_window *win = NULL; object_getInstanceVariable(self, "RGFW_window", (void **)&win); if (win == NULL || !(win->internal.enabledEvents & RGFW_mouseScroll)) return; RGFW_event e; float deltaX = (float)((CGFloat(*) (id, SEL)) abi_objc_msgSend_fpret) (event, sel_registerName("deltaX")); float deltaY = (float)((CGFloat(*) (id, SEL)) abi_objc_msgSend_fpret) (event, sel_registerName("deltaY")); e.type = RGFW_mouseScroll; e.scroll.x = deltaX; e.scroll.y = deltaY; e.common.win = win; _RGFW->scrollX = e.scroll.x; _RGFW->scrollY = e.scroll.y; RGFW_eventQueuePush(&e); RGFW_mouseScrollCallback(win, deltaX, deltaY); } RGFW_bool RGFW_createSurfacePtr(u8 * data, i32 w, i32 h, RGFW_format format, RGFW_surface * surface) { surface->data = data; surface->w = w; surface->h = h; surface->format = format; surface->native.format = RGFW_formatRGBA8; return RGFW_TRUE; } void RGFW_surface_freePtr(RGFW_surface * surface) { RGFW_UNUSED(surface); } void RGFW_window_blitSurface(RGFW_window * win, RGFW_surface * surface) { RGFW_copyImageData(surface->data, surface->w, RGFW_MIN(win->h, surface->h), surface->native.format, surface->data, surface->format); size_t depth = (surface->format >= RGFW_formatRGBA8) ? 4 : 3; id image = ((id(*) (Class, SEL)) objc_msgSend) (objc_getClass("NSImage"), sel_getUid("alloc")); NSSize size = (NSSize) {(double)surface->w, (double)surface->h}; image = ((id(*) (id, SEL, NSSize)) objc_msgSend) ((id) image, sel_getUid("initWithSize:"), size); int minX = RGFW_MIN(win->w, surface->w); int minY = RGFW_MIN(win->h, surface->h); id rep = NSBitmapImageRep_initWithBitmapData(&surface->data, minX, minY, 8, (i32) depth, (depth == 4), false, "NSDeviceRGBColorSpace", 1 << 1, (u32) surface->w * (u32) depth, 8 * (u32) depth); RGFW_copyImageData(NSBitmapImageRep_bitmapData(rep), minX, minY, RGFW_formatRGBA8, surface->data, surface->format); ((void (*) (id, SEL, id))objc_msgSend) ((id) image, sel_getUid("addRepresentation:"), rep); id contentView = ((id(*) (id, SEL)) objc_msgSend) ((id) win->src.window, sel_getUid("contentView")); ((void (*) (id, SEL, BOOL))objc_msgSend) (contentView, sel_getUid("setWantsLayer:"), YES); id layer = ((id(*) (id, SEL)) objc_msgSend) (contentView, sel_getUid("layer")); ((void (*) (id, SEL, id))objc_msgSend) (layer, sel_getUid("setContents:"), (id) image); ((void (*) (id, SEL, BOOL))objc_msgSend) (contentView, sel_getUid("setNeedsDisplay:"), YES); NSRelease(rep); NSRelease(image); } void *RGFW_window_getView_OSX(RGFW_window * win) { return win->src.view; } void RGFW_window_setLayer_OSX(RGFW_window * win, void *layer){ objc_msgSend_void_id((id) win->src.view, sel_registerName("setLayer"), (id) layer); } void *RGFW_getLayer_OSX(void){ return objc_msgSend_class((id) objc_getClass("CAMetalLayer"), (SEL) sel_registerName("layer")); } void *RGFW_window_getWindow_OSX(RGFW_window * win) { return win->src.window; } void RGFW_initKeycodesPlatform(void){ _RGFW->keycodes[0x1D] = RGFW_0; _RGFW->keycodes[0x12] = RGFW_1; _RGFW->keycodes[0x13] = RGFW_2; _RGFW->keycodes[0x14] = RGFW_3; _RGFW->keycodes[0x15] = RGFW_4; _RGFW->keycodes[0x17] = RGFW_5; _RGFW->keycodes[0x16] = RGFW_6; _RGFW->keycodes[0x1A] = RGFW_7; _RGFW->keycodes[0x1C] = RGFW_8; _RGFW->keycodes[0x19] = RGFW_9; _RGFW->keycodes[0x00] = RGFW_a; _RGFW->keycodes[0x0B] = RGFW_b; _RGFW->keycodes[0x08] = RGFW_c; _RGFW->keycodes[0x02] = RGFW_d; _RGFW->keycodes[0x0E] = RGFW_e; _RGFW->keycodes[0x03] = RGFW_f; _RGFW->keycodes[0x05] = RGFW_g; _RGFW->keycodes[0x04] = RGFW_h; _RGFW->keycodes[0x22] = RGFW_i; _RGFW->keycodes[0x26] = RGFW_j; _RGFW->keycodes[0x28] = RGFW_k; _RGFW->keycodes[0x25] = RGFW_l; _RGFW->keycodes[0x2E] = RGFW_m; _RGFW->keycodes[0x2D] = RGFW_n; _RGFW->keycodes[0x1F] = RGFW_o; _RGFW->keycodes[0x23] = RGFW_p; _RGFW->keycodes[0x0C] = RGFW_q; _RGFW->keycodes[0x0F] = RGFW_r; _RGFW->keycodes[0x01] = RGFW_s; _RGFW->keycodes[0x11] = RGFW_t; _RGFW->keycodes[0x20] = RGFW_u; _RGFW->keycodes[0x09] = RGFW_v; _RGFW->keycodes[0x0D] = RGFW_w; _RGFW->keycodes[0x07] = RGFW_x; _RGFW->keycodes[0x10] = RGFW_y; _RGFW->keycodes[0x06] = RGFW_z; _RGFW->keycodes[0x27] = RGFW_apostrophe; _RGFW->keycodes[0x2A] = RGFW_backSlash; _RGFW->keycodes[0x2B] = RGFW_comma; _RGFW->keycodes[0x18] = RGFW_equals; _RGFW->keycodes[0x32] = RGFW_backtick; _RGFW->keycodes[0x21] = RGFW_bracket; _RGFW->keycodes[0x1B] = RGFW_minus; _RGFW->keycodes[0x2F] = RGFW_period; _RGFW->keycodes[0x1E] = RGFW_closeBracket; _RGFW->keycodes[0x29] = RGFW_semicolon; _RGFW->keycodes[0x2C] = RGFW_slash; _RGFW->keycodes[0x0A] = RGFW_world1; _RGFW->keycodes[0x33] = RGFW_backSpace; _RGFW->keycodes[0x39] = RGFW_capsLock; _RGFW->keycodes[0x75] = RGFW_delete; _RGFW->keycodes[0x7D] = RGFW_down; _RGFW->keycodes[0x77] = RGFW_end; _RGFW->keycodes[0x24] = RGFW_enter; _RGFW->keycodes[0x35] = RGFW_escape; _RGFW->keycodes[0x7A] = RGFW_F1; _RGFW->keycodes[0x78] = RGFW_F2; _RGFW->keycodes[0x63] = RGFW_F3; _RGFW->keycodes[0x76] = RGFW_F4; _RGFW->keycodes[0x60] = RGFW_F5; _RGFW->keycodes[0x61] = RGFW_F6; _RGFW->keycodes[0x62] = RGFW_F7; _RGFW->keycodes[0x64] = RGFW_F8; _RGFW->keycodes[0x65] = RGFW_F9; _RGFW->keycodes[0x6D] = RGFW_F10; _RGFW->keycodes[0x67] = RGFW_F11; _RGFW->keycodes[0x6F] = RGFW_F12; _RGFW->keycodes[0x69] = RGFW_printScreen; _RGFW->keycodes[0x6B] = RGFW_F14; _RGFW->keycodes[0x71] = RGFW_F15; _RGFW->keycodes[0x6A] = RGFW_F16; _RGFW->keycodes[0x40] = RGFW_F17; _RGFW->keycodes[0x4F] = RGFW_F18; _RGFW->keycodes[0x50] = RGFW_F19; _RGFW->keycodes[0x5A] = RGFW_F20; _RGFW->keycodes[0x73] = RGFW_home; _RGFW->keycodes[0x72] = RGFW_insert; _RGFW->keycodes[0x7B] = RGFW_left; _RGFW->keycodes[0x3A] = RGFW_altL; _RGFW->keycodes[0x3B] = RGFW_controlL; _RGFW->keycodes[0x38] = RGFW_shiftL; _RGFW->keycodes[0x37] = RGFW_superL; _RGFW->keycodes[0x6E] = RGFW_menu; _RGFW->keycodes[0x47] = RGFW_numLock; _RGFW->keycodes[0x79] = RGFW_pageDown; _RGFW->keycodes[0x74] = RGFW_pageUp; _RGFW->keycodes[0x7C] = RGFW_right; _RGFW->keycodes[0x3D] = RGFW_altR; _RGFW->keycodes[0x3E] = RGFW_controlR; _RGFW->keycodes[0x3C] = RGFW_shiftR; _RGFW->keycodes[0x36] = RGFW_superR; _RGFW->keycodes[0x31] = RGFW_space; _RGFW->keycodes[0x30] = RGFW_tab; _RGFW->keycodes[0x7E] = RGFW_up; _RGFW->keycodes[0x52] = RGFW_kp0; _RGFW->keycodes[0x53] = RGFW_kp1; _RGFW->keycodes[0x54] = RGFW_kp2; _RGFW->keycodes[0x55] = RGFW_kp3; _RGFW->keycodes[0x56] = RGFW_kp4; _RGFW->keycodes[0x57] = RGFW_kp5; _RGFW->keycodes[0x58] = RGFW_kp6; _RGFW->keycodes[0x59] = RGFW_kp7; _RGFW->keycodes[0x5B] = RGFW_kp8; _RGFW->keycodes[0x5C] = RGFW_kp9; _RGFW->keycodes[0x45] = RGFW_kpSlash; _RGFW->keycodes[0x41] = RGFW_kpPeriod; _RGFW->keycodes[0x4B] = RGFW_kpSlash; _RGFW->keycodes[0x4C] = RGFW_kpReturn; _RGFW->keycodes[0x51] = RGFW_kpEqual; _RGFW->keycodes[0x43] = RGFW_kpMultiply; _RGFW->keycodes[0x4E] = RGFW_kpMinus; } i32 RGFW_initPlatform(void){ class_addMethod(objc_getClass("NSObject"), sel_registerName("windowShouldClose:"), (IMP) (void *)RGFW_OnClose, 0); /* * NOTE(EimaMei): Fixes the 'Boop' sfx from * constantly playing each time you click a * key. Only a problem when running in the * terminal. */ class_addMethod(objc_getClass("NSWindowClass"), sel_registerName("acceptsFirstResponder:"), (IMP) (void *)acceptsFirstResponder, 0); class_addMethod(objc_getClass("NSWindowClass"), sel_registerName("performKeyEquivalent:"), (IMP) (void *)performKeyEquivalent, 0); _RGFW->NSApp = objc_msgSend_id((id) objc_getClass("NSApplication"), sel_registerName("sharedApplication")); ((void (*) (id, SEL, NSUInteger))objc_msgSend) ((id) _RGFW->NSApp, sel_registerName("setActivationPolicy:"), NSApplicationActivationPolicyRegular); _RGFW->customViewClasses[0] = objc_allocateClassPair(objc_getClass("NSView"), "RGFWCustomView", 0); _RGFW->customViewClasses[1] = objc_allocateClassPair(objc_getClass("NSOpenGLView"), "RGFWOpenGLCustomView", 0); for (size_t i = 0; i < 2; i++) { class_addIvar((Class) _RGFW->customViewClasses[i], "RGFW_window", sizeof(RGFW_window *), sizeof(RGFW_window *), "L"); class_addMethod((Class) _RGFW->customViewClasses[i], sel_registerName("drawRect:"), (IMP) RGFW__osxDrawRect, "v@:{CGRect=ffff}"); class_addMethod((Class) _RGFW->customViewClasses[i], sel_registerName("viewDidChangeBackingProperties"), (IMP) RGFW__osxViewDidChangeBackingProperties, "v@:"); class_addMethod((Class) _RGFW->customViewClasses[i], sel_registerName("mouseDown:"), (IMP) RGFW__osxMouseDown, "v@:@"); class_addMethod((Class) _RGFW->customViewClasses[i], sel_registerName("rightMouseDown:"), (IMP) RGFW__osxMouseDown, "v@:@"); class_addMethod((Class) _RGFW->customViewClasses[i], sel_registerName("otherMouseDown:"), (IMP) RGFW__osxMouseDown, "v@:@"); class_addMethod((Class) _RGFW->customViewClasses[i], sel_registerName("mouseUp:"), (IMP) RGFW__osxMouseUp, "v@:@"); class_addMethod((Class) _RGFW->customViewClasses[i], sel_registerName("rightMouseUp:"), (IMP) RGFW__osxMouseUp, "v@:@"); class_addMethod((Class) _RGFW->customViewClasses[i], sel_registerName("otherMouseUp:"), (IMP) RGFW__osxMouseUp, "v@:@"); class_addMethod((Class) _RGFW->customViewClasses[i], sel_registerName("scrollWheel:"), (IMP) RGFW__osxScrollWheel, "v@:@"); class_addMethod((Class) _RGFW->customViewClasses[i], sel_registerName("mouseDragged:"), (IMP) RGFW__osxMouseMoved, "v@:@"); class_addMethod((Class) _RGFW->customViewClasses[i], sel_registerName("rightMouseDragged:"), (IMP) RGFW__osxMouseMoved, "v@:@"); class_addMethod((Class) _RGFW->customViewClasses[i], sel_registerName("otherMouseDragged:"), (IMP) RGFW__osxMouseMoved, "v@:@"); class_addMethod((Class) _RGFW->customViewClasses[i], sel_registerName("keyDown:"), (IMP) RGFW__osxKeyDown, "v@:@"); class_addMethod((Class) _RGFW->customViewClasses[i], sel_registerName("keyUp:"), (IMP) RGFW__osxKeyUp, "v@:@"); class_addMethod((Class) _RGFW->customViewClasses[i], sel_registerName("mouseMoved:"), (IMP) RGFW__osxMouseMoved, "v@:@"); class_addMethod((Class) _RGFW->customViewClasses[i], sel_registerName("mouseEntered:"), (IMP) RGFW__osxMouseEntered, "v@:@"); class_addMethod((Class) _RGFW->customViewClasses[i], sel_registerName("mouseExited:"), (IMP) RGFW__osxMouseExited, "v@:@"); class_addMethod((Class) _RGFW->customViewClasses[i], sel_registerName("flagsChanged:"), (IMP) RGFW__osxFlagsChanged, "v@:@"); class_addMethod((Class) _RGFW->customViewClasses[i], sel_getUid("acceptsFirstResponder"), (IMP) acceptsFirstResponder, "B@:"); class_addMethod((Class) _RGFW->customViewClasses[i], sel_registerName("initWithRGFWWindow:"), (IMP) RGFW__osxCustomInitWithRGFWWindow, "@@:{CGRect={CGPoint=dd}{CGSize=dd}}"); class_addMethod((Class) _RGFW->customViewClasses[i], sel_registerName("wantsUpdateLayer"), (IMP) RGFW__osxWantsUpdateLayer, "B@:"); class_addMethod((Class) _RGFW->customViewClasses[i], sel_registerName("updateLayer"), (IMP) RGFW__osxUpdateLayer, "v@:"); objc_registerClassPair((Class) _RGFW->customViewClasses[i]); } _RGFW->customWindowDelegateClass = objc_allocateClassPair(objc_getClass("NSObject"), "RGFWWindowDelegate", 0); class_addIvar((Class) _RGFW->customWindowDelegateClass, "RGFW_window", sizeof(RGFW_window *), sizeof(RGFW_window *), "L"); class_addMethod((Class) _RGFW->customWindowDelegateClass, sel_registerName("windowDidResize:"), (IMP) RGFW__osxDidWindowResize, "v@:@"); class_addMethod((Class) _RGFW->customWindowDelegateClass, sel_registerName("windowDidMove:"), (IMP) RGFW__osxWindowMove, ""); class_addMethod((Class) _RGFW->customWindowDelegateClass, sel_registerName("windowDidMiniaturize:"), (IMP) RGFW__osxWindowMiniaturize, ""); class_addMethod((Class) _RGFW->customWindowDelegateClass, sel_registerName("windowDidDeminiaturize:"), (IMP) RGFW__osxWindowDeminiaturize, ""); class_addMethod((Class) _RGFW->customWindowDelegateClass, sel_registerName("windowDidBecomeKey:"), (IMP) RGFW__osxWindowBecameKey, ""); class_addMethod((Class) _RGFW->customWindowDelegateClass, sel_registerName("windowDidResignKey:"), (IMP) RGFW__osxWindowResignKey, ""); class_addMethod((Class) _RGFW->customWindowDelegateClass, sel_registerName("draggingEntered:"), (IMP) draggingEntered, "l@:@"); class_addMethod((Class) _RGFW->customWindowDelegateClass, sel_registerName("draggingUpdated:"), (IMP) draggingUpdated, "l@:@"); class_addMethod((Class) _RGFW->customWindowDelegateClass, sel_registerName("draggingExited:"), (IMP) RGFW__osxDraggingEnded, "v@:@"); class_addMethod((Class) _RGFW->customWindowDelegateClass, sel_registerName("draggingEnded:"), (IMP) RGFW__osxDraggingEnded, "v@:@"); class_addMethod((Class) _RGFW->customWindowDelegateClass, sel_registerName("prepareForDragOperation:"), (IMP) prepareForDragOperation, "B@:@"); class_addMethod((Class) _RGFW->customWindowDelegateClass, sel_registerName("performDragOperation:"), (IMP) performDragOperation, "B@:@"); objc_registerClassPair((Class) _RGFW->customWindowDelegateClass); return 0; } void RGFW_osx_initView(RGFW_window * win) { NSRect contentRect; contentRect.origin.x = 0; contentRect.origin.y = 0; contentRect.size.width = (double)win->w; contentRect.size.height = (double)win->h; ((void (*) (id, SEL, CGRect))objc_msgSend) ((id) win->src.view, sel_registerName("setFrame:"), contentRect); if (RGFW_COCOA_FRAME_NAME) objc_msgSend_ptr(win->src.view, sel_registerName("setFrameAutosaveName:"), RGFW_COCOA_FRAME_NAME); object_setInstanceVariable((id) win->src.view, "RGFW_window", win); objc_msgSend_void_id((id) win->src.window, sel_registerName("setContentView:"), win->src.view); objc_msgSend_void_bool(win->src.view, sel_registerName("setWantsLayer:"), true); objc_msgSend_int((id) win->src.view, sel_registerName("setLayerContentsPlacement:"), 4); id trackingArea = objc_msgSend_id(objc_getClass("NSTrackingArea"), sel_registerName("alloc")); trackingArea = ((id(*) (id, SEL, NSRect, NSUInteger, id, id)) objc_msgSend) ( trackingArea, sel_registerName("initWithRect:options:owner:userInfo:"), contentRect, NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingInVisibleRect, (id) win->src.view, nil ); ((void (*) (id, SEL, id))objc_msgSend) ((id) win->src.view, sel_registerName("addTrackingArea:"), trackingArea); ((void (*) (id, SEL))objc_msgSend) (trackingArea, sel_registerName("release")); } RGFW_window *RGFW_createWindowPlatform(const char *name, RGFW_windowFlags flags, RGFW_window * win){ /* RR Create an autorelease pool */ id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); pool = objc_msgSend_id(pool, sel_registerName("init")); RGFW_window_setMouseDefault(win); NSRect windowRect; windowRect.origin.x = (double)win->x; windowRect.origin.y = (double)win->y; windowRect.size.width = (double)win->w; windowRect.size.height = (double)win->h; NSBackingStoreType macArgs = (NSBackingStoreType) (NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSBackingStoreBuffered | NSWindowStyleMaskTitled); if (!(flags & RGFW_windowNoResize)) macArgs = (NSBackingStoreType) (macArgs | (NSBackingStoreType) NSWindowStyleMaskResizable); if (!(flags & RGFW_windowNoBorder)) macArgs = (NSBackingStoreType) (macArgs | (NSBackingStoreType) NSWindowStyleMaskTitled); { void *nsclass = objc_getClass("NSWindow"); SEL func = sel_registerName("initWithContentRect:styleMask:backing:defer:"); win->src.window = ((id(*) (id, SEL, NSRect, NSWindowStyleMask, NSBackingStoreType, bool)) objc_msgSend) (NSAlloc(nsclass), func, windowRect, (NSWindowStyleMask) macArgs, macArgs, false); } id str = NSString_stringWithUTF8String(name); objc_msgSend_void_id((id) win->src.window, sel_registerName("setTitle:"), str); id delegate = objc_msgSend_id(NSAlloc((Class) _RGFW->customWindowDelegateClass), sel_registerName("init")); object_setInstanceVariable(delegate, "RGFW_window", win); objc_msgSend_void_id((id) win->src.window, sel_registerName("setDelegate:"), delegate); if (flags & RGFW_windowAllowDND) { win->internal.flags |= RGFW_windowAllowDND; NSPasteboardType types[] = {NSPasteboardTypeURL, NSPasteboardTypeFileURL, NSPasteboardTypeString}; NSregisterForDraggedTypes((id) win->src.window, types, 3); } objc_msgSend_void_bool((id) win->src.window, sel_registerName("setAcceptsMouseMovedEvents:"), true); if (flags & RGFW_windowTransparent) { objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), false); objc_msgSend_void_id((id) win->src.window, sel_registerName("setBackgroundColor:"), NSColor_colorWithSRGB(0, 0, 0, 0)); } /* Show the window */ objc_msgSend_void_bool((id) _RGFW->NSApp, sel_registerName("activateIgnoringOtherApps:"), true); if (_RGFW->root == NULL) { objc_msgSend_void(win->src.window, sel_registerName("makeMainWindow")); } objc_msgSend_void(win->src.window, sel_registerName("makeKeyWindow")); objc_msgSend_void((id) _RGFW->NSApp, sel_registerName("finishLaunching")); NSRetain(win->src.window); NSRetain(_RGFW->NSApp); win->src.view = ((id(*) (id, SEL, RGFW_window *)) objc_msgSend) (NSAlloc((Class) _RGFW->customViewClasses[0]), sel_registerName("initWithRGFWWindow:"), win); return win; } void RGFW_window_setBorder(RGFW_window * win, RGFW_bool border) { NSRect frame = ((NSRect(*) (id, SEL)) abi_objc_msgSend_stret) ((id) win->src.window, sel_registerName("frame")); NSRect content = ((NSRect(*) (id, SEL)) abi_objc_msgSend_stret) ((id) win->src.view, sel_registerName("frame")); double offset = 0; RGFW_setBit(&win->internal.flags, RGFW_windowNoBorder, !border); NSBackingStoreType storeType = (NSBackingStoreType) (NSWindowStyleMaskBorderless | NSWindowStyleMaskFullSizeContentView); if (border) storeType = (NSBackingStoreType) (NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable); if (!(win->internal.flags & RGFW_windowNoResize)) { storeType = (NSBackingStoreType) (storeType | (NSBackingStoreType) NSWindowStyleMaskResizable); } ((void (*) (id, SEL, NSBackingStoreType))objc_msgSend) ((id) win->src.window, sel_registerName("setStyleMask:"), storeType); if (!border) { id miniaturizeButton = objc_msgSend_int((id) win->src.window, sel_registerName("standardWindowButton:"), NSWindowMiniaturizeButton); id titleBarView = objc_msgSend_id(miniaturizeButton, sel_registerName("superview")); objc_msgSend_void_bool(titleBarView, sel_registerName("setHidden:"), true); offset = (double)(frame.size.height - content.size.height); } RGFW_window_resize(win, win->w, win->h + (i32) offset); win->h -= (i32) offset; } RGFW_bool RGFW_getGlobalMouse(i32 * x, i32 * y) { RGFW_ASSERT(_RGFW->root != NULL); CGEventRef e = CGEventCreate(NULL); CGPoint point = CGEventGetLocation(e); CFRelease(e); if (x) *x = (i32) point.x; if (y) *y = (i32) point.y; return RGFW_TRUE; } void RGFW_stopCheckEvents(void){ id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); eventPool = objc_msgSend_id(eventPool, sel_registerName("init")); id e = (id) ((id(*) (Class, SEL, NSEventType, NSPoint, NSEventModifierFlags, void *, NSInteger, void **, short, NSInteger, NSInteger)) objc_msgSend) (objc_getClass("NSEvent"), sel_registerName("otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:"), NSEventTypeApplicationDefined, (NSPoint) {0, 0}, (NSEventModifierFlags) 0, NULL, (NSInteger) 0, NULL, 0, 0, 0); ((void (*) (id, SEL, id, bool))objc_msgSend) ((id) _RGFW->NSApp, sel_registerName("postEvent:atStart:"), e, 1); objc_msgSend_bool_void(eventPool, sel_registerName("drain")); } void RGFW_waitForEvent(i32 waitMS) { id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); eventPool = objc_msgSend_id(eventPool, sel_registerName("init")); void *date = (void *)((id(*) (Class, SEL, double)) objc_msgSend) (objc_getClass("NSDate"), sel_registerName("dateWithTimeIntervalSinceNow:"), waitMS); SEL eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"); id e = (id) ((id(*) (id, SEL, NSEventMask, void *, id, bool)) objc_msgSend) ((id) _RGFW->NSApp, eventFunc, ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true); if (e) { ((void (*) (id, SEL, id, bool))objc_msgSend) ((id) _RGFW->NSApp, sel_registerName("postEvent:atStart:"), e, 1); } objc_msgSend_bool_void(eventPool, sel_registerName("drain")); } u8 RGFW_rgfwToKeyChar(u32 rgfw_keycode) { return (u8) rgfw_keycode; /* TODO */ } void RGFW_pollEvents(void){ /* * TODO look to see if all these events can be * replaced with callbacks callbacks seem to * give better info on mac's api */ RGFW_resetPrevState(); id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); eventPool = objc_msgSend_id(eventPool, sel_registerName("init")); SEL eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"); while (1) { void *date = NULL; id e = (id) ((id(*) (id, SEL, NSEventMask, void *, id, bool)) objc_msgSend) ((id) _RGFW->NSApp, eventFunc, ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true); if (e == NULL) { objc_msgSend_void_id((id) _RGFW->NSApp, sel_registerName("sendEvent:"), e); ((void (*) (id, SEL))objc_msgSend) ((id) _RGFW->NSApp, sel_registerName("updateWindows")); break; } RGFW_event event; RGFW_MEMSET(&event, 0, sizeof(event)); objc_msgSend_void_id((id) _RGFW->NSApp, sel_registerName("sendEvent:"), e); ((void (*) (id, SEL))objc_msgSend) ((id) _RGFW->NSApp, sel_registerName("updateWindows")); } objc_msgSend_bool_void(eventPool, sel_registerName("drain")); } void RGFW_window_move(RGFW_window * win, i32 x, i32 y) { RGFW_ASSERT(win != NULL); win->x = x; win->y = y; ((void (*) (id, SEL, NSRect, bool, bool))objc_msgSend) ((id) win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect) {{ (double)win->x, (double)win->y } ,{ (double)win->w, (double)win->h } } ,true, true); } void RGFW_window_resize(RGFW_window * win, i32 w, i32 h) { RGFW_ASSERT(win != NULL); NSRect frame = ((NSRect(*) (id, SEL)) abi_objc_msgSend_stret) ((id) win->src.window, sel_registerName("frame")); NSRect content = ((NSRect(*) (id, SEL)) abi_objc_msgSend_stret) ((id) win->src.view, sel_registerName("frame")); float offset = (float)(frame.size.height - content.size.height); win->w = w; win->h = h; ((void (*) (id, SEL, CGRect))objc_msgSend) ((id) win->src.view, sel_registerName("setFrame:"), (NSRect) {{ 0, 0 } ,{ (double)win->w, (double)win->h } }); ((void (*) (id, SEL, NSRect, bool, bool))objc_msgSend) ((id) win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect) {{ (double)win->x, (double)win->y } ,{ (double)win->w, (double)win->h + (double)offset } } ,true, true); } void RGFW_window_focus(RGFW_window * win) { RGFW_ASSERT(win); objc_msgSend_void_bool((id) _RGFW->NSApp, sel_registerName("activateIgnoringOtherApps:"), true); ((void (*) (id, SEL))objc_msgSend) ((id) win->src.window, sel_registerName("makeKeyWindow")); } void RGFW_window_raise(RGFW_window * win) { RGFW_ASSERT(win != NULL); ((id(*) (id, SEL, SEL)) objc_msgSend) ((id) win->src.window, sel_registerName("orderFront:"), (SEL) NULL); objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGNormalWindowLevelKey); } void RGFW_window_setFullscreen(RGFW_window * win, RGFW_bool fullscreen) { RGFW_ASSERT(win != NULL); if (fullscreen && (win->internal.flags & RGFW_windowFullscreen)) return; if (!fullscreen && !(win->internal.flags & RGFW_windowFullscreen)) return; if (fullscreen) { if (!(win->internal.flags & RGFW_windowFullscreen)) { return; } win->internal.oldX = win->x; win->internal.oldY = win->y; win->internal.oldW = win->w; win->internal.oldH = win->h; RGFW_monitor mon = RGFW_window_getMonitor(win); win->x = mon.x; win->y = mon.y; win->w = mon.mode.w; win->h = mon.mode.h; win->internal.flags |= RGFW_windowFullscreen; RGFW_window_resize(win, mon.mode.w, mon.mode.h); RGFW_window_move(win, mon.x, mon.y); } objc_msgSend_void_SEL(win->src.window, sel_registerName("toggleFullScreen:"), NULL); if (!fullscreen) { win->x = win->internal.oldX; win->y = win->internal.oldY; win->w = win->internal.oldW; win->h = win->internal.oldH; win->internal.flags &= ~(u32) RGFW_windowFullscreen; RGFW_window_resize(win, win->w, win->h); RGFW_window_move(win, win->x, win->y); } } void RGFW_window_maximize(RGFW_window * win) { RGFW_ASSERT(win != NULL); if (RGFW_window_isMaximized(win)) return; win->internal.flags |= RGFW_windowMaximize; objc_msgSend_void_SEL(win->src.window, sel_registerName("zoom:"), NULL); } void RGFW_window_minimize(RGFW_window * win) { RGFW_ASSERT(win != NULL); objc_msgSend_void_SEL(win->src.window, sel_registerName("performMiniaturize:"), NULL); } void RGFW_window_setFloating(RGFW_window * win, RGFW_bool floating) { RGFW_ASSERT(win != NULL); if (floating) objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGFloatingWindowLevelKey); else objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGNormalWindowLevelKey); } void RGFW_window_setOpacity(RGFW_window * win, u8 opacity) { objc_msgSend_int(win->src.window, sel_registerName("setAlphaValue:"), opacity); objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), (opacity < (u8) 255)); if (opacity) objc_msgSend_void_id((id) win->src.window, sel_registerName("setBackgroundColor:"), NSColor_colorWithSRGB(0, 0, 0, opacity)); } void RGFW_window_restore(RGFW_window * win) { RGFW_ASSERT(win != NULL); if (RGFW_window_isMaximized(win)) objc_msgSend_void_SEL(win->src.window, sel_registerName("zoom:"), NULL); objc_msgSend_void_SEL(win->src.window, sel_registerName("deminiaturize:"), NULL); RGFW_window_show(win); } RGFW_bool RGFW_window_isFloating(RGFW_window * win) { RGFW_ASSERT(win != NULL); int level = ((int (*) (id, SEL))objc_msgSend) ((id) (win->src.window), (SEL) sel_registerName("level")); return level > kCGNormalWindowLevelKey; } void RGFW_window_setName(RGFW_window * win, const char *name){ RGFW_ASSERT(win != NULL); id str = NSString_stringWithUTF8String(name); objc_msgSend_void_id((id) win->src.window, sel_registerName("setTitle:"), str); } #ifndef RGFW_NO_PASSTHROUGH void RGFW_window_setMousePassthrough(RGFW_window * win, RGFW_bool passthrough) { objc_msgSend_void_bool(win->src.window, sel_registerName("setIgnoresMouseEvents:"), passthrough); } #endif void RGFW_window_setAspectRatio(RGFW_window * win, i32 w, i32 h) { if (w == 0 && h == 0) { w = 1; h = 1; }; ((void (*) (id, SEL, NSSize))objc_msgSend) ((id) win->src.window, sel_registerName("setContentAspectRatio:"), (NSSize) { (CGFloat) w, (CGFloat) h }); } void RGFW_window_setMinSize(RGFW_window * win, i32 w, i32 h) { ((void (*) (id, SEL, NSSize))objc_msgSend) ((id) win->src.window, sel_registerName("setMinSize:"), (NSSize) { (CGFloat) w, (CGFloat) h }); } void RGFW_window_setMaxSize(RGFW_window * win, i32 w, i32 h) { if (w == 0 && h == 0) { RGFW_monitor mon = RGFW_window_getMonitor(win); w = mon.mode.w; h = mon.mode.h; } ((void (*) (id, SEL, NSSize))objc_msgSend) ((id) win->src.window, sel_registerName("setMaxSize:"), (NSSize) { (CGFloat) w, (CGFloat) h }); } RGFW_bool RGFW_window_setIconEx(RGFW_window * win, u8 * data, i32 w, i32 h, RGFW_format format, RGFW_icon type) { RGFW_ASSERT(win != NULL); RGFW_UNUSED(type); if (data == NULL) { objc_msgSend_void_id((id) _RGFW->NSApp, sel_registerName("setApplicationIconImage:"), NULL); return RGFW_TRUE; } id representation = NSBitmapImageRep_initWithBitmapData(NULL, w, h, 8, (NSInteger) 4, true, false, "NSCalibratedRGBColorSpace", 1 << 1, w * 4, 32); RGFW_copyImageData(NSBitmapImageRep_bitmapData(representation), w, h, RGFW_formatRGBA8, data, format); id dock_image = ((id(*) (id, SEL, NSSize)) objc_msgSend) (NSAlloc((id) objc_getClass("NSImage")), sel_registerName("initWithSize:"), ((NSSize) {(CGFloat) w, (CGFloat) h})); objc_msgSend_void_id(dock_image, sel_registerName("addRepresentation:"), representation); objc_msgSend_void_id((id) _RGFW->NSApp, sel_registerName("setApplicationIconImage:"), dock_image); NSRelease(dock_image); NSRelease(representation); return RGFW_TRUE; } id NSCursor_arrowStr(const char *str){ void *nclass = objc_getClass("NSCursor"); SEL func = sel_registerName(str); return (id) objc_msgSend_id(nclass, func); } RGFW_mouse *RGFW_loadMouse(u8 * data, i32 w, i32 h, RGFW_format format) { if (data == NULL) { objc_msgSend_void(NSCursor_arrowStr("arrowCursor"), sel_registerName("set")); return NULL; } id representation = (id) NSBitmapImageRep_initWithBitmapData(NULL, w, h, 8, (NSInteger) 4, true, false, "NSCalibratedRGBColorSpace", 1 << 1, w * 4, 32); RGFW_copyImageData(NSBitmapImageRep_bitmapData(representation), w, h, RGFW_formatRGBA8, data, format); id cursor_image = ((id(*) (id, SEL, NSSize)) objc_msgSend) (NSAlloc((id) objc_getClass("NSImage")), sel_registerName("initWithSize:"), ((NSSize) {(CGFloat) w, (CGFloat) h})); objc_msgSend_void_id(cursor_image, sel_registerName("addRepresentation:"), representation); id cursor = (id) ((id(*) (id, SEL, id, NSPoint)) objc_msgSend) (NSAlloc(objc_getClass("NSCursor")), sel_registerName("initWithImage:hotSpot:"), cursor_image, (NSPoint) {0.0, 0.0}); NSRelease(cursor_image); NSRelease(representation); return (void *)cursor; } void RGFW_window_setMouse(RGFW_window * win, RGFW_mouse * mouse) { RGFW_ASSERT(win != NULL); RGFW_ASSERT(mouse); CGDisplayShowCursor(kCGDirectMainDisplay); objc_msgSend_void((id) mouse, sel_registerName("set")); win->src.mouse = mouse; } void RGFW_freeMouse(RGFW_mouse * mouse) { RGFW_ASSERT(mouse); NSRelease((id) mouse); } RGFW_bool RGFW_window_setMouseDefault(RGFW_window * win) { return RGFW_window_setMouseStandard(win, RGFW_mouseArrow); } void RGFW_window_showMouse(RGFW_window * win, RGFW_bool show) { RGFW_window_showMouseFlags(win, show); if (show) CGDisplayShowCursor(kCGDirectMainDisplay); else CGDisplayHideCursor(kCGDirectMainDisplay); } RGFW_bool RGFW_window_setMouseStandard(RGFW_window * win, u8 stdMouses) { static const char *mouseIconSrc[16] = {"arrowCursor", "arrowCursor", "IBeamCursor", "crosshairCursor", "pointingHandCursor", "resizeLeftRightCursor", "resizeUpDownCursor", "_windowResizeNorthWestSouthEastCursor", "_windowResizeNorthEastSouthWestCursor", "closedHandCursor", "operationNotAllowedCursor"}; if (stdMouses > ((sizeof(mouseIconSrc)) / (sizeof(char *)))) return RGFW_FALSE; const char *mouseStr = mouseIconSrc[stdMouses]; id mouse = NSCursor_arrowStr(mouseStr); if (mouse == NULL) return RGFW_FALSE; RGFW_UNUSED(win); CGDisplayShowCursor(kCGDirectMainDisplay); objc_msgSend_void(mouse, sel_registerName("set")); win->src.mouse = mouse; return RGFW_TRUE; } void RGFW_releaseCursor(RGFW_window * win) { RGFW_UNUSED(win); CGAssociateMouseAndMouseCursorPosition(1); } void RGFW_captureCursor(RGFW_window * win) { RGFW_UNUSED(win); CGWarpMouseCursorPosition((CGPoint) { (CGFloat) (win->x + (win->w / 2)), (CGFloat) (win->y + (win->h / 2)) }); CGAssociateMouseAndMouseCursorPosition(0); } void RGFW_window_moveMouse(RGFW_window * win, i32 x, i32 y) { RGFW_UNUSED(win); win->internal.lastMouseX = x - win->x; win->internal.lastMouseY = y - win->y; CGWarpMouseCursorPosition((CGPoint) { (CGFloat) x, (CGFloat) y }); } void RGFW_window_hide(RGFW_window * win) { objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), false); } void RGFW_window_show(RGFW_window * win) { if (win->internal.flags & RGFW_windowFocusOnShow) ((id(*) (id, SEL, SEL)) objc_msgSend) ((id) win->src.window, sel_registerName("makeKeyAndOrderFront:"), NULL); ((id(*) (id, SEL, SEL)) objc_msgSend) ((id) win->src.window, sel_registerName("orderFront:"), NULL); objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), true); } RGFW_bool RGFW_window_isHidden(RGFW_window * win) { RGFW_ASSERT(win != NULL); bool visible = objc_msgSend_bool(win->src.window, sel_registerName("isVisible")); return visible == NO && !RGFW_window_isMinimized(win); } RGFW_bool RGFW_window_isMinimized(RGFW_window * win) { RGFW_ASSERT(win != NULL); return objc_msgSend_bool(win->src.window, sel_registerName("isMiniaturized")) == YES; } RGFW_bool RGFW_window_isMaximized(RGFW_window * win) { RGFW_ASSERT(win != NULL); RGFW_bool b = (RGFW_bool) objc_msgSend_bool(win->src.window, sel_registerName("isZoomed")); return b; } id RGFW_getNSScreenForDisplayID(CGDirectDisplayID display) { Class NSScreenClass = objc_getClass("NSScreen"); id screens = objc_msgSend_id(NSScreenClass, sel_registerName("screens")); NSUInteger count = (NSUInteger) objc_msgSend_uint(screens, sel_registerName("count")); NSUInteger i; for (i = 0; i < count; i++) { id screen = ((id(*) (id, SEL, int)) objc_msgSend) (screens, sel_registerName("objectAtIndex:"), (int)i); id description = objc_msgSend_id(screen, sel_registerName("deviceDescription")); id screenNumberKey = NSString_stringWithUTF8String("NSScreenNumber"); id screenNumber = objc_msgSend_id_id(description, sel_registerName("objectForKey:"), screenNumberKey); if ((CGDirectDisplayID) objc_msgSend_uint(screenNumber, sel_registerName("unsignedIntValue")) == display) { return screen; } } return NULL; } u32 RGFW_osx_getFallbackRefreshRate(CGDirectDisplayID displayID); u32 RGFW_osx_getRefreshRate(CGDirectDisplayID display, CGDisplayModeRef mode) { if (mode) { u32 refreshRate = (u32) CGDisplayModeGetRefreshRate(mode); if (refreshRate != 0) return refreshRate; } #ifndef RGFW_NO_IOKIT u32 res = RGFW_osx_getFallbackRefreshRate(display); if (res != 0) return res; #else RGFW_UNUSED(display); #endif return 60; } RGFW_monitor RGFW_NSCreateMonitor(CGDirectDisplayID display, id screen) { RGFW_monitor monitor; const char name[] = "MacOS\0"; RGFW_MEMCPY(monitor.name, name, 6); CGRect bounds = CGDisplayBounds(display); monitor.x = (i32) bounds.origin.x; monitor.y = (i32) bounds.origin.y; monitor.mode.w = (i32) bounds.size.width; monitor.mode.h = (i32) bounds.size.height; monitor.mode.red = 8; monitor.mode.green = 8; monitor.mode.blue = 8; CGDisplayModeRef mode = CGDisplayCopyDisplayMode(display); monitor.mode.refreshRate = RGFW_osx_getRefreshRate(display, mode); CFRelease(mode); CGSize screenSizeMM = CGDisplayScreenSize(display); monitor.physW = (float)screenSizeMM.width / 25.4f; monitor.physH = (float)screenSizeMM.height / 25.4f; float ppi_width = (monitor.mode.w / monitor.physW); float ppi_height = (monitor.mode.h / monitor.physH); monitor.pixelRatio = (float)((CGFloat(*) (id, SEL)) abi_objc_msgSend_fpret) (screen, sel_registerName("backingScaleFactor")); float dpi = 96.0f * monitor.pixelRatio; monitor.scaleX = ((i32) (((float)(ppi_width) / dpi) * 10.0f)) / 10.0f; monitor.scaleY = ((i32) (((float)(ppi_height) / dpi) * 10.0f)) / 10.0f; RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, "monitor found"); return monitor; } RGFW_monitor *RGFW_getMonitors(size_t * len) { static CGDirectDisplayID displays[7]; u32 count; if (CGGetActiveDisplayList(6, displays, &count) != kCGErrorSuccess) return NULL; if (count > 6) count = 6; static RGFW_monitor monitors[7]; u32 i; for (i = 0; i < count; i++) monitors[i] = RGFW_NSCreateMonitor(displays[i], RGFW_getNSScreenForDisplayID(displays[i])); if (len != NULL) *len = count; return monitors; } RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { CGPoint point = {(CGFloat) mon.x, (CGFloat) mon.y}; CGDirectDisplayID display; u32 displayCount = 0; CGError err = CGGetDisplaysWithPoint(point, 1, &display, &displayCount); if (err != kCGErrorSuccess || displayCount != 1) return RGFW_FALSE; CFArrayRef allModes = CGDisplayCopyAllDisplayModes(display, NULL); if (allModes == NULL) return RGFW_FALSE; CFIndex i; for (i = 0; i < CFArrayGetCount(allModes); i++) { CGDisplayModeRef cmode = (CGDisplayModeRef) CFArrayGetValueAtIndex(allModes, i); RGFW_monitorMode foundMode; foundMode.w = (i32) CGDisplayModeGetWidth(cmode); foundMode.h = (i32) CGDisplayModeGetHeight(cmode); foundMode.refreshRate = RGFW_osx_getRefreshRate(display, cmode); foundMode.red = 8; foundMode.green = 8; foundMode.blue = 8; if (RGFW_monitorModeCompare(mode, foundMode, request)) { if (CGDisplaySetDisplayMode(display, cmode, NULL) == kCGErrorSuccess) { CFRelease(allModes); return RGFW_TRUE; } break; } } CFRelease(allModes); return RGFW_FALSE; } RGFW_monitor RGFW_getPrimaryMonitor(void){ CGDirectDisplayID primary = CGMainDisplayID(); return RGFW_NSCreateMonitor(primary, RGFW_getNSScreenForDisplayID(primary)); } RGFW_monitor RGFW_window_getMonitor(RGFW_window * win) { id screen = objc_msgSend_id(win->src.window, sel_registerName("screen")); id description = objc_msgSend_id(screen, sel_registerName("deviceDescription")); id screenNumberKey = NSString_stringWithUTF8String("NSScreenNumber"); id screenNumber = objc_msgSend_id_id(description, sel_registerName("objectForKey:"), screenNumberKey); CGDirectDisplayID display = (CGDirectDisplayID) objc_msgSend_uint(screenNumber, sel_registerName("unsignedIntValue")); return RGFW_NSCreateMonitor(display, screen); } RGFW_ssize_t RGFW_readClipboardPtr(char *str, size_t strCapacity){ size_t clip_len; char *clip = (char *)NSPasteboard_stringForType(NSPasteboard_generalPasteboard(), NSPasteboardTypeString, &clip_len); if (clip == NULL) return -1; if (str != NULL) { if (strCapacity < clip_len) return 0; RGFW_MEMCPY(str, clip, clip_len); str[clip_len] = '\0'; } return (RGFW_ssize_t) clip_len; } void RGFW_writeClipboard(const char *text, u32 textLen){ RGFW_UNUSED(textLen); NSPasteboardType array[] = {NSPasteboardTypeString, NULL}; NSPasteBoard_declareTypes(NSPasteboard_generalPasteboard(), array, 1, NULL); SEL func = sel_registerName("setString:forType:"); ((bool (*) (id, SEL, id, id))objc_msgSend) (NSPasteboard_generalPasteboard(), func, NSString_stringWithUTF8String(text), NSString_stringWithUTF8String((const char *)NSPasteboardTypeString)); } #ifdef RGFW_OPENGL void NSOpenGLContext_setValues(id context, const int *vals, NSOpenGLContextParameter param); void NSOpenGLContext_setValues(id context, const int *vals, NSOpenGLContextParameter param){ ((void (*) (id, SEL, const int *, NSOpenGLContextParameter))objc_msgSend) (context, sel_registerName("setValues:forParameter:"), vals, param); } /* * MacOS OpenGL API spares us yet again (there are no * extensions) */ RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char *extension, size_t len){ RGFW_UNUSED(extension); RGFW_UNUSED(len); return RGFW_FALSE; } RGFW_proc RGFW_getProcAddress_OpenGL(const char *procname){ static CFBundleRef RGFWnsglFramework = NULL; if (RGFWnsglFramework == NULL) RGFWnsglFramework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault, procname, kCFStringEncodingASCII); RGFW_proc symbol = (RGFW_proc) CFBundleGetFunctionPointerForName(RGFWnsglFramework, symbolName); CFRelease(symbolName); return symbol; } RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window * win, RGFW_glContext * ctx, RGFW_glHints * hints) { win->src.ctx.native = ctx; win->src.gfxType = RGFW_gfxNativeOpenGL; i32 attribs[40]; size_t render_type_index = 0; { RGFW_attribStack stack; RGFW_attribStack_init(&stack, attribs, 40); i32 colorBits = (i32) (hints->red + hints->green + hints->blue + hints->alpha) / 4; RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAColorSize, colorBits); RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAAlphaSize, hints->alpha); RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFADepthSize, hints->depth); RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAStencilSize, hints->stencil); RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAAuxBuffers, hints->auxBuffers); RGFW_attribStack_pushAttrib(&stack, NSOpenGLPFAClosestPolicy); if (hints->samples) { RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFASampleBuffers, 1); RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFASamples, hints->samples); } else RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFASampleBuffers, 0); if (hints->doubleBuffer) RGFW_attribStack_pushAttrib(&stack, NSOpenGLPFADoubleBuffer); #ifdef RGFW_COCOA_GRAPHICS_SWITCHING RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAAllowOfflineRenderers, kCGLPFASupportsAutomaticGraphicsSwitching) #endif #if MAC_OS_X_VERSION_MAX_ALLOWED < 101200 if (hints->stereo] ) RGFW_attribStack_pushAttrib(&stack, NSOpenGLPFAStereo); #endif /* * macOS has the surface attribs and * the OpenGL attribs connected for * some reason maybe this is to give * macOS more control to limit * openGL/the OpenGL version? */ RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAOpenGLProfile, (hints->major >= 4) ? NSOpenGLProfileVersion4_1Core : (hints->major >= 3) ? NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy); if (hints->major <= 2) { i32 accumSize = (i32) (hints->accumRed + hints->accumGreen + hints->accumBlue + hints->accumAlpha) / 4; RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAAccumSize, accumSize); } if (hints->renderer == RGFW_glSoftware) { RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFARendererID, kCGLRendererGenericFloatID); } else { RGFW_attribStack_pushAttrib(&stack, NSOpenGLPFAAccelerated); } render_type_index = stack.count - 1; RGFW_attribStack_pushAttribs(&stack, 0, 0); } void *format = (void *)((id(*) (id, SEL, const u32 *)) objc_msgSend) (NSAlloc((id) objc_getClass("NSOpenGLPixelFormat")), sel_registerName("initWithAttributes:"), (u32 *) attribs); if (format == NULL) { RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load pixel format for OpenGL"); assert(render_type_index + 3 < (sizeof(attribs) / sizeof(attribs[0]))); attribs[render_type_index] = NSOpenGLPFARendererID; attribs[render_type_index + 1] = kCGLRendererGenericFloatID; attribs[render_type_index + 3] = 0; format = (void *)((id(*) (id, SEL, const u32 *)) objc_msgSend) (NSAlloc((id) objc_getClass("NSOpenGLPixelFormat")), sel_registerName("initWithAttributes:"), (u32 *) attribs); if (format == NULL) RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "and loading software rendering OpenGL failed"); else RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, "Switching to software rendering"); } /* * the pixel format can be passed directly to * OpenGL context creation to create a context * this is because the format also includes * information about the OpenGL version (which * may be a bad thing) */ if (win->src.view) NSRelease(win->src.view); win->src.view = (id) ((id(*) (id, SEL, NSRect, u32 *)) objc_msgSend) (NSAlloc(_RGFW->customViewClasses[1]), sel_registerName("initWithFrame:pixelFormat:"), (NSRect) {{0, 0}, {(double)win->w, (double)win->h}}, (u32 *) format); id share = NULL; if (hints->share) { share = (id) hints->share->ctx; } win->src.ctx.native->ctx = ((id(*) (id, SEL, id, id)) objc_msgSend) (NSAlloc(objc_getClass("NSOpenGLContext")), sel_registerName("initWithFormat:shareContext:"), (id) format, share); objc_msgSend_void_id(win->src.view, sel_registerName("setOpenGLContext:"), win->src.ctx.native->ctx); if (win->internal.flags & RGFW_windowTransparent) { i32 opacity = 0; #define NSOpenGLCPSurfaceOpacity 236 NSOpenGLContext_setValues((id) win->src.ctx.native->ctx, &opacity, (NSOpenGLContextParameter) NSOpenGLCPSurfaceOpacity); } objc_msgSend_void(win->src.ctx.native->ctx, sel_registerName("makeCurrentContext")); objc_msgSend_void_id((id) win->src.window, sel_registerName("setContentView:"), win->src.view); objc_msgSend_void_bool(win->src.view, sel_registerName("setWantsLayer:"), true); objc_msgSend_int((id) win->src.view, sel_registerName("setLayerContentsPlacement:"), 4); RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized."); return RGFW_TRUE; } void RGFW_window_deleteContextPtr_OpenGL(RGFW_window * win, RGFW_glContext * ctx) { objc_msgSend_void(ctx->ctx, sel_registerName("release")); win->src.ctx.native->ctx = NULL; RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context freed."); } void RGFW_window_makeCurrentContext_OpenGL(RGFW_window * win) { if (win) RGFW_ASSERT(win->src.ctx.native); if (win != NULL) objc_msgSend_void(win->src.ctx.native->ctx, sel_registerName("makeCurrentContext")); else objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("clearCurrentContext")); } void *RGFW_getCurrentContext_OpenGL(void){ return objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("currentContext")); } void RGFW_window_swapBuffers_OpenGL(RGFW_window * win) { RGFW_ASSERT(win && win->src.ctx.native); objc_msgSend_void(win->src.ctx.native->ctx, sel_registerName("flushBuffer")); } void RGFW_window_swapInterval_OpenGL(RGFW_window * win, i32 swapInterval) { RGFW_ASSERT(win != NULL && win->src.ctx.native != NULL); NSOpenGLContext_setValues((id) win->src.ctx.native->ctx, &swapInterval, (NSOpenGLContextParameter) 222); } #endif void RGFW_deinitPlatform(void){ } void RGFW_window_closePlatform(RGFW_window * win) { NSRelease(win->src.view); } #ifdef RGFW_WEBGPU WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window * window, WGPUInstance instance) { WGPUSurfaceDescriptor surfaceDesc = {0}; id *nsView = (id *) window->src.view; if (!nsView) { fprintf(stderr, "RGFW Error: NSView is NULL for macOS window.\n"); return NULL; } ((void (*) (id, SEL, BOOL))objc_msgSend) (nsView, sel_registerName("setWantsLayer:"), YES); id layer = ((id(*) (id, SEL)) objc_msgSend) (nsView, sel_registerName("layer")); void *metalLayer = RGFW_getLayer_OSX(); if (metalLayer == NULL) { return NULL; } ((void (*) (id, SEL, id))objc_msgSend) ((id) nsView, sel_registerName("setLayer:"), metalLayer); layer = metalLayer; /* Use the newly created * layer */ /* * At this point, 'layer' should be a valid * CAMetalLayer* */ WGPUSurfaceSourceMetalLayer fromMetal = {0}; fromMetal.chain.sType = WGPUSType_SurfaceSourceMetalLayer; #ifdef __OBJC__ fromMetal.layer = (__bridge CAMetalLayer *) layer; /* Use __bridge for ARC * compatibility if * mixing C/Obj-C */ #else fromMetal.layer = layer; #endif surfaceDesc.nextInChain = (WGPUChainedStruct *) & fromMetal.chain; return wgpuInstanceCreateSurface(instance, &surfaceDesc); } #endif #endif /* RGFW_MACOS */ /* * End of MaOS defines */ /* * WASM defines */ #ifdef RGFW_WASM EM_BOOL Emscripten_on_resize(int eventType, const EmscriptenUiEvent * E, void *userData){ RGFW_UNUSED(eventType); RGFW_UNUSED(userData); if (!(_RGFW->root->internal.enabledEvents & RGFW_windowResizedFlag)) return EM_TRUE; RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e.common.win = _RGFW->root); RGFW_windowResizedCallback(_RGFW->root, E->windowInnerWidth, E->windowInnerHeight); return EM_TRUE; } EM_BOOL Emscripten_on_fullscreenchange(int eventType, const EmscriptenFullscreenChangeEvent * E, void *userData){ RGFW_UNUSED(eventType); RGFW_UNUSED(userData); if (!(_RGFW->root->internal.enabledEvents & RGFW_windowResizedFlag)) return EM_TRUE; static u8 fullscreen = RGFW_FALSE; static i32 originalW, originalH; if (fullscreen == RGFW_FALSE) { originalW = _RGFW->root->w; originalH = _RGFW->root->h; } fullscreen = !fullscreen; RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e.common.win = _RGFW->root); _RGFW->root->w = E->screenWidth; _RGFW->root->h = E->screenHeight; EM_ASM("Module.canvas.focus();"); if (fullscreen == RGFW_FALSE) { _RGFW->root->w = originalW; _RGFW->root->h = originalH; } else { #if __EMSCRIPTEN_major__ >= 1 && __EMSCRIPTEN_minor__ >= 29 && __EMSCRIPTEN_tiny__ >= 0 EmscriptenFullscreenStrategy FSStrat = {0}; FSStrat.scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH; FSStrat.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF; FSStrat.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT; emscripten_request_fullscreen_strategy("#canvas", 1, &FSStrat); #else emscripten_request_fullscreen("#canvas", 1); #endif } emscripten_set_canvas_element_size("#canvas", _RGFW->root->w, _RGFW->root->h); RGFW_windowResizedCallback(_RGFW->root, _RGFW->root->w, _RGFW->root->h); return EM_TRUE; } EM_BOOL Emscripten_on_focusin(int eventType, const EmscriptenFocusEvent * E, void *userData){ RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(E); if (!(_RGFW->root->internal.enabledEvents & RGFW_focusInFlag)) return EM_TRUE; RGFW_eventQueuePushEx(e.type = RGFW_focusIn; e.common.win = _RGFW->root); _RGFW->root->internal.inFocus = RGFW_TRUE; RGFW_focusCallback(_RGFW->root, 1); if ((_RGFW->root->internal.holdMouse)) RGFW_window_holdMouse(_RGFW->root); return EM_TRUE; } EM_BOOL Emscripten_on_focusout(int eventType, const EmscriptenFocusEvent * E, void *userData){ RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(E); if (!(_RGFW->root->internal.enabledEvents & RGFW_focusOutFlag)) return EM_TRUE; RGFW_eventQueuePushEx(e.type = RGFW_focusOut; e.common.win = _RGFW->root); RGFW_window_focusLost(_RGFW->root); RGFW_focusCallback(_RGFW->root, 0); return EM_TRUE; } EM_BOOL Emscripten_on_mousemove(int eventType, const EmscriptenMouseEvent * E, void *userData){ RGFW_UNUSED(eventType); RGFW_UNUSED(userData); if (!(_RGFW->root->internal.enabledEvents & RGFW_mousePosChangedFlag)) return EM_TRUE; RGFW_eventQueuePushEx(e.type = RGFW_mousePosChanged; e.mouse.x = E->targetX; e.mouse.y = E->targetY; e.mouse.vecX = E->movementX; e.mouse.vecY = E->movementY; e.common.win = _RGFW->root); _RGFW->vectorX = E->movementX; _RGFW->vectorY = E->movementY; _RGFW->root->internal.lastMouseX = E->targetX; _RGFW->root->internal.lastMouseY = E->targetY; RGFW_mousePosCallback(_RGFW->root, E->targetX, E->targetY, E->movementX, E->movementY); return EM_TRUE; } EM_BOOL Emscripten_on_mousedown(int eventType, const EmscriptenMouseEvent * E, void *userData){ RGFW_UNUSED(eventType); RGFW_UNUSED(userData); if (!(_RGFW->root->internal.enabledEvents & RGFW_mouseButtonPressedFlag)) return EM_TRUE; int button = E->button; if (button > 2) button += 2; RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonPressed; e.mouse.x = E->targetX; e.mouse.y = E->targetY; e.mouse.vecX = E->movementX; e.mouse.vecY = E->movementY; e.button.value = (u8) button; e.common.win = _RGFW->root); _RGFW->vectorX = E->movementX; _RGFW->vectorY = E->movementY; _RGFW->mouseButtons[button].prev = _RGFW->mouseButtons[button].current; _RGFW->mouseButtons[button].current = 1; RGFW_mouseButtonCallback(_RGFW->root, button, 1); return EM_TRUE; } EM_BOOL Emscripten_on_mouseup(int eventType, const EmscriptenMouseEvent * E, void *userData){ RGFW_UNUSED(eventType); RGFW_UNUSED(userData); if (!(_RGFW->root->internal.enabledEvents & RGFW_mouseButtonReleasedFlag)) return EM_TRUE; int button = E->button; if (button > 2) button += 2; RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonReleased; e.mouse.x = E->targetX; e.mouse.y = E->targetY; e.mouse.vecX = E->movementX; e.mouse.vecY = E->movementY; e.button.value = (u8) button; e.common.win = _RGFW->root); _RGFW->vectorX = E->movementX; _RGFW->vectorY = E->movementY; _RGFW->mouseButtons[button].prev = _RGFW->mouseButtons[button].current; _RGFW->mouseButtons[button].current = 0; RGFW_mouseButtonCallback(_RGFW->root, button, 0); return EM_TRUE; } EM_BOOL Emscripten_on_wheel(int eventType, const EmscriptenWheelEvent * E, void *userData){ RGFW_UNUSED(eventType); RGFW_UNUSED(userData); if (!(_RGFW->root->internal.enabledEvents & RGFW_mouseScrollFlag)) return EM_TRUE; _RGFW->scrollX = E->deltaX; _RGFW->scrollY = E->deltaY; RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonPressed; e.scroll.x = E->deltaX; e.scroll.y = E->deltaY; ); RGFW_mouseScrollCallback(_RGFW->root, E->deltaX, E->deltaY); return EM_TRUE; } EM_BOOL Emscripten_on_touchstart(int eventType, const EmscriptenTouchEvent * E, void *userData){ RGFW_UNUSED(eventType); RGFW_UNUSED(userData); if (!(_RGFW->root->internal.enabledEvents & RGFW_mouseButtonPressedFlag)) return EM_TRUE; size_t i; for (i = 0; i < (size_t) E->numTouches; i++) { RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonPressed; e.mouse.x = E->touches[i].targetX; e.mouse.y = E->touches[i].targetY; e.button.value = RGFW_mouseLeft; e.common.win = _RGFW->root); _RGFW->mouseButtons[RGFW_mouseLeft].prev = _RGFW->mouseButtons[RGFW_mouseLeft].current; _RGFW->mouseButtons[RGFW_mouseLeft].current = 1; _RGFW->root->internal.lastMouseX = E->touches[i].targetX; _RGFW->root->internal.lastMouseX = E->touches[i].targetY; RGFW_mousePosCallback(_RGFW->root, E->touches[i].targetX, E->touches[i].targetY, 0, 0); RGFW_mouseButtonCallback(_RGFW->root, RGFW_mouseLeft, 1); } return EM_TRUE; } EM_BOOL Emscripten_on_touchmove(int eventType, const EmscriptenTouchEvent * E, void *userData){ RGFW_UNUSED(eventType); RGFW_UNUSED(userData); if (!(_RGFW->root->internal.enabledEvents & RGFW_mousePosChangedFlag)) return EM_TRUE; size_t i; for (i = 0; i < (size_t) E->numTouches; i++) { RGFW_eventQueuePushEx(e.type = RGFW_mousePosChanged; e.mouse.x = E->touches[i].targetX; e.mouse.y = E->touches[i].targetY; e.mouse.x = E->touches[i].targetX; e.mouse.y = E->touches[i].targetY; e.button.value = RGFW_mouseLeft; e.common.win = _RGFW->root); _RGFW->root->internal.lastMouseX = E->touches[i].targetX; _RGFW->root->internal.lastMouseX = E->touches[i].targetY; RGFW_mousePosCallback(_RGFW->root, E->touches[i].targetX, E->touches[i].targetY, 0, 0); } return EM_TRUE; } EM_BOOL Emscripten_on_touchend(int eventType, const EmscriptenTouchEvent * E, void *userData){ RGFW_UNUSED(eventType); RGFW_UNUSED(userData); if (!(_RGFW->root->internal.enabledEvents & RGFW_mouseButtonReleasedFlag)) return EM_TRUE; size_t i; for (i = 0; i < (size_t) E->numTouches; i++) { RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonReleased; e.mouse.x = E->touches[i].targetX; e.mouse.y = E->touches[i].targetY; e.button.value = RGFW_mouseLeft; e.common.win = _RGFW->root); _RGFW->mouseButtons[RGFW_mouseLeft].prev = _RGFW->mouseButtons[RGFW_mouseLeft].current; _RGFW->mouseButtons[RGFW_mouseLeft].current = 0; _RGFW->root->internal.lastMouseX = E->touches[i].targetX; _RGFW->root->internal.lastMouseY = E->touches[i].targetY; RGFW_mousePosCallback(_RGFW->root, E->touches[i].targetX, E->touches[i].targetY, 0, 0); RGFW_mouseButtonCallback(_RGFW->root, RGFW_mouseLeft, 0); } return EM_TRUE; } EM_BOOL Emscripten_on_touchcancel(int eventType, const EmscriptenTouchEvent * E, void *userData){ RGFW_UNUSED(eventType); RGFW_UNUSED(userData); return EM_TRUE; } u32 RGFW_WASMPhysicalToRGFW(u32 hash); void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyEvent(char *key, char *code, RGFW_bool press){ const char *iCode = code; u32 hash = 0; while (*iCode) hash = ((hash ^ 0x7E057D79U) << 3) ^ (unsigned int)*iCode++; u32 physicalKey = RGFW_WASMPhysicalToRGFW(hash); u8 mappedKey = (u8) (*((u32 *) key)); if (*((u16 *) key) != mappedKey) { mappedKey = 0; if (*((u32 *) key) == *((u32 *) "Tab")) mappedKey = RGFW_tab; } if (!(press ? (_RGFW->root->internal.enabledEvents & RGFW_keyPressedFlag) : (_RGFW->root->internal.enabledEvents & RGFW_keyReleasedFlag))) return; RGFW_eventQueuePushEx(e.type = (RGFW_eventType) (press ? RGFW_keyPressed : RGFW_keyReleased); e.key.value = (u8) physicalKey; e.key.sym = (u8) mappedKey; e.key.mod = _RGFW->root->internal.mod; e.key.repeat = RGFW_window_isKeyDown(_RGFW->root, (u8) physicalKey); e.common.win = _RGFW->root); _RGFW->keyboard[physicalKey].prev = _RGFW->keyboard[physicalKey].current; _RGFW->keyboard[physicalKey].current = press; RGFW_keyCallback(_RGFW->root, physicalKey, mappedKey, _RGFW->root->internal.mod, RGFW_window_isKeyDown(_RGFW->root, (u8) physicalKey), press); } void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyMods(RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll) { RGFW_updateKeyModsEx(_RGFW->root, capital, numlock, control, alt, shift, super, scroll); } void EMSCRIPTEN_KEEPALIVE Emscripten_onDrop(size_t count) { if (!(_RGFW->root->internal.flags & RGFW_windowAllowDND)) return; if (!(_RGFW->root->internal.enabledEvents & RGFW_dataDropFlag)) return; RGFW_eventQueuePushEx(e.type = RGFW_dataDrop; e.drop.count = count; e.common.win = _RGFW->root); _RGFW->windowState.win = _RGFW->root; _RGFW->windowState.dataDrop = RGFW_TRUE; _RGFW->windowState.filesCount = count; RGFW_dataDropCallback(_RGFW->root, _RGFW->files, count); } void RGFW_stopCheckEvents(void){ _RGFW->stopCheckEvents_bool = RGFW_TRUE; } RGFW_bool RGFW_createSurfacePtr(u8 * data, i32 w, i32 h, RGFW_format format, RGFW_surface * surface) { surface->data = data; surface->w = w; surface->h = h; surface->format = format; return RGFW_TRUE; } void RGFW_window_blitSurface(RGFW_window * win, RGFW_surface * surface) { /* TODO: Needs fixing. */ RGFW_copyImageData(surface->data, surface->w, RGFW_MIN(win->h, surface->h), RGFW_formatRGBA8, surface->data, surface->format); EM_ASM_({ var data = Module.HEAPU8.slice($0, $0 + $1 * $2 * 4); let context = document.getElementById("canvas").getContext("2d"); let image = context.getImageData(0, 0, $1, $2); image.data.set(data); context.putImageData(image, 0, $4 - $2); } ,surface->data, surface->w, surface->h, RGFW_MIN(win->h, surface->w), RGFW_MIN(win->h, surface->h)); } void RGFW_surface_freePtr(RGFW_surface * surface) { } void EMSCRIPTEN_KEEPALIVE RGFW_makeSetValue(size_t index, char *file){ /* * This seems like a terrible idea, don't * replicate this unless you hate yourself or * the OS */ /* * TODO: find a better way to do this */ RGFW_STRNCPY((char *)_RGFW->files[index], file, RGFW_MAX_PATH - 1); _RGFW->files[index][RGFW_MAX_PATH - 1] = '\0'; } #include #include #include #include void EMSCRIPTEN_KEEPALIVE RGFW_mkdir(char *name){ mkdir(name, 0755); } void EMSCRIPTEN_KEEPALIVE RGFW_writeFile(const char *path, const char *data, size_t len){ FILE *file = fopen(path, "w+"); if (file == NULL) return; fwrite(data, sizeof(char), len, file); fclose(file); } void RGFW_initKeycodesPlatform(void){ _RGFW->keycodes[DOM_VK_BACK_QUOTE] = RGFW_backtick; _RGFW->keycodes[DOM_VK_0] = RGFW_0; _RGFW->keycodes[DOM_VK_1] = RGFW_1; _RGFW->keycodes[DOM_VK_2] = RGFW_2; _RGFW->keycodes[DOM_VK_3] = RGFW_3; _RGFW->keycodes[DOM_VK_4] = RGFW_4; _RGFW->keycodes[DOM_VK_5] = RGFW_5; _RGFW->keycodes[DOM_VK_6] = RGFW_6; _RGFW->keycodes[DOM_VK_7] = RGFW_7; _RGFW->keycodes[DOM_VK_8] = RGFW_8; _RGFW->keycodes[DOM_VK_9] = RGFW_9; _RGFW->keycodes[DOM_VK_SPACE] = RGFW_space; _RGFW->keycodes[DOM_VK_A] = RGFW_a; _RGFW->keycodes[DOM_VK_B] = RGFW_b; _RGFW->keycodes[DOM_VK_C] = RGFW_c; _RGFW->keycodes[DOM_VK_D] = RGFW_d; _RGFW->keycodes[DOM_VK_E] = RGFW_e; _RGFW->keycodes[DOM_VK_F] = RGFW_f; _RGFW->keycodes[DOM_VK_G] = RGFW_g; _RGFW->keycodes[DOM_VK_H] = RGFW_h; _RGFW->keycodes[DOM_VK_I] = RGFW_i; _RGFW->keycodes[DOM_VK_J] = RGFW_j; _RGFW->keycodes[DOM_VK_K] = RGFW_k; _RGFW->keycodes[DOM_VK_L] = RGFW_l; _RGFW->keycodes[DOM_VK_M] = RGFW_m; _RGFW->keycodes[DOM_VK_N] = RGFW_n; _RGFW->keycodes[DOM_VK_O] = RGFW_o; _RGFW->keycodes[DOM_VK_P] = RGFW_p; _RGFW->keycodes[DOM_VK_Q] = RGFW_q; _RGFW->keycodes[DOM_VK_R] = RGFW_r; _RGFW->keycodes[DOM_VK_S] = RGFW_s; _RGFW->keycodes[DOM_VK_T] = RGFW_t; _RGFW->keycodes[DOM_VK_U] = RGFW_u; _RGFW->keycodes[DOM_VK_V] = RGFW_v; _RGFW->keycodes[DOM_VK_W] = RGFW_w; _RGFW->keycodes[DOM_VK_X] = RGFW_x; _RGFW->keycodes[DOM_VK_Y] = RGFW_y; _RGFW->keycodes[DOM_VK_Z] = RGFW_z; _RGFW->keycodes[DOM_VK_PERIOD] = RGFW_period; _RGFW->keycodes[DOM_VK_COMMA] = RGFW_comma; _RGFW->keycodes[DOM_VK_SLASH] = RGFW_slash; _RGFW->keycodes[DOM_VK_OPEN_BRACKET] = RGFW_bracket; _RGFW->keycodes[DOM_VK_CLOSE_BRACKET] = RGFW_closeBracket; _RGFW->keycodes[DOM_VK_SEMICOLON] = RGFW_semicolon; _RGFW->keycodes[DOM_VK_QUOTE] = RGFW_apostrophe; _RGFW->keycodes[DOM_VK_BACK_SLASH] = RGFW_backSlash; _RGFW->keycodes[DOM_VK_RETURN] = RGFW_return; _RGFW->keycodes[DOM_VK_DELETE] = RGFW_delete; _RGFW->keycodes[DOM_VK_NUM_LOCK] = RGFW_numLock; _RGFW->keycodes[DOM_VK_DIVIDE] = RGFW_kpSlash; _RGFW->keycodes[DOM_VK_MULTIPLY] = RGFW_kpMultiply; _RGFW->keycodes[DOM_VK_SUBTRACT] = RGFW_kpMinus; _RGFW->keycodes[DOM_VK_NUMPAD1] = RGFW_kp1; _RGFW->keycodes[DOM_VK_NUMPAD2] = RGFW_kp2; _RGFW->keycodes[DOM_VK_NUMPAD3] = RGFW_kp3; _RGFW->keycodes[DOM_VK_NUMPAD4] = RGFW_kp4; _RGFW->keycodes[DOM_VK_NUMPAD5] = RGFW_kp5; _RGFW->keycodes[DOM_VK_NUMPAD6] = RGFW_kp6; _RGFW->keycodes[DOM_VK_NUMPAD9] = RGFW_kp9; _RGFW->keycodes[DOM_VK_NUMPAD0] = RGFW_kp0; _RGFW->keycodes[DOM_VK_DECIMAL] = RGFW_kpPeriod; _RGFW->keycodes[DOM_VK_RETURN] = RGFW_kpReturn; _RGFW->keycodes[DOM_VK_HYPHEN_MINUS] = RGFW_minus; _RGFW->keycodes[DOM_VK_EQUALS] = RGFW_equals; _RGFW->keycodes[DOM_VK_BACK_SPACE] = RGFW_backSpace; _RGFW->keycodes[DOM_VK_TAB] = RGFW_tab; _RGFW->keycodes[DOM_VK_CAPS_LOCK] = RGFW_capsLock; _RGFW->keycodes[DOM_VK_SHIFT] = RGFW_shiftL; _RGFW->keycodes[DOM_VK_CONTROL] = RGFW_controlL; _RGFW->keycodes[DOM_VK_ALT] = RGFW_altL; _RGFW->keycodes[DOM_VK_META] = RGFW_superL; _RGFW->keycodes[DOM_VK_F1] = RGFW_F1; _RGFW->keycodes[DOM_VK_F2] = RGFW_F2; _RGFW->keycodes[DOM_VK_F3] = RGFW_F3; _RGFW->keycodes[DOM_VK_F4] = RGFW_F4; _RGFW->keycodes[DOM_VK_F5] = RGFW_F5; _RGFW->keycodes[DOM_VK_F6] = RGFW_F6; _RGFW->keycodes[DOM_VK_F7] = RGFW_F7; _RGFW->keycodes[DOM_VK_F8] = RGFW_F8; _RGFW->keycodes[DOM_VK_F9] = RGFW_F9; _RGFW->keycodes[DOM_VK_F10] = RGFW_F10; _RGFW->keycodes[DOM_VK_F11] = RGFW_F11; _RGFW->keycodes[DOM_VK_F12] = RGFW_F12; _RGFW->keycodes[DOM_VK_UP] = RGFW_up; _RGFW->keycodes[DOM_VK_DOWN] = RGFW_down; _RGFW->keycodes[DOM_VK_LEFT] = RGFW_left; _RGFW->keycodes[DOM_VK_RIGHT] = RGFW_right; _RGFW->keycodes[DOM_VK_INSERT] = RGFW_insert; _RGFW->keycodes[DOM_VK_END] = RGFW_end; _RGFW->keycodes[DOM_VK_PAGE_UP] = RGFW_pageUp; _RGFW->keycodes[DOM_VK_PAGE_DOWN] = RGFW_pageDown; _RGFW->keycodes[DOM_VK_ESCAPE] = RGFW_escape; _RGFW->keycodes[DOM_VK_HOME] = RGFW_home; _RGFW->keycodes[DOM_VK_SCROLL_LOCK] = RGFW_scrollLock; _RGFW->keycodes[DOM_VK_PRINTSCREEN] = RGFW_printScreen; _RGFW->keycodes[DOM_VK_PAUSE] = RGFW_pause; _RGFW->keycodes[DOM_VK_F13] = RGFW_F13; _RGFW->keycodes[DOM_VK_F14] = RGFW_F14; _RGFW->keycodes[DOM_VK_F15] = RGFW_F15; _RGFW->keycodes[DOM_VK_F16] = RGFW_F16; _RGFW->keycodes[DOM_VK_F17] = RGFW_F17; _RGFW->keycodes[DOM_VK_F18] = RGFW_F18; _RGFW->keycodes[DOM_VK_F19] = RGFW_F19; _RGFW->keycodes[DOM_VK_F20] = RGFW_F20; _RGFW->keycodes[DOM_VK_F21] = RGFW_F21; _RGFW->keycodes[DOM_VK_F22] = RGFW_F22; _RGFW->keycodes[DOM_VK_F23] = RGFW_F23; _RGFW->keycodes[DOM_VK_F24] = RGFW_F24; } i32 RGFW_initPlatform(void){ return 0; } RGFW_window *RGFW_createWindowPlatform(const char *name, RGFW_windowFlags flags, RGFW_window * win){ emscripten_set_canvas_element_size("#canvas", win->w, win->h); emscripten_set_window_title(name); /* load callbacks */ emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_resize); emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, NULL, EM_FALSE, Emscripten_on_fullscreenchange); emscripten_set_mousemove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousemove); emscripten_set_touchstart_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchstart); emscripten_set_touchend_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchend); emscripten_set_touchmove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchmove); emscripten_set_touchcancel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchcancel); emscripten_set_mousedown_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousedown); emscripten_set_mouseup_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mouseup); emscripten_set_wheel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_wheel); emscripten_set_focusin_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusin); emscripten_set_focusout_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusout); if (flags & RGFW_windowAllowDND) { win->internal.flags |= RGFW_windowAllowDND; } EM_ASM({ window.addEventListener("keydown", (event) = >{ var key = stringToNewUTF8(event.key); var code = stringToNewUTF8(event.code); Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta"), event.getModifierState("ScrollLock")); Module._RGFW_handleKeyEvent(key, code, 1); _free(key); _free(code); } , true); window.addEventListener("keyup", (event) = >{ var key = stringToNewUTF8(event.key); var code = stringToNewUTF8(event.code); Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta"), event.getModifierState("ScrollLock")); Module._RGFW_handleKeyEvent(key, code, 0); _free(key); _free(code); } , true); }); EM_ASM({ var canvas = document.getElementById('canvas'); canvas.addEventListener('drop', function(e) { e.preventDefault(); if (e.dataTransfer.file < 0) return; var filenamesArray =[]; var count = e.dataTransfer.files.length; /* * Read and save the files to * emscripten's files */ var drop_dir = '.rgfw_dropped_files'; Module._RGFW_mkdir(drop_dir); for (var i = 0; i < count; i++) { var file = e.dataTransfer.files[i]; var path = '/' + drop_dir + '/' + file.name.replace("//", '_'); var reader = new FileReader(); reader.onloadend = (e) = >{ if (reader.readyState != 2) { out('failed to read dropped file: ' + file.name + ': ' + reader.error); } else { var data = e.target.result; Module._RGFW_writeFile(path, new Uint8Array(data), file.size); } }; reader.readAsArrayBuffer(file); /* * This works weird on * modern OpenGL */ var filename = stringToNewUTF8(path); filenamesArray.push(filename); Module._RGFW_makeSetValue(i, filename); } Module._Emscripten_onDrop(count); for (var i = 0; i < count; ++i) { _free(filenamesArray[i]); } } ,true); canvas.addEventListener('dragover', function(e) { e.preventDefault(); return false; } ,true); }); return win; } u8 RGFW_rgfwToKeyChar(u32 rgfw_keycode) { return (u8) rgfw_keycode; /* TODO */ } void RGFW_pollEvents(void){ RGFW_resetPrevState(); } void RGFW_window_resize(RGFW_window * win, i32 w, i32 h) { RGFW_UNUSED(win); emscripten_set_canvas_element_size("#canvas", w, h); } /* NOTE: I don't know if this is possible */ void RGFW_window_moveMouse(RGFW_window * win, i32 x, i32 y) { RGFW_UNUSED(win); RGFW_UNUSED(x); RGFW_UNUSED(y); } /* this one might be possible but it looks iffy */ RGFW_mouse *RGFW_loadMouse(u8 * data, i32 w, i32 h, RGFW_format format) { RGFW_UNUSED(data); RGFW_UNUSED(w); RGFW_UNUSED(h); RGFW_UNUSED(format); return NULL; } void RGFW_window_setMouse(RGFW_window * win, RGFW_mouse * mouse) { RGFW_UNUSED(win); RGFW_UNUSED(mouse); } void RGFW_freeMouse(RGFW_mouse * mouse) { RGFW_UNUSED(mouse); } RGFW_bool RGFW_window_setMouseStandard(RGFW_window * win, u8 mouse) { static const char cursors[16][16] = { "default", "default", "text", "crosshair", "pointer", "ew-resize", "ns-resize", "nwse-resize", "nesw-resize", "move", "not-allowed" }; RGFW_UNUSED(win); EM_ASM({ document.getElementById("canvas").style.cursor = UTF8ToString($0); } ,cursors[mouse]); return RGFW_TRUE; } RGFW_bool RGFW_window_setMouseDefault(RGFW_window * win) { return RGFW_window_setMouseStandard(win, RGFW_mouseNormal); } void RGFW_window_showMouse(RGFW_window * win, RGFW_bool show) { RGFW_window_showMouseFlags(win, show); if (show) RGFW_window_setMouseDefault(win); else EM_ASM(document.getElementById('canvas').style.cursor = 'none'; ); } RGFW_bool RGFW_getGlobalMouse(i32 * x, i32 * y) { if (x) *x = EM_ASM_INT({ return window.mouseX || 0; }); if (y) *y = EM_ASM_INT({ return window.mouseY || 0; }); return RGFW_TRUE; } void RGFW_window_setMousePassthrough(RGFW_window * win, RGFW_bool passthrough) { RGFW_UNUSED(win); EM_ASM_({ var canvas = document.getElementById('canvas'); if ($0) { canvas.style.pointerEvents = 'none'; } else { canvas.style.pointerEvents = 'auto'; } } ,passthrough); } void RGFW_writeClipboard(const char *text, u32 textLen){ RGFW_UNUSED(textLen); EM_ASM({ navigator.clipboard.writeText(UTF8ToString($0)); } ,text); } RGFW_ssize_t RGFW_readClipboardPtr(char *str, size_t strCapacity){ RGFW_UNUSED(str); RGFW_UNUSED(strCapacity); /* * placeholder code for later I'm not sure if * this is possible do the the async stuff */ return 0; } #ifdef RGFW_OPENGL RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window * win, RGFW_glContext * ctx, RGFW_glHints * hints) { win->src.ctx.native = ctx; win->src.gfxType = RGFW_gfxNativeOpenGL; EmscriptenWebGLContextAttributes attrs; attrs.alpha = hints->alpha; attrs.depth = hints->depth; attrs.stencil = hints->stencil; attrs.antialias = hints->samples; attrs.premultipliedAlpha = EM_TRUE; attrs.preserveDrawingBuffer = EM_FALSE; if (hints->doubleBuffer == 0) attrs.renderViaOffscreenBackBuffer = 0; else attrs.renderViaOffscreenBackBuffer = hints->auxBuffers; attrs.failIfMajorPerformanceCaveat = EM_FALSE; attrs.majorVersion = (hints->major == 0) ? 1 : hints->major; attrs.minorVersion = hints->minor; attrs.enableExtensionsByDefault = EM_TRUE; attrs.explicitSwapControl = EM_TRUE; emscripten_webgl_init_context_attributes(&attrs); win->src.ctx.native->ctx = emscripten_webgl_create_context("#canvas", &attrs); emscripten_webgl_make_context_current(win->src.ctx.native->ctx); #ifdef LEGACY_GL_EMULATION EM_ASM("Module.useWebGL = true; GLImmediate.init();"); RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized."); #endif return RGFW_TRUE; } void RGFW_window_deleteContextPtr_OpenGL(RGFW_window * win, RGFW_glContext * ctx) { emscripten_webgl_destroy_context(ctx->ctx); win->src.ctx.native->ctx = 0; RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context freed."); } void RGFW_window_makeCurrentContext_OpenGL(RGFW_window * win) { if (win) RGFW_ASSERT(win->src.ctx.native); if (win == NULL) emscripten_webgl_make_context_current(0); else emscripten_webgl_make_context_current(win->src.ctx.native->ctx); } void RGFW_window_swapBuffers_OpenGL(RGFW_window * win) { RGFW_ASSERT(win && win->src.ctx.native); emscripten_webgl_commit_frame(); emscripten_sleep(0); } void *RGFW_getCurrentContext_OpenGL(void){ return (void *)emscripten_webgl_get_current_context(); } RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char *extension, size_t len){ return EM_ASM_INT({ var ext = UTF8ToString($0, $1); var canvas = document.querySelector('canvas'); var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); if (!gl) return 0; var supported = gl.getSupportedExtensions(); return supported && supported.includes(ext) ? 1 : 0; } ,extension, len); return RGFW_FALSE; } RGFW_proc RGFW_getProcAddress_OpenGL(const char *procname){ return (RGFW_proc) emscripten_webgl_get_proc_address(procname); return NULL; } #endif void RGFW_window_swapInterval_OpenGL(RGFW_window * win, i32 swapInterval) { RGFW_UNUSED(win); RGFW_UNUSED(swapInterval); } void RGFW_deinitPlatform(void){ } void RGFW_window_closePlatform(RGFW_window * win) { } int RGFW_innerWidth(void){ return EM_ASM_INT({ return window.innerWidth; }); } int RGFW_innerHeight(void){ return EM_ASM_INT({ return window.innerHeight; }); } void RGFW_releaseCursor(RGFW_window * win) { RGFW_UNUSED(win); emscripten_exit_pointerlock(); } void RGFW_captureCursor(RGFW_window * win) { RGFW_UNUSED(win); emscripten_request_pointerlock("#canvas", 1); } void RGFW_window_setName(RGFW_window * win, const char *name){ RGFW_UNUSED(win); emscripten_set_window_title(name); } void RGFW_window_maximize(RGFW_window * win) { RGFW_ASSERT(win != NULL); RGFW_monitor mon = RGFW_window_getMonitor(win); RGFW_window_move(win, 0, 0); RGFW_window_resize(win, mon.mode.w, mon.mode.h); } void RGFW_window_setFullscreen(RGFW_window * win, RGFW_bool fullscreen) { RGFW_ASSERT(win != NULL); if (fullscreen) { win->internal.flags |= RGFW_windowFullscreen; EM_ASM(Module.requestFullscreen(false, true); ); return; } win->internal.flags &= ~(u32) RGFW_windowFullscreen; EM_ASM(Module.exitFullscreen(false, true); ); } void RGFW_window_setOpacity(RGFW_window * win, u8 opacity) { RGFW_UNUSED(win); EM_ASM({ var element = document.getElementById("canvas"); if (element) element.style.opacity = $1; } ,"elementId", opacity); } #ifdef RGFW_WEBGPU WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window * window, WGPUInstance instance) { WGPUSurfaceDescriptor surfaceDesc = {0}; WGPUEmscriptenSurfaceSourceCanvasHTMLSelector canvasDesc = {0}; canvasDesc.chain.sType = WGPUSType_EmscriptenSurfaceSourceCanvasHTMLSelector; canvasDesc.selector = (WGPUStringView) {.data = "#canvas",.length = 7}; surfaceDesc.nextInChain = &canvasDesc.chain; return wgpuInstanceCreateSurface(instance, &surfaceDesc); } #endif u32 RGFW_WASMPhysicalToRGFW(u32 hash) { switch (hash) { /* 0x0000 */ case 0x67243A2DU /* Escape */ :return RGFW_escape; /* 0x0001 */ case 0x67251058U /* Digit0 */ :return RGFW_0; /* 0x0002 */ case 0x67251059U /* Digit1 */ :return RGFW_1; /* 0x0003 */ case 0x6725105AU /* Digit2 */ :return RGFW_2; /* 0x0004 */ case 0x6725105BU /* Digit3 */ :return RGFW_3; /* 0x0005 */ case 0x6725105CU /* Digit4 */ :return RGFW_4; /* 0x0006 */ case 0x6725105DU /* Digit5 */ :return RGFW_5; /* 0x0007 */ case 0x6725105EU /* Digit6 */ :return RGFW_6; /* 0x0008 */ case 0x6725105FU /* Digit7 */ :return RGFW_7; /* 0x0009 */ case 0x67251050U /* Digit8 */ :return RGFW_8; /* 0x000A */ case 0x67251051U /* Digit9 */ :return RGFW_9; /* 0x000B */ case 0x92E14DD3U /* Minus */ :return RGFW_minus; /* 0x000C */ case 0x92E1FBACU /* Equal */ :return RGFW_equals; /* 0x000D */ case 0x36BF1CB5U /* Backspace */ :return RGFW_backSpace; /* 0x000E */ case 0x7B8E51E2U /* Tab */ :return RGFW_tab; /* 0x000F */ case 0x2C595B51U /* KeyQ */ :return RGFW_q; /* 0x0010 */ case 0x2C595B57U /* KeyW */ :return RGFW_w; /* 0x0011 */ case 0x2C595B45U /* KeyE */ :return RGFW_e; /* 0x0012 */ case 0x2C595B52U /* KeyR */ :return RGFW_r; /* 0x0013 */ case 0x2C595B54U /* KeyT */ :return RGFW_t; /* 0x0014 */ case 0x2C595B59U /* KeyY */ :return RGFW_y; /* 0x0015 */ case 0x2C595B55U /* KeyU */ :return RGFW_u; /* 0x0016 */ case 0x2C595B4FU /* KeyO */ :return RGFW_o; /* 0x0018 */ case 0x2C595B50U /* KeyP */ :return RGFW_p; /* 0x0019 */ case 0x45D8158CU /* BracketLeft */ :return RGFW_closeBracket; /* 0x001A */ case 0xDEEABF7CU /* BracketRight */ :return RGFW_bracket; /* 0x001B */ case 0x92E1C5D2U /* Enter */ :return RGFW_return; /* 0x001C */ case 0xE058958CU /* ControlLeft */ :return RGFW_controlL; /* 0x001D */ case 0x2C595B41U /* KeyA */ :return RGFW_a; /* 0x001E */ case 0x2C595B53U /* KeyS */ :return RGFW_s; /* 0x001F */ case 0x2C595B44U /* KeyD */ :return RGFW_d; /* 0x0020 */ case 0x2C595B46U /* KeyF */ :return RGFW_f; /* 0x0021 */ case 0x2C595B47U /* KeyG */ :return RGFW_g; /* 0x0022 */ case 0x2C595B48U /* KeyH */ :return RGFW_h; /* 0x0023 */ case 0x2C595B4AU /* KeyJ */ :return RGFW_j; /* 0x0024 */ case 0x2C595B4BU /* KeyK */ :return RGFW_k; /* 0x0025 */ case 0x2C595B4CU /* KeyL */ :return RGFW_l; /* 0x0026 */ case 0x2707219EU /* Semicolon */ :return RGFW_semicolon; /* 0x0027 */ case 0x92E0B58DU /* Quote */ :return RGFW_apostrophe; /* 0x0028 */ case 0x36BF358DU /* Backquote */ :return RGFW_backtick; /* 0x0029 */ case 0x26B1958CU /* ShiftLeft */ :return RGFW_shiftL; /* 0x002A */ case 0x36BF2438U /* Backslash */ :return RGFW_backSlash; /* 0x002B */ case 0x2C595B5AU /* KeyZ */ :return RGFW_z; /* 0x002C */ case 0x2C595B58U /* KeyX */ :return RGFW_x; /* 0x002D */ case 0x2C595B43U /* KeyC */ :return RGFW_c; /* 0x002E */ case 0x2C595B56U /* KeyV */ :return RGFW_v; /* 0x002F */ case 0x2C595B42U /* KeyB */ :return RGFW_b; /* 0x0030 */ case 0x2C595B4EU /* KeyN */ :return RGFW_n; /* 0x0031 */ case 0x2C595B4DU /* KeyM */ :return RGFW_m; /* 0x0032 */ case 0x92E1A1C1U /* Comma */ :return RGFW_comma; /* 0x0033 */ case 0x672FFAD4U /* Period */ :return RGFW_period; /* 0x0034 */ case 0x92E0A438U /* Slash */ :return RGFW_slash; /* 0x0035 */ case 0xC5A6BF7CU /* ShiftRight */ :return RGFW_shiftR; case 0x5D64DA91U /* NumpadMultiply */ :return RGFW_kpMultiply; case 0xC914958CU /* AltLeft */ :return RGFW_altL; /* 0x0038 */ case 0x92E09CB5U /* Space */ :return RGFW_space; /* 0x0039 */ case 0xB8FAE73BU /* CapsLock */ :return RGFW_capsLock; /* 0x003A */ case 0x7174B789U /* F1 */ :return RGFW_F1; /* 0x003B */ case 0x7174B78AU /* F2 */ :return RGFW_F2; /* 0x003C */ case 0x7174B78BU /* F3 */ :return RGFW_F3; /* 0x003D */ case 0x7174B78CU /* F4 */ :return RGFW_F4; /* 0x003E */ case 0x7174B78DU /* F5 */ :return RGFW_F5; /* 0x003F */ case 0x7174B78EU /* F6 */ :return RGFW_F6; /* 0x0040 */ case 0x7174B78FU /* F7 */ :return RGFW_F7; /* 0x0041 */ case 0x7174B780U /* F8 */ :return RGFW_F8; /* 0x0042 */ case 0x7174B781U /* F9 */ :return RGFW_F9; /* 0x0043 */ case 0x7B8E57B0U /* F10 */ :return RGFW_F10; /* 0x0044 */ case 0xC925FCDFU /* Numpad7 */ :return RGFW_kpMultiply; /* 0x0047 */ case 0xC925FCD0U /* Numpad8 */ :return RGFW_kp8; /* 0x0048 */ case 0xC925FCD1U /* Numpad9 */ :return RGFW_kp9; /* 0x0049 */ case 0x5EA3E8A4U /* NumpadSubtract */ :return RGFW_minus; /* 0x004A */ case 0xC925FCDCU /* Numpad4 */ :return RGFW_kp4; /* 0x004B */ case 0xC925FCDDU /* Numpad5 */ :return RGFW_kp5; /* 0x004C */ case 0xC925FCDEU /* Numpad6 */ :return RGFW_kp6; /* 0x004D */ case 0xC925FCD9U /* Numpad1 */ :return RGFW_kp1; /* 0x004F */ case 0xC925FCDAU /* Numpad2 */ :return RGFW_kp2; /* 0x0050 */ case 0xC925FCDBU /* Numpad3 */ :return RGFW_kp3; /* 0x0051 */ case 0xC925FCD8U /* Numpad0 */ :return RGFW_kp0; /* 0x0052 */ case 0x95852DACU /* NumpadDecimal */ :return RGFW_period; /* 0x0053 */ case 0x7B8E57B1U /* F11 */ :return RGFW_F11; /* 0x0057 */ case 0x7B8E57B2U /* F12 */ :return RGFW_F12; /* 0x0058 */ case 0x7B8E57B3U /* F13 */ :return DOM_PK_F13; /* 0x0064 */ case 0x7B8E57B4U /* F14 */ :return DOM_PK_F14; /* 0x0065 */ case 0x7B8E57B5U /* F15 */ :return DOM_PK_F15; /* 0x0066 */ case 0x7B8E57B6U /* F16 */ :return DOM_PK_F16; /* 0x0067 */ case 0x7B8E57B7U /* F17 */ :return DOM_PK_F17; /* 0x0068 */ case 0x7B8E57B8U /* F18 */ :return DOM_PK_F18; /* 0x0069 */ case 0x7B8E57B9U /* F19 */ :return DOM_PK_F19; /* 0x006A */ case 0x7B8E57A8U /* F20 */ :return DOM_PK_F20; /* 0x006B */ case 0x7B8E57A9U /* F21 */ :return DOM_PK_F21; /* 0x006C */ case 0x7B8E57AAU /* F22 */ :return DOM_PK_F22; /* 0x006D */ case 0x7B8E57ABU /* F23 */ :return DOM_PK_F23; /* 0x006E */ case 0x7393FBACU /* NumpadEqual */ :return RGFW_kpReturn; case 0xB88EBF7CU /* AltRight */ :return RGFW_altR; /* 0xE038 */ case 0xC925873BU /* NumLock */ :return RGFW_numLock; /* 0xE045 */ case 0x2C595F45U /* Home */ :return RGFW_home; /* 0xE047 */ case 0xC91BB690U /* ArrowUp */ :return RGFW_up; /* 0xE048 */ case 0x672F9210U /* PageUp */ :return RGFW_pageUp; /* 0xE049 */ case 0x3799258CU /* ArrowLeft */ :return RGFW_left; /* 0xE04B */ case 0x4CE33F7CU /* ArrowRight */ :return RGFW_right; /* 0xE04D */ case 0x7B8E55DCU /* End */ :return RGFW_end; /* 0xE04F */ case 0x3799379EU /* ArrowDown */ :return RGFW_down; /* 0xE050 */ case 0xBA90179EU /* PageDown */ :return RGFW_pageDown; /* 0xE051 */ case 0x6723CB2CU /* Insert */ :return RGFW_insert; /* 0xE052 */ case 0x6725C50DU /* Delete */ :return RGFW_delete; /* 0xE053 */ case 0x6723658CU /* OSLeft */ :return RGFW_superL; /* 0xE05B */ case 0x39643F7CU /* MetaRight */ :return RGFW_superR; /* 0xE05C */ case 0x380B9C8CU /* NumpadAdd */ :return DOM_PK_NUMPAD_ADD; /* 0x004E */ default:return DOM_PK_UNKNOWN; } return 0; } /* unsupported functions */ void RGFW_window_focus(RGFW_window * win) { RGFW_UNUSED(win); } void RGFW_window_raise(RGFW_window * win) { RGFW_UNUSED(win); } RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { RGFW_UNUSED(mon); RGFW_UNUSED(mode); RGFW_UNUSED(request); return RGFW_FALSE; } RGFW_monitor *RGFW_getMonitors(size_t * len) { RGFW_UNUSED(len); return NULL; } RGFW_monitor RGFW_getPrimaryMonitor(void){ return (RGFW_monitor) { }; } void RGFW_window_move(RGFW_window * win, i32 x, i32 y) { RGFW_UNUSED(win); RGFW_UNUSED(x); RGFW_UNUSED(y); } void RGFW_window_setAspectRatio(RGFW_window * win, i32 w, i32 h) { RGFW_UNUSED(win); RGFW_UNUSED(w); RGFW_UNUSED(h); } void RGFW_window_setMinSize(RGFW_window * win, i32 w, i32 h) { RGFW_UNUSED(win); RGFW_UNUSED(w); RGFW_UNUSED(h); } void RGFW_window_setMaxSize(RGFW_window * win, i32 w, i32 h) { RGFW_UNUSED(win); RGFW_UNUSED(w); RGFW_UNUSED(h); } void RGFW_window_minimize(RGFW_window * win) { RGFW_UNUSED(win); } void RGFW_window_restore(RGFW_window * win) { RGFW_UNUSED(win); } void RGFW_window_setFloating(RGFW_window * win, RGFW_bool floating) { RGFW_UNUSED(win); RGFW_UNUSED(floating); } void RGFW_window_setBorder(RGFW_window * win, RGFW_bool border) { RGFW_UNUSED(win); RGFW_UNUSED(border); } RGFW_bool RGFW_window_setIconEx(RGFW_window * win, u8 * data, i32 w, i32 h, RGFW_format format, RGFW_icon type) { RGFW_UNUSED(win); RGFW_UNUSED(data); RGFW_UNUSED(w); RGFW_UNUSED(h); RGFW_UNUSED(format); RGFW_UNUSED(type); return RGFW_FALSE; } void RGFW_window_hide(RGFW_window * win) { RGFW_UNUSED(win); } void RGFW_window_show(RGFW_window * win) { RGFW_UNUSED(win); } RGFW_bool RGFW_window_isHidden(RGFW_window * win) { RGFW_UNUSED(win); return RGFW_FALSE; } RGFW_bool RGFW_window_isMinimized(RGFW_window * win) { RGFW_UNUSED(win); return RGFW_FALSE; } RGFW_bool RGFW_window_isMaximized(RGFW_window * win) { RGFW_UNUSED(win); return RGFW_FALSE; } RGFW_bool RGFW_window_isFloating(RGFW_window * win) { RGFW_UNUSED(win); return RGFW_FALSE; } RGFW_monitor RGFW_window_getMonitor(RGFW_window * win) { RGFW_UNUSED(win); return (RGFW_monitor) { }; } void RGFW_waitForEvent(i32 waitMS) { RGFW_UNUSED(waitMS); } #endif /* end of web asm defines */ /* * RGFW function pointer backend, made to allow you to * compile for Wayland but fallback to X11 */ #ifdef RGFW_DYNAMIC typedef RGFW_window * (*RGFW_createWindowPlatform_ptr) (const char *name, RGFW_windowFlags flags, RGFW_window * win); typedef RGFW_bool(*RGFW_getMouse_ptr) (i32 * x, i32 * y); typedef u8(*RGFW_rgfwToKeyChar_ptr) (u32 key); typedef void (*RGFW_pollEvents_ptr) (void); typedef void (*RGFW_window_move_ptr) (RGFW_window * win, i32 x, i32 y); typedef void (*RGFW_window_resize_ptr) (RGFW_window * win, i32 w, i32 h); typedef void (*RGFW_window_setAspectRatio_ptr) (RGFW_window * win, i32 w, i32 h); typedef void (*RGFW_window_setMinSize_ptr) (RGFW_window * win, i32 w, i32 h); typedef void (*RGFW_window_setMaxSize_ptr) (RGFW_window * win, i32 w, i32 h); typedef void (*RGFW_window_maximize_ptr) (RGFW_window * win); typedef void (*RGFW_window_focus_ptr) (RGFW_window * win); typedef void (*RGFW_window_raise_ptr) (RGFW_window * win); typedef void (*RGFW_window_setFullscreen_ptr) (RGFW_window * win, RGFW_bool fullscreen); typedef void (*RGFW_window_setFloating_ptr) (RGFW_window * win, RGFW_bool floating); typedef void (*RGFW_window_setOpacity_ptr) (RGFW_window * win, u8 opacity); typedef void (*RGFW_window_minimize_ptr) (RGFW_window * win); typedef void (*RGFW_window_restore_ptr) (RGFW_window * win); typedef RGFW_bool(*RGFW_window_isFloating_ptr) (RGFW_window * win); typedef void (*RGFW_window_setName_ptr) (RGFW_window * win, const char *name); typedef void (*RGFW_window_setMousePassthrough_ptr) (RGFW_window * win, RGFW_bool passthrough); typedef RGFW_bool(*RGFW_window_setIconEx_ptr) (RGFW_window * win, u8 * data, i32 w, i32 h, RGFW_format format, u8 type); typedef RGFW_mouse * (*RGFW_loadMouse_ptr) (u8 * data, i32 w, i32 h, RGFW_format format); typedef void (*RGFW_window_setMouse_ptr) (RGFW_window * win, RGFW_mouse * mouse); typedef void (*RGFW_window_moveMouse_ptr) (RGFW_window * win, i32 x, i32 y); typedef RGFW_bool(*RGFW_window_setMouseDefault_ptr) (RGFW_window * win); typedef RGFW_bool(*RGFW_window_setMouseStandard_ptr) (RGFW_window * win, u8 mouse); typedef void (*RGFW_window_hide_ptr) (RGFW_window * win); typedef void (*RGFW_window_show_ptr) (RGFW_window * win); typedef RGFW_ssize_t(*RGFW_readClipboardPtr_ptr) (char *str, size_t strCapacity); typedef void (*RGFW_writeClipboard_ptr) (const char *text, u32 textLen); typedef RGFW_bool(*RGFW_window_isHidden_ptr) (RGFW_window * win); typedef RGFW_bool(*RGFW_window_isMinimized_ptr) (RGFW_window * win); typedef RGFW_bool(*RGFW_window_isMaximized_ptr) (RGFW_window * win); typedef RGFW_monitor * (*RGFW_getMonitors_ptr) (size_t * len); typedef RGFW_monitor(*RGFW_getPrimaryMonitor_ptr) (void); typedef RGFW_bool(*RGFW_monitor_requestMode_ptr) (RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request); typedef RGFW_monitor(*RGFW_window_getMonitor_ptr) (RGFW_window * win); typedef void (*RGFW_window_closePlatform_ptr) (RGFW_window * win); typedef RGFW_bool(*RGFW_createSurfacePtr_ptr) (u8 * data, i32 w, i32 h, RGFW_format format, RGFW_surface * surface); typedef void (*RGFW_window_blitSurface_ptr) (RGFW_window * win, RGFW_surface * surface); typedef void (*RGFW_surface_freePtr_ptr) (RGFW_surface * surface); typedef void (*RGFW_freeMouse_ptr) (RGFW_mouse * mouse); typedef void (*RGFW_window_setBorder_ptr) (RGFW_window * win, RGFW_bool border); typedef void (*RGFW_releaseCursor_ptr) (RGFW_window * win); typedef void (*RGFW_captureCursor_ptr) (RGFW_window * win); #ifdef RGFW_OPENGL typedef void (*RGFW_window_makeCurrentContext_OpenGL_ptr) (RGFW_window * win); typedef void *(*RGFW_getCurrentContext_OpenGL_ptr) (void); typedef void (*RGFW_window_swapBuffers_OpenGL_ptr) (RGFW_window * win); typedef void (*RGFW_window_swapInterval_OpenGL_ptr) (RGFW_window * win, i32 swapInterval); typedef RGFW_bool(*RGFW_extensionSupportedPlatform_OpenGL_ptr) (const char *extension, size_t len); typedef RGFW_proc(*RGFW_getProcAddress_OpenGL_ptr) (const char *procname); typedef RGFW_bool(*RGFW_window_createContextPtr_OpenGL_ptr) (RGFW_window * win, RGFW_glContext * ctx, RGFW_glHints * hints); typedef void (*RGFW_window_deleteContextPtr_OpenGL_ptr) (RGFW_window * win, RGFW_glContext * ctx); #endif #ifdef RGFW_WEBGPU typedef WGPUSurface(*RGFW_window_createSurface_WebGPU_ptr) (RGFW_window * window, WGPUInstance instance); #endif /* Structure to hold all function pointers */ typedef struct RGFW_FunctionPointers { RGFW_createSurfacePtr_ptr createSurfacePtr; RGFW_window_blitSurface_ptr window_blitSurface; RGFW_surface_freePtr_ptr surface_freePtr; RGFW_freeMouse_ptr freeMouse; RGFW_window_setBorder_ptr window_setBorder; RGFW_releaseCursor_ptr releaseCursor; RGFW_captureCursor_ptr captureCursor; RGFW_createWindowPlatform_ptr createWindowPlatform; RGFW_getMouse_ptr getGlobalMouse; RGFW_rgfwToKeyChar_ptr rgfwToKeyChar; RGFW_pollEvents_ptr pollEvents; RGFW_window_move_ptr window_move; RGFW_window_resize_ptr window_resize; RGFW_window_setAspectRatio_ptr window_setAspectRatio; RGFW_window_setMinSize_ptr window_setMinSize; RGFW_window_setMaxSize_ptr window_setMaxSize; RGFW_window_maximize_ptr window_maximize; RGFW_window_focus_ptr window_focus; RGFW_window_raise_ptr window_raise; RGFW_window_setFullscreen_ptr window_setFullscreen; RGFW_window_setFloating_ptr window_setFloating; RGFW_window_setOpacity_ptr window_setOpacity; RGFW_window_minimize_ptr window_minimize; RGFW_window_restore_ptr window_restore; RGFW_window_isFloating_ptr window_isFloating; RGFW_window_setName_ptr window_setName; RGFW_window_setMousePassthrough_ptr window_setMousePassthrough; RGFW_window_setIconEx_ptr window_setIconEx; RGFW_loadMouse_ptr loadMouse; RGFW_window_setMouse_ptr window_setMouse; RGFW_window_moveMouse_ptr window_moveMouse; RGFW_window_setMouseDefault_ptr window_setMouseDefault; RGFW_window_setMouseStandard_ptr window_setMouseStandard; RGFW_window_hide_ptr window_hide; RGFW_window_show_ptr window_show; RGFW_readClipboardPtr_ptr readClipboardPtr; RGFW_writeClipboard_ptr writeClipboard; RGFW_window_isHidden_ptr window_isHidden; RGFW_window_isMinimized_ptr window_isMinimized; RGFW_window_isMaximized_ptr window_isMaximized; RGFW_getMonitors_ptr getMonitors; RGFW_getPrimaryMonitor_ptr getPrimaryMonitor; RGFW_monitor_requestMode_ptr monitor_requestMode; RGFW_window_getMonitor_ptr window_getMonitor; RGFW_window_closePlatform_ptr window_closePlatform; #ifdef RGFW_OPENGL RGFW_extensionSupportedPlatform_OpenGL_ptr extensionSupportedPlatform_OpenGL; RGFW_getProcAddress_OpenGL_ptr getProcAddress_OpenGL; RGFW_window_createContextPtr_OpenGL_ptr window_createContextPtr_OpenGL; RGFW_window_deleteContextPtr_OpenGL_ptr window_deleteContextPtr_OpenGL; RGFW_window_makeCurrentContext_OpenGL_ptr window_makeCurrentContext_OpenGL; RGFW_getCurrentContext_OpenGL_ptr getCurrentContext_OpenGL; RGFW_window_swapBuffers_OpenGL_ptr window_swapBuffers_OpenGL; RGFW_window_swapInterval_OpenGL_ptr window_swapInterval_OpenGL; #endif #ifdef RGFW_WEBGPU RGFW_window_createSurface_WebGPU_ptr window_createSurface_WebGPU; #endif } RGFW_functionPointers; RGFW_functionPointers RGFW_api; RGFW_bool RGFW_createSurfacePtr(u8 * data, i32 w, i32 h, RGFW_format format, RGFW_surface * surface) { return RGFW_api.createSurfacePtr(data, w, h, format, surface); } void RGFW_surface_freePtr(RGFW_surface * surface) { RGFW_api.surface_freePtr(surface); } void RGFW_freeMouse(RGFW_mouse * mouse) { RGFW_api.freeMouse(mouse); } void RGFW_window_blitSurface(RGFW_window * win, RGFW_surface * surface) { RGFW_api.window_blitSurface(win, surface); } void RGFW_window_setBorder(RGFW_window * win, RGFW_bool border) { RGFW_api.window_setBorder(win, border); } void RGFW_releaseCursor(RGFW_window * win) { RGFW_api.releaseCursor(win); } void RGFW_captureCursor(RGFW_window * win) { RGFW_api.captureCursor(win); } RGFW_window *RGFW_createWindowPlatform(const char *name, RGFW_windowFlags flags, RGFW_window * win){ RGFW_init(); return RGFW_api.createWindowPlatform(name, flags, win); } RGFW_bool RGFW_getGlobalMouse(i32 * x, i32 * y) { return RGFW_api.getGlobalMouse(x, y); } u8 RGFW_rgfwToKeyChar(u32 key) { return RGFW_api.rgfwToKeyChar(key); } void RGFW_pollEvents(void){ RGFW_api.pollEvents(); } void RGFW_window_move(RGFW_window * win, i32 x, i32 y) { RGFW_api.window_move(win, x, y); } void RGFW_window_resize(RGFW_window * win, i32 w, i32 h) { RGFW_api.window_resize(win, w, h); } void RGFW_window_setAspectRatio(RGFW_window * win, i32 w, i32 h) { RGFW_api.window_setAspectRatio(win, w, h); } void RGFW_window_setMinSize(RGFW_window * win, i32 w, i32 h) { RGFW_api.window_setMinSize(win, w, h); } void RGFW_window_setMaxSize(RGFW_window * win, i32 w, i32 h) { RGFW_api.window_setMaxSize(win, w, h); } void RGFW_window_maximize(RGFW_window * win) { RGFW_api.window_maximize(win); } void RGFW_window_focus(RGFW_window * win) { RGFW_api.window_focus(win); } void RGFW_window_raise(RGFW_window * win) { RGFW_api.window_raise(win); } void RGFW_window_setFullscreen(RGFW_window * win, RGFW_bool fullscreen) { RGFW_api.window_setFullscreen(win, fullscreen); } void RGFW_window_setFloating(RGFW_window * win, RGFW_bool floating) { RGFW_api.window_setFloating(win, floating); } void RGFW_window_setOpacity(RGFW_window * win, u8 opacity) { RGFW_api.window_setOpacity(win, opacity); } void RGFW_window_minimize(RGFW_window * win) { RGFW_api.window_minimize(win); } void RGFW_window_restore(RGFW_window * win) { RGFW_api.window_restore(win); } RGFW_bool RGFW_window_isFloating(RGFW_window * win) { return RGFW_api.window_isFloating(win); } void RGFW_window_setName(RGFW_window * win, const char *name){ RGFW_api.window_setName(win, name); } #ifndef RGFW_NO_PASSTHROUGH void RGFW_window_setMousePassthrough(RGFW_window * win, RGFW_bool passthrough) { RGFW_api.window_setMousePassthrough(win, passthrough); } #endif RGFW_bool RGFW_window_setIconEx(RGFW_window * win, u8 * data, i32 w, i32 h, RGFW_format format, u8 type) { return RGFW_api.window_setIconEx(win, data, w, h, format, type); } RGFW_mouse *RGFW_loadMouse(u8 * data, i32 w, i32 h, RGFW_format format) { return RGFW_api.loadMouse(data, w, h, format); } void RGFW_window_setMouse(RGFW_window * win, RGFW_mouse * mouse) { RGFW_api.window_setMouse(win, mouse); } void RGFW_window_moveMouse(RGFW_window * win, i32 x, i32 y) { RGFW_api.window_moveMouse(win, x, y); } RGFW_bool RGFW_window_setMouseDefault(RGFW_window * win) { return RGFW_api.window_setMouseDefault(win); } RGFW_bool RGFW_window_setMouseStandard(RGFW_window * win, u8 mouse) { return RGFW_api.window_setMouseStandard(win, mouse); } void RGFW_window_hide(RGFW_window * win) { RGFW_api.window_hide(win); } void RGFW_window_show(RGFW_window * win) { RGFW_api.window_show(win); } RGFW_ssize_t RGFW_readClipboardPtr(char *str, size_t strCapacity){ return RGFW_api.readClipboardPtr(str, strCapacity); } void RGFW_writeClipboard(const char *text, u32 textLen){ RGFW_api.writeClipboard(text, textLen); } RGFW_bool RGFW_window_isHidden(RGFW_window * win) { return RGFW_api.window_isHidden(win); } RGFW_bool RGFW_window_isMinimized(RGFW_window * win) { return RGFW_api.window_isMinimized(win); } RGFW_bool RGFW_window_isMaximized(RGFW_window * win) { return RGFW_api.window_isMaximized(win); } RGFW_monitor *RGFW_getMonitors(size_t * len) { return RGFW_api.getMonitors(len); } RGFW_monitor RGFW_getPrimaryMonitor(void){ return RGFW_api.getPrimaryMonitor(); } RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { return RGFW_api.monitor_requestMode(mon, mode, request); } RGFW_monitor RGFW_window_getMonitor(RGFW_window * win) { return RGFW_api.window_getMonitor(win); } void RGFW_window_closePlatform(RGFW_window * win) { RGFW_api.window_closePlatform(win); } #ifdef RGFW_OPENGL RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char *extension, size_t len){ return RGFW_api.extensionSupportedPlatform_OpenGL(extension, len); } RGFW_proc RGFW_getProcAddress_OpenGL(const char *procname){ return RGFW_api.getProcAddress_OpenGL(procname); } RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window * win, RGFW_glContext * ctx, RGFW_glHints * hints) { return RGFW_api.window_createContextPtr_OpenGL(win, ctx, hints); } void RGFW_window_deleteContextPtr_OpenGL(RGFW_window * win, RGFW_glContext * ctx) { RGFW_api.window_deleteContextPtr_OpenGL(win, ctx); } void RGFW_window_makeCurrentContext_OpenGL(RGFW_window * win) { RGFW_api.window_makeCurrentContext_OpenGL(win); } void *RGFW_getCurrentContext_OpenGL(void){ return RGFW_api.getCurrentContext_OpenGL(); } void RGFW_window_swapBuffers_OpenGL(RGFW_window * win) { RGFW_api.window_swapBuffers_OpenGL(win); } void RGFW_window_swapInterval_OpenGL(RGFW_window * win, i32 swapInterval) { RGFW_api.window_swapInterval_OpenGL(win, swapInterval); } #endif #ifdef RGFW_WEBGPU WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window * window, WGPUInstance instance) { return RGFW_api.window_createSurface_WebGPU(window, instance); } #endif #endif /* RGFW_DYNAMIC */ /* * start of X11 AND wayland defines this allows a * single executable to support x11 AND wayland falling * back to x11 if wayland fails to initalize */ #if defined(RGFW_WAYLAND) && defined(RGFW_X11) void RGFW_load_X11(void){ RGFW_api.createSurfacePtr = RGFW_createSurfacePtr_X11; RGFW_api.window_blitSurface = RGFW_window_blitSurface_X11; RGFW_api.surface_freePtr = RGFW_surface_freePtr_X11; RGFW_api.freeMouse = RGFW_freeMouse_X11; RGFW_api.window_setBorder = RGFW_window_setBorder_X11; RGFW_api.releaseCursor = RGFW_releaseCursor_X11; RGFW_api.captureCursor = RGFW_captureCursor_X11; RGFW_api.createWindowPlatform = RGFW_createWindowPlatform_X11; RGFW_api.getGlobalMouse = RGFW_getGlobalMouse_X11; RGFW_api.rgfwToKeyChar = RGFW_rgfwToKeyChar_X11; RGFW_api.pollEvents = RGFW_pollEvents_X11; RGFW_api.window_move = RGFW_window_move_X11; RGFW_api.window_resize = RGFW_window_resize_X11; RGFW_api.window_setAspectRatio = RGFW_window_setAspectRatio_X11; RGFW_api.window_setMinSize = RGFW_window_setMinSize_X11; RGFW_api.window_setMaxSize = RGFW_window_setMaxSize_X11; RGFW_api.window_maximize = RGFW_window_maximize_X11; RGFW_api.window_focus = RGFW_window_focus_X11; RGFW_api.window_raise = RGFW_window_raise_X11; RGFW_api.window_setFullscreen = RGFW_window_setFullscreen_X11; RGFW_api.window_setFloating = RGFW_window_setFloating_X11; RGFW_api.window_setOpacity = RGFW_window_setOpacity_X11; RGFW_api.window_minimize = RGFW_window_minimize_X11; RGFW_api.window_restore = RGFW_window_restore_X11; RGFW_api.window_isFloating = RGFW_window_isFloating_X11; RGFW_api.window_setName = RGFW_window_setName_X11; #ifndef RGFW_NO_PASSTHROUGH RGFW_api.window_setMousePassthrough = RGFW_window_setMousePassthrough_X11; #endif RGFW_api.window_setIconEx = RGFW_window_setIconEx_X11; RGFW_api.loadMouse = RGFW_loadMouse_X11; RGFW_api.window_setMouse = RGFW_window_setMouse_X11; RGFW_api.window_moveMouse = RGFW_window_moveMouse_X11; RGFW_api.window_setMouseDefault = RGFW_window_setMouseDefault_X11; RGFW_api.window_setMouseStandard = RGFW_window_setMouseStandard_X11; RGFW_api.window_hide = RGFW_window_hide_X11; RGFW_api.window_show = RGFW_window_show_X11; RGFW_api.readClipboardPtr = RGFW_readClipboardPtr_X11; RGFW_api.writeClipboard = RGFW_writeClipboard_X11; RGFW_api.window_isHidden = RGFW_window_isHidden_X11; RGFW_api.window_isMinimized = RGFW_window_isMinimized_X11; RGFW_api.window_isMaximized = RGFW_window_isMaximized_X11; RGFW_api.getMonitors = RGFW_getMonitors_X11; RGFW_api.getPrimaryMonitor = RGFW_getPrimaryMonitor_X11; RGFW_api.monitor_requestMode = RGFW_monitor_requestMode_X11; RGFW_api.window_getMonitor = RGFW_window_getMonitor_X11; RGFW_api.window_closePlatform = RGFW_window_closePlatform_X11; #ifdef RGFW_OPENGL RGFW_api.extensionSupportedPlatform_OpenGL = RGFW_extensionSupportedPlatform_OpenGL_X11; RGFW_api.getProcAddress_OpenGL = RGFW_getProcAddress_OpenGL_X11; RGFW_api.window_createContextPtr_OpenGL = RGFW_window_createContextPtr_OpenGL_X11; RGFW_api.window_deleteContextPtr_OpenGL = RGFW_window_deleteContextPtr_OpenGL_X11; RGFW_api.window_makeCurrentContext_OpenGL = RGFW_window_makeCurrentContext_OpenGL_X11; RGFW_api.getCurrentContext_OpenGL = RGFW_getCurrentContext_OpenGL_X11; RGFW_api.window_swapBuffers_OpenGL = RGFW_window_swapBuffers_OpenGL_X11; RGFW_api.window_swapInterval_OpenGL = RGFW_window_swapInterval_OpenGL_X11; #endif #ifdef RGFW_WEBGPU RGFW_api.window_createSurface_WebGPU = RGFW_window_createSurface_WebGPU_X11; #endif } void RGFW_load_Wayland(void){ RGFW_api.createSurfacePtr = RGFW_createSurfacePtr_Wayland; RGFW_api.window_blitSurface = RGFW_window_blitSurface_Wayland; RGFW_api.surface_freePtr = RGFW_surface_freePtr_Wayland; RGFW_api.freeMouse = RGFW_freeMouse_Wayland; RGFW_api.window_setBorder = RGFW_window_setBorder_Wayland; RGFW_api.releaseCursor = RGFW_releaseCursor_Wayland; RGFW_api.captureCursor = RGFW_captureCursor_Wayland; RGFW_api.createWindowPlatform = RGFW_createWindowPlatform_Wayland; RGFW_api.getGlobalMouse = RGFW_getGlobalMouse_Wayland; RGFW_api.rgfwToKeyChar = RGFW_rgfwToKeyChar_Wayland; RGFW_api.pollEvents = RGFW_pollEvents_Wayland; RGFW_api.window_move = RGFW_window_move_Wayland; RGFW_api.window_resize = RGFW_window_resize_Wayland; RGFW_api.window_setAspectRatio = RGFW_window_setAspectRatio_Wayland; RGFW_api.window_setMinSize = RGFW_window_setMinSize_Wayland; RGFW_api.window_setMaxSize = RGFW_window_setMaxSize_Wayland; RGFW_api.window_maximize = RGFW_window_maximize_Wayland; RGFW_api.window_focus = RGFW_window_focus_Wayland; RGFW_api.window_raise = RGFW_window_raise_Wayland; RGFW_api.window_setFullscreen = RGFW_window_setFullscreen_Wayland; RGFW_api.window_setFloating = RGFW_window_setFloating_Wayland; RGFW_api.window_setOpacity = RGFW_window_setOpacity_Wayland; RGFW_api.window_minimize = RGFW_window_minimize_Wayland; RGFW_api.window_restore = RGFW_window_restore_Wayland; RGFW_api.window_isFloating = RGFW_window_isFloating_Wayland; RGFW_api.window_setName = RGFW_window_setName_Wayland; #ifndef RGFW_NO_PASSTHROUGH RGFW_api.window_setMousePassthrough = RGFW_window_setMousePassthrough_Wayland; #endif RGFW_api.window_setIconEx = RGFW_window_setIconEx_Wayland; RGFW_api.loadMouse = RGFW_loadMouse_Wayland; RGFW_api.window_setMouse = RGFW_window_setMouse_Wayland; RGFW_api.window_moveMouse = RGFW_window_moveMouse_Wayland; RGFW_api.window_setMouseDefault = RGFW_window_setMouseDefault_Wayland; RGFW_api.window_setMouseStandard = RGFW_window_setMouseStandard_Wayland; RGFW_api.window_hide = RGFW_window_hide_Wayland; RGFW_api.window_show = RGFW_window_show_Wayland; RGFW_api.readClipboardPtr = RGFW_readClipboardPtr_Wayland; RGFW_api.writeClipboard = RGFW_writeClipboard_Wayland; RGFW_api.window_isHidden = RGFW_window_isHidden_Wayland; RGFW_api.window_isMinimized = RGFW_window_isMinimized_Wayland; RGFW_api.window_isMaximized = RGFW_window_isMaximized_Wayland; RGFW_api.getMonitors = RGFW_getMonitors_Wayland; RGFW_api.getPrimaryMonitor = RGFW_getPrimaryMonitor_Wayland; RGFW_api.monitor_requestMode = RGFW_monitor_requestMode_Wayland; RGFW_api.window_getMonitor = RGFW_window_getMonitor_Wayland; RGFW_api.window_closePlatform = RGFW_window_closePlatform_Wayland; #ifdef RGFW_OPENGL RGFW_api.extensionSupportedPlatform_OpenGL = RGFW_extensionSupportedPlatform_OpenGL_Wayland; RGFW_api.getProcAddress_OpenGL = RGFW_getProcAddress_OpenGL_Wayland; RGFW_api.window_createContextPtr_OpenGL = RGFW_window_createContextPtr_OpenGL_Wayland; RGFW_api.window_deleteContextPtr_OpenGL = RGFW_window_deleteContextPtr_OpenGL_Wayland; RGFW_api.window_makeCurrentContext_OpenGL = RGFW_window_makeCurrentContext_OpenGL_Wayland; RGFW_api.getCurrentContext_OpenGL = RGFW_getCurrentContext_OpenGL_Wayland; RGFW_api.window_swapBuffers_OpenGL = RGFW_window_swapBuffers_OpenGL_Wayland; RGFW_api.window_swapInterval_OpenGL = RGFW_window_swapInterval_OpenGL_Wayland; #endif #ifdef RGFW_WEBGPU RGFW_api.window_createSurface_WebGPU = RGFW_window_createSurface_WebGPU_Wayland; #endif } #endif /* wayland AND x11 */ /* end of X11 AND wayland defines */ #endif /* RGFW_IMPLEMENTATION */ #if defined(__cplusplus) && !defined(__EMSCRIPTEN__) } #endif #if _MSC_VER #pragma warning( pop ) #endif