diff options
| author | andromeda <andromeda@bsd.my.domain> | 2026-10-24 00:48:05 -0400 |
|---|---|---|
| committer | andromeda <andromeda@bsd.my.domain> | 2026-10-24 00:48:05 -0400 |
| commit | eb0f2cc6373393303c5a4cd83792dd79103b85de (patch) | |
| tree | 3f4b746ec73ce745f0c65a5666da7293bd7bd907 /rgfw.c3l/include | |
| parent | 2e0b6ffcd7c3ddc09daca64993bdc62fc428a175 (diff) | |
revitalise
Diffstat (limited to 'rgfw.c3l/include')
| -rw-r--r-- | rgfw.c3l/include/RGFW.h | 5081 |
1 files changed, 3145 insertions, 1936 deletions
diff --git a/rgfw.c3l/include/RGFW.h b/rgfw.c3l/include/RGFW.h index 8016f02..844eb95 100644 --- a/rgfw.c3l/include/RGFW.h +++ b/rgfw.c3l/include/RGFW.h @@ -41,8 +41,8 @@ #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_STATIC_CONTEXT - do not initalizize with a static variable, use the heap if RGFW is not manually initalized #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) @@ -55,10 +55,11 @@ #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 and don't use libShcore (win32) - #define RGFW_NO_XRANDR - do use not XRandr (X11) #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_NO_GLXWINDOW - do not use GLXWindow + #define RGFW_NO_ALLOCATE_MONITORS - do not allocate monitors on the heap at all (when there's no pre-allocated space left) + #define RGFW_NO_INCLUDE_VULKAN - do not include the Vulkan.h header, you have to include it yourself #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) @@ -69,12 +70,14 @@ #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 + + #define RGFW_PREALLOCATED_MONITORS x - choose the default amount of pre-allocated monitors (can be zero) */ /* Example to get you started : -linux : gcc main.c -lX11 -lXrandr -lm +*nix : gcc main.c -lX11 -lXrandr -lm windows : gcc main.c -lgdi32 macos : gcc main.c -framework Cocoa -framework CoreVideo -framework IOKit @@ -116,7 +119,7 @@ int main() { shared : windows: gcc -shared RGFW.o -lopengl32 -lgdi32 -o RGFW.dll - linux: + unix: gcc -shared RGFW.o -lX11 -lGL -lXrandr -o RGFW.so macos: gcc -shared RGFW.o -framework CoreVideo -framework Cocoa -framework OpenGL -framework IOKit @@ -165,7 +168,7 @@ int main() { #pragma comment(lib, "User32") #pragma comment(lib, "Advapi32") #pragma warning( push ) - #pragma warning( disable : 4995 4191 4127) + #pragma warning( disable : 4996 4191 4127) #if _MSC_VER < 600 #define RGFW_C89 #endif @@ -175,15 +178,14 @@ int main() { #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 + #ifdef RGFW_EGL + #define RGFW_OPENGL + #endif #endif #if defined(RGFW_X11) && defined(__APPLE__) && !defined(RGFW_CUSTOM_BACKEND) @@ -212,11 +214,27 @@ int main() { #define RGFW_MACOS #endif +#if defined(RGFW_X11) || defined(RGFW_WASM) || defined(RGFW_WAYLAND) + #ifndef _POSIX_C_SOURCE + #define _POSIX_C_SOURCE 199309L + #endif + + /* __USE_POSIX199309 is part of glibc internals, and isn't intended to be used outside. */ + /* However, existing RGFW code may depend on it implicitly. */ + #ifndef __USE_POSIX199309 + #define __USE_POSIX199309 + #endif +#endif + #ifndef RGFW_ASSERT #include <assert.h> #define RGFW_ASSERT assert #endif +#ifndef RGFW_STATIC_ASSERT + #define RGFW_STATIC_ASSERT(check_name, x) typedef char RGFW_check_##check_name[(x) ? 1 : -1]; +#endif + #if !defined(__STDC_VERSION__) #define RGFW_C89 #endif @@ -239,6 +257,10 @@ int main() { #define RGFW_ROUND(x) (i32)((x) >= 0 ? (x) + 0.5f : (x) - 0.5f) #endif +#ifndef RGFW_ABS + #define RGFW_ABS(x) (((x) < 0) ? -(x) : (x)) +#endif + #ifndef RGFW_ROUNDF #define RGFW_ROUNDF(x) (float)((i32)((x) + ((x) < 0.0f ? -0.5f : 0.5f))) #endif @@ -293,9 +315,10 @@ int main() { #ifndef RGFW_MAX_EVENTS #define RGFW_MAX_EVENTS 32 #endif - -#ifndef RGFW_MAX_MONITORS - #define RGFW_MAX_MONITORS 6 +#ifndef RGFW_PREALLOCATED_MONITORS + #define RGFW_PREALLOCATED_MONITORS 6 /* the number of preallocated monitors */ +#elif defined(RGFW_NO_ALLOCATE_MONITORS) && (RGFW_PREALLOCATED_MONITORS == 0) + #warning RGFW monitors have no place to be allocated #endif #ifndef RGFW_COCOA_FRAME_NAME @@ -345,16 +368,28 @@ int main() { #define RGFW_HEADER #include <stddef.h> +#include <limits.h> + #ifndef RGFW_INT_DEFINED #ifdef RGFW_USE_INT /* optional for any system that might not have stdint.h */ typedef unsigned char u8; typedef signed char i8; typedef unsigned short u16; typedef signed short i16; - typedef unsigned long int u32; - typedef signed long int i32; - typedef unsigned long long u64; - typedef signed long long i64; + #if INT_MAX == 0x7FFFFFFF + typedef unsigned int u32; + typedef signed int i32; + #else + typedef unsigned long int u32; + typedef signed long int i32; + #endif + #if LONG_MAX == 0x7FFFFFFFFFFFFFFFL + typedef unsigned long u64; + typedef signed long i64; + #else + typedef unsigned long long u64; + typedef signed long long i64; + #endif #else /* use stdint standard types instead of c "standard" types */ #include <stdint.h> @@ -370,7 +405,9 @@ int main() { #define RGFW_INT_DEFINED #endif -typedef ptrdiff_t RGFW_ssize_t; +RGFW_STATIC_ASSERT(size64, sizeof(i64) == 8) +RGFW_STATIC_ASSERT(size32, sizeof(i32) == 4) +RGFW_STATIC_ASSERT(size16, sizeof(i16) == 2) #ifndef RGFW_BOOL_DEFINED #define RGFW_BOOL_DEFINED @@ -381,7 +418,7 @@ typedef ptrdiff_t RGFW_ssize_t; #define RGFW_TRUE (RGFW_bool)1 #define RGFW_FALSE (RGFW_bool)0 -#define RGFW_ENUM(type, name) type name; enum +#define RGFW_ENUM(type, name) type name; enum name##_enum #define RGFW_BIT(x) (1 << (x)) #ifdef RGFW_VULKAN @@ -408,8 +445,31 @@ typedef ptrdiff_t RGFW_ssize_t; #define RGFW_VK_SURFACE NULL #endif + #ifndef RGFW_NO_INCLUDE_VULKAN + #include <vulkan/vulkan.h> + #endif + + #if defined(RGFW_X11) + typedef VkResult (VKAPI_PTR *RGFW_vkCreateXlibSurfaceKHRProc)(VkInstance, const VkXlibSurfaceCreateInfoKHR*, const VkAllocationCallbacks*, VkSurfaceKHR*); + typedef VkBool32 (VKAPI_PTR *RGFW_vkGetPhysicalDeviceXlibPresentationSupportKHRProc)(VkPhysicalDevice, uint32_t, Display*, VisualID); + #endif + #ifdef RGFW_WAYLAND + typedef VkResult (VKAPI_PTR *RGFW_vkCreateWaylandSurfaceKHRProc)(VkInstance, const VkWaylandSurfaceCreateInfoKHR*, const VkAllocationCallbacks*, VkSurfaceKHR*); + typedef VkBool32 (VKAPI_PTR *RGFW_vkGetPhysicalDeviceWaylandPresentationSupportKHRProc)(VkPhysicalDevice, uint32_t, struct wl_display*); + #endif + #ifdef RGFW_WINDOWS + typedef VkResult (VKAPI_PTR *RGFW_vkCreateWin32SurfaceKHRProc)(VkInstance, const VkWin32SurfaceCreateInfoKHR*, const VkAllocationCallbacks*, VkSurfaceKHR*); + typedef VkBool32 (VKAPI_PTR *RGFW_vkGetPhysicalDeviceWin32PresentationSupportKHRProc)(VkPhysicalDevice, uint32_t); + #endif #endif +/*! @brief Flags for RGFW initialization */ +typedef RGFW_ENUM(u8, RGFW_initFlags) { + RGFW_initOpenGL = RGFW_BIT(0), /*!< Load Native OpenGL */ + RGFW_initEGL = RGFW_BIT(1), /*!< Load EGL */ + RGFW_initVulkan = RGFW_BIT(2), /*!< Load Vulkan */ + RGFW_initX11 = RGFW_BIT(3) /*!< Force X11 (over Wayland) */ +}; /*! @brief The stucture that contains information about the current RGFW instance */ typedef struct RGFW_info RGFW_info; @@ -616,9 +676,9 @@ typedef RGFW_ENUM(u8, RGFW_key) { /*! @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_mouseLeft = 0, /*!< left mouse button */ + RGFW_mouseMiddle, /*!< mouse-wheel-button */ + RGFW_mouseRight, /*!< right mouse button */ RGFW_mouseMisc1, RGFW_mouseMisc2, RGFW_mouseMisc3, RGFW_mouseMisc4, RGFW_mouseMisc5, RGFW_mouseFinal }; @@ -639,7 +699,7 @@ typedef RGFW_ENUM(u8, RGFW_dndActionType) { RGFW_dndActionNone = 0, RGFW_dndActionEnter, /*!< data has been dragged into the window area */ RGFW_dndActionMove, /*!< the data that was dragged into the window area has moved inside the window */ - RGFW_dndActionExit, /*!< the data that was dragged into the window area has left the window */ + RGFW_dndActionExit /*!< the data that was dragged into the window area has left the window */ }; /*! types of transfered data (clipboard, dnd) */ @@ -652,10 +712,17 @@ typedef RGFW_ENUM(u8, RGFW_dataTransferType) { RGFW_dataUnknown /*!< unknown raw data */ }; +/*! struct for data transfers, mostly used for the clipboard API */ +typedef struct RGFW_dataTransfer { + const char* data; /*!< transfered data */ + size_t length; /*!< the full length of the data in bytes, including null-terminator, if included. null-terminators are ensured when reading data from RGFW */ + RGFW_dataTransferType type; /*!< the type of data being transfered */ +} RGFW_dataTransfer; + /*! internal node for a individual data drop */ typedef struct RGFW_dataDropNode { const char* data; /*!< dropped data */ - size_t size; /*!< the size of the data in bytes */ + size_t length; /*!< the size of the data in bytes */ RGFW_dataTransferType type; /*!< the type of data being dropped */ struct RGFW_dataDropNode* next; /*!< the next drop data node if any [when handling callbacks, this will always be NULL because the linked list is built as events are processed] */ } RGFW_dataDropNode; @@ -669,7 +736,7 @@ typedef RGFW_ENUM(u8, RGFW_eventType) { 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 */ + RGFW_mouseMotion, /*!< the position of the mouse has been changed / the mouse has moved */ RGFW_mouseRawMotion, /*!< raw mouse motion */ RGFW_mouseEnter, /*!< mouse entered the window */ RGFW_mouseLeave, /*!< mouse left the window */ @@ -687,7 +754,8 @@ typedef RGFW_ENUM(u8, RGFW_eventType) { RGFW_scaleUpdated, /*!< content scale factor changed */ RGFW_monitorConnected, /*!< a monitor has been connected */ RGFW_monitorDisconnected, /*!< a monitor has been disconnected */ - RGFW_eventCount /*!< the number of event types there are */ + RGFW_eventCount, /*!< the number of event types there are */ + RGFW_mousePosChanged = RGFW_mouseMotion /*!< alias for RGFW_mouseMotion (may be deleted at some point) */ }; /*! @brief flags for toggling whether or not an event should be processed */ @@ -698,7 +766,7 @@ typedef RGFW_ENUM(u32, RGFW_eventFlag) { 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_mouseMotionFlag = RGFW_BIT(RGFW_mouseMotion), RGFW_mouseRawMotionFlag = RGFW_BIT(RGFW_mouseRawMotion), RGFW_mouseEnterFlag = RGFW_BIT(RGFW_mouseEnter), RGFW_mouseLeaveFlag = RGFW_BIT(RGFW_mouseLeave), @@ -716,9 +784,10 @@ typedef RGFW_ENUM(u32, RGFW_eventFlag) { RGFW_dataDragFlag = RGFW_BIT(RGFW_dataDrag), RGFW_monitorConnectedFlag = RGFW_BIT(RGFW_monitorConnected), RGFW_monitorDisconnectedFlag = RGFW_BIT(RGFW_monitorDisconnected), + RGFW_mousePosChangedFlag = RGFW_mouseMotionFlag, /* alias for RGFW_mouseMotionFlag (may be deleted at some point) */ RGFW_keyEventsFlag = RGFW_keyPressedFlag | RGFW_keyReleasedFlag | RGFW_keyCharFlag, - RGFW_mouseEventsFlag = RGFW_mouseButtonPressedFlag | RGFW_mouseButtonReleasedFlag | RGFW_mousePosChangedFlag | RGFW_mouseEnterFlag | RGFW_mouseLeaveFlag | RGFW_mouseScrollFlag | RGFW_mouseRawMotionFlag, + RGFW_mouseEventsFlag = RGFW_mouseButtonPressedFlag | RGFW_mouseButtonReleasedFlag | RGFW_mouseMotionFlag | RGFW_mouseEnterFlag | RGFW_mouseLeaveFlag | RGFW_mouseScrollFlag | RGFW_mouseRawMotionFlag, RGFW_windowEventsFlag = RGFW_windowMovedFlag | RGFW_windowResizedFlag | RGFW_windowRefreshFlag | RGFW_windowMaximizedFlag | RGFW_windowMinimizedFlag | RGFW_windowRestoredFlag | RGFW_scaleUpdatedFlag, RGFW_windowFocusEventsFlag = RGFW_windowFocusInFlag | RGFW_windowFocusOutFlag, RGFW_dataDragDropEventsFlag = RGFW_dataDropFlag | RGFW_dataDragFlag, @@ -756,13 +825,13 @@ typedef struct RGFW_mouseDeltaEvent { float x, y; /*!< the raw mouse scroll or motion delta value */ } RGFW_mouseDeltaEvent; -/*! @brief event data for a mouse position event (RGFW_mousePosChanged) */ -typedef struct RGFW_mousePosEvent { +/*! @brief event data for a mouse position event (RGFW_mouseMotion) */ +typedef struct RGFW_mouseMotionEvent { RGFW_eventType type; /*!< which event has been sent?*/ RGFW_window* win; /*!< the window this event applies to (for event queue events) */ i32 x, y; /*!< mouse x, y of event (or drop point) */ RGFW_bool inWindow; /*!< if the mouse is in the window or not */ -} RGFW_mousePosEvent; +} RGFW_mouseMotionEvent; /*! @brief event data for a key press/release event */ typedef struct RGFW_keyEvent { @@ -830,7 +899,7 @@ typedef union RGFW_event { RGFW_windowUpdateEvent update; /*!< data for window update/move/resize/refresh events */ RGFW_mouseButtonEvent button; /*!< data for a button press/release */ RGFW_mouseDeltaEvent delta; /*!< data for a mouse scroll or raw motion */ - RGFW_mousePosEvent mouse; /*!< data for mouse motion events */ + RGFW_mouseMotionEvent mouse; /*!< data for mouse motion events */ RGFW_keyEvent key; /*!< data for key press/release/hold events */ RGFW_keyCharEvent keyChar; /*!< data for key character events */ RGFW_dataDropEvent drop; /*!< data dropping events */ @@ -859,13 +928,24 @@ typedef struct RGFW_callbacks { RGFW_genericFunc arr[RGFW_eventCount]; /*!< an array of all the callbacks */ } RGFW_callbacks; +typedef RGFW_ENUM(u8, RGFW_fullscreenMode) { + RGFW_fullscreenNone, + /*!< borderless/windowed fullscreen | the window changes it's size to match the monitor's current mode + the window is not hidden and maintains it's size when it is unfocused */ + RGFW_fullscreenBorderless, /*!< borderless/windowed fullscreen */ + /*!< exclusive fullscreen | the monitor's mode tries to change to match the window's size. + The original mode is toggled when the window goes in and out of focus and + the window is hidden when it is not in focus */ + RGFW_fullscreenExclusive, /*!< exclusive fullscreen */ +}; + /*! @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 / frame / decor */ 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_windowFullscreenExclusive = RGFW_BIT(4), /*!< the window is exclusive fullscreen by default */ RGFW_windowTranslucent = RGFW_BIT(5), /*!< the window is translucent (only properly works on X11 and MacOS, although it's meant for for windows) */ RGFW_windowTransparent = RGFW_windowTranslucent, /*!< the window is translucent (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 */ @@ -881,8 +961,7 @@ typedef RGFW_ENUM(u32, RGFW_windowFlags) { RGFW_windowCaptureMouse = RGFW_BIT(16), /*!< capture the mouse mouse mouse on window creation */ 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_noDeinitOnClose = RGFW_BIT(19), /*!< do not auto deinit RGFW if the window closes and this is the last window open */ - RGFW_windowedFullscreen = RGFW_windowNoBorder | RGFW_windowMaximize, + RGFW_windowFullscreenBorderless = RGFW_BIT(19), /*!< the window is borderless fullscreen by default */ RGFW_windowCaptureRawMouse = RGFW_windowCaptureMouse | RGFW_windowRawMouse }; @@ -945,8 +1024,10 @@ typedef RGFW_ENUM(u8, RGFW_errorCode) { RGFW_errFailedFuncLoad, RGFW_errBuffer, RGFW_errMetal, + RGFW_errObjcRuntime, RGFW_errPlatform, RGFW_errEventQueue, + RGFW_errNoInit, RGFW_infoWindow, RGFW_infoBuffer, RGFW_infoGlobal, RGFW_infoOpenGL, RGFW_warningWayland, RGFW_warningOpenGL }; @@ -964,7 +1045,7 @@ typedef void (* RGFW_debugFunc)(const RGFW_debugInfo* info); /*! @brief function pointer equivalent of void* */ typedef void (*RGFW_proc)(void); -#if defined(RGFW_OPENGL) +#if defined(RGFW_OPENGL) || defined(RGFW_EGL) /*! @brief abstract structure for interfacing with the underlying OpenGL API */ typedef struct RGFW_glContext RGFW_glContext; @@ -983,7 +1064,8 @@ typedef RGFW_ENUM(i32, RGFW_glProfile) { RGFW_glCore = 0, /*!< the core OpenGL version, e.g. just support for that version */ RGFW_glForwardCompatibility, /*!< only compatibility for newer versions of OpenGL as well as the requested version */ RGFW_glCompatibility, /*!< allow compatibility for older versions of OpenGL as well as the requested version */ - RGFW_glES /*!< use OpenGL ES */ + RGFW_glES, /*!< use OpenGL ES */ + RGFW_glWeb /*!< use WebGL version (otherwise the version is changed to match it's GLES equivalent) */ }; /*! values for the renderer hint */ @@ -1014,7 +1096,7 @@ typedef struct RGFW_glHints { RGFW_glRenderer renderer; /*!< renderer to use e.g. accelerated or software defaults to accelerated */ } RGFW_glHints; -#endif +#endif /* RGFW_OPENGL */ /**! * @brief Allocates memory using the allocator defined by RGFW_ALLOC at compile time. @@ -1030,6 +1112,51 @@ RGFWDEF void* RGFW_alloc(size_t size); RGFWDEF void RGFW_free(void* ptr); /**! + * @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 internally. + * @param className The class name for the application. + * @param flags The initialization flags. + * @return 0 on success, a negative number error error on failure and a positive number for a warning. +*/ +RGFWDEF i32 RGFW_init(const char* className, RGFW_initFlags flags); + +/**! + * @brief Deinitializes the current instance of the RGFW library. +*/ +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, a negative number error error on failure and a positive number for a warning. +*/ +RGFWDEF i32 RGFW_init_ptr(const char* className, RGFW_initFlags flags, 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); + + +/**! * @brief Returns the size (in bytes) of the RGFW_window structure. * @return The size of the RGFW_window structure. */ @@ -1042,15 +1169,6 @@ RGFWDEF size_t RGFW_sizeofWindow(void); 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. */ @@ -1075,21 +1193,6 @@ RGFWDEF void* RGFW_getDisplay_X11(void); 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); @@ -1336,13 +1439,27 @@ RGFWDEF RGFW_bool RGFW_monitor_getMode(RGFW_monitor* monitor, RGFW_monitorMode* RGFWDEF void RGFW_pollMonitors(void); /**! - * @brief Retrieves an array of all available monitors. - * @param len [OUTPUT] A pointer to store the number of monitors found (maximum of RGFW_MAX_MONITORS [6 by default]). - * @return An array of pointers to RGFW_monitor structures. + * @brief free all leftlover monitor data (this is called internally RGFW_deinit) +*/ +RGFWDEF void RGFW_freeMonitors(void); + +/**! + * @brief Allocates and returns an array of all available monitors. + * @param len [OUTPUT] A pointer to store the number of monitors found. + * @return An allocated array of pointers to RGFW_monitor structures that must be freed. */ RGFWDEF RGFW_monitor** RGFW_getMonitors(size_t* len); /**! + * @brief fills a pre-allocated array with available monitors. + * @param maximum number of monitors that the passed [monitors] buffer supports, can be zero to get the length alone + * @param pre-allocated buffer of monitors, can be NULL to get the length alone + * @param len [OUTPUT] A pointer to store the number of monitors found, if max is not zero and monitors is not NULL, length will be set to max. + * @return An array of pointers to RGFW_monitor structures or NULL if the function failed. +*/ +RGFWDEF RGFW_bool RGFW_getMonitorsPtr(size_t max, RGFW_monitor** monitors, size_t* len); + +/**! * @brief Retrieves the primary monitor. * @return A pointer to the RGFW_monitor structure representing the primary monitor. */ @@ -1538,7 +1655,7 @@ RGFWDEF void RGFW_getMouseVector(float* x, float* y); * * 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); +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 @@ -1864,7 +1981,7 @@ RGFWDEF RGFW_bool RGFW_window_getDataDrag(RGFW_window* win, i32* x, i32* y); RGFWDEF RGFW_bool RGFW_window_didDataDrop(RGFW_window* win); /**! - * @brief retrieves datta from a data drop (drag and drop) + * @brief retrieves data from a data drop (drag and drop) * @param win a pointer to the target window * @return a valid pointer to the root drag node if a data drop occurred, NULL otherwise */ @@ -1966,9 +2083,9 @@ 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 + * @param fullscreen the fullscreen mode to use RGFW_fullscreenNone, RGFW_fullscreenBorderless, RGFW_fullscreenExclusive */ -RGFWDEF void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen); +RGFWDEF void RGFW_window_setFullscreen(RGFW_window* win, RGFW_fullscreenMode mode); /**! * @brief centers the window on the screen @@ -2208,13 +2325,27 @@ RGFWDEF void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y); RGFWDEF RGFW_bool RGFW_window_shouldClose(RGFW_window* win); /**! - * @brief Checks if the window is currently fullscreen. + * @brief Checks if the window is currently fullscreen (borderless or exclusive). * @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 fullscreen (exclusive). + * @param win The target window. + * @return True if the window is fullscreen. +*/ +RGFWDEF RGFW_bool RGFW_window_isFullscreenExclusive(RGFW_window* win); + +/**! + * @brief Checks if the window is currently fullscreen (borderless). + * @param win The target window. + * @return True if the window is fullscreen. +*/ +RGFWDEF RGFW_bool RGFW_window_isFullscreenBorderless(RGFW_window* win); + +/**! * @brief Checks if the window is currently hidden. * @param win The target window. * @return True if the window is hidden. @@ -2269,25 +2400,43 @@ RGFWDEF RGFW_monitor* RGFW_window_getMonitor(RGFW_window* win); /**! * @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. + * @param requestedType the requested clipboard data type to attempt to read + * @return A pointer to the clipboard data object or NULL on failure. +*/ +RGFWDEF const RGFW_dataTransfer* RGFW_readClipboard(RGFW_dataTransferType requestedType); + +/**! + * @brief Reads clipboard data into your object pointer using your provided buffer, or returns the required length if the buffer is NULL or bufferCapacity is 0. + * @param requestedType the requested clipboard data type to attempt to read + * @param buffer the buffer used to fill the output dataTransfer object's data + * @param capacity the capacity/length of the buffer in bytes + * @param data [OUTPUT] A pointer to the dataTransfer object that will receive the clipboard data. (cannot be NULL) + * @return returns RGFW_TRUE on success and RGFW_FALSE on failure */ -RGFWDEF const char* RGFW_readClipboard(size_t* size); +RGFWDEF RGFW_bool RGFW_readClipboardPtr(RGFW_dataTransferType requestedType, u8* buffer, size_t capacity, RGFW_dataTransfer* data); /**! - * @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. + * @brief Reads clipboard string data. + * @param requestedType the requested clipboard data type to attempt to read + * @return A pointer to the clipboard data object or NULL on failure. */ -RGFWDEF RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity); +RGFWDEF const RGFW_dataTransfer* RGFW_readClipboardString(void); /**! - * @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. + * @brief Reads clipboard data into your object pointer using your provided buffer, or returns the required length if the buffer is NULL or bufferCapacity is 0. + * @param buffer the buffer used to fill the output dataTransfer object's data + * @param capacity the capacity/length of the buffer in bytes + * @param data [OUTPUT] A pointer to the dataTransfer object that will receive the clipboard data. (cannot be NULL) + * @return returns RGFW_TRUE on success and RGFW_FALSE on failure */ -RGFWDEF void RGFW_writeClipboard(const char* text, u32 textLen); +RGFWDEF RGFW_bool RGFW_readClipboardStringPtr(u8* buffer, size_t capacity, RGFW_dataTransfer* data); + +/**! + * @brief Writes data to the clipboard. + * @param data The data to be written to the clipboard, including the length and type. + * @param returns RGFW_TRUE on success and RGFW_FALSE on failure +*/ +RGFWDEF RGFW_bool RGFW_writeClipboard(const RGFW_dataTransfer* data); /** @} */ @@ -2313,17 +2462,8 @@ RGFWDEF void RGFW_debugCallback(RGFW_debugType type, RGFW_errorCode code, const /** * @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 -*/ +#if defined(RGFW_OPENGL) || defined(RGFW_EGL) +/* these are generic functions that work for both EGL and native OpenGL */ /**! * @brief Sets the global OpenGL hints to the specified pointer. @@ -2342,47 +2482,85 @@ RGFWDEF void RGFW_resetGlobalHints_OpenGL(void); */ RGFWDEF RGFW_glHints* RGFW_getGlobalHints_OpenGL(void); +#endif + +/*! 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 Creates and allocates an OpenGL context for the specified window. - * @param win A pointer to the target RGFW_window. + * @brief Creates and allocates an OpenGL context that can be attached to a 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); +RGFWDEF RGFW_glContext* RGFW_createContext_OpenGL(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. + * @brief Creates an OpenGL context that can be attached to a window, using a preallocated context structure. * @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); +RGFWDEF RGFW_bool RGFW_createContextPtr_OpenGL(RGFW_glContext* ctx, RGFW_glHints* hints); /**! * @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 Only use this version if you allocated a context with RGFW_createContext_OpenGL * @note This is automatically called by RGFW_window_close if the window’s context is not NULL. + * @note you should set the window context to NULL with RGFW_window_setContext_OpenGL(win, NULL) after calling this function */ -RGFWDEF void RGFW_window_deleteContext_OpenGL(RGFW_window* win, RGFW_glContext* ctx); +RGFWDEF void RGFW_deleteContext_OpenGL(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 Only use this version if you allocated a context with RGFW_createContext_OpenGL * @note This is automatically called by RGFW_window_close if the window’s context is not NULL. + * @note you should set the window context to NULL with RGFW_window_setContext_OpenGL(win, NULL) after calling this function +*/ +RGFWDEF void RGFW_deleteContextPtr_OpenGL(RGFW_glContext* ctx); + +/**! + * @brief allocates a new context, copying the info from an old context + * @param ctx A pointer to the RGFW_glContext to copy. + * @return The newly allocated context +*/ +RGFWDEF RGFW_glContext* RGFW_copyContext_OpenGL(RGFW_glContext* ctx); + +/**! + * @brief copies info from a context to make a new context with the supplied pointer + * @param ctx A pointer to the RGFW_glContext to copy. + * @param newCtx A pointer to the new context. + * @return boolean RGFW_TRUE for success, RGFW_FALSE for failure +*/ +RGFWDEF RGFW_bool RGFW_copyContextPtr_OpenGL(RGFW_glContext* ctx, RGFW_glContext* newCtx); + +/**! + * @brief sets the window's context to a context that was already created + * @param win A pointer to the RGFW_window. + * @param ctx A pointer to the RGFW_glContext to use. + * @return boolean RGFW_TRUE for success, RGFW_FALSE for failure +*/ +RGFWDEF RGFW_bool RGFW_window_setContext_OpenGL(RGFW_window* win, RGFW_glContext* ctx); + +/**! + * @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 void RGFW_window_deleteContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx); +RGFWDEF RGFW_glContext* RGFW_window_getContext_OpenGL(RGFW_window* win); /**! * @brief Retrieves the native source context from an RGFW_glContext. @@ -2421,6 +2599,12 @@ RGFWDEF void RGFW_window_swapBuffers_OpenGL(RGFW_window* win); RGFWDEF void* RGFW_getCurrentContext_OpenGL(void); /**! + * @brief Retrieves the current OpenGL surface. + * @return A pointer to the currently active OpenGL surface (GLX, WGL, Cocoa, or WebGL backend). +*/ +RGFWDEF void* RGFW_getCurrentSurface_OpenGL(void); + +/**! * @brief Retrieves the current OpenGL window. * @return A pointer to the RGFW_window currently bound as the OpenGL context target. */ @@ -2455,43 +2639,66 @@ RGFWDEF RGFW_bool RGFW_extensionSupported_OpenGL(const char* extension, size_t l * @return RGFW_TRUE if supported, RGFW_FALSE otherwise. */ RGFWDEF RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char* extension, size_t len); +#endif -/* these are EGL specific functions, they may fallback to OpenGL */ #ifdef RGFW_EGL + +/* these are EGL specific functions, they may fallback to OpenGL */ /**! - * @brief Creates and allocates an OpenGL/EGL context for the specified window. - * @param win A pointer to the target RGFW_window. + * @brief Creates and allocates an OpenGL/EGL context that can be attached to a 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); +RGFWDEF RGFW_eglContext* RGFW_createContext_EGL(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. + * @brief Creates an OpenGL/EGL context that can be attached to a window, using a preallocated context structure. * @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); +RGFWDEF RGFW_bool RGFW_createContextPtr_EGL(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. + * @note you should set the window context to NULL with RGFW_window_setContext_OpenGL(win, NULL) after calling this function */ -RGFWDEF void RGFW_window_deleteContext_EGL(RGFW_window* win, RGFW_eglContext* ctx); +RGFWDEF void RGFW_deleteContext_EGL(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. + * @note you should set the window context to NULL with RGFW_window_setContext_OpenGL(win, NULL) after calling this function +*/ +RGFWDEF void RGFW_deleteContextPtr_EGL(RGFW_eglContext* ctx); + +/**! + * @brief allocates a new context, copying the info from an old context + * @param ctx A pointer to the RGFW_eglContext to copy. + * @return The newly allocated context +*/ +RGFWDEF RGFW_eglContext* RGFW_copyContext_EGL(RGFW_eglContext* ctx); + +/**! + * @brief copies info from a context to make a new context with the supplied pointer + * @param ctx A pointer to the RGFW_eglContext to copy. + * @param newCtx A pointer to the new context. + * @return boolean RGFW_TRUE for success, RGFW_FALSE for failure */ -RGFWDEF void RGFW_window_deleteContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ctx); +RGFWDEF RGFW_bool RGFW_copyContextPtr_EGL(RGFW_eglContext* ctx, RGFW_eglContext* newCtx); + +/**! + * @brief sets the window's context to a context that was already created + * @param win A pointer to the RGFW_window. + * @param ctx A pointer to the RGFW_eglContext to use. + * @return boolean RGFW_TRUE for success, RGFW_FALSE for failure +*/ +RGFWDEF RGFW_bool RGFW_window_setContext_EGL(RGFW_window* win, RGFW_eglContext* ctx); /**! * @brief Retrieves the OpenGL/EGL context associated with a window. @@ -2559,6 +2766,12 @@ RGFWDEF void RGFW_window_makeCurrentContext_EGL(RGFW_window* win); RGFWDEF void* RGFW_getCurrentContext_EGL(void); /**! + * @brief Retrieves the current EGL surface. + * @return A pointer to the currently active EGLSurface. +*/ +RGFWDEF void* RGFW_getCurrentSurface_EGL(void); + +/**! * @brief Retrieves the current EGL window. * @return A pointer to the RGFW_window currently bound as the EGL context target. */ @@ -2593,13 +2806,17 @@ RGFWDEF RGFW_bool RGFW_extensionSupported_EGL(const char* extension, size_t len) * @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 <vulkan/vulkan.h> +#endif /* RGFW_EGL */ -/* if you don't want to use the above macros */ +#ifdef RGFW_VULKAN +/**! + * @brief Retrieves the address of a Vulkan procedure using a Vulkan instance. + * @param the Vulkan Instance to use + * @param procname The name of the Vulkan function to look up. + * @return A pointer to the function, or NULL if not found. +*/ +RGFWDEF RGFW_proc RGFW_getInstanceProcAddress_Vulkan(VkInstance instance, const char* procname); /**! * @brief Retrieves the Vulkan instance extensions required by RGFW. @@ -2624,7 +2841,7 @@ RGFWDEF VkResult RGFW_window_createSurface_Vulkan(RGFW_window* win, VkInstance i * @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(VkPhysicalDevice physicalDevice, u32 queueFamilyIndex); +RGFWDEF RGFW_bool RGFW_getPhysicalDevicePresentationSupport_Vulkan(VkInstance instance, VkPhysicalDevice physicalDevice, u32 queueFamilyIndex); #endif #ifdef RGFW_DIRECTX @@ -2645,7 +2862,7 @@ RGFWDEF RGFW_bool RGFW_getPresentationSupport_Vulkan(VkPhysicalDevice physicalDe * @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); +RGFWDEF i32 RGFW_window_createSwapChain_DirectX(RGFW_window* win, IDXGIFactory* pFactory, IUnknown* pDevice, IDXGISwapChain** swapchain); #endif #endif @@ -2728,75 +2945,34 @@ RGFWDEF u32 RGFW_rgfwToApiKey(RGFW_key keycode); */ RGFWDEF RGFW_key RGFW_physicalToMappedKey(RGFW_key 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 + #ifdef RGFW_EGL struct RGFW_eglContext { void* ctx; void* surface; + void* config; struct wl_egl_window* eglWindow; }; + #endif + #if defined(RGFW_OPENGL) || defined(RGFW_EGL) typedef union RGFW_gfxContext { - RGFW_glContext* native; - RGFW_eglContext* egl; + #ifdef RGFW_OPENGL + RGFW_glContext* native; + #endif + + #ifdef RGFW_EGL + RGFW_eglContext* egl; + #endif } RGFW_gfxContext; typedef RGFW_ENUM(u32, RGFW_gfxContextType) { RGFW_gfxNativeOpenGL = RGFW_BIT(0), - RGFW_gfxEGL = RGFW_BIT(1), - RGFW_gfxOwnedByRGFW = RGFW_BIT(2) + RGFW_gfxEGL = RGFW_BIT(1) }; #endif @@ -2820,7 +2996,7 @@ RGFWDEF RGFW_info* RGFW_getInfo(void); }; #ifdef RGFW_OPENGL - struct RGFW_glContext { HGLRC ctx; }; + struct RGFW_glContext { HGLRC ctx; i32 format; }; #endif struct RGFW_window_src { @@ -2830,7 +3006,7 @@ RGFWDEF RGFW_info* RGFW_getInfo(void); i32 maxSizeW, maxSizeH, minSizeW, minSizeH, aspectRatioW, aspectRatioH; /*!< for setting max/min resize (RGFW_WINDOWS) */ RGFW_bool actionFrame; /* frame after a caption button was toggled (e.g. minimize, maximize or close) */ WCHAR highSurrogate; - #ifdef RGFW_OPENGL + #if defined(RGFW_OPENGL) || defined(RGFW_EGL) RGFW_gfxContext ctx; RGFW_gfxContextType gfxType; #endif @@ -2841,10 +3017,8 @@ RGFWDEF RGFW_info* RGFW_getInfo(void); #include <X11/Xlib.h> #include <X11/Xutil.h> - #ifndef RGFW_NO_XRANDR - #include <X11/extensions/Xrandr.h> - #include <X11/Xresource.h> - #endif + #include <X11/extensions/Xrandr.h> + #include <X11/Xresource.h> #ifndef RGFW_XDND_VERSION #define RGFW_XDND_VERSION 5 @@ -2873,10 +3047,11 @@ RGFWDEF RGFW_info* RGFW_getInfo(void); RGFW_format format; }; - #ifdef RGFW_OPENGL + #if defined(RGFW_OPENGL) || defined(RGFW_EGL) struct RGFW_glContext { #ifdef RGFW_X11 struct __GLXcontextRec* ctx; /*!< source graphics context */ + void* config; Window window; #endif #ifdef RGFW_WAYLAND @@ -2887,7 +3062,7 @@ RGFWDEF RGFW_info* RGFW_getInfo(void); struct RGFW_window_src { i32 x, y, w, h; - #ifdef RGFW_OPENGL + #if defined(RGFW_OPENGL) || defined(RGFW_EGL) RGFW_gfxContext ctx; RGFW_gfxContextType gfxType; #endif @@ -2954,7 +3129,7 @@ RGFWDEF RGFW_info* RGFW_getInfo(void); void* view; /* apple viewpoint thingy */ void* mouse; void* delegate; - #ifdef RGFW_OPENGL + #if defined(RGFW_OPENGL) || defined(RGFW_EGL) RGFW_gfxContext ctx; RGFW_gfxContextType gfxType; #endif @@ -2969,14 +3144,14 @@ RGFWDEF RGFW_info* RGFW_getInfo(void); RGFW_format format; }; - #ifdef RGFW_OPENGL + #if defined(RGFW_OPENGL) || defined(RGFW_EGL) struct RGFW_glContext { EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx; }; #endif struct RGFW_window_src { - #ifdef RGFW_OPENGL + #if defined(RGFW_OPENGL) || defined(RGFW_EGL) RGFW_gfxContext ctx; RGFW_gfxContextType gfxType; #endif @@ -3007,7 +3182,9 @@ typedef struct RGFW_windowInternal { RGFW_eventFlag enabledEvents; u32 flags; /*!< windows flags (for RGFW to check and modify) */ i32 oldX, oldY, oldW, oldH; - RGFW_monitorMode oldMode; + RGFW_bool oldBorderless; + RGFW_monitor* monitor; + RGFW_monitorMode oldMode, newMode; RGFW_mouse* mouse; } RGFW_windowInternal; @@ -3015,6 +3192,7 @@ 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 user data */ + RGFW_window* next; /* pointer to the next RGFW window in the same context */ i32 x, y, w, h; /*!< position and size of the window */ }; /*!< window structure for the window */ @@ -3022,7 +3200,7 @@ typedef struct RGFW_windowState { RGFW_bool mouseEnter; RGFW_bool dataDragging; RGFW_bool dataDrop; - size_t dataSize; + size_t dataLength; 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 */ @@ -3046,8 +3224,7 @@ struct RGFW_monitorNode { RGFW_monitorMode* modes; size_t modeCount; #endif -#if defined(RGFW_X11) && !defined(RGFW_NO_XRANDR) - i32 screen; +#if defined(RGFW_X11) RROutput rrOutput; RRCrtc crtc; #endif @@ -3060,6 +3237,7 @@ struct RGFW_monitorNode { void* screen; CGDirectDisplayID display; u32 uintNum; + CFArrayRef allModes; #endif }; @@ -3070,18 +3248,17 @@ typedef struct RGFW_monitorList { typedef struct RGFW_monitors { RGFW_monitorList list; - RGFW_monitorList freeList; size_t count; RGFW_monitorNode* primary; - RGFW_monitorNode data[RGFW_MAX_MONITORS]; + #if (RGFW_PREALLOCATED_MONITORS) + RGFW_monitorList freeList; + RGFW_monitorNode data[RGFW_PREALLOCATED_MONITORS]; + #endif } RGFW_monitors; -RGFWDEF RGFW_monitorNode* RGFW_monitors_add(const RGFW_monitor* mon); -RGFWDEF void RGFW_monitors_remove(RGFW_monitorNode* node, RGFW_monitorNode* prev); - struct RGFW_info { - RGFW_window* root; + RGFW_window* root, * cur; i32 windowCount; RGFW_mouse* hiddenMouse; @@ -3107,24 +3284,20 @@ struct RGFW_info { RGFW_key keycodes[256]; #endif - const char* className; - RGFW_bool useWaylandBool; RGFW_bool stopCheckEvents_bool ; u64 timerOffset; - char* clipboard_data; - char* clipboard; /* for writing to the clipboard selection */ - size_t clipboard_len; + RGFW_dataTransfer* clipboard; RGFW_bool dndBuild; RGFW_dataDropNode* dndRoot; RGFW_dataDropNode* dndCur; #ifdef RGFW_X11 + const char* className; Display* display; XContext context; Window helperWindow; - const char* instName; XErrorEvent* x11Error; i32 xrandrEventBase; XIM im; @@ -3132,7 +3305,44 @@ struct RGFW_info { long x11Version; i32 x11Format; RGFW_dataTransferType x11TransferType; - #endif + Atom _NET_WORKAREA, + _NET_CURRENT_DESKTOP, + _NET_WM_STATE_MAXIMIZED_VERT, + _NET_WM_STATE_MAXIMIZED_HORZ, + _NET_WM_BYPASS_COMPOSITOR, + _NET_WM_STATE, + _MOTIF_WM_HINTS, + WM_DELETE_WINDOW, + _NET_WM_SYNC_REQUEST_COUNTER, + _NET_WM_SYNC_REQUEST, + ATOM_PAIR, + MULTIPLE, + TARGETS, + SAVE_TARGETS, + UTF8_STRING, + XdndAware, + XdndTypeList, + XdndSelection, + XdndEnter, + XdndPosition, + XdndStatus, + XdndLeave, + XdndDrop, + XdndFinished, + XdndActionCopy, + WM_PROTOCOLS, + WM_STATE, + _NET_WM_STATE_FULLSCREEN, + _NET_WM_STATE_ABOVE, + NET_WM_WINDOW_OPACITY, + _NET_WM_NAME, + _NET_WM_ICON, + XSEL_DATA, + CLIPBOARD, + CLIPBOARD_MANAGER, + XtextUriList, + XtextPlain; + #endif #ifdef RGFW_WAYLAND struct wl_display* wl_display; struct xkb_context *xkb_context; @@ -3168,13 +3378,20 @@ struct RGFW_info { u32 last_key; /* wayland key repeat data */ i32 wl_repeat_info_rate, wl_repeat_info_delay; u32 last_key_time; - #endif + RGFW_bool useWaylandBool; + #endif + #ifdef RGFW_WINDOWS + HINSTANCE instance; + WNDCLASSW wndClass; + HWND helperWindow; + wchar_t wideClassName[256]; + #endif RGFW_monitors monitors; #ifdef RGFW_UNIX int eventWait_forceStop[3]; - i32 clock; + RGFW_dataTransfer* unixClipboard; #endif #ifdef RGFW_MACOS @@ -3183,15 +3400,39 @@ struct RGFW_info { void* customViewClasses[2]; /* NSView and NSOpenGLView */ void* customNSAppDelegateClass; void* customWindowDelegateClass; + void* customWindowClass; void* customNSAppDelegate; void* tisBundle; #endif - #ifdef RGFW_OPENGL + #if defined(RGFW_OPENGL) || defined(RGFW_EGL) RGFW_window* current; #endif + #ifdef RGFW_OPENGL + void* nativeGL_handle; + RGFW_proc (*glGetProcAddress)(const char*); + #endif #ifdef RGFW_EGL void* EGL_display; + void* EGL_handle; + RGFW_proc (*eglGetProcAddress)(const char*); + #endif + #ifdef RGFW_VULKAN + void* vulkan_handle; + RGFW_proc (*vkGetInstanceProcAddress)(void*, const char*); + #if defined(RGFW_X11) + RGFW_vkCreateXlibSurfaceKHRProc vkCreateXlibSurfaceKHR; + RGFW_vkGetPhysicalDeviceXlibPresentationSupportKHRProc vkGetPhysicalDeviceXlibPresentationSupportKHR; + #endif + #ifdef RGFW_WAYLAND + RGFW_vkCreateWaylandSurfaceKHRProc vkCreateWaylandSurfaceKHR; + RGFW_vkGetPhysicalDeviceWaylandPresentationSupportKHRProc vkGetPhysicalDeviceWaylandPresentationSupportKHR; + #endif + + #ifdef RGFW_WINDOWS + RGFW_vkCreateWin32SurfaceKHRProc vkCreateWin32SurfaceKHR; + RGFW_vkGetPhysicalDeviceWin32PresentationSupportKHRProc vkGetPhysicalDeviceWin32PresentationSupportKHR; + #endif #endif RGFW_bool rawMouse; /* global raw mouse toggle */ @@ -3211,25 +3452,45 @@ struct RGFW_info { #include <math.h> #endif +#if defined(RGFW_MACOS) || defined(RGFW_UNIX) + #include <dlfcn.h> +#endif + /* global private API */ /* for C++ / C89 */ RGFWDEF RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win); RGFWDEF void RGFW_window_closePlatform(RGFW_window* win); RGFWDEF RGFW_bool RGFW_window_setMousePlatform(RGFW_window* win, RGFW_mouse* mouse); - +RGFWDEF void RGFW_window_showPlatform(RGFW_window* win); +RGFWDEF void RGFW_window_restorePlatform(RGFW_window* win); +RGFWDEF void RGFW_window_minimizePlatform(RGFW_window* win); +RGFWDEF void RGFW_window_movePlatform(RGFW_window* win, i32 x, i32 y); +RGFWDEF void RGFW_window_resizePlatform(RGFW_window* win, i32 w, i32 h); +RGFWDEF void RGFW_window_maximizePlatform(RGFW_window* win); +RGFWDEF void RGFW_window_setFullscreenPlatform(RGFW_window* win, RGFW_bool fullscreen); 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_keyUpdateKeyModsEx(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_keyUpdateKeyMods(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_keyUpdateKeyMod(RGFW_window* win, RGFW_keymod mod, RGFW_bool value); + +RGFWDEF RGFW_bool RGFW_loadGL(void); +RGFWDEF void RGFW_unloadGL(void); +RGFWDEF RGFW_bool RGFW_loadEGL(void); +RGFWDEF void RGFW_unloadEGL(void); +RGFWDEF RGFW_bool RGFW_loadVulkan(void); +RGFWDEF void RGFW_unloadVulkan(void); + RGFWDEF void RGFW_monitors_refresh(void); +RGFWDEF RGFW_monitorNode* RGFW_monitors_add(const RGFW_monitor* mon); +RGFWDEF void RGFW_monitors_remove(RGFW_monitorNode* node, RGFW_monitorNode* prev); +RGFWDEF void RGFW_monitorNode_free(RGFW_monitorNode* node); RGFWDEF void RGFW_windowMaximizedCallback(RGFW_window* win, i32 x, i32 y, i32 w, i32 h); RGFWDEF void RGFW_windowMinimizedCallback(RGFW_window* win); @@ -3237,7 +3498,7 @@ RGFWDEF void RGFW_windowRestoredCallback(RGFW_window* win, i32 x, i32 y, i32 w, RGFWDEF void RGFW_windowMovedCallback(RGFW_window* win, i32 x, i32 y); RGFWDEF void RGFW_windowResizedCallback(RGFW_window* win, i32 w, i32 h); RGFWDEF void RGFW_windowCloseCallback(RGFW_window* win); -RGFWDEF void RGFW_mousePosCallback(RGFW_window* win, i32 x, i32 y); +RGFWDEF void RGFW_mouseMotionCallback(RGFW_window* win, i32 x, i32 y); RGFWDEF void RGFW_rawMotionCallback(RGFW_window* win, float x, float y); RGFWDEF void RGFW_windowRefreshCallback(RGFW_window* win, i32 x, i32 y, i32 w, i32 h); RGFWDEF void RGFW_windowFocusCallback(RGFW_window* win, RGFW_bool inFocus); @@ -3260,9 +3521,7 @@ RGFWDEF void RGFW_window_setRawMouseModePlatform(RGFW_window *win, RGFW_bool sta 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, RGFW_convertImageDataFunc func); -RGFWDEF RGFW_bool RGFW_loadEGL(void); - -#ifdef RGFW_OPENGL +#if defined(RGFW_OPENGL) || defined(RGFW_EGL) typedef struct RGFW_attribStack { i32* attribs; size_t count; @@ -3275,11 +3534,31 @@ RGFWDEF void RGFW_attribStack_pushAttribs(RGFW_attribStack* stack, i32 attrib1, RGFWDEF RGFW_bool RGFW_extensionSupportedStr(const char* extensions, const char* ext, size_t len); #endif +#ifndef RGFW_EGL +RGFW_bool RGFW_loadEGL(void) { return RGFW_FALSE; } +void RGFW_unloadEGL(void) { } +#endif + +#ifndef RGFW_OPENGL +RGFW_bool RGFW_loadGL(void) { return RGFW_FALSE; } +void RGFW_unloadGL(void) { } +#endif + +#ifndef RGFW_VULKAN +RGFW_bool RGFW_loadVulkan(void) { return RGFW_FALSE; } +void RGFW_unloadVulkan(void) { } +#endif + #ifdef RGFW_X11 -RGFWDEF void RGFW_XCreateWindow (XVisualInfo visual, const char* name, RGFW_windowFlags flags, RGFW_window* win); +RGFWDEF RGFW_bool RGFW_XCreateWindow (XVisualInfo visual, const char* name, RGFW_windowFlags flags, RGFW_window* win); +RGFWDEF char* RGFW_XGetWindowName(Window window); #endif #ifdef RGFW_MACOS RGFWDEF void RGFW_osx_initView(RGFW_window* win); + + #ifdef RGFW_OPENGL + RGFWDEF void RGFW_copyContext_OSX_OpenGL(RGFW_glContext* ctx, RGFW_glContext* newCtx); + #endif #endif /* end of global private API defs */ @@ -3291,46 +3570,38 @@ 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_setRawMouseMode(RGFW_bool state) { _RGFW->rawMouse = state; RGFW_window_setRawMouseModePlatform(_RGFW->root, state); } -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 RGFW_dataTransfer* RGFW_readClipboard(RGFW_dataTransferType requestedType) { + RGFW_dataTransfer data_check; + RGFW_bool ret = RGFW_readClipboardPtr(requestedType, NULL, 0, &data_check); + if (ret == RGFW_FALSE || data_check.length == 0) return _RGFW->clipboard; -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'; + u8* cont_data = (u8*)RGFW_ALLOC(sizeof(RGFW_dataTransfer) + (size_t)data_check.length); + RGFW_ASSERT(cont_data != NULL); - size = RGFW_readClipboardPtr(str, (size_t)size); + RGFW_dataTransfer* data = (RGFW_dataTransfer*)(void*)cont_data; + ret = RGFW_readClipboardPtr(requestedType, (u8*)&cont_data[sizeof(RGFW_dataTransfer) - 1], data_check.length, data); - RGFW_CHECK_CLIPBOARD(); + if (ret == RGFW_FALSE || data->length == 0) { + RGFW_FREE(cont_data); + data = NULL; + } else if (_RGFW->clipboard) { + RGFW_FREE(_RGFW->clipboard); + } - if (len != NULL) *len = (size_t)size; + _RGFW->clipboard = data; - RGFW_clipboard_switch(str); - return (const char*)str; + return _RGFW->clipboard; } -/* generic RGFW defines */ +const RGFW_dataTransfer* RGFW_readClipboardString(void) { return RGFW_readClipboard(RGFW_dataText); } +RGFW_bool RGFW_readClipboardStringPtr(u8* buffer, size_t capacity, RGFW_dataTransfer* data) { return RGFW_readClipboardPtr(RGFW_dataText, buffer, capacity, data); } +/* generic RGFW defines */ void RGFW_initKeycodes(void) { RGFW_MEMZERO(_RGFW->keycodes, sizeof(_RGFW->keycodes)); RGFW_initKeycodesPlatform(); @@ -3368,7 +3639,7 @@ void RGFW_resetKey(void) { RGFW_MEMZERO(_RGFW->keyboard, sizeof(_RGFW->keyboard) RGFW_genericFunc RGFW_setEventCallback(RGFW_eventType type, RGFW_genericFunc func) { RGFW_ASSERT(type > RGFW_eventNone && type < RGFW_eventCount); - RGFW_init(); + RGFW_ASSERT(_RGFW && "An RGFW context must be initialized using RGFW_init and/or set with RGFW_setInfo"); RGFW_genericFunc old = _RGFW->callbacks[type]; _RGFW->callbacks[type] = func; @@ -3392,7 +3663,8 @@ void RGFW_setAllEventCallbacks(RGFW_genericFunc func, RGFW_callbacks* callbacks) } RGFW_debugFunc RGFW_setDebugCallback(RGFW_debugFunc func) { - RGFW_init(); + RGFW_ASSERT(_RGFW && "An RGFW context must be initialized using RGFW_init and/or set with RGFW_setInfo"); + RGFW_debugFunc prev = _RGFW->debugCallbackSrc; _RGFW->debugCallbackSrc = func; return prev; @@ -3467,7 +3739,7 @@ void RGFW_windowMovedCallback(RGFW_window* win, i32 x, i32 y) { RGFW_event event; event.type = RGFW_windowMoved; event.update.x = x; - event.update.x = y; + event.update.y = y; event.update.w = win->w; event.update.h = win->h; event.common.win = win; @@ -3498,14 +3770,14 @@ void RGFW_windowCloseCallback(RGFW_window* win) { RGFW_eventQueuePushAndCall(&event); } -void RGFW_mousePosCallback(RGFW_window* win, i32 x, i32 y) { +void RGFW_mouseMotionCallback(RGFW_window* win, i32 x, i32 y) { win->internal.lastMouseX = x; win->internal.lastMouseY = y; - if (!(win->internal.enabledEvents & RGFW_mousePosChangedFlag)) return; + if (!(win->internal.enabledEvents & RGFW_mouseMotionFlag)) return; RGFW_event event; - event.type = RGFW_mousePosChanged; + event.type = RGFW_mouseMotion; event.mouse.x = x; event.mouse.y = y; event.mouse.inWindow = win->internal.mouseInside; @@ -3549,14 +3821,24 @@ void RGFW_windowFocusCallback(RGFW_window* win, RGFW_bool inFocus) { event.common.win = win; event.focus.state = inFocus; + #ifdef RGFW_MACOS + if (RGFW_window_isFullscreen(win)) { + RGFW_window_setFullscreenPlatform(win, inFocus); + } + #endif + if (inFocus == RGFW_TRUE) { - if ((win->internal.flags & RGFW_windowFullscreen)) + if ((win->internal.flags & RGFW_windowFullscreenExclusive) && win->internal.monitor) { RGFW_window_raise(win); + RGFW_monitor_setMode(win->internal.monitor, &win->internal.newMode); + } event.type = RGFW_windowFocusIn; } else if (inFocus == RGFW_FALSE) { - if ((win->internal.flags & RGFW_windowFullscreen)) + if ((win->internal.flags & RGFW_windowFullscreenExclusive) && win->internal.monitor) { RGFW_window_minimize(win); + RGFW_monitor_setMode(win->internal.monitor, &win->internal.oldMode); + } size_t key; for (key = 0; key < RGFW_keyLast; key++) { @@ -3605,18 +3887,18 @@ void RGFW_mouseNotifyCallback(RGFW_window* win, i32 x, i32 y, RGFW_bool status) RGFW_eventQueuePushAndCall(&event); } -void RGFW_dataDropCallback(RGFW_window* win, const char* data, size_t size, RGFW_dataTransferType dataType) { +void RGFW_dataDropCallback(RGFW_window* win, const char* data, size_t length, RGFW_dataTransferType dataType) { if (!(win->internal.enabledEvents & RGFW_dataDropFlag) || !(win->internal.flags & RGFW_windowAllowDND)) return; _RGFW->windowState.win = win; _RGFW->windowState.dataDrop = RGFW_TRUE; - _RGFW->windowState.dataSize = size; + _RGFW->windowState.dataLength = length; RGFW_dataDropNode node; RGFW_MEMZERO(&node, sizeof(node)); node.data = data; - node.size = size; + node.length = length; node.type = dataType; node.next = NULL; @@ -3636,8 +3918,8 @@ void RGFW_dataDropCallback(RGFW_window* win, const char* data, size_t size, RGFW _RGFW->dndCur = _RGFW->dndCur->next; } else { RGFW_ASSERT(0); } - char* dataCopy = (char*)RGFW_ALLOC(size); - RGFW_MEMCPY(dataCopy, data, size); + char* dataCopy = (char*)RGFW_ALLOC(length); + RGFW_MEMCPY(dataCopy, data, length); node.data = dataCopy; RGFW_MEMCPY(_RGFW->dndCur, &node, sizeof(node)); @@ -3676,10 +3958,10 @@ void RGFW_keyCharCallback(RGFW_window* win, u32 codepoint) { RGFW_eventQueuePushAndCall(&event); } -void RGFW_keyCallback(RGFW_window* win, RGFW_key key, RGFW_keymod mod, RGFW_bool repeat, RGFW_bool press) { +void RGFW_keyCallback(RGFW_window* win, RGFW_key key, RGFW_keymod mod, RGFW_bool repeat, RGFW_bool state) { RGFW_event event; - if (press) { + if (state) { if (!(win->internal.enabledEvents & RGFW_keyPressedFlag)) return; event.type = RGFW_keyPressed; } else { @@ -3688,12 +3970,12 @@ void RGFW_keyCallback(RGFW_window* win, RGFW_key key, RGFW_keymod mod, RGFW_bool } _RGFW->keyboard[key].prev = _RGFW->keyboard[key].current; - _RGFW->keyboard[key].current = press; + _RGFW->keyboard[key].current = state; event.key.value = key; event.key.repeat = repeat; event.key.mod = mod; - event.key.state = press; + event.key.state = state; event.common.win = win; RGFW_eventQueuePushAndCall(&event); } @@ -3802,18 +4084,18 @@ 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; } +RGFW_window_src* RGFW_window_getSrc(RGFW_window* win) { RGFW_ASSERT(win); return &win->src; } +RGFW_bool RGFW_window_getPosition(RGFW_window* win, i32* x, i32* y) { RGFW_ASSERT(win); 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) { RGFW_ASSERT(win); if (w) *w = win->w; if (h) *h = win->h; return RGFW_TRUE; } +u32 RGFW_window_getFlags(RGFW_window* win) { RGFW_ASSERT(win); return win->internal.flags; } +RGFW_key RGFW_window_getExitKey(RGFW_window* win) { RGFW_ASSERT(win); return win->internal.exitKey; } +void RGFW_window_setExitKey(RGFW_window* win, RGFW_key key) { RGFW_ASSERT(win); win->internal.exitKey = key; } +void RGFW_window_setEnabledEvents(RGFW_window* win, RGFW_eventFlag events) { RGFW_ASSERT(win); win->internal.enabledEvents = events; } +RGFW_eventFlag RGFW_window_getEnabledEvents(RGFW_window* win) { RGFW_ASSERT(win); return win->internal.enabledEvents; } +void RGFW_window_setDisabledEvents(RGFW_window* win, RGFW_eventFlag events) { RGFW_ASSERT(win); RGFW_window_setEnabledEvents(win, (RGFW_allEventFlags) & ~(u32)events); } +void RGFW_window_setEventState(RGFW_window* win, RGFW_eventFlag event, RGFW_bool state) { RGFW_ASSERT(win); RGFW_setBit(&win->internal.enabledEvents, event, state); } +void* RGFW_window_getUserPtr(RGFW_window* win) { RGFW_ASSERT(win); return win->userPtr; } +void RGFW_window_setUserPtr(RGFW_window* win, void* ptr) { RGFW_ASSERT(win); win->userPtr = ptr; } RGFW_bool RGFW_window_getSizeInPixels(RGFW_window* win, i32* w, i32* h) { RGFW_monitor* mon = RGFW_window_getMonitor(win); @@ -3831,40 +4113,70 @@ RGFW_bool RGFW_window_getSizeInPixels(RGFW_window* win, i32* w, i32* h) { #include "XDL.h" #endif -#ifndef RGFW_FORCE_INIT -RGFW_info _rgfwGlobal; -#endif +#ifndef RGFW_NO_STATIC_CONTEXT + +i32 RGFW_init(const char* className, RGFW_initFlags flags) { + static RGFW_info _rgfwGlobal; + return RGFW_init_ptr(className, flags, &_rgfwGlobal); +} + + +void RGFW_deinit(void) { RGFW_deinit_ptr(_RGFW); } + +#else -i32 RGFW_init(void) { return RGFW_init_ptr(&_rgfwGlobal); } -void RGFW_deinit(void) { RGFW_deinit_ptr(&_rgfwGlobal); } +RGFW_info* _rgfwGlobal; + +i32 RGFW_init(const char* className, RGFW_initFlags flags) { + if (_rgfwGlobal != NULL) { + RGFW_FREE(_rgfwGlobal); + } + + _rgfwGlobal = (RGFW_info*)RGFW_ALLOC(sizeof(RGFW_info)); + return RGFW_init_ptr(className, flags, &_rgfwGlobal); +} + +void RGFW_deinit(void) { + if (_RGFW == _rgfwGlobal) { + RGFW_FREE(_rgfwGlobal); + _rgfwGlobal = NULL; + } + RGFW_deinit_ptr(_RGFW); +} -i32 RGFW_initPlatform(void); +#endif + +i32 RGFW_initPlatform(const char* className, RGFW_initFlags flags); void RGFW_deinitPlatform(void); -i32 RGFW_init_ptr(RGFW_info* info) { +i32 RGFW_init_ptr(const char* className, RGFW_initFlags flags, RGFW_info* info) { if (info == _RGFW || info == NULL) return 1; + className = className ? className : "RGFW"; + RGFW_setInfo(info); RGFW_MEMZERO(_RGFW, sizeof(RGFW_info)); - _RGFW->queueEvents = RGFW_FALSE; - _RGFW->polledEvents = RGFW_FALSE; -#ifdef RGFW_WAYLAND - _RGFW->useWaylandBool = RGFW_TRUE; -#endif - _RGFW->monitors.freeList.head = &_RGFW->monitors.data[0]; - _RGFW->monitors.freeList.cur = _RGFW->monitors.freeList.head; + #if (RGFW_PREALLOCATED_MONITORS) + _RGFW->monitors.freeList.head = &_RGFW->monitors.data[0]; + _RGFW->monitors.freeList.cur = _RGFW->monitors.freeList.head; - for (size_t 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; - } + for (size_t i = 1; i < RGFW_PREALLOCATED_MONITORS; i++) { + RGFW_monitorNode* newNode = &_RGFW->monitors.data[i]; + _RGFW->monitors.freeList.cur->next = newNode; + _RGFW->monitors.freeList.cur = _RGFW->monitors.freeList.cur->next; + } + #endif - _RGFW->monitors.list.head = NULL; - _RGFW->monitors.list.head = NULL; RGFW_initKeycodes(); - i32 out = RGFW_initPlatform(); + i32 out = RGFW_initPlatform(className, flags); + if (out != 0) { + RGFW_debugCallback(RGFW_typeError, RGFW_infoGlobal, "failed to initialize global context"); + RGFW_deinitPlatform(); + RGFW_MEMZERO(_RGFW, sizeof(RGFW_info)); + RGFW_setInfo(NULL); + return out; + } for (size_t i = 0; i < RGFW_mouseIconCount; i++) { _RGFW->standardMice[i] = RGFW_createMouseStandard((RGFW_mouseIcon)i); @@ -3872,29 +4184,57 @@ i32 RGFW_init_ptr(RGFW_info* info) { RGFW_pollMonitors(); + if (flags & RGFW_initOpenGL) { + #ifdef RGFW_WAYLAND + if (!(flags & RGFW_initX11)) { + flags |= RGFW_initEGL; + } else + #endif + + if (RGFW_loadGL() == RGFW_FALSE) { + RGFW_debugCallback(RGFW_typeError, RGFW_errFailedFuncLoad, "Failed to load the OpenGL library"); + return -1; + } + } + + if (flags & RGFW_initVulkan) { + if (RGFW_loadVulkan() == RGFW_FALSE) { + RGFW_debugCallback(RGFW_typeError, RGFW_errFailedFuncLoad, "Failed to load the Vulkan library"); + return -1; + } + } + + if (flags & RGFW_initEGL) { + if (RGFW_loadEGL() == RGFW_FALSE) { + RGFW_debugCallback(RGFW_typeError, RGFW_errFailedFuncLoad, "Failed to load the EGL library"); + return -1; + } + } + RGFW_debugCallback(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(); for (RGFW_mouseIcon i = 0; i < RGFW_mouseIconCount; i++) { if (_RGFW->standardMice[i]) RGFW_freeMouse(_RGFW->standardMice[i]); } + RGFW_freeMonitors(); + RGFW_debugCallback(RGFW_typeInfo, RGFW_infoGlobal, "global context deinitialized"); RGFW_deinitPlatform(); + RGFW_unloadEGL(); + RGFW_unloadGL(); + _RGFW->root = NULL; + _RGFW->cur = NULL; _RGFW->windowCount = 0; RGFW_setInfo(NULL); } @@ -3912,17 +4252,32 @@ void RGFW_window_close(RGFW_window* win) { } RGFW_window* RGFW_createWindowPtr(const char* name, i32 x, i32 y, i32 w, i32 h, RGFW_windowFlags flags, RGFW_window* win) { + RGFW_ASSERT(_RGFW && "An RGFW context must be initialized using RGFW_init and/or set with RGFW_setInfo"); RGFW_ASSERT(win != NULL); if (name == NULL) name = "\0"; - RGFW_MEMZERO(win, sizeof(RGFW_window)); +#ifndef RGFW_OPENGL + if ((flags & RGFW_windowOpenGL)) { + RGFW_debugCallback(RGFW_typeWarning, RGFW_warningOpenGL, "cannot create an OpenGL context if RGFW is not compiled with OpenGL support via RGFW_OPENGL"); + flags &= (RGFW_windowFlags)~RGFW_windowOpenGL; + } +#endif +#ifndef RGFW_EGL + if ((flags & RGFW_windowEGL)) { + RGFW_debugCallback(RGFW_typeWarning, RGFW_warningOpenGL, "cannot create an EGL context if RGFW is not compiled with EGL support via RGFW_EGL"); + flags &= (RGFW_windowFlags)~RGFW_windowEGL; + } +#endif - if (_RGFW == NULL) RGFW_init(); + RGFW_MEMZERO(win, sizeof(RGFW_window)); _RGFW->windowCount++; /* rect based the requested flags */ if (_RGFW->root == NULL) { RGFW_setRootWindow(win); + _RGFW->cur = _RGFW->root; + } else { + _RGFW->cur->next = win; } /* set and init the new window's data */ @@ -3933,11 +4288,15 @@ RGFW_window* RGFW_createWindowPtr(const char* name, i32 x, i32 y, i32 w, i32 h, win->internal.mouse = _RGFW->standardMice[RGFW_mouseNormal]; win->internal.flags = flags; win->internal.enabledEvents = RGFW_allEventFlags; + win->next = NULL; RGFW_windowFlags reservedFlags = flags & (RGFW_windowScaleToMonitor); - flags &= ~reservedFlags; RGFW_window* ret = RGFW_createWindowPlatform(name, flags, win); + if (ret == NULL) { + RGFW_debugCallback(RGFW_typeError, RGFW_errPlatform, "failed to create a window"); + return NULL; + } flags |= reservedFlags; @@ -3947,13 +4306,18 @@ RGFW_window* RGFW_createWindowPtr(const char* name, i32 x, i32 y, i32 w, i32 h, #ifdef RGFW_OPENGL win->src.gfxType = 0; - if (flags & RGFW_windowOpenGL) - RGFW_window_createContext_OpenGL(win, RGFW_getGlobalHints_OpenGL()); + if (flags & RGFW_windowOpenGL) { + RGFW_glContext* context = RGFW_createContext_OpenGL(RGFW_getGlobalHints_OpenGL()); + if (context) RGFW_window_setContext_OpenGL(win, context); + } #endif #ifdef RGFW_EGL - if (flags & RGFW_windowEGL) - RGFW_window_createContext_EGL(win, RGFW_getGlobalHints_OpenGL()); + if (!(flags & RGFW_windowOpenGL)) win->src.gfxType = 0; + if (flags & RGFW_windowEGL) { + RGFW_eglContext* context = RGFW_createContext_EGL(RGFW_getGlobalHints_OpenGL()); + if (context) RGFW_window_setContext_EGL(win, context); + } #endif /* X11 creates the window after the OpenGL context is created (because of visual garbage), @@ -3965,11 +4329,6 @@ RGFW_window* RGFW_createWindowPtr(const char* name, i32 x, i32 y, i32 w, i32 h, 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 */ @@ -3987,6 +4346,10 @@ RGFW_window* RGFW_createWindowPtr(const char* name, i32 x, i32 y, i32 w, i32 h, } #endif +#ifdef RGFW_MACOS + RGFW_osx_initView(win); +#endif + if (!(flags & RGFW_windowHideMouse)) { RGFW_window_setMouseDefault(win); } @@ -3995,6 +4358,8 @@ RGFW_window* RGFW_createWindowPtr(const char* name, i32 x, i32 y, i32 w, i32 h, if (!(flags & RGFW_windowHide)) { flags |= RGFW_windowHide; RGFW_window_show(win); + } else if ((flags & RGFW_windowMaximize) || (flags & RGFW_windowFullscreenExclusive) || (flags & RGFW_windowFullscreenBorderless)) { + RGFW_window_hide(win); } RGFW_debugCallback(RGFW_typeInfo, RGFW_infoWindow, "a new window was created"); @@ -4004,6 +4369,9 @@ RGFW_window* RGFW_createWindowPtr(const char* name, i32 x, i32 y, i32 w, i32 h, void RGFW_window_closePtr(RGFW_window* win) { RGFW_ASSERT(win != NULL); + if ((win->internal.flags & RGFW_windowFullscreenExclusive) && win->internal.monitor) { + RGFW_monitor_setMode(win->internal.monitor, &win->internal.oldMode); + } if (win->internal.captureMouse) { RGFW_window_captureMouse(win, RGFW_FALSE); @@ -4011,26 +4379,37 @@ void RGFW_window_closePtr(RGFW_window* win) { #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; + RGFW_eglContext* ctx = win->src.ctx.egl; + RGFW_window_setContext_EGL(win, NULL); + RGFW_deleteContext_EGL(ctx); } #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; + RGFW_glContext* ctx = win->src.ctx.native; + RGFW_window_setContext_OpenGL(win, NULL); + RGFW_deleteContext_OpenGL(ctx); } #endif RGFW_window_closePlatform(win); - RGFW_clipboard_switch(NULL); + if (_RGFW->root == win) { + _RGFW->root = win->next; + if (_RGFW->cur == win) _RGFW->cur = NULL; + } else if (_RGFW->cur == win) { + RGFW_window* cur; + for (cur = _RGFW->root; cur->next && cur->next != win; cur = cur->next); + _RGFW->cur = cur; + } + + if (_RGFW->clipboard != NULL) + RGFW_FREE(_RGFW->clipboard); + _RGFW->clipboard = NULL; _RGFW->windowCount--; RGFW_debugCallback(RGFW_typeInfo, RGFW_infoWindow, "a window was freed"); - - if (_RGFW->windowCount == 0 && !(win->internal.flags & RGFW_noDeinitOnClose)) RGFW_deinit(); } void RGFW_setQueueEvents(RGFW_bool queue) { _RGFW->queueEvents = RGFW_BOOL(queue); } @@ -4210,6 +4589,7 @@ RGFW_event* RGFW_window_eventQueuePop(RGFW_window* win) { } if (ev->common.win != win && ev->common.win != NULL) { + RGFW_eventQueuePush(ev); return NULL; } @@ -4219,10 +4599,6 @@ RGFW_event* RGFW_window_eventQueuePop(RGFW_window* win) { 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) { if (flags & RGFW_windowNoBorder) RGFW_window_setBorder(win, 0); else if (cmpFlags & RGFW_windowNoBorder) RGFW_window_setBorder(win, 1); @@ -4232,8 +4608,10 @@ void RGFW_window_setFlagsInternal(RGFW_window* win, RGFW_windowFlags flags, RGFW else if (cmpFlags & RGFW_windowMinimize) RGFW_window_restore(win); 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_windowFullscreen) RGFW_window_setFullscreen(win, RGFW_TRUE); - else if (cmpFlags & RGFW_windowFullscreen) RGFW_window_setFullscreen(win, 0); + if (flags & RGFW_windowFullscreenExclusive) RGFW_window_setFullscreen(win, RGFW_fullscreenExclusive); + else if (cmpFlags & RGFW_windowFullscreenExclusive) RGFW_window_setFullscreen(win, 0); + if (flags & RGFW_windowFullscreenBorderless) RGFW_window_setFullscreen(win, RGFW_fullscreenBorderless); + else if (cmpFlags & RGFW_fullscreenBorderless) RGFW_window_setFullscreen(win, 0); 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); @@ -4269,13 +4647,8 @@ RGFW_bool RGFW_window_isInFocus(RGFW_window* win) { #endif } -void RGFW_setClassName(const char* name) { RGFW_init(); _RGFW->className = name; } void RGFW_setBuildDND(RGFW_bool state) { _RGFW->dndBuild = state; } -#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; @@ -4301,6 +4674,7 @@ u64 RGFW_window_getWindow_X11(RGFW_window* win) { RGFW_UNUSED(win); return 0; } #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; } +RGFW_bool RGFW_usingWayland(void) { return RGFW_FALSE; } #endif #ifndef RGFW_WINDOWS @@ -4329,12 +4703,19 @@ void RGFW_window_center(RGFW_window* win) { } RGFW_bool RGFW_monitor_scaleToWindow(RGFW_monitor* mon, RGFW_window* win) { - RGFW_monitorMode mode; RGFW_ASSERT(win != NULL); + RGFW_ASSERT(mon != NULL); + RGFW_monitorMode mode = mon->mode; mode.w = win->w; mode.h = win->h; RGFW_bool ret = RGFW_monitor_requestMode(mon, &mode, RGFW_monitorScale); + if (ret == RGFW_FALSE) { + RGFW_monitorMode closest; + ret = RGFW_monitor_findClosestMode(mon, &mode, &closest); + if (ret == RGFW_FALSE) { return ret; } + ret = RGFW_monitor_setMode(mon, &closest); + } /* move window to monitor origin so it doesn't move to the next monitor */ RGFW_window_move(win, mon->x, mon->y); @@ -4374,13 +4755,14 @@ void RGFW_window_setShouldClose(RGFW_window* win, RGFW_bool shouldClose) { void RGFW_window_scaleToMonitor(RGFW_window* win) { RGFW_monitor* monitor = RGFW_window_getMonitor(win); - if (monitor->scaleX == 0 && monitor->scaleY == 0) + if (monitor == NULL || (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_ASSERT(m != NULL); RGFW_window_move(win, m->x + win->x, m->y + win->y); } @@ -4478,14 +4860,22 @@ void RGFW_copyImageData64(u8* dest_data, i32 dest_w, i32 dest_h, RGFW_format des RGFW_monitorNode* RGFW_monitors_add(const RGFW_monitor* mon) { RGFW_monitorNode* node = NULL; - if (_RGFW->monitors.freeList.head == NULL) return node; - node = _RGFW->monitors.freeList.head; - - _RGFW->monitors.freeList.head = node->next; - if (_RGFW->monitors.freeList.head == NULL) { - _RGFW->monitors.freeList.cur = NULL; + #if (RGFW_PREALLOCATED_MONITORS) + node = _RGFW->monitors.freeList.head; + if (node) { + _RGFW->monitors.freeList.head = node->next; + if (_RGFW->monitors.freeList.head == NULL) { + _RGFW->monitors.freeList.cur = NULL; + } + } else + #elif !defined(RGFW_NO_ALLOCATE_MONITORS) + { + node = (RGFW_monitorNode*)RGFW_ALLOC(sizeof(RGFW_monitorNode)); } + #endif + + if (node == NULL) return NULL; node->next = NULL; @@ -4508,23 +4898,34 @@ RGFW_monitorNode* RGFW_monitors_add(const RGFW_monitor* mon) { void RGFW_monitors_remove(RGFW_monitorNode* node, RGFW_monitorNode* prev) { _RGFW->monitors.count -= 1; + RGFW_monitorNode_free(node); + /* remove node from the list */ if (prev != node) { prev->next = node->next; } else { /* node is the head */ - _RGFW->monitors.list.head = NULL; + _RGFW->monitors.list.head = node->next; } 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; - } + #if (RGFW_PREALLOCATED_MONITORS) + /* check if the monitor was allocated in the heap or not */ + if (node >= _RGFW->monitors.data && node <= &_RGFW->monitors.data[RGFW_PREALLOCATED_MONITORS - 1]) { + /* 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->monitors.freeList.cur = node; + } else + { + #elif !defined(RGFW_NO_ALLOCATE_MONITORS) + RGFW_FREE(node); + #endif + } } void RGFW_monitors_refresh(void) { @@ -4538,7 +4939,17 @@ void RGFW_monitors_refresh(void) { } } +void RGFW_freeMonitors(void) { + RGFW_monitorNode* node = _RGFW->monitors.list.head; + while (node != NULL) { + RGFW_monitorNode* next = node->next; + RGFW_monitors_remove(node, node); + node = next; + } +} + RGFW_monitorMode* RGFW_monitor_getModes(RGFW_monitor* monitor, size_t* count) { + RGFW_ASSERT(monitor != NULL); size_t num = RGFW_monitor_getModesPtr(monitor, NULL); RGFW_monitorMode* modes = (RGFW_monitorMode*)RGFW_ALLOC(num * sizeof(RGFW_monitorNode)); num = RGFW_monitor_getModesPtr(monitor, &modes); @@ -4552,36 +4963,50 @@ void RGFW_freeModes(RGFW_monitorMode* modes) { } RGFW_bool RGFW_monitor_findClosestMode(RGFW_monitor* monitor, RGFW_monitorMode* mode, RGFW_monitorMode* closest) { + RGFW_ASSERT(monitor != NULL); size_t count = RGFW_monitor_getModesPtr(monitor, NULL); RGFW_monitorMode* modes = (RGFW_monitorMode*)RGFW_ALLOC(count * sizeof(RGFW_monitorNode)); count = RGFW_monitor_getModesPtr(monitor, &modes); RGFW_monitorMode* chosen = NULL; + u32 sizeScore = UINT_MAX; + u32 rateScore = UINT_MAX; + u32 colorScore = UINT_MAX; - u32 topScore = 1; for (size_t i = 0; i < count; i++) { RGFW_monitorMode* mode2 = &modes[i]; - u32 score = 0; - if (mode->w == mode2->w && mode->h == mode2->h) score += 1000; - if (mode->red == mode2->red && mode->green == mode2->green && mode->blue == mode2->blue) score += 100; - if (mode->refreshRate == mode->refreshRate) score += 10; + u32 currColorScore = 0; + if (mode->red) currColorScore += (u32)RGFW_ABS(mode2->red - mode->red); + if (mode->blue) currColorScore += (u32)RGFW_ABS(mode2->green - mode->green); + if (mode->green) currColorScore += (u32)RGFW_ABS(mode2->blue - mode->blue); - if (score > topScore) { - topScore = score; - chosen = mode2; - } + u32 currSizeScore = (u32)RGFW_ABS((mode2->w - mode->w) * (mode2->w- mode->w) + + (mode2->h - mode->h) * (mode2->h - mode->h)); + + + u32 currRateScore = UINT_MAX - (u32)mode2->refreshRate; + currRateScore = (u32)RGFW_ABS(mode2->refreshRate - mode->refreshRate); + + if ((currColorScore < colorScore) || + (currColorScore == colorScore && currSizeScore < sizeScore) || + (currColorScore == colorScore && currSizeScore == sizeScore && currRateScore < rateScore)) { + sizeScore = currSizeScore; + rateScore = currRateScore; + colorScore = currColorScore; + chosen = mode2; + } } if (chosen && closest) *closest = *chosen; - RGFW_FREE(modes); return (chosen == NULL) ? RGFW_FALSE : RGFW_TRUE; } RGFW_bool RGFW_monitor_getPosition(RGFW_monitor* monitor, i32* x, i32* y) { + RGFW_ASSERT(monitor != NULL); if (x) *x = monitor->x; if (y) *y = monitor->y; return RGFW_TRUE; @@ -4592,31 +5017,37 @@ const char* RGFW_monitor_getName(RGFW_monitor* monitor) { } RGFW_bool RGFW_monitor_getScale(RGFW_monitor* monitor, float* x, float* y) { + RGFW_ASSERT(monitor != NULL); if (x) *x = monitor->scaleX; if (y) *y = monitor->scaleY; return RGFW_TRUE; } RGFW_bool RGFW_monitor_getPhysicalSize(RGFW_monitor* monitor, float* w, float* h) { + RGFW_ASSERT(monitor != NULL); if (w) *w = monitor->physW; if (h) *h = monitor->physH; return RGFW_TRUE; } void RGFW_monitor_setUserPtr(RGFW_monitor* monitor, void* userPtr) { + RGFW_ASSERT(monitor != NULL); monitor->userPtr = userPtr; } void* RGFW_monitor_getUserPtr(RGFW_monitor* monitor) { + RGFW_ASSERT(monitor != NULL); return monitor->userPtr; } RGFW_bool RGFW_monitor_getMode(RGFW_monitor* monitor, RGFW_monitorMode* mode) { + RGFW_ASSERT(monitor != NULL); if (mode) *mode = monitor->mode; return RGFW_TRUE; } RGFW_gammaRamp* RGFW_monitor_getGammaRamp(RGFW_monitor* monitor) { + RGFW_ASSERT(monitor != NULL); RGFW_gammaRamp* ramp = (RGFW_gammaRamp*)RGFW_ALLOC(sizeof(RGFW_gammaRamp)); ramp->count = RGFW_monitor_getGammaRampPtr(monitor, NULL); ramp->red = (u16*)RGFW_ALLOC(sizeof(u16) * ramp->count); @@ -4659,6 +5090,7 @@ RGFW_bool RGFW_monitor_setGammaPtr(RGFW_monitor* monitor, float gamma, u16* ptr, } RGFW_bool RGFW_monitor_setGamma(RGFW_monitor* monitor, float gamma) { + RGFW_ASSERT(monitor != NULL); size_t count = RGFW_monitor_getGammaRampPtr(monitor, NULL); u16* ptr = (u16*)RGFW_ALLOC(count * sizeof(u16)); @@ -4669,23 +5101,50 @@ RGFW_bool RGFW_monitor_setGamma(RGFW_monitor* monitor, float gamma) { } RGFW_monitor** RGFW_getMonitors(size_t* len) { - static RGFW_monitor* monitors[RGFW_MAX_MONITORS]; - RGFW_init(); + if (len != NULL) *len = 0; + + size_t count = 0; + if (RGFW_getMonitorsPtr(0, NULL, &count) == RGFW_FALSE || count == 0) return NULL; + + RGFW_monitor** monitors = (RGFW_monitor**)RGFW_ALLOC(sizeof(RGFW_monitor*) * count); + + if (RGFW_getMonitorsPtr(count, monitors, &count) == RGFW_FALSE) { + RGFW_FREE(monitors); + return NULL; + } + + if (len != NULL) *len = count; + + return monitors; +} + +RGFW_bool RGFW_getMonitorsPtr(size_t max, RGFW_monitor** monitors, size_t* len) { + RGFW_ASSERT(monitors != NULL); + RGFW_ASSERT(_RGFW && "An RGFW context must be initialized using RGFW_init and/or set with RGFW_setInfo"); if (len != NULL) { *len = _RGFW->monitors.count; } - u8 i = 0; + if (monitors == NULL || max == 0) return RGFW_TRUE; + + + if (len != NULL) { + *len = max; + } + + size_t i = 0; RGFW_monitorNode* cur_node = _RGFW->monitors.list.head; - while (cur_node != NULL) { + while (cur_node != NULL && i < max) { monitors[i] = &cur_node->mon; i++; cur_node = cur_node->next; } - return monitors; + + return RGFW_TRUE; } RGFW_monitor* RGFW_getPrimaryMonitor(void) { + RGFW_ASSERT(_RGFW && "An RGFW context must be initialized using RGFW_init and/or set with RGFW_setInfo"); if (_RGFW->monitors.primary == NULL) { _RGFW->monitors.primary = _RGFW->monitors.list.head; } @@ -4754,7 +5213,9 @@ 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_isFullscreenExclusive(RGFW_window* win){ return RGFW_BOOL(win->internal.flags & RGFW_windowFullscreenExclusive); } +RGFW_bool RGFW_window_isFullscreenBorderless(RGFW_window* win){ return RGFW_BOOL(win->internal.flags & RGFW_windowFullscreenBorderless); } +RGFW_bool RGFW_window_isFullscreen(RGFW_window* win){ return RGFW_window_isFullscreenExclusive(win) || RGFW_window_isFullscreenBorderless(win); } RGFW_bool RGFW_window_allowsDND(RGFW_window* win) { return RGFW_BOOL(win->internal.flags & RGFW_windowAllowDND); } RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) { @@ -4782,14 +5243,6 @@ void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow) { } #endif -#if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WASM) || defined(RGFW_WAYLAND) -#ifndef __USE_POSIX199309 - #define __USE_POSIX199309 -#endif -#include <time.h> -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); @@ -4834,6 +5287,118 @@ u32 RGFW_decodeUTF8(const char* string, size_t* starting_index) { return codepoint - offsets[count - 1]; } +void RGFW_window_show(RGFW_window* win) { + RGFW_ASSERT(win != NULL); + if (win->internal.flags & RGFW_windowFocusOnShow) RGFW_window_focus(win); + RGFW_window_showPlatform(win); + if ((win->internal.flags & RGFW_windowMaximize)) RGFW_window_maximize(win); +} + +void RGFW_window_restore(RGFW_window* win) { + RGFW_ASSERT(win != NULL); + RGFW_window_restorePlatform(win); + win->internal.flags &= ~(u32)RGFW_windowMaximize; + RGFW_window_show(win); + RGFW_window_move(win, win->internal.oldX, win->internal.oldY); + RGFW_window_resize(win, win->internal.oldW, win->internal.oldH); +} + +void RGFW_window_minimize(RGFW_window* win) { + RGFW_ASSERT(win != NULL); + RGFW_window_minimizePlatform(win); + win->internal.flags &= ~(u32)RGFW_windowMaximize; +} + +void RGFW_window_maximize(RGFW_window* win) { + RGFW_ASSERT(win != NULL); + win->internal.oldX = win->x; + win->internal.oldY = win->y; + win->internal.oldW = win->w; + win->internal.oldH = win->h; + win->internal.flags |= RGFW_windowMaximize; + RGFW_window_fetchSize(win, NULL, NULL); + + RGFW_window_maximizePlatform(win); +} + +void RGFW_window_move(RGFW_window* win, i32 x, i32 y) { + RGFW_ASSERT(win != NULL); + win->x = x; + win->y = y; + RGFW_window_movePlatform(win, x, y); + win->internal.flags &= ~(u32)RGFW_windowMaximize; +} + +void RGFW_window_resize(RGFW_window* win, i32 w, i32 h) { + RGFW_ASSERT(win != NULL); + win->w = w; + win->h = h; + RGFW_window_resizePlatform(win, w, h); + win->internal.flags &= ~(u32)RGFW_windowMaximize; +} + +void RGFW_window_setFullscreen(RGFW_window* win, RGFW_fullscreenMode fullscreen) { + RGFW_ASSERT(win != NULL); + if ((fullscreen == RGFW_fullscreenExclusive && (win->internal.flags & RGFW_windowFullscreenExclusive)) || + (fullscreen == RGFW_fullscreenBorderless && RGFW_BOOL(win->internal.flags & RGFW_windowFullscreenBorderless)) || + (fullscreen == 0 && RGFW_window_isFullscreen(win) == RGFW_FALSE)) { + return; + } + + if ((fullscreen == RGFW_fullscreenExclusive && RGFW_BOOL(win->internal.flags & RGFW_windowFullscreenBorderless)) || + (fullscreen == RGFW_fullscreenBorderless && (win->internal.flags & RGFW_windowFullscreenExclusive))) { + RGFW_window_setFullscreen(win, RGFW_fullscreenNone); + } + + if (fullscreen) { + win->internal.oldX = win->x; + win->internal.oldY = win->y; + win->internal.oldW = win->w; + win->internal.oldH = win->h; + + win->internal.oldBorderless = RGFW_window_borderless(win); + RGFW_window_setBorder(win, 0); + + RGFW_monitor* mon = RGFW_window_getMonitor(win); + RGFW_window_move(win, mon->x, mon->y); + + if (fullscreen == RGFW_fullscreenExclusive) { + win->internal.oldMode = mon->mode; + RGFW_monitor_scaleToWindow(mon, win); + win->internal.monitor = mon; + win->internal.newMode = mon->mode; + win->internal.flags |= RGFW_windowFullscreenExclusive; + } else { + win->internal.flags |= RGFW_windowFullscreenBorderless; + win->internal.monitor = NULL; + } + + RGFW_window_resize(win, mon->mode.w, mon->mode.h); + } + + RGFW_window_setFullscreenPlatform(win, (fullscreen > 0) ? RGFW_TRUE : RGFW_FALSE); + + if (fullscreen == 0) { + if (win->internal.monitor != NULL) { + RGFW_monitor_setMode(win->internal.monitor, &win->internal.oldMode); + } + + RGFW_window_setBorder(win, !win->internal.oldBorderless); + + RGFW_window_move(win, win->internal.oldX, win->internal.oldY); + RGFW_window_resize(win, win->internal.oldW, win->internal.oldH); + + win->internal.flags &= ~(u32)RGFW_windowFullscreenExclusive; + win->internal.flags &= ~(u32)RGFW_windowFullscreenBorderless; + + win->x = win->internal.oldX; + win->y = win->internal.oldY; + win->w = win->internal.oldW; + win->h = win->internal.oldH; + return; + } +} + /* graphics API specific code (end of generic code) starts here @@ -4844,7 +5409,8 @@ u32 RGFW_decodeUTF8(const char* string, size_t* starting_index) { OpenGL defines start here (Normal, EGL, OSMesa) */ -#if defined(RGFW_OPENGL) +#if defined(RGFW_OPENGL) || defined(RGFW_EGL) + /* EGL, OpenGL */ #define RGFW_DEFAULT_GL_HINTS { \ /* Stencil */ 0, \ @@ -4885,7 +5451,10 @@ void RGFW_resetGlobalHints_OpenGL(void) { #endif } void RGFW_setGlobalHints_OpenGL(RGFW_glHints* hints) { RGFW_globalHints_OpenGL = hints; } -RGFW_glHints* RGFW_getGlobalHints_OpenGL(void) { RGFW_init(); return RGFW_globalHints_OpenGL; } +RGFW_glHints* RGFW_getGlobalHints_OpenGL(void) { + RGFW_ASSERT(_RGFW && "An RGFW context must be initialized using RGFW_init and/or set with RGFW_setInfo"); + return RGFW_globalHints_OpenGL; +} void* RGFW_glContext_getSourceContext(RGFW_glContext* ctx) { @@ -4902,30 +5471,15 @@ void* RGFW_glContext_getSourceContext(RGFW_glContext* ctx) { #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_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_window_deleteContext_OpenGL(RGFW_window* win, RGFW_glContext* ctx) { - RGFW_window_deleteContextPtr_OpenGL(win, ctx); - if (win->src.gfxType & RGFW_gfxOwnedByRGFW) RGFW_FREE(ctx); +void RGFW_attribStack_pushAttribs(RGFW_attribStack* stack, i32 attrib1, i32 attrib2) { + RGFW_attribStack_pushAttrib(stack, attrib1); + RGFW_attribStack_pushAttrib(stack, attrib2); } RGFW_bool RGFW_extensionSupportedStr(const char* extensions, const char* ext, size_t len) { @@ -4954,16 +5508,16 @@ RGFW_bool RGFW_extensionSupportedStr(const char* extensions, const char* ext, si 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) { +RGFWDEF RGFW_bool RGFW_extensionSupported_base(const char* extension, size_t len, RGFW_proc (*getProcAddress)(const char* procname)); +RGFW_bool RGFW_extensionSupported_base(const char* extension, size_t len, RGFW_proc (*getProcAddress)(const char* procname)) { #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"); + RGFW_proc RGFW_glGetStringi = getProcAddress("glGetStringi"); + RGFW_proc RGFW_glGetIntegerv = getProcAddress("glGetIntegerv"); if (RGFW_glGetIntegerv) ((void(*)(GLenum, GLint*))RGFW_glGetIntegerv)(GL_NUM_EXTENSIONS, &count); @@ -4976,7 +5530,7 @@ RGFW_bool RGFW_extensionSupported_base(const char* extension, size_t len) { } else #endif { - RGFW_proc RGFW_glGetString = RGFW_getProcAddress_OpenGL("glGetString"); + RGFW_proc RGFW_glGetString = getProcAddress("glGetString"); #define RGFW_GL_EXTENSIONS 0x1F03 if (RGFW_glGetString) { const char* extensions = ((const char*(*)(u32))RGFW_glGetString)(RGFW_GL_EXTENSIONS); @@ -4989,8 +5543,64 @@ RGFW_bool RGFW_extensionSupported_base(const char* extension, size_t len) { return RGFW_FALSE; } +#endif /* OpenGL or EGL */ + +#ifdef RGFW_OPENGL + +void RGFW_unloadGL(void) { + if (!_RGFW->nativeGL_handle) return; + #ifdef RGFW_WINDOWS + FreeLibrary((HMODULE)_RGFW->nativeGL_handle); + #elif defined(RGFW_UNIX) + dlclose(_RGFW->nativeGL_handle); + #endif /* OSX doesn't need it's handle freed */ + + _RGFW->nativeGL_handle = NULL; + _RGFW->glGetProcAddress = NULL; +} + +RGFW_glContext* RGFW_createContext_OpenGL(RGFW_glHints* hints) { + #ifdef RGFW_WAYLAND + if (RGFW_usingWayland()) { + return (RGFW_glContext*)RGFW_createContext_EGL(hints); + } + #endif + RGFW_glContext* ctx = (RGFW_glContext*)RGFW_ALLOC(sizeof(RGFW_glContext)); + if (RGFW_createContextPtr_OpenGL(ctx, hints) == RGFW_FALSE) { + RGFW_FREE(ctx); + return NULL; + } + 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_deleteContext_OpenGL(RGFW_glContext* ctx) { + RGFW_deleteContextPtr_OpenGL(ctx); + RGFW_FREE(ctx); +} + +RGFW_glContext* RGFW_copyContext_OpenGL(RGFW_glContext* ctx) { + RGFW_glContext* newCtx = (RGFW_glContext*)RGFW_ALLOC(sizeof(RGFW_glContext)); + RGFW_copyContextPtr_OpenGL(ctx, newCtx); + return newCtx; +} + +RGFW_bool RGFW_copyContextPtr_OpenGL(RGFW_glContext* ctx, RGFW_glContext* newCtx) { + RGFW_ASSERT(ctx); RGFW_ASSERT(newCtx); + RGFW_MEMCPY(newCtx, ctx, sizeof(RGFW_glContext)); + +#ifdef RGFW_MACOS + RGFW_copyContext_OSX_OpenGL(ctx, newCtx); +#endif + return RGFW_TRUE; +} + RGFW_bool RGFW_extensionSupported_OpenGL(const char* extension, size_t len) { - if (RGFW_extensionSupported_base(extension, len)) return RGFW_TRUE; + if (RGFW_extensionSupported_base(extension, len, RGFW_getProcAddress_OpenGL)) return RGFW_TRUE; return RGFW_extensionSupportedPlatform_OpenGL(extension, len); } @@ -5003,16 +5613,7 @@ void RGFW_window_makeCurrentWindow_OpenGL(RGFW_window* 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); -} +#endif /* OPENGL only */ /* EGL */ #ifdef RGFW_EGL @@ -5032,33 +5633,25 @@ PFNEGLDESTROYCONTEXTPROC RGFW_eglDestroyContext; PFNEGLTERMINATEPROC RGFW_eglTerminate; PFNEGLDESTROYSURFACEPROC RGFW_eglDestroySurface; PFNEGLGETCURRENTCONTEXTPROC RGFW_eglGetCurrentContext; -PFNEGLGETPROCADDRESSPROC RGFW_eglGetProcAddress = NULL; +PFNEGLGETCURRENTSURFACEPROC RGFW_eglGetCurrentSurface; PFNEGLQUERYSTRINGPROC RGFW_eglQueryString; PFNEGLGETCONFIGATTRIBPROC RGFW_eglGetConfigAttrib; #define EGL_SURFACE_MAJOR_VERSION_KHR 0x3098 #define EGL_SURFACE_MINOR_VERSION_KHR 0x30fb -#ifdef RGFW_WINDOWS - #include <windows.h> -#elif defined(RGFW_MACOS) || defined(RGFW_UNIX) - #include <dlfcn.h> -#endif - #ifdef RGFW_WAYLAND #include <wayland-egl.h> #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) { + RGFW_ASSERT(_RGFW && "An RGFW context must be initialized using RGFW_init) and/or set with RGFW_setInfo"); + if (_RGFW->eglGetProcAddress != NULL) { return RGFW_TRUE; } @@ -5066,7 +5659,7 @@ RGFW_bool RGFW_loadEGL(void) { #ifdef RGFW_WINDOWS const char* libNames[] = { "libEGL.dll", "EGL.dll" }; #elif defined(RGFW_MACOS) || defined(RGFW_UNIX) - /* Linux and macOS */ + /* unix (including macOS) */ const char* libNames[] = { "libEGL.so.1", /* most common */ "libEGL.so", /* fallback */ @@ -5076,44 +5669,45 @@ RGFW_bool RGFW_loadEGL(void) { 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"); + _RGFW->EGL_handle = (void*)LoadLibraryA(libNames[i]); + if (_RGFW->EGL_handle) { + _RGFW->eglGetProcAddress = (PFNEGLGETPROCADDRESSPROC)(RGFW_proc)GetProcAddress((HMODULE)_RGFW->EGL_handle, "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)); + _RGFW->EGL_handle = dlopen(libNames[i], RTLD_LAZY | RTLD_GLOBAL); + if (_RGFW->EGL_handle) { + void* lib = dlsym(_RGFW->EGL_handle, "eglGetProcAddress"); + if (lib != NULL) RGFW_MEMCPY(&_RGFW->eglGetProcAddress, &lib, sizeof(PFNEGLGETPROCADDRESSPROC)); break; } #endif } - if (!RGFW_eglLibHandle || !RGFW_eglGetProcAddress) { + if (!_RGFW->EGL_handle || !_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"); + 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_eglGetCurrentSurface = (PFNEGLGETCURRENTSURFACEPROC) _RGFW->eglGetProcAddress("eglGetCurrentSurface"); + RGFW_eglGetConfigAttrib = (PFNEGLGETCONFIGATTRIBPROC) _RGFW->eglGetProcAddress("eglGetConfigAttrib"); #else - RGFW_eglGetProcAddress = eglGetProcAddress; + _RGFW->eglGetProcAddress = eglGetProcAddress; RGFW_eglInitialize = (PFNEGLINITIALIZEPROC) eglInitialize; RGFW_eglGetConfigs = (PFNEGLGETCONFIGSPROC) eglGetConfigs; RGFW_eglChooseConfig = (PFNEGLCHOOSECONFIGPROC) eglChooseConfig; @@ -5129,6 +5723,7 @@ RGFW_bool RGFW_loadEGL(void) { RGFW_eglDestroySurface = (PFNEGLDESTROYSURFACEPROC) eglDestroySurface; RGFW_eglQueryString = (PFNEGLQUERYSTRINGPROC) eglQueryString; RGFW_eglGetCurrentContext = (PFNEGLGETCURRENTCONTEXTPROC) eglGetCurrentContext; + RGFW_eglGetCurrentSurface = (PFNEGLGETCURRENTSURFACEPROC) eglGetCurrentSurface; RGFW_eglGetConfigAttrib = (PFNEGLGETCONFIGATTRIBPROC)eglGetConfigAttrib; #endif @@ -5147,6 +5742,7 @@ RGFW_bool RGFW_loadEGL(void) { RGFW_eglDestroySurface!= NULL && RGFW_eglQueryString != NULL && RGFW_eglGetCurrentContext != NULL && + RGFW_eglGetCurrentSurface != NULL && RGFW_eglGetConfigAttrib != NULL); if (out) { @@ -5155,7 +5751,7 @@ RGFW_bool RGFW_loadEGL(void) { _RGFW->EGL_display = RGFW_eglGetDisplay((EGLNativeDisplayType) dc); ReleaseDC(NULL, dc); #elif defined(RGFW_WAYLAND) - if (_RGFW->useWaylandBool) + if (RGFW_usingWayland() == RGFW_TRUE) _RGFW->EGL_display = RGFW_eglGetDisplay((EGLNativeDisplayType) _RGFW->wl_display); else #endif @@ -5175,28 +5771,19 @@ RGFW_bool RGFW_loadEGL(void) { void RGFW_unloadEGL(void) { - if (!RGFW_eglLibHandle) return; + if (!_RGFW->EGL_handle) return; RGFW_eglTerminate(_RGFW->EGL_display); #ifdef RGFW_WINDOWS - FreeLibrary((HMODULE)RGFW_eglLibHandle); + FreeLibrary((HMODULE)_RGFW->EGL_handle); #elif defined(RGFW_MACOS) || defined(RGFW_UNIX) - dlclose(RGFW_eglLibHandle); + dlclose(_RGFW->EGL_handle); #endif - RGFW_eglLibHandle = NULL; - RGFW_eglGetProcAddress = NULL; + _RGFW->EGL_handle = 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 - +RGFW_bool RGFW_createContextPtr_EGL(RGFW_eglContext* ctx, RGFW_glHints* hints) { #ifndef EGL_OPENGL_ES1_BIT #define EGL_OPENGL_ES1_BIT 0x1 #endif @@ -5243,8 +5830,13 @@ RGFW_bool RGFW_window_createContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ct RGFW_eglChooseConfig(_RGFW->EGL_display, egl_config, configs, numConfigs, &numConfigs); + if (hints->profile == RGFW_glES) + RGFW_eglBindAPI(EGL_OPENGL_ES_API); + else + RGFW_eglBindAPI(EGL_OPENGL_API); + #ifdef RGFW_X11 - RGFW_bool transparent = (win->internal.flags & RGFW_windowTransparent); + RGFW_bool transparent = (hints->depth == 32); EGLint best_depth = 0; #endif @@ -5258,7 +5850,7 @@ RGFW_bool RGFW_window_createContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ct if (best_config == -1) best_config = i; #ifdef RGFW_X11 - if (_RGFW->useWaylandBool == RGFW_FALSE) { + if (RGFW_usingWayland() == RGFW_FALSE) { XVisualInfo vinfo_template; vinfo_template.visualid = (VisualID)visual_id; @@ -5287,15 +5879,101 @@ RGFW_bool RGFW_window_createContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ct } EGLConfig config = configs[best_config]; + ctx->config = config; + RGFW_FREE(configs); + + 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); + } else if (hints->profile == RGFW_glForwardCompatibility) { + RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE, EGL_TRUE); + } + + + 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); + } + + ctx->ctx = RGFW_eglCreateContext(_RGFW->EGL_display, config, hints->shareEGL, attribs); + if (ctx->ctx == NULL) { + RGFW_attribStack stack; + RGFW_attribStack_init(&stack, attribs, 20); + RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_CLIENT_VERSION, hints->major); + RGFW_attribStack_pushAttribs(&stack, EGL_NONE, EGL_NONE); + ctx->ctx = RGFW_eglCreateContext(_RGFW->EGL_display, config, hints->shareEGL, attribs); + } + + if (ctx->ctx == NULL) { + RGFW_debugCallback(RGFW_typeError, RGFW_errEGLContext, "Failed to create an EGL context."); + return RGFW_FALSE; + } + + RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "EGL context initalized."); + return RGFW_TRUE; +} + +RGFW_bool RGFW_window_setContext_EGL(RGFW_window* win, RGFW_eglContext* ctx) { + RGFW_ASSERT(win); + if (ctx == NULL && win->src.ctx.egl != NULL) { + #ifdef RGFW_WAYLAND + if (RGFW_usingWayland() == RGFW_TRUE) { + wl_egl_window_destroy(win->src.ctx.egl->eglWindow); + } + #endif + + win->src.ctx.egl = NULL; + RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "EGL window surface freed"); + return RGFW_TRUE; + } + + win->src.ctx.egl = ctx; + win->src.gfxType = RGFW_gfxEGL; + +#ifdef RGFW_WAYLAND + if (RGFW_usingWayland() == RGFW_TRUE) + 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 + #ifdef RGFW_X11 - if (_RGFW->useWaylandBool == RGFW_FALSE) { + if (RGFW_usingWayland() == 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); + RGFW_eglGetConfigAttrib(_RGFW->EGL_display, ctx->config, EGL_NATIVE_VISUAL_ID, &visualID); if (visualID) { desired.visualid = (VisualID)visualID; result = XGetVisualInfo(_RGFW->display, VisualIDMask, &desired, &count); @@ -5310,12 +5988,18 @@ RGFW_bool RGFW_window_createContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ct RGFW_debugCallback(RGFW_typeError, RGFW_errEGLContext, "Failed to find a valid visual for the EGL config"); } else { RGFW_bool showWindow = RGFW_FALSE; + char* name = NULL; if (win->src.window) { showWindow = (RGFW_window_isMinimized(win) == RGFW_FALSE); + name = RGFW_XGetWindowName(win->src.window); RGFW_window_closePlatform(win); } - RGFW_XCreateWindow(*result, "", win->internal.flags, win); + if (RGFW_XCreateWindow(*result, name ? name : "", win->internal.flags, win) == RGFW_FALSE) { + return RGFW_FALSE; + } + + if (name != NULL) XFree(name); if (showWindow) { RGFW_window_show(win); @@ -5325,6 +6009,8 @@ RGFW_bool RGFW_window_createContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ct } #endif + RGFW_glHints* hints = RGFW_getGlobalHints_OpenGL(); + EGLint surf_attribs[9]; { @@ -5366,81 +6052,38 @@ RGFW_bool RGFW_window_createContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ct RGFW_window_setLayer_OSX(win, layer); - win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, config, (EGLNativeWindowType) layer, surf_attribs); + win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, (EGLConfig)ctx->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); + win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, (EGLConfig)ctx->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); + if (RGFW_usingWayland() == RGFW_TRUE) + win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, (EGLConfig)ctx->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); + win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, (EGLConfig)ctx->config, (EGLNativeWindowType) win->src.window, surf_attribs); #else {} #endif #ifdef RGFW_WASM - win->src.ctx.egl->surface = eglCreateWindowSurface(_RGFW->EGL_display, config, 0, 0); + win->src.ctx.egl->surface = eglCreateWindowSurface(_RGFW->EGL_display, (EGLConfig)ctx->config, 0, 0); #endif - if (win->src.ctx.egl->surface == NULL) { + if (win->src.ctx.egl->surface == EGL_NO_SURFACE) { RGFW_debugCallback(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); - } else if (hints->profile == RGFW_glForwardCompatibility) { - RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE, EGL_TRUE); - } - - - 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); + 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); - win->src.ctx.egl->ctx = RGFW_eglCreateContext(_RGFW->EGL_display, config, hints->shareEGL, attribs); + RGFW_window_swapInterval_EGL(win, 0); - if (win->src.ctx.egl->ctx == NULL) { - RGFW_debugCallback(RGFW_typeError, RGFW_errEGLContext, "Failed to create an EGL context."); - return RGFW_FALSE; - } +#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 - 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_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "EGL context initalized."); return RGFW_TRUE; } @@ -5450,18 +6093,12 @@ RGFW_eglContext* RGFW_window_getContext_EGL(RGFW_window* win) { return win->src.ctx.egl; } -void RGFW_window_deleteContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ctx) { +void RGFW_deleteContextPtr_EGL(RGFW_eglContext* ctx) { if (_RGFW->EGL_display == NULL) return; RGFW_eglDestroySurface(_RGFW->EGL_display, ctx->surface); RGFW_eglDestroyContext(_RGFW->EGL_display, ctx->ctx); RGFW_debugCallback(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_debugCallback(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); @@ -5475,37 +6112,52 @@ void RGFW_window_makeCurrentContext_EGL(RGFW_window* win) { if (win) RGFW_ASSERT void RGFW_window_swapBuffers_EGL(RGFW_window* win) { if (RGFW_eglSwapBuffers) RGFW_eglSwapBuffers(_RGFW->EGL_display, win->src.ctx.egl->surface); + #ifdef RGFW_OPENGL else RGFW_window_swapBuffers_OpenGL(win); + #endif } void* RGFW_getCurrentContext_EGL(void) { return RGFW_eglGetCurrentContext(); } +void* RGFW_getCurrentSurface_EGL(void) { + return RGFW_eglGetCurrentSurface(EGL_DRAW); +} + RGFW_proc RGFW_getProcAddress_EGL(const char* procname) { #if defined(RGFW_WINDOWS) - RGFW_proc proc = (RGFW_proc) GetProcAddress(RGFW_wgl_dll, procname); + RGFW_proc proc = (RGFW_proc) GetProcAddress(_RGFW->nativeGL_handle, procname); if (proc) return proc; #endif - return (RGFW_proc) RGFW_eglGetProcAddress(procname); + 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); + + void* ctx = RGFW_eglGetCurrentContext(); + void* surface = RGFW_eglGetCurrentSurface(EGL_DRAW); + if (ctx == win->src.ctx.egl->ctx && surface == win->src.ctx.egl->surface) { + RGFW_eglSwapInterval(_RGFW->EGL_display, swapInterval); + return; + } + + RGFW_eglMakeCurrent(_RGFW->EGL_display, win->src.ctx.egl->surface, win->src.ctx.egl->surface, win->src.ctx.egl->ctx); RGFW_eglSwapInterval(_RGFW->EGL_display, swapInterval); + RGFW_eglMakeCurrent(_RGFW->EGL_display, surface, surface, ctx); } RGFW_bool RGFW_extensionSupported_EGL(const char* extension, size_t len) { - if (RGFW_extensionSupported_base(extension, len)) return RGFW_TRUE; + if (RGFW_extensionSupported_base(extension, len, RGFW_getProcAddress_EGL)) return RGFW_TRUE; return RGFW_extensionSupportedPlatform_EGL(extension, len); } @@ -5516,20 +6168,30 @@ void RGFW_window_makeCurrentWindow_EGL(RGFW_window* win) { RGFW_window* RGFW_getCurrentWindow_EGL(void) { return _RGFW->current; } -RGFW_eglContext* RGFW_window_createContext_EGL(RGFW_window* win, RGFW_glHints* hints) { +RGFW_eglContext* RGFW_createContext_EGL(RGFW_glHints* hints) { RGFW_eglContext* ctx = (RGFW_eglContext*)RGFW_ALLOC(sizeof(RGFW_eglContext)); - if (RGFW_window_createContextPtr_EGL(win, ctx, hints) == RGFW_FALSE) { + if (RGFW_createContextPtr_EGL(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); +void RGFW_deleteContext_EGL(RGFW_eglContext* ctx) { + RGFW_deleteContextPtr_EGL(ctx); + RGFW_FREE(ctx); +} + +RGFW_eglContext* RGFW_copyContext_EGL(RGFW_eglContext* ctx) { + RGFW_eglContext* newCtx = (RGFW_eglContext*)RGFW_ALLOC(sizeof(RGFW_eglContext)); + RGFW_copyContextPtr_EGL(ctx, newCtx); + return newCtx; +} + +RGFW_bool RGFW_copyContextPtr_EGL(RGFW_eglContext* ctx, RGFW_eglContext* newCtx) { + RGFW_ASSERT(ctx); RGFW_ASSERT(newCtx); + RGFW_MEMCPY(newCtx, ctx, sizeof(RGFW_eglContext)); + return RGFW_TRUE; } #endif /* RGFW_EGL */ @@ -5537,7 +6199,8 @@ void RGFW_window_deleteContext_EGL(RGFW_window* win, RGFW_eglContext* ctx) { /* end of RGFW_EGL defines */ -#endif /* end of RGFW_GL (OpenGL, EGL, OSMesa )*/ + +/* end of RGFW_GL (OpenGL, EGL, OSMesa )*/ /* RGFW_VULKAN defines @@ -5547,6 +6210,67 @@ void RGFW_window_deleteContext_EGL(RGFW_window* win, RGFW_eglContext* ctx) { #include <objc/message.h> #endif +RGFW_bool RGFW_loadVulkan(void) { + if (_RGFW->vulkan_handle) return RGFW_TRUE; + const char* names[] = { + #ifdef RGFW_WINDOWS + "vulkan-1.dll", + #endif + #ifdef RGFW_MACOS + "libvulkan.1.dylib", + #endif + #ifdef RGFW_UNIX + "libvulkan.so.1", + "libvulkan.so" + #endif + }; + + for (size_t i = 0; i < sizeof(names) / sizeof(names[0]); i++) { + if (_RGFW->vulkan_handle) break; + #ifdef RGFW_WINDOWS + _RGFW->vulkan_handle = LoadLibraryA(names[i]); + #else + _RGFW->vulkan_handle = dlopen(names[i], RTLD_LAZY | RTLD_LOCAL); + #endif + } + + if (!_RGFW->vulkan_handle) { + return RGFW_FALSE; + } + + #ifdef RGFW_WINDOWS + _RGFW->vkGetInstanceProcAddress = (RGFW_proc(*)(void*, const char*))(RGFW_proc)GetProcAddress((HMODULE)_RGFW->vulkan_handle, "vkGetInstanceProcAddr"); + #else + void* lib = dlsym(_RGFW->vulkan_handle, "vkGetInstanceProcAddr"); + if (lib != NULL) RGFW_MEMCPY(&_RGFW->vkGetInstanceProcAddress, &lib, sizeof(_RGFW->vkGetInstanceProcAddress)); + #endif + + if (_RGFW->vkGetInstanceProcAddress == NULL) { + return RGFW_FALSE; + } + + + return RGFW_TRUE; +} + +#define RGFW_LOAD_VK(func) if (_RGFW->func == NULL) _RGFW->func = (RGFW_##func##Proc)RGFW_getInstanceProcAddress_Vulkan(instance, #func); RGFW_ASSERT(_RGFW->func); + +void RGFW_unloadVulkan(void) { + if (!_RGFW->vulkan_handle) return; + #ifdef RGFW_WINDOWS + FreeLibrary((HMODULE)_RGFW->vulkan_handle); + #elif defined(RGFW_UNIX) + dlclose(_RGFW->vulkan_handle); + #endif /* OSX doesn't need it's handle freed */ + + _RGFW->vulkan_handle = NULL; +} + +RGFW_proc RGFW_getInstanceProcAddress_Vulkan(VkInstance instance, const char* procname) { + RGFW_ASSERT(_RGFW->vkGetInstanceProcAddress); + return _RGFW->vkGetInstanceProcAddress(instance, procname); +} + const char** RGFW_getRequiredInstanceExtensions_Vulkan(size_t* count) { static const char* arr[2] = {VK_KHR_SURFACE_EXTENSION_NAME}; arr[1] = RGFW_VK_SURFACE; @@ -5559,40 +6283,41 @@ const char** RGFW_getRequiredInstanceExtensions_Vulkan(size_t* count) { 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 - + RGFW_LOAD_VK(vkCreateXlibSurfaceKHR); 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); + return _RGFW->vkCreateXlibSurfaceKHR(instance, &x11, NULL, surface); #endif #if defined(RGFW_WAYLAND) - + RGFW_LOAD_VK(vkCreateWaylandSurfaceKHR); 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); + return _RGFW->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); + RGFW_LOAD_VK(vkCreateWin32SurfaceKHR); + VkWin32SurfaceCreateInfoKHR win32 = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, 0, 0, _RGFW->instance, (HWND)win->src.window }; + return _RGFW->vkCreateWin32SurfaceKHR(instance, &win32, NULL, surface); #endif } #endif -RGFW_bool RGFW_getPresentationSupport_Vulkan(VkPhysicalDevice physicalDevice, u32 queueFamilyIndex) { - if (_RGFW == NULL) RGFW_init(); -#ifdef RGFW_X11 +RGFW_bool RGFW_getPhysicalDevicePresentationSupport_Vulkan(VkInstance instance, VkPhysicalDevice physicalDevice, u32 queueFamilyIndex) { + RGFW_ASSERT(_RGFW && "An RGFW context must be initialized using RGFW_init and/or set with RGFW_setInfo"); +#ifdef RGFW_X11 + RGFW_LOAD_VK(vkGetPhysicalDeviceXlibPresentationSupportKHR); Visual* visual = DefaultVisual(_RGFW->display, DefaultScreen(_RGFW->display)); - RGFW_bool out = vkGetPhysicalDeviceXlibPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW->display, XVisualIDFromVisual(visual)); + RGFW_bool out = _RGFW->vkGetPhysicalDeviceXlibPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW->display, XVisualIDFromVisual(visual)); return out; #endif #if defined(RGFW_WAYLAND) - - RGFW_bool wlout = vkGetPhysicalDeviceWaylandPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW->wl_display); + RGFW_LOAD_VK(vkGetPhysicalDeviceWaylandPresentationSupportKHR); + RGFW_bool wlout = _RGFW->vkGetPhysicalDeviceWaylandPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW->wl_display); return wlout; #elif defined(RGFW_WINDOWS) - RGFW_bool out = vkGetPhysicalDeviceWin32PresentationSupportKHR(physicalDevice, queueFamilyIndex); + RGFW_LOAD_VK(vkGetPhysicalDeviceWin32PresentationSupportKHR); + RGFW_bool out = _RGFW->vkGetPhysicalDeviceWin32PresentationSupportKHR(physicalDevice, queueFamilyIndex); return out; #elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11) RGFW_UNUSED(physicalDevice); @@ -5600,6 +6325,9 @@ RGFW_bool RGFW_getPresentationSupport_Vulkan(VkPhysicalDevice physicalDevice, u3 return RGFW_FALSE; /* TODO */ #endif } + + +#undef RGFW_LOAD_VK #endif /* end of RGFW_vulkan */ /* @@ -5609,9 +6337,11 @@ This is where OS specific stuff starts /* start of unix (wayland or X11 (unix) ) defines */ #ifdef RGFW_UNIX + #include <fcntl.h> #include <poll.h> #include <unistd.h> +#include <time.h> void RGFW_stopCheckEvents(void) { @@ -5624,11 +6354,21 @@ void RGFW_stopCheckEvents(void) { } } -RGFWDEF u64 RGFW_linux_getTimeNS(void); -u64 RGFW_linux_getTimeNS(void) { - struct timespec ts; +RGFWDEF u64 RGFW_unix_getTimeNS(void); +u64 RGFW_unix_getTimeNS(void) { + struct timespec ts; + static i32 clock = -1; + if (clock == -1) { + #if defined(_POSIX_MONOTONIC_CLOCK) + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) + clock = CLOCK_MONOTONIC; + else + #endif + clock = CLOCK_REALTIME; + } + const u64 scale_factor = 1000000000; - clock_gettime(_RGFW->clock, &ts); + clock_gettime(clock, &ts); return (u64)ts.tv_sec * scale_factor + (u64)ts.tv_nsec; } @@ -5685,7 +6425,7 @@ void RGFW_waitForEvent(i32 waitMS) { } - u64 start = RGFW_linux_getTimeNS(); + u64 start = RGFW_unix_getTimeNS(); if (RGFW_usingWayland()) { #ifdef RGFW_WAYLAND while (wl_display_dispatch_pending(_RGFW->wl_display) == 0) { @@ -5698,7 +6438,7 @@ void RGFW_waitForEvent(i32 waitMS) { } if (waitMS != RGFW_eventWaitNext) { - waitMS -= (i32)(RGFW_linux_getTimeNS() - start) / (i32)1e+6; + waitMS -= (i32)(RGFW_unix_getTimeNS() - start) / (i32)1e+6; } } @@ -5714,7 +6454,7 @@ void RGFW_waitForEvent(i32 waitMS) { break; if (waitMS != RGFW_eventWaitNext) { - waitMS -= (i32)(RGFW_linux_getTimeNS() - start) / (i32)1e+6; + waitMS -= (i32)(RGFW_unix_getTimeNS() - start) / (i32)1e+6; } } #endif @@ -5781,11 +6521,11 @@ char* RGFW_strtok(char* str, const char* delimStr) { } #ifdef RGFW_X11 -RGFWDEF i32 RGFW_initPlatform_X11(void); +RGFWDEF i32 RGFW_initPlatform_X11(const char* className, RGFW_initFlags flags); RGFWDEF void RGFW_deinitPlatform_X11(void); #endif #ifdef RGFW_WAYLAND -RGFWDEF i32 RGFW_initPlatform_Wayland(void); +RGFWDEF i32 RGFW_initPlatform_Wayland(const char* className, RGFW_initFlags flags); RGFWDEF void RGFW_deinitPlatform_Wayland(void); #endif @@ -5922,34 +6662,30 @@ void RGFW_initKeycodesPlatform(void) { _RGFW->keycodes[162] = RGFW_keyWorld2; /* non-US key #2 */ } -i32 RGFW_initPlatform(void) { - #if defined(_POSIX_MONOTONIC_CLOCK) - struct timespec ts; - RGFW_MEMZERO(&ts, sizeof(struct timespec)); - - if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) - _RGFW->clock = CLOCK_MONOTONIC; - #else - _RGFW->clock = CLOCK_REALTIME; - #endif - +i32 RGFW_initPlatform(const char* className, RGFW_initFlags flags) { #ifdef RGFW_WAYLAND - RGFW_load_Wayland(); - i32 ret = RGFW_initPlatform_Wayland(); - if (ret == 0) { - return 0; + if (!(flags & RGFW_initX11)) { + _RGFW->useWaylandBool = RGFW_TRUE; + RGFW_load_Wayland(); + i32 ret = RGFW_initPlatform_Wayland(className, flags); + + if (ret == 0) { + return 0; + } else { + #ifdef RGFW_X11 + RGFW_debugCallback(RGFW_typeWarning, RGFW_warningWayland, "Falling back to X11"); + _RGFW->useWaylandBool = RGFW_FALSE; + #else + return ret; + #endif + } } else { - #ifdef RGFW_X11 - RGFW_debugCallback(RGFW_typeWarning, RGFW_warningWayland, "Falling back to X11"); - RGFW_useWayland(0); - #else - return ret; - #endif + _RGFW->useWaylandBool = RGFW_FALSE; } #endif #ifdef RGFW_X11 RGFW_load_X11(); - return RGFW_initPlatform_X11(); + return RGFW_initPlatform_X11(className, flags); #else return 0; #endif @@ -5962,7 +6698,7 @@ void RGFW_deinitPlatform(void) { close(_RGFW->eventWait_forceStop[1]); } #ifdef RGFW_WAYLAND - if (_RGFW->useWaylandBool) { + if (RGFW_usingWayland()) { RGFW_deinitPlatform_Wayland(); return; } @@ -6034,6 +6770,9 @@ void RGFW_unix_parseURI(RGFW_window* win, char* data) { } } +#if !defined(RGFW_X11) && defined(RGFW_OPENGL) +RGFW_bool RGFW_loadGL(void) { return RGFW_FALSE; } +#endif #endif /* end of wayland or X11 defines */ @@ -6041,7 +6780,7 @@ void RGFW_unix_parseURI(RGFW_window* win, char* data) { /* -Start of Linux / Unix defines +Start of *nix defines */ @@ -6053,13 +6792,16 @@ Start of Linux / Unix defines #define RGFW_FUNC(func) func #endif +#ifdef RGFW_X11_DEBUG + #define RGFW_X11_CRASH_ON_ERROR +#endif + #include <dlfcn.h> #include <unistd.h> #include <limits.h> /* for data limits (mainly used in drag and drop functions) */ #include <poll.h> -void RGFW_setXInstName(const char* name) { _RGFW->instName = name; } #if !defined(RGFW_NO_X11_CURSOR) && defined(RGFW_X11) #include <X11/Xcursor/Xcursor.h> #endif @@ -6110,7 +6852,106 @@ void RGFW_setXInstName(const char* name) { _RGFW->instName = name; } #undef GLsizeiptr #undef GLboolean #endif - typedef GLXContext(*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*); + typedef GLXContext(*RGFW_glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*); + typedef const char* (*RGFW_glXQueryExtensionsStringProc)(Display* dpy, int screen); + typedef XVisualInfo* (*RGFW_glXChooseVisualProc)(Display*, int, int*); + typedef GLXContext (*RGFW_glXCreateContextProc)(Display*, XVisualInfo*, GLXContext, Bool); + typedef Bool (*RGFW_glXMakeCurrentProc)(Display*, GLXDrawable, GLXContext); + typedef GLXContext (*RGFW_glXGetCurrentContextProc)(void); + typedef GLXContext (*RGFW_glXGetCurrentDrawableProc)(void); + typedef void (*RGFW_glXSwapBuffersProc)(Display*, GLXDrawable); + typedef PFNGLXSWAPINTERVALEXTPROC RGFW_glXSwapIntervalEXTProc; + typedef __GLXextFuncPtr (*RGFW_glXGetProcAddressProc)(const u8*procname); + typedef PFNGLXGETVISUALFROMFBCONFIGPROC RGFW_glXGetVisualFromFBConfigProc; + typedef PFNGLXGETFBCONFIGATTRIBPROC RGFW_glXGetFBConfigAttribProc; + typedef __GLXextFuncPtr (*RGFW_glXGetProcAddressARBProc)(const u8*); + typedef PFNGLXCHOOSEFBCONFIGPROC RGFW_glXChooseFBConfigProc; + typedef void (*RGFW_glXDestroyContextProc)(Display *dpy, GLXContext ctx); + typedef GLXWindow (*RGFW_glXCreateWindowProc)(Display*,GLXFBConfig,Window,const int*); + typedef void (*RGFW_glXDestroyWindowProc)(Display*,GLXWindow); + typedef int (*RGFW_GLX_MESA_swap_controlProc) (int); + typedef int (*RGFW_GLX_SGI_swap_controlProc) (int); + + RGFW_glXCreateContextAttribsARBProc RGFW_glXCreateContextAttribsARB; + RGFW_glXQueryExtensionsStringProc RGFW_glXQueryExtensionsString; + RGFW_glXChooseVisualProc RGFW_glXChooseVisual; + RGFW_glXCreateContextProc RGFW_glXCreateContext; + RGFW_glXMakeCurrentProc RGFW_glXMakeCurrent; + RGFW_glXGetCurrentContextProc RGFW_glXGetCurrentContext; + RGFW_glXGetCurrentDrawableProc RGFW_glXGetCurrentDrawable; + RGFW_glXSwapBuffersProc RGFW_glXSwapBuffers; + RGFW_glXSwapIntervalEXTProc RGFW_glXSwapIntervalEXT; + RGFW_glXGetVisualFromFBConfigProc RGFW_glXGetVisualFromFBConfig; + RGFW_glXGetFBConfigAttribProc RGFW_glXGetFBConfigAttrib; + RGFW_glXGetProcAddressARBProc RGFW_glXGetProcAddressARB; + RGFW_glXChooseFBConfigProc RGFW_glXChooseFBConfig; + RGFW_glXDestroyContextProc RGFW_glXDestroyContext; + RGFW_glXCreateWindowProc RGFW_glXCreateWindow; + RGFW_glXDestroyWindowProc RGFW_glXDestroyWindow; + RGFW_GLX_MESA_swap_controlProc RGFW_GLX_MESA_swap_control; + RGFW_GLX_SGI_swap_controlProc RGFW_GLX_SGI_swap_control; + + RGFW_bool RGFW_loadGL(void) { + RGFW_ASSERT(_RGFW && "An RGFW context must be initialized using RGFW_init and/or set with RGFW_setInfo"); + if (RGFW_usingWayland()) return RGFW_FALSE; + if (_RGFW->nativeGL_handle && _RGFW->glGetProcAddress != NULL) { + return RGFW_TRUE; + } + + const char* glxSonames[] = { + #if defined(__CYGWIN__) + "libGL-1.so", + #elif defined(__OpenBSD__) || defined(__NetBSD__) + "libGL.so", + #else + "libGLX.so.0", + "libGL.so.1", + "libGL.so", + #endif + }; + + for (int i = 0; sizeof(glxSonames) / sizeof(char*); i++) { + _RGFW->nativeGL_handle = dlopen(glxSonames[i], RTLD_LAZY | RTLD_LOCAL); + if (_RGFW->nativeGL_handle) + break; + } + + void* ptr = dlsym(_RGFW->nativeGL_handle, "glXGetProcAddress"); + RGFW_ASSERT(ptr != NULL); + RGFW_MEMCPY(&_RGFW->glGetProcAddress, &ptr, sizeof(void*)); + #define RGFW_PROC_DEF(name) if (RGFW_##name == NULL) RGFW_##name = (RGFW_##name##Proc)_RGFW->glGetProcAddress(#name); + + RGFW_PROC_DEF(glXChooseVisual); + RGFW_PROC_DEF(glXCreateContext); + RGFW_PROC_DEF(glXMakeCurrent); + RGFW_PROC_DEF(glXGetCurrentContext); + RGFW_PROC_DEF(glXGetCurrentDrawable); + RGFW_PROC_DEF(glXSwapBuffers); + RGFW_PROC_DEF(glXGetVisualFromFBConfig); + RGFW_PROC_DEF(glXGetFBConfigAttrib); + RGFW_PROC_DEF(glXGetProcAddressARB); + RGFW_PROC_DEF(glXChooseFBConfig); + RGFW_PROC_DEF(glXDestroyContext); + RGFW_PROC_DEF(glXCreateWindow); + RGFW_PROC_DEF(glXDestroyWindow); + RGFW_PROC_DEF(glXQueryExtensionsString); + RGFW_PROC_DEF(glXCreateContextAttribsARB); + RGFW_PROC_DEF(glXGetProcAddressARB); + RGFW_PROC_DEF(GLX_SGI_swap_control); + RGFW_PROC_DEF(GLX_MESA_swap_control); + RGFW_PROC_DEF(glXSwapIntervalEXT); + + if (RGFW_glXSwapIntervalEXT == NULL) { + if (RGFW_GLX_MESA_swap_control == NULL && RGFW_GLX_SGI_swap_control == NULL) { + RGFW_debugCallback(RGFW_typeWarning, RGFW_infoOpenGL, "Failed to load swap interval function"); + } else { + RGFW_debugCallback(RGFW_typeWarning, RGFW_infoOpenGL, "Failed to load swap interval function, fallingback to the native swapinterval function"); + } + } + #undef RGFW_PROC_DEF + + return RGFW_TRUE; + } #endif /* atoms needed for drag and drop */ @@ -6304,31 +7145,32 @@ void RGFW_FUNC(RGFW_surface_freePtr) (RGFW_surface* surface) { 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; + unsigned long flags, functions, decorations; long input_mode; + unsigned long status; } hints; + RGFW_MEMZERO(&hints, sizeof(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); - } + hints.decorations = border ? 1 : 0; + XChangeProperty(_RGFW->display, win->src.window, _RGFW->_MOTIF_WM_HINTS, _RGFW->_MOTIF_WM_HINTS, 32, PropModeReplace, (u8*)&hints, (sizeof(hints) / sizeof(long))); } void RGFW_FUNC(RGFW_window_setRawMouseModePlatform) (RGFW_window* win, RGFW_bool state) { - RGFW_UNUSED(win); RGFW_UNUSED(state); + RGFW_UNUSED(win); + unsigned char mask[XIMaskLen(XI_RawMotion)]; + RGFW_MEMZERO(mask, sizeof(mask)); + if (state) 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); } void RGFW_FUNC(RGFW_window_captureMousePlatform) (RGFW_window* win, RGFW_bool state) { @@ -6369,10 +7211,29 @@ int RGFW_XErrorHandler(Display* display, XErrorEvent* ev) { RGFW_debugCallback(RGFW_typeError, RGFW_errX11, buf); _RGFW->x11Error = ev; + + #ifdef RGFW_X11_CRASH_ON_ERROR + RGFW_ASSERT(0); + #endif + return 0; } -void RGFW_XCreateWindow (XVisualInfo visual, const char* name, RGFW_windowFlags flags, RGFW_window* win) { +char* RGFW_XGetWindowName(Window window) { + Atom actualType; + int actualFormat; + unsigned long nitems, bytesAfter; + char* name = NULL; + + if (XGetWindowProperty(_RGFW->display, window, _RGFW->_NET_WM_NAME, 0, (~0L), False, _RGFW->UTF8_STRING, &actualType, &actualFormat, &nitems, &bytesAfter, (u8**)&name) == Success && name) { + return name; + } + + if (XFetchName(_RGFW->display, window, &name) != Success) return NULL; + return name; +} + +RGFW_bool 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; @@ -6394,6 +7255,8 @@ void RGFW_XCreateWindow (XVisualInfo visual, const char* name, RGFW_windowFlags 0, visual.depth, InputOutput, visual.visual, CWBorderPixel | CWColormap | CWEventMask, &swa); + if (win->src.window == 0) return RGFW_FALSE; + win->src.flashEnd = 0; XFreeColors(_RGFW->display, cmap, NULL, 0, 0); @@ -6410,22 +7273,17 @@ void RGFW_XCreateWindow (XVisualInfo visual, const char* name, RGFW_windowFlags win->src.ic = XCreateIC(_RGFW->im, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, win->src.window, XNFocusWindow, win->src.window, XNDestroyCallback, &callback, 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_name = (char*)(name ? name : "RGFW"); 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); XWMHints hints; + RGFW_MEMZERO(&hints, sizeof(hints)); hints.flags = StateHint; hints.initial_state = NormalState; @@ -6434,8 +7292,7 @@ void RGFW_XCreateWindow (XVisualInfo visual, const char* name, RGFW_windowFlags 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); + XSetWMProtocols(_RGFW->display, (Drawable) win->src.window, &_RGFW->WM_DELETE_WINDOW, 1); /* set the background */ RGFW_window_setName(win, name); @@ -6445,26 +7302,22 @@ void RGFW_XCreateWindow (XVisualInfo visual, const char* name, RGFW_windowFlags 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, + _RGFW->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}; + Atom protcols[2] = {_RGFW->_NET_WM_SYNC_REQUEST, _RGFW->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, (u8*)&win->src.counter, 1); + XChangeProperty(_RGFW->display, win->src.window, _RGFW->_NET_WM_SYNC_REQUEST_COUNTER, XA_CARDINAL, 32, PropModeReplace, (u8*)&win->src.counter, 1); #endif win->src.x = win->x; @@ -6477,6 +7330,8 @@ void RGFW_XCreateWindow (XVisualInfo visual, const char* name, RGFW_windowFlags /* stupid hack to make resizing the window less bad */ XSetWindowBackgroundPixmap(_RGFW->display, win->src.window, None); + + return RGFW_TRUE; } RGFW_window* RGFW_FUNC(RGFW_createWindowPlatform) (const char* name, RGFW_windowFlags flags, RGFW_window* win) { @@ -6487,12 +7342,12 @@ RGFW_window* RGFW_FUNC(RGFW_createWindowPlatform) (const char* name, RGFW_window XVisualInfo visual; RGFW_window_getVisual(&visual, RGFW_BOOL(win->internal.flags & RGFW_windowTransparent)); - RGFW_XCreateWindow(visual, name, flags, win); + if (RGFW_XCreateWindow(visual, name, flags, win) == RGFW_FALSE) return NULL; return win; /*return newly created window */ } RGFW_bool RGFW_FUNC(RGFW_getGlobalMouse) (i32* fX, i32* fY) { - RGFW_init(); + RGFW_ASSERT(_RGFW && "An RGFW context must be initialized using RGFW_init and/or set with RGFW_setInfo"); i32 x, y; u32 z; Window window1, window2; @@ -6502,28 +7357,22 @@ RGFW_bool RGFW_FUNC(RGFW_getGlobalMouse) (i32* fX, i32* fY) { 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; Atom formats[2] = {0}; - formats[0] = UTF8_STRING; + formats[0] = _RGFW->UTF8_STRING; formats[1] = XA_STRING; const int formatCount = sizeof(formats) / sizeof(formats[0]); - if (request->target == TARGETS) { + if (request->target == _RGFW->TARGETS) { Atom targets[4] = {0}; - targets[0] = TARGETS; - targets[1] = MULTIPLE; - targets[2] = UTF8_STRING; + targets[0] = _RGFW->TARGETS; + targets[1] = _RGFW->MULTIPLE; + targets[2] = _RGFW->UTF8_STRING; targets[3] = XA_STRING; XChangeProperty(_RGFW->display, request->requestor, request->property, XA_ATOM, 32, PropModeReplace, (u8*) targets, sizeof(targets) / sizeof(Atom)); - } else if (request->target == MULTIPLE) { + } else if (request->target == _RGFW->MULTIPLE) { Atom* targets = NULL; Atom actualType = 0; @@ -6531,24 +7380,24 @@ void RGFW_XHandleClipboardSelection(XEvent* event) { RGFW_UNUSED(event); 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); + False, _RGFW->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) + if (targets[i] == _RGFW->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); + 8, PropModeReplace, (const unsigned char *)_RGFW->unixClipboard->data, (i32)_RGFW->unixClipboard->length); else targets[i + 1] = None; } XChangeProperty(_RGFW->display, - request->requestor, request->property, ATOM_PAIR, 32, + request->requestor, request->property, _RGFW->ATOM_PAIR, 32, PropModeReplace, (u8*) targets, (i32)count); XFlush(_RGFW->display); XFree(targets); - } else if (request->target == SAVE_TARGETS) + } else if (request->target == _RGFW->SAVE_TARGETS) XChangeProperty(_RGFW->display, request->requestor, request->property, 0, 32, PropModeReplace, NULL, 0); else { int i; @@ -6556,7 +7405,7 @@ void RGFW_XHandleClipboardSelection(XEvent* event) { RGFW_UNUSED(event); if (request->target != formats[i]) continue; XChangeProperty(_RGFW->display, request->requestor, request->property, request->target, - 8, PropModeReplace, (u8*) _RGFW->clipboard, (i32)_RGFW->clipboard_len); + 8, PropModeReplace, (u8*) _RGFW->unixClipboard->data, (i32)_RGFW->unixClipboard->length); } } @@ -6583,6 +7432,11 @@ RGFW_key RGFW_FUNC(RGFW_physicalToMappedKey) (RGFW_key key) { } switch (sym) { + case XK_BackSpace: return RGFW_keyBackSpace; + case XK_Tab: return RGFW_keyTab; + case XK_Return: return RGFW_keyReturn; + case XK_Escape: return RGFW_keyEscape; + case XK_Delete: return RGFW_keyDelete; case XK_F1: return RGFW_keyF1; case XK_F2: return RGFW_keyF2; case XK_F3: return RGFW_keyF3; @@ -6656,24 +7510,11 @@ RGFW_key RGFW_FUNC(RGFW_physicalToMappedKey) (RGFW_key key) { 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); - static float deltaX = 0.0f; static float deltaY = 0.0f; XEvent E; + RGFW_MEMZERO(&E, sizeof(E)); XNextEvent(_RGFW->display, &E); @@ -6682,12 +7523,10 @@ void RGFW_XHandleEvent(void) { deltaY = 0.0f; } -#ifndef RGFW_NO_XRANDR if (E.type == _RGFW->xrandrEventBase + RRNotify) { RGFW_pollMonitors(); return; } -#endif switch (E.type) { case SelectionRequest: @@ -6730,7 +7569,7 @@ void RGFW_XHandleEvent(void) { } if (win->src.flashEnd) { - if ((win->src.flashEnd <= RGFW_linux_getTimeNS()) || RGFW_window_isInFocus(win)) { + if ((win->src.flashEnd <= RGFW_unix_getTimeNS()) || RGFW_window_isInFocus(win)) { RGFW_window_flash(win, RGFW_flashCancel); } } @@ -6862,11 +7701,11 @@ void RGFW_XHandleEvent(void) { break; } case MotionNotify: - RGFW_mousePosCallback(win, E.xmotion.x, E.xmotion.y); + RGFW_mouseMotionCallback(win, E.xmotion.x, E.xmotion.y); break; case Expose: { - RGFW_windowRefreshCallback(win, 0, 0, win->w, win->h); + RGFW_windowRefreshCallback(win, E.xexpose.x, E.xexpose.y, E.xexpose.width, E.xexpose.height); #ifdef RGFW_ADVANCED_SMOOTH_RESIZE XSyncValue value; @@ -6879,12 +7718,12 @@ void RGFW_XHandleEvent(void) { case PropertyNotify: if (E.xproperty.state != PropertyNewValue) break; - if (E.xproperty.atom == WM_STATE) { + if (E.xproperty.atom == _RGFW->WM_STATE) { if (RGFW_window_isMinimized(win) && !(win->internal.flags & RGFW_windowMinimized)) { RGFW_windowMinimizedCallback(win); break; } - } else if (E.xproperty.atom == _NET_WM_STATE) { + } else if (E.xproperty.atom == _RGFW->_NET_WM_STATE) { if (RGFW_window_isMaximized(win) && !(win->internal.flags & RGFW_windowMaximize)) { RGFW_windowMaximizedCallback(win, win->x, win->y, win->w, win->h); break; @@ -6895,14 +7734,13 @@ void RGFW_XHandleEvent(void) { 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) { + if (E.xclient.data.l[0] == (long)_RGFW->WM_DELETE_WINDOW) { RGFW_windowCloseCallback(win); break; } #ifdef RGFW_ADVANCED_SMOOTH_RESIZE - if (E.xclient.message_type == WM_PROTOCOLS && (Atom)E.xclient.data.l[0] == _NET_WM_SYNC_REQUEST) { + if (E.xclient.message_type == _RGFW->WM_PROTOCOLS && (Atom)E.xclient.data.l[0] == _RGFW->_NET_WM_SYNC_REQUEST) { RGFW_windowRefreshCallback(win, 0, 0, win->w, win->h); win->src.counter_value = 0; win->src.counter_value |= E.xclient.data.l[2]; @@ -6921,7 +7759,7 @@ void RGFW_XHandleEvent(void) { i32 dragX = 0; i32 dragY = 0; - if (E.xclient.message_type == XdndEnter) { + if (E.xclient.message_type == _RGFW->XdndEnter) { unsigned long count; Atom* formats; Atom real_formats[3]; @@ -6936,7 +7774,7 @@ void RGFW_XHandleEvent(void) { unsigned long bytesAfter; XGetWindowProperty( - _RGFW->display, _RGFW->x11Source, XdndTypeList, + _RGFW->display, _RGFW->x11Source, _RGFW->XdndTypeList, 0, LONG_MAX, False, 4, &actualType, &actualFormat, &count, &bytesAfter, (u8**)&formats ); @@ -6954,13 +7792,10 @@ void RGFW_XHandleEvent(void) { 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) _RGFW->x11TransferType = RGFW_dataFile; - else if (formats[i] == XtextPlain) _RGFW->x11TransferType = RGFW_dataText; + if (formats[i] == _RGFW->XtextUriList) _RGFW->x11TransferType = RGFW_dataFile; + else if (formats[i] == _RGFW->XtextPlain) _RGFW->x11TransferType = RGFW_dataText; else continue; _RGFW->x11Format = (int)formats[i]; @@ -6973,7 +7808,7 @@ void RGFW_XHandleEvent(void) { RGFW_dataDragCallback(win, _RGFW->x11TransferType , RGFW_dndActionEnter, dragX, dragY); - } else if (E.xclient.message_type == XdndPosition) { + } else if (E.xclient.message_type == _RGFW->XdndPosition) { const i32 xabs = (E.xclient.data.l[2] >> 16) & 0xffff; const i32 yabs = (E.xclient.data.l[2]) & 0xffff; Window dummy; @@ -6987,10 +7822,10 @@ void RGFW_XHandleEvent(void) { dragX = xpos; dragY = ypos; - RGFW_mousePosCallback(win, xpos, ypos); + RGFW_mouseMotionCallback(win, xpos, ypos); XEvent reply = { ClientMessage }; reply.xclient.window = _RGFW->x11Source; - reply.xclient.message_type = XdndStatus; + reply.xclient.message_type = _RGFW->XdndStatus; reply.xclient.format = 32; reply.xclient.data.l[0] = (long)win->src.window; reply.xclient.data.l[2] = 0; @@ -6999,7 +7834,7 @@ void RGFW_XHandleEvent(void) { if (_RGFW->x11Format) { reply.xclient.data.l[1] = 1; if (_RGFW->x11Version >= 2) - reply.xclient.data.l[4] = (long)XdndActionCopy; + reply.xclient.data.l[4] = (long)_RGFW->XdndActionCopy; } XSendEvent(_RGFW->display, _RGFW->x11Source, False, NoEventMask, &reply); @@ -7007,21 +7842,21 @@ void RGFW_XHandleEvent(void) { RGFW_dataDragCallback(win, _RGFW->x11TransferType, RGFW_dndActionMove, dragX, dragY); - } else if (E.xclient.message_type == XdndLeave) { + } else if (E.xclient.message_type == _RGFW->XdndLeave) { RGFW_dataDragCallback(win, _RGFW->x11TransferType, RGFW_dndActionExit, dragX, dragY); - } else if (E.xclient.message_type == XdndDrop) { + } else if (E.xclient.message_type == _RGFW->XdndDrop) { if (_RGFW->x11Format) { Time time = (_RGFW->x11Version >= 1) ? (Time)E.xclient.data.l[2] : CurrentTime; XConvertSelection( - _RGFW->display, XdndSelection, (Atom)_RGFW->x11Format, - XdndSelection, win->src.window, time + _RGFW->display, _RGFW->XdndSelection, (Atom)_RGFW->x11Format, + _RGFW->XdndSelection, win->src.window, time ); } else if (_RGFW->x11Version >= 2) { XEvent reply = { ClientMessage }; reply.xclient.window = _RGFW->x11Source; - reply.xclient.message_type = XdndFinished; + reply.xclient.message_type = _RGFW->XdndFinished; reply.xclient.format = 32; reply.xclient.data.l[0] = (long)win->src.window; reply.xclient.data.l[1] = 0; @@ -7034,7 +7869,7 @@ void RGFW_XHandleEvent(void) { } 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)) + if (!(win->internal.enabledEvents & RGFW_dataDropFlag) || E.xselection.property != _RGFW->XdndSelection || !(win->internal.flags & RGFW_windowAllowDND)) return; char* data; unsigned long result; @@ -7055,11 +7890,11 @@ void RGFW_XHandleEvent(void) { if (_RGFW->x11Version >= 2) { XEvent reply = { ClientMessage }; reply.xclient.window = _RGFW->x11Source; - reply.xclient.message_type = XdndFinished; + reply.xclient.message_type = _RGFW->XdndFinished; reply.xclient.format = 32; reply.xclient.data.l[0] = (long)win->src.window; reply.xclient.data.l[1] = (long int)result; - reply.xclient.data.l[2] = (long int)XdndActionCopy; + reply.xclient.data.l[2] = (long int)_RGFW->XdndActionCopy; XSendEvent(_RGFW->display, _RGFW->x11Source, False, NoEventMask, &reply); XFlush(_RGFW->display); } @@ -7108,10 +7943,10 @@ void RGFW_XHandleEvent(void) { } /* detect move */ - if (E.xconfigure.x != win->src.x || E.xconfigure.y != win->src.y) { - win->src.x = E.xconfigure.x; - win->src.y = E.xconfigure.y; - RGFW_windowMovedCallback(win, E.xconfigure.x, E.xconfigure.y); + if (x != win->src.x || y != win->src.y) { + win->src.x = x; + win->src.y = y; + RGFW_windowMovedCallback(win, x, y); } return; } @@ -7142,21 +7977,12 @@ void RGFW_FUNC(RGFW_pollEvents) (void) { } } -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_movePlatform) (RGFW_window* win, i32 x, i32 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; - +void RGFW_FUNC(RGFW_window_resizePlatform) (RGFW_window* win, i32 w, i32 h) { XResizeWindow(_RGFW->display, win->src.window, (u32)w, (u32)h); if ((win->internal.flags & RGFW_windowNoResize)) { @@ -7229,32 +8055,23 @@ void RGFW_FUNC(RGFW_window_setMaxSize) (RGFW_window* win, i32 w, i32 h) { 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.message_type = _RGFW->_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[1] = (long int)_RGFW->_NET_WM_STATE_MAXIMIZED_HORZ; + xev.xclient.data.l[2] = (long int)_RGFW->_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; - +void RGFW_FUNC(RGFW_window_maximizePlatform) (RGFW_window* win) { RGFW_toggleXMaximized(win, 1); - RGFW_window_fetchSize(win, NULL, NULL); return; } @@ -7272,19 +8089,18 @@ void RGFW_FUNC(RGFW_window_focus) (RGFW_window* win) { void RGFW_FUNC(RGFW_window_raise) (RGFW_window* win) { RGFW_ASSERT(win); XMapRaised(_RGFW->display, win->src.window); - RGFW_window_setFullscreen(win, RGFW_window_isFullscreen(win)); + RGFW_window_setFullscreenPlatform(win, RGFW_window_isFullscreen(win)); } 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.message_type = _RGFW->_NET_WM_STATE; xev.xclient.window = win->src.window; xev.xclient.format = 32; xev.xclient.data.l[0] = fullscreen; @@ -7294,48 +8110,33 @@ void RGFW_window_setXAtom(RGFW_window* win, Atom netAtom, RGFW_bool fullscreen) 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; - +void RGFW_FUNC(RGFW_window_setFullscreenPlatform)(RGFW_window* win, RGFW_bool fullscreen) { XRaiseWindow(_RGFW->display, win->src.window); - RGFW_LOAD_ATOM(_NET_WM_STATE_FULLSCREEN); - RGFW_window_setXAtom(win, _NET_WM_STATE_FULLSCREEN, fullscreen); + RGFW_window_setXAtom(win, _RGFW->_NET_WM_STATE_FULLSCREEN, fullscreen); if (!(win->internal.flags & RGFW_windowTransparent)) { const unsigned char value = fullscreen; - RGFW_LOAD_ATOM(_NET_WM_BYPASS_COMPOSITOR); XChangeProperty( _RGFW->display, win->src.window, - _NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32, + _RGFW->_NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32, PropModeReplace, &value, 1); } } 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); + RGFW_window_setXAtom(win, _RGFW->_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); + _RGFW->NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32, PropModeReplace, (unsigned char*) &value, 1); } -void RGFW_FUNC(RGFW_window_minimize)(RGFW_window* win) { +void RGFW_FUNC(RGFW_window_minimizePlatform)(RGFW_window* win) { RGFW_ASSERT(win != NULL); if (RGFW_window_isMaximized(win)) return; @@ -7348,26 +8149,19 @@ void RGFW_FUNC(RGFW_window_minimize)(RGFW_window* win) { XFlush(_RGFW->display); } -void RGFW_FUNC(RGFW_window_restore)(RGFW_window* win) { +void RGFW_FUNC(RGFW_window_restorePlatform)(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); + 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, + int status = XGetWindowProperty(_RGFW->display, win->src.window, _RGFW->_NET_WM_STATE, 0, (~0L), False, XA_ATOM, &actual_type, &actual_format, &nitems, &bytes_after, (unsigned char **)&prop_return); @@ -7376,7 +8170,7 @@ RGFW_bool RGFW_FUNC(RGFW_window_isFloating)(RGFW_window* win) { unsigned long i; for (i = 0; i < nitems; i++) - if (prop_return[i] == _NET_WM_STATE_ABOVE) return RGFW_TRUE; + if (prop_return[i] == _RGFW->_NET_WM_STATE_ABOVE) return RGFW_TRUE; if (prop_return) XFree(prop_return); @@ -7390,10 +8184,8 @@ void RGFW_FUNC(RGFW_window_setName)(RGFW_window* win, const char* name) { Xutf8SetWMProperties(_RGFW->display, win->src.window, name, name, NULL, 0, NULL, NULL, NULL); XStoreName(_RGFW->display, win->src.window, name); - RGFW_LOAD_ATOM(_NET_WM_NAME); RGFW_LOAD_ATOM(UTF8_STRING); - XChangeProperty( - _RGFW->display, win->src.window, _NET_WM_NAME, UTF8_STRING, + _RGFW->display, win->src.window, _RGFW->_NET_WM_NAME, _RGFW->UTF8_STRING, 8, PropModeReplace, (u8*)name, (int)RGFW_unix_stringlen(name) ); } @@ -7414,11 +8206,10 @@ void RGFW_FUNC(RGFW_window_setMousePassthrough) (RGFW_window* win, RGFW_bool pas #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, + _RGFW->display, win->src.window, _RGFW->_NET_WM_ICON, XA_CARDINAL, 32, PropModeReplace, (u8*)NULL, 0 ); return res; @@ -7437,7 +8228,7 @@ RGFW_bool RGFW_FUNC(RGFW_window_setIconEx) (RGFW_window* win, u8* data_src, i32 RGFW_bool res = RGFW_TRUE; if (type & RGFW_iconTaskbar) { res = (RGFW_bool)XChangeProperty( - _RGFW->display, win->src.window, _NET_WM_ICON, XA_CARDINAL, 32, + _RGFW->display, win->src.window, _RGFW->_NET_WM_ICON, XA_CARDINAL, 32, PropModeReplace, (u8*)data, count ); } @@ -7498,9 +8289,9 @@ RGFW_mouse* RGFW_FUNC(RGFW_createMouseStandard) (RGFW_mouseIcon mouse) { } RGFW_mouse* RGFW_FUNC(RGFW_createMouse) (u8* data, i32 w, i32 h, RGFW_format format) { - RGFW_ASSERT(data); + RGFW_ASSERT(_RGFW && "An RGFW context must be initialized using RGFW_init and/or set with RGFW_setInfo"); + RGFW_ASSERT(data); #ifndef RGFW_NO_X11_CURSOR - RGFW_init(); XcursorImage* native = XcursorImageCreate((i32)w, (i32)h); native->xhot = 0; native->yhot = 0; @@ -7553,9 +8344,8 @@ void RGFW_FUNC(RGFW_window_hide)(RGFW_window* win) { XFlush(_RGFW->display); } -void RGFW_FUNC(RGFW_window_show) (RGFW_window* win) { +void RGFW_FUNC(RGFW_window_showPlatform) (RGFW_window* win) { win->internal.flags &= ~(u32)RGFW_windowHide; - if (win->internal.flags & RGFW_windowFocusOnShow) RGFW_window_focus(win); if (RGFW_window_isHidden(win) == RGFW_FALSE) { return; @@ -7565,7 +8355,7 @@ void RGFW_FUNC(RGFW_window_show) (RGFW_window* win) { RGFW_window_move(win, win->x, win->y); RGFW_waitForShowEvent_X11(win); - RGFW_window_setFullscreen(win, RGFW_window_isFullscreen(win)); + RGFW_window_setFullscreenPlatform(win, RGFW_window_isFullscreen(win)); return; } @@ -7580,7 +8370,7 @@ void RGFW_FUNC(RGFW_window_flash) (RGFW_window* win, RGFW_flashRequest request) if (request) { wmhints->flags |= XUrgencyHint; if (request == RGFW_flashBriefly) - win->src.flashEnd = RGFW_linux_getTimeNS() + (u64)1e+9; + win->src.flashEnd = RGFW_unix_getTimeNS() + (u64)1e+9; if (request == RGFW_flashUntilFocused) win->src.flashEnd = (u64)-1; } else { @@ -7592,56 +8382,68 @@ void RGFW_FUNC(RGFW_window_flash) (RGFW_window* win, RGFW_flashRequest request) XFree(wmhints); } -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; +RGFW_bool RGFW_FUNC(RGFW_readClipboardPtr) (RGFW_dataTransferType requestedType, u8* buffer, size_t capacity, RGFW_dataTransfer* dataTransfer) { + RGFW_ASSERT(_RGFW && "An RGFW context must be initialized using RGFW_init and/or set with RGFW_setInfo"); + RGFW_ASSERT(dataTransfer != NULL); + + if (requestedType != RGFW_dataText) return RGFW_FALSE; + dataTransfer->data = (char*)buffer; + + if (XGetSelectionOwner(_RGFW->display, _RGFW->CLIPBOARD) == _RGFW->helperWindow) { + dataTransfer->length = _RGFW->unixClipboard->length; + if (buffer != NULL && _RGFW->unixClipboard->data != NULL) { + if (_RGFW->unixClipboard->length > capacity) return RGFW_FALSE; + + RGFW_MEMCPY((char*)buffer, _RGFW->unixClipboard->data, _RGFW->unixClipboard->length); + } + + dataTransfer->type = RGFW_dataText; + return RGFW_TRUE; } XEvent event; int format; - unsigned long N, sizeN; + unsigned long N, size; char* data; Atom target; - XConvertSelection(_RGFW->display, CLIPBOARD, UTF8_STRING, XSEL_DATA, _RGFW->helperWindow, CurrentTime); + XConvertSelection(_RGFW->display, _RGFW->CLIPBOARD, _RGFW->UTF8_STRING, _RGFW->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; + if (event.xselection.selection != _RGFW->CLIPBOARD || event.xselection.property == 0) + return RGFW_FALSE; break; } XGetWindowProperty(event.xselection.display, event.xselection.requestor, event.xselection.property, 0L, (~0L), 0, AnyPropertyType, &target, - &format, &sizeN, &N, (u8**) &data); + &format, &size, &N, (u8**) &data); + + RGFW_bool ret = RGFW_TRUE; - RGFW_ssize_t size; - if (sizeN > strCapacity && str != NULL) - size = -1; + size_t length = size; + if (data[size - 1] != '\0') length += 1; + + if (size > capacity && buffer != NULL) + ret = RGFW_FALSE; + else if ((target == _RGFW->UTF8_STRING || target == XA_STRING) && buffer != NULL) { + RGFW_MEMCPY(buffer, data, size); + buffer[length - 1] = '\0'; - 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; + } else if (buffer != NULL) ret = RGFW_FALSE; XDeleteProperty(event.xselection.display, event.xselection.requestor, event.xselection.property); - size = (RGFW_ssize_t)sizeN; - return size; + dataTransfer->length = length; + dataTransfer->type = RGFW_dataText; + return ret; } i32 RGFW_XHandleClipboardSelectionHelper(void) { - RGFW_LOAD_ATOM(SAVE_TARGETS); - XEvent event; XPending(_RGFW->display); @@ -7655,7 +8457,7 @@ i32 RGFW_XHandleClipboardSelectionHelper(void) { RGFW_XHandleClipboardSelection(&event); return 0; case SelectionNotify: - if (event.xselection.target == SAVE_TARGETS) + if (event.xselection.target == _RGFW->SAVE_TARGETS) return 0; break; default: break; @@ -7664,27 +8466,37 @@ i32 RGFW_XHandleClipboardSelectionHelper(void) { return 0; } -void RGFW_FUNC(RGFW_writeClipboard)(const char* text, u32 textLen) { - RGFW_LOAD_ATOM(SAVE_TARGETS); RGFW_LOAD_ATOM(CLIPBOARD); - RGFW_init(); +RGFW_bool RGFW_FUNC(RGFW_writeClipboard)(const RGFW_dataTransfer* data) { + RGFW_ASSERT(_RGFW && "An RGFW context must be initialized using RGFW_init and/or set with RGFW_setInfo"); /* 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) { + XSetSelectionOwner(_RGFW->display, _RGFW->CLIPBOARD, _RGFW->helperWindow, CurrentTime); + if (XGetSelectionOwner(_RGFW->display, _RGFW->CLIPBOARD) != _RGFW->helperWindow) { RGFW_debugCallback(RGFW_typeError, RGFW_errClipboard, "X11 failed to become owner of clipboard selection"); - return; + return RGFW_FALSE; } - if (_RGFW->clipboard) - RGFW_FREE(_RGFW->clipboard); + if (_RGFW->unixClipboard) { + RGFW_FREE(_RGFW->unixClipboard); + _RGFW->unixClipboard = NULL; + } - _RGFW->clipboard = (char*)RGFW_ALLOC(textLen); - RGFW_ASSERT(_RGFW->clipboard != NULL); + size_t length = data->length; + if (data->data[data->length - 1] != '\0') { + length += 1; + } - RGFW_STRNCPY(_RGFW->clipboard, text, textLen - 1); - _RGFW->clipboard[textLen - 1] = '\0'; - _RGFW->clipboard_len = textLen; - return; + _RGFW->unixClipboard = (RGFW_dataTransfer*)RGFW_ALLOC(sizeof(RGFW_dataTransfer) + data->length); + RGFW_ASSERT(_RGFW->unixClipboard != NULL); + + char* data_ptr = &((char*)(void*)_RGFW->unixClipboard)[sizeof(RGFW_dataTransfer) - 1]; + RGFW_MEMCPY(data_ptr, data->data, data->length); + data_ptr[length - 1] = '\0'; + + _RGFW->unixClipboard->data = (const char*)data_ptr; + _RGFW->unixClipboard->type = RGFW_dataText; + _RGFW->unixClipboard->length = length; + return RGFW_TRUE; } RGFW_bool RGFW_FUNC(RGFW_window_isHidden)(RGFW_window* win) { @@ -7697,14 +8509,13 @@ RGFW_bool RGFW_FUNC(RGFW_window_isHidden)(RGFW_window* 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, + i32 status = XGetWindowProperty(_RGFW->display, win->src.window, _RGFW->WM_STATE, 0, 2, False, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop_data); @@ -7723,16 +8534,13 @@ RGFW_bool RGFW_FUNC(RGFW_window_isMinimized)(RGFW_window* win) { 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, + i32 status = XGetWindowProperty(_RGFW->display, win->src.window, _RGFW->_NET_WM_STATE, 0, 1024, False, XA_ATOM, &actual_type, &actual_format, &nitems, &bytes_after, &prop_data); @@ -7745,8 +8553,8 @@ RGFW_bool RGFW_FUNC(RGFW_window_isMaximized)(RGFW_window* win) { 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) { + if (prop_data[i] == _RGFW->_NET_WM_STATE_MAXIMIZED_VERT || + prop_data[i] == _RGFW->_NET_WM_STATE_MAXIMIZED_HORZ) { XFree(prop_data); return RGFW_TRUE; } @@ -7763,20 +8571,18 @@ void RGFW_XGetSystemContentDPI(float* dpi) { if (dpi == NULL) return; float dpiOutput = 96.0f; - #ifndef RGFW_NO_XRANDR - char* rms = XResourceManagerString(_RGFW->display); - if (rms == NULL) return; + char* rms = XResourceManagerString(_RGFW->display); + if (rms == NULL) return; - XrmDatabase db = XrmGetStringDatabase(rms); - if (db == NULL) return; + XrmDatabase db = XrmGetStringDatabase(rms); + if (db == NULL) return; - XrmValue value; - char* type = NULL; + XrmValue value; + char* type = NULL; - if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value) && type && RGFW_STRNCMP(type, "String", 7) == 0) - dpiOutput = (float)RGFW_ATOF(value.addr); - XrmDestroyDatabase(db); - #endif + if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value) && type && RGFW_STRNCMP(type, "String", 7) == 0) + dpiOutput = (float)RGFW_ATOF(value.addr); + XrmDestroyDatabase(db); if (dpi) *dpi = dpiOutput; } @@ -7836,7 +8642,7 @@ XRRModeInfo* RGFW_XGetMode(XRRCrtcInfo* ci, XRRScreenResources* res, RRMode mode } void RGFW_FUNC(RGFW_pollMonitors) (void) { - RGFW_init(); + RGFW_ASSERT(_RGFW && "An RGFW context must be initialized using RGFW_init and/or set with RGFW_setInfo"); Window root = XDefaultRootWindow(_RGFW->display); XRRScreenResources* res = XRRGetScreenResourcesCurrent(_RGFW->display, root); @@ -7858,14 +8664,6 @@ void RGFW_FUNC(RGFW_pollMonitors) (void) { } } - if (node) { - node->disconnected = RGFW_FALSE; - if (node->rrOutput == primary) { - _RGFW->monitors.primary = node; - } - continue; - } - RGFW_monitor monitor; XRROutputInfo* info = XRRGetOutputInfo(_RGFW->display, res, res->outputs[i]); @@ -7914,20 +8712,32 @@ void RGFW_FUNC(RGFW_pollMonitors) (void) { XRRFreeCrtcInfo(ci); - node = RGFW_monitors_add(&monitor); - if (node == NULL) break; - - node->rrOutput = res->outputs[i]; - node->crtc = info->crtc; - - if (node->rrOutput == primary) { - _RGFW->monitors.primary = node; - } + RROutput rrOutput = res->outputs[i]; + RRCrtc crtc = info->crtc; XRRFreeOutputInfo(info); info = NULL; - RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_TRUE); + if (node) { + node->disconnected = RGFW_FALSE; + if (node->rrOutput == primary) { + _RGFW->monitors.primary = node; + } + + continue; + } else { + node = RGFW_monitors_add(&monitor); + if (node == NULL) break; + + node->rrOutput = rrOutput; + node->crtc = crtc; + + if (node->rrOutput == primary) { + _RGFW->monitors.primary = node; + } + + RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_TRUE); + } } XRRFreeScreenResources(res); @@ -7935,10 +8745,12 @@ void RGFW_FUNC(RGFW_pollMonitors) (void) { RGFW_monitors_refresh(); } -RGFW_bool RGFW_FUNC(RGFW_monitor_getWorkarea) (RGFW_monitor* monitor, i32* x, i32* y, i32* width, i32* height) { - RGFW_LOAD_ATOM(_NET_WORKAREA); - RGFW_LOAD_ATOM(_NET_CURRENT_DESKTOP); +void RGFW_FUNC(RGFW_monitorNode_free) (RGFW_monitorNode* node) { + RGFW_ASSERT(node); +} +RGFW_bool RGFW_FUNC(RGFW_monitor_getWorkarea) (RGFW_monitor* monitor, i32* x, i32* y, i32* width, i32* height) { + RGFW_ASSERT(monitor != NULL); Window root = DefaultRootWindow(_RGFW->display); i32 areaX = monitor->x; @@ -7946,17 +8758,17 @@ RGFW_bool RGFW_FUNC(RGFW_monitor_getWorkarea) (RGFW_monitor* monitor, i32* x, i3 i32 areaW = monitor->mode.w; i32 areaH = monitor->mode.h; - if (_NET_WORKAREA && _NET_CURRENT_DESKTOP) { + if (_RGFW->_NET_WORKAREA && _RGFW->_NET_CURRENT_DESKTOP) { Atom* extents = NULL; Atom* desktop = NULL; Atom actualType = 0; int actualFormat = 0; unsigned long extentCount = 0, bytesAfter = 0; - XGetWindowProperty(_RGFW->display, root, _NET_WORKAREA, 0, LONG_MAX, False, XA_CARDINAL, &actualType, &actualFormat, &extentCount, &bytesAfter, (u8**) &extents); + XGetWindowProperty(_RGFW->display, root, _RGFW->_NET_WORKAREA, 0, LONG_MAX, False, XA_CARDINAL, &actualType, &actualFormat, &extentCount, &bytesAfter, (u8**) &extents); unsigned long count; - XGetWindowProperty(_RGFW->display, root, _NET_CURRENT_DESKTOP, 0, LONG_MAX, False, XA_CARDINAL, &actualType, &actualFormat, &count, &bytesAfter, (u8**) &desktop); + XGetWindowProperty(_RGFW->display, root, _RGFW->_NET_CURRENT_DESKTOP, 0, LONG_MAX, False, XA_CARDINAL, &actualType, &actualFormat, &count, &bytesAfter, (u8**) &desktop); if (count) { if (extentCount >= 4 && *desktop < extentCount / 4) { @@ -7997,6 +8809,7 @@ RGFW_bool RGFW_FUNC(RGFW_monitor_getWorkarea) (RGFW_monitor* monitor, i32* x, i3 } size_t RGFW_FUNC(RGFW_monitor_getModesPtr) (RGFW_monitor* monitor, RGFW_monitorMode** modes) { + RGFW_ASSERT(monitor != NULL); size_t count = 0; XRRScreenResources* res = XRRGetScreenResourcesCurrent(_RGFW->display, DefaultRootWindow(_RGFW->display)); @@ -8020,8 +8833,8 @@ size_t RGFW_FUNC(RGFW_monitor_getModesPtr) (RGFW_monitor* monitor, RGFW_monitorM } size_t RGFW_FUNC(RGFW_monitor_getGammaRampPtr) (RGFW_monitor* monitor, RGFW_gammaRamp* ramp) { + RGFW_ASSERT(monitor != NULL); RGFW_UNUSED(monitor); RGFW_UNUSED(ramp); -#ifndef RGFW_NO_XRANDR size_t size = (size_t)XRRGetCrtcGammaSize(_RGFW->display, monitor->node->crtc); XRRCrtcGamma* gamma = XRRGetCrtcGamma(_RGFW->display, monitor->node->crtc); @@ -8033,15 +8846,12 @@ size_t RGFW_FUNC(RGFW_monitor_getGammaRampPtr) (RGFW_monitor* monitor, RGFW_gamm XRRFreeGamma(gamma); return size; -#endif - - return 0; } RGFW_bool RGFW_FUNC(RGFW_monitor_setGammaRamp) (RGFW_monitor* monitor, RGFW_gammaRamp* ramp) { + RGFW_ASSERT(monitor != NULL); RGFW_UNUSED(monitor); RGFW_UNUSED(ramp); -#ifndef RGFW_NO_XRANDR size_t size = (size_t)XRRGetCrtcGammaSize(_RGFW->display, monitor->node->crtc); if (size != ramp->count) { RGFW_debugCallback(RGFW_typeError, RGFW_errX11, "X11: Gamma ramp size must match current ramp size"); @@ -8058,18 +8868,18 @@ RGFW_bool RGFW_FUNC(RGFW_monitor_setGammaRamp) (RGFW_monitor* monitor, RGFW_gamm XRRFreeGamma(gamma); return RGFW_TRUE; -#endif - return RGFW_FALSE; } RGFW_bool RGFW_FUNC(RGFW_monitor_setMode)(RGFW_monitor* mon, RGFW_monitorMode* mode) { + RGFW_ASSERT(mon != NULL); RGFW_bool out = RGFW_FALSE; XRRScreenResources* res = XRRGetScreenResourcesCurrent(_RGFW->display, DefaultRootWindow(_RGFW->display)); XRRCrtcInfo* ci = XRRGetCrtcInfo(_RGFW->display, res, mon->node->crtc); - if (XRRSetCrtcConfig(_RGFW->display, res, mon->node->crtc, CurrentTime, ci->x, ci->y, (RRMode)mode->src, ci->rotation, ci->outputs, ci->noutput) == True) { + if (XRRSetCrtcConfig(_RGFW->display, res, mon->node->crtc, CurrentTime, ci->x, ci->y, (RRMode)mode->src, ci->rotation, ci->outputs, ci->noutput) == 0) { out = RGFW_TRUE; + mon->mode = *mode; } XRRFreeCrtcInfo(ci); @@ -8078,8 +8888,8 @@ RGFW_bool RGFW_FUNC(RGFW_monitor_setMode)(RGFW_monitor* mon, RGFW_monitorMode* m } RGFW_bool RGFW_FUNC(RGFW_monitor_requestMode)(RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request) { - #ifndef RGFW_NO_XRANDR - RGFW_init(); + RGFW_ASSERT(mon != NULL); + RGFW_ASSERT(_RGFW && "An RGFW context must be initialized using RGFW_init and/or set with RGFW_setInfo"); RGFW_bool output = RGFW_FALSE; @@ -8115,8 +8925,6 @@ RGFW_bool RGFW_FUNC(RGFW_monitor_requestMode)(RGFW_monitor* mon, RGFW_monitorMod XRRFreeCrtcInfo(ci); XRRFreeScreenResources(res); return output; -#endif - return RGFW_FALSE; } RGFW_monitor* RGFW_FUNC(RGFW_window_getMonitor) (RGFW_window* win) { @@ -8137,7 +8945,9 @@ RGFW_monitor* RGFW_FUNC(RGFW_window_getMonitor) (RGFW_window* win) { } #ifdef RGFW_OPENGL -RGFW_bool RGFW_FUNC(RGFW_window_createContextPtr_OpenGL) (RGFW_window* win, RGFW_glContext* context, RGFW_glHints* hints) { +RGFW_bool RGFW_FUNC(RGFW_createContextPtr_OpenGL) (RGFW_glContext* context, RGFW_glHints* hints) { + RGFW_ASSERT(_RGFW); RGFW_ASSERT(context); RGFW_ASSERT(hints); + /* for checking extensions later */ const char sRGBARBstr[] = "GLX_ARB_framebuffer_sRGB"; const char sRGBEXTstr[] = "GLX_EXT_framebuffer_sRGB"; @@ -8145,18 +8955,8 @@ RGFW_bool RGFW_FUNC(RGFW_window_createContextPtr_OpenGL) (RGFW_window* win, RGFW 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 */ - RGFW_bool showWindow = RGFW_FALSE; - if (win->src.window) { - showWindow = (RGFW_window_isMinimized(win) == RGFW_FALSE); - RGFW_window_closePlatform(win); - } - - RGFW_bool transparent = (win->internal.flags & RGFW_windowTransparent); + RGFW_bool transparent = (hints->depth == 32); /* start by creating a GLX config / X11 Viusal */ XVisualInfo visual; @@ -8194,7 +8994,8 @@ RGFW_bool RGFW_FUNC(RGFW_window_createContextPtr_OpenGL) (RGFW_window* win, RGFW /* find the configs */ i32 fbcount; - GLXFBConfig* fbc = glXChooseFBConfig(_RGFW->display, DefaultScreen(_RGFW->display), visual_attribs, &fbcount); + GLXFBConfig* fbc = RGFW_glXChooseFBConfig(_RGFW->display, DefaultScreen(_RGFW->display), visual_attribs, &fbcount); + if (fbc == NULL) return RGFW_FALSE; i32 best_fbc = -1; i32 best_depth = 0; @@ -8208,13 +9009,13 @@ RGFW_bool RGFW_FUNC(RGFW_window_createContextPtr_OpenGL) (RGFW_window* win, RGFW /* 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]); + XVisualInfo* vi = RGFW_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); + RGFW_glXGetFBConfigAttrib(_RGFW->display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf); + RGFW_glXGetFBConfigAttrib(_RGFW->display, fbc[i], GLX_SAMPLES, &samples); if (best_fbc == -1) best_fbc = i; if ((!(transparent) || vi->depth == 32) && best_depth == 0) { @@ -8236,32 +9037,22 @@ RGFW_bool RGFW_FUNC(RGFW_window_createContextPtr_OpenGL) (RGFW_window* win, RGFW /* we found a config */ bestFbc = fbc[best_fbc]; - XVisualInfo* vi = glXGetVisualFromFBConfig(_RGFW->display, bestFbc); - if (vi->depth != 32 && transparent) - RGFW_debugCallback(RGFW_typeWarning, RGFW_warningOpenGL, "Failed to to find a matching visual with a 32-bit depth."); + context->config = bestFbc; if (best_samples < hints->samples) RGFW_debugCallback(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); - - if (showWindow) { - RGFW_window_show(win); - } /* create the actual OpenGL context */ i32 context_attribs[40]; RGFW_attribStack_init(&stack, context_attribs, 40); i32 mask = 0; + i32 flags = 0; + switch (hints->profile) { case RGFW_glES: mask |= GLX_CONTEXT_ES_PROFILE_BIT_EXT; break; - case RGFW_glForwardCompatibility: mask |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; 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; @@ -8269,12 +9060,18 @@ RGFW_bool RGFW_FUNC(RGFW_window_createContextPtr_OpenGL) (RGFW_window* win, RGFW RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_PROFILE_MASK_ARB, mask); + if (hints->profile == RGFW_glForwardCompatibility) flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; + if (hints->debug) flags |= GLX_CONTEXT_DEBUG_BIT_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 (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); @@ -8283,13 +9080,6 @@ RGFW_bool RGFW_FUNC(RGFW_window_createContextPtr_OpenGL) (RGFW_window* win, RGFW } } - i32 flags = 0; - if (hints->debug) flags |= GLX_CONTEXT_DEBUG_BIT_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); } @@ -8297,111 +9087,207 @@ RGFW_bool RGFW_FUNC(RGFW_window_createContextPtr_OpenGL) (RGFW_window* win, RGFW 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) { + if (RGFW_glXCreateContextAttribsARB == NULL) { RGFW_debugCallback(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); + context->ctx = RGFW_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) { + context->ctx = RGFW_glXCreateContextAttribsARB(_RGFW->display, bestFbc, ctx, True, context_attribs); + if (_RGFW->x11Error || context->ctx == NULL) { RGFW_debugCallback(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); + context->ctx = RGFW_glXCreateContext(_RGFW->display, &visual, ctx, True); + } + } + + RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized."); + return RGFW_TRUE; +} + +void RGFW_FUNC(RGFW_deleteContextPtr_OpenGL) (RGFW_glContext* ctx) { + RGFW_glXDestroyContext(_RGFW->display, ctx->ctx); + RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context freed."); +} + +RGFW_bool RGFW_FUNC(RGFW_window_setContext_OpenGL) (RGFW_window* win, RGFW_glContext* context) { + RGFW_ASSERT(win); + + if (context == NULL && win->src.ctx.native != NULL) { + #ifndef RGFW_NO_GLXWINDOW + if (win->src.ctx.native->window != win->src.window) { + RGFW_glXDestroyWindow(_RGFW->display, win->src.ctx.native->window); } + #endif + + win->src.ctx.native = NULL; + RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL surface freed."); + return RGFW_TRUE; + } + + /* 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 */ + RGFW_bool showWindow = RGFW_FALSE; + + char* name = NULL; + if (win->src.window) { + showWindow = (RGFW_window_isMinimized(win) == RGFW_FALSE); + name = RGFW_XGetWindowName(win->src.window); + RGFW_window_closePlatform(win); + } + + XVisualInfo* vi = RGFW_glXGetVisualFromFBConfig(_RGFW->display, (GLXFBConfig)context->config); + + /* use the visual to create a new window */ + if (RGFW_XCreateWindow(*vi, name ? name : "", win->internal.flags, win) == RGFW_FALSE) return RGFW_FALSE; + if (name != NULL) XFree(name); + + if (showWindow) { + RGFW_window_show(win); } #ifndef RGFW_NO_GLXWINDOW - win->src.ctx.native->window = glXCreateWindow(_RGFW->display, bestFbc, win->src.window, NULL); + win->src.ctx.native->window = RGFW_glXCreateWindow(_RGFW->display, (GLXFBConfig)context->config, win->src.window, NULL); #else win->src.ctx.native->window = win->src.window; #endif - glXMakeCurrent(_RGFW->display, (Drawable)win->src.ctx.native->window, (GLXContext)win->src.ctx.native->ctx); - RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized."); + RGFW_glXMakeCurrent(_RGFW->display, (Drawable)win->src.ctx.native->window, (GLXContext)win->src.ctx.native->ctx); + RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL surface initalized."); RGFW_window_swapInterval_OpenGL(win, 0); return RGFW_TRUE; } -void RGFW_FUNC(RGFW_window_deleteContextPtr_OpenGL) (RGFW_window* win, RGFW_glContext* ctx) { - #ifndef RGFW_NO_GLXWINDOW - if (win->src.ctx.native->window != win->src.window) { - glXDestroyWindow(_RGFW->display, win->src.ctx.native->window); - } - #endif - - glXDestroyContext(_RGFW->display, ctx->ctx); - win->src.ctx.native = NULL; - RGFW_debugCallback(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)); + RGFW_ASSERT(_RGFW && "An RGFW context must be initialized using RGFW_init and/or set with RGFW_setInfo"); + const char* extensions = RGFW_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); } +RGFW_proc RGFW_FUNC(RGFW_getProcAddress_OpenGL)(const char* procname) { return _RGFW->glGetProcAddress((const char*) 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); + RGFW_glXMakeCurrent(NULL, (Drawable)NULL, (GLXContext) NULL); else - glXMakeCurrent(_RGFW->display, (Drawable)win->src.ctx.native->window, (GLXContext) win->src.ctx.native->ctx); + RGFW_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_getCurrentContext_OpenGL) (void) { return RGFW_glXGetCurrentContext(); } +void* RGFW_FUNC(RGFW_getCurrentSurface_OpenGL) (void) { return RGFW_glXGetCurrentDrawable(); } +void RGFW_FUNC(RGFW_window_swapBuffers_OpenGL) (RGFW_window* win) { RGFW_ASSERT(win->src.ctx.native); RGFW_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"}; + if (RGFW_glXSwapIntervalEXT) { + RGFW_glXSwapIntervalEXT(_RGFW->display, win->src.ctx.native->window, swapInterval); + } else if (RGFW_GLX_MESA_swap_control || RGFW_GLX_SGI_swap_control) { + void* ctx = RGFW_getCurrentContext_OpenGL(); + void* surf = RGFW_getCurrentSurface_OpenGL(); + if (ctx != win->src.ctx.native->ctx || (Drawable)surf != win->src.ctx.native->window) + RGFW_glXMakeCurrent(_RGFW->display, (Drawable)win->src.ctx.native->window, (GLXContext) win->src.ctx.native->ctx); - 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_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load swap interval function, fallingback to the native swapinterval function"); + if (RGFW_GLX_MESA_swap_control) + RGFW_GLX_MESA_swap_control(swapInterval); + else if (RGFW_GLX_SGI_swap_control) { + if (swapInterval > 0) { + RGFW_GLX_SGI_swap_control(swapInterval); } else { - RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load swap interval function"); + RGFW_debugCallback(RGFW_typeWarning, RGFW_errOpenGLContext, "Failed to disable swap interval, not supported with GLX_SGI_swap_control"); } } - } - if (pfn != (PFNGLXSWAPINTERVALEXTPROC)1) { - pfn(_RGFW->display, win->src.ctx.native->window, swapInterval); - } - else if (pfn2 != NULL) { - pfn2(swapInterval); + if (ctx != win->src.ctx.native->ctx || (Drawable)surf != win->src.ctx.native->window) + RGFW_glXMakeCurrent(_RGFW->display, (Drawable)surf, (GLXContext)ctx); + } else { + RGFW_debugCallback(RGFW_typeWarning, RGFW_errOpenGLContext, "Failed to load swap interval function"); } } #endif /* RGFW_OPENGL */ -i32 RGFW_initPlatform_X11(void) { +i32 RGFW_initPlatform_X11(const char* className, RGFW_initFlags flags) { + _RGFW->className = className; + RGFW_UNUSED(flags); + #ifdef RGFW_USE_XDL XDL_init(); #endif + XInitThreads(); /*!< init X11 threading */ + _RGFW->display = XOpenDisplay(0); + +#ifdef RGFW_X11_DEBUG + XSynchronize(_RGFW->display, True); +#endif + + if (_RGFW->display == NULL) return -1; + + #define RGFW_LOAD_ATOM(name) _RGFW->name = XInternAtom(_RGFW->display, #name, False) + RGFW_LOAD_ATOM(_NET_CURRENT_DESKTOP); + RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_VERT); + RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ); + RGFW_LOAD_ATOM(_NET_WM_BYPASS_COMPOSITOR); + RGFW_LOAD_ATOM(_NET_WM_STATE); + RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_VERT); + RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ); + RGFW_LOAD_ATOM(_MOTIF_WM_HINTS); + RGFW_LOAD_ATOM(WM_DELETE_WINDOW); + RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST_COUNTER); + RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST); + RGFW_LOAD_ATOM(ATOM_PAIR); + RGFW_LOAD_ATOM(MULTIPLE); + RGFW_LOAD_ATOM(TARGETS); + RGFW_LOAD_ATOM(SAVE_TARGETS); + RGFW_LOAD_ATOM(UTF8_STRING); + RGFW_LOAD_ATOM(XdndTypeList); + RGFW_LOAD_ATOM(XdndSelection); + RGFW_LOAD_ATOM(XdndAware); + 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); + RGFW_LOAD_ATOM(_NET_WM_STATE_FULLSCREEN); + RGFW_LOAD_ATOM(_NET_WM_STATE_ABOVE); + RGFW_LOAD_ATOM(NET_WM_WINDOW_OPACITY); + RGFW_LOAD_ATOM(_NET_WM_STATE); + RGFW_LOAD_ATOM(_NET_WM_STATE_ABOVE); + RGFW_LOAD_ATOM(_NET_WM_NAME); + RGFW_LOAD_ATOM(_NET_WM_ICON); + RGFW_LOAD_ATOM(UTF8_STRING); + RGFW_LOAD_ATOM(XSEL_DATA); + RGFW_LOAD_ATOM(UTF8_STRING); + RGFW_LOAD_ATOM(CLIPBOARD); + RGFW_LOAD_ATOM(CLIPBOARD_MANAGER); + _RGFW->XtextUriList = XInternAtom(_RGFW->display, "text/uri-list", False); + _RGFW->XtextPlain = XInternAtom(_RGFW->display, "text/plain", False); + #undef RGFW_LOAD_ATOM + + _RGFW->context = XUniqueContext(); + if (_RGFW->context == 0) return -1; + + XSetWindowAttributes wa; + RGFW_MEMZERO(&wa, 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); + + if (_RGFW->helperWindow == 0) return -1; + #if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD) #if defined(__CYGWIN__) RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor-1.so"); @@ -8441,25 +9327,17 @@ i32 RGFW_initPlatform_X11(void) { RGFW_PROC_DEF(X11XEXThandle, XShapeCombineMask); #endif - XInitThreads(); /*!< init X11 threading */ - _RGFW->display = XOpenDisplay(0); - _RGFW->context = XUniqueContext(); - - XSetWindowAttributes wa; - RGFW_MEMZERO(&wa, 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_createMouse(RGFW_blk, 1, 1, RGFW_formatRGBA8); - _RGFW->clipboard = NULL; + _RGFW->unixClipboard = NULL; XkbComponentNamesRec rec; XkbDescPtr desc = XkbGetMap(_RGFW->display, 0, XkbUseCoreKbd); XkbDescPtr evdesc; XSetErrorHandler(RGFW_XErrorHandler); + XSync(_RGFW->display, False); + u8 old[256]; XkbGetNames(_RGFW->display, XkbKeyNamesMask, desc); @@ -8490,47 +9368,35 @@ i32 RGFW_initPlatform_X11(void) { XSetLocaleModifiers(""); XRegisterIMInstantiateCallback(_RGFW->display, NULL, NULL, NULL, RGFW_x11_imInitCallback, NULL); - unsigned char mask[XIMaskLen(XI_RawMotion)]; - RGFW_MEMZERO(mask, sizeof(mask)); - 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); - -#ifndef RGFW_NO_XRANDR i32 errorBase; if (XRRQueryExtension(_RGFW->display, &_RGFW->xrandrEventBase, &errorBase)) { XRRSelectInput(_RGFW->display, RootWindow(_RGFW->display, DefaultScreen(_RGFW->display)), RROutputChangeNotifyMask); } -#endif 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()); - } - XUnregisterIMInstantiateCallback(_RGFW->display, NULL, NULL, NULL, RGFW_x11_imInitCallback, NULL); + if (_RGFW->display != NULL) { + /* to save the clipboard on the x server after the window is closed */ + if (XGetSelectionOwner(_RGFW->display, _RGFW->CLIPBOARD) == _RGFW->helperWindow) { + XConvertSelection(_RGFW->display, _RGFW->CLIPBOARD_MANAGER, _RGFW->SAVE_TARGETS, None, _RGFW->helperWindow, CurrentTime); + while (RGFW_XHandleClipboardSelectionHelper()); + } + + XUnregisterIMInstantiateCallback(_RGFW->display, NULL, NULL, NULL, RGFW_x11_imInitCallback, NULL); + } if (_RGFW->im) { XCloseIM(_RGFW->im); _RGFW->im = NULL; } - if (_RGFW->clipboard) { - RGFW_FREE(_RGFW->clipboard); - _RGFW->clipboard = NULL; + if (_RGFW->unixClipboard) { + RGFW_FREE(_RGFW->unixClipboard); + _RGFW->unixClipboard = NULL; } if (_RGFW->hiddenMouse) { @@ -8538,8 +9404,12 @@ void RGFW_deinitPlatform_X11(void) { _RGFW->hiddenMouse = NULL; } - XDestroyWindow(_RGFW->display, (Drawable) _RGFW->helperWindow); /*!< close the window */ - XCloseDisplay(_RGFW->display); /*!< kill connection to the x server */ + if (_RGFW->helperWindow) + XDestroyWindow(_RGFW->display, (Drawable) _RGFW->helperWindow); /*!< close the window */ + + if (_RGFW->display) + XCloseDisplay(_RGFW->display); /*!< kill connection to the x server */ + _RGFW->display = NULL; #if !defined(RGFW_NO_X11_CURSOR_PRELOAD) && !defined(RGFW_NO_X11_CURSOR) RGFW_FREE_LIBRARY(X11Cursorhandle); @@ -8584,12 +9454,12 @@ WGPUSurface RGFW_FUNC(RGFW_window_createSurface_WebGPU) (RGFW_window* window, WG #endif /* - End of X11 linux / wayland / unix defines + End of *nix */ /* - Start of Wayland defayland + Start of Wayland defines */ #ifdef RGFW_WAYLAND @@ -8600,24 +9470,6 @@ WGPUSurface RGFW_FUNC(RGFW_window_createSurface_WebGPU) (RGFW_window* window, WG #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 <errno.h> #include <unistd.h> #include <sys/mman.h> @@ -8629,10 +9481,13 @@ Wayland TODO: (out of date) #include <wayland-cursor.h> #include <fcntl.h> +#ifndef RGFW_X11 +RGFW_bool RGFW_usingWayland(void) { return RGFW_TRUE; } +#endif + 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" @@ -8825,7 +9680,7 @@ static void RGFW_wl_pointer_motion(void* data, struct wl_pointer *pointer, u32 t i32 convertedX = (i32)wl_fixed_to_double(x); i32 convertedY = (i32)wl_fixed_to_double(y); - RGFW_mousePosCallback(win, convertedX, convertedY); + RGFW_mouseMotionCallback(win, convertedX, convertedY); } static void RGFW_wl_pointer_button(void* data, struct wl_pointer *pointer, u32 serial, u32 time, u32 button, u32 state) { @@ -8902,7 +9757,6 @@ static void RGFW_wl_keyboard_enter(void* data, struct wl_keyboard *keyboard, u32 RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface); RGFW->kbOwner = win; - // this is to prevent race conditions if (RGFW->data_device != NULL && win->src.data_source != NULL) { wl_data_device_set_selection(RGFW->data_device, win->src.data_source, serial); @@ -9136,7 +9990,7 @@ static void RGFW_wl_output_handle_done(void* data, struct wl_output* output) { return; } - ((RGFW_monitorNode*)data)->disconnected = RGFW_TRUE; + ((RGFW_monitorNode*)data)->disconnected = RGFW_FALSE; RGFW_monitorCallback(_RGFW->root, monitor, RGFW_TRUE); } @@ -9150,7 +10004,7 @@ static void RGFW_wl_create_outputs(struct wl_registry *const registry, u32 id) { char RGFW_mon_default_name[10]; - RGFW_SNPRINTF(RGFW_mon_default_name, sizeof(RGFW_mon_default_name), "monitor-%li", _RGFW->monitors.count); + RGFW_SNPRINTF(RGFW_mon_default_name, sizeof(RGFW_mon_default_name), "monitor-%zu", _RGFW->monitors.count); RGFW_STRNCPY(mon.name, RGFW_mon_default_name, sizeof(mon.name) - 1); mon.name[sizeof(mon.name) - 1] = '\0'; @@ -9212,7 +10066,11 @@ static void RGFW_wl_data_source_send(void *data, struct wl_data_source *wl_data_ // a client can accept our clipboard if (RGFW_STRNCMP(mime_type, "text/plain;charset=utf-8", 25) == 0) { // do not write \0 - write(fd, _RGFW->clipboard, _RGFW->clipboard_len - 1); + size_t length = _RGFW->unixClipboard->length; + if (_RGFW->unixClipboard->data[0] == '\0') { + length -= 1; + } + write(fd, _RGFW->unixClipboard->data, length); } close(fd); @@ -9222,7 +10080,7 @@ static void RGFW_wl_data_source_cancelled(void *data, struct wl_data_source *wl_ RGFW_info* RGFW = (RGFW_info*)data; - if (RGFW->kbOwner->src.data_source == wl_data_source) { + if (RGFW->kbOwner && RGFW->kbOwner->src.data_source == wl_data_source) { RGFW->kbOwner->src.data_source = NULL; } @@ -9251,7 +10109,7 @@ static void RGFW_wl_data_device_selection(void *data, struct wl_data_device *wl_ int pfds[2]; pipe(pfds); - wl_data_offer_receive(wl_data_offer, "text/plain;charset=utf-8", pfds[1]); + wl_data_offer_receive(wl_data_offer, "text/plain", pfds[1]); close(pfds[1]); wl_display_roundtrip(_RGFW->wl_display); @@ -9259,12 +10117,27 @@ static void RGFW_wl_data_device_selection(void *data, struct wl_data_device *wl_ char buf[1024]; ssize_t n = read(pfds[0], buf, sizeof(buf)); + if (n <= 0) { + close(pfds[0]); + wl_data_offer_destroy(wl_data_offer); + return; + } + + size_t length = (size_t)n; + if (buf[n - 1] != '\0') length += 1; + + if (_RGFW->unixClipboard != NULL) RGFW_FREE(_RGFW->unixClipboard); - _RGFW->clipboard = (char*)RGFW_ALLOC((size_t)n); - RGFW_ASSERT(_RGFW->clipboard != NULL); - RGFW_STRNCPY(_RGFW->clipboard, buf, (size_t)n); + _RGFW->unixClipboard = (RGFW_dataTransfer*)RGFW_ALLOC(sizeof(RGFW_dataTransfer) + (size_t)n); + RGFW_ASSERT(_RGFW->unixClipboard != NULL); - _RGFW->clipboard_len = (size_t)n + 1; + char* data_ptr = &((char*)(void*)_RGFW->unixClipboard)[sizeof(RGFW_dataTransfer) - 1]; + RGFW_MEMCPY(data_ptr, buf, (size_t)n); + data_ptr[length - 1] = '\0'; + + _RGFW->unixClipboard->data = data_ptr; + _RGFW->unixClipboard->type = RGFW_dataText; + _RGFW->unixClipboard->length = length; close(pfds[0]); @@ -9328,19 +10201,6 @@ static void RGFW_wl_global_registry_remove(void* data, struct wl_registry *regis node = prev; } - if (node->output) { - wl_output_destroy(node->output); - } - - if (node->xdg_output) { - zxdg_output_v1_destroy(node->xdg_output); - } - - if (node->modeCount) { - RGFW_FREE(node->modes); - node->modeCount = 0; - } - RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_FALSE); RGFW_monitors_remove(node, prev); } @@ -9390,7 +10250,8 @@ static int RGFW_wl_create_shm_file(off_t size) { return fd; } -i32 RGFW_initPlatform_Wayland(void) { +i32 RGFW_initPlatform_Wayland(const char* className, RGFW_initFlags flags) { + RGFW_UNUSED(className); RGFW_UNUSED(flags); _RGFW->wl_display = wl_display_connect(NULL); if (_RGFW->wl_display == NULL) { RGFW_debugCallback(RGFW_typeError, RGFW_errWayland, "Failed to load Wayland display"); @@ -9410,7 +10271,7 @@ i32 RGFW_initPlatform_Wayland(void) { if (_RGFW->compositor == NULL) { RGFW_debugCallback(RGFW_typeError, RGFW_errWayland, "Can't find compositor."); - return 1; + return -1; } if (_RGFW->wl_cursor_theme == NULL) { @@ -9447,9 +10308,9 @@ i32 RGFW_initPlatform_Wayland(void) { } void RGFW_deinitPlatform_Wayland(void) { - if (_RGFW->clipboard) { - RGFW_FREE(_RGFW->clipboard); - _RGFW->clipboard = NULL; + if (_RGFW->unixClipboard) { + RGFW_FREE(_RGFW->unixClipboard); + _RGFW->unixClipboard = NULL; } if (_RGFW->wl_pointer) { @@ -9459,7 +10320,10 @@ void RGFW_deinitPlatform_Wayland(void) { wl_keyboard_destroy(_RGFW->wl_keyboard); } - wl_registry_destroy(_RGFW->registry); + if (_RGFW->registry) { + wl_registry_destroy(_RGFW->registry); + } + if (_RGFW->decoration_manager != NULL) zxdg_decoration_manager_v1_destroy(_RGFW->decoration_manager); if (_RGFW->relative_pointer_manager != NULL) { @@ -9474,7 +10338,6 @@ void RGFW_deinitPlatform_Wayland(void) { 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); } @@ -9499,30 +10362,27 @@ void RGFW_deinitPlatform_Wayland(void) { wp_pointer_warp_v1_destroy(_RGFW->wp_pointer_warp); } - RGFW_freeMouse(_RGFW->hiddenMouse); + if (_RGFW->hiddenMouse) { + RGFW_freeMouse(_RGFW->hiddenMouse); + } - RGFW_monitorNode* node = _RGFW->monitors.list.head; + if (_RGFW->cursor_surface) + wl_surface_destroy(_RGFW->cursor_surface); - while (node != NULL) { - if (node->output) { - wl_output_destroy(node->output); - } + if (_RGFW->shm) + wl_shm_destroy(_RGFW->shm); - if (node->xdg_output) { - zxdg_output_v1_destroy(node->xdg_output); - } + if (_RGFW->seat) + wl_seat_release(_RGFW->seat); - _RGFW->monitors.count -= 1; - node = node->next; + if (_RGFW->xdg_wm_base) + xdg_wm_base_destroy(_RGFW->xdg_wm_base); - } + if (_RGFW->compositor) + wl_compositor_destroy(_RGFW->compositor); - 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); + if (_RGFW->wl_display) + wl_display_disconnect(_RGFW->wl_display); } RGFW_format RGFW_FUNC(RGFW_nativeFormat)(void) { return RGFW_formatBGRA8; } @@ -9661,9 +10521,6 @@ RGFW_window* RGFW_FUNC(RGFW_createWindowPlatform) (const char* name, RGFW_window win->src.xdg_toplevel = xdg_surface_get_toplevel(win->src.xdg_surface); - if (_RGFW->className == NULL) - _RGFW->className = (char*)name; - xdg_toplevel_set_app_id(win->src.xdg_toplevel, name); xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->w, win->h); @@ -9746,21 +10603,25 @@ RGFW_window* RGFW_FUNC(RGFW_createWindowPlatform) (const char* name, RGFW_window } RGFW_bool RGFW_FUNC(RGFW_getGlobalMouse) (i32* x, i32* y) { - RGFW_init(); + RGFW_ASSERT(_RGFW && "An RGFW context must be initialized using RGFW_init and/or set with RGFW_setInfo"); if (x) *x = 0; if (y) *y = 0; return RGFW_FALSE; } RGFW_key RGFW_FUNC(RGFW_physicalToMappedKey)(RGFW_key key) { - u32 keycode = RGFW_rgfwToApiKey(key); - xkb_keycode_t kc = keycode + 8; - xkb_keysym_t sym = xkb_state_key_get_one_sym(_RGFW->xkb_state, kc); + xkb_keycode_t keycode = (xkb_keycode_t)RGFW_rgfwToApiKey(key); + xkb_keysym_t sym = xkb_state_key_get_one_sym(_RGFW->xkb_state, keycode); if (sym < 256) { return (RGFW_key)sym; } switch (sym) { + case XKB_KEY_BackSpace: return RGFW_keyBackSpace; + case XKB_KEY_Tab: return RGFW_keyTab; + case XKB_KEY_Return: return RGFW_keyReturn; + case XKB_KEY_Escape: return RGFW_keyEscape; + case XKB_KEY_Delete: return RGFW_keyDelete; case XKB_KEY_F1: return RGFW_keyF1; case XKB_KEY_F2: return RGFW_keyF2; case XKB_KEY_F3: return RGFW_keyF3; @@ -9852,7 +10713,7 @@ void RGFW_FUNC(RGFW_pollEvents) (void) { } } if (_RGFW->wl_repeat_info_rate != 0 && _RGFW->last_key) { - u32 now = (u32)(RGFW_linux_getTimeNS() / 1000000); + u32 now = (u32)(RGFW_unix_getTimeNS() / 1000000); if (now > _RGFW->last_key_time) { RGFW_wl_send_key_event(_RGFW->last_key); _RGFW->last_key_time = now + 1000 / (u32)_RGFW->wl_repeat_info_rate; @@ -9861,25 +10722,41 @@ void RGFW_FUNC(RGFW_pollEvents) (void) { /* read the events; if empty this reads from the */ /* wayland file descriptor */ - if (wl_display_dispatch(_RGFW->wl_display) == -1) { - return; - } + struct pollfd fds; + memset(&fds, 0, sizeof(fds)); + fds.fd = wl_display_get_fd(_RGFW->wl_display); + fds.events = POLLIN; + fds.revents = 0; -} + while (1) { + while (wl_display_prepare_read(_RGFW->wl_display) != 0) { + if (wl_display_dispatch_pending(_RGFW->wl_display) > 0) + return; + } -void RGFW_FUNC(RGFW_window_move) (RGFW_window* win, i32 x, i32 y) { - RGFW_ASSERT(win != NULL); - win->x = x; - win->y = y; + if (poll(&fds, 1, 0) == 0) { + wl_display_cancel_read(_RGFW->wl_display); + return; + } + + if (fds.revents & POLLIN) { + wl_display_read_events(_RGFW->wl_display); + if (wl_display_dispatch_pending(_RGFW->wl_display) > 0) { + return; + } + } else { + wl_display_cancel_read(_RGFW->wl_display); + } + } } +void RGFW_FUNC(RGFW_window_movePlatform) (RGFW_window* win, i32 x, i32 y) { + RGFW_UNUSED(win); RGFW_UNUSED(x); RGFW_UNUSED(y); +} -void RGFW_FUNC(RGFW_window_resize) (RGFW_window* win, i32 w, i32 h) { - RGFW_ASSERT(win != NULL); - win->w = w; - win->h = h; +void RGFW_FUNC(RGFW_window_resizePlatform) (RGFW_window* win, i32 w, i32 h) { if (_RGFW->compositor) { - xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->w, win->h); + xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, w, h); #ifdef RGFW_OPENGL if (win->src.ctx.egl) wl_egl_window_resize(win->src.ctx.egl->eglWindow, (i32)w, (i32)h, 0, 0); @@ -9914,13 +10791,8 @@ void RGFW_toggleWaylandMaximized(RGFW_window* win, RGFW_bool maximized) { } } -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; +void RGFW_FUNC(RGFW_window_maximizePlatform) (RGFW_window* win) { RGFW_toggleWaylandMaximized(win, 1); - RGFW_window_fetchSize(win, NULL, NULL); return; } @@ -9932,21 +10804,12 @@ 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); +void RGFW_FUNC(RGFW_window_setFullscreenPlatform)(RGFW_window* win, RGFW_bool fullscreen) { 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) { @@ -9959,7 +10822,7 @@ void RGFW_FUNC(RGFW_window_setOpacity) (RGFW_window* win, u8 opacity) { RGFW_UNUSED(opacity); } -void RGFW_FUNC(RGFW_window_minimize)(RGFW_window* win) { +void RGFW_FUNC(RGFW_window_minimizePlatform)(RGFW_window* win) { RGFW_ASSERT(win != NULL); if (RGFW_window_isMaximized(win)) return; win->internal.oldX = win->x; @@ -9970,18 +10833,9 @@ void RGFW_FUNC(RGFW_window_minimize)(RGFW_window* win) { xdg_toplevel_set_minimized(win->src.xdg_toplevel); } -void RGFW_FUNC(RGFW_window_restore)(RGFW_window* win) { +void RGFW_FUNC(RGFW_window_restorePlatform)(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) { @@ -10118,9 +10972,8 @@ void RGFW_FUNC(RGFW_window_hide) (RGFW_window* win) { win->internal.flags |= RGFW_windowHide; } -void RGFW_FUNC(RGFW_window_show) (RGFW_window* win) { +void RGFW_FUNC(RGFW_window_showPlatform) (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); } @@ -10131,31 +10984,57 @@ void RGFW_FUNC(RGFW_window_flash) (RGFW_window* win, RGFW_flashRequest request) } } -RGFW_ssize_t RGFW_FUNC(RGFW_readClipboardPtr) (char* str, size_t strCapacity) { +RGFW_bool RGFW_FUNC(RGFW_readClipboardPtr) (RGFW_dataTransferType requestedType, u8* buffer, size_t capacity, RGFW_dataTransfer* data) { + RGFW_ASSERT(data != NULL); + + if (requestedType != RGFW_dataText) return RGFW_FALSE; + + if (_RGFW->unixClipboard == NULL || _RGFW->unixClipboard->length == 0) { + data->length = 0; + data->type = RGFW_dataNone; + return RGFW_FALSE; + } + + data->length = _RGFW->unixClipboard->length; + data->type = RGFW_dataText; + + if (buffer == NULL) return RGFW_TRUE; - RGFW_UNUSED(strCapacity); + if (_RGFW->unixClipboard->length > capacity) return RGFW_FALSE; - 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; + RGFW_MEMCPY(buffer, _RGFW->unixClipboard->data, _RGFW->unixClipboard->length); + data->data = (const char*)buffer; + + return RGFW_TRUE; } -void RGFW_FUNC(RGFW_writeClipboard) (const char* text, u32 textLen) { +RGFW_bool RGFW_FUNC(RGFW_writeClipboard) (const RGFW_dataTransfer* data) { + RGFW_ASSERT(data != NULL); - // compositor does not support wl_data_device_manager - // clients cannot read rgfw's clipboard - if (_RGFW->data_device_manager == NULL) return; + /* compositor does not support wl_data_device_manager + clients cannot read rgfw's clipboard + */ + if (_RGFW->data_device_manager == NULL) return RGFW_FALSE; // clear the clipboard - if (_RGFW->clipboard) - RGFW_FREE(_RGFW->clipboard); + if (_RGFW->unixClipboard) { + RGFW_FREE(_RGFW->unixClipboard); + _RGFW->unixClipboard = NULL; + } // set the contents - _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; + _RGFW->unixClipboard = (RGFW_dataTransfer*)RGFW_ALLOC(sizeof(RGFW_dataTransfer) + data->length); + RGFW_ASSERT(_RGFW->unixClipboard!= NULL); + + size_t length = data->length; + if (data->data[length - 1] != '\0') length += 1; + + char* data_ptr = &((char*)(void*)_RGFW->unixClipboard)[sizeof(RGFW_dataTransfer) - 1]; + RGFW_MEMCPY(data_ptr, data->data, data->length); + data_ptr[length - 1] = '\0'; + + _RGFW->unixClipboard->data = data_ptr; + _RGFW->unixClipboard->type = RGFW_dataText; + _RGFW->unixClipboard->length = length; // means we already wrote to the clipboard // so destroy it to create a new one @@ -10172,9 +11051,8 @@ void RGFW_FUNC(RGFW_writeClipboard) (const char* text, u32 textLen) { // basic error checking if (win->src.data_source == NULL) { RGFW_debugCallback(RGFW_typeError, RGFW_errClipboard, "Could not create clipboard data source"); - return; + return RGFW_FALSE; } - wl_data_source_offer(win->src.data_source , "text/plain;charset=utf-8"); // needed RGFW_doNothing because wayland will call the functions // if not set they are random data that lead to a crash @@ -10188,7 +11066,9 @@ void RGFW_FUNC(RGFW_writeClipboard) (const char* text, u32 textLen) { }; wl_data_source_add_listener(win->src.data_source, &data_source_listener, _RGFW); + wl_data_source_offer(win->src.data_source , "text/plain;charset=utf-8"); + return RGFW_TRUE; } RGFW_bool RGFW_FUNC(RGFW_window_isHidden) (RGFW_window* win) { @@ -10210,8 +11090,25 @@ void RGFW_FUNC(RGFW_pollMonitors) (void) { _RGFW->monitors.primary = _RGFW->monitors.list.head; } +void RGFW_FUNC(RGFW_monitorNode_free) (RGFW_monitorNode* node) { + RGFW_ASSERT(node); + + if (node->output) { + wl_output_destroy(node->output); + } + + if (node->xdg_output) { + zxdg_output_v1_destroy(node->xdg_output); + } + + if (node->modes) { + RGFW_FREE(node->modes); + node->modeCount = 0; + } +} RGFW_bool RGFW_FUNC(RGFW_monitor_getWorkarea) (RGFW_monitor* monitor, i32* x, i32* y, i32* width, i32* height) { + RGFW_ASSERT(monitor != NULL); /* NOTE: Wayland has no way to get the actual workarea as far as I'm aware :( */ if (x) *x = monitor->x; if (y) *y = monitor->y; @@ -10221,6 +11118,7 @@ RGFW_bool RGFW_FUNC(RGFW_monitor_getWorkarea) (RGFW_monitor* monitor, i32* x, i3 } size_t RGFW_FUNC(RGFW_monitor_getModesPtr) (RGFW_monitor* monitor, RGFW_monitorMode** modes) { + RGFW_ASSERT(monitor != NULL); if (modes) { RGFW_MEMCPY((*modes), monitor->node->modes, monitor->node->modeCount * sizeof(RGFW_monitorMode)); } @@ -10229,16 +11127,19 @@ size_t RGFW_FUNC(RGFW_monitor_getModesPtr) (RGFW_monitor* monitor, RGFW_monitorM } size_t RGFW_FUNC(RGFW_monitor_getGammaRampPtr) (RGFW_monitor* monitor, RGFW_gammaRamp* ramp) { + RGFW_ASSERT(monitor != NULL); RGFW_UNUSED(monitor); RGFW_UNUSED(ramp); return 0; } RGFW_bool RGFW_FUNC(RGFW_monitor_setGammaRamp) (RGFW_monitor* monitor, RGFW_gammaRamp* ramp) { + RGFW_ASSERT(monitor != NULL); RGFW_UNUSED(monitor); RGFW_UNUSED(ramp); return RGFW_FALSE; } RGFW_bool RGFW_FUNC(RGFW_monitor_requestMode) (RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request) { + RGFW_ASSERT(mon != NULL); for (size_t i = 0; i < mon->node->modeCount; i++) { if (RGFW_monitorModeCompare(mode, &mon->node->modes[i], request) == RGFW_FALSE) { continue; @@ -10252,7 +11153,8 @@ RGFW_bool RGFW_FUNC(RGFW_monitor_requestMode) (RGFW_monitor* mon, RGFW_monitorMo } RGFW_bool RGFW_FUNC(RGFW_monitor_setMode) (RGFW_monitor* mon, RGFW_monitorMode* mode) { - RGFW_UNUSED(mon); RGFW_UNUSED(mode); + RGFW_ASSERT(mon != NULL); + mon->mode = *mode; return RGFW_FALSE; } @@ -10271,17 +11173,31 @@ RGFW_bool RGFW_FUNC(RGFW_extensionSupportedPlatform_OpenGL) (const char * extens 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); +RGFW_bool RGFW_FUNC(RGFW_createContextPtr_OpenGL)(RGFW_glContext* ctx, RGFW_glHints* hints) { + RGFW_bool out = RGFW_createContextPtr_EGL(&ctx->egl, hints); + return out; +} +void RGFW_FUNC(RGFW_deleteContextPtr_OpenGL) (RGFW_glContext* ctx) { RGFW_deleteContextPtr_EGL(&ctx->egl); } +RGFW_bool RGFW_FUNC(RGFW_window_setContext_OpenGL) (RGFW_window* win, RGFW_glContext* context) { + RGFW_ASSERT(win); + if (context == NULL && win->src.ctx.native != NULL) { + RGFW_window_setContext_EGL(win, 0); + win->src.ctx.native = NULL; + RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL window surface freed"); + return RGFW_TRUE; + } + + win->src.ctx.native = context; win->src.gfxType = RGFW_gfxNativeOpenGL; + if (RGFW_window_setContext_EGL(win, &context->egl) == RGFW_FALSE) return RGFW_FALSE; RGFW_window_swapInterval_OpenGL(win, 0); - return out; + return RGFW_TRUE; } -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_getCurrentSurface_OpenGL) (void) { return RGFW_getCurrentSurface_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 */ @@ -10344,16 +11260,6 @@ WGPUSurface RGFW_FUNC(RGFW_window_createSurface_WebGPU) (RGFW_window* window, WG */ #ifdef RGFW_WINDOWS -#ifndef WIN32_LEAN_AND_MEAN - #define WIN32_LEAN_AND_MEAN -#endif - -#ifndef OEMRESOURCE - #define OEMRESOURCE -#endif - -#include <windows.h> - #ifndef OCR_NORMAL #define OCR_NORMAL 32512 #define OCR_IBEAM 32513 @@ -10381,12 +11287,17 @@ WGPUSurface RGFW_FUNC(RGFW_window_createSurface_WebGPU) (RGFW_window* window, WG #define WM_DPICHANGED 0x02E0 #endif +#define RGFW_LOAD_LIBRARY(x, lib) if (x == NULL) { x = LoadLibraryA(lib); RGFW_ASSERT(x != NULL); } +#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); \ + } RGFWDEF DWORD RGFW_winapi_window_getStyle(RGFW_window* win, RGFW_windowFlags flags); DWORD RGFW_winapi_window_getStyle(RGFW_window* win, RGFW_windowFlags flags) { RGFW_UNUSED(win); DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; - if ((flags & RGFW_windowFullscreen)) { + if ((flags & RGFW_windowFullscreenExclusive)) { style |= WS_POPUP; } else { style |= WS_SYSMENU | WS_MINIMIZEBOX; @@ -10407,68 +11318,155 @@ DWORD RGFW_winapi_window_getStyle(RGFW_window* win, RGFW_windowFlags flags) { RGFWDEF DWORD RGFW_winapi_window_getExStyle(RGFW_window* win, RGFW_windowFlags flags); DWORD RGFW_winapi_window_getExStyle(RGFW_window* win, RGFW_windowFlags flags) { DWORD style = WS_EX_APPWINDOW; - if (flags & RGFW_windowFullscreen || (flags & RGFW_windowFloating || RGFW_window_isFloating(win))) { + if (flags & RGFW_windowFullscreenExclusive || (flags & RGFW_windowFloating || RGFW_window_isFloating(win))) { style |= WS_EX_TOPMOST; } return style; } -RGFW_bool RGFW_createUTF8FromWideStringWin32(const WCHAR* source, char* out, size_t max); +RGFWDEF i32 RGFW_createUTF8FromWideStringWin32(const WCHAR* source, char* out, size_t max); +i32 RGFW_createUTF8FromWideStringWin32(const WCHAR* source, char* output, size_t max) { + RGFW_ASSERT(source != NULL); -#define GL_FRONT 0x0404 -#define GL_BACK 0x0405 -#define GL_LEFT 0x0406 -#define GL_RIGHT 0x0407 + i32 size = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL); + if (!size) { + return RGFW_FALSE; + } -typedef int (*PFN_wglGetSwapIntervalEXT)(void); -PFN_wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc = NULL; -#define wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc + if (output == NULL || max == 0) { + return size; + } -/* these two wgl functions need to be preloaded */ -typedef HGLRC (WINAPI *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC hdc, HGLRC hglrc, const int *attribList); -PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL; + if ((size_t)size > max) + size = (i32)max; -HMODULE RGFW_wgl_dll = NULL; + if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, output, size, NULL, NULL)) { + return RGFW_FALSE; + } -#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); + return size; +} - PFN_wglCreateContext wglCreateContextSRC; - PFN_wglDeleteContext wglDeleteContextSRC; - PFN_wglGetProcAddress wglGetProcAddressSRC; - PFN_wglMakeCurrent wglMakeCurrentSRC; - PFN_wglGetCurrentDC wglGetCurrentDCSRC; - PFN_wglGetCurrentContext wglGetCurrentContextSRC; - PFN_wglShareLists wglShareListsSRC; +#ifdef RGFW_OPENGL +#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_SAMPLE_BUFFERS_ARB 0x2041 +#define WGL_SAMPLES_ARB 0x2042 +#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_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_FORWARD_COMPATIBLE_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 - #define wglCreateContext wglCreateContextSRC - #define wglDeleteContext wglDeleteContextSRC - #define wglGetProcAddress wglGetProcAddressSRC - #define wglMakeCurrent wglMakeCurrentSRC - #define wglGetCurrentDC wglGetCurrentDCSRC - #define wglGetCurrentContext wglGetCurrentContextSRC - #define wglShareLists wglShareListsSRC -#endif +typedef int (*RGFW_wglGetSwapIntervalEXTProc)(void); +typedef HGLRC (WINAPI *RGFW_wglCreateContextAttribsARBProc)(HDC hdc, HGLRC hglrc, const int *attribList); +typedef HGLRC(WINAPI* RGFW_wglCreateContextProc)(HDC); +typedef BOOL(WINAPI* RGFW_wglDeleteContextProc)(HGLRC); +typedef PROC(WINAPI* RGFW_wglGetProcAddressProc)(LPCSTR); +typedef BOOL(WINAPI* RGFW_wglMakeCurrentProc)(HDC, HGLRC); +typedef HGLRC(WINAPI* RGFW_wglGetCurrentContextProc)(void); +typedef HDC(WINAPI* RGFW_wglGetCurrentDCProc)(void); +typedef BOOL(WINAPI* RGFW_wglShareListsProc)(HGLRC, HGLRC); +typedef HRESULT (APIENTRY* RGFW_wglChoosePixelFormatARBProc)(HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats); +typedef BOOL(APIENTRY* RGFW_wglSwapIntervalEXTProc)(int interval); -void* RGFW_window_getHWND(RGFW_window* win) { return win->src.window; } -void* RGFW_window_getHDC(RGFW_window* win) { return win->src.hdc; } +RGFW_wglCreateContextProc RGFW_wglCreateContext; +RGFW_wglDeleteContextProc RGFW_wglDeleteContext; +RGFW_wglMakeCurrentProc RGFW_wglMakeCurrent; +RGFW_wglGetCurrentDCProc RGFW_wglGetCurrentDC; +RGFW_wglGetCurrentContextProc RGFW_wglGetCurrentContext; +RGFW_wglShareListsProc RGFW_wglShareLists; +RGFW_wglCreateContextAttribsARBProc RGFW_wglCreateContextAttribsARB; +RGFW_wglGetSwapIntervalEXTProc RGFW_wglGetSwapIntervalEXT; +RGFW_wglChoosePixelFormatARBProc RGFW_wglChoosePixelFormatARB; +RGFW_wglSwapIntervalEXTProc RGFW_wglSwapIntervalEXT; -#ifdef RGFW_OPENGL -RGFWDEF void RGFW_win32_loadOpenGLFuncs(HWND dummyWin); +RGFW_bool RGFW_loadGL(void) { + RGFW_ASSERT(_RGFW && "An RGFW context must be initialized using RGFW_init and/or set with RGFW_setInfo"); + if (_RGFW->nativeGL_handle && _RGFW->glGetProcAddress != NULL) { + return RGFW_TRUE; + } + + RGFW_LOAD_LIBRARY(_RGFW->nativeGL_handle, "opengl32.dll"); + _RGFW->glGetProcAddress = (RGFW_proc(*)(const char*))(RGFW_proc)GetProcAddress((HMODULE)_RGFW->nativeGL_handle, "wglGetProcAddress"); + RGFW_ASSERT(_RGFW->glGetProcAddress); + + #define RGFW_WGL_PROC(name) if (RGFW_##name == NULL) RGFW_##name = (RGFW_##name##Proc)RGFW_getProcAddress_OpenGL(#name); + + RGFW_WGL_PROC(wglCreateContext); + RGFW_WGL_PROC(wglDeleteContext); + RGFW_WGL_PROC(wglMakeCurrent); + RGFW_WGL_PROC(wglGetCurrentDC); + RGFW_WGL_PROC(wglGetCurrentContext); + RGFW_WGL_PROC(wglShareLists); + + HWND dummyWin = CreateWindowW(_RGFW->wndClass.lpszClassName, (wchar_t*)NULL, 0, 0, 0, 0, 0, 0, 0, _RGFW->instance, 0); + 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 = RGFW_wglCreateContext(dummy_dc); + + HGLRC cur = RGFW_wglGetCurrentContext(); + RGFW_wglMakeCurrent(dummy_dc, dummy_context); -typedef HRESULT (APIENTRY* PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats); -PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL; + RGFW_WGL_PROC(wglCreateContextAttribsARB); + RGFW_WGL_PROC(wglChoosePixelFormatARB); + RGFW_WGL_PROC(wglSwapIntervalEXT); + + #undef RGFW_WGL_PROC + + if (RGFW_wglSwapIntervalEXT == NULL) { + RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load swap interval function"); + } + + RGFW_wglMakeCurrent(dummy_dc, cur); + RGFW_wglDeleteContext(dummy_context); + ReleaseDC(dummyWin, dummy_dc); + DestroyWindow(dummyWin); + + return RGFW_TRUE; +} -typedef BOOL(APIENTRY* PFNWGLSWAPINTERVALEXTPROC)(int interval); -PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL; #endif +void* RGFW_window_getHWND(RGFW_window* win) { return win->src.window; } +void* RGFW_window_getHDC(RGFW_window* win) { return win->src.hdc; } #ifndef RGFW_NO_DWM HMODULE RGFW_dwm_dll = NULL; @@ -10525,6 +11523,15 @@ void RGFW_win32_makeWindowDarkMode(RGFW_window* win, RGFW_bool state) { LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { + switch (message) { + case WM_DISPLAYCHANGE: + RGFW_pollMonitors(); + break; + default: break; + } + + if (hWnd == _RGFW->helperWindow) return DefWindowProcW(hWnd, message, wParam, lParam); + RGFW_window* win = (RGFW_window*)GetPropW(hWnd, L"RGFW"); if (win == NULL) return DefWindowProcW(hWnd, message, wParam, lParam); @@ -10538,11 +11545,7 @@ LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) AdjustWindowRectEx(&frame, style, FALSE, exStyle); switch (message) { - case WM_DISPLAYCHANGE: - RGFW_pollMonitors(); - break; case WM_CLOSE: - case WM_QUIT: RGFW_windowCloseCallback(win); return 0; case WM_ACTIVATE: { @@ -10627,10 +11630,15 @@ LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) return DefWindowProcW(hWnd, message, wParam, lParam); } case WM_PAINT: { - PAINTSTRUCT ps; - BeginPaint(hWnd, &ps); - RGFW_windowRefreshCallback(win, 0, 0, win->w, win->h); - EndPaint(hWnd, &ps); + RECT rect; + if (GetUpdateRect(hWnd, &rect, FALSE)) { + RGFW_windowRefreshCallback(win, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); + } else { + PAINTSTRUCT ps; + BeginPaint(hWnd, &ps); + RGFW_windowRefreshCallback(win, 0, 0, win->w, win->h); + EndPaint(hWnd, &ps); + } return DefWindowProcW(hWnd, message, wParam, lParam); } @@ -10767,7 +11775,7 @@ LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) RGFW_mouseNotifyCallback(win, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), RGFW_TRUE); } - RGFW_mousePosCallback(win, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + RGFW_mouseMotionCallback(win, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); break; } case WM_INPUT: { @@ -10819,6 +11827,7 @@ LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) else value = (message == WM_LBUTTONDOWN) ? (u8)RGFW_mouseLeft : (message == WM_RBUTTONDOWN) ? (u8)RGFW_mouseRight : (u8)RGFW_mouseMiddle; + SetCapture(win->src.window); RGFW_mouseButtonCallback(win, value, 1); break; } @@ -10830,6 +11839,9 @@ LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) (message == WM_RBUTTONUP) ? (u8)RGFW_mouseRight : (u8)RGFW_mouseMiddle; RGFW_mouseButtonCallback(win, value, 0); + + RGFW_mouseButton i = 0; + for (i = RGFW_mouseLeft; i < RGFW_mouseFinal && RGFW_isMouseDown(i) == RGFW_FALSE; i += 1); break; } case WM_MOUSEWHEEL: { @@ -10855,20 +11867,23 @@ LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) u32 i; for (i = 0; i < count; i++) { - UINT length = DragQueryFileW(drop, i, NULL, 0); - if (length == 0) + UINT length = DragQueryFileW(drop, i, NULL, 0) + 1; + if (length <= 1) continue; - WCHAR* buffer = (WCHAR*)RGFW_ALLOC(sizeof(WCHAR) * (length + 1)); - char* cbuffer = (char*)RGFW_ALLOC(length + 1); - - DragQueryFileW(drop, i, buffer, length + 1); + WCHAR* buffer = (WCHAR*)RGFW_ALLOC(sizeof(WCHAR) * length); + DragQueryFileW(drop, i, buffer, length); - RGFW_createUTF8FromWideStringWin32(buffer, cbuffer, length); + i32 clength = RGFW_createUTF8FromWideStringWin32(buffer, NULL, 0); + if (clength > 0) { + char* cbuffer = (char*)RGFW_ALLOC((size_t)clength); + if (RGFW_createUTF8FromWideStringWin32(buffer, cbuffer, (size_t)clength) != RGFW_FALSE) { + RGFW_dataDropCallback(win, cbuffer, (size_t)clength, RGFW_dataFile); + } + RGFW_FREE(cbuffer); + } - RGFW_dataDropCallback(win, cbuffer, length + 1, RGFW_dataFile); RGFW_FREE(buffer); - RGFW_FREE(cbuffer); } DragFinish(drop); @@ -10899,10 +11914,6 @@ LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) __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_format RGFW_nativeFormat(void) { return RGFW_formatBGRA8; } @@ -10973,35 +11984,6 @@ void RGFW_window_captureMousePlatform(RGFW_window* win, RGFW_bool state) { ClipCursor(&clipRect); } -#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; - RGFW_MEMZERO(&swapChainDesc, sizeof(swapChainDesc)); - 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_debugCallback(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_key0; @@ -11125,7 +12107,8 @@ void RGFW_initKeycodesPlatform(void) { } -i32 RGFW_initPlatform(void) { +i32 RGFW_initPlatform(const char* className, RGFW_initFlags flags) { + RGFW_UNUSED(flags); #ifndef RGFW_NO_DPI #if (_WIN32_WINNT >= 0x0600) SetProcessDPIAware(); @@ -11147,20 +12130,28 @@ i32 RGFW_initPlatform(void) { RGFW_PROC_DEF(RGFW_dwm_dll, DwmSetWindowAttribute); #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 + _RGFW->instance = GetModuleHandleW(NULL); + MultiByteToWideChar(CP_UTF8, 0, className, -1, _RGFW->wideClassName, 255); + + RGFW_MEMZERO(&_RGFW->wndClass, sizeof(_RGFW->wndClass)); + + _RGFW->wndClass.lpszClassName = _RGFW->wideClassName; + _RGFW->wndClass.hInstance = _RGFW->instance; + _RGFW->wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); + _RGFW->wndClass.lpfnWndProc = WndProcW; + _RGFW->wndClass.cbClsExtra = sizeof(RGFW_window*); + _RGFW->wndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); + _RGFW->wndClass.hIcon = (HICON)LoadImageA(_RGFW->instance, "RGFW_ICON", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED); + if (_RGFW->wndClass.hIcon == NULL) + _RGFW->wndClass.hIcon = (HICON)LoadImageA(NULL, (LPCSTR)IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED); + + RegisterClassW(&_RGFW->wndClass); + + _RGFW->helperWindow = CreateWindowW(_RGFW->wndClass.lpszClassName, (wchar_t*)NULL, 0, 0, 0, 0, 0, 0, 0, _RGFW->instance, 0); u8 RGFW_blk[] = { 0, 0, 0, 0 }; _RGFW->hiddenMouse = RGFW_createMouse(RGFW_blk, 1, 1, RGFW_formatRGBA8); - return 1; + return 0; } RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win) { @@ -11173,32 +12164,6 @@ RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, 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; if (!(flags & RGFW_windowNoBorder)) { @@ -11211,20 +12176,13 @@ RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, 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); - -#ifdef RGFW_OPENGL - RGFW_win32_loadOpenGLFuncs(dummyWin); -#endif - - DestroyWindow(dummyWin); RECT rect = { 0, 0, win->w, win->h}; DWORD style = RGFW_winapi_window_getStyle(win, flags); DWORD exStyle = RGFW_winapi_window_getExStyle(win, flags); AdjustWindowRectEx(&rect, style, FALSE, exStyle); - win->src.window = CreateWindowW(Class.lpszClassName, (wchar_t*)wide_name, window_style, win->x + rect.left, win->y + rect.top, rect.right - rect.left, rect.bottom - rect.top, 0, 0, inh, 0); + win->src.window = CreateWindowW(_RGFW->wndClass.lpszClassName, (wchar_t*)wide_name, window_style, win->x + rect.left, win->y + rect.top, rect.right - rect.left, rect.bottom - rect.top, 0, 0, _RGFW->instance, 0); SetPropW(win->src.window, L"RGFW", win); RGFW_window_resize(win, win->w, win->h); /* so WM_GETMINMAXINFO gets called again */ @@ -11309,57 +12267,15 @@ void RGFW_window_raise(RGFW_window* win) { 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); - - RGFW_monitor* mon = RGFW_window_getMonitor(win); - - if (fullscreen == RGFW_FALSE) { - RGFW_monitor_setMode(mon, &win->internal.oldMode); - - RGFW_window_setBorder(win, 1); +void RGFW_window_setFullscreenPlatform(RGFW_window* win, RGFW_bool fullscreen) { RGFW_UNUSED(win); RGFW_UNUSED(fullscreen); } - RECT rect = { 0, 0, win->internal.oldW, win->internal.oldH}; - DWORD style = RGFW_winapi_window_getStyle(win, win->internal.flags); - DWORD exStyle = RGFW_winapi_window_getExStyle(win, win->internal.flags); - AdjustWindowRectEx(&rect, style, FALSE, exStyle); - SetWindowPos(win->src.window, HWND_TOP, win->internal.oldX, win->internal.oldY, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER); - - 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.oldMode = mon->mode; - win->internal.flags |= RGFW_windowFullscreen; - - RGFW_window_setBorder(win, 0); - - SetWindowPos(win->src.window, HWND_TOPMOST, (i32)mon->x, (i32)mon->y, 0, 0, SWP_NOOWNERZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOSIZE); - win->x = mon->x; - win->y = mon->y; - - RGFW_monitor_scaleToWindow(mon, win); - SetWindowPos(win->src.window, HWND_TOPMOST, 0, 0, (i32)mon->mode.w, (i32)mon->mode.h, SWP_NOOWNERZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE); - win->w = mon->mode.w; - win->h = mon->mode.h; -} - -void RGFW_window_maximize(RGFW_window* win) { +void RGFW_window_maximizePlatform(RGFW_window* win) { RGFW_ASSERT(win != NULL); RGFW_window_hide(win); ShowWindow(win->src.window, SW_MAXIMIZE); - RGFW_window_fetchSize(win, NULL, NULL); } -void RGFW_window_minimize(RGFW_window* win) { +void RGFW_window_minimizePlatform(RGFW_window* win) { RGFW_ASSERT(win != NULL); ShowWindow(win->src.window, SW_MINIMIZE); } @@ -11375,14 +12291,14 @@ void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) { SetLayeredWindowAttributes(win->src.window, 0, opacity, LWA_ALPHA); } -void RGFW_window_restore(RGFW_window* win) { RGFW_window_show(win); } +void RGFW_window_restorePlatform(RGFW_window* win) { RGFW_UNUSED(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); + PostMessageW(_RGFW->helperWindow, WM_NULL, 0, 0); } void RGFW_waitForEvent(i32 waitMS) { @@ -11404,9 +12320,15 @@ RGFW_key RGFW_physicalToMappedKey(RGFW_key key) { if (result == 1 && charBuffer[0] < 256) { return (RGFW_key)charBuffer[0]; - } + } switch (vk) { + case VK_BACK: return RGFW_keyBackSpace; + case VK_TAB: return RGFW_keyTab; + /* VK_RETURN can be either RGFW_keyReturn or RGFW_keyPadReturn. RGFW can only give its best guess as to which key it should be. */ + case VK_RETURN: return (key == RGFW_keyPadReturn) ? RGFW_keyPadReturn : RGFW_keyReturn; + case VK_ESCAPE: return RGFW_keyEscape; + case VK_DELETE: return RGFW_keyDelete; case VK_F1: return RGFW_keyF1; case VK_F2: return RGFW_keyF2; case VK_F3: return RGFW_keyF3; @@ -11456,7 +12378,6 @@ RGFW_key RGFW_physicalToMappedKey(RGFW_key key) { case VK_SUBTRACT: return RGFW_keyPadMinus; case VK_MULTIPLY: return RGFW_keyPadMultiply; case VK_DIVIDE: return RGFW_keyPadSlash; - case VK_RETURN: return RGFW_keyPadReturn; case VK_DECIMAL: return RGFW_keyPadPeriod; case VK_NUMPAD0: return RGFW_keyPad0; case VK_NUMPAD1: return RGFW_keyPad1; @@ -11470,7 +12391,7 @@ RGFW_key RGFW_physicalToMappedKey(RGFW_key key) { case VK_NUMPAD9: return RGFW_keyPad9; case VK_SNAPSHOT: return RGFW_keyPrintScreen; case VK_PAUSE: return RGFW_keyPause; - default: return RGFW_keyNULL; + default: break; } return RGFW_keyNULL; @@ -11490,6 +12411,15 @@ void RGFW_pollEvents(void) { RGFW_resetPrevState(); MSG msg; while (PeekMessageA(&msg, NULL, 0u, 0u, PM_REMOVE)) { + if (msg.message == WM_QUIT) { + RGFW_window* cur = _RGFW->root; + while (cur) { + RGFW_window* next = cur->next; + RGFW_windowCloseCallback(cur); + cur = next; + } + } + TranslateMessage(&msg); DispatchMessageA(&msg); } @@ -11503,11 +12433,8 @@ RGFW_bool RGFW_window_isHidden(RGFW_window* win) { RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { RGFW_ASSERT(win != NULL); - #ifndef __cplusplus - WINDOWPLACEMENT placement = {0}; - #else - WINDOWPLACEMENT placement = {}; - #endif + WINDOWPLACEMENT placement; + RGFW_MEMZERO(&placement, sizeof(placement)); GetWindowPlacement(win->src.window, &placement); return placement.showCmd == SW_SHOWMINIMIZED; } @@ -11515,16 +12442,14 @@ RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { RGFW_ASSERT(win != NULL); - #ifndef __cplusplus - WINDOWPLACEMENT placement = {0}; - #else - WINDOWPLACEMENT placement = {}; - #endif + WINDOWPLACEMENT placement; + RGFW_MEMZERO(&placement, sizeof(placement)); GetWindowPlacement(win->src.window, &placement); return placement.showCmd == SW_SHOWMAXIMIZED || IsZoomed(win->src.window); } RGFW_bool RGFW_monitor_getWorkarea(RGFW_monitor* monitor, i32* x, i32* y, i32* width, i32* height) { + RGFW_ASSERT(monitor != NULL); MONITORINFOEX mi; mi.cbSize = sizeof(MONITORINFOEX); GetMonitorInfoA(monitor->node->hMonitor, (LPMONITORINFO)&mi); @@ -11538,6 +12463,7 @@ RGFW_bool RGFW_monitor_getWorkarea(RGFW_monitor* monitor, i32* x, i32* y, i32* w } size_t RGFW_monitor_getGammaRampPtr(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) { + RGFW_ASSERT(monitor != NULL); WORD values[3][256]; HDC dc = CreateDCW(L"DISPLAY", monitor->node->adapterName, NULL, NULL); @@ -11554,6 +12480,7 @@ size_t RGFW_monitor_getGammaRampPtr(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) } RGFW_bool RGFW_monitor_setGammaRamp(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) { + RGFW_ASSERT(monitor != NULL); WORD values[3][256]; if (ramp->count != 256) { RGFW_debugCallback(RGFW_typeError, RGFW_errX11, "Win32: Gamma ramp size must be 256"); @@ -11609,7 +12536,8 @@ void RGFW_win32_getMode(DEVMODEW* dm, RGFW_monitorMode* mode) { } } -size_t RGFW_monitor_getModesPtr(RGFW_monitor* monitor, RGFW_monitorMode** modes){ +size_t RGFW_monitor_getModesPtr(RGFW_monitor* monitor, RGFW_monitorMode** modes) { + RGFW_ASSERT(monitor != NULL); size_t count = 0; DWORD modeIndex = 0; @@ -11654,8 +12582,8 @@ size_t RGFW_monitor_getModesPtr(RGFW_monitor* monitor, RGFW_monitorMode** modes) return count; } -RGFWDEF void RGFW_win32_createMonitor(DISPLAY_DEVICEW* adapter, DISPLAY_DEVICEW* dd); -void RGFW_win32_createMonitor(DISPLAY_DEVICEW* adapter, DISPLAY_DEVICEW* dd) { +RGFWDEF void RGFW_win32_initMonitor(DISPLAY_DEVICEW* adapter, RGFW_monitorNode* node); +void RGFW_win32_initMonitor(DISPLAY_DEVICEW* adapter, RGFW_monitorNode* node) { DEVMODEW dm; ZeroMemory(&dm, sizeof(dm)); dm.dmSize = sizeof(dm); @@ -11664,14 +12592,6 @@ void RGFW_win32_createMonitor(DISPLAY_DEVICEW* adapter, DISPLAY_DEVICEW* dd) { return; } - RGFW_monitorNode* node = RGFW_monitors_add(NULL); - - wcscpy(node->adapterName, adapter->DeviceName); - wcscpy(node->deviceName, dd->DeviceName); - - RGFW_createUTF8FromWideStringWin32(dd->DeviceString, node->mon.name, sizeof(node->mon.name)); - node->mon.name[sizeof(node->mon.name) - 1] = '\0'; - RECT rect; rect.left = (LONG)dm.dmPosition.x; rect.top = (LONG)dm.dmPosition.y; @@ -11689,9 +12609,9 @@ void RGFW_win32_createMonitor(DISPLAY_DEVICEW* adapter, DISPLAY_DEVICEW* dd) { node->mon.y = 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); + float dpiY = (float)GetDeviceCaps(hdc, LOGPIXELSY); node->mon.scaleX = dpiX / 96.0f; node->mon.scaleY = dpiY / 96.0f; @@ -11717,6 +12637,18 @@ void RGFW_win32_createMonitor(DISPLAY_DEVICEW* adapter, DISPLAY_DEVICEW* dd) { if (monitorInfo.dwFlags & MONITORINFOF_PRIMARY) { _RGFW->monitors.primary = node; } +} + +RGFWDEF void RGFW_win32_createMonitor(DISPLAY_DEVICEW* adapter, DISPLAY_DEVICEW* dd); +void RGFW_win32_createMonitor(DISPLAY_DEVICEW* adapter, DISPLAY_DEVICEW* dd) { + RGFW_monitorNode* node = RGFW_monitors_add(NULL); + RGFW_win32_initMonitor(adapter, node); + + wcscpy(node->adapterName, adapter->DeviceName); + wcscpy(node->deviceName, dd->DeviceName); + + i32 size = RGFW_createUTF8FromWideStringWin32(dd->DeviceString, node->mon.name, sizeof(node->mon.name)); + node->mon.name[size - 1] = '\0'; RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_TRUE); } @@ -11758,7 +12690,7 @@ void RGFW_pollMonitors(void) { for (node = _RGFW->monitors.list.head; node; node = node->next) { if (node->disconnected == RGFW_TRUE && wcscmp(node->deviceName, dd.DeviceName) == 0) { node->disconnected = RGFW_FALSE; - EnumDisplayMonitors(NULL, NULL, RGFW_win32_getMonitorHandle, (LPARAM) &node->mon); + RGFW_win32_initMonitor(&adapter, node); break; } } @@ -11776,6 +12708,7 @@ void RGFW_pollMonitors(void) { for (node = _RGFW->monitors.list.head; node; node = node->next) { if (node->disconnected == RGFW_TRUE && wcscmp(node->adapterName, adapter.DeviceName) == 0) { node->disconnected = RGFW_FALSE; + RGFW_win32_initMonitor(&adapter, node); break; } } @@ -11783,14 +12716,16 @@ void RGFW_pollMonitors(void) { if (node) { continue; } - - RGFW_win32_createMonitor(&adapter, NULL); } } RGFW_monitors_refresh(); } +void RGFW_monitorNode_free(RGFW_monitorNode* node) { + RGFW_ASSERT(node); +} + RGFW_monitor* RGFW_window_getMonitor(RGFW_window* win) { HMONITOR src = MonitorFromWindow(win->src.window, MONITOR_DEFAULTTOPRIMARY); RGFW_monitorNode* node = _RGFW->monitors.list.head; @@ -11805,6 +12740,7 @@ RGFW_monitor* RGFW_window_getMonitor(RGFW_window* win) { } RGFW_bool RGFW_monitor_setMode(RGFW_monitor* mon, RGFW_monitorMode* mode) { + RGFW_ASSERT(mon != NULL); DEVMODEW dm; ZeroMemory(&dm, sizeof(dm)); dm.dmSize = sizeof(dm); @@ -11822,6 +12758,7 @@ RGFW_bool RGFW_monitor_setMode(RGFW_monitor* mon, RGFW_monitorMode* mode) { if (ChangeDisplaySettingsExW(mon->node->adapterName, &dm, NULL, CDS_TEST, NULL) == DISP_CHANGE_SUCCESSFUL) { if (ChangeDisplaySettingsExW(mon->node->adapterName, &dm, NULL, CDS_UPDATEREGISTRY, NULL) == DISP_CHANGE_SUCCESSFUL) { RGFW_win32_getMode(&dm, &mon->mode); + mon->mode = *mode; return RGFW_TRUE; } return RGFW_FALSE; @@ -11829,7 +12766,8 @@ RGFW_bool RGFW_monitor_setMode(RGFW_monitor* mon, RGFW_monitorMode* mode) { } RGFW_bool RGFW_monitor_requestMode(RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request) { -HMONITOR src = mon->node->hMonitor; + RGFW_ASSERT(mon != NULL); + HMONITOR src = mon->node->hMonitor; MONITORINFOEX monitorInfo; monitorInfo.cbSize = sizeof(MONITORINFOEX); @@ -11968,9 +12906,10 @@ 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); +void RGFW_window_showPlatform(RGFW_window* win) { + if (!(win->internal.flags & RGFW_windowMaximize)) { + ShowWindow(win->src.window, SW_RESTORE); + } } void RGFW_window_flash(RGFW_window* win, RGFW_flashRequest request) { @@ -12004,21 +12943,25 @@ void RGFW_window_flash(RGFW_window* win, RGFW_flashRequest request) { #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); + 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 + timeEndPeriod(1); + #ifndef RGFW_NO_LOAD_WINMM + RGFW_FREE_LIBRARY(RGFW_winmm_dll); + #endif #endif - RGFW_FREE_LIBRARY(RGFW_wgl_dll); + if (_RGFW->helperWindow) + DestroyWindow(_RGFW->helperWindow); - RGFW_freeMouse(_RGFW->hiddenMouse); -} + if (_RGFW->instance) + UnregisterClassW(_RGFW->wndClass.lpszClassName, _RGFW->instance); + if (_RGFW->hiddenMouse) + RGFW_freeMouse(_RGFW->hiddenMouse); +} void RGFW_window_closePlatform(RGFW_window* win) { RemovePropW(win->src.window, L"RGFW"); @@ -12029,19 +12972,16 @@ void RGFW_window_closePlatform(RGFW_window* win) { 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_movePlatform(RGFW_window* win, i32 x, i32 y) { + SetWindowPos(win->src.window, HWND_TOP, x, y, 0, 0, SWP_NOSIZE); } -void RGFW_window_resize(RGFW_window* win, i32 w, i32 h) { - RGFW_ASSERT(win != NULL); +void RGFW_window_resizePlatform(RGFW_window* win, i32 w, i32 h) { + if (win->internal.flags & RGFW_windowNoResize) { + win->src.minSizeW = win->src.maxSizeW = w; + win->src.minSizeH = win->src.maxSizeH = h; + } - win->w = w; - win->h = h; RECT rect = { 0, 0, w, h}; DWORD style = RGFW_winapi_window_getStyle(win, win->internal.flags); DWORD exStyle = RGFW_winapi_window_getExStyle(win, win->internal.flags); @@ -12115,69 +13055,84 @@ RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_f #endif } -RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) { +RGFW_bool RGFW_readClipboardPtr(RGFW_dataTransferType requestedType, u8* buffer, size_t capacity, RGFW_dataTransfer* data) { + RGFW_ASSERT(data != NULL); + + if (requestedType != RGFW_dataText) return RGFW_FALSE; + /* Open the clipboard */ - if (OpenClipboard(NULL) == 0) - return -1; + size_t retry = 0; + BOOL isOpen = FALSE; + while (isOpen == FALSE && retry < 3) { + isOpen = OpenClipboard(NULL); + retry += 1; + } + + if (isOpen == FALSE) return RGFW_FALSE; /* Get the clipboard data as a Unicode string */ HANDLE hData = GetClipboardData(CF_UNICODETEXT); if (hData == NULL) { CloseClipboard(); - return -1; + return RGFW_FALSE; } wchar_t* wstr = (wchar_t*) GlobalLock(hData); - RGFW_ssize_t textLen = 0; + RGFW_bool ret = RGFW_TRUE; - { - 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; + i32 length = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL); + if (length <= 0) return RGFW_FALSE; - if (str != NULL && textLen) { - if (textLen > 1) - wcstombs(str, wstr, (size_t)(textLen)); + data->length = (size_t)length; + data->type = RGFW_dataText; - str[textLen - 1] = '\0'; - } + if (buffer != NULL && capacity < data->length) { + ret = RGFW_FALSE; + } else if (buffer != NULL && data->length) { + if (WideCharToMultiByte(CP_UTF8, 0, wstr, -1, (char*)buffer, length, NULL, NULL) <= 0) return RGFW_FALSE; + data->data = (const char*)buffer; } /* Release the clipboard data */ GlobalUnlock(hData); CloseClipboard(); - return textLen; + return ret; } -void RGFW_writeClipboard(const char* text, u32 textLen) { - HANDLE object; - WCHAR* buffer; - - object = GlobalAlloc(GMEM_MOVEABLE, (1 + textLen) * sizeof(WCHAR)); +RGFW_bool RGFW_writeClipboard(const RGFW_dataTransfer* data) { + RGFW_ASSERT(data != NULL); + HANDLE object = GlobalAlloc(GMEM_MOVEABLE, data->length * sizeof(WCHAR)); if (!object) - return; + return RGFW_FALSE; - buffer = (WCHAR*) GlobalLock(object); + WCHAR* buffer = (WCHAR*) GlobalLock(object); if (!buffer) { GlobalFree(object); - return; + return RGFW_FALSE; } - MultiByteToWideChar(CP_UTF8, 0, text, -1, buffer, (i32)textLen); + MultiByteToWideChar(CP_UTF8, 0, data->data, -1, buffer, (i32)data->length); GlobalUnlock(object); - if (!OpenClipboard(_RGFW->root->src.window)) { + size_t retry = 0; + BOOL isOpen = FALSE; + while (isOpen == FALSE && retry < 3) { + isOpen = OpenClipboard(NULL); + retry += 1; + } + + if (isOpen == FALSE) { GlobalFree(object); - return; + return RGFW_FALSE; } EmptyClipboard(); SetClipboardData(CF_UNICODETEXT, object); CloseClipboard(); + + return RGFW_TRUE; } void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y) { @@ -12187,6 +13142,36 @@ void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y) { SetCursorPos(x, y); } +#ifdef RGFW_DIRECTX +i32 RGFW_window_createSwapChain_DirectX(RGFW_window* win, IDXGIFactory* pFactory, IUnknown* pDevice, IDXGISwapChain** swapchain) { + RGFW_ASSERT(win && pFactory && pDevice && swapchain); + + DXGI_SWAP_CHAIN_DESC swapChainDesc; + RGFW_MEMZERO(&swapChainDesc, sizeof(swapChainDesc)); + 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; +#ifdef __cplusplus + HRESULT hr = pFactory->CreateSwapChain(pDevice, &swapChainDesc, swapchain); +#else + HRESULT hr = pFactory->lpVtbl->CreateSwapChain(pFactory, (IUnknown*)pDevice, &swapChainDesc, swapchain); +#endif + if (FAILED(hr)) { + RGFW_debugCallback(RGFW_typeError, RGFW_errDirectXContext, "Failed to create DirectX swap chain!"); + return -2; + } + + return 0; +} +#endif + #ifdef RGFW_OPENGL RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char * extension, size_t len) { const char* extensions = NULL; @@ -12195,97 +13180,27 @@ RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char * extension, size_t RGFW_proc proc2 = RGFW_getProcAddress_OpenGL("wglGetExtensionsStringEXT"); if (proc) - extensions = ((const char* (*)(HDC))proc)(wglGetCurrentDC()); + extensions = ((const char* (*)(HDC))proc)(RGFW_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); + RGFW_proc proc = (RGFW_proc)_RGFW->glGetProcAddress(procname); if (proc) return proc; - return (RGFW_proc) GetProcAddress(RGFW_wgl_dll, procname); + return (RGFW_proc) GetProcAddress((HMODULE)_RGFW->nativeGL_handle, 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_debugCallback(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_FORWARD_COMPATIBLE_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) { +RGFW_bool RGFW_createContextPtr_OpenGL(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; + HWND dummyWindow = CreateWindowW(_RGFW->wndClass.lpszClassName, (wchar_t*)NULL, 0, 0, 0, 0, 0, 0, 0, _RGFW->instance, 0); + HDC hdc = GetDC(dummyWindow); PIXELFORMATDESCRIPTOR pfd; pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); @@ -12293,9 +13208,9 @@ RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* 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.cColorBits = (BYTE)(hints->red + hints->green + hints->blue + hints->alpha); + pfd.cAlphaBits = (BYTE)hints->alpha; + pfd.cDepthBits = (BYTE)hints->depth; pfd.cStencilBits = (BYTE)hints->stencil; pfd.cAuxBuffers = (BYTE)hints->auxBuffers; if (hints->stereo) pfd.dwFlags |= PFD_STEREO; @@ -12305,8 +13220,8 @@ RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* 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) { + ctx->format = ChoosePixelFormat(hdc, &pfd); + if (RGFW_wglChoosePixelFormatARB != NULL) { i32 pixel_format_attribs[50]; RGFW_attribStack stack; RGFW_attribStack_init(&stack, pixel_format_attribs, 50); @@ -12315,7 +13230,7 @@ RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* 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_COLOR_BITS_ARB, hints->red + hints->green + hints->blue + hints->alpha); 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); @@ -12337,24 +13252,28 @@ RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* RGFW_attribStack_pushAttribs(&stack, WGL_COLORSPACE_SRGB_EXT, hints->sRGB); } - RGFW_attribStack_pushAttribs(&stack, WGL_COVERAGE_SAMPLES_NV, hints->samples); + if (hints->samples) { + RGFW_attribStack_pushAttribs(&stack, WGL_SAMPLE_BUFFERS_ARB, 1); + RGFW_attribStack_pushAttribs(&stack, WGL_SAMPLES_ARB, 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); + RGFW_wglChoosePixelFormatARB(hdc, pixel_format_attribs, 0, 1, &new_pixel_format, &num_formats); if (!num_formats) RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to create a pixel format for WGL"); - else pixel_format = new_pixel_format; + else ctx->format = new_pixel_format; } + PIXELFORMATDESCRIPTOR suggested; - if (!DescribePixelFormat(win->src.hdc, pixel_format, sizeof(suggested), &suggested) || - !SetPixelFormat(win->src.hdc, pixel_format, &pfd)) + if (!DescribePixelFormat(hdc, ctx->format, sizeof(suggested), &suggested) || + !SetPixelFormat(hdc, ctx->format, &suggested)) RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to set the WGL pixel format"); - if (wglCreateContextAttribsARB != NULL) { + if (RGFW_wglCreateContextAttribsARB != NULL) { /* create OpenGL/WGL context for the specified version */ i32 attribs[40]; RGFW_attribStack stack; @@ -12398,41 +13317,109 @@ RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* RGFW_attribStack_pushAttribs(&stack, 0, 0); - win->src.ctx.native->ctx = (HGLRC)wglCreateContextAttribsARB(win->src.hdc, NULL, attribs); + ctx->ctx = (HGLRC)RGFW_wglCreateContextAttribsARB(hdc, NULL, attribs); } - if (wglCreateContextAttribsARB == NULL || win->src.ctx.native->ctx == NULL) { /* fall back to a default context (probably OpenGL 2 or something) */ + if (RGFW_wglCreateContextAttribsARB == NULL || ctx->ctx == NULL) { /* fall back to a default context (probably OpenGL 2 or something) */ RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to create an accelerated OpenGL Context."); - win->src.ctx.native->ctx = wglCreateContext(win->src.hdc); + ctx->ctx = RGFW_wglCreateContext(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); + RGFW_wglShareLists((HGLRC)RGFW_getCurrentContext_OpenGL(), hints->share->ctx); } - wglMakeCurrent(win->src.hdc, win->src.ctx.native->ctx); + DestroyWindow(dummyWindow); + RGFW_debugCallback(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_bool RGFW_window_setContext_OpenGL(RGFW_window* win, RGFW_glContext* ctx) { + RGFW_ASSERT(win); + if (ctx == NULL && win->src.ctx.native != NULL) { + RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL surface freed."); + win->src.ctx.native = NULL; + + RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL window surface freed"); + return RGFW_TRUE; + } + + win->src.ctx.native = ctx; + win->src.gfxType = RGFW_gfxNativeOpenGL; + + PIXELFORMATDESCRIPTOR suggested; + if (!DescribePixelFormat(win->src.hdc, ctx->format, sizeof(suggested), &suggested) || + !SetPixelFormat(win->src.hdc, ctx->format, &suggested)) + RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to set the WGL pixel format"); + + if (RGFW_wglMakeCurrent(win->src.hdc, win->src.ctx.native->ctx) == FALSE) { + /* + Windows may fail to set the pixel format if the window was already created, + this tries to make a new window as a fallback + */ + + int length = GetWindowTextLengthW(win->src.window); + char* name = NULL; + if (length > 0) { + WCHAR* buffer = (WCHAR*)RGFW_ALLOC(sizeof(WCHAR) * (size_t)(length)); + if (GetWindowTextW(win->src.window, buffer, length) > 0) { + i32 clength = RGFW_createUTF8FromWideStringWin32(buffer, NULL, 0); + if (clength > 0) { + name = (char*)RGFW_ALLOC((size_t)clength + 1); + if (RGFW_createUTF8FromWideStringWin32(buffer, name, (size_t)clength) > 0) { + name[clength] = '\0'; + } else { + RGFW_FREE(name); + name = NULL; + } + } + RGFW_FREE(buffer); + } + } + + RGFW_window_closePlatform(win); + win = RGFW_createWindowPlatform(name ? name : "", win->internal.flags, win); + + if (name) RGFW_FREE(name); + + win->src.ctx.native = ctx; + win->src.gfxType = RGFW_gfxNativeOpenGL; + + if (!DescribePixelFormat(win->src.hdc, ctx->format, sizeof(suggested), &suggested) || + !SetPixelFormat(win->src.hdc, ctx->format, &suggested)) + RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to set the WGL pixel format"); + + if (RGFW_wglMakeCurrent(win->src.hdc, win->src.ctx.native->ctx) == FALSE) { + RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "failed to create OpenGL surface."); + return RGFW_FALSE; + } + } + + RGFW_window_swapInterval_OpenGL(win, 0); + RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL surface initalized."); + return RGFW_TRUE; +} + +void RGFW_deleteContextPtr_OpenGL(RGFW_glContext* ctx) { + RGFW_wglDeleteContext((HGLRC) ctx->ctx); /*!< delete OpenGL context */ RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context freed."); } void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win) { if (win == NULL) - wglMakeCurrent(NULL, NULL); + RGFW_wglMakeCurrent(NULL, NULL); else - wglMakeCurrent(win->src.hdc, (HGLRC) win->src.ctx.native->ctx); + RGFW_wglMakeCurrent(win->src.hdc, (HGLRC) win->src.ctx.native->ctx); } void* RGFW_getCurrentContext_OpenGL(void) { - return wglGetCurrentContext(); + return RGFW_wglGetCurrentContext(); +} + +void* RGFW_getCurrentSurface_OpenGL(void) { + return RGFW_wglGetCurrentDC(); } + void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { RGFW_ASSERT(win->src.ctx.native); SwapBuffers(win->src.hdc); @@ -12440,31 +13427,18 @@ void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { void RGFW_window_swapInterval_OpenGL(RGFW_window* win, i32 swapInterval) { RGFW_ASSERT(win != NULL); - if (wglSwapIntervalEXT == NULL || wglSwapIntervalEXT(swapInterval) == FALSE) - RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to set swap interval"); -} -#endif + void* ctx = RGFW_getCurrentContext_OpenGL(); + void* surf = RGFW_getCurrentSurface_OpenGL(); + if (ctx != win->src.ctx.native->ctx || surf != win->src.hdc) + RGFW_wglMakeCurrent(win->src.hdc, (HGLRC) win->src.ctx.native->ctx); -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; - } + if (RGFW_wglSwapIntervalEXT == NULL || RGFW_wglSwapIntervalEXT(swapInterval) == FALSE) + RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to set swap interval"); - output[size] = 0; - return RGFW_TRUE; + if (ctx != win->src.ctx.native->ctx || surf != win->src.hdc) + RGFW_wglMakeCurrent((HDC)surf, (HGLRC)ctx); } +#endif #ifdef RGFW_WEBGPU WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance instance) { @@ -12473,7 +13447,7 @@ WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance i fromHwnd.chain.sType = WGPUSType_SurfaceSourceWindowsHWND; fromHwnd.hwnd = window->src.window; - fromHwnd.hinstance = GetModuleHandle(NULL); + fromHwnd.hinstance = _RGFW->instance; surfaceDesc.nextInChain = (WGPUChainedStruct*)&fromHwnd.chain; return wgpuInstanceCreateSurface(instance, &surfaceDesc); @@ -12523,12 +13497,15 @@ PFN_LMGetKbdType LMGetKbdTypeSrc; CFStringRef kTISPropertyUnicodeKeyLayoutDataSrc; +#define RSGL_NSPasteboardTypeURL "public.url" +#define RSGL_NSPasteboardTypeFileURL "public.file-url" +#define RSGL_NSPasteboardTypeString "public.utf8-plain-text" + #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; @@ -12538,19 +13515,19 @@ typedef enum NSRequestUserAttentionType { NSInformationalRequest = 10 } NSRequestUserAttentionType; -typedef enum NSApplicationActivationPolicy { +typedef RGFW_ENUM(NSInteger, NSApplicationActivationPolicy) { NSApplicationActivationPolicyRegular, NSApplicationActivationPolicyAccessory, NSApplicationActivationPolicyProhibited -} NSApplicationActivationPolicy; +}; -typedef RGFW_ENUM(u32, NSBackingStoreType) { +typedef RGFW_ENUM(NSUInteger, NSBackingStoreType) { NSBackingStoreRetained = 0, NSBackingStoreNonretained = 1, NSBackingStoreBuffered = 2 }; -typedef RGFW_ENUM(u32, NSWindowStyleMask) { +typedef RGFW_ENUM(NSUInteger, NSWindowStyleMask) { NSWindowStyleMaskBorderless = 0, NSWindowStyleMaskTitled = 1 << 0, NSWindowStyleMaskClosable = 1 << 1, @@ -12566,9 +13543,7 @@ typedef RGFW_ENUM(u32, NSWindowStyleMask) { NSWindowStyleMaskHUDWindow = 1 << 13 }; -#define NSPasteboardTypeString "public.utf8-plain-text" - -typedef RGFW_ENUM(i32, NSDragOperation) { +typedef RGFW_ENUM(NSUInteger, NSDragOperation) { NSDragOperationNone = 0, NSDragOperationCopy = 1, NSDragOperationLink = 2, @@ -12608,8 +13583,6 @@ typedef RGFW_ENUM(NSInteger, NSWindowButton) { NSWindowFullScreenButton = 7, }; -#define NSPasteboardTypeURL "public.url" -#define NSPasteboardTypeFileURL "public.file-url" #define NSTrackingMouseEnteredAndExited 0x01 #define NSTrackingMouseMoved 0x02 #define NSTrackingCursorUpdate 0x04 @@ -12665,19 +13638,19 @@ enum { NSOpenGLPFARemotePixelBuffer = 91, }; -typedef RGFW_ENUM(u32, NSEventType) { /* various types of events */ +typedef RGFW_ENUM(NSUInteger, NSEventType) { /* various types of events */ NSEventTypeApplicationDefined = 15, }; -typedef unsigned long long NSEventMask; +typedef NSUInteger NSEventMask; -typedef enum NSEventModifierFlags { +typedef RGFW_ENUM(NSUInteger, 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.) */ @@ -12731,6 +13704,17 @@ id NSString_stringWithUTF8String(const char* str) { RGFWDEF float RGFW_cocoaYTransform(float y); float RGFW_cocoaYTransform(float y) { return (float)(CGDisplayBounds(CGMainDisplayID()).size.height - (double)y - (double)1.0f); } +RGFWDEF void RGFW_cocoaFetchRect(RGFW_window* win); +void RGFW_cocoaFetchRect(RGFW_window* win) { + NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame")); + NSRect content = ((NSRect(*)(id, SEL, NSRect))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("contentRectForFrameRect:"), frame); + + win->x = (i32)content.origin.x; + win->y = (i32)RGFW_cocoaYTransform((float)(content.origin.y + content.size.height - 1)); + win->w = (i32)content.size.width; + win->h = (i32)content.size.height; +} + 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")); @@ -12772,8 +13756,8 @@ id* cstrToNSStringArray(char** strs, size_t len) { return nstrs; } -const char* NSPasteboard_stringForType(id pasteboard, NSPasteboardType dataType, size_t* len); -const char* NSPasteboard_stringForType(id pasteboard, NSPasteboardType dataType, size_t* len) { +const char* NSPasteboard_stringForType(id pasteboard, const char* dataType, size_t* len); +const char* NSPasteboard_stringForType(id pasteboard, const char* 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); @@ -12789,8 +13773,8 @@ id c_array_to_NSArray(void* array, size_t len) { } -void NSregisterForDraggedTypes(id view, NSPasteboardType* newTypes, size_t len); -void NSregisterForDraggedTypes(id view, NSPasteboardType* newTypes, size_t len) { +void NSregisterForDraggedTypes(id view, const char** newTypes, size_t len); +void NSregisterForDraggedTypes(id view, const char** newTypes, size_t len) { id* ntypes = cstrToNSStringArray((char**)newTypes, len); id array = c_array_to_NSArray(ntypes, len); @@ -12798,8 +13782,8 @@ void NSregisterForDraggedTypes(id view, NSPasteboardType* newTypes, size_t len) 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) { +NSInteger NSPasteBoard_declareTypes(id pasteboard, const char** newTypes, size_t len, void* owner); +NSInteger NSPasteBoard_declareTypes(id pasteboard, const char** newTypes, size_t len, void* owner) { id* ntypes = cstrToNSStringArray((char**)newTypes, len); SEL func = sel_registerName("declareTypes:owner:"); @@ -12813,8 +13797,6 @@ NSInteger NSPasteBoard_declareTypes(id pasteboard, NSPasteboardType* newTypes, s return output; } -#define NSRetain(obj) objc_msgSend_void((id)obj, sel_registerName("retain")) - /* End of cocoa wrapper */ @@ -12847,24 +13829,16 @@ static id RGFW__osxCustomInitWithRGFWWindow(id self, SEL _cmd, RGFW_window* win) ((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" - ) - ) - ); - } + const char* types[] = {RSGL_NSPasteboardTypeURL, RSGL_NSPasteboardTypeFileURL, RSGL_NSPasteboardTypeString}; + NSregisterForDraggedTypes((id)self, types, 3); + + } return self; } -static u32 RGFW_OnClose(id self) { +static BOOL RGFW_osxWindowShouldClose(id self, SEL _cmd, id sender) { + RGFW_UNUSED(_cmd); RGFW_UNUSED(sender); RGFW_window* win = NULL; object_getInstanceVariable(self, (const char*)"RGFW_window", (void**)&win); if (win == NULL) return true; @@ -12873,9 +13847,47 @@ static u32 RGFW_OnClose(id self) { return false; } -/* NOTE(EimaMei): Fixes the constant clicking when the app is running under a terminal. */ -static bool RGFW__osxAcceptsFirstResponder(void) { return true; } -static bool RGFW__osxPerformKeyEquivalent(id event) { RGFW_UNUSED(event); return true; } +static BOOL RGFW__osxAcceptsFirstResponder(id self, SEL _cmd) { RGFW_UNUSED(self); RGFW_UNUSED(_cmd); return true; } +static BOOL RGFW__osxPerformKeyEquivalent(id self, SEL _cmd, id event) { + RGFW_UNUSED(_cmd); + RGFW_window* win = NULL; + object_getInstanceVariable(self, (const char*)"RGFW_window", (void**)&win); + if (win == NULL) return true; + + /* claim and emit consumed key combinations so they aren't missed (hack borrowed from GLFW (I'm not giving it back)) */ + u32 key = (u16)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("keyCode")); + RGFW_key value = (u8)RGFW_apiKeyToRGFW(key); + + u32 flags = (u32)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("modifierFlags")); + RGFW_keyUpdateKeyModsEx(win, + ((u32)(flags & NSEventModifierFlagCapsLock) % 255), + ((flags & NSEventModifierFlagNumericPad) % 255), + ((flags & NSEventModifierFlagControl) % 255), + ((flags & NSEventModifierFlagOption) % 255), + ((flags & NSEventModifierFlagShift) % 255), + ((flags & NSEventModifierFlagCommand) % 255), 0); + + RGFW_bool repeat = RGFW_isKeyDown(value); + + if (win->internal.mod & RGFW_modControl) { + if (key == RGFW_keyTab || key == RGFW_keyEscape) { + RGFW_keyCallback(win, value, win->internal.mod, repeat, 1); + return YES; + } + } + + if (win->internal.mod & RGFW_modSuper) { + if (key == RGFW_keyPeriod) { + RGFW_keyCallback(win, value, win->internal.mod, repeat, 1); + return YES; + } + } + + struct objc_super s = { self, class_getSuperclass(object_getClass(self)) }; + return ((bool (*)(struct objc_super*, SEL, id))objc_msgSendSuper)(&s, sel_registerName("performKeyEquivalent:"), event); +} + +static BOOL RGFW__osxAcceptsFirstMouse(id self, SEL _cmd, id event) { RGFW_UNUSED(self); RGFW_UNUSED(_cmd); RGFW_UNUSED(event); return true; } static NSDragOperation RGFW__osxDraggingEntered(id self, SEL sel, id sender) { RGFW_UNUSED(sel); @@ -12902,7 +13914,7 @@ static NSDragOperation RGFW__osxDraggingUpdated(id self, SEL sel, id sender) { RGFW_dataDragCallback(win, RGFW_dataFile, RGFW_dndActionMove, (i32) p.x, (i32) (win->h - p.y)); return NSDragOperationCopy; } -static bool RGFW__osxPrepareForDragOperation(id self) { +static BOOL RGFW__osxPrepareForDragOperation(id self) { RGFW_window* win = NULL; object_getInstanceVariable(self, "RGFW_window", (void**)&win); if (win == NULL || (!(win->internal.enabledEvents & RGFW_dataDropFlag))) @@ -12929,7 +13941,7 @@ static void RGFW__osxDraggingEnded(id self, SEL sel, id sender) { return; } -static bool RGFW__osxPerformDragOperation(id self, SEL sel, id sender) { +static BOOL RGFW__osxPerformDragOperation(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); @@ -12952,17 +13964,25 @@ static bool RGFW__osxPerformDragOperation(id self, SEL sel, id sender) { return 0; } - id fileURLs = objc_msgSend_id_id(pasteBoard, sel_registerName("propertyListForType:"), fileURLsType); - int count = ((int (*)(id, SEL))objc_msgSend)(fileURLs, sel_registerName("count")); + id propertyList = objc_msgSend_id_id(pasteBoard, sel_registerName("propertyListForType:"), fileURLsType); + + if (objc_msgSend_id_bool(propertyList, sel_registerName("isKindOfClass:"), objc_getClass("NSString"))) { + int string_count = ((int (*)(id, SEL))objc_msgSend)(propertyList , sel_registerName("length")); + const char *filePath = ((const char* (*)(id, SEL))objc_msgSend)(propertyList, sel_registerName("UTF8String")); + RGFW_dataDropCallback(win, filePath, (size_t)string_count + 1, RGFW_dataFile); + /*} if (objc_msgSend_id_bool(propertyList, sel_registerName("isKindOfClass:"), objc_getClass("NSData"))) { */ + } if (objc_msgSend_id_bool(propertyList, sel_registerName("isKindOfClass:"), objc_getClass("NSArray")) == false) return false; + + int count = ((int (*)(id, SEL))objc_msgSend)(propertyList, sel_registerName("count")); if (count == 0) return 0; u32 i; for (i = 0; i < (u32)count; i++) { - id fileURL = objc_msgSend_arr(fileURLs, sel_registerName("objectAtIndex:"), i); + id fileURL = objc_msgSend_arr(propertyList, sel_registerName("objectAtIndex:"), i); const char *filePath = ((const char* (*)(id, SEL))objc_msgSend)(fileURL, sel_registerName("UTF8String")); - int string_count = ((int (*)(id, SEL))objc_msgSend)(fileURL, sel_registerName("count")); + int string_count = ((int (*)(id, SEL))objc_msgSend)(fileURL, sel_registerName("length")); RGFW_dataDropCallback(win, filePath, (size_t)string_count + 1, RGFW_dataFile); } @@ -13050,8 +14070,23 @@ static void RGFW__osxDidChangeScreenParameters(id self, SEL _cmd, id notificatio RGFW_pollMonitors(); } -static void RGFW__osxWindowDeminiaturize(id self, SEL sel) { - RGFW_UNUSED(sel); +static NSUInteger RGFW__osxApplicationShouldTerminate(id self, SEL _cmd, id sender) { + RGFW_UNUSED(self); RGFW_UNUSED(_cmd); RGFW_UNUSED(sender); + + id windows = objc_msgSend_id(_RGFW->NSApp, sel_registerName("windows")); + NSUInteger count = (NSUInteger)objc_msgSend_uint(windows, sel_registerName("count")); + + for (unsigned long i = 0; i < count; i++) { + id window = ((id (*)(id, SEL, int))objc_msgSend) (windows, sel_registerName("objectAtIndex:"), (int)i); + id delegate = ((id (*)(id, SEL))objc_msgSend) (window, sel_registerName("delegate")); + ((void(*)(id, SEL, id))objc_msgSend)(delegate, sel_registerName("windowShouldClose:"), window); + } + + return 0; /* NSTerminateCancel */ +} + +static void RGFW__osxWindowDeminiaturize(id self, SEL sel, id notification) { + RGFW_UNUSED(sel); RGFW_UNUSED(notification); RGFW_window* win = NULL; object_getInstanceVariable(self, "RGFW_window", (void**)&win); if (win == NULL) return; @@ -13059,8 +14094,8 @@ static void RGFW__osxWindowDeminiaturize(id self, SEL sel) { RGFW_windowRestoredCallback(win, win->x, win->y, win->w, win->h); } -static void RGFW__osxWindowMiniaturize(id self, SEL sel) { - RGFW_UNUSED(sel); +static void RGFW__osxWindowMiniaturize(id self, SEL sel, id notification) { + RGFW_UNUSED(sel); RGFW_UNUSED(notification); RGFW_window* win = NULL; object_getInstanceVariable(self, "RGFW_window", (void**)&win); if (win == NULL) return; @@ -13069,8 +14104,8 @@ static void RGFW__osxWindowMiniaturize(id self, SEL sel) { } -static void RGFW__osxWindowBecameKey(id self, SEL sel) { - RGFW_UNUSED(sel); +static void RGFW__osxWindowBecameKey(id self, SEL sel, id notification) { + RGFW_UNUSED(sel); RGFW_UNUSED(notification); RGFW_window* win = NULL; object_getInstanceVariable(self, "RGFW_window", (void**)&win); if (win == NULL) return; @@ -13078,8 +14113,8 @@ static void RGFW__osxWindowBecameKey(id self, SEL sel) { RGFW_windowFocusCallback(win, RGFW_TRUE); } -static void RGFW__osxWindowResignKey(id self, SEL sel) { - RGFW_UNUSED(sel); +static void RGFW__osxWindowResignKey(id self, SEL sel, id notification) { + RGFW_UNUSED(sel); RGFW_UNUSED(notification); RGFW_window* win = NULL; object_getInstanceVariable(self, "RGFW_window", (void**)&win); if (win == NULL) return; @@ -13113,8 +14148,8 @@ static void RGFW__osxDidWindowResize(id self, SEL _cmd, id notification) { RGFW_windowResizedCallback(win, win->w, win->h); } -static void RGFW__osxWindowMove(id self, SEL sel) { - RGFW_UNUSED(sel); +static void RGFW__osxWindowMove(id self, SEL sel, id notification) { + RGFW_UNUSED(sel); RGFW_UNUSED(notification); RGFW_window* win = NULL; object_getInstanceVariable(self, "RGFW_window", (void**)&win); if (win == NULL) return; @@ -13155,7 +14190,9 @@ static void RGFW__osxDrawRect(id self, SEL _cmd, CGRect rect) { object_getInstanceVariable(self, "RGFW_window", (void**)&win); if (win == NULL) return; - RGFW_windowRefreshCallback(win, 0, 0, win->w, win->h); + float y = RGFW_cocoaYTransform((float)(rect.size.height - 1)); + + RGFW_windowRefreshCallback(win, (i32)rect.origin.x, (i32)y, (i32)rect.size.width, (i32)rect.size.height); } static void RGFW__osxMouseEntered(id self, SEL _cmd, id event) { @@ -13267,7 +14304,7 @@ static void RGFW__osxMouseMoved(id self, SEL _cmd, id event) { CGFloat vecX = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(event, sel_registerName("deltaX")); CGFloat vecY = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(event, sel_registerName("deltaY")); - RGFW_mousePosCallback(win, (i32)p.x, (i32)(win->h - p.y)); + RGFW_mouseMotionCallback(win, (i32)p.x, (i32)(win->h - p.y)); RGFW_rawMotionCallback(win, (float)vecX, (float)vecY); } @@ -13315,10 +14352,27 @@ static void RGFW__osxScrollWheel(id self, SEL _cmd, id event) { object_getInstanceVariable(self, "RGFW_window", (void**)&win); if (win == NULL) return; - 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")); + CGFloat deltaX = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(event, sel_registerName("scrollingDeltaX")); + CGFloat deltaY = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(event, sel_registerName("scrollingDeltaY")); + + if (objc_msgSend_bool(event, sel_registerName("hasPreciseScrollingDeltas"))) { + deltaX *= (CGFloat)0.1; + deltaY *= (CGFloat)0.1; + } + + RGFW_mouseScrollCallback(win, (float)deltaX, (float)deltaY); +} - RGFW_mouseScrollCallback(win, deltaX, deltaY); +BOOL RGFW__osxCanBecomeKeyWindow(id self, SEL _cmd); +BOOL RGFW__osxCanBecomeKeyWindow(id self, SEL _cmd) { + RGFW_UNUSED(self); RGFW_UNUSED(_cmd); + return YES; +} + +BOOL RGFW__osxCanBecomeMainWindow(id self, SEL _cmd); +BOOL RGFW__osxCanBecomeMainWindow(id self, SEL _cmd) { + RGFW_UNUSED(self); RGFW_UNUSED(_cmd); + return YES; } RGFW_format RGFW_nativeFormat(void) { return RGFW_formatRGBA8; } @@ -13494,7 +14548,8 @@ void RGFW_initKeycodesPlatform(void) { _RGFW->keycodes[0x4E] = RGFW_keyPadMinus; } -i32 RGFW_initPlatform(void) { +i32 RGFW_initPlatform(const char* className, RGFW_initFlags flags) { + RGFW_UNUSED(className); RGFW_UNUSED(flags); _RGFW->tisBundle = (void*)CFBundleGetBundleWithIdentifier(CFSTR("com.apple.HIToolbox")); TISGetInputSourcePropertySrc = (PFN_TISGetInputSourceProperty)CFBundleGetFunctionPointerForName((CFBundleRef)_RGFW->tisBundle, CFSTR("TISGetInputSourceProperty")); @@ -13503,31 +14558,42 @@ i32 RGFW_initPlatform(void) { CFStringRef* cfStr = (CFStringRef*)CFBundleGetDataPointerForName((CFBundleRef)_RGFW->tisBundle, CFSTR("kTISPropertyUnicodeKeyLayoutData"));; if (cfStr) kTISPropertyUnicodeKeyLayoutDataSrc = *cfStr; - - 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*)RGFW__osxAcceptsFirstResponder, 0); - class_addMethod(objc_getClass("NSWindowClass"), sel_registerName("performKeyEquivalent:"), (IMP)(void*)RGFW__osxPerformKeyEquivalent, 0); - _RGFW->NSApp = objc_msgSend_id(objc_getClass("NSApplication"), sel_registerName("sharedApplication")); - - NSRetain(_RGFW->NSApp); + ((void (*)(id, SEL, NSUInteger))objc_msgSend) ((id)_RGFW->NSApp, sel_registerName("setActivationPolicy:"), NSApplicationActivationPolicyRegular); + /* Note about addMethod strings + * @ -> id, : -> SEL, B -> bool + * a basic char is a c-type, capital letter = unsigned, ^ = pointer + * e.g. i = int, I = unsigned int c = char, C = unsigned char and ^C = unsigned char* + * most functions start with v@: because it's `void function(id self, SEL _cmd) + */ _RGFW->customNSAppDelegateClass = objc_allocateClassPair(objc_getClass("NSObject"), "RGFWNSAppDelegate", 0); + if (_RGFW->customNSAppDelegateClass == NULL) { + RGFW_debugCallback(RGFW_typeError, RGFW_errObjcRuntime, "failed to create RGFWNSAppDelegate class"); + return -1; + } + class_addMethod((Class)_RGFW->customNSAppDelegateClass, sel_registerName("applicationDidChangeScreenParameters:"), (IMP)RGFW__osxDidChangeScreenParameters, "v@:@"); + class_addMethod((Class)_RGFW->customNSAppDelegateClass, sel_registerName("applicationShouldTerminate:"), (IMP)RGFW__osxApplicationShouldTerminate, "@:@"); objc_registerClassPair((Class)_RGFW->customNSAppDelegateClass); _RGFW->customNSAppDelegate = objc_msgSend_id(NSAlloc(_RGFW->customNSAppDelegateClass), sel_registerName("init")); objc_msgSend_void_id(_RGFW->NSApp, sel_registerName("setDelegate:"), _RGFW->customNSAppDelegate); - ((void (*)(id, SEL, NSUInteger))objc_msgSend) ((id)_RGFW->NSApp, sel_registerName("setActivationPolicy:"), NSApplicationActivationPolicyRegular); + objc_msgSend_void(_RGFW->NSApp, sel_registerName("finishLaunching")); _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}"); + if (_RGFW->customViewClasses[i] == NULL) { + RGFW_debugCallback(RGFW_typeError, RGFW_errObjcRuntime, (i == 0) ? "failed to create RGFWCustomView class" : "failed to create RGFWOpenGLCustomView class"); + return -1; + } + + RGFW_ASSERT((sizeof(RGFW_window*) <= 8)); /* some future where pointers are greater than 8 bytes (64-bit) (I'm pretty sure much more will be broken if this is the case) */ + class_addIvar((Class)_RGFW->customViewClasses[i], "RGFW_window", sizeof(RGFW_window*), (sizeof(RGFW_window*) == 8) ? 3 : 2, "^v"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("acceptsFirstMouse:"), (IMP)RGFW__osxAcceptsFirstMouse, "B@:@"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("drawRect:"), (IMP)RGFW__osxDrawRect, "v@:{CGRect={CGPoint=dd}{CGSize=dd}}"); 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@:@"); @@ -13546,27 +14612,45 @@ i32 RGFW_initPlatform(void) { 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)RGFW__osxAcceptsFirstResponder, "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("initWithRGFWWindow:"), (IMP)RGFW__osxCustomInitWithRGFWWindow, "@@:^v"); 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@:"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("draggingEntered:"), (IMP)RGFW__osxDraggingEntered, "L@:@"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("draggingUpdated:"), (IMP)RGFW__osxDraggingUpdated, "L@:@"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("draggingExited:"), (IMP)RGFW__osxDraggingEnded, "v@:@"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("draggingEnded:"), (IMP)RGFW__osxDraggingEnded, "v@:@"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("prepareForDragOperation:"), (IMP)RGFW__osxPrepareForDragOperation, "B@:@"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("performDragOperation:"), (IMP)RGFW__osxPerformDragOperation, "B@:@"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("performKeyEquivalent:"), (IMP)(void*)RGFW__osxPerformKeyEquivalent, "B@:@"); 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"); + if (_RGFW->customWindowDelegateClass == NULL) { + RGFW_debugCallback(RGFW_typeError, RGFW_errObjcRuntime, "failed to create RGFWWindowDelegate class"); + return -1; + } + + class_addIvar((Class)_RGFW->customWindowDelegateClass, "RGFW_window", sizeof(RGFW_window*), (sizeof(RGFW_window*) == 8) ? 3 : 2, "^v"); 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)RGFW__osxDraggingEntered, "l@:@"); - class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("draggingUpdated:"), (IMP)RGFW__osxDraggingUpdated, "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)RGFW__osxPrepareForDragOperation, "B@:@"); - class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("performDragOperation:"), (IMP)RGFW__osxPerformDragOperation, "B@:@"); + class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidMove:"), (IMP) RGFW__osxWindowMove, "v@:@"); + class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidMiniaturize:"), (IMP) RGFW__osxWindowMiniaturize, "v@:@"); + class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidDeminiaturize:"), (IMP) RGFW__osxWindowDeminiaturize, "v@:@"); + class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidBecomeKey:"), (IMP) RGFW__osxWindowBecameKey, "v@:@"); + class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidResignKey:"), (IMP) RGFW__osxWindowResignKey, "v@:@"); + class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowShouldClose:"), (IMP)(void*)RGFW_osxWindowShouldClose, "B@:@"); objc_registerClassPair((Class)_RGFW->customWindowDelegateClass); + + _RGFW->customWindowClass = objc_allocateClassPair(objc_getClass("NSWindow"), "RGFWWindowClass", 0); + if (_RGFW->customWindowClass== NULL) { + RGFW_debugCallback(RGFW_typeError, RGFW_errObjcRuntime, "failed to create RGFWWindowClass class"); + return -1; + } + + class_addMethod((Class)_RGFW->customWindowClass, sel_registerName("canBecomeKeyWindow"), (IMP)RGFW__osxCanBecomeKeyWindow, "B@:"); + class_addMethod((Class)_RGFW->customWindowClass, sel_registerName("canBecomeMainWindow"),(IMP)RGFW__osxCanBecomeMainWindow, "B@:"); + objc_registerClassPair((Class)_RGFW->customWindowClass); + return 0; } @@ -13613,17 +14697,19 @@ RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, windowRect.origin.y = (double)RGFW_cocoaYTransform((float)(win->y + win->h - 1)); windowRect.size.width = (double)win->w; windowRect.size.height = (double)win->h; - NSBackingStoreType macArgs = (NSBackingStoreType)(NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSBackingStoreBuffered | NSWindowStyleMaskTitled); + NSWindowStyleMask macArgs = (NSWindowStyleMask)(NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSBackingStoreBuffered); if (!(flags & RGFW_windowNoResize)) - macArgs = (NSBackingStoreType)(macArgs | (NSBackingStoreType)NSWindowStyleMaskResizable); + macArgs |= (NSWindowStyleMask)NSWindowStyleMaskResizable; if (!(flags & RGFW_windowNoBorder)) - macArgs = (NSBackingStoreType)(macArgs | (NSBackingStoreType)NSWindowStyleMaskTitled); + macArgs |= (NSWindowStyleMask)NSWindowStyleMaskTitled; + else + macArgs |= (NSWindowStyleMask)NSWindowStyleMaskBorderless; { - void* nsclass = objc_getClass("NSWindow"); + void* nsclass = objc_getClass("RGFWWindowClass"); SEL func = sel_registerName("initWithContentRect:styleMask:backing:defer:"); - win->src.window = ((id(*)(id, SEL, NSRect, NSWindowStyleMask, NSBackingStoreType, bool))objc_msgSend) + win->src.window = ((id(*)(id, SEL, NSRect, NSWindowStyleMask, NSWindowStyleMask, bool))objc_msgSend) (NSAlloc(nsclass), func, windowRect, (NSWindowStyleMask)macArgs, macArgs, false); } @@ -13635,13 +14721,6 @@ RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, objc_msgSend_void_id((id)win->src.window, sel_registerName("setDelegate:"), (id)win->src.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) { @@ -13651,46 +14730,38 @@ RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, NSColor_colorWithSRGB(0, 0, 0, 0)); } - /* Show the window */ - objc_msgSend_void_bool((id)_RGFW->NSApp, sel_registerName("activateIgnoringOtherApps:"), true); + if (flags & RGFW_windowAllowDND) { + win->internal.flags |= RGFW_windowAllowDND; + } if (_RGFW->root == NULL) { objc_msgSend_void(win->src.window, sel_registerName("makeMainWindow")); } - objc_msgSend_void(win->src.window, sel_registerName("makeKeyWindow")); - - NSRetain(win->src.window); - win->src.view = ((id(*)(id, SEL, RGFW_window*))objc_msgSend) (NSAlloc((Class)_RGFW->customViewClasses[0]), sel_registerName("initWithRGFWWindow:"), win); + + RGFW_cocoaFetchRect(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); + NSWindowStyleMask styleMask = ((NSWindowStyleMask (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_registerName("styleMask")); + if (border) { + styleMask |= (NSWindowStyleMaskTitled | NSWindowStyleMaskClosable); + styleMask &= (u32)~NSWindowStyleMaskBorderless; + } else { + styleMask |= NSWindowStyleMaskBorderless; + styleMask &= (u32)~(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable); + } - 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); + ((void (*)(id, SEL, NSWindowStyleMask))objc_msgSend)((id)win->src.window, sel_registerName("setStyleMask:"), styleMask); - offset = (double)(frame.size.height - content.size.height); - } + /* changing the style can clear the first responder */ + ((void (*)(id, SEL, id))objc_msgSend)((id)win->src.window, sel_registerName("makeFirstResponder:"), (id)win->src.view); - RGFW_window_resize(win, win->w, win->h + (i32)offset); - win->h -= (i32)offset; + RGFW_window_move(win, win->x, win->y); } RGFW_bool RGFW_getGlobalMouse(i32* x, i32* y) { @@ -13723,8 +14794,12 @@ 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); + void* date = objc_msgSend_class(objc_getClass("NSDate"), sel_registerName("distantFuture")); + if (waitMS >= 0) { + double seconds = (((double)waitMS) / ((double)1000)); + date = (void*) ((id(*)(Class, SEL, double))objc_msgSend) + (objc_getClass("NSDate"), sel_registerName("dateWithTimeIntervalSinceNow:"), seconds); + } SEL eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"); id e = (id) ((id(*)(id, SEL, NSEventMask, void*, id, bool))objc_msgSend) @@ -13734,6 +14809,15 @@ void RGFW_waitForEvent(i32 waitMS) { if (e) { ((void (*)(id, SEL, id, bool))objc_msgSend) ((id)_RGFW->NSApp, sel_registerName("postEvent:atStart:"), e, 1); + + u32 flags = (u32)((u32(*)(id, SEL))objc_msgSend)((id)e, sel_registerName("modifierFlags")); + if (flags & NSEventModifierFlagCommand) { + id window = objc_msgSend_id(_RGFW->NSApp, sel_registerName("keyWindow")); + + if (window) { + objc_msgSend_void_id((id)window, sel_registerName("sendEvent:"), e); + } + } } objc_msgSend_bool_void(eventPool, sel_registerName("drain")); @@ -13801,31 +14885,23 @@ void RGFW_pollEvents(void) { } -void RGFW_window_move(RGFW_window* win, i32 x, i32 y) { - RGFW_ASSERT(win != NULL); - +void RGFW_window_movePlatform(RGFW_window* win, i32 x, i32 y) { NSRect content = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame")); - - win->x = x; - win->y = (i32)RGFW_cocoaYTransform((float)y + (float)content.size.height - 1.0f); - - ((void(*)(id,SEL,NSPoint))objc_msgSend)((id)win->src.window, sel_registerName("setFrameOrigin:"), (NSPoint){(double)x, (double)y}); + float yFlip = RGFW_cocoaYTransform((float)y + (float)content.size.height - 1.0f); + ((void(*)(id,SEL,NSPoint))objc_msgSend)((id)win->src.window, sel_registerName("setFrameOrigin:"), (NSPoint){(double)x, (double)yFlip}); + RGFW_cocoaFetchRect(win); } -void RGFW_window_resize(RGFW_window* win, i32 w, i32 h) { - RGFW_ASSERT(win != NULL); - +void RGFW_window_resizePlatform(RGFW_window* win, i32 w, i32 h) { 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; + NSRect content = ((NSRect(*)(id, SEL, NSRect))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("contentRectForFrameRect:"), frame); + content.origin.y += content.size.height - (CGFloat)h; + content.size = (CGSize){(CGFloat)w, (CGFloat)h}; + frame = ((NSRect(*)(id, SEL, NSRect))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frameRectForContentRect:"), content); - ((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(*)(id, SEL, CGRect))objc_msgSend)((id)win->src.view, sel_registerName("setFrame:"),frame); + RGFW_cocoaFetchRect(win); } void RGFW_window_focus(RGFW_window* win) { @@ -13837,76 +14913,43 @@ void RGFW_window_focus(RGFW_window* win) { 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; - +void RGFW_window_setFullscreenPlatform(RGFW_window* win, RGFW_bool fullscreen) { if (fullscreen) { - 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_monitor_scaleToWindow(mon, win); - - RGFW_window_setBorder(win, RGFW_FALSE); - - if (mon != NULL) { - win->x = mon->x; - win->y = mon->y; - win->w = mon->mode.w; - win->h = mon->mode.h; - RGFW_window_resize(win, mon->mode.w, mon->mode.h); - RGFW_window_move(win, mon->x, mon->y); - } - ((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:"), 25); + } else { + objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGNormalWindowLevel); } - objc_msgSend_void_SEL(win->src.window, sel_registerName("toggleFullScreen:"), NULL); + NSWindowStyleMask styleMask = ((NSWindowStyleMask (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_registerName("styleMask")); - 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); + if (RGFW_BOOL(styleMask & NSWindowStyleMaskFullScreen) != fullscreen) { + objc_msgSend_void_SEL(win->src.window, sel_registerName("toggleFullScreen:"), NULL); } } -void RGFW_window_maximize(RGFW_window* win) { - RGFW_ASSERT(win != NULL); +void RGFW_window_maximizePlatform(RGFW_window* win) { if (RGFW_window_isMaximized(win)) return; - win->internal.flags |= RGFW_windowMaximize; objc_msgSend_void_SEL(win->src.window, sel_registerName("zoom:"), NULL); - RGFW_window_fetchSize(win, NULL, NULL); } -void RGFW_window_minimize(RGFW_window* win) { +void RGFW_window_minimizePlatform(RGFW_window* win) { RGFW_ASSERT(win != NULL); - objc_msgSend_void_SEL(win->src.window, sel_registerName("performMiniaturize:"), NULL); + objc_msgSend_void_SEL(win->src.window, sel_registerName("miniaturize:"), 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); + if (floating) objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGFloatingWindowLevel); + else objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGNormalWindowLevel); } void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) { - objc_msgSend_int(win->src.window, sel_registerName("setAlphaValue:"), opacity); + ((void(*)(id, SEL, CGFloat))objc_msgSend) ((id)win->src.window, sel_registerName("setAlphaValue:"), ((CGFloat)opacity) / (CGFloat)255.0); + objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), (opacity < (u8)255)); if (opacity) @@ -13914,7 +14957,7 @@ void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) { } -void RGFW_window_restore(RGFW_window* win) { +void RGFW_window_restorePlatform(RGFW_window* win) { RGFW_ASSERT(win != NULL); if (RGFW_window_isMaximized(win)) @@ -13927,7 +14970,7 @@ void RGFW_window_restore(RGFW_window* 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; + return level > kCGNormalWindowLevel; } void RGFW_window_setName(RGFW_window* win, const char* name) { @@ -14003,7 +15046,7 @@ id NSCursor_arrowStr(const char* str) { void* nclass = objc_getClass("NSCursor"); SEL func = sel_registerName(str); id mouse = (id) objc_msgSend_id(nclass, func); - NSRetain(mouse); + objc_msgSend_void((id)mouse, sel_registerName("retain")); return mouse; } @@ -14078,7 +15121,9 @@ void RGFW_freeMouse(RGFW_mouse* mouse) { } void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) { + if (RGFW_window_isMouseHidden(win) != show) return; RGFW_window_showMouseFlags(win, show); + if (show) CGDisplayShowCursor(kCGDirectMainDisplay); else CGDisplayHideCursor(kCGDirectMainDisplay); } @@ -14105,12 +15150,13 @@ 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) { +void RGFW_window_showPlatform(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_cocoaFetchRect(win); } void RGFW_window_flash(RGFW_window* win, RGFW_flashRequest request) { @@ -14196,14 +15242,17 @@ float RGFW_osx_getRefreshRate(CGDirectDisplayID display, CGDisplayModeRef mode) } void RGFW_pollMonitors(void) { - static CGDirectDisplayID displays[RGFW_MAX_MONITORS]; u32 count; - if (CGGetActiveDisplayList(RGFW_MAX_MONITORS, displays, &count) != kCGErrorSuccess) { + if (CGGetActiveDisplayList(0, NULL, &count) != kCGErrorSuccess) { + return; + } + + CGDirectDisplayID* displays = (CGDirectDisplayID*)RGFW_ALLOC(sizeof(CGDirectDisplayID) * count); + if (CGGetActiveDisplayList(count, displays, &count) != kCGErrorSuccess) { return; } - if (count > RGFW_MAX_MONITORS) count = RGFW_MAX_MONITORS; for (RGFW_monitorNode* node = _RGFW->monitors.list.head; node; node = node->next) { node->disconnected = RGFW_TRUE; @@ -14223,27 +15272,29 @@ void RGFW_pollMonitors(void) { if (node->uintNum == uintNum) break; } - if (node) { - node->screen = (void*)screen; - node->display = displays[i]; - node->disconnected = RGFW_FALSE; - if (displays[i] == primary) { - _RGFW->monitors.primary = node; - } - continue; - } - const char name[] = "MacOS\0"; RGFW_MEMCPY(monitor.name, name, 6); CGRect bounds = CGDisplayBounds(displays[i]); monitor.x = (i32)bounds.origin.x; - monitor.y = (i32)RGFW_cocoaYTransform((float)(bounds.origin.y + bounds.size.height - 1)); + monitor.y = (i32)bounds.origin.y; CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displays[i]); + + CFArrayRef allModes = CGDisplayCopyAllDisplayModes(displays[i], NULL); + CFIndex modeCount = (CFIndex)CFArrayGetCount(allModes); + + CFIndex modeIndex; + for (modeIndex = 0; modeIndex < modeCount && allModes; modeIndex++) { + CGDisplayModeRef cmode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, modeIndex); + if (cmode == mode) { + monitor.mode.src = (void*)modeIndex; + break; + } + } + monitor.mode.w = (i32)CGDisplayModeGetWidth(mode); monitor.mode.h = (i32)CGDisplayModeGetHeight(mode); - monitor.mode.src = (void*)mode; monitor.mode.red = 8; monitor.mode.green = 8; monitor.mode.blue = 8; monitor.mode.refreshRate = RGFW_osx_getRefreshRate(displays[i], mode); @@ -14262,23 +15313,42 @@ void RGFW_pollMonitors(void) { monitor.scaleX = ((((float) (ppi_width) / dpi) * 10.0f)) / 10.0f; monitor.scaleY = ((((float) (ppi_height) / dpi) * 10.0f)) / 10.0f; - node = RGFW_monitors_add(&monitor); + if (node) { + node->screen = (void*)screen; + node->display = displays[i]; + node->disconnected = RGFW_FALSE; + if (displays[i] == primary) { + _RGFW->monitors.primary = node; + } + continue; + } else { + node = RGFW_monitors_add(&monitor); - node->screen = (void*)screen; - node->uintNum = uintNum; - node->display = displays[i]; + node->allModes = allModes; + node->screen = (void*)screen; + node->uintNum = uintNum; + node->display = displays[i]; - if (displays[i] == primary) { - _RGFW->monitors.primary = node; - } + if (displays[i] == primary) { + _RGFW->monitors.primary = node; + } - RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_TRUE); + RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_TRUE); + } } + RGFW_FREE(displays); + RGFW_monitors_refresh(); } +void RGFW_monitorNode_free(RGFW_monitorNode* node) { + RGFW_ASSERT(node); + CFRelease(node->allModes); +} + RGFW_bool RGFW_monitor_getWorkarea(RGFW_monitor* monitor, i32* x, i32* y, i32* width, i32* height) { + RGFW_ASSERT(monitor != NULL); NSRect frameRect = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)monitor->node->screen, sel_registerName("visibleFrame")); if (x) *x = (i32)frameRect.origin.x; @@ -14290,6 +15360,7 @@ RGFW_bool RGFW_monitor_getWorkarea(RGFW_monitor* monitor, i32* x, i32* y, i32* w } size_t RGFW_monitor_getGammaRampPtr(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) { + RGFW_ASSERT(monitor != NULL); id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); pool = objc_msgSend_id(pool, sel_registerName("init")); @@ -14311,6 +15382,7 @@ size_t RGFW_monitor_getGammaRampPtr(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) } RGFW_bool RGFW_monitor_setGammaRamp(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) { + RGFW_ASSERT(monitor != NULL); id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); pool = objc_msgSend_id(pool, sel_registerName("init")); @@ -14332,8 +15404,9 @@ RGFW_bool RGFW_monitor_setGammaRamp(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) } size_t RGFW_monitor_getModesPtr(RGFW_monitor* mon, RGFW_monitorMode** modes) { + RGFW_ASSERT(mon != NULL); CGDirectDisplayID display = mon->node->display; - CFArrayRef allModes = CGDisplayCopyAllDisplayModes(display, NULL); + CFArrayRef allModes = mon->node->allModes; if (allModes == NULL) { return RGFW_FALSE; @@ -14350,16 +15423,19 @@ size_t RGFW_monitor_getModesPtr(RGFW_monitor* mon, RGFW_monitorMode** modes) { foundMode.h = (i32)CGDisplayModeGetHeight(cmode); foundMode.refreshRate = RGFW_osx_getRefreshRate(display, cmode); foundMode.red = 8; foundMode.green = 8; foundMode.blue = 8; - foundMode.src = (void*)cmode; + foundMode.src = (void*)i; (*modes)[i] = foundMode; } - CFRelease(allModes); return count; } RGFW_bool RGFW_monitor_setMode(RGFW_monitor* mon, RGFW_monitorMode* mode) { - if (CGDisplaySetDisplayMode(mon->node->display, (CGDisplayModeRef)mode->src, NULL) == kCGErrorSuccess) { + RGFW_ASSERT(mon != NULL); + + CGDisplayModeRef cmode = (CGDisplayModeRef)CFArrayGetValueAtIndex(mon->node->allModes, (CFIndex)mode->src); + if (CGDisplaySetDisplayMode(mon->node->display, cmode, NULL) == kCGErrorSuccess) { + mon->mode = *mode; return RGFW_TRUE; } @@ -14367,8 +15443,9 @@ RGFW_bool RGFW_monitor_setMode(RGFW_monitor* mon, RGFW_monitorMode* mode) { } RGFW_bool RGFW_monitor_requestMode(RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request) { + RGFW_ASSERT(mon != NULL); CGDirectDisplayID display = mon->node->display; - CFArrayRef allModes = CGDisplayCopyAllDisplayModes(display, NULL); + CFArrayRef allModes = mon->node->allModes; if (allModes == NULL) { return RGFW_FALSE; @@ -14385,7 +15462,7 @@ RGFW_bool RGFW_monitor_requestMode(RGFW_monitor* mon, RGFW_monitorMode* mode, RG foundMode.h = (i32)CGDisplayModeGetHeight(cmode); foundMode.refreshRate = RGFW_osx_getRefreshRate(display, cmode); foundMode.red = 8; foundMode.green = 8; foundMode.blue = 8; - foundMode.src = (void*)cmode; + foundMode.src = (void*)i; if (RGFW_monitorModeCompare(mode, &foundMode, request)) { native = cmode; @@ -14394,8 +15471,6 @@ RGFW_bool RGFW_monitor_requestMode(RGFW_monitor* mon, RGFW_monitorMode* mode, RG } } - CFRelease(allModes); - if (native) { if (CGDisplaySetDisplayMode(display, native, NULL) == kCGErrorSuccess) { return RGFW_TRUE; @@ -14428,35 +15503,60 @@ RGFW_monitor* RGFW_window_getMonitor(RGFW_window* win) { return &node->mon; } -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; +RGFW_bool RGFW_readClipboardPtr(RGFW_dataTransferType requestedType, u8* buffer, size_t capacity, RGFW_dataTransfer* data) { + RGFW_ASSERT(data != NULL); - if (str != NULL) { - if (strCapacity < clip_len) - return 0; + if (requestedType != RGFW_dataText) return RGFW_FALSE; - RGFW_MEMCPY(str, clip, clip_len); + size_t length = 0; + char* clip = (char*)NSPasteboard_stringForType(NSPasteboard_generalPasteboard(), RSGL_NSPasteboardTypeString, &length); + if (clip == NULL) return RGFW_FALSE; - str[clip_len] = '\0'; - } + data->type = RGFW_dataText; + data->length = length; - return (RGFW_ssize_t)clip_len; + if (clip[data->length - 1] != '\0') data->length += 1; + + if (buffer == NULL) return RGFW_TRUE; + if (capacity < data->length) return RGFW_FALSE; + + RGFW_MEMCPY(buffer, clip, length); + buffer[data->length - 1] = '\0'; + data->data = (const char*)buffer; + + return RGFW_TRUE; } -void RGFW_writeClipboard(const char* text, u32 textLen) { - RGFW_UNUSED(textLen); +RGFW_bool RGFW_writeClipboard(const RGFW_dataTransfer* data) { + RGFW_ASSERT(data != NULL); - NSPasteboardType array[] = { NSPasteboardTypeString, NULL }; + const char* array[] = { RSGL_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)); + bool ret = ((bool (*)(id, SEL, id, id))objc_msgSend) + (NSPasteboard_generalPasteboard(), func, NSString_stringWithUTF8String(data->data), NSString_stringWithUTF8String((const char*)RSGL_NSPasteboardTypeString)); + + return (ret == true) ? RGFW_TRUE : RGFW_FALSE; } #ifdef RGFW_OPENGL +RGFW_bool RGFW_loadGL(void) { + _RGFW->nativeGL_handle = (void*)CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); + _RGFW->glGetProcAddress = RGFW_getProcAddress_OpenGL; + return RGFW_TRUE; +} + +void RGFW_copyContext_OSX_OpenGL(RGFW_glContext* ctx, RGFW_glContext* newCtx) { + id pixelFormat = (id)objc_msgSend_id((id)ctx->ctx, sel_registerName("pixelFormat")); + id newContext = ((id (*)(id, SEL, id, id))objc_msgSend)(NSAlloc((id)objc_getClass("NSOpenGLContext")), + sel_registerName("initWithFormat:shareContext:"), + pixelFormat, (id)ctx->ctx + ); + + newCtx->ctx = newContext; +} + 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) @@ -14468,23 +15568,16 @@ void NSOpenGLContext_setValues(id context, const int* vals, NSOpenGLContextParam 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); + RGFW_proc symbol = (RGFW_proc)CFBundleGetFunctionPointerForName((CFBundleRef)_RGFW->nativeGL_handle, 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; - +RGFW_bool RGFW_createContextPtr_OpenGL(RGFW_glContext* ctx, RGFW_glHints* hints) { i32 attribs[40]; size_t render_type_index = 0; { @@ -14553,48 +15646,65 @@ RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* /* 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")), + ctx->ctx = ((id (*)(id, SEL, id, id))objc_msgSend)(NSAlloc(objc_getClass("NSOpenGLContext")), sel_registerName("initWithFormat:shareContext:"), (id)format, share); - win->src.ctx.native->format = format; + ctx->format = format; - objc_msgSend_void_id(win->src.view, sel_registerName("setOpenGLContext:"), win->src.ctx.native->ctx); - if (win->internal.flags & RGFW_windowTransparent) { + if (hints->depth == 32) { i32 opacity = 0; #define NSOpenGLCPSurfaceOpacity 236 - NSOpenGLContext_setValues((id)win->src.ctx.native->ctx, &opacity, (NSOpenGLContextParameter)NSOpenGLCPSurfaceOpacity); + NSOpenGLContext_setValues((id)ctx->ctx, &opacity, (NSOpenGLContextParameter)NSOpenGLCPSurfaceOpacity); + } + + RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized."); + return RGFW_TRUE; +} + +RGFW_bool RGFW_window_setContext_OpenGL(RGFW_window* win, RGFW_glContext* ctx) { + RGFW_ASSERT(win); + if (ctx == NULL && win->src.ctx.native != NULL) { + win->src.ctx.native = NULL; + RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL surface freed."); + return RGFW_TRUE; } - objc_msgSend_void(win->src.ctx.native->ctx, sel_registerName("makeCurrentContext")); + win->src.ctx.native = ctx; + win->src.gfxType = RGFW_gfxNativeOpenGL; + + 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*)ctx->format); + + + objc_msgSend_void_id(win->src.view, sel_registerName("setOpenGLContext:"), ctx->ctx); + + objc_msgSend_void(ctx->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_window_swapInterval_OpenGL(win, 0); + /*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); + ((void (*)(id, SEL, id))objc_msgSend)((id)win->src.window, sel_registerName("makeFirstResponder:"), (id)win->src.view); - RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized."); + RGFW_window_swapInterval_OpenGL(win, 0); + RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL surface initalized."); return RGFW_TRUE; } -void RGFW_window_deleteContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx) { +void RGFW_deleteContextPtr_OpenGL(RGFW_glContext* ctx) { objc_msgSend_void(ctx->format, sel_registerName("release")); - win->src.ctx.native->format = NULL; - objc_msgSend_void(ctx->ctx, sel_registerName("release")); - win->src.ctx.native->ctx = NULL; RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context freed."); } @@ -14609,6 +15719,12 @@ void* RGFW_getCurrentContext_OpenGL(void) { return objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("currentContext")); } +void* RGFW_getCurrentSurface_OpenGL(void) { + id ctx = (id)RGFW_getCurrentContext_OpenGL(); + if (ctx == NULL) return NULL; + return objc_msgSend_id(ctx, sel_registerName("view")); +} + 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")); @@ -14620,29 +15736,54 @@ void RGFW_window_swapInterval_OpenGL(RGFW_window* win, i32 swapInterval) { #endif void RGFW_deinitPlatform(void) { - objc_msgSend_void_id(_RGFW->NSApp, sel_registerName("setDelegate:"), NULL); + if (_RGFW->NSApp) { + objc_msgSend_void_id(_RGFW->NSApp, sel_registerName("setDelegate:"), NULL); + NSRelease(_RGFW->customNSAppDelegate); + _RGFW->customNSAppDelegate = NULL; - objc_msgSend_void_id(_RGFW->NSApp, sel_registerName("stop:"), NULL); - NSRelease(_RGFW->NSApp); - _RGFW->NSApp = NULL; + objc_msgSend_void_id(_RGFW->NSApp, sel_registerName("stop:"), NULL); + _RGFW->NSApp = NULL; + } - NSRelease(_RGFW->customNSAppDelegate); + if (_RGFW->customNSAppDelegate != NULL) + NSRelease(_RGFW->customNSAppDelegate); _RGFW->customNSAppDelegate = NULL; - objc_disposeClassPair((Class)_RGFW->customViewClasses[0]); - objc_disposeClassPair((Class)_RGFW->customViewClasses[1]); - objc_disposeClassPair((Class)_RGFW->customWindowDelegateClass); - objc_disposeClassPair((Class)_RGFW->customNSAppDelegateClass); + if (_RGFW->customViewClasses[0] != NULL) + objc_disposeClassPair((Class)_RGFW->customViewClasses[0]); + if (_RGFW->customViewClasses[0] != NULL) + objc_disposeClassPair((Class)_RGFW->customViewClasses[1]); + + if (_RGFW->customWindowDelegateClass) + objc_disposeClassPair((Class)_RGFW->customWindowDelegateClass); + + if (_RGFW->customWindowClass) { + Class kvoClass = objc_getClass("NSKVONotifying_RGFWWindowClass"); + if (kvoClass) { + objc_disposeClassPair(kvoClass); + + } + objc_disposeClassPair((Class)_RGFW->customWindowClass); + } + + if (_RGFW->customNSAppDelegateClass) + objc_disposeClassPair((Class)_RGFW->customNSAppDelegateClass); } void RGFW_window_closePlatform(RGFW_window* win) { + id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); + pool = objc_msgSend_id(pool, sel_registerName("init")); + objc_msgSend_void_id((id)win->src.window, sel_registerName("setDelegate:"), NULL); NSRelease((id)win->src.delegate); NSRelease(win->src.view); objc_msgSend_id(win->src.window, sel_registerName("close")); NSRelease(win->src.window); + + objc_msgSend_bool_void(pool, sel_registerName("drain")); + RGFW_pollEvents(); } #ifdef RGFW_VULKAN @@ -14667,7 +15808,7 @@ VkResult RGFW_window_createSurface_Vulkan(RGFW_window* win, VkInstance instance, if (metalLayer == NULL) { return -1; } - ((void (*)(id, SEL, id))objc_msgSend)((id)nsView, sel_registerName("setLayer:"), metalLayer); + ((void (*)(id, SEL, id))objc_msgSend)((id)nsView, sel_registerName("setLayer:"), (id)metalLayer); ((void (*)(id, SEL, BOOL))objc_msgSend)(nsView, sel_registerName("setWantsLayer:"), YES); VkResult result; @@ -14695,7 +15836,7 @@ VkResult RGFW_window_createSurface_Vulkan(RGFW_window* win, VkInstance instance, #ifdef RGFW_WEBGPU WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance instance) { WGPUSurfaceDescriptor surfaceDesc = {0}; - id* nsView = (id*)window->src.view; + id nsView = (id)window->src.view; if (!nsView) { RGFW_debugCallback(RGFW_typeError, RGFW_errMetal, "NSView is NULL for macOS window"); return NULL; @@ -14708,8 +15849,8 @@ WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance i if (metalLayer == NULL) { return NULL; } - ((void (*)(id, SEL, id))objc_msgSend)((id)nsView, sel_registerName("setLayer:"), metalLayer); - layer = metalLayer; + ((void (*)(id, SEL, id))objc_msgSend)((id)nsView, sel_registerName("setLayer:"), (id)metalLayer); + layer = (id)metalLayer; WGPUSurfaceSourceMetalLayer fromMetal = {0}; fromMetal.chain.sType = WGPUSType_SurfaceSourceMetalLayer; @@ -14764,7 +15905,7 @@ EM_BOOL Emscripten_on_fullscreenchange(int eventType, const EmscriptenFullscreen _RGFW->root->w = originalW; _RGFW->root->h = originalH; } else { - #if __EMSCRIPTEN_major__ >= 1 && __EMSCRIPTEN_minor__ >= 29 && __EMSCRIPTEN_tiny__ >= 0 + #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; @@ -14796,7 +15937,7 @@ EM_BOOL Emscripten_on_focusout(int eventType, const EmscriptenFocusEvent* E, voi EM_BOOL Emscripten_on_mousemove(int eventType, const EmscriptenMouseEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); - RGFW_mousePosCallback(_RGFW->root, E->targetX, E->targetY); + RGFW_mouseMotionCallback(_RGFW->root, E->targetX, E->targetY); RGFW_rawMotionCallback(_RGFW->root, E->movementX, E->movementY); return EM_TRUE; } @@ -14838,7 +15979,7 @@ EM_BOOL Emscripten_on_touchstart(int eventType, const EmscriptenTouchEvent* E, v size_t i; for (i = 0; i < (size_t)E->numTouches; i++) { - RGFW_mousePosCallback(_RGFW->root, E->touches[i].targetX, E->touches[i].targetY); + RGFW_mouseMotionCallback(_RGFW->root, E->touches[i].targetX, E->touches[i].targetY); RGFW_rawMotionCallback(_RGFW->root, 0, 0); RGFW_mouseButtonCallback(_RGFW->root, RGFW_mouseLeft, 1); } @@ -14849,11 +15990,11 @@ EM_BOOL Emscripten_on_touchstart(int eventType, const EmscriptenTouchEvent* E, v 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; + if (!(_RGFW->root->internal.enabledEvents & RGFW_mouseMotionFlag)) return EM_TRUE; size_t i; for (i = 0; i < (size_t)E->numTouches; i++) { - RGFW_mousePosCallback(_RGFW->root, E->touches[i].targetX, E->touches[i].targetY); + RGFW_mouseMotionCallback(_RGFW->root, E->touches[i].targetX, E->touches[i].targetY); RGFW_rawMotionCallback(_RGFW->root, 0, 0); } return EM_TRUE; @@ -14866,7 +16007,7 @@ EM_BOOL Emscripten_on_touchend(int eventType, const EmscriptenTouchEvent* E, voi size_t i; for (i = 0; i < (size_t)E->numTouches; i++) { - RGFW_mousePosCallback(_RGFW->root, E->touches[i].targetX, E->touches[i].targetY); + RGFW_mouseMotionCallback(_RGFW->root, E->touches[i].targetX, E->touches[i].targetY); RGFW_rawMotionCallback(_RGFW->root, 0, 0); RGFW_mouseButtonCallback(_RGFW->root, RGFW_mouseLeft, 0); } @@ -14899,6 +16040,8 @@ void EMSCRIPTEN_KEEPALIVE Emscripten_onDrop(char* file, size_t size) { RGFW_dataDropCallback(_RGFW->root, file, size, RGFW_dataFile); } +void EMSCRIPTEN_KEEPALIVE RGFW_webFree(void* ptr) { free(ptr); } + void RGFW_stopCheckEvents(void) { _RGFW->stopCheckEvents_bool = RGFW_TRUE; } @@ -15052,7 +16195,8 @@ void RGFW_initKeycodesPlatform(void) { _RGFW->keycodes[DOM_VK_F24] = RGFW_keyF24; } -i32 RGFW_initPlatform(void) { +i32 RGFW_initPlatform(const char* className, RGFW_initFlags flags) { + RGFW_UNUSED(className); RGFW_UNUSED(flags); RGFW_monitorNode* node = NULL; RGFW_monitor monitor; @@ -15119,7 +16263,7 @@ RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, } Module._RGFW_handleKeyEvent(code, codepoint, 1); - _free(code); + Module._RGFW_webFree(code); }, true); window.addEventListener("keyup", @@ -15127,7 +16271,7 @@ RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, 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(code, 0, 0); - _free(code); + Module._RGFW_webFree(code); }, true); }); @@ -15186,11 +16330,16 @@ RGFW_bool RGFW_window_fetchSize(RGFW_window* win, i32* w, i32* h) { } void RGFW_pollEvents(void) { + static int using_asyncify = -1; + if (using_asyncify == -1) using_asyncify = EM_ASM_INT({ return (typeof Asyncify !== 'undefined') || ('Asyncify' in Module); }); + RGFW_resetPrevState(); - emscripten_sleep(0); + if (using_asyncify) { + emscripten_sleep(0); + } } -void RGFW_window_resize(RGFW_window* win, i32 w, i32 h) { +void RGFW_window_resizePlatform(RGFW_window* win, i32 w, i32 h) { RGFW_UNUSED(win); emscripten_set_canvas_element_size("#canvas", w, h); } @@ -15271,27 +16420,32 @@ void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) { }, passthrough); } -void RGFW_writeClipboard(const char* text, u32 textLen) { - RGFW_UNUSED(textLen); - EM_ASM({ navigator.clipboard.writeText(UTF8ToString($0)); }, text); +RGFW_bool RGFW_writeClipboard(const RGFW_dataTransfer* data) { + RGFW_ASSERT(data != NULL); + EM_ASM({ navigator.clipboard.writeText(UTF8ToString($0)); }, data->data); + return RGFW_TRUE; } -RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) { - RGFW_UNUSED(str); RGFW_UNUSED(strCapacity); +RGFW_bool RGFW_readClipboardPtr(RGFW_dataTransferType requestedType, u8* buffer, size_t capacity, RGFW_dataTransfer* data) { + RGFW_ASSERT(data != NULL); + RGFW_UNUSED(buffer); RGFW_UNUSED(capacity); + + if (requestedType != RGFW_dataText) return RGFW_FALSE; + /* placeholder code for later I'm not sure if this is possible do the the async stuff */ - return 0; + return RGFW_FALSE; } #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; +RGFW_bool RGFW_loadGL(void) { return RGFW_TRUE; } +RGFW_bool RGFW_createContextPtr_OpenGL(RGFW_glContext* ctx, RGFW_glHints* hints) { EmscriptenWebGLContextAttributes attrs; + emscripten_webgl_init_context_attributes(&attrs); attrs.alpha = hints->alpha; attrs.depth = hints->depth; attrs.stencil = hints->stencil; @@ -15305,29 +16459,65 @@ RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* attrs.renderViaOffscreenBackBuffer = hints->auxBuffers; attrs.failIfMajorPerformanceCaveat = EM_FALSE; - attrs.majorVersion = (hints->major == 0) ? 1 : hints->major; - attrs.minorVersion = hints->minor; attrs.enableExtensionsByDefault = EM_TRUE; + + if (hints->profile == RGFW_glWeb) { + attrs.majorVersion = (hints->major == 0) ? 1 : hints->major; + attrs.minorVersion = hints->minor; + } else { + attrs.majorVersion = (hints->major == 0) ? 1 : ( (hints->major > 1) ? hints->major - 1 : hints->major ); + attrs.minorVersion = hints->minor; + } + attrs.explicitSwapControl = EM_TRUE; + ctx->ctx = emscripten_webgl_create_context("#canvas", &attrs); - 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); + if (ctx->ctx == 0) { + RGFW_debugCallback(RGFW_typeError, RGFW_warningOpenGL, "WebGL: Failed to create an OpenGL Context with explicit swap control."); + attrs.explicitSwapControl = EM_FALSE; + ctx->ctx = emscripten_webgl_create_context("#canvas", &attrs); + } + + if (ctx->ctx == 0) { + RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to create an OpenGL Context with the requested attributes, falling back to defaults."); + ctx->ctx = emscripten_webgl_create_context("#canvas", &attrs); + } + + if (ctx->ctx == 0) { + RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to create an OpenGL Context."); + return RGFW_FALSE; + } + + emscripten_webgl_make_context_current(ctx->ctx); #ifdef LEGACY_GL_EMULATION EM_ASM("Module.useWebGL = true; GLImmediate.init();"); RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized."); #endif - RGFW_window_swapInterval_OpenGL(win, 0); + return RGFW_TRUE; +} +RGFW_bool RGFW_window_setContext_OpenGL(RGFW_window* win, RGFW_glContext* ctx) { + RGFW_ASSERT(win); + if (ctx == NULL && win->src.ctx.native != NULL) { + win->src.ctx.native = NULL; + + RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL surface freed."); + return RGFW_TRUE; + } + + win->src.ctx.native = ctx; + win->src.gfxType = RGFW_gfxNativeOpenGL; + + RGFW_window_swapInterval_OpenGL(win, 0); + RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL surface initalized."); return RGFW_TRUE; } -void RGFW_window_deleteContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx) { +void RGFW_deleteContextPtr_OpenGL(RGFW_glContext* ctx) { emscripten_webgl_destroy_context(ctx->ctx); - win->src.ctx.native->ctx = 0; RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context freed."); } @@ -15344,6 +16534,7 @@ void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { emscripten_webgl_commit_frame(); } void* RGFW_getCurrentContext_OpenGL(void) { return (void*)emscripten_webgl_get_current_context(); } +void* RGFW_getCurrentSurface_OpenGL(void) { return (void*)emscripten_webgl_get_current_context(); } RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char* extension, size_t len) { return EM_ASM_INT({ @@ -15394,26 +16585,20 @@ void RGFW_window_setName(RGFW_window* win, const char* name) { emscripten_set_window_title(name); } -void RGFW_window_maximize(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - +void RGFW_window_maximizePlatform(RGFW_window* win) { RGFW_monitor* mon = RGFW_window_getMonitor(win); if (mon != NULL) { RGFW_window_resize(win, mon->mode.w, mon->mode.h); } RGFW_window_move(win, 0, 0); - RGFW_window_fetchSize(win, NULL, NULL); } -void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) { - RGFW_ASSERT(win != NULL); +void RGFW_window_setFullscreenPlatform(RGFW_window* win, RGFW_bool fullscreen) { 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); ); } @@ -15462,6 +16647,7 @@ RGFW_key RGFW_WASMPhysicalToRGFW(u32 hash) { case 0x2C595B54U /* KeyT */: return RGFW_keyT; /* 0x0014 */ case 0x2C595B59U /* KeyY */: return RGFW_keyY; /* 0x0015 */ case 0x2C595B55U /* KeyU */: return RGFW_keyU; /* 0x0016 */ + case 0x2C595B49U /* KeyI */: return RGFW_keyI; /* 0x0017 */ case 0x2C595B4FU /* KeyO */: return RGFW_keyO; /* 0x0018 */ case 0x2C595B50U /* KeyP */: return RGFW_keyP; /* 0x0019 */ case 0x45D8158CU /* BracketLeft */: return RGFW_keyCloseBracket; /* 0x001A */ @@ -15507,7 +16693,7 @@ RGFW_key RGFW_WASMPhysicalToRGFW(u32 hash) { case 0x7174B780U /* F8 */: return RGFW_keyF8; /* 0x0042 */ case 0x7174B781U /* F9 */: return RGFW_keyF9; /* 0x0043 */ case 0x7B8E57B0U /* F10 */: return RGFW_keyF10; /* 0x0044 */ - case 0xC925FCDFU /* Numpad7 */: return RGFW_keyPadMultiply; /* 0x0047 */ + case 0xC925FCDFU /* Numpad7 */: return RGFW_key7; /* 0x0047 */ case 0xC925FCD0U /* Numpad8 */: return RGFW_keyPad8; /* 0x0048 */ case 0xC925FCD1U /* Numpad9 */: return RGFW_keyPad9; /* 0x0049 */ case 0x5EA3E8A4U /* NumpadSubtract */: return RGFW_keyMinus; /* 0x004A */ @@ -15521,17 +16707,17 @@ RGFW_key RGFW_WASMPhysicalToRGFW(u32 hash) { case 0x95852DACU /* NumpadDecimal */: return RGFW_keyPeriod; /* 0x0053 */ case 0x7B8E57B1U /* F11 */: return RGFW_keyF11; /* 0x0057 */ case 0x7B8E57B2U /* F12 */: return RGFW_keyF12; /* 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 0x7B8E57B3U /* F13 */: return RGFW_keyF13; /* 0x0064 */ + case 0x7B8E57B4U /* F14 */: return RGFW_keyF14; /* 0x0065 */ + case 0x7B8E57B5U /* F15 */: return RGFW_keyF15; /* 0x0066 */ + case 0x7B8E57B6U /* F16 */: return RGFW_keyF16; /* 0x0067 */ + case 0x7B8E57B7U /* F17 */: return RGFW_keyF17; /* 0x0068 */ + case 0x7B8E57B8U /* F18 */: return RGFW_keyF18; /* 0x0069 */ + case 0x7B8E57B9U /* F19 */: return RGFW_keyF19; /* 0x006A */ + case 0x7B8E57A8U /* F20 */: return RGFW_keyF20; /* 0x006B */ + case 0x7B8E57A9U /* F21 */: return RGFW_keyF21; /* 0x006C */ + case 0x7B8E57AAU /* F22 */: return RGFW_keyF22; /* 0x006D */ + case 0x7B8E57ABU /* F23 */: return RGFW_keyF23; /* 0x006E */ case 0x7393FBACU /* NumpadEqual */: return RGFW_keyPadReturn; case 0xB88EBF7CU /* AltRight */: return RGFW_keyAltR; /* 0xE038 */ case 0xC925873BU /* NumLock */: return RGFW_keyNumLock; /* 0xE045 */ @@ -15547,7 +16733,13 @@ RGFW_key RGFW_WASMPhysicalToRGFW(u32 hash) { case 0x6725C50DU /* Delete */: return RGFW_keyDelete; /* 0xE053 */ case 0x6723658CU /* OSLeft */: return RGFW_keySuperL; /* 0xE05B */ case 0x39643F7CU /* MetaRight */: return RGFW_keySuperR; /* 0xE05C */ - case 0x380B9C8CU /* NumpadAdd */: return DOM_PK_NUMPAD_ADD; /* 0x004E */ + case 0x380B9C8CU /* NumpadAdd */: return RGFW_keyPadPlus; /* 0x004E */ + case 0x92E08B35U /* Pause */: return RGFW_keyPause; /* 0x0045 */ + case 0xCC1E198EU /* PrintScreen */: return RGFW_keyPrintScreen; /* 0x0054 */ + case 0xCDED173BU /* ScrollLock */: return RGFW_keyScrollLock; /* 0x0046 */ + case 0x7393C5D2U /* NumpadEnter */: return RGFW_keyPadReturn; /* 0xE01C */ + case 0xE00E97CDU /* ContextMenu */: return RGFW_keyMenu; /* 0xE05D */ + case 0x6CB5328DU /* NumpadDivide */: return RGFW_keyPadSlash; /* 0xE035 */ default: return DOM_PK_UNKNOWN; } @@ -15561,6 +16753,7 @@ RGFW_monitor* RGFW_window_getMonitor(RGFW_window* win) { /* unsupported functions */ void RGFW_pollMonitors(void) { } +void RGFW_monitorNode_free(RGFW_monitorNode* node) { RGFW_UNUSED(node); } 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; } @@ -15569,17 +16762,17 @@ size_t RGFW_monitor_getGammaRampPtr(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) RGFW_bool RGFW_monitor_setGammaRamp(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) { RGFW_UNUSED(monitor); RGFW_UNUSED(ramp); return RGFW_FALSE; } size_t RGFW_monitor_getModesPtr(RGFW_monitor* mon, RGFW_monitorMode** modes) { RGFW_UNUSED(mon); RGFW_UNUSED(modes); return 0; } RGFW_bool RGFW_monitor_setMode(RGFW_monitor* mon, RGFW_monitorMode* mode) { RGFW_UNUSED(mon); RGFW_UNUSED(mode); return RGFW_FALSE; } -void RGFW_window_move(RGFW_window* win, i32 x, i32 y) { RGFW_UNUSED(win); RGFW_UNUSED(x); RGFW_UNUSED(y); } +void RGFW_window_movePlatform(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_minimizePlatform(RGFW_window* win) { RGFW_UNUSED(win); } +void RGFW_window_restorePlatform(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); } +void RGFW_window_showPlatform(RGFW_window* win) {RGFW_UNUSED(win); } void RGFW_window_flash(RGFW_window* win, RGFW_flashRequest request) { RGFW_UNUSED(win); RGFW_UNUSED(request); } 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; } @@ -15600,6 +16793,7 @@ typedef RGFW_key (*RGFW_physicalToMappedKey_ptr)(RGFW_key key); typedef void (*RGFW_pollEvents_ptr)(void); typedef RGFW_bool (*RGFW_window_fetchSize_ptr)(RGFW_window* win, i32* w, i32* h); typedef void (*RGFW_pollMonitors_ptr)(void); +typedef void (*RGFW_monitorNode_free_ptr)(RGFW_monitorNode* node); 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); @@ -15608,7 +16802,7 @@ 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_setFullscreenPlatform_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); @@ -15624,8 +16818,8 @@ typedef void (*RGFW_window_moveMouse_ptr)(RGFW_window* win, i32 x, i32 y); typedef void (*RGFW_window_hide_ptr)(RGFW_window* win); typedef void (*RGFW_window_show_ptr)(RGFW_window* win); typedef void (*RGFW_window_flash_ptr)(RGFW_window* win, RGFW_flashRequest request); -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_readClipboardPtr_ptr)(RGFW_dataTransferType requestedType, u8* buffer, size_t capacity, RGFW_dataTransfer* data); +typedef RGFW_bool (*RGFW_writeClipboard_ptr)(const RGFW_dataTransfer* data); 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); @@ -15648,12 +16842,14 @@ typedef void (*RGFW_window_setRawMouseModePlatform_ptr)(RGFW_window* win, RGFW_b #ifdef RGFW_OPENGL typedef void (*RGFW_window_makeCurrentContext_OpenGL_ptr)(RGFW_window* win); typedef void* (*RGFW_getCurrentContext_OpenGL_ptr)(void); +typedef void* (*RGFW_getCurrentSurface_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); +typedef RGFW_bool (*RGFW_createContextPtr_OpenGL_ptr)(RGFW_glContext* ctx, RGFW_glHints* hints); +typedef RGFW_bool (*RGFW_window_setContext_OpenGL_ptr)(RGFW_window* win, RGFW_glContext* ctx); +typedef void (*RGFW_deleteContextPtr_OpenGL_ptr)(RGFW_glContext* ctx); #endif #ifdef RGFW_WEBGPU typedef WGPUSurface (*RGFW_window_createSurface_WebGPU_ptr)(RGFW_window* window, WGPUInstance instance); @@ -15675,25 +16871,26 @@ typedef struct RGFW_FunctionPointers { RGFW_window_fetchSize_ptr window_fetchSize; RGFW_pollEvents_ptr pollEvents; RGFW_pollMonitors_ptr pollMonitors; - RGFW_window_move_ptr window_move; - RGFW_window_resize_ptr window_resize; + RGFW_monitorNode_free_ptr monitorNode_free; + RGFW_window_move_ptr window_movePlatform; + RGFW_window_resize_ptr window_resizePlatform; 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_maximize_ptr window_maximizePlatform; RGFW_window_focus_ptr window_focus; RGFW_window_raise_ptr window_raise; - RGFW_window_setFullscreen_ptr window_setFullscreen; + RGFW_window_setFullscreenPlatform_ptr window_setFullscreenPlatform; 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_minimize_ptr window_minimizePlatform; + RGFW_window_restore_ptr window_restorePlatform; 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_createMouse_ptr loadMouse; - RGFW_createMouseStandard_ptr loadMouseStandard; + RGFW_createMouse_ptr createMouse; + RGFW_createMouseStandard_ptr createMouseStandard; RGFW_window_setMousePlatform_ptr window_setMousePlatform; RGFW_window_moveMouse_ptr window_moveMouse; RGFW_window_hide_ptr window_hide; @@ -15715,10 +16912,12 @@ typedef struct RGFW_FunctionPointers { #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_createContextPtr_OpenGL_ptr createContextPtr_OpenGL; + RGFW_window_setContext_OpenGL_ptr window_setContext_OpenGL; + RGFW_deleteContextPtr_OpenGL_ptr deleteContextPtr_OpenGL; RGFW_window_makeCurrentContext_OpenGL_ptr window_makeCurrentContext_OpenGL; RGFW_getCurrentContext_OpenGL_ptr getCurrentContext_OpenGL; + RGFW_getCurrentSurface_OpenGL_ptr getCurrentSurface_OpenGL; RGFW_window_swapBuffers_OpenGL_ptr window_swapBuffers_OpenGL; RGFW_window_swapInterval_OpenGL_ptr window_swapInterval_OpenGL; #endif @@ -15737,25 +16936,26 @@ void RGFW_window_blitSurface(RGFW_window* win, RGFW_surface* surface) { RGFW_api void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { RGFW_api.window_setBorder(win, border); } void RGFW_window_captureMousePlatform(RGFW_window* win, RGFW_bool state) { RGFW_api.window_captureMousePlatform(win, state); } void RGFW_window_setRawMouseModePlatform(RGFW_window* win, RGFW_bool state) { RGFW_api.window_setRawMouseModePlatform(win, state); } -RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win) { RGFW_init(); return RGFW_api.createWindowPlatform(name, flags, win); } +RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win) { return RGFW_api.createWindowPlatform(name, flags, win); } RGFW_bool RGFW_getGlobalMouse(i32* x, i32* y) { return RGFW_api.getGlobalMouse(x, y); } RGFW_key RGFW_physicalToMappedKey(RGFW_key key) { return RGFW_api.physicalToMappedKey(key); } void RGFW_pollEvents(void) { RGFW_api.pollEvents(); } RGFW_bool RGFW_window_fetchSize(RGFW_window* win, i32* w, i32* h) { return RGFW_api.window_fetchSize(win, w, h); } void RGFW_pollMonitors(void) { RGFW_api.pollMonitors(); } -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_monitorNode_free(RGFW_monitorNode* node) { RGFW_api.monitorNode_free(node); } +void RGFW_window_movePlatform(RGFW_window* win, i32 x, i32 y) { RGFW_api.window_movePlatform(win, x, y); } +void RGFW_window_resizePlatform(RGFW_window* win, i32 w, i32 h) { RGFW_api.window_resizePlatform(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_maximizePlatform(RGFW_window* win) { RGFW_api.window_maximizePlatform(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_setFullscreenPlatform(RGFW_window* win, RGFW_bool fullscreen) { RGFW_api.window_setFullscreenPlatform(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); } +void RGFW_window_minimizePlatform(RGFW_window* win) { RGFW_api.window_minimizePlatform(win); } +void RGFW_window_restorePlatform(RGFW_window* win) { RGFW_api.window_restorePlatform(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); } @@ -15764,15 +16964,15 @@ void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool 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_createMouse(u8* data, i32 w, i32 h, RGFW_format format) { return RGFW_api.loadMouse(data, w, h, format); } -RGFW_mouse* RGFW_createMouseStandard(RGFW_mouseIcon icon) { return RGFW_api.loadMouseStandard(icon); } +RGFW_mouse* RGFW_createMouse(u8* data, i32 w, i32 h, RGFW_format format) { return RGFW_api.createMouse(data, w, h, format); } +RGFW_mouse* RGFW_createMouseStandard(RGFW_mouseIcon icon) { return RGFW_api.createMouseStandard(icon); } RGFW_bool RGFW_window_setMousePlatform(RGFW_window* win, RGFW_mouse* mouse) { return RGFW_api.window_setMousePlatform(win, mouse); } void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y) { RGFW_api.window_moveMouse(win, x, y); } void RGFW_window_hide(RGFW_window* win) { RGFW_api.window_hide(win); } -void RGFW_window_show(RGFW_window* win) { RGFW_api.window_show(win); } +void RGFW_window_showPlatform(RGFW_window* win) { RGFW_api.window_show(win); } void RGFW_window_flash(RGFW_window* win, RGFW_flashRequest request) { RGFW_api.window_flash(win, request); } -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_readClipboardPtr(RGFW_dataTransferType requestedType, u8* buffer, size_t capacity, RGFW_dataTransfer* data) { return RGFW_api.readClipboardPtr(requestedType, buffer, capacity, data); } +RGFW_bool RGFW_writeClipboard(const RGFW_dataTransfer* data) { return RGFW_api.writeClipboard(data); } 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); } @@ -15788,10 +16988,12 @@ void RGFW_window_closePlatform(RGFW_window* win) { RGFW_api.window_closePlatform #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); } +RGFW_bool RGFW_createContextPtr_OpenGL(RGFW_glContext* ctx, RGFW_glHints* hints) { return RGFW_api.createContextPtr_OpenGL(ctx, hints); } +RGFW_bool RGFW_window_setContext_OpenGL(RGFW_window* win, RGFW_glContext* ctx) { return RGFW_api.window_setContext_OpenGL(win, ctx); } +void RGFW_deleteContextPtr_OpenGL(RGFW_glContext* ctx) { RGFW_api.deleteContextPtr_OpenGL(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_getCurrentSurface_OpenGL(void) { return RGFW_api.getCurrentSurface_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 @@ -15807,6 +17009,8 @@ WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance i * falling back to x11 if wayland fails to initalize */ #if defined(RGFW_WAYLAND) && defined(RGFW_X11) +RGFW_bool RGFW_usingWayland(void) { return _RGFW->useWaylandBool; } + void RGFW_load_X11(void) { RGFW_api.nativeFormat = RGFW_nativeFormat_X11; RGFW_api.createSurfacePtr = RGFW_createSurfacePtr_X11; @@ -15822,30 +17026,31 @@ void RGFW_load_X11(void) { RGFW_api.pollEvents = RGFW_pollEvents_X11; RGFW_api.window_fetchSize = RGFW_window_fetchSize_X11; RGFW_api.pollMonitors = RGFW_pollMonitors_X11; - RGFW_api.window_move = RGFW_window_move_X11; - RGFW_api.window_resize = RGFW_window_resize_X11; + RGFW_api.window_movePlatform = RGFW_window_movePlatform_X11; + RGFW_api.window_resizePlatform = RGFW_window_resizePlatform_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_maximizePlatform = RGFW_window_maximizePlatform_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_setFullscreenPlatform = RGFW_window_setFullscreenPlatform_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_minimizePlatform = RGFW_window_minimizePlatform_X11; + RGFW_api.window_restorePlatform = RGFW_window_restorePlatform_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_createMouse_X11; + RGFW_api.createMouse = RGFW_createMouse_X11; + RGFW_api.createMouseStandard = RGFW_createMouseStandard_X11; RGFW_api.window_setMousePlatform = RGFW_window_setMousePlatform_X11; RGFW_api.window_moveMouse = RGFW_window_moveMouse_X11; RGFW_api.window_hide = RGFW_window_hide_X11; - RGFW_api.window_show = RGFW_window_show_X11; + RGFW_api.window_show = RGFW_window_showPlatform_X11; RGFW_api.window_flash = RGFW_window_flash_X11; RGFW_api.readClipboardPtr = RGFW_readClipboardPtr_X11; RGFW_api.writeClipboard = RGFW_writeClipboard_X11; @@ -15856,17 +17061,40 @@ void RGFW_load_X11(void) { RGFW_api.monitor_getModesPtr = RGFW_monitor_getModesPtr_X11; RGFW_api.monitor_setGammaRamp = RGFW_monitor_setGammaRamp_X11; RGFW_api.monitor_getGammaRampPtr = RGFW_monitor_getGammaRampPtr_X11; - RGFW_api.monitor_setMode = RGFW_monitor_setMode_X11; + RGFW_api.window_setRawMouseModePlatform = RGFW_window_setRawMouseModePlatform_Wayland; + RGFW_api.createWindowPlatform = RGFW_createWindowPlatform_Wayland; + RGFW_api.getGlobalMouse = RGFW_getGlobalMouse_Wayland; + RGFW_api.physicalToMappedKey = RGFW_physicalToMappedKey_Wayland; + RGFW_api.pollEvents = RGFW_pollEvents_Wayland; + RGFW_api.window_fetchSize = RGFW_window_fetchSize_Wayland; + RGFW_api.pollMonitors = RGFW_pollMonitors_Wayland; + RGFW_api.window_movePlatform = RGFW_window_movePlatform_Wayland; + RGFW_api.window_resizePlatform = RGFW_window_resizePlatform_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_maximizePlatform = RGFW_window_maximizePlatform_Wayland; + RGFW_api.window_focus = RGFW_window_focus_Wayland; + RGFW_api.window_raise = RGFW_window_raise_Wayland; + RGFW_api.window_setFullscreenPlatform = RGFW_window_setFullscreenPlatform_Wayland; + RGFW_api.window_setFloating = RGFW_window_setFloating_Wayland; + RGFW_api.window_setOpacity = RGFW_window_setOpacity_Wayland; + RGFW_api.window_minimizePlatform = RGFW_window_minimizePlatform_Wayland; + RGFW_api.window_restorePlatform = RGFW_window_restorePlatform_Wayland; + RGFW_api.window_isFloating = RGFW_window_isFloating_Wayland; + RGFW_api.window_setName = RGFW_window_setName_Wayland;RGFW_api.monitor_setMode = RGFW_monitor_setMode_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.createContextPtr_OpenGL = RGFW_createContextPtr_OpenGL_X11; + RGFW_api.deleteContextPtr_OpenGL = RGFW_deleteContextPtr_OpenGL_X11; RGFW_api.window_makeCurrentContext_OpenGL = RGFW_window_makeCurrentContext_OpenGL_X11; RGFW_api.getCurrentContext_OpenGL = RGFW_getCurrentContext_OpenGL_X11; + RGFW_api.getCurrentSurface_OpenGL = RGFW_getCurrentSurface_OpenGL_X11; RGFW_api.window_swapBuffers_OpenGL = RGFW_window_swapBuffers_OpenGL_X11; + RGFW_api.window_setContext_OpenGL = RGFW_window_setContext_OpenGL_X11; RGFW_api.window_swapInterval_OpenGL = RGFW_window_swapInterval_OpenGL_X11; #endif #ifdef RGFW_WEBGPU @@ -15882,37 +17110,16 @@ void RGFW_load_Wayland(void) { RGFW_api.freeMouse = RGFW_freeMouse_Wayland; RGFW_api.window_setBorder = RGFW_window_setBorder_Wayland; RGFW_api.window_captureMousePlatform = RGFW_window_captureMousePlatform_Wayland; - RGFW_api.window_setRawMouseModePlatform = RGFW_window_setRawMouseModePlatform_Wayland; - RGFW_api.createWindowPlatform = RGFW_createWindowPlatform_Wayland; - RGFW_api.getGlobalMouse = RGFW_getGlobalMouse_Wayland; - RGFW_api.physicalToMappedKey = RGFW_physicalToMappedKey_Wayland; - RGFW_api.pollEvents = RGFW_pollEvents_Wayland; - RGFW_api.window_fetchSize = RGFW_window_fetchSize_Wayland; - RGFW_api.pollMonitors = RGFW_pollMonitors_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_createMouse_Wayland; + RGFW_api.createMouse = RGFW_createMouse_Wayland; + RGFW_api.createMouseStandard = RGFW_createMouseStandard_Wayland; RGFW_api.window_setMousePlatform = RGFW_window_setMousePlatform_Wayland; RGFW_api.window_moveMouse = RGFW_window_moveMouse_Wayland; RGFW_api.window_hide = RGFW_window_hide_Wayland; - RGFW_api.window_show = RGFW_window_show_Wayland; + RGFW_api.window_show = RGFW_window_showPlatform_Wayland; RGFW_api.window_flash = RGFW_window_flash_X11; RGFW_api.readClipboardPtr = RGFW_readClipboardPtr_Wayland; RGFW_api.writeClipboard = RGFW_writeClipboard_Wayland; @@ -15929,10 +17136,12 @@ void RGFW_load_Wayland(void) { #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.createContextPtr_OpenGL = RGFW_createContextPtr_OpenGL_Wayland; + RGFW_api.deleteContextPtr_OpenGL = RGFW_deleteContextPtr_OpenGL_Wayland; RGFW_api.window_makeCurrentContext_OpenGL = RGFW_window_makeCurrentContext_OpenGL_Wayland; RGFW_api.getCurrentContext_OpenGL = RGFW_getCurrentContext_OpenGL_Wayland; + RGFW_api.getCurrentSurface_OpenGL = RGFW_getCurrentSurface_OpenGL_Wayland; + RGFW_api.window_setContext_OpenGL = RGFW_window_setContext_OpenGL_Wayland; RGFW_api.window_swapBuffers_OpenGL = RGFW_window_swapBuffers_OpenGL_Wayland; RGFW_api.window_swapInterval_OpenGL = RGFW_window_swapInterval_OpenGL_Wayland; #endif |
