From c34ef3543302fea1b59905467ce25ead39d58387 Mon Sep 17 00:00:00 2001 From: Colleague Riley Date: Fri, 21 Feb 2025 06:32:09 -0500 Subject: [PATCH] Update RGFW and ensure it's consistent with the GLFW backend (#4783) * add PLATFORM_WEB_RGFW * fix some bugs * fix web_rgfw gamepad * send fake screensize * fix gamepad bugs (linux) | add L3 + R3 (gamepad) * fix? * update RGFW (again) * update raylib (merge) * fix xinput stuff * delete makefile added by mistake * update RGFW * update RGFW (rename joystick to gamepad to avoid misunderstandings * update RGFW (fix X11 bug) * update RGFW * use RL_MALLOC for RGFW * update RGFW (fixes xdnd bug) * fix some formating * Update RGFW * update RGFW * undo change * undo change * undo change * undo change * have .scroll be 0 by default * update RGFW * update RGFW * update RGFW * fix year * fix wasm key event bug * update RGFW * link to IOKit * update --- examples/Makefile | 2 +- src/Makefile | 2 +- src/external/RGFW.h | 3865 +++++++++++++++------------- src/platforms/rcore_desktop_rgfw.c | 208 +- 4 files changed, 2290 insertions(+), 1787 deletions(-) diff --git a/examples/Makefile b/examples/Makefile index 0a2c908a3..717486803 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -477,7 +477,7 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_RGFW) # NOTE: Required packages: libegl1-mesa-dev LDFLAGS += -L../src LDLIBS = -lraylib -lm - LDLIBS += -framework Foundation -framework AppKit -framework OpenGL -framework CoreVideo + LDLIBS += -framework Foundation -framework AppKit -framework IOKit -framework OpenGL -framework CoreVideo endif endif ifeq ($(TARGET_PLATFORM),PLATFORM_DRM) diff --git a/src/Makefile b/src/Makefile index 1b7562da4..c29eedc6b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -619,7 +619,7 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_RGFW) ifeq ($(PLATFORM_OS),OSX) # Libraries for Debian MacOS desktop compiling # NOTE: Required packages: libegl1-mesa-dev - LDLIBS += -lm -framework Foundation -framework AppKit -framework OpenGL -framework CoreVideo + LDLIBS += -lm -framework Foundation -framework AppKit -framework IOKit -framework OpenGL -framework CoreVideo endif endif ifeq ($(TARGET_PLATFORM),PLATFORM_DRM) diff --git a/src/external/RGFW.h b/src/external/RGFW.h index d4ec7d77f..ee8b163fe 100644 --- a/src/external/RGFW.h +++ b/src/external/RGFW.h @@ -1,6 +1,6 @@ /* * -* RGFW 1.5.1-dev +* RGFW 1.6-dev * * Copyright (C) 2022-25 ColleagueRiley * @@ -57,18 +57,20 @@ #define RGFW_NO_UNIX_CLOCK (optional) (unux) don't link unix clock functions #define RGFW_NO_DWM (windows only) - Do not use or linj dwmapi #define RGFW_USE_XDL (optional) (X11) use X11 in RGFW (must include XDL.h along with RGFW) (XLib Dynamic Loader) + #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 (cocoa) #define RGFW_NO_DPI - Do not include calculate DPI (no XRM nor libShcore included) - #define RGFW_ALLOC_DROPFILES (optional) if room should be allocating for drop files (by default it's global data) - #define RGFW_alloc(userptr, size) x - choose what default function to use to allocate, by default the standard malloc is used - #define RGFW_free(userptr, ptr) x - choose what default function to use to allocated memory, by default the standard free is used + #define RGFW_ALLOC x - choose what default function to use to allocate, by default the standard malloc is used + #define RGFW_FREE x - choose what default function to use to allocated memory, by default the standard free is used #define RGFW_USERPTR x - choose the default userptr sent to the malloc call, (NULL by default) #define RGFW_EXPORT - Use when building RGFW #define RGFW_IMPORT - Use when linking with RGFW (not as a single-header) #define RGFW_USE_INT - force the use c-types rather than stdint.h (for systems that might not have stdint.h (msvc)) + #define RGFW_bool x - choose what type to use for bool, by default u32 is used */ /* @@ -76,7 +78,7 @@ Example to get you started : linux : gcc main.c -lX11 -lXrandr -lGL windows : gcc main.c -lopengl32 -lgdi32 -macos : gcc main.c -framework Cocoa -framework OpenGL -framework IOKit +macos : gcc main.c -framework Cocoa -framework CoreVideo -framework OpenGL -framework IOKit #define RGFW_IMPLEMENTATION #include "RGFW.h" @@ -130,7 +132,7 @@ int main() { linux: gcc -shared RGFW.o -lX11 -lGL -lXrandr -o RGFW.so macos: - gcc -shared RGFW.o -framework Cocoa -framework OpenGL -framework IOKit + gcc -shared RGFW.o -framework CoreVideo -framework Cocoa -framework OpenGL -framework IOKit */ @@ -185,8 +187,8 @@ int main() { #define __USE_POSIX199309 #endif - #define RGFW_ALLOC(userptr, size) (RGFW_UNUSED(userptr),malloc(size)) - #define RGFW_FREE(userptr, ptr) (RGFW_UNUSED(userptr),free(ptr)) + #define RGFW_ALLOC malloc + #define RGFW_FREE free #endif #ifndef RGFW_MEMCPY @@ -253,6 +255,7 @@ int main() { #define RGFW_HEADER +#include #if !defined(u8) #ifdef RGFW_USE_INT /* optional for any system that might not have stdint.h */ typedef unsigned char u8; @@ -265,7 +268,6 @@ int main() { typedef signed long long i64; #else /* use stdint standard types instead of c ""standard"" types */ #include - #include typedef uint8_t u8; typedef int8_t i8; @@ -279,20 +281,20 @@ int main() { #define u8 u8 #endif -#if !defined(b8) /* RGFW bool type */ - typedef u8 b8; - typedef u32 b32; - #define b8 b8 +#if !defined(RGFW_bool) /* RGFW bool type */ + typedef u32 RGFW_bool; + #define RGFW_bool u8 #endif -#define RGFW_TRUE (!(0)) +#define RGFW_BOOL(x) ((x) ? RGFW_TRUE : RGFW_FALSE) /* force an value to be 0 or 1 */ +#define RGFW_TRUE 1 #define RGFW_FALSE 0 /* thse OS macros looks better & are standardized */ /* plus it helps with cross-compiling */ #ifdef __EMSCRIPTEN__ - #define RGFW_WEBASM + #define RGFW_WASM #if !defined(RGFW_NO_API) && !defined(RGFW_WEBGPU) #define RGFW_OPENGL @@ -316,7 +318,7 @@ int main() { #undef __APPLE__ #endif -#if defined(_WIN32) && !defined(RGFW_UNIX) && !defined(RGFW_WEBASM) && !defined(RGFW_CUSTOM_BACKEND) /* (if you're using X11 on windows some how) */ +#if defined(_WIN32) && !defined(RGFW_UNIX) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND) /* (if you're using X11 on windows some how) */ #define RGFW_WINDOWS /* make sure the correct architecture is defined */ #if defined(_WIN64) @@ -336,19 +338,6 @@ int main() { #include #endif #endif - - #if defined(RGFW_DIRECTX) - #define OEMRESOURCE - #include - #include - #include - #include - - #ifndef __cplusplus - #define __uuidof(T) IID_##T - #endif - #endif - #elif defined(RGFW_WAYLAND) #define RGFW_DEBUG // wayland will be in debug mode by default for now #if !defined(RGFW_NO_API) && (!defined(RGFW_BUFFER) || defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) @@ -360,12 +349,12 @@ int main() { #include #endif -#if !defined(RGFW_NO_X11) && !defined(RGFW_NO_X11) && (defined(__unix__) || defined(RGFW_MACOS_X11) || defined(RGFW_X11)) && !defined(RGFW_WEBASM) && !defined(RGFW_CUSTOM_BACKEND) +#if !defined(RGFW_NO_X11) && !defined(RGFW_NO_X11) && (defined(__unix__) || defined(RGFW_MACOS_X11) || defined(RGFW_X11)) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND) #define RGFW_MACOS_X11 #define RGFW_X11 #define RGFW_UNIX #include -#elif defined(__APPLE__) && !defined(RGFW_MACOS_X11) && !defined(RGFW_X11) && !defined(RGFW_WEBASM) && !defined(RGFW_CUSTOM_BACKEND) +#elif defined(__APPLE__) && !defined(RGFW_MACOS_X11) && !defined(RGFW_X11) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND) #define RGFW_MACOS #endif @@ -401,33 +390,17 @@ int main() { #include /* GLX defs, xlib.h, gl.h */ #endif +#define RGFW_COCOA_FRAME_NAME NULL + /*! (unix) Toggle use of wayland, this will be on by default if you use `RGFW_WAYLAND` (if you don't use RGFW_WAYLAND, you dont' expose WAYLAND functions) this is mostly used to allow you to force the use of XWayland */ -RGFWDEF void RGFW_useWayland(b8 wayland); - -/* - RGFW_allocator (optional) - you can ignore this if you use standard malloc/free -*/ -typedef void* (* RGFW_allocatorMallocfunc)(void* userdata, size_t size); -typedef void (* RGFW_allocatorFreefunc)(void* userdata, void* ptr); - -typedef struct RGFW_allocator { - void* userdata; - RGFW_allocatorMallocfunc alloc; - RGFW_allocatorFreefunc free; -} RGFW_allocator; - -RGFWDEF RGFW_allocator RGFW_loadAllocator(RGFW_allocator allocator); -RGFWDEF void* RGFW_alloc(size_t len); -RGFWDEF void RGFW_free(void* ptr); - +RGFWDEF void RGFW_useWayland(RGFW_bool wayland); /* regular RGFW stuff */ -typedef u8 RGFW_key; +#define RGFW_key u8 typedef RGFW_ENUM(u8, RGFW_eventType) { /*! event codes */ @@ -466,7 +439,7 @@ typedef RGFW_ENUM(u8, RGFW_eventType) { RGFW_event.axisesCount says how many axis there are */ RGFW_windowMoved, /*!< the window was moved (b the user) */ - RGFW_windowResized, /*!< the window was resized (by the user), [on webASM this means the browser was resized] */ + RGFW_windowResized, /*!< the window was resized (by the user), [on WASM this means the browser was resized] */ RGFW_focusIn, /*!< window is in focus now */ RGFW_focusOut, /*!< window is out of focus now */ RGFW_mouseEnter, /* mouse entered the window */ @@ -492,12 +465,13 @@ typedef RGFW_ENUM(u8, RGFW_eventType) { /*! mouse button codes (RGFW_event.button) */ typedef RGFW_ENUM(u8, RGFW_mouseButton) { - RGFW_mouseNone = 0, /*!< no mouse button is pressed*/ - RGFW_mouseLeft, /*!< left mouse button is pressed*/ - RGFW_mouseMiddle, /*!< mouse-wheel-button is pressed*/ + RGFW_mouseLeft = 0, /*!< left mouse button is pressed*/ + RGFW_mouseMiddle, /* !< mouse-wheel-button is pressed*/ RGFW_mouseRight, /*!< right mouse button is pressed*/ RGFW_mouseScrollUp, /*!< mouse wheel is scrolling up*/ - RGFW_mouseScrollDown /*!< mouse wheel is scrolling down*/ + RGFW_mouseScrollDown, /*!< mouse wheel is scrolling down*/ + RGFW_mouseMisc1, RGFW_mouseMisc2, RGFW_mouseMisc3, RGFW_mouseMisc4, RGFW_mouseMisc5, + RGFW_mouseFinal }; #ifndef RGFW_MAX_PATH @@ -516,7 +490,8 @@ typedef RGFW_ENUM(u8, RGFW_keymod) { RGFW_modControl = RGFW_BIT(2), RGFW_modAlt = RGFW_BIT(3), RGFW_modShift = RGFW_BIT(4), - RGFW_modSuper = RGFW_BIT(5) + RGFW_modSuper = RGFW_BIT(5), + RGFW_modScrollLock = RGFW_BIT(6) }; /*! gamepad button codes (based on xbox/playstation), you may need to change these values per controller */ @@ -562,23 +537,39 @@ typedef RGFW_ENUM(u8, RGFW_gamepadCodes) { #define RGFW_AREA(w, h) (RGFW_area){(u32)(w), (u32)(h)} #ifndef RGFW_NO_MONITOR + /* monitor mode data | can be changed by the user (with functions)*/ + typedef struct RGFW_monitorMode { + RGFW_area area; /*!< monitor workarea size */ + u32 refreshRate; /*!< monitor refresh rate */ + u8 red, blue, green; + } RGFW_monitorMode; + /*! structure for monitor data */ typedef struct RGFW_monitor { + i32 x, y; /*!< x - y of the monitor workarea */ char name[128]; /*!< monitor name */ - RGFW_rect rect; /*!< monitor Workarea */ float scaleX, scaleY; /*!< monitor content scale*/ float pixelRatio; /*!< pixel ratio for monitor (1.0 for regular, 2.0 for hiDPI) */ float physW, physH; /*!< monitor physical size in inches*/ - } RGFW_monitor; - /* - NOTE : Monitor functions should be ran only as many times as needed (not in a loop) - */ + RGFW_monitorMode mode; + } RGFW_monitor; /*! get an array of all the monitors (max 6) */ RGFWDEF RGFW_monitor* RGFW_getMonitors(void); /*! get the primary monitor */ RGFWDEF RGFW_monitor RGFW_getPrimaryMonitor(void); + + typedef RGFW_ENUM(u8, RGFW_modeRequest) { + RGFW_monitorScale = RGFW_BIT(0), /*!< scale the monitor size */ + RGFW_monitorRefresh = RGFW_BIT(1), /*!< change the refresh rate */ + RGFW_monitorRGB = RGFW_BIT(2), /*!< change the monitor RGB bits size */ + RGFW_monitorAll = RGFW_monitorScale | RGFW_monitorRefresh | RGFW_monitorRGB + }; + + /*! request a specific mode */ + RGFWDEF RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request); + RGFWDEF RGFW_bool RGFW_monitorModeCompare(RGFW_monitorMode mon, RGFW_monitorMode mon2, RGFW_modeRequest request); #endif /* RGFW mouse loading */ @@ -595,21 +586,18 @@ RGFWDEF void RGFW_freeMouse(RGFW_mouse* mouse); typedef struct RGFW_event { /*! drag and drop data */ /* 260 max paths with a max length of 260 */ -#ifdef RGFW_ALLOC_DROPFILES - char** droppedFiles; -#else char droppedFiles[RGFW_MAX_DROPS][RGFW_MAX_PATH]; /*!< dropped files*/ -#endif size_t droppedFilesCount; /*!< house many files were dropped */ RGFW_eventType type; /*!< which event has been sent?*/ RGFW_point point; /*!< mouse x, y of event (or drop point) */ + RGFW_point vector; /*!< raw mouse movement */ RGFW_key key; /*!< the physical key of the event, refers to where key is physically !!Keycodes defined at the bottom of the RGFW_HEADER part of this file!! */ u8 keyChar; /*!< mapped key char of the event*/ - b8 repeat; /*!< key press event repeated (the key is being held) */ - b8 inFocus; /*!< if the window is in focus or not (this is always true for MacOS windows due to the api being weird) */ + RGFW_bool repeat; /*!< key press event repeated (the key is being held) */ + RGFW_bool inFocus; /*!< if the window is in focus or not (this is always true for MacOS windows due to the api being weird) */ RGFW_keymod keyMod; @@ -631,14 +619,11 @@ typedef struct RGFW_window_src { HWND window; /*!< source window */ HDC hdc; /*!< source HDC */ u32 hOffset; /*!< height offset for window */ + HICON hIcon; /*!< source window icon */ #if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL) HGLRC ctx; /*!< source graphics context */ #elif defined(RGFW_OSMESA) OSMesaContext ctx; - #elif defined(RGFW_DIRECTX) - IDXGISwapChain* swapchain; - ID3D11RenderTargetView* renderTargetView; - ID3D11DepthStencilView* pDepthStencilView; #elif defined(RGFW_EGL) EGLSurface EGL_surface; EGLDisplay EGL_display; @@ -648,8 +633,9 @@ typedef struct RGFW_window_src { #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) HDC hdcMem; HBITMAP bitmap; + u8* bitmapBits; #endif - RGFW_area maxSize, minSize; /*!< for setting max/min resize (RGFW_WINDOWS) */ + RGFW_area maxSize, minSize, aspectRatio; /*!< for setting max/min resize (RGFW_WINDOWS) */ } RGFW_window_src; #elif defined(RGFW_UNIX) typedef struct RGFW_window_src { @@ -670,6 +656,8 @@ typedef struct RGFW_window_src { XImage* bitmap; GC gc; #endif + char* clipboard; /* for writing to the clipboard selection */ + size_t clipboard_len; #endif /* RGFW_X11 */ #if defined(RGFW_WAYLAND) struct wl_display* wl_display; @@ -705,7 +693,6 @@ typedef struct RGFW_window_src { #if defined(RGFW_MACOS) typedef struct RGFW_window_src { void* window; - b8 dndPassed; #if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL) void* ctx; /*!< source graphics context */ #elif defined(RGFW_OSMESA) @@ -723,7 +710,7 @@ typedef struct RGFW_window_src { void* image; #endif } RGFW_window_src; -#elif defined(RGFW_WEBASM) +#elif defined(RGFW_WASM) typedef struct RGFW_window_src { #ifdef RGFW_WEBGPU WGPUInstance ctx; @@ -746,9 +733,13 @@ typedef RGFW_ENUM(u32, RGFW_windowFlags) { RGFW_windowTransparent = RGFW_BIT(6), /*!< the window is transparent (only properly works on X11 and MacOS, although it's although for windows) */ RGFW_windowCenter = RGFW_BIT(7), /*! center the window on the screen */ RGFW_windowOpenglSoftware = RGFW_BIT(8), /*! use OpenGL software rendering */ - RGFW_windowCocoaCHDirToRes = RGFW_BIT(9), /* (cocoa only), change directory to resource folder */ - RGFW_windowScaleToMonitor = RGFW_BIT(10), /* scale the window to the screen */ - RGFW_windowHide = RGFW_BIT(11)/* the window is hidden */ + RGFW_windowCocoaCHDirToRes = RGFW_BIT(9), /*! (cocoa only), change directory to resource folder */ + RGFW_windowScaleToMonitor = RGFW_BIT(10), /*! scale the window to the screen */ + RGFW_windowHide = RGFW_BIT(11), /*! the window is hidden */ + RGFW_windowMaximize = RGFW_BIT(12), + RGFW_windowCenterCursor = RGFW_BIT(13), + RGFW_windowFloating = RGFW_BIT(14), /*!< creat a floating window */ + RGFW_windowedFullscreen = RGFW_windowNoBorder | RGFW_windowMaximize, }; typedef struct RGFW_window { @@ -757,6 +748,7 @@ typedef struct RGFW_window { #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) u8* buffer; /*!< buffer for non-GPU systems (OSMesa, basic software rendering) */ /* when rendering using RGFW_BUFFER, the buffer is in the RGBA format */ + RGFW_area bufferSize; #endif void* userPtr; /* ptr for usr data */ @@ -767,7 +759,7 @@ typedef struct RGFW_window { RGFW_point _lastMousePoint; /*!< last cusor point (for raw mouse data) */ u32 _flags; /*!< windows flags (for RGFW to check) */ - RGFW_allocator _mem; /*!< the allocator that was used to allocate RGFW window data, used to free it*/ + RGFW_rect _oldRect; /*!< rect before fullscreen */ } RGFW_window; /*!< Window structure for managing the window */ #if defined(RGFW_X11) || defined(RGFW_MACOS) @@ -776,6 +768,9 @@ typedef struct RGFW_window { typedef void* RGFW_thread; /*!< thread type for window */ #endif +/*! scale monitor to window size */ +RGFWDEF RGFW_bool RGFW_monitor_scaleToWindow(RGFW_monitor mon, RGFW_window* win); + /** * @defgroup Window_management * @{ */ @@ -785,9 +780,10 @@ typedef struct RGFW_window { * by default the class name will == the root window's name */ RGFWDEF void RGFW_setClassName(const char* name); +RGFWDEF void RGFW_setXInstName(const char* name); /*!< X11 instance name (window name will by used by default) */ -/*! this has to be set before createWindow is called, else the fulscreen size is used */ -RGFWDEF void RGFW_setBufferSize(RGFW_area size); /*!< the buffer cannot be resized (by RGFW) */ +/*! (cocoa only), change directory to resource folder */ +RGFWDEF void RGFW_moveToMacOSResourceDir(void); /* NOTE: (windows)If the executable has an icon resource named RGFW_ICON, it will be set as the initial icon for the window.*/ @@ -804,13 +800,16 @@ RGFWDEF RGFW_window* RGFW_createWindowPtr( RGFW_window* win /* ptr to the window struct you want to use */ ); /*!< function to create a window (without allocating a window struct) */ +RGFWDEF void RGFW_window_initBuffer(RGFW_window* win); +RGFWDEF void RGFW_window_initBufferSize(RGFW_window* win, RGFW_area area); +RGFWDEF void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area); + +/*! set the window flags (will undo flags if they don't match the old ones)*/ +RGFWDEF void RGFW_window_setFlags(RGFW_window* win, RGFW_windowFlags); + /*! get the size of the screen to an area struct */ RGFWDEF RGFW_area RGFW_getScreenSize(void); -/*! frees win->buffer (if it was allocated by RGFW) and sets the pointer to your pointer */ -RGFWDEF void RGFW_window_setBufferPtr(RGFW_window* win, u8* ptr, RGFW_area size); -/*< the new buffer is not be resized or freed (by RGFW) */ - /*! this function checks an *individual* event (and updates window structure attributes) @@ -831,21 +830,21 @@ RGFWDEF RGFW_event* RGFW_window_checkEvent(RGFW_window* win); /*!< check current waitMS -> Allows th e function to keep checking for events even after `RGFW_window_checkEvent == NULL` if waitMS == 0, the loop will not wait for events if waitMS == a positive integer, the loop will wait that many miliseconds after there are no more events until it returns - if waitMS == a negative integer, the loop will not return until it gets another event + if waitMS == a the max size of a 32-bit int (or -1), the loop will not return until it gets another event */ -typedef RGFW_ENUM(i32, RGFW_eventWait) { - RGFW_eventWaitNext = -1, - RGFW_eventNoWait = 0 +typedef RGFW_ENUM(u32, RGFW_eventWait) { + RGFW_eventNoWait = 0, + RGFW_eventWaitNext = 0xFFFFFFFF }; /*! sleep until RGFW gets an event or the timer ends (defined by OS) */ -RGFWDEF void RGFW_window_eventWait(RGFW_window* win, i32 waitMS); +RGFWDEF void RGFW_window_eventWait(RGFW_window* win, u32 waitMS); /*! check all the events until there are none left, this should only be used if you're using callbacks only */ -RGFWDEF void RGFW_window_checkEvents(RGFW_window* win, i32 waitMS); +RGFWDEF void RGFW_window_checkEvents(RGFW_window* win, u32 waitMS); /*! Tell RGFW_window_eventWait to stop waiting, to be ran from another thread @@ -870,24 +869,36 @@ RGFWDEF void RGFW_window_resize(RGFW_window* win, /*!< source window */ RGFW_area a/*!< new size*/ ); +/*! set window aspect ratio */ +RGFWDEF void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a); /*! set the minimum size a user can shrink a window to a given size/area */ RGFWDEF void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a); /*! set the minimum size a user can extend a window to a given size/area */ RGFWDEF void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a); +RGFWDEF void RGFW_window_focus(RGFW_window* win); /*!< sets the focus to this window */ +RGFWDEF void RGFW_window_raise(RGFW_window* win); /*!< raise the window (to the top) */ RGFWDEF void RGFW_window_maximize(RGFW_window* win); /*!< maximize the window size */ +RGFWDEF void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen); /*!< fullscreen the window size */ +RGFWDEF void RGFW_window_center(RGFW_window* win); /*!< center the window */ RGFWDEF void RGFW_window_minimize(RGFW_window* win); /*!< minimize the window (in taskbar (per OS))*/ RGFWDEF void RGFW_window_restore(RGFW_window* win); /*!< restore the window from minimized (per OS)*/ +RGFWDEF void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating); /*!< make the window a floating window */ +RGFWDEF void RGFW_window_setOpacity(RGFW_window* win, u8 opacity); /*!< sets the opacity of the whole window */ /*! if the window should have a border or not (borderless) based on bool value of `border` */ -RGFWDEF void RGFW_window_setBorder(RGFW_window* win, b8 border); +RGFWDEF void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border); +RGFWDEF RGFW_bool RGFW_window_borderless(RGFW_window* win); /*! turn on / off dnd (RGFW_windowAllowDND stil must be passed to the window)*/ -RGFWDEF void RGFW_window_setDND(RGFW_window* win, b8 allow); +RGFWDEF void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow); +/*! check if DND is allowed */ +RGFWDEF RGFW_bool RGFW_window_allowsDND(RGFW_window* win); + #ifndef RGFW_NO_PASSTHROUGH /*!! turn on / off mouse passthrough */ - RGFWDEF void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough); + RGFWDEF void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough); #endif /*! rename window to a given string */ @@ -895,19 +906,19 @@ RGFWDEF void RGFW_window_setName(RGFW_window* win, const char* name ); -RGFWDEF b32 RGFW_window_setIcon(RGFW_window* win, /*!< source window */ +RGFWDEF RGFW_bool RGFW_window_setIcon(RGFW_window* win, /*!< source window */ u8* icon /*!< icon bitmap */, RGFW_area a /*!< width and height of the bitmap*/, i32 channels /*!< how many channels the bitmap has (rgb : 3, rgba : 4) */ -); /*!< image resized by default */ +); /*!< image MAY be resized by default */ /*!< sets mouse to RGFW_mouse icon (loaded from a bitmap struct) */ RGFWDEF void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse); /*!< sets the mouse to a standard API cursor (based on RGFW_MOUSE, as seen at the end of the RGFW_HEADER part of this file) */ -RGFWDEF b32 RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse); +RGFWDEF RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse); -RGFWDEF b32 RGFW_window_setMouseDefault(RGFW_window* win); /*!< sets the mouse to the default mouse icon */ +RGFWDEF RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win); /*!< sets the mouse to the default mouse icon */ /* Locks cursor at the center of the window win->event.point become raw mouse movement data @@ -936,20 +947,24 @@ RGFWDEF RGFW_point RGFW_getGlobalMousePoint(void); RGFWDEF RGFW_point RGFW_window_getMousePoint(RGFW_window* win); /*! show the mouse or hide the mouse*/ -RGFWDEF void RGFW_window_showMouse(RGFW_window* win, i8 show); +RGFWDEF void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show); +/*! if the mouse is hidden */ +RGFWDEF RGFW_bool RGFW_window_mouseHidden(RGFW_window* win); /*! move the mouse to a set x, y pos*/ RGFWDEF void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v); /*! if the window should close (RGFW_close was sent or escape was pressed) */ -RGFWDEF b8 RGFW_window_shouldClose(RGFW_window* win); +RGFWDEF RGFW_bool RGFW_window_shouldClose(RGFW_window* win); /*! if window is fullscreen'd */ -RGFWDEF b8 RGFW_window_isFullscreen(RGFW_window* win); +RGFWDEF RGFW_bool RGFW_window_isFullscreen(RGFW_window* win); /*! if window is hidden */ -RGFWDEF b8 RGFW_window_isHidden(RGFW_window* win); +RGFWDEF RGFW_bool RGFW_window_isHidden(RGFW_window* win); /*! if window is minimized */ -RGFWDEF b8 RGFW_window_isMinimized(RGFW_window* win); +RGFWDEF RGFW_bool RGFW_window_isMinimized(RGFW_window* win); /*! if window is maximized */ -RGFWDEF b8 RGFW_window_isMaximized(RGFW_window* win); +RGFWDEF RGFW_bool RGFW_window_isMaximized(RGFW_window* win); +/*! if window is floating */ +RGFWDEF RGFW_bool RGFW_window_isFloating(RGFW_window* win); /** @} */ @@ -972,24 +987,24 @@ RGFWDEF RGFW_monitor RGFW_window_getMonitor(RGFW_window* win); * @{ */ /*! if window == NULL, it checks if the key is pressed globally. Otherwise, it checks only if the key is pressed while the window in focus.*/ -RGFWDEF b8 RGFW_isPressed(RGFW_window* win, RGFW_key key); /*!< if key is pressed (key code)*/ +RGFWDEF RGFW_bool RGFW_isPressed(RGFW_window* win, RGFW_key key); /*!< if key is pressed (key code)*/ -RGFWDEF b8 RGFW_wasPressed(RGFW_window* win, RGFW_key key); /*!< if key was pressed (checks previous state only) (key code)*/ +RGFWDEF RGFW_bool RGFW_wasPressed(RGFW_window* win, RGFW_key key); /*!< if key was pressed (checks previous state only) (key code)*/ -RGFWDEF b8 RGFW_isHeld(RGFW_window* win, RGFW_key key); /*!< if key is held (key code)*/ -RGFWDEF b8 RGFW_isReleased(RGFW_window* win, RGFW_key key); /*!< if key is released (key code)*/ +RGFWDEF RGFW_bool RGFW_isHeld(RGFW_window* win, RGFW_key key); /*!< if key is held (key code)*/ +RGFWDEF RGFW_bool RGFW_isReleased(RGFW_window* win, RGFW_key key); /*!< if key is released (key code)*/ /* if a key is pressed and then released, pretty much the same as RGFW_isReleased */ -RGFWDEF b8 RGFW_isClicked(RGFW_window* win, RGFW_key key /*!< key code*/); +RGFWDEF RGFW_bool RGFW_isClicked(RGFW_window* win, RGFW_key key /*!< key code*/); /*! if a mouse button is pressed */ -RGFWDEF b8 RGFW_isMousePressed(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ ); +RGFWDEF RGFW_bool RGFW_isMousePressed(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ ); /*! if a mouse button is held */ -RGFWDEF b8 RGFW_isMouseHeld(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ ); +RGFWDEF RGFW_bool RGFW_isMouseHeld(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ ); /*! if a mouse button was released */ -RGFWDEF b8 RGFW_isMouseReleased(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ ); +RGFWDEF RGFW_bool RGFW_isMouseReleased(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ ); /*! if a mouse button was pressed (checks previous state only) */ -RGFWDEF b8 RGFW_wasMousePressed(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ ); +RGFWDEF RGFW_bool RGFW_wasMousePressed(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ ); /** @} */ /** * @defgroup Clipboard @@ -1020,32 +1035,29 @@ typedef void (* RGFW_windowresizefunc)(RGFW_window* win, RGFW_rect r); /*! RGFW_quit, the window that was closed */ typedef void (* RGFW_windowquitfunc)(RGFW_window* win); /*! RGFW_focusIn / RGFW_focusOut, the window who's focus has changed and if its inFocus */ -typedef void (* RGFW_focusfunc)(RGFW_window* win, b8 inFocus); +typedef void (* RGFW_focusfunc)(RGFW_window* win, RGFW_bool inFocus); /*! RGFW_mouseEnter / RGFW_mouseLeave, the window that changed, the point of the mouse (enter only) and if the mouse has entered */ -typedef void (* RGFW_mouseNotifyfunc)(RGFW_window* win, RGFW_point point, b8 status); +typedef void (* RGFW_mouseNotifyfunc)(RGFW_window* win, RGFW_point point, RGFW_bool status); /*! RGFW_mousePosChanged, the window that the move happened on and the new point of the mouse */ -typedef void (* RGFW_mouseposfunc)(RGFW_window* win, RGFW_point point); +typedef void (* RGFW_mouseposfunc)(RGFW_window* win, RGFW_point point, RGFW_point vector); /*! RGFW_DNDInit, the window, the point of the drop on the windows */ typedef void (* RGFW_dndInitfunc)(RGFW_window* win, RGFW_point point); /*! RGFW_windowRefresh, the window that needs to be refreshed */ typedef void (* RGFW_windowrefreshfunc)(RGFW_window* win); /*! RGFW_keyPressed / RGFW_keyReleased, the window that got the event, the mapped key, the physical key, the string version, the state of mod keys, if it was a press (else it's a release) */ -typedef void (* RGFW_keyfunc)(RGFW_window* win, u8 key, char keyChar, RGFW_keymod keyMod, b8 pressed); +typedef void (* RGFW_keyfunc)(RGFW_window* win, u8 key, char keyChar, RGFW_keymod keyMod, RGFW_bool pressed); /*! RGFW_mouseButtonPressed / RGFW_mouseButtonReleased, the window that got the event, the button that was pressed, the scroll value, if it was a press (else it's a release) */ -typedef void (* RGFW_mousebuttonfunc)(RGFW_window* win, RGFW_mouseButton button, double scroll, b8 pressed); +typedef void (* RGFW_mousebuttonfunc)(RGFW_window* win, RGFW_mouseButton button, double scroll, RGFW_bool pressed); /*!gamepad /gamepad, the window that got the event, the button that was pressed, the scroll value, if it was a press (else it's a release) */ -typedef void (* RGFW_gamepadButtonfunc)(RGFW_window* win, u16 gamepad, u8 button, b8 pressed); +typedef void (* RGFW_gamepadButtonfunc)(RGFW_window* win, u16 gamepad, u8 button, RGFW_bool pressed); /*! RGFW_gamepadAxisMove, the window that got the event, the gamepad in question, the axis values and the amount of axises */ typedef void (* RGFW_gamepadAxisfunc)(RGFW_window* win, u16 gamepad, RGFW_point axis[2], u8 axisesCount, u8 whichAxis); /*! RGFW_gamepadConnected/RGFW_gamepadDisconnected, the window that got the event, the gamepad in question, if the controller was connected (or disconnected if false) */ -typedef void (* RGFW_gamepadfunc)(RGFW_window* win, u16 gamepad, b8 connected); +typedef void (* RGFW_gamepadfunc)(RGFW_window* win, u16 gamepad, RGFW_bool connected); /*! RGFW_dnd, the window that had the drop, the drop data and the amount files dropped returns previous callback function (if it was set) */ -#ifdef RGFW_ALLOC_DROPFILES - typedef void (* RGFW_dndfunc)(RGFW_window* win, char** droppedFiles, u32 droppedFilesCount); -#else - typedef void (* RGFW_dndfunc)(RGFW_window* win, char droppedFiles[RGFW_MAX_DROPS][RGFW_MAX_PATH], u32 droppedFilesCount); -#endif +typedef void (* RGFW_dndfunc)(RGFW_window* win, char droppedFiles[RGFW_MAX_DROPS][RGFW_MAX_PATH], u32 droppedFilesCount); + /*! set callback for a window move event returns previous callback function (if it was set) */ RGFWDEF RGFW_windowmovefunc RGFW_setWindowMoveCallback(RGFW_windowmovefunc func); /*! set callback for a window resize event returns previous callback function (if it was set) */ @@ -1090,7 +1102,7 @@ RGFWDEF RGFW_gamepadfunc RGFW_setGamepadCallback(RGFW_gamepadfunc func); which is a good idea generally */ -#if defined(__unix__) || defined(__APPLE__) || defined(RGFW_WEBASM) || defined(RGFW_CUSTOM_BACKEND) +#if defined(__unix__) || defined(__APPLE__) || defined(RGFW_WASM) || defined(RGFW_CUSTOM_BACKEND) typedef void* (* RGFW_threadFunc_ptr)(void*); #else typedef DWORD (__stdcall *RGFW_threadFunc_ptr) (LPVOID lpThreadParameter); @@ -1142,38 +1154,57 @@ RGFWDEF u32 RGFW_window_checkFPS(RGFW_window* win, u32 fpsCap); RGFWDEF void RGFW_window_swapBuffers(RGFW_window* win); /*!< swap the rendering buffer */ RGFWDEF void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval); -RGFWDEF void RGFW_window_setGPURender(RGFW_window* win, i8 set); -RGFWDEF void RGFW_window_setCPURender(RGFW_window* win, i8 set); +RGFWDEF void RGFW_window_setGPURender(RGFW_window* win, RGFW_bool set); +RGFWDEF void RGFW_window_setCPURender(RGFW_window* win, RGFW_bool set); /*! native API functions */ #if defined(RGFW_OPENGL) || defined(RGFW_EGL) /*! OpenGL init hints */ -RGFWDEF void RGFW_setGLStencil(i32 stencil); /*!< set stencil buffer bit size (8 by default) */ -RGFWDEF void RGFW_setGLSamples(i32 samples); /*!< set number of sampiling buffers (4 by default) */ -RGFWDEF void RGFW_setGLStereo(i32 stereo); /*!< use GL_STEREO (GL_FALSE by default) */ -RGFWDEF void RGFW_setGLAuxBuffers(i32 auxBuffers); /*!< number of aux buffers (0 by default) */ - -/*! which profile to use for the opengl verion */ -typedef RGFW_ENUM(u8, RGFW_glProfile) { RGFW_glCore = 0, RGFW_glCompatibility }; -/*! Set OpenGL version hint (core or compatibility profile)*/ -RGFWDEF void RGFW_setGLVersion(RGFW_glProfile profile, i32 major, i32 minor); -RGFWDEF void RGFW_setDoubleBuffer(b8 useDoubleBuffer); +typedef RGFW_ENUM(u8, RGFW_glHints) { + RGFW_glStencil = 0, /*!< set stencil buffer bit size (8 by default) */ + RGFW_glSamples, /*!< set number of sampiling buffers (4 by default) */ + RGFW_glStereo, /*!< use GL_STEREO (GL_FALSE by default) */ + RGFW_glAuxBuffers, /*!< number of aux buffers (0 by default) */ + RGFW_glDoubleBuffer, /*!< request double buffering */ + RGFW_glRed, RGFW_glGreen, RGFW_glBlue, RGFW_glAlpha, /*!< set RGBA bit sizes */ + RGFW_glDepth, + RGFW_glAccumRed, RGFW_glAccumGreen, RGFW_glAccumBlue,RGFW_glAccumAlpha, /*!< set accumulated RGBA bit sizes*/ + RGFW_glSRGB, /*!< request sRGA */ + RGFW_glRobustness, /*!< request a robust context */ + RGFW_glDebug, /*!< request opengl debugging */ + RGFW_glNoError, /*!< request no opengl errors */ + RGFW_glReleaseBehavior, + RGFW_glProfile, + RGFW_glMajor, RGFW_glMinor, + RGFW_glFinalHint, /*!< the final hint (not for setting) */ + RGFW_releaseFlush = 0, RGFW_glReleaseNone, /* RGFW_glReleaseBehavior options */ + RGFW_glCore = 0, RGFW_glCompatibility /*!< RGFW_glProfile options */ +}; +RGFWDEF void RGFW_setGLHint(RGFW_glHints hint, i32 value); RGFWDEF void* RGFW_getProcAddress(const char* procname); /*!< get native opengl proc address */ RGFWDEF void RGFW_window_makeCurrent_OpenGL(RGFW_window* win); /*!< to be called by RGFW_window_makeCurrent */ +void* RGFW_getCurrent_OpenGL(void); /*!< get the current context (OpenGL backend (GLX) (WGL) (EGL) (cocoa) (webgl))*/ +#elif defined(RGFW_VULKAN) + #if defined(RGFW_X11) + #define VK_USE_PLATFORM_XLIB_KHR + #define RGFW_VK_SURFACE "VK_KHR_xlib_surface" + #elif defined(RGFW_WINDOWS) + #define VK_USE_PLATFORM_WIN32_KHR + #define OEMRESOURCE + #define RGFW_VK_SURFACE "VK_KHR_win32_surface" + #elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11) + #define VK_USE_PLATFORM_MACOS_MVK + #define RGFW_VK_SURFACE "VK_MVK_macos_surface" + #elif defined(RGFW_WAYLAND) + #define VK_USE_PLATFORM_WAYLAND_KHR + #define RGFW_VK_SURFACE "VK_KHR_wayland_surface" + #else + #define RGFW_VK_SURFACE NULL + #endif -#elif defined(RGFW_DIRECTX) -typedef struct { - IDXGIFactory* pFactory; - IDXGIAdapter* pAdapter; - ID3D11Device* pDevice; - ID3D11DeviceContext* pDeviceContext; -} RGFW_directXinfo; +#include -/* - RGFW stores a global instance of RGFW_directXinfo, - you can use this function to get a pointer the instance -*/ -RGFWDEF RGFW_directXinfo* RGFW_getDirectXInfo(void); +RGFWDEF VkResult RGFW_window_createVKSurface(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface); #endif /** @} */ @@ -1183,11 +1214,13 @@ RGFWDEF RGFW_directXinfo* RGFW_getDirectXInfo(void); RGFWDEF u64 RGFW_getTime(void); /*!< get time in seconds */ RGFWDEF u64 RGFW_getTimeNS(void); /*!< get time in nanoseconds */ RGFWDEF void RGFW_sleep(u64 milisecond); /*!< sleep for a set time */ +RGFWDEF u64 RGFW_getTimerValue(void); /*!< get API timer value */ +RGFWDEF u64 RGFW_getTimerFreq(void); /*!< get API time freq */ /*! key codes and mouse icon enums */ - +#undef RGFW_key typedef RGFW_ENUM(u8, RGFW_key) { RGFW_keyNULL = 0, RGFW_escape = '\033', @@ -1297,6 +1330,7 @@ typedef RGFW_ENUM(u8, RGFW_key) { RGFW_KP_0, RGFW_KP_Period, RGFW_KP_Return, + RGFW_scrollLock, RGFW_keyLast }; @@ -1325,13 +1359,13 @@ typedef RGFW_ENUM(u8, RGFW_mouseIcons) { #define RGFW_OS_BASED_VALUE(l, w, m, h) w #elif defined(RGFW_MACOS) #define RGFW_OS_BASED_VALUE(l, w, m, h) m -#elif defined(RGFW_WEBASM) +#elif defined(RGFW_WASM) #define RGFW_OS_BASED_VALUE(l, w, m, h) h #endif #ifdef RGFW_IMPLEMENTATION -b8 RGFW_useWaylandBool = 1; +RGFW_bool RGFW_useWaylandBool = 1; #ifdef RGFW_DEBUG #include @@ -1342,36 +1376,11 @@ b8 RGFW_useWaylandBool = 1; #define RGFW_ASSERT assert #endif -/* - RGFW_allocator, (optional) - you can ignore this if you use standard malloc/free -*/ - -void* RGFW_allocatorMalloc(void* userdata, size_t size) { - void* out = RGFW_ALLOC(userdata, size); RGFW_ASSERT(out != NULL); - return out; -} -void RGFW_allocatorFree(void* userdata, void* ptr) { RGFW_ASSERT(ptr != NULL); RGFW_FREE(userdata, ptr); } -RGFW_allocator RGFW_current_allocator = {RGFW_USERPTR, RGFW_allocatorMalloc, RGFW_allocatorFree}; - -RGFW_allocator RGFW_loadAllocator(RGFW_allocator allocator) { - RGFW_allocator old = RGFW_current_allocator; - RGFW_current_allocator = allocator; - return old; -} - -void* RGFW_alloc(size_t len) { return RGFW_current_allocator.alloc(RGFW_current_allocator.userdata, len); } -void RGFW_free(void* ptr) { RGFW_current_allocator.free(RGFW_current_allocator.userdata, ptr); } - - -char* RGFW_clipboard_data = NULL; -RGFW_allocator RGFW_clipboard_alloc; - +char* RGFW_clipboard_data; void RGFW_clipboard_switch(char* newstr) { if (RGFW_clipboard_data != NULL) - RGFW_clipboard_alloc.free(RGFW_clipboard_alloc.userdata, RGFW_clipboard_data); + RGFW_FREE(RGFW_clipboard_data); RGFW_clipboard_data = newstr; - RGFW_clipboard_alloc = RGFW_current_allocator; } #define RGFW_CHECK_CLIPBOARD() \ @@ -1383,7 +1392,7 @@ void RGFW_clipboard_switch(char* newstr) { const char* RGFW_readClipboard(size_t* len) { RGFW_ssize_t size = RGFW_readClipboardPtr(NULL, 0); RGFW_CHECK_CLIPBOARD(); - char* str = (char*)RGFW_alloc(size); + char* str = (char*)RGFW_ALLOC(size); size = RGFW_readClipboardPtr(str, size); RGFW_CHECK_CLIPBOARD(); @@ -1501,7 +1510,7 @@ void RGFW_init_keys(void) { RGFW_MAP [RGFW_OS_BASED_VALUE(37, 0x01D, 59, DOM_VK_CONTROL)] = RGFW_controlL RGFW_NEXT RGFW_MAP [RGFW_OS_BASED_VALUE(64, 0x038, 58, DOM_VK_ALT)] = RGFW_altL RGFW_NEXT RGFW_MAP [RGFW_OS_BASED_VALUE(133, 0x15B, 55, DOM_VK_WIN)] = RGFW_superL, - #if !defined(RGFW_MACOS) && !defined(RGFW_WEBASM) + #if !defined(RGFW_MACOS) && !defined(RGFW_WASM) RGFW_MAP [RGFW_OS_BASED_VALUE(105, 0x11D, 59, 0)] = RGFW_controlR RGFW_NEXT RGFW_MAP [RGFW_OS_BASED_VALUE(135, 0x15C, 55, 0)] = RGFW_superR, RGFW_MAP [RGFW_OS_BASED_VALUE(62, 0x036, 56, 0)] = RGFW_shiftR RGFW_NEXT @@ -1529,6 +1538,7 @@ void RGFW_init_keys(void) { RGFW_MAP [RGFW_OS_BASED_VALUE(117, 0x151, 122, DOM_VK_PAGE_DOWN)] = RGFW_pageDown RGFW_NEXT RGFW_MAP [RGFW_OS_BASED_VALUE(9, 0x001, 53, DOM_VK_ESCAPE)] = RGFW_escape RGFW_NEXT RGFW_MAP [RGFW_OS_BASED_VALUE(110, 0x147, 116, DOM_VK_HOME)] = RGFW_home RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(78, 0x046, 107, DOM_VK_SCROLL_LOCK)] = RGFW_scrollLock RGFW_NEXT #ifndef __cplusplus }; #else @@ -1554,8 +1564,8 @@ u32 RGFW_apiKeyToRGFW(u32 keycode) { #endif typedef struct { - b8 current : 1; - b8 prev : 1; + RGFW_bool current : 1; + RGFW_bool prev : 1; } RGFW_keyState; RGFW_keyState RGFW_keyboard[RGFW_keyLast] = { {0, 0} }; @@ -1595,22 +1605,17 @@ u16 RGFW_gamepadCount = 0; /*!< the actual amount of gamepads */ void RGFW_windowmovefuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); } void RGFW_windowresizefuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); } void RGFW_windowquitfuncEMPTY(RGFW_window* win) { RGFW_UNUSED(win); } -void RGFW_focusfuncEMPTY(RGFW_window* win, b8 inFocus) {RGFW_UNUSED(win); RGFW_UNUSED(inFocus);} -void RGFW_mouseNotifyfuncEMPTY(RGFW_window* win, RGFW_point point, b8 status) {RGFW_UNUSED(win); RGFW_UNUSED(point); RGFW_UNUSED(status);} -void RGFW_mouseposfuncEMPTY(RGFW_window* win, RGFW_point point) {RGFW_UNUSED(win); RGFW_UNUSED(point);} +void RGFW_focusfuncEMPTY(RGFW_window* win, RGFW_bool inFocus) {RGFW_UNUSED(win); RGFW_UNUSED(inFocus);} +void RGFW_mouseNotifyfuncEMPTY(RGFW_window* win, RGFW_point point, RGFW_bool status) {RGFW_UNUSED(win); RGFW_UNUSED(point); RGFW_UNUSED(status);} +void RGFW_mouseposfuncEMPTY(RGFW_window* win, RGFW_point point, RGFW_point vector) {RGFW_UNUSED(win); RGFW_UNUSED(point); RGFW_UNUSED(vector);} void RGFW_dndInitfuncEMPTY(RGFW_window* win, RGFW_point point) {RGFW_UNUSED(win); RGFW_UNUSED(point);} void RGFW_windowrefreshfuncEMPTY(RGFW_window* win) {RGFW_UNUSED(win); } -void RGFW_keyfuncEMPTY(RGFW_window* win, RGFW_key key, char keyChar, RGFW_keymod keyMod, b8 pressed) {RGFW_UNUSED(win); RGFW_UNUSED(key); RGFW_UNUSED(keyChar); RGFW_UNUSED(keyMod); RGFW_UNUSED(pressed);} -void RGFW_mousebuttonfuncEMPTY(RGFW_window* win, RGFW_mouseButton button, double scroll, b8 pressed) {RGFW_UNUSED(win); RGFW_UNUSED(button); RGFW_UNUSED(scroll); RGFW_UNUSED(pressed);} -void RGFW_gamepadButtonfuncEMPTY(RGFW_window* win, u16 gamepad, u8 button, b8 pressed){RGFW_UNUSED(win); RGFW_UNUSED(gamepad); RGFW_UNUSED(button); RGFW_UNUSED(pressed); } +void RGFW_keyfuncEMPTY(RGFW_window* win, RGFW_key key, char keyChar, RGFW_keymod keyMod, RGFW_bool pressed) {RGFW_UNUSED(win); RGFW_UNUSED(key); RGFW_UNUSED(keyChar); RGFW_UNUSED(keyMod); RGFW_UNUSED(pressed);} +void RGFW_mousebuttonfuncEMPTY(RGFW_window* win, RGFW_mouseButton button, double scroll, RGFW_bool pressed) {RGFW_UNUSED(win); RGFW_UNUSED(button); RGFW_UNUSED(scroll); RGFW_UNUSED(pressed);} +void RGFW_gamepadButtonfuncEMPTY(RGFW_window* win, u16 gamepad, u8 button, RGFW_bool pressed){RGFW_UNUSED(win); RGFW_UNUSED(gamepad); RGFW_UNUSED(button); RGFW_UNUSED(pressed); } void RGFW_gamepadAxisfuncEMPTY(RGFW_window* win, u16 gamepad, RGFW_point axis[2], u8 axisesCount, u8 whichAxis){RGFW_UNUSED(win); RGFW_UNUSED(gamepad); RGFW_UNUSED(axis); RGFW_UNUSED(axisesCount); RGFW_UNUSED(whichAxis); } -void RGFW_gamepadfuncEMPTY(RGFW_window* win, u16 gamepad, b8 connected) {RGFW_UNUSED(win); RGFW_UNUSED(gamepad); RGFW_UNUSED(connected);} - -#ifdef RGFW_ALLOC_DROPFILES -void RGFW_dndfuncEMPTY(RGFW_window* win, char** droppedFiles, u32 droppedFilesCount) {RGFW_UNUSED(win); RGFW_UNUSED(droppedFiles); RGFW_UNUSED(droppedFilesCount);} -#else +void RGFW_gamepadfuncEMPTY(RGFW_window* win, u16 gamepad, RGFW_bool connected) {RGFW_UNUSED(win); RGFW_UNUSED(gamepad); RGFW_UNUSED(connected);} void RGFW_dndfuncEMPTY(RGFW_window* win, char droppedFiles[RGFW_MAX_DROPS][RGFW_MAX_PATH], u32 droppedFilesCount) {RGFW_UNUSED(win); RGFW_UNUSED(droppedFiles); RGFW_UNUSED(droppedFilesCount);} -#endif RGFW_windowmovefunc RGFW_windowMoveCallback = RGFW_windowmovefuncEMPTY; RGFW_windowresizefunc RGFW_windowResizeCallback = RGFW_windowresizefuncEMPTY; @@ -1627,14 +1632,14 @@ RGFW_gamepadButtonfunc RGFW_gamepadButtonCallback = RGFW_gamepadButtonfuncEMPTY; RGFW_gamepadAxisfunc RGFW_gamepadAxisCallback = RGFW_gamepadAxisfuncEMPTY; RGFW_gamepadfunc RGFW_gamepadCallback = RGFW_gamepadfuncEMPTY; -void RGFW_window_checkEvents(RGFW_window* win, i32 waitMS) { +void RGFW_window_checkEvents(RGFW_window* win, u32 waitMS) { RGFW_window_eventWait(win, waitMS); while (RGFW_window_checkEvent(win) != NULL && RGFW_window_shouldClose(win) == 0) { if (win->event.type == RGFW_quit) return; } - #ifdef RGFW_WEBASM /* webasm needs to run the sleep function for asyncify */ + #ifdef RGFW_WASM /* WASM needs to run the sleep function for asyncify */ RGFW_sleep(0); #endif } @@ -1721,20 +1726,17 @@ no more event call back defines attribs[index++] = v; \ } -#define RGFW_NO_GPU_RENDER RGFW_BIT(20) /* don't render (using the GPU based API)*/ -#define RGFW_NO_CPU_RENDER RGFW_BIT(21) /* don't render (using the CPU based buffer rendering)*/ -#define RGFW_HOLD_MOUSE RGFW_BIT(22) /*!< hold the moues still */ -#define RGFW_MOUSE_LEFT RGFW_BIT(23) /* if mouse left the window */ -#define RGFW_WINDOW_ALLOC RGFW_BIT(24) /* if window was allocated by RGFW */ -#define RGFW_BUFFER_ALLOC RGFW_BIT(25) /* if window.buffer was allocated by RGFW */ - -RGFW_area RGFW_bufferSize = {0, 0}; -void RGFW_setBufferSize(RGFW_area size) { - RGFW_bufferSize = size; -} +#define RGFW_EVENT_PASSED RGFW_BIT(24) /* if a queued event was passed*/ +#define RGFW_NO_GPU_RENDER RGFW_BIT(25) /* don't render (using the GPU based API)*/ +#define RGFW_NO_CPU_RENDER RGFW_BIT(26) /* don't render (using the CPU based buffer rendering)*/ +#define RGFW_HOLD_MOUSE RGFW_BIT(27) /*!< hold the moues still */ +#define RGFW_MOUSE_LEFT RGFW_BIT(28) /* if mouse left the window */ +#define RGFW_WINDOW_ALLOC RGFW_BIT(29) /* if window was allocated by RGFW */ +#define RGFW_BUFFER_ALLOC RGFW_BIT(30) /* if window.buffer was allocated by RGFW */ RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, RGFW_windowFlags flags) { - RGFW_window* win = (RGFW_window*)RGFW_alloc(sizeof(RGFW_window)); + RGFW_window* win = (RGFW_window*)RGFW_ALLOC(sizeof(RGFW_window)); + win->_flags = 0; win->_flags |= RGFW_WINDOW_ALLOC; return RGFW_createWindowPtr(name, rect, flags, win); } @@ -1745,7 +1747,6 @@ RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, RGFW_windowFlag #endif RGFWDEF void RGFW_window_basic_init(RGFW_window* win, RGFW_rect rect, RGFW_windowFlags flags); - #if defined(RGFW_X11) || defined(RGFW_WINDOWS) RGFW_mouse* RGFW_hiddenMouse = NULL; #endif @@ -1754,35 +1755,21 @@ RGFW_window* RGFW_root = NULL; /* do a basic initialization for RGFW_window, this is to standard it for each OS */ void RGFW_window_basic_init(RGFW_window* win, RGFW_rect rect, RGFW_windowFlags flags) { - /* clear out dnd info */ -#ifdef RGFW_ALLOC_DROPFILES - win->event.droppedFiles = (char**) RGFW_alloc(sizeof(char*) * RGFW_MAX_DROPS); - u32 i; - for (i = 0; i < RGFW_MAX_DROPS; i++) { - win->event.droppedFiles[i] = (char*) RGFW_alloc(RGFW_MAX_PATH); - win->event.droppedFiles[i][0] = 0; - } -#endif - - /* X11 requires us to have a display to get the screen size */ - #ifndef RGFW_X11 - RGFW_area screenR = RGFW_getScreenSize(); - #else - win->src.display = XOpenDisplay(NULL); - RGFW_ASSERT(win->src.display != NULL); - - Screen* scrn = DefaultScreenOfDisplay(win->src.display); - RGFW_area screenR = RGFW_AREA((u32)scrn->width, (u32)scrn->height); - #endif - + RGFW_UNUSED(flags); /* rect based the requested flags */ - if (flags & RGFW_windowFullscreen) - rect = RGFW_RECT(0, 0, screenR.w, screenR.h); - if (RGFW_root == NULL) { RGFW_root = win; + #ifdef RGFW_X11 + RGFW_root->src.display = XOpenDisplay(NULL); + #endif } + #ifdef RGFW_X11 + win->src.clipboard = NULL; + win->src.display = RGFW_root->src.display; + RGFW_ASSERT(win->src.display != NULL); + #endif + #if defined(RGFW_X11) || defined(RGFW_WINDOWS) if (RGFW_hiddenMouse == NULL) { u8 RGFW_blk[] = { 0, 0, 0, 0 }; @@ -1794,24 +1781,43 @@ void RGFW_window_basic_init(RGFW_window* win, RGFW_rect rect, RGFW_windowFlags f win->r = rect; win->event.inFocus = 1; win->event.droppedFilesCount = 0; - win->_flags = 0; + win->_flags = flags; win->event.keyMod = 0; - win->_mem.free = RGFW_current_allocator.free; } -void RGFW_window_setBufferPtr(RGFW_window* win, u8* ptr, RGFW_area size) { - RGFW_ASSERT(win); RGFW_ASSERT(ptr); +void RGFW_window_setFlags(RGFW_window* win, RGFW_windowFlags flags) { + #ifndef RGFW_NO_MONITOR + if (flags & RGFW_windowScaleToMonitor) RGFW_window_scaleToMonitor(win); + #endif - #ifdef RGFW_BUFFER - if (win->buffer != NULL && ((win->_flags & RGFW_BUFFER_ALLOC))) { - win->_mem.free(win->_mem.userdata, win->buffer); - win->_flags ^= RGFW_BUFFER_ALLOC; - } + if (flags & RGFW_windowCenter) RGFW_window_center(win); + if (flags & RGFW_windowCenterCursor) + RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2))); + if (flags & RGFW_windowNoBorder) RGFW_window_setBorder(win, 0); + else RGFW_window_setBorder(win, 1); + if (flags & RGFW_windowFullscreen) RGFW_window_setFullscreen(win, RGFW_TRUE); + else if (win->_flags & RGFW_windowFullscreen) RGFW_window_setFullscreen(win, 0); + if (flags & RGFW_windowMaximize) RGFW_window_maximize(win); + else if (win->_flags & RGFW_windowMaximize) RGFW_window_restore(win); + if (flags & RGFW_windowHideMouse) RGFW_window_showMouse(win, 0); + else if (win->_flags & RGFW_windowHideMouse) RGFW_window_showMouse(win, 1); + if (flags & RGFW_windowCocoaCHDirToRes) RGFW_moveToMacOSResourceDir(); + if (flags & RGFW_windowFloating) RGFW_window_setFloating(win, 1); + else if (win->_flags & RGFW_windowFloating) RGFW_window_setFloating(win, 0); - RGFW_bufferSize = size; - win->buffer = ptr; - #else - RGFW_UNUSED(size); + win->_flags = flags; +} + +void RGFW_window_initBuffer(RGFW_window* win) { + RGFW_window_initBufferSize(win, RGFW_getScreenSize()); +} + +void RGFW_window_initBufferSize(RGFW_window* win, RGFW_area area) { + win->_flags |= RGFW_BUFFER_ALLOC; + #ifndef RGFW_WINDOWS + RGFW_window_initBufferPtr(win, RGFW_ALLOC(area.w * area.h * 4), area); + #else /* windows's bitmap allocs memory for us */ + RGFW_window_initBufferPtr(win, NULL, area); #endif } @@ -1821,58 +1827,55 @@ RGFWDEF void* RGFW_cocoaGetLayer(void); #endif const char* RGFW_className = NULL; -void RGFW_setClassName(const char* name) { - RGFW_className = name; -} +void RGFW_setClassName(const char* name) { RGFW_className = name; } + +#ifndef RGFW_X11 +void RGFW_setXInstName(const char* name) { RGFW_UNUSED(name); } +#endif -RGFW_keyState RGFW_mouseButtons[5] = { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} }; +RGFW_keyState RGFW_mouseButtons[RGFW_mouseFinal] = { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} }; -b8 RGFW_isMousePressed(RGFW_window* win, RGFW_mouseButton button) { +RGFW_bool RGFW_isMousePressed(RGFW_window* win, RGFW_mouseButton button) { return RGFW_mouseButtons[button].current && (win == NULL || win->event.inFocus); } -b8 RGFW_wasMousePressed(RGFW_window* win, RGFW_mouseButton button) { +RGFW_bool RGFW_wasMousePressed(RGFW_window* win, RGFW_mouseButton button) { return RGFW_mouseButtons[button].prev && (win != NULL || win->event.inFocus); } -b8 RGFW_isMouseHeld(RGFW_window* win, RGFW_mouseButton button) { +RGFW_bool RGFW_isMouseHeld(RGFW_window* win, RGFW_mouseButton button) { return (RGFW_isMousePressed(win, button) && RGFW_wasMousePressed(win, button)); } -b8 RGFW_isMouseReleased(RGFW_window* win, RGFW_mouseButton button) { +RGFW_bool RGFW_isMouseReleased(RGFW_window* win, RGFW_mouseButton button) { return (!RGFW_isMousePressed(win, button) && RGFW_wasMousePressed(win, button)); } -b8 RGFW_isPressed(RGFW_window* win, RGFW_key key) { +RGFW_point RGFW_window_getMousePoint(RGFW_window* win) { + RGFW_ASSERT(win != NULL); + return win->_lastMousePoint; +} + +RGFW_bool RGFW_isPressed(RGFW_window* win, RGFW_key key) { return RGFW_keyboard[key].current && (win == NULL || win->event.inFocus); } -b8 RGFW_wasPressed(RGFW_window* win, RGFW_key key) { +RGFW_bool RGFW_wasPressed(RGFW_window* win, RGFW_key key) { return RGFW_keyboard[key].prev && (win == NULL || win->event.inFocus); } -b8 RGFW_isHeld(RGFW_window* win, RGFW_key key) { +RGFW_bool RGFW_isHeld(RGFW_window* win, RGFW_key key) { return (RGFW_isPressed(win, key) && RGFW_wasPressed(win, key)); } -b8 RGFW_isClicked(RGFW_window* win, RGFW_key key) { +RGFW_bool RGFW_isClicked(RGFW_window* win, RGFW_key key) { return (RGFW_wasPressed(win, key) && !RGFW_isPressed(win, key)); } -b8 RGFW_isReleased(RGFW_window* win, RGFW_key key) { +RGFW_bool RGFW_isReleased(RGFW_window* win, RGFW_key key) { return (!RGFW_isPressed(win, key) && RGFW_wasPressed(win, key)); } -#if defined(RGFW_WINDOWS) && defined(RGFW_DIRECTX) /* defines for directX context*/ - RGFW_directXinfo RGFW_dxInfo; - RGFW_directXinfo* RGFW_getDirectXInfo(void) { return &RGFW_dxInfo; } -#endif - #ifndef RGFW_CUSTOM_BACKEND void RGFW_window_makeCurrent(RGFW_window* win) { -#if defined(RGFW_WINDOWS) && defined(RGFW_DIRECTX) - if (win == NULL) - RGFW_dxInfo.pDeviceContext->lpVtbl->OMSetRenderTargets(RGFW_dxInfo.pDeviceContext, 1, NULL, NULL); - else - RGFW_dxInfo.pDeviceContext->lpVtbl->OMSetRenderTargets(RGFW_dxInfo.pDeviceContext, 1, &win->src.renderTargetView, NULL); -#elif defined(RGFW_OPENGL) +#if defined(RGFW_OPENGL) RGFW_window_makeCurrent_OpenGL(win); #else RGFW_UNUSED(win); @@ -1880,32 +1883,53 @@ void RGFW_window_makeCurrent(RGFW_window* win) { } #endif -void RGFW_window_setGPURender(RGFW_window* win, i8 set) { - if (!set && !(win->_flags & RGFW_NO_GPU_RENDER)) - win->_flags |= RGFW_NO_GPU_RENDER; +RGFWDEF void RGFW_setBit(u32* data, u32 bit, RGFW_bool value); +void RGFW_setBit(u32* data, u32 bit, RGFW_bool value) { + if (value) + *data |= bit; + else if (!value && (*(data) & bit)) + *data ^= bit; +} - else if (set && win->_flags & RGFW_NO_GPU_RENDER) - win->_flags ^= RGFW_NO_GPU_RENDER; +void RGFW_window_setGPURender(RGFW_window* win, RGFW_bool set) { + RGFW_setBit(&win->_flags, RGFW_NO_GPU_RENDER, !set); } -void RGFW_window_setCPURender(RGFW_window* win, i8 set) { - if (!set && !(win->_flags & RGFW_NO_CPU_RENDER)) - win->_flags |= RGFW_NO_CPU_RENDER; +void RGFW_window_setCPURender(RGFW_window* win, RGFW_bool set) { + RGFW_setBit(&win->_flags, RGFW_NO_CPU_RENDER, !set); +} - else if (set && win->_flags & RGFW_NO_CPU_RENDER) - win->_flags ^= RGFW_NO_CPU_RENDER; +void RGFW_window_center(RGFW_window* win) { + RGFW_ASSERT(win != NULL); + RGFW_area screenR = RGFW_getScreenSize(); + RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2)); } -void RGFW_window_maximize(RGFW_window* win) { +RGFW_bool RGFW_monitor_scaleToWindow(RGFW_monitor mon, RGFW_window* win) { RGFW_ASSERT(win != NULL); - RGFW_area screen = RGFW_getScreenSize(); + RGFW_monitorMode mode; + mode.area = RGFW_AREA(win->r.w, win->r.h); + return RGFW_monitor_requestMode(mon, mode, RGFW_monitorScale); +} - RGFW_window_move(win, RGFW_POINT(0, 0)); - RGFW_window_resize(win, screen); + +void RGFW_splitBPP(u32 bpp, RGFW_monitorMode* mode) { + if (bpp == 32) bpp = 24; + mode->red = mode->green = mode->blue = bpp / 3; + + u32 delta = bpp - (mode->red * 3); // handle leftovers + if (delta >= 1) mode->green = mode->green + 1; + if (delta == 2) mode->red = mode->red + 1; } -b8 RGFW_window_shouldClose(RGFW_window* win) { +RGFW_bool RGFW_monitorModeCompare(RGFW_monitorMode mon, RGFW_monitorMode mon2, RGFW_modeRequest request) { + return (((mon.area.w == mon2.area.w && mon.area.h == mon2.area.h) || !(request & RGFW_monitorScale)) && + ((mon.refreshRate == mon2.refreshRate) || !(request & RGFW_monitorRefresh)) && + ((mon.red == mon2.red && mon.green == mon2.green && mon.blue == mon2.blue) || !(request & RGFW_monitorRGB))); +} + +RGFW_bool RGFW_window_shouldClose(RGFW_window* win) { RGFW_ASSERT(win != NULL); return (win->event.type == RGFW_quit || RGFW_isPressed(win, RGFW_escape)); } @@ -1915,12 +1939,14 @@ void RGFW_window_setShouldClose(RGFW_window* win) { win->event.type = RGFW_quit; #ifndef RGFW_NO_MONITOR void RGFW_window_scaleToMonitor(RGFW_window* win) { RGFW_monitor monitor = RGFW_window_getMonitor(win); + if (monitor.scaleX == 0 && monitor.scaleY == 0) + return; RGFW_window_resize(win, RGFW_AREA((u32)(monitor.scaleX * (float)win->r.w), (u32)(monitor.scaleY * (float)win->r.h))); } void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m) { - RGFW_window_move(win, RGFW_POINT(m.rect.x + win->r.x, m.rect.y + win->r.y)); + RGFW_window_move(win, RGFW_POINT(m.x + win->r.x, m.y + win->r.y)); } #endif @@ -1931,7 +1957,6 @@ void RGFW_window_mouseHold(RGFW_window* win, RGFW_area area) { if ((win->_flags & RGFW_HOLD_MOUSE)) return; - if (!area.w && !area.h) area = RGFW_AREA(win->r.w / 2, win->r.h / 2); @@ -1941,11 +1966,8 @@ void RGFW_window_mouseHold(RGFW_window* win, RGFW_area area) { } void RGFW_window_mouseUnhold(RGFW_window* win) { - if ((win->_flags & RGFW_HOLD_MOUSE)) { - win->_flags ^= RGFW_HOLD_MOUSE; - - RGFW_releaseCursor(win); - } + win->_flags &= ~RGFW_HOLD_MOUSE; + RGFW_releaseCursor(win); } u32 RGFW_window_checkFPS(RGFW_window* win, u32 fpsCap) { @@ -2013,43 +2035,57 @@ RGFW_gamepadType RGFW_getGamepadType(RGFW_window* win, u16 controller) { return RGFW_gamepads_type[controller]; } -#if defined(RGFW_X11) || defined(RGFW_WINDOWS) -void RGFW_window_showMouse(RGFW_window* win, i8 show) { - if (show == 0) - RGFW_window_setMouse(win, RGFW_hiddenMouse); - else - RGFW_window_setMouseDefault(win); -} -#endif - -RGFWDEF void RGFW_updateKeyMod(RGFW_window* win, RGFW_keymod mod, b8 value); -void RGFW_updateKeyMod(RGFW_window* win, RGFW_keymod mod, b8 value) { - if (value && !(win->event.keyMod & mod)) - win->event.keyMod |= mod; - else if (!value && ((win->event.keyMod & mod))) - win->event.keyMod ^= mod; +RGFWDEF void RGFW_updateKeyMod(RGFW_window* win, RGFW_keymod mod, RGFW_bool value); +void RGFW_updateKeyMod(RGFW_window* win, RGFW_keymod mod, RGFW_bool value) { + RGFW_setBit((u32*)&win->event.keyMod, mod, value); } -RGFWDEF void RGFW_updateKeyModsPro(RGFW_window* win, b8 capital, b8 numlock, b8 control, b8 alt, b8 shift, b8 super); -void RGFW_updateKeyModsPro(RGFW_window* win, b8 capital, b8 numlock, b8 control, b8 alt, b8 shift, b8 super) { +RGFWDEF void RGFW_updateKeyModsPro(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll); +void RGFW_updateKeyModsPro(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll) { RGFW_updateKeyMod(win, RGFW_modCapsLock, capital); RGFW_updateKeyMod(win, RGFW_modNumLock, numlock); RGFW_updateKeyMod(win, RGFW_modControl, control); RGFW_updateKeyMod(win, RGFW_modAlt, alt); RGFW_updateKeyMod(win, RGFW_modShift, shift); RGFW_updateKeyMod(win, RGFW_modSuper, super); + RGFW_updateKeyMod(win, RGFW_modScrollLock, scroll); } -RGFWDEF void RGFW_updateKeyMods(RGFW_window* win, b8 capital, b8 numlock); -void RGFW_updateKeyMods(RGFW_window* win, b8 capital, b8 numlock) { +RGFWDEF void RGFW_updateKeyMods(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool scroll); +void RGFW_updateKeyMods(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool scroll) { RGFW_updateKeyModsPro(win, capital, numlock, RGFW_isPressed(win, RGFW_controlL) || RGFW_isPressed(win, RGFW_controlR), RGFW_isPressed(win, RGFW_altL) || RGFW_isPressed(win, RGFW_altR), RGFW_isPressed(win, RGFW_shiftL) || RGFW_isPressed(win, RGFW_shiftR), - RGFW_isPressed(win, RGFW_superL) || RGFW_isPressed(win, RGFW_superR)); + RGFW_isPressed(win, RGFW_superL) || RGFW_isPressed(win, RGFW_superR), + scroll); +} + +RGFWDEF void RGFW_window_showMouseFlags(RGFW_window* win, RGFW_bool show); +void RGFW_window_showMouseFlags(RGFW_window* win, RGFW_bool show) { + if (show && (win->_flags & RGFW_windowHideMouse)) + win->_flags ^= RGFW_windowHideMouse; + else if (!show && !(win->_flags & RGFW_windowHideMouse)) + win->_flags |= RGFW_windowHideMouse; +} + +RGFW_bool RGFW_window_mouseHidden(RGFW_window* win) { + return (RGFW_bool)RGFW_BOOL(win->_flags & RGFW_windowHideMouse); +} + +RGFW_bool RGFW_window_borderless(RGFW_window* win) { + return (RGFW_bool)RGFW_BOOL(win->_flags & RGFW_windowNoBorder); } -#if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WEBASM) || defined(RGFW_WAYLAND) +RGFW_bool RGFW_window_isFullscreen(RGFW_window* win){ return RGFW_BOOL(win->_flags & RGFW_windowFullscreen); } +RGFW_bool RGFW_window_allowsDND(RGFW_window* win) { return RGFW_BOOL(win->_flags & RGFW_windowAllowDND); } +#ifndef RGFW_WINDOWS +void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow) { + RGFW_setBit(&win->_flags, RGFW_windowAllowDND, allow); +} +#endif + +#if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WASM) || defined(RGFW_WAYLAND) #include struct timespec; @@ -2059,16 +2095,22 @@ int clock_gettime(clockid_t clk_id, struct timespec* tp); #endif int setenv(const char *name, const char *value, int overwrite); +#endif -void RGFW_window_setDND(RGFW_window* win, b8 allow) { - if (allow && !(win->_flags & RGFW_windowAllowDND)) - win->_flags |= RGFW_windowAllowDND; - - else if (!allow && (win->_flags & RGFW_windowAllowDND)) - win->_flags ^= RGFW_windowAllowDND; +#if defined(RGFW_X11) || defined(RGFW_WINDOWS) +void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) { + RGFW_window_showMouseFlags(win, show); + if (show == 0) + RGFW_window_setMouse(win, RGFW_hiddenMouse); + else + RGFW_window_setMouseDefault(win); } #endif +#ifndef RGFW_MACOS +void RGFW_moveToMacOSResourceDir(void) { } +#endif + /* graphics API specific code (end of generic code) starts here @@ -2098,25 +2140,15 @@ void RGFW_window_setDND(RGFW_window* win, b8 allow) { #endif /* EGL, normal OpenGL only */ -i32 RGFW_majorVersion = 0, RGFW_minorVersion = 0; -b8 RGFW_profile = RGFW_glCore; - #ifndef RGFW_EGL -i32 RGFW_STENCIL = 8, RGFW_SAMPLES = 4, RGFW_STEREO = 0, RGFW_AUX_BUFFERS = 0, RGFW_DOUBLE_BUFFER = 1; +i32 RGFW_GL_HINTS[RGFW_glFinalHint] = {8, 4, #else -i32 RGFW_STENCIL = 0, RGFW_SAMPLES = 0, RGFW_STEREO = 0, RGFW_AUX_BUFFERS = 0, RGFW_DOUBLE_BUFFER = 1; +i32 RGFW_GL_HINTS[RGFW_glFinalHint] = {0, 0, #endif + 0, 0, 1, 8, 8, 8, 8, 24, 0, 0, 0, 0, 0, 0, 0, 0, RGFW_glReleaseNone, RGFW_glCore, 0, 0}; -void RGFW_setGLStencil(i32 stencil) { RGFW_STENCIL = stencil; } -void RGFW_setGLSamples(i32 samples) { RGFW_SAMPLES = samples; } -void RGFW_setGLStereo(i32 stereo) { RGFW_STEREO = stereo; } -void RGFW_setGLAuxBuffers(i32 auxBuffers) { RGFW_AUX_BUFFERS = auxBuffers; } -void RGFW_setDoubleBuffer(b8 useDoubleBuffer) { RGFW_DOUBLE_BUFFER = useDoubleBuffer; } - -void RGFW_setGLVersion(b8 profile, i32 major, i32 minor) { - RGFW_profile = profile; - RGFW_majorVersion = major; - RGFW_minorVersion = minor; +void RGFW_setGLHint(RGFW_glHints hint, i32 value) { + if (hint < RGFW_glFinalHint && hint) RGFW_GL_HINTS[hint] = value; } /* OPENGL normal only (no EGL / OSMesa) */ @@ -2139,6 +2171,19 @@ void RGFW_setGLVersion(b8 profile, i32 major, i32 minor) { #define RGFW_GL_GREEN_SIZE RGFW_OS_BASED_VALUE(GLX_GREEN_SIZE, 0x2017, 0, 0) #define RGFW_GL_BLUE_SIZE RGFW_OS_BASED_VALUE(GLX_BLUE_SIZE, 0x2019, 0, 0) #define RGFW_GL_USE_RGBA RGFW_OS_BASED_VALUE(GLX_RGBA_BIT, 0x202B, 0, 0) + #define RGFW_GL_ACCUM_RED_SIZE RGFW_OS_BASED_VALUE(14, 0x201E, 0, 0) + #define RGFW_GL_ACCUM_GREEN_SIZE RGFW_OS_BASED_VALUE(15, 0x201F, 0, 0) + #define RGFW_GL_ACCUM_BLUE_SIZE RGFW_OS_BASED_VALUE(16, 0x2020, 0, 0) + #define RGFW_GL_ACCUM_ALPHA_SIZE RGFW_OS_BASED_VALUE(17, 0x2021, 0, 0) + #define RGFW_GL_SRGB RGFW_OS_BASED_VALUE(0x20b2, 0x3089, 0, 0) + #define RGFW_GL_NOERROR RGFW_OS_BASED_VALUE(0x31b3, 0x31b3, 0, 0) + #define RGFW_GL_FLAGS RGFW_OS_BASED_VALUE(GLX_CONTEXT_FLAGS_ARB, 0x2094, 0, 0) + #define RGFW_GL_RELEASE_BEHAVIOR RGFW_OS_BASED_VALUE(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, 0x2097 , 0, 0) + #define RGFW_GL_CONTEXT_RELEASE RGFW_OS_BASED_VALUE(GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB, 0x2098, 0, 0) + #define RGFW_GL_CONTEXT_NONE RGFW_OS_BASED_VALUE(GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB, 0x0000, 0, 0) + #define RGFW_GL_FLAGS RGFW_OS_BASED_VALUE(GLX_CONTEXT_FLAGS_ARB, 0x2094, 0, 0) + #define RGFW_GL_DEBUG_BIT RGFW_OS_BASED_VALUE(GLX_CONTEXT_FLAGS_ARB, 0x2094, 0, 0) + #define RGFW_GL_ROBUST_BIT RGFW_OS_BASED_VALUE(GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB, 0x00000004, 0, 0) #endif #ifdef RGFW_WINDOWS @@ -2168,14 +2213,7 @@ u32* RGFW_initFormatAttribs(u32 useSoftware) { #if defined(RGFW_X11) || defined(RGFW_WINDOWS) RGFW_GL_RENDER_TYPE, RGFW_GL_FULL_FORMAT, - #endif - RGFW_GL_ALPHA_SIZE , 8, - RGFW_GL_DEPTH_SIZE , 24, - #if defined(RGFW_X11) || defined(RGFW_WINDOWS) RGFW_GL_DRAW, 1, - RGFW_GL_RED_SIZE , 8, - RGFW_GL_GREEN_SIZE , 8, - RGFW_GL_BLUE_SIZE , 8, RGFW_GL_DRAW_TYPE , RGFW_GL_USE_RGBA, #endif @@ -2193,11 +2231,10 @@ u32* RGFW_initFormatAttribs(u32 useSoftware) { WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, WGL_COLOR_BITS_ARB, 32, #endif - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - size_t index = (sizeof(attribs) / sizeof(attribs[0])) - 13; + size_t index = (sizeof(attribs) / sizeof(attribs[0])) - 27; #define RGFW_GL_ADD_ATTRIB(attrib, attVal) \ if (attVal) { \ @@ -2206,14 +2243,49 @@ u32* RGFW_initFormatAttribs(u32 useSoftware) { index += 2;\ } + #if defined(RGFW_MACOS) && defined(RGFW_COCOA_GRAPHICS_SWITCHING) + RGFW_GL_ADD_ATTRIB(96, kCGLPFASupportsAutomaticGraphicsSwitching); + #endif + RGFW_GL_ADD_ATTRIB(RGFW_GL_DOUBLEBUFFER, 1); + + RGFW_GL_ADD_ATTRIB(RGFW_GL_ALPHA_SIZE, RGFW_GL_HINTS[RGFW_glAlpha]); + RGFW_GL_ADD_ATTRIB(RGFW_GL_DEPTH_SIZE, RGFW_GL_HINTS[RGFW_glDepth]); + RGFW_GL_ADD_ATTRIB(RGFW_GL_STENCIL_SIZE, RGFW_GL_HINTS[RGFW_glStencil]); + RGFW_GL_ADD_ATTRIB(RGFW_GL_STEREO, RGFW_GL_HINTS[RGFW_glStereo]); + RGFW_GL_ADD_ATTRIB(RGFW_GL_AUX_BUFFERS, RGFW_GL_HINTS[RGFW_glAuxBuffers]); + + #if defined(RGFW_X11) || defined(RGFW_WINDOWS) + RGFW_GL_ADD_ATTRIB(RGFW_GL_RED_SIZE, RGFW_GL_HINTS[RGFW_glRed]); + RGFW_GL_ADD_ATTRIB(RGFW_GL_GREEN_SIZE, RGFW_GL_HINTS[RGFW_glBlue]); + RGFW_GL_ADD_ATTRIB(RGFW_GL_BLUE_SIZE, RGFW_GL_HINTS[RGFW_glGreen]); + #endif - RGFW_GL_ADD_ATTRIB(RGFW_GL_STENCIL_SIZE, RGFW_STENCIL); - RGFW_GL_ADD_ATTRIB(RGFW_GL_STEREO, RGFW_STEREO); - RGFW_GL_ADD_ATTRIB(RGFW_GL_AUX_BUFFERS, RGFW_AUX_BUFFERS); + #if defined(RGFW_X11) || defined(RGFW_WINDOWS) + RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_RED_SIZE, RGFW_GL_HINTS[RGFW_glAccumRed]); + RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_GREEN_SIZE, RGFW_GL_HINTS[RGFW_glAccumBlue]); + RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_BLUE_SIZE, RGFW_GL_HINTS[RGFW_glAccumGreen]); + RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_ALPHA_SIZE, RGFW_GL_HINTS[RGFW_glAccumAlpha]); + RGFW_GL_ADD_ATTRIB(RGFW_GL_SRGB, RGFW_GL_HINTS[RGFW_glSRGB]); + RGFW_GL_ADD_ATTRIB(RGFW_GL_NOERROR, RGFW_GL_HINTS[RGFW_glNoError]); + + if (RGFW_GL_HINTS[RGFW_glReleaseBehavior] == RGFW_releaseFlush) { + RGFW_GL_ADD_ATTRIB(RGFW_GL_RELEASE_BEHAVIOR, RGFW_GL_CONTEXT_RELEASE); + } else if (RGFW_GL_HINTS[RGFW_glReleaseBehavior] == RGFW_glReleaseNone) { + RGFW_GL_ADD_ATTRIB(RGFW_GL_RELEASE_BEHAVIOR, RGFW_GL_CONTEXT_NONE); + } + + u32 flags = 0; + if (RGFW_GL_HINTS[RGFW_glDebug]) flags |= RGFW_GL_DEBUG_BIT; + if (RGFW_GL_HINTS[RGFW_glRobustness]) flags |= RGFW_GL_ROBUST_BIT; + RGFW_GL_ADD_ATTRIB(RGFW_GL_FLAGS, flags); + #else + u32 accumSize = (RGFW_GL_HINTS[RGFW_glAccumRed] + RGFW_GL_HINTS[RGFW_glAccumGreen] + RGFW_GL_HINTS[RGFW_glAccumBlue] + RGFW_GL_HINTS[RGFW_glAccumAlpha]) / 4; + RGFW_GL_ADD_ATTRIB(14, accumSize); + #endif #ifndef RGFW_X11 - RGFW_GL_ADD_ATTRIB(RGFW_GL_SAMPLES, RGFW_SAMPLES); + RGFW_GL_ADD_ATTRIB(RGFW_GL_SAMPLES, RGFW_GL_HINTS[RGFW_glSamples]); #endif #ifdef RGFW_MACOS @@ -2232,8 +2304,9 @@ u32* RGFW_initFormatAttribs(u32 useSoftware) { attribs[index] = 99; attribs[index + 1] = 0x1000; - if (RGFW_majorVersion >= 4 || RGFW_majorVersion >= 3) { - attribs[index + 1] = (u32) ((RGFW_majorVersion >= 4) ? 0x4100 : 0x3200); + + if (RGFW_GL_HINTS[RGFW_glMinor] >= 4 || RGFW_GL_HINTS[RGFW_glMinor] >= 3) { + attribs[index + 1] = (u32) ((RGFW_GL_HINTS[RGFW_glMinor] >= 4) ? 0x4100 : 0x3200); } #endif @@ -2346,6 +2419,22 @@ void RGFW_createOpenGLContext(RGFW_window* win) { EGL_NONE, EGL_NONE }; + { + size_t index = 7; + EGLint* attribs = egl_config; + + RGFW_GL_ADD_ATTRIB(EGL_RED_SIZE, RGFW_GL_HINTS[RGFW_glRed]); + RGFW_GL_ADD_ATTRIB(EGL_GREEN_SIZE, RGFW_GL_HINTS[RGFW_glBlue]); + RGFW_GL_ADD_ATTRIB(EGL_BLUE_SIZE, RGFW_GL_HINTS[RGFW_glGreen]); + RGFW_GL_ADD_ATTRIB(EGL_ALPHA_SIZE, RGFW_GL_HINTS[RGFW_glAlpha]); + RGFW_GL_ADD_ATTRIB(EGL_DEPTH_SIZE, RGFW_GL_HINTS[RGFW_glDepth]); + + if (RGFW_GL_HINTS[RGFW_glSRGB]) + RGFW_GL_ADD_ATTRIB(0x3089, RGFW_GL_HINTS[RGFW_glSRGB]); + + RGFW_GL_ADD_ATTRIB(EGL_NONE, EGL_NONE); + } + EGLConfig config; EGLint numConfigs; eglChooseConfig(win->src.EGL_display, egl_config, &config, 1, &numConfigs); @@ -2357,7 +2446,7 @@ void RGFW_createOpenGLContext(RGFW_window* win) { win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) layer, NULL); #elif defined(RGFW_WINDOWS) - win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.hwnd, NULL); + win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL); #elif defined(RGFW_WAYLAND) if (RGFW_useWaylandBool) win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.eglWindow, NULL); @@ -2378,25 +2467,32 @@ void RGFW_createOpenGLContext(RGFW_window* win) { }; size_t index = 4; - RGFW_GL_ADD_ATTRIB(EGL_STENCIL_SIZE, RGFW_STENCIL); - RGFW_GL_ADD_ATTRIB(EGL_SAMPLES, RGFW_SAMPLES); + RGFW_GL_ADD_ATTRIB(EGL_STENCIL_SIZE, RGFW_GL_HINTS[RGFW_glStencil]); + RGFW_GL_ADD_ATTRIB(EGL_SAMPLES, RGFW_GL_HINTS[RGFW_glSamples]); - if (RGFW_DOUBLE_BUFFER) + if (RGFW_GL_HINTS[RGFW_glDoubleBuffer]) RGFW_GL_ADD_ATTRIB(EGL_RENDER_BUFFER, EGL_BACK_BUFFER); - if (RGFW_majorVersion) { - attribs[1] = RGFW_majorVersion; + if (RGFW_GL_HINTS[RGFW_glMinor]) { + attribs[1] = RGFW_GL_HINTS[RGFW_glMinor]; - RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_MAJOR_VERSION, RGFW_majorVersion); - RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_MINOR_VERSION, RGFW_minorVersion); + RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_MAJOR_VERSION, RGFW_GL_HINTS[RGFW_glMinor]); + RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_MINOR_VERSION, RGFW_GL_HINTS[RGFW_glMajor]); - if (RGFW_profile == RGFW_glCore) { + if (RGFW_GL_HINTS[RGFW_glProfile] == RGFW_glCore) { RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT); } else { RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT); } + } + RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_ROBUST_ACCESS, RGFW_GL_HINTS[RGFW_glRobustness]); + RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_DEBUG, RGFW_GL_HINTS[RGFW_glDebug]); + if (RGFW_GL_HINTS[RGFW_glReleaseBehavior] == RGFW_releaseFlush) { + RGFW_GL_ADD_ATTRIB(0x2097, 0x2098); + } else { + RGFW_GL_ADD_ATTRIB(0x2097, 0x0000); } #if defined(RGFW_OPENGL_ES1) || defined(RGFW_OPENGL_ES2) || defined(RGFW_OPENGL_ES3) @@ -2420,6 +2516,8 @@ void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { eglMakeCurrent(win->src.EGL_display, win->src.EGL_surface, win->src.EGL_surface, win->src.EGL_context); } +void* RGFW_getCurrent_OpenGL(void) { return eglGetCurrentContext(); } + #ifdef RGFW_APPLE void* RGFWnsglFramework = NULL; #elif defined(RGFW_WINDOWS) @@ -2456,7 +2554,33 @@ void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { /* end of RGFW_EGL defines */ -#endif /* RGFW_GL (OpenGL, EGL, OSMesa )*/ +/* end of RGFW_GL (OpenGL, EGL, OSMesa )*/ + +/* + RGFW_VULKAN defines +*/ +#elif defined(RGFW_VULKAN) + +VkResult RGFW_window_createVKSurface(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface) { + assert(win != NULL); assert(instance); + assert(surface != NULL); + + *surface = VK_NULL_HANDLE; + +#ifdef RGFW_X11 + VkXlibSurfaceCreateInfoKHR x11 = { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, 0, 0, (Display*) win->src.display, (Window) win->src.window }; + return vkCreateXlibSurfaceKHR(instance, &x11, NULL, surface); +#elif defined(RGFW_WINDOWS) + VkWin32SurfaceCreateInfoKHR win32 = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, 0, 0, GetModuleHandle(NULL), (HWND)win->src.window }; + + return vkCreateWin32SurfaceKHR(instance, &win32, NULL, surface); +#elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11) + VkMacOSSurfaceCreateFlagsMVK macos = { VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK, 0, 0, vulkWin->display, (void *)win->src.window }; + + return vkCreateMacOSSurfaceMVK(instance, &macos, NULL, surface); +#endif +} +#endif /* end of RGFW_vulkan */ /* This is where OS specific stuff starts @@ -2635,11 +2759,11 @@ This is where OS specific stuff starts #ifdef RGFW_WAYLAND /* -Wayland TODO: +Wayland TODO: (out of date) - fix RGFW_keyPressed lock state RGFW_windowMoved, the window was moved (by the user) - RGFW_windowResized the window was resized (by the user), [on webASM this means the browser was resized] + RGFW_windowResized the window was resized (by the user), [on WASM this means the browser was resized] RGFW_windowRefresh The window content needs to be refreshed RGFW_DND a file has been dropped into the window @@ -2716,7 +2840,7 @@ static const struct xdg_wm_base_listener xdg_wm_base_listener = { .ping = xdg_wm_base_ping_handler, }; -b8 RGFW_wl_configured = 0; +RGFW_bool RGFW_wl_configured = 0; static void xdg_surface_configure_handler(void *data, struct xdg_surface *xdg_surface, uint32_t serial) @@ -2815,7 +2939,7 @@ static void pointer_motion(void *data, struct wl_pointer *pointer, uint32_t time ev.point = RGFW_POINT(wl_fixed_to_double(x), wl_fixed_to_double(y)); RGFW_eventPipe_push(RGFW_mouse_win, ev); - RGFW_mousePosCallback(RGFW_mouse_win, RGFW_POINT(wl_fixed_to_double(x), wl_fixed_to_double(y))); + RGFW_mousePosCallback(RGFW_mouse_win, RGFW_POINT(wl_fixed_to_double(x), wl_fixed_to_double(y)), ev.vector); } static void pointer_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(serial); @@ -2913,7 +3037,7 @@ static void keyboard_key (void *data, struct wl_keyboard *keyboard, uint32_t ser ev.repeat = RGFW_isHeld(RGFW_key_win, RGFW_key); RGFW_eventPipe_push(RGFW_key_win, ev); - RGFW_updateKeyMods(RGFW_key_win, xkb_keymap_mod_get_index(keymap, "Lock"), xkb_keymap_mod_get_index(keymap, "Mod2")); + RGFW_updateKeyMods(RGFW_key_win, xkb_keymap_mod_get_index(keymap, "Lock"), xkb_keymap_mod_get_index(keymap, "Mod2"), , xkb_keymap_mod_get_index(keymap, "ScrollLock")); RGFW_keyCallback(RGFW_key_win, RGFW_key, (u8)keysym, RGFW_key_win->event.keyMod, state); } @@ -3071,11 +3195,11 @@ static const struct wl_callback_listener wl_surface_frame_listener = { }; #endif /* RGFW_WAYLAND */ #if !defined(RGFW_NO_X11) && defined(RGFW_WAYLAND) -void RGFW_useWayland(b8 wayland) { RGFW_useWaylandBool = wayland; } +void RGFW_useWayland(RGFW_bool wayland) { RGFW_useWaylandBool = wayland; } #define RGFW_GOTO_WAYLAND(fallback) if (RGFW_useWaylandBool && fallback == 0) goto wayland #else #define RGFW_GOTO_WAYLAND(fallback) -void RGFW_useWayland(b8 wayland) { RGFW_UNUSED(wayland); } +void RGFW_useWayland(RGFW_bool wayland) { RGFW_UNUSED(wayland); } #endif /* @@ -3121,9 +3245,8 @@ Start of Linux / Unix defines #include #endif -u8 RGFW_mouseIconSrc[] = { XC_arrow, XC_left_ptr, XC_xterm, XC_crosshair, XC_hand2, XC_sb_h_double_arrow, XC_sb_v_double_arrow, XC_bottom_left_corner, XC_bottom_right_corner, XC_fleur, XC_X_cursor}; /*atoms needed for drag and drop*/ -Atom XdndAware, XdndTypeList, XdndSelection, XdndEnter, XdndPosition, XdndStatus, XdndLeave, XdndDrop, XdndFinished, XdndActionCopy, XtextPlain, XtextUriList; +Atom XdndAware, XtextPlain, XtextUriList; Atom RGFW_XUTF8_STRING = 0; Atom wm_delete_window = 0, RGFW_XCLIPBOARD = 0; @@ -3157,37 +3280,34 @@ Atom wm_delete_window = 0, RGFW_XCLIPBOARD = 0; void* X11Cursorhandle = NULL; #endif -u32 RGFW_windowsOpen = 0; +const char* RGFW_instName = NULL; +void RGFW_setXInstName(const char* name) { + RGFW_instName = name; +} #if defined(RGFW_OPENGL) && !defined(RGFW_EGL) void* RGFW_getProcAddress(const char* procname) { return (void*) glXGetProcAddress((GLubyte*) procname); } #endif -RGFWDEF void RGFW_init_buffer(RGFW_window* win, XVisualInfo* vi); -void RGFW_init_buffer(RGFW_window* win, XVisualInfo* vi) { +void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area) { RGFW_GOTO_WAYLAND(0); #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - #ifdef RGFW_X11 - if (RGFW_bufferSize.w == 0 && RGFW_bufferSize.h == 0) - RGFW_bufferSize = RGFW_getScreenSize(); - - win->buffer = (u8*)RGFW_alloc(RGFW_bufferSize.w * RGFW_bufferSize.h * 4); - win->_flags |= RGFW_BUFFER_ALLOC; - - #ifdef RGFW_DEBUG - printf("RGFW INFO: createing a 4 channel %i by %i buffer\n", RGFW_bufferSize.w, RGFW_bufferSize.h); - #endif + win->buffer = (u8*)buffer; + win->bufferSize = area; + #ifdef RGFW_DEBUG + printf("RGFW INFO: createing a 4 channel %i by %i buffer\n", area.w, area.h); + #endif + #ifdef RGFW_X11 #ifdef RGFW_OSMESA win->src.ctx = OSMesaCreateContext(OSMESA_BGRA, NULL); - OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, RGFW_bufferSize.w, RGFW_bufferSize.h); + OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h); #endif win->src.bitmap = XCreateImage( - win->src.display, XDefaultVisual(win->src.display, vi->screen), - vi->depth, - ZPixmap, 0, NULL, RGFW_bufferSize.w, RGFW_bufferSize.h, + win->src.display, XDefaultVisual(win->src.display, XDefaultScreen(win->src.display)), + 32, ZPixmap, 0, NULL, area.w, area.h, 32, 0 ); @@ -3200,12 +3320,7 @@ void RGFW_init_buffer(RGFW_window* win, XVisualInfo* vi) { if (fd < 0) { fprintf(stderr, "Failed to create a buffer. size: %ld\n", size); exit(1); - } - if (RGFW_bufferSize.w == 0 && RGFW_bufferSize.h == 0) - RGFW_bufferSize = RGFW_getScreenSize(); - - win->buffer = (u8*)RGFW_alloc(RGFW_bufferSize.w * RGFW_bufferSize.h * 4); win->src.buffer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (win->src.buffer == MAP_FAILED) { fprintf(stderr, "mmap failed!\n"); @@ -3217,7 +3332,7 @@ void RGFW_init_buffer(RGFW_window* win, XVisualInfo* vi) { struct wl_shm_pool* pool = wl_shm_create_pool(win->src.shm, fd, size); win->src.wl_buffer = wl_shm_pool_create_buffer(pool, 0, win->r.w, win->r.h, win->r.w * 4, - WL_SHM_FORMAT_ARGB8888); + WL_SHM_FORMAT_ARGRGFW_bool888); wl_shm_pool_destroy(pool); close(fd); @@ -3228,7 +3343,7 @@ void RGFW_init_buffer(RGFW_window* win, XVisualInfo* vi) { u8 color[] = {0x00, 0x00, 0x00, 0xFF}; size_t i; - for (i = 0; i < RGFW_bufferSize.w * RGFW_bufferSize.h * 4; i += 4) { + for (i = 0; i < area.w * area.h * 4; i += 4) { RGFW_MEMCPY(&win->buffer[i], color, 4); } @@ -3236,13 +3351,12 @@ void RGFW_init_buffer(RGFW_window* win, XVisualInfo* vi) { #if defined(RGFW_OSMESA) win->src.ctx = OSMesaCreateContext(OSMESA_BGRA, NULL); - OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, RGFW_bufferSize.w, RGFW_bufferSize.h); + OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h); #endif #endif #else wayland: - RGFW_UNUSED(win); - RGFW_UNUSED(vi); + RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area); #endif } @@ -3250,7 +3364,9 @@ void RGFW_init_buffer(RGFW_window* win, XVisualInfo* vi) { static Atom name = 0; \ if (name == 0) name = XInternAtom(RGFW_root->src.display, #name, False); -void RGFW_window_setBorder(RGFW_window* win, u8 border) { +void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { + RGFW_setBit(&win->_flags, RGFW_windowNoBorder, !border); + RGFW_GOTO_WAYLAND(0); #ifdef RGFW_X11 RGFW_LOAD_ATOM(_MOTIF_WM_HINTS); @@ -3259,14 +3375,18 @@ void RGFW_window_setBorder(RGFW_window* win, u8 border) { unsigned long flags, functions, decorations, status; long input_mode; } hints; - hints.flags = (1L << 1); + hints.flags = 2; hints.decorations = border; - XChangeProperty( - win->src.display, win->src.window, - _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, - 32, PropModeReplace, (u8*)&hints, 5 + XChangeProperty(win->src.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); + } + #endif #ifdef RGFW_WAYLAND wayland: @@ -3359,7 +3479,7 @@ RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowF RGFW_GOTO_WAYLAND(0); #ifdef RGFW_X11 u64 event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | FocusChangeMask | LeaveWindowMask | EnterWindowMask | ExposureMask; /*!< X11 events accepted*/ - + #if defined(RGFW_OPENGL) && !defined(RGFW_EGL) u32* visual_attribs = (u32*)RGFW_initFormatAttribs(flags & RGFW_windowOpenglSoftware); i32 fbcount; @@ -3387,7 +3507,7 @@ RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowF glXGetFBConfigAttrib(win->src.display, fbc[i], GLX_SAMPLES, &samples); if ((!(flags & RGFW_windowTransparent) || vi->depth == 32) && - (best_fbc < 0 || samp_buf) && (samples == RGFW_SAMPLES || best_fbc == -1)) { + (best_fbc < 0 || samp_buf) && (samples == RGFW_GL_HINTS[RGFW_glSamples] || best_fbc == -1)) { best_fbc = i; } } @@ -3449,23 +3569,24 @@ RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowF XClassHint hint; hint.res_class = (char*)RGFW_className; - hint.res_name = (char*)name; // just use the window name as the app name + if (RGFW_instName == NULL) hint.res_name = (char*)name; + else hint.res_name = (char*)RGFW_instName; XSetClassHint(win->src.display, win->src.window, &hint); if ((flags & RGFW_windowNoInitAPI) == 0) { #if defined(RGFW_OPENGL) && !defined(RGFW_EGL) /* This is the second part of setting up opengl. This is where we ask OpenGL for a specific version. */ i32 context_attribs[7] = { 0, 0, 0, 0, 0, 0, 0 }; context_attribs[0] = GLX_CONTEXT_PROFILE_MASK_ARB; - if (RGFW_profile == RGFW_glCore) + if (RGFW_GL_HINTS[RGFW_glProfile] == RGFW_glCore) context_attribs[1] = GLX_CONTEXT_CORE_PROFILE_BIT_ARB; else context_attribs[1] = GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; - if (RGFW_majorVersion || RGFW_minorVersion) { + if (RGFW_GL_HINTS[RGFW_glMinor] || RGFW_GL_HINTS[RGFW_glMajor]) { context_attribs[2] = GLX_CONTEXT_MAJOR_VERSION_ARB; - context_attribs[3] = RGFW_majorVersion; + context_attribs[3] = RGFW_GL_HINTS[RGFW_glMinor]; context_attribs[4] = GLX_CONTEXT_MINOR_VERSION_ARB; - context_attribs[5] = RGFW_minorVersion; + context_attribs[5] = RGFW_GL_HINTS[RGFW_glMajor]; } glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0; @@ -3474,13 +3595,11 @@ RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowF GLXContext ctx = NULL; - if (RGFW_root != NULL) + if (RGFW_root != NULL && RGFW_root != win) ctx = RGFW_root->src.ctx; win->src.ctx = glXCreateContextAttribsARB(win->src.display, bestFbc, ctx, True, context_attribs); #endif - - RGFW_init_buffer(win, vi); } #ifndef RGFW_NO_MONITOR @@ -3488,11 +3607,6 @@ RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowF RGFW_window_scaleToMonitor(win); #endif - if (flags & RGFW_windowCenter) { - RGFW_area screenR = RGFW_getScreenSize(); - RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2)); - } - if (flags & RGFW_windowNoResize) { /* make it so the user can't resize the window*/ XSizeHints sh; sh.flags = (1L << 4) | (1L << 5); @@ -3504,10 +3618,6 @@ RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowF win->_flags |= RGFW_windowNoResize; } - if (flags & RGFW_windowNoBorder) { - RGFW_window_setBorder(win, 0); - } - XSelectInput(win->src.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*/ @@ -3534,23 +3644,9 @@ RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowF if (flags & RGFW_windowAllowDND) { /* init drag and drop atoms and turn on drag and drop for this window */ win->_flags |= RGFW_windowAllowDND; - XdndTypeList = XInternAtom(win->src.display, "XdndTypeList", False); - XdndSelection = XInternAtom(win->src.display, "XdndSelection", False); - - /* client messages */ - XdndEnter = XInternAtom(win->src.display, "XdndEnter", False); - XdndPosition = XInternAtom(win->src.display, "XdndPosition", False); - XdndStatus = XInternAtom(win->src.display, "XdndStatus", False); - XdndLeave = XInternAtom(win->src.display, "XdndLeave", False); - XdndDrop = XInternAtom(win->src.display, "XdndDrop", False); - XdndFinished = XInternAtom(win->src.display, "XdndFinished", False); - /* actions */ - XdndActionCopy = XInternAtom(win->src.display, "XdndActionCopy", False); - XtextUriList = XInternAtom(win->src.display, "text/uri-list", False); XtextPlain = XInternAtom(win->src.display, "text/plain", False); - XdndAware = XInternAtom(win->src.display, "XdndAware", False); const u8 version = 5; @@ -3567,7 +3663,8 @@ RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowF printf("RGFW INFO: a window with a rect of {%i, %i, %i, %i} \n", win->r.x, win->r.y, win->r.w, win->r.h); #endif RGFW_window_setMouseDefault(win); - RGFW_windowsOpen++; + RGFW_window_setFlags(win, flags); + return win; /*return newly created window*/ #endif #ifdef RGFW_WAYLAND @@ -3655,11 +3752,6 @@ RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowF decoration_manager, win->src.xdg_toplevel); } - if (flags & RGFW_windowCenter) { - RGFW_area screenR = RGFW_getScreenSize(); - RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2)); - } - if (flags & RGFW_windowOpenglSoftware) setenv("LIBGL_ALWAYS_SOFTWARE", "1", 1); @@ -3676,17 +3768,10 @@ RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowF RGFW_createOpenGLContext(win); } #endif - - RGFW_init_buffer(win, NULL); - struct wl_callback* callback = wl_surface_frame(win->src.surface); wl_callback_add_listener(callback, &wl_surface_frame_listener, win); wl_surface_commit(win->src.surface); - if (flags & RGFW_windowHideMouse) { - RGFW_window_showMouse(win, 0); - } - win->src.eventIndex = 0; win->src.eventLen = 0; @@ -3700,7 +3785,7 @@ RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowF #endif RGFW_window_setMouseDefault(win); - RGFW_windowsOpen++; + RGFW_window_setFlags(win, flags); return win; /*return newly created window*/ #endif } @@ -3731,17 +3816,68 @@ RGFW_point RGFW_getGlobalMousePoint(void) { return RGFWMouse; } -RGFW_point RGFW_window_getMousePoint(RGFW_window* win) { - RGFW_ASSERT(win != NULL); +RGFWDEF void RGFW_XHandleClipboardSelection(RGFW_window* win, XEvent* event); - RGFW_point RGFWMouse; +void RGFW_XHandleClipboardSelection(RGFW_window* win, XEvent* event) { + RGFW_LOAD_ATOM(ATOM_PAIR); + RGFW_LOAD_ATOM(MULTIPLE); + RGFW_LOAD_ATOM(TARGETS); + RGFW_LOAD_ATOM(SAVE_TARGETS); - i32 x, y; - u32 z; - Window window1, window2; - XQueryPointer(win->src.display, win->src.window, &window1, &window2, &x, &y, &RGFWMouse.x, &RGFWMouse.y, &z); + const XSelectionRequestEvent* request = &event->xselectionrequest; + const Atom formats[] = { RGFW_XUTF8_STRING, XA_STRING }; + const int formatCount = sizeof(formats) / sizeof(formats[0]); - return RGFWMouse; + if (request->target == TARGETS) { + const Atom targets[] = { TARGETS, MULTIPLE, RGFW_XUTF8_STRING, XA_STRING }; + + XChangeProperty(win->src.display, request->requestor, request->property, + XA_ATOM, 32, PropModeReplace, (u8*) targets, sizeof(targets) / sizeof(Atom)); + } else if (request->target == MULTIPLE) { + Atom* targets = NULL; + + Atom actualType = 0; + int actualFormat = 0; + unsigned long count = 0, bytesAfter = 0; + + XGetWindowProperty(RGFW_root->src.display, request->requestor, request->property, 0, LONG_MAX, + False, ATOM_PAIR, &actualType, &actualFormat, &count, &bytesAfter, (u8**) &targets); + + unsigned long i; + for (i = 0; i < (u32)count; i += 2) { + if (targets[i] == RGFW_XUTF8_STRING || targets[i] == XA_STRING) + XChangeProperty(RGFW_root->src.display, request->requestor, targets[i + 1], targets[i], + 8, PropModeReplace, win->src.clipboard, win->src.clipboard_len); + else + targets[i + 1] = None; + } + + XChangeProperty(RGFW_root->src.display, + request->requestor, request->property, ATOM_PAIR, 32, + PropModeReplace, (u8*) targets, count); + + XFlush(RGFW_root->src.display); + XFree(targets); + } else if (request->target == SAVE_TARGETS) + XChangeProperty(win->src.display, request->requestor, request->property, 0, 32, PropModeReplace, NULL, 0); + else { + for (int i = 0; i < formatCount; i++) { + if (request->target != formats[i]) + continue; + XChangeProperty(win->src.display, request->requestor, request->property, request->target, + 8, PropModeReplace, (u8*) win->src.clipboard, win->src.clipboard_len); + } + } + + XEvent reply = { SelectionNotify }; + reply.xselection.property = request->property; + reply.xselection.display = request->display; + reply.xselection.requestor = request->requestor; + reply.xselection.selection = request->selection; + reply.xselection.target = request->target; + reply.xselection.time = request->time; + + XSendEvent(win->src.display, request->requestor, False, 0, &reply); } char* RGFW_strtok(char* str, const char* delimStr) { @@ -3755,7 +3891,7 @@ char* RGFW_strtok(char* str, const char* delimStr) { } while (*static_str != '\0') { - b8 delim = 0; + RGFW_bool delim = 0; for (const char* d = delimStr; *d != '\0'; d++) { if (*static_str == *d) { delim = 1; @@ -3790,16 +3926,14 @@ char* RGFW_strtok(char* str, const char* delimStr) { return token_start; } -int xAxis = 0, yAxis = 0; RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { RGFW_ASSERT(win != NULL); - if (win->event.type == 0) RGFW_resetKey(); if (win->event.type == RGFW_quit) { - return NULL; + return &win->event; } win->event.type = 0; @@ -3809,6 +3943,16 @@ RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { #endif RGFW_GOTO_WAYLAND(0); #ifdef RGFW_X11 + 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); + XPending(win->src.display); XEvent E; /*!< raw X11 event */ @@ -3825,9 +3969,9 @@ RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { win->event.type = 0; /* xdnd data */ - Window source = 0; - long version = 0; - i32 format = 0; + static Window source = 0; + static long version = 0; + static i32 format = 0; XEvent reply = { ClientMessage }; @@ -3846,7 +3990,6 @@ RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { /* set event key data */ win->event.key = RGFW_apiKeyToRGFW(E.xkey.keycode); - KeySym sym = (KeySym)XkbKeycodeToKeysym(win->src.display, E.xkey.keycode, 0, E.xkey.state & ShiftMask ? 1 : 0); if ((E.xkey.state & LockMask) && sym >= XK_a && sym <= XK_z) @@ -3865,15 +4008,23 @@ RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { XGetKeyboardControl(win->src.display, &keystate); RGFW_keyboard[win->event.key].current = (E.type == KeyPress); - RGFW_updateKeyMods(win, (keystate.led_mask & 1), (keystate.led_mask & 2)); + + XkbStateRec state; + XkbGetState(win->src.display, XkbUseCoreKbd, &state); + RGFW_updateKeyMods(win, (state.locked_mods & LockMask), (state.locked_mods & Mod2Mask), (state.locked_mods & Mod3Mask)); + RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, (E.type == KeyPress)); break; } case ButtonPress: case ButtonRelease: + if (E.xbutton.button > RGFW_mouseFinal) { /* skip this event */ + XFlush(win->src.display); + return RGFW_window_checkEvent(win); + } + win->event.type = RGFW_mouseButtonPressed + (E.type == ButtonRelease); // the events match - - win->event.button = E.xbutton.button; + win->event.button = E.xbutton.button - 1; switch(win->event.button) { case RGFW_mouseScrollUp: win->event.scroll = 1; @@ -3883,7 +4034,7 @@ RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { break; default: break; } - + RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; if (win->event.repeat == RGFW_FALSE) @@ -3897,17 +4048,12 @@ RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { win->event.point.x = E.xmotion.x; win->event.point.y = E.xmotion.y; - if ((win->_flags & RGFW_HOLD_MOUSE)) { - win->event.point.y = E.xmotion.y; - - win->event.point.x = win->event.point.x - win->_lastMousePoint.x; - win->event.point.y = win->event.point.y - win->_lastMousePoint.y; - } - - win->_lastMousePoint = RGFW_POINT(E.xmotion.x, E.xmotion.y); + win->event.vector.x = win->event.point.x - win->_lastMousePoint.x; + win->event.vector.y = win->event.point.y - win->_lastMousePoint.y; + win->_lastMousePoint = win->event.point; win->event.type = RGFW_mousePosChanged; - RGFW_mousePosCallback(win, win->event.point); + RGFW_mousePosCallback(win, win->event.point, win->event.vector); break; case GenericEvent: { @@ -3934,12 +4080,15 @@ RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { if (XIMaskIsSet(raw->valuators.mask, 1) != 0) deltaY += raw->raw_values[1]; - win->event.point = RGFW_POINT((i32)deltaX, (i32)deltaY); - + win->event.vector = RGFW_POINT((i32)deltaX, (i32)deltaY); + win->event.point.x = win->_lastMousePoint.x + win->event.vector.x; + win->event.point.y = win->_lastMousePoint.y + win->event.vector.y; + win->_lastMousePoint = win->event.point; + RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2))); win->event.type = RGFW_mousePosChanged; - RGFW_mousePosCallback(win, win->event.point); + RGFW_mousePosCallback(win, win->event.point, win->event.vector); } XFreeEventData(win->src.display, &E.xcookie); @@ -3985,7 +4134,6 @@ RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { source = E.xclient.data.l[0]; version = E.xclient.data.l[1] >> 24; format = None; - if (list) { Atom actualType; i32 actualFormat; @@ -4011,7 +4159,7 @@ RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { } for (size_t i = 0; i < count; i++) { - if (formats[i] == XtextUriList || formats[i] == XtextPlain) { + if (formats[i] == XtextUriList || formats[i] == XtextPlain) { format = (int)formats[i]; break; } @@ -4054,10 +4202,9 @@ RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { XFlush(win->src.display); break; } - if (E.xclient.message_type != XdndDrop) break; - + if (version > 5) break; @@ -4067,7 +4214,7 @@ RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { Time time = (version >= 1) ? (Time)E.xclient.data.l[2] : CurrentTime; - + XConvertSelection( win->src.display, XdndSelection, (Atom)format, XdndSelection, win->src.window, time @@ -4081,11 +4228,14 @@ RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { RGFW_dndInitCallback(win, win->event.point); } break; + case SelectionRequest: + RGFW_XHandleClipboardSelection(win, &E); + XFlush(win->src.display); + return RGFW_window_checkEvent(win); case SelectionNotify: { /* this is only for checking for xdnd drops */ if (E.xselection.property != XdndSelection || !(win->_flags & RGFW_windowAllowDND)) break; - char* data; unsigned long result; @@ -4165,11 +4315,17 @@ RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { break; } case FocusIn: + if ((win->_flags & RGFW_windowFullscreen)) + XMapRaised(win->src.display, win->src.window); + win->event.inFocus = 1; win->event.type = RGFW_focusIn; RGFW_focusCallback(win, 1); break; case FocusOut: + if ((win->_flags & RGFW_windowFullscreen)) + RGFW_window_minimize(win); + win->event.inFocus = 0; win->event.type = RGFW_focusOut; RGFW_focusCallback(win, 0); @@ -4233,9 +4389,8 @@ RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { RGFW_event ev = RGFW_eventPipe_pop(win); - if (ev.type == 0 || win->event.type == RGFW_quit) { - return NULL; - } + if (ev.type == 0) return NULL; + if (win->event.type == RGFW_quit) return &win->event; ev.frameTime = win->event.frameTime; ev.frameTime2 = win->event.frameTime2; @@ -4299,6 +4454,25 @@ void RGFW_window_resize(RGFW_window* win, RGFW_area a) { #endif } +void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) { + RGFW_ASSERT(win != NULL); + + if (a.w == 0 && a.h == 0) + return; + + XSizeHints hints; + long flags; + + XGetWMNormalHints(win->src.display, win->src.window, &hints, &flags); + + hints.flags |= PAspect; + + hints.min_aspect.x = hints.max_aspect.x = a.w; + hints.min_aspect.y = hints.max_aspect.y = a.h; + + XSetWMNormalHints(win->src.display, win->src.window, &hints); +} + void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { RGFW_ASSERT(win != NULL); @@ -4337,23 +4511,145 @@ void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { XSetWMNormalHints(win->src.display, win->src.window, &hints); } +void RGFW_toggleXMaximized(RGFW_window* win, RGFW_bool maximized) { + RGFW_ASSERT(win != NULL); + RGFW_LOAD_ATOM(_NET_WM_STATE); + RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_VERT); + RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ); + + XEvent xev = {0}; + xev.type = ClientMessage; + xev.xclient.window = win->src.window; + xev.xclient.message_type = _NET_WM_STATE; + xev.xclient.format = 32; + xev.xclient.data.l[0] = maximized; + xev.xclient.data.l[1] = _NET_WM_STATE_MAXIMIZED_HORZ; + xev.xclient.data.l[2] = _NET_WM_STATE_MAXIMIZED_VERT; + xev.xclient.data.l[3] = 0; + xev.xclient.data.l[4] = 0; + + XSendEvent(win->src.display, DefaultRootWindow(win->src.display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); +} + +void RGFW_window_maximize(RGFW_window* win) { + win->_oldRect = win->r; + RGFW_toggleXMaximized(win, 1); +} + +void RGFW_window_focus(RGFW_window* win) { + RGFW_ASSERT(win); + + XWindowAttributes attr; + XGetWindowAttributes(win->src.display, win->src.window, &attr); + if (attr.map_state != IsViewable) return; + + XSetInputFocus(win->src.display, win->src.window, RevertToPointerRoot, CurrentTime); + XFlush(win->src.display); +} + +void RGFW_window_raise(RGFW_window* win) { + RGFW_ASSERT(win); + XRaiseWindow(win->src.display, win->src.window); + XMapRaised(win->src.display, win->src.window); +} + +void RGFW_window_setXAtom(RGFW_window* win, Atom netAtom, RGFW_bool fullscreen) { + RGFW_ASSERT(win != NULL); + RGFW_LOAD_ATOM(_NET_WM_STATE); + + XEvent xev = {0}; + xev.xclient.type = ClientMessage; + xev.xclient.serial = 0; + xev.xclient.send_event = True; + xev.xclient.message_type = _NET_WM_STATE; + xev.xclient.window = win->src.window; + xev.xclient.format = 32; + xev.xclient.data.l[0] = fullscreen; + xev.xclient.data.l[1] = netAtom; + xev.xclient.data.l[2] = 0; + + XSendEvent(win->src.display, DefaultRootWindow(win->src.display), False, SubstructureNotifyMask | SubstructureRedirectMask, &xev); +} + +void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) { + RGFW_ASSERT(win != NULL); + if (fullscreen) { + win->_flags |= RGFW_windowFullscreen; + win->_oldRect = win->r; + } + else win->_flags &= ~RGFW_windowFullscreen; + + RGFW_LOAD_ATOM(_NET_WM_STATE_FULLSCREEN); + + RGFW_window_setXAtom(win, _NET_WM_STATE_FULLSCREEN, fullscreen); + + XRaiseWindow(win->src.display, win->src.window); + XMapRaised(win->src.display, win->src.window); +} + +void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) { + RGFW_ASSERT(win != NULL); + + RGFW_LOAD_ATOM(_NET_WM_STATE_ABOVE); + RGFW_window_setXAtom(win, _NET_WM_STATE_ABOVE, floating); +} + +void RGFW_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(win->src.display, win->src.window, + NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32, PropModeReplace, (unsigned char*) &value, 1); +} void RGFW_window_minimize(RGFW_window* win) { RGFW_ASSERT(win != NULL); + if (RGFW_window_isMaximized(win)) return; + win->_oldRect = win->r; XIconifyWindow(win->src.display, win->src.window, DefaultScreen(win->src.display)); XFlush(win->src.display); } void RGFW_window_restore(RGFW_window* win) { RGFW_ASSERT(win != NULL); + RGFW_toggleXMaximized(win, 0); + + win->r = win->_oldRect; + RGFW_window_move(win, RGFW_POINT(win->r.x, win->r.y)); + RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h)); XMapWindow(win->src.display, win->src.window); XFlush(win->src.display); } +RGFW_bool 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(win->src.display, win->src.window, _NET_WM_STATE, 0, (~0L), False, XA_ATOM, + &actual_type, &actual_format, &nitems, &bytes_after, + (unsigned char **)&prop_return); + + if (status != Success || actual_type != XA_ATOM) + return RGFW_FALSE; + + for (unsigned long i = 0; i < nitems; i++) + if (prop_return[i] == _NET_WM_STATE_ABOVE) return RGFW_TRUE; + + if (prop_return) + XFree(prop_return); + + return RGFW_FALSE; +} + void RGFW_window_setName(RGFW_window* win, const char* name) { - RGFW_ASSERT(win); + RGFW_ASSERT(win != NULL); RGFW_GOTO_WAYLAND(0); #ifdef RGFW_X11 XStoreName(win->src.display, win->src.window, name); @@ -4375,7 +4671,7 @@ void* RGFW_libxshape = NULL; #ifndef RGFW_NO_PASSTHROUGH -void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough) { +void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) { RGFW_ASSERT(win != NULL); #if defined(__CYGWIN__) @@ -4408,19 +4704,19 @@ void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough) { #endif /* RGFW_NO_PASSTHROUGH */ -b32 RGFW_window_setIcon(RGFW_window* win, u8* icon, RGFW_area a, i32 channels) { +RGFW_bool RGFW_window_setIcon(RGFW_window* win, u8* icon, RGFW_area a, i32 channels) { RGFW_ASSERT(win != NULL); RGFW_ASSERT(icon != NULL); RGFW_ASSERT(channels == 3 || channels == 4); RGFW_GOTO_WAYLAND(0); #ifdef RGFW_X11 + RGFW_LOAD_ATOM(_NET_WM_ICON); i32 count = 2 + (a.w * a.h); - unsigned long* data = (unsigned long*) RGFW_alloc(count * sizeof(unsigned long)); + unsigned long* data = (unsigned long*) RGFW_ALLOC(count * sizeof(unsigned long)); data[0] = (unsigned long)a.w; data[1] = (unsigned long)a.h; unsigned long* target = &data[2]; - u32 x, y; for (x = 0; x < a.w; x++) { @@ -4435,21 +4731,19 @@ b32 RGFW_window_setIcon(RGFW_window* win, u8* icon, RGFW_area a, i32 channels) { } } - RGFW_LOAD_ATOM(_NET_WM_ICON); - - b32 res = (b32)XChangeProperty( + RGFW_bool res = (RGFW_bool)XChangeProperty( win->src.display, win->src.window, _NET_WM_ICON, XA_CARDINAL, 32, PropModeReplace, (u8*)data, count ); - RGFW_free(data); + RGFW_FREE(data); XFlush(win->src.display); - return res; + return RGFW_BOOL(res); #endif #ifdef RGFW_WAYLAND wayland: - return 0; + return RGFW_FALSE; #endif } @@ -4538,24 +4832,26 @@ RGFW_GOTO_WAYLAND(1); #endif } -b32 RGFW_window_setMouseDefault(RGFW_window* win) { +RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) { return RGFW_window_setMouseStandard(win, RGFW_mouseArrow); } -b32 RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) { +RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) { RGFW_ASSERT(win != NULL); RGFW_GOTO_WAYLAND(0); #ifdef RGFW_X11 - if (mouse > (sizeof(RGFW_mouseIconSrc) / sizeof(u8))) - return 0; + static const u8 mouseIconSrc[] = { XC_arrow, XC_left_ptr, XC_xterm, XC_crosshair, XC_hand2, XC_sb_h_double_arrow, XC_sb_v_double_arrow, XC_bottom_left_corner, XC_bottom_right_corner, XC_fleur, XC_X_cursor}; + + if (mouse > (sizeof(mouseIconSrc) / sizeof(u8))) + return RGFW_FALSE; - mouse = RGFW_mouseIconSrc[mouse]; + mouse = mouseIconSrc[mouse]; Cursor cursor = XCreateFontCursor(win->src.display, mouse); XDefineCursor(win->src.display, win->src.window, (Cursor) cursor); XFreeCursor(win->src.display, (Cursor) cursor); - return 1; + return RGFW_TRUE; #endif #ifdef RGFW_WAYLAND wayland: @@ -4567,14 +4863,14 @@ b32 RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) { wl_surface_attach(RGFW_cursor_surface, cursor_buffer, 0, 0); wl_surface_commit(RGFW_cursor_surface); - return 1; + return RGFW_TRUE; #endif } void RGFW_window_hide(RGFW_window* win) { RGFW_GOTO_WAYLAND(0); #ifdef RGFW_X11 - XMapWindow(win->src.display, win->src.window); + XUnmapWindow(win->src.display, win->src.window); #endif #ifdef RGFW_WAYLAND wayland: @@ -4585,11 +4881,10 @@ void RGFW_window_hide(RGFW_window* win) { } void RGFW_window_show(RGFW_window* win) { - if (win->_flags & RGFW_windowHide) - win->_flags ^= RGFW_windowHide; + win->_flags &= ~RGFW_windowHide; RGFW_GOTO_WAYLAND(0); #ifdef RGFW_X11 - XUnmapWindow(win->src.display, win->src.window); + XMapWindow(win->src.display, win->src.window); #endif #ifdef RGFW_WAYLAND wayland: @@ -4601,6 +4896,13 @@ void RGFW_window_show(RGFW_window* win) { RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) { RGFW_GOTO_WAYLAND(1); #ifdef RGFW_X11 + + if (XGetSelectionOwner(RGFW_root->src.display, RGFW_XCLIPBOARD) == RGFW_root->src.window) { + if (str != NULL) + strncpy(str, RGFW_root->src.clipboard, RGFW_root->src.clipboard_len); + return (RGFW_ssize_t)RGFW_root->src.clipboard_len; + } + XEvent event; int format; unsigned long N, sizeN; @@ -4615,10 +4917,10 @@ RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) { if (event.type != SelectionNotify || event.xselection.selection != RGFW_XCLIPBOARD || event.xselection.property == 0) return -1; - + XGetWindowProperty(event.xselection.display, event.xselection.requestor, event.xselection.property, 0L, (~0L), 0, AnyPropertyType, &target, - &format, &sizeN, &N, (unsigned char**) &data); + &format, &sizeN, &N, (u8**) &data); RGFW_ssize_t size; if (sizeN > strCapacity && str != NULL) @@ -4639,122 +4941,56 @@ RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) { #endif } -void RGFW_writeClipboard(const char* text, u32 textLen) { - RGFW_GOTO_WAYLAND(1); - #ifdef RGFW_X11 +void RGFW_XHandleClipboardSelectionLoop(RGFW_window* win) { RGFW_LOAD_ATOM(SAVE_TARGETS); - RGFW_LOAD_ATOM(TARGETS); - RGFW_LOAD_ATOM(MULTIPLE); - RGFW_LOAD_ATOM(ATOM_PAIR); - RGFW_LOAD_ATOM(CLIPBOARD_MANAGER); - - XSetSelectionOwner(RGFW_root->src.display, RGFW_XCLIPBOARD, RGFW_root->src.window, CurrentTime); - XConvertSelection(RGFW_root->src.display, CLIPBOARD_MANAGER, SAVE_TARGETS, None, RGFW_root->src.window, CurrentTime); for (;;) { XEvent event; - - XNextEvent(RGFW_root->src.display, &event); - if (event.type != SelectionRequest) { - break; - } - - const XSelectionRequestEvent* request = &event.xselectionrequest; - - XEvent reply = { SelectionNotify }; - reply.xselection.property = 0; - - if (request->target == TARGETS) { - const Atom targets[] = { TARGETS, - MULTIPLE, - RGFW_XUTF8_STRING, - XA_STRING }; - - XChangeProperty(RGFW_root->src.display, - request->requestor, - request->property, - 4, - 32, - PropModeReplace, - (u8*) targets, - sizeof(targets) / sizeof(targets[0])); - - reply.xselection.property = request->property; + XNextEvent(win->src.display, &event); + switch (event.type) { + case SelectionRequest: + return RGFW_XHandleClipboardSelection(win, &event); + case SelectionNotify: + if (event.xselection.target == SAVE_TARGETS) + return; + break; + default: break; } + } +} - if (request->target == MULTIPLE) { - Atom* targets = NULL; - - Atom actualType = 0; - int actualFormat = 0; - unsigned long count = 0, bytesAfter = 0; - - XGetWindowProperty(RGFW_root->src.display, request->requestor, request->property, 0, LONG_MAX, False, ATOM_PAIR, &actualType, &actualFormat, &count, &bytesAfter, (u8**) &targets); - - unsigned long i; - for (i = 0; i < (u32)count; i += 2) { - if (targets[i] == RGFW_XUTF8_STRING || targets[i] == XA_STRING) { - XChangeProperty(RGFW_root->src.display, - request->requestor, - targets[i + 1], - targets[i], - 8, - PropModeReplace, - (u8*) text, - textLen); - XFlush(RGFW_root->src.display); - } else { - targets[i + 1] = None; - } - } - - XChangeProperty(RGFW_root->src.display, - request->requestor, - request->property, - ATOM_PAIR, - 32, - PropModeReplace, - (u8*) targets, - count); +void RGFW_writeClipboard(const char* text, u32 textLen) { + RGFW_GOTO_WAYLAND(1); + #ifdef RGFW_X11 + RGFW_LOAD_ATOM(SAVE_TARGETS); - XFlush(RGFW_root->src.display); - XFree(targets); + /* request ownership of the clipboard section and request to convert it, this means its our job to convert it */ + XSetSelectionOwner(RGFW_root->src.display, RGFW_XCLIPBOARD, RGFW_root->src.window, CurrentTime); + if (XGetSelectionOwner(RGFW_root->src.display, RGFW_XCLIPBOARD) != RGFW_root->src.window) { + #ifdef RGFW_DEBUG + fprintf(stderr, "RGFW: X11 failed to become owner of clipboard selection\n"); + #endif + return; + } - reply.xselection.property = request->property; - } + if (RGFW_root->src.clipboard) + RGFW_FREE(RGFW_root->src.clipboard); - reply.xselection.display = request->display; - reply.xselection.requestor = request->requestor; - reply.xselection.selection = request->selection; - reply.xselection.target = request->target; - reply.xselection.time = request->time; + RGFW_root->src.clipboard = RGFW_ALLOC(textLen); + strncpy(RGFW_root->src.clipboard, text, textLen); + RGFW_root->src.clipboard_len = textLen; +#ifdef RGFW_WAYLAND + if (RGFW_useWaylandBool) + RGFW_XHandleClipboardSelectionLoop(RGFW_root); +#endif - XSendEvent(RGFW_root->src.display, request->requestor, False, 0, &reply); - XFlush(RGFW_root->src.display); - } #endif #if defined(RGFW_WAYLAND) wayland: #endif } -u8 RGFW_window_isFullscreen(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - - XWindowAttributes windowAttributes; - XGetWindowAttributes(win->src.display, win->src.window, &windowAttributes); - - /* check if the window is visable */ - if (windowAttributes.map_state != IsViewable) - return 0; - - /* check if the window covers the full screen */ - return (windowAttributes.x == 0 && windowAttributes.y == 0 && - windowAttributes.width == XDisplayWidth(win->src.display, DefaultScreen(win->src.display)) && - windowAttributes.height == XDisplayHeight(win->src.display, DefaultScreen(win->src.display))); -} - -u8 RGFW_window_isHidden(RGFW_window* win) { +RGFW_bool RGFW_window_isHidden(RGFW_window* win) { RGFW_ASSERT(win != NULL); XWindowAttributes windowAttributes; @@ -4763,7 +4999,7 @@ u8 RGFW_window_isHidden(RGFW_window* win) { return (windowAttributes.map_state == IsUnmapped && !RGFW_window_isMinimized(win)); } -u8 RGFW_window_isMinimized(RGFW_window* win) { +RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { RGFW_ASSERT(win != NULL); RGFW_LOAD_ATOM(WM_STATE); @@ -4779,16 +5015,16 @@ u8 RGFW_window_isMinimized(RGFW_window* win) { if (status == Success && nitems >= 1 && *((int*) prop_data) == IconicState) { XFree(prop_data); - return 1; + return RGFW_TRUE; } if (prop_data != NULL) XFree(prop_data); - return 0; + return RGFW_FALSE; } -u8 RGFW_window_isMaximized(RGFW_window* win) { +RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { RGFW_ASSERT(win != NULL); RGFW_LOAD_ATOM(_NET_WM_STATE); RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_VERT); @@ -4807,7 +5043,7 @@ u8 RGFW_window_isMaximized(RGFW_window* win) { if (prop_data != NULL) XFree(prop_data); - return 0; + return RGFW_FALSE; } Atom* atoms = (Atom*) prop_data; @@ -4816,12 +5052,21 @@ u8 RGFW_window_isMaximized(RGFW_window* win) { if (atoms[i] == _NET_WM_STATE_MAXIMIZED_VERT || atoms[i] == _NET_WM_STATE_MAXIMIZED_HORZ) { XFree(prop_data); - return 1; + return RGFW_TRUE; } } - return 0; + return RGFW_FALSE; +} + +#ifndef RGFW_NO_DPI +static u32 RGFW_XCalculateRefreshRate(XRRModeInfo mi) { + if (mi.hTotal == 0 || mi.vTotal == 0) return 0; + + return (u32) RGFW_ROUND((double) mi.dotClock / ((double) mi.hTotal * (double) mi.vTotal)); } +#endif + static float XGetSystemContentDPI(Display* display, i32 screen) { float dpi = 96.0f; @@ -4830,15 +5075,14 @@ static float XGetSystemContentDPI(Display* display, i32 screen) { RGFW_UNUSED(screen); char* rms = XResourceManagerString(display); XrmDatabase db = NULL; - + if (rms) db = XrmGetStringDatabase(rms); + if (rms && db) { - db = XrmGetStringDatabase(rms); XrmValue value; char* type = NULL; - if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value) && type && RGFW_STRNCMP(type, "String", 7) == 0) { + if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value) && type && RGFW_STRNCMP(type, "String", 7) == 0) dpi = (float)atof(value.addr); - } XrmDestroyDatabase(db); } #else @@ -4851,22 +5095,36 @@ static float XGetSystemContentDPI(Display* display, i32 screen) { RGFW_monitor RGFW_XCreateMonitor(i32 screen) { RGFW_monitor monitor; - Display* display = XOpenDisplay(NULL); + Display* display; + if (RGFW_root == NULL) + display = XOpenDisplay(NULL); + else + display = RGFW_root->src.display; - RGFW_area size = RGFW_getScreenSize(); + if (screen == -1) screen = DefaultScreen(display); + + Screen* scrn = DefaultScreenOfDisplay(display); + RGFW_area size = RGFW_AREA(scrn->width, scrn->height); - monitor.rect = RGFW_RECT(0, 0, size.w, size.h); + monitor.x = 0; + monitor.y = 0; + monitor.mode.area = RGFW_AREA(size.w, size.h); monitor.physW = DisplayWidthMM(display, screen) / 25.4; monitor.physH = DisplayHeightMM(display, screen) / 25.4; + RGFW_splitBPP(DefaultDepth(display, DefaultScreen(display)), &monitor.mode); + char* name = XDisplayName((const char*)display); RGFW_MEMCPY(monitor.name, name, 128); float dpi = XGetSystemContentDPI(display, screen); - monitor.pixelRatio = dpi / 96.0f; + monitor.pixelRatio = dpi >= 192.0f ? 2 : 1; + monitor.scaleX = (float) (dpi) / 96.0f; + monitor.scaleY = (float) (dpi) / 96.0f; #ifndef RGFW_NO_DPI XRRScreenResources* sr = XRRGetScreenResourcesCurrent(display, RootWindow(display, screen)); + monitor.mode.refreshRate = RGFW_XCalculateRefreshRate(sr->modes[screen]); XRRCrtcInfo* ci = NULL; int crtc = screen; @@ -4876,12 +5134,6 @@ RGFW_monitor RGFW_XCreateMonitor(i32 screen) { } #endif - float ppi_width = RGFW_ROUND((float)monitor.rect.w/(float)monitor.physW); - float ppi_height = RGFW_ROUND((float)monitor.rect.h/(float)monitor.physH); - - monitor.scaleX = (float) (ppi_width) / dpi; - monitor.scaleY = (float) (ppi_height) / dpi; - #ifndef RGFW_NO_DPI XRROutputInfo* info = XRRGetOutputInfo (display, sr, sr->outputs[screen]); @@ -4890,7 +5142,7 @@ RGFW_monitor RGFW_XCreateMonitor(i32 screen) { XCloseDisplay(display); #ifdef RGFW_DEBUG - printf("RGFW INFO: monitor found: scale (%s):\n rect: {%i, %i, %i, %i}\n physical size:%f %f\n scale: %f %f\n pixelRatio: %f\n", monitor.name, monitor.rect.x, monitor.rect.y, monitor.rect.w, monitor.rect.h, monitor.physW, monitor.physH, monitor.scaleX, monitor.scaleY, monitor.pixelRatio); + printf("RGFW INFO: monitor found: scale (%s):\n rect: {%i, %i, %i, %i}\n physical size:%f %f\n scale: %f %f\n pixelRatio: %f\n refreshRate: %i\n depth: %i\n", monitor.name, monitor.x, monitor.y, monitor.mode.area.w, monitor.mode.area.h, monitor.physW, monitor.physH, monitor.scaleX, monitor.scaleY, monitor.pixelRatio, monitor.mode.refreshRate, monitor.mode.red + monitor.mode.green + monitor.mode.blue); #endif return monitor; } @@ -4906,75 +5158,115 @@ RGFW_monitor RGFW_XCreateMonitor(i32 screen) { monitor.physH = physH; } - monitor.rect.x = ci->x; - monitor.rect.y = ci->y; + monitor.x = ci->x; + monitor.y = ci->y; float w = ci->width; float h = ci->height; if (w && h) { - monitor.rect.w = w; - monitor.rect.h = h; + monitor.mode.area.w = w; + monitor.mode.area.h = h; } #endif - if (monitor.physW == 0 || monitor.physH == 0) { - monitor.scaleX = 0; - monitor.scaleY = 0; - } else { - float ppi_width = RGFW_ROUND((float)monitor.rect.w/(float)monitor.physW); - float ppi_height = RGFW_ROUND((float)monitor.rect.h/(float)monitor.physH); - - monitor.scaleX = (float) (ppi_width) / (float) dpi; - monitor.scaleY = (float) (ppi_height) / (float) dpi; - - if ((monitor.scaleX > 1 && monitor.scaleX < 1.1)) - monitor.scaleX = 1; - - if ((monitor.scaleY > 1 && monitor.scaleY < 1.1)) - monitor.scaleY = 1; - } - #ifndef RGFW_NO_DPI XRRFreeCrtcInfo(ci); XRRFreeScreenResources(sr); #endif - XCloseDisplay(display); + if (RGFW_root == NULL) XCloseDisplay(display); #ifdef RGFW_DEBUG - printf("RGFW INFO: monitor found: scale (%s):\n rect: {%i, %i, %i, %i}\n physical size:%f %f\n scale: %f %f\n pixelRatio: %f\n", monitor.name, monitor.rect.x, monitor.rect.y, monitor.rect.w, monitor.rect.h, monitor.physW, monitor.physH, monitor.scaleX, monitor.scaleY, monitor.pixelRatio); + printf("RGFW INFO: monitor found: scale (%s):\n rect: {%i, %i, %i, %i}\n physical size:%f %f\n scale: %f %f\n pixelRatio: %f\n refreshRate: %i\n depth: %i\n", monitor.name, monitor.x, monitor.y, monitor.mode.area.w, monitor.mode.area.h, monitor.physW, monitor.physH, monitor.scaleX, monitor.scaleY, monitor.pixelRatio, monitor.mode.refreshRate, monitor.mode.red + monitor.mode.green + monitor.mode.blue); #endif return monitor; } -RGFW_monitor RGFW_monitors[6]; RGFW_monitor* RGFW_getMonitors(void) { + RGFW_monitor monitors[7]; + RGFW_GOTO_WAYLAND(1); #ifdef RGFW_X11 + + Display* display; + if (RGFW_root == NULL) display = XOpenDisplay(NULL); + else display = RGFW_root->src.display; + size_t i; - for (i = 0; i < (size_t)ScreenCount(RGFW_root->src.display) && i < 6; i++) - RGFW_monitors[i] = RGFW_XCreateMonitor(i); + for (i = 0; i < (size_t)ScreenCount(display) && i < 6; i++) + monitors[i] = RGFW_XCreateMonitor(i); - return RGFW_monitors; + if (RGFW_root == NULL) XCloseDisplay(display); + + return monitors; #endif #ifdef RGFW_WAYLAND - wayland: return RGFW_monitors; // TODO WAYLAND + wayland: return monitors; // TODO WAYLAND #endif } RGFW_monitor RGFW_getPrimaryMonitor(void) { RGFW_GOTO_WAYLAND(1); #ifdef RGFW_X11 - RGFW_ASSERT(RGFW_root != NULL); - return RGFW_XCreateMonitor(DefaultScreen(RGFW_root->src.display)); + return RGFW_XCreateMonitor(-1); #endif #ifdef RGFW_WAYLAND wayland: return (RGFW_monitor){ }; // TODO WAYLAND #endif } +RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { + RGFW_GOTO_WAYLAND(1); +#ifdef RGFW_X11 + #ifndef RGFW_NO_DPI + XRRScreenResources* screenRes = XRRGetScreenResources(RGFW_root->src.display, DefaultRootWindow(RGFW_root->src.display)); + if (screenRes == NULL) return RGFW_FALSE; + for (int i = 0; i < screenRes->ncrtc; i++) { + XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(RGFW_root->src.display, screenRes, screenRes->crtcs[i]); + if (!crtcInfo) continue; + + if (mon.x == crtcInfo->x && mon.y == crtcInfo->y && (u32)mon.mode.area.w == crtcInfo->width && (u32)mon.mode.area.h == crtcInfo->height) { + RRMode rmode = None; + for (int index = 0; index < screenRes->nmode; index++) { + RGFW_monitorMode foundMode; + foundMode.area = RGFW_AREA(screenRes->modes[index].width, screenRes->modes[index].height); + foundMode.refreshRate = RGFW_XCalculateRefreshRate(screenRes->modes[index]); + RGFW_splitBPP(DefaultDepth(RGFW_root->src.display, DefaultScreen(RGFW_root->src.display)), &foundMode); + + if (RGFW_monitorModeCompare(mode, foundMode, request)) { + rmode = screenRes->modes[index].id; + + RROutput output = screenRes->outputs[i]; + XRROutputInfo* info = XRRGetOutputInfo(RGFW_root->src.display, screenRes, output); + if (info) { + XRRSetCrtcConfig(RGFW_root->src.display, screenRes, screenRes->crtcs[i], + CurrentTime, 0, 0, rmode, RR_Rotate_0, &output, 1); + XRRFreeOutputInfo(info); + XRRFreeCrtcInfo(crtcInfo); + XRRFreeScreenResources(screenRes); + return RGFW_TRUE; + } + } + } + + XRRFreeCrtcInfo(crtcInfo); + XRRFreeScreenResources(screenRes); + return RGFW_FALSE; + } + + XRRFreeCrtcInfo(crtcInfo); + } + + XRRFreeScreenResources(screenRes); + return RGFW_FALSE; + #endif +#endif +wayland: + return RGFW_FALSE; +} + RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { RGFW_ASSERT(win != NULL); RGFW_GOTO_WAYLAND(1); @@ -4984,43 +5276,13 @@ RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { return (RGFW_monitor){}; } - #ifndef RGFW_NO_DPI - XRRScreenResources* screenRes = XRRGetScreenResources(win->src.display, DefaultRootWindow(win->src.display)); - if (screenRes == NULL) { - return (RGFW_monitor){}; - } - - for (int i = 0; i < screenRes->ncrtc; i++) { - XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(win->src.display, screenRes, screenRes->crtcs[i]); - if (!crtcInfo) continue; - - int monitorX = crtcInfo->x; - int monitorY = crtcInfo->y; - int monitorWidth = crtcInfo->width; - int monitorHeight = crtcInfo->height; - - if (attrs.x >= monitorX && - attrs.x < monitorX + monitorWidth && - attrs.y >= monitorY && - attrs.y < monitorY + monitorHeight) { - XRRFreeCrtcInfo(crtcInfo); - XRRFreeScreenResources(screenRes); - return RGFW_XCreateMonitor(i); - } - - XRRFreeCrtcInfo(crtcInfo); - } - - XRRFreeScreenResources(screenRes); - #else size_t i; - for (i = 0; i < (size_t)ScreenCount(RGFW_root->src.display) && i < 6; i++) { - Screen* screen = ScreenOfDisplay(RGFW_root->src.display, i); - if (attrs.x >= 0 && attrs.x < 0 + XWidthOfScreen(screen) && - attrs.y >= 0 && attrs.y < 0 + XHeightOfScreen(screen)) + for (i = 0; i < (size_t)ScreenCount(win->src.display) && i < 6; i++) { + Screen* screen = ScreenOfDisplay(win->src.display, i); + if (attrs.x >= 0 && attrs.x < XWidthOfScreen(screen) && + attrs.y >= 0 && attrs.y < XHeightOfScreen(screen)) return RGFW_XCreateMonitor(i); } - #endif #endif wayland: return (RGFW_monitor){}; @@ -5028,13 +5290,13 @@ wayland: } #if defined(RGFW_OPENGL) && !defined(RGFW_EGL) - void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { if (win == NULL) glXMakeCurrent(NULL, (Drawable)NULL, (GLXContext) NULL); else glXMakeCurrent(win->src.display, (Drawable) win->src.window, (GLXContext) win->src.ctx); } +void* RGFW_getCurrent_OpenGL(void) { return glXGetCurrentContext(); } #endif @@ -5045,7 +5307,7 @@ void RGFW_window_swapBuffers(RGFW_window* win) { /* clear the window*/ if (!(win->_flags & RGFW_NO_CPU_RENDER)) { #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - RGFW_area area = RGFW_bufferSize; + RGFW_area area = win->bufferSize; win->src.bitmap->data = (char*) win->buffer; #if !defined(RGFW_X11_DONT_CONVERT_BGR) && !defined(RGFW_OSMESA) u32 x, y; @@ -5060,7 +5322,7 @@ void RGFW_window_swapBuffers(RGFW_window* win) { } } #endif - XPutImage(win->src.display, win->src.window, win->src.gc, win->src.bitmap, 0, 0, 0, 0, RGFW_bufferSize.w, RGFW_bufferSize.h); + XPutImage(win->src.display, win->src.window, win->src.gc, win->src.bitmap, 0, 0, 0, 0, win->bufferSize.w, win->bufferSize.h); win->src.bitmap->data = NULL; #endif } @@ -5081,7 +5343,7 @@ void RGFW_window_swapBuffers(RGFW_window* win) { for (u32 y = 0; y < (u32)win->r.h; y++) { for (u32 x = 0; x < (u32)win->r.w; x++) { u32 index = (y * 4 * win->r.w) + x * 4; - u32 index2 = (y * 4 * RGFW_bufferSize.w) + x * 4; + u32 index2 = (y * 4 * win->bufferSize.w) + x * 4; u8 red = win->buffer[index2]; win->src.buffer[index] = win->buffer[index2 + 2]; @@ -5092,7 +5354,7 @@ void RGFW_window_swapBuffers(RGFW_window* win) { #else for (size_t y = 0; y < win->r.h; y++) { u32 index = (y * 4 * win->r.w); - u32 index2 = (y * 4 * RGFW_bufferSize.w); + u32 index2 = (y * 4 * win->bufferSize.w); RGFW_MEMCPY(&win->src.buffer[index], &win->buffer[index2], win->r.w * 4); } #endif @@ -5126,8 +5388,21 @@ void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { void RGFW_window_close(RGFW_window* win) { RGFW_ASSERT(win != NULL); - RGFW_GOTO_WAYLAND(0); #ifdef RGFW_X11 + /* to save the clipboard on the x server after the window is closed */ + RGFW_LOAD_ATOM(CLIPBOARD_MANAGER); + RGFW_LOAD_ATOM(SAVE_TARGETS); + if (XGetSelectionOwner(win->src.display, RGFW_XCLIPBOARD) == win->src.window) { + XConvertSelection(win->src.display, CLIPBOARD_MANAGER, SAVE_TARGETS, None, win->src.window, CurrentTime); + RGFW_XHandleClipboardSelectionLoop(win); + } + if (win->src.clipboard) { + RGFW_FREE(win->src.clipboard); + win->src.clipboard = NULL; + } + + RGFW_GOTO_WAYLAND(0); + /* ungrab pointer if it was grabbed */ if (win->_flags & RGFW_HOLD_MOUSE) XUngrabPointer(win->src.display, CurrentTime); @@ -5136,7 +5411,7 @@ void RGFW_window_close(RGFW_window* win) { RGFW_closeEGL(win); #endif - if (RGFW_hiddenMouse != NULL && (RGFW_windowsOpen - 1) <= 0) { + if (RGFW_hiddenMouse != NULL && win == RGFW_root) { RGFW_freeMouse(RGFW_hiddenMouse); RGFW_hiddenMouse = 0; } @@ -5144,45 +5419,31 @@ void RGFW_window_close(RGFW_window* win) { #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) if (win->buffer != NULL) { if ((win->_flags & RGFW_BUFFER_ALLOC)) - win->_mem.free(win->_mem.userdata, win->buffer); + RGFW_FREE(win->buffer); XDestroyImage((XImage*) win->src.bitmap); XFreeGC(win->src.display, win->src.gc); } #endif - + if (win->src.display) { #if defined(RGFW_OPENGL) && !defined(RGFW_EGL) glXDestroyContext(win->src.display, win->src.ctx); #endif - - if (win == RGFW_root) - RGFW_root = NULL; - if ((Drawable) win->src.window) XDestroyWindow(win->src.display, (Drawable) win->src.window); /*!< close the window*/ - XCloseDisplay(win->src.display); /*!< kill the display*/ - } - - #ifdef RGFW_ALLOC_DROPFILES - { - u32 i; - for (i = 0; i < RGFW_MAX_DROPS; i++) - win->_mem.free(win->_mem.userdata, win->event.droppedFiles[i]); - - - win->_mem.free(win->_mem.userdata, win->event.droppedFiles); + if (win == RGFW_root) { + XCloseDisplay(win->src.display); /*!< kill the x server connection */ + RGFW_root = NULL; } - #endif + } /* set cleared display / window to NULL for error checking */ win->src.display = 0; win->src.window = 0; - RGFW_windowsOpen--; - #define RGFW_FREE_LIBRARY(x) if (x != NULL) dlclose(x); x = NULL; - if (RGFW_windowsOpen <= 0) { + if (win == RGFW_root) { #if !defined(RGFW_NO_X11_CURSOR_PRELOAD) && !defined(RGFW_NO_X11_CURSOR) RGFW_FREE_LIBRARY(X11Cursorhandle); #endif @@ -5213,7 +5474,7 @@ void RGFW_window_close(RGFW_window* win) { } RGFW_clipboard_switch(NULL); if ((win->_flags & RGFW_WINDOW_ALLOC)) - win->_mem.free(win->_mem.userdata, win); + RGFW_FREE(win); return; #endif @@ -5222,7 +5483,6 @@ void RGFW_window_close(RGFW_window* win) { #ifdef RGFW_X11 XDestroyWindow(win->src.display, (Drawable) win->src.window); - XCloseDisplay(win->src.display); /*!< kill the display*/ #endif #ifdef RGFW_EGL @@ -5230,6 +5490,9 @@ void RGFW_window_close(RGFW_window* win) { #endif if (RGFW_root == win) { + #ifdef RGFW_X11 + XCloseDisplay(win->src.display); /*!< kill connection to the x server */ + #endif RGFW_root = NULL; } @@ -5240,7 +5503,7 @@ void RGFW_window_close(RGFW_window* win) { #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) wl_buffer_destroy(win->src.wl_buffer); if ((win->_flags & RGFW_BUFFER_ALLOC)) - win->_mem.free(win->_mem.userdata, win->buffer); + RGFW_FREE(win->buffer); munmap(win->src.buffer, win->r.w * win->r.h * 4); #endif @@ -5248,7 +5511,7 @@ void RGFW_window_close(RGFW_window* win) { wl_display_disconnect(win->src.wl_display); RGFW_clipboard_switch(NULL); if ((win->_flags & RGFW_WINDOW_ALLOC)) - win->_mem.free(win->_mem.userdata, win); + RGFW_FREE(win); #endif } @@ -5272,9 +5535,8 @@ void RGFW_stopCheckEvents(void) { } } -void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) { - if (waitMS == 0) - return; +void RGFW_window_eventWait(RGFW_window* win, u32 waitMS) { + if (waitMS == 0) return; u8 i; if (RGFW_eventWait_forceStop[0] == 0 || RGFW_eventWait_forceStop[1] == 0) { @@ -5315,14 +5577,14 @@ void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) { #ifdef RGFW_WAYLAND - while (wl_display_dispatch(win->src.wl_display) <= 0 && waitMS >= -1) { + while (wl_display_dispatch(win->src.wl_display) <= 0 && waitMS != RGFW_eventWaitNext) { #else - while (XPending(win->src.display) == 0 && waitMS >= -1) { + while (XPending(win->src.display) == 0 && waitMS != RGFW_eventWaitNext) { #endif - if (poll(fds, index, waitMS) <= 0) + if (poll(fds, index, (int)waitMS) <= 0) break; - if (waitMS > 0) { + if (waitMS != RGFW_eventWaitNext) { waitMS -= (RGFW_getTimeNS() - start) / 1e+6; } } @@ -5349,12 +5611,22 @@ u64 RGFW_getTimeNS(void) { u64 RGFW_getTime(void) { struct timespec ts = { 0, 0 }; #ifndef RGFW_NO_UNIX_CLOCK - clock_gettime(1, &ts); + clock_gettime(CLOCK_REALTIME, &ts); #endif - unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec; + unsigned long long int nanoSeconds = (u64)ts.tv_sec * 1000000000LLU + (u64)ts.tv_nsec; return (double)(nanoSeconds) * 1e-9; } + +u64 RGFW_getTimerFreq(void) { + return 1000000000LLU; +} + +u64 RGFW_getTimerValue(void) { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + return (u64)ts.tv_sec * 1000000000LLU + (u64)ts.tv_nsec; +} #endif /* end of wayland or X11 defines*/ @@ -5392,8 +5664,6 @@ __declspec(dllimport) int __stdcall WideCharToMultiByte( UINT CodePage, DWORD dw static HMODULE RGFW_XInput_dll = NULL; #endif -u32 RGFW_mouseIconSrc[] = {OCR_NORMAL, OCR_NORMAL, OCR_IBEAM, OCR_CROSS, OCR_HAND, OCR_SIZEWE, OCR_SIZENS, OCR_SIZENWSE, OCR_SIZENESW, OCR_SIZEALL, OCR_NO}; - char* RGFW_createUTF8FromWideStringWin32(const WCHAR* source); #define GL_FRONT 0x0404 @@ -5455,34 +5725,95 @@ PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL; static PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL; #endif -RGFW_window RGFW_eventWindow; +LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { + RGFW_window* win = GetPropA(hWnd, "RGFW"); -LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { + RECT windowRect; + GetWindowRect(hWnd, &windowRect); + switch (message) { - case WM_MOVE: - RGFW_eventWindow.r.x = LOWORD(lParam); - RGFW_eventWindow.r.y = HIWORD(lParam); - RGFW_eventWindow.src.window = hWnd; - return DefWindowProcA(hWnd, message, wParam, lParam); - case WM_SIZE: - RGFW_eventWindow.r.w = LOWORD(lParam); - RGFW_eventWindow.r.h = HIWORD(lParam); - RGFW_eventWindow.src.window = hWnd; - return DefWindowProcA(hWnd, message, wParam, lParam); // Call DefWindowProc after handling - default: - return DefWindowProcA(hWnd, message, wParam, lParam); - } -} - -#ifndef RGFW_NO_DPI - static HMODULE RGFW_Shcore_dll = NULL; - typedef HRESULT (WINAPI * PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*,UINT*); - PFN_GetDpiForMonitor GetDpiForMonitorSRC = NULL; - #define GetDpiForMonitor GetDpiForMonitorSRC -#endif + case WM_CLOSE: + RGFW_windowQuitCallback(win); + win->event.type = RGFW_quit; + return 0; + case WM_ACTIVATE: + win->event.type = RGFW_focusIn + RGFW_BOOL(LOWORD(wParam) == WA_INACTIVE); + RGFW_focusCallback(win, RGFW_BOOL(LOWORD(wParam) != WA_INACTIVE)); -#ifndef RGFW_NO_DWM -static HMODULE RGFW_dwm_dll = NULL; + if ((win->_flags & RGFW_windowFullscreen) == 0) + break; + + if (LOWORD(wParam) == WA_INACTIVE) + RGFW_window_minimize(win); + else RGFW_window_setFullscreen(win, 1); + break; + case WM_MOVE: + win->r.x = windowRect.left; + win->r.y = windowRect.top; + win->_flags &= ~RGFW_EVENT_PASSED; + win->event.type = RGFW_windowMoved; + RGFW_windowMoveCallback(win, win->r); + return DefWindowProcW(hWnd, message, wParam, lParam); + case WM_SIZE: { + RECT clientRect; + GetClientRect(hWnd, &clientRect); + i32 offset = (windowRect.bottom - windowRect.top) - (clientRect.bottom - clientRect.top); + + if (win->src.aspectRatio.w != 0 && win->src.aspectRatio.h != 0) { + double aspectRatio = (double)win->src.aspectRatio.w / win->src.aspectRatio.h; + + int width = windowRect.right - windowRect.left; + int height = windowRect.bottom - windowRect.top; + int newHeight = (int)(width / aspectRatio); + int newWidth = (int)(height * aspectRatio); + + if (win->r.w > windowRect.right - windowRect.left || + win->r.h > (windowRect.bottom - windowRect.top) - offset) + { + if (newHeight > height) windowRect.right = windowRect.left + newWidth; + else windowRect.bottom = windowRect.top + newHeight; + } else { + if (newHeight < height) windowRect.right = windowRect.left + newWidth; + else windowRect.bottom = windowRect.top + newHeight; + } + + RGFW_window_resize(win, RGFW_AREA((windowRect.right - windowRect.left), + (windowRect.bottom - windowRect.top) - offset)); + } + win->r.w = windowRect.right - windowRect.left; + win->r.h = (windowRect.bottom - windowRect.top) - offset; + win->_flags &= ~RGFW_EVENT_PASSED; + win->event.type = RGFW_windowResized; + RGFW_windowResizeCallback(win, win->r); + return DefWindowProcW(hWnd, message, wParam, lParam); + } + case WM_GETMINMAXINFO: + if (win == NULL) + return DefWindowProcW(hWnd, message, wParam, lParam); + + MINMAXINFO* mmi = (MINMAXINFO*) lParam; + mmi->ptMinTrackSize.x = win->src.minSize.w; + mmi->ptMinTrackSize.y = win->src.minSize.h; + if (win->src.maxSize.w == 0 && win->src.maxSize.h == 0) + return DefWindowProcW(hWnd, message, wParam, lParam); + + mmi->ptMaxTrackSize.x = win->src.maxSize.w; + mmi->ptMaxTrackSize.y = win->src.maxSize.h; + return DefWindowProcW(hWnd, message, wParam, lParam); + default: break; + } + return DefWindowProcW(hWnd, message, wParam, lParam); +} + +#ifndef RGFW_NO_DPI + static HMODULE RGFW_Shcore_dll = NULL; + typedef HRESULT (WINAPI * PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*,UINT*); + PFN_GetDpiForMonitor GetDpiForMonitorSRC = NULL; + #define GetDpiForMonitor GetDpiForMonitorSRC +#endif + +#ifndef RGFW_NO_DWM +static HMODULE RGFW_dwm_dll = NULL; typedef struct { DWORD dwFlags; int fEnable; HRGN hRgnBlur; int fTransitionOnMaximized;} DWM_BLURBEHIND; typedef HRESULT (WINAPI * PFN_DwmEnableBlurBehindWindow)(HWND, const DWM_BLURBEHIND*); PFN_DwmEnableBlurBehindWindow DwmEnableBlurBehindWindowSRC = NULL; @@ -5519,17 +5850,16 @@ void RGFW_loadXInput(void) { } #endif -RGFWDEF void RGFW_init_buffer(RGFW_window* win); -void RGFW_init_buffer(RGFW_window* win) { +void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area){ #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - if (RGFW_bufferSize.w == 0 && RGFW_bufferSize.h == 0) - RGFW_bufferSize = RGFW_getScreenSize(); + win->buffer = buffer; + win->bufferSize = area; BITMAPV5HEADER bi = { 0 }; ZeroMemory(&bi, sizeof(bi)); bi.bV5Size = sizeof(bi); - bi.bV5Width = RGFW_bufferSize.w; - bi.bV5Height = -((LONG) RGFW_bufferSize.h); + bi.bV5Width = area.w; + bi.bV5Height = -((LONG) area.h); bi.bV5Planes = 1; bi.bV5BitCount = 32; bi.bV5Compression = BI_BITFIELDS; @@ -5539,11 +5869,12 @@ void RGFW_init_buffer(RGFW_window* win) { bi.bV5AlphaMask = 0xff000000; win->src.bitmap = CreateDIBSection(win->src.hdc, - (BITMAPINFO*) &bi, - DIB_RGB_COLORS, - (void**) &win->buffer, - NULL, - (DWORD) 0); + (BITMAPINFO*) &bi, DIB_RGB_COLORS, + (void**) &win->src.bitmapBits, + NULL, (DWORD) 0); + + if (win->buffer == NULL) + win->buffer = win->src.bitmapBits; win->src.hdcMem = CreateCompatibleDC(win->src.hdc); @@ -5552,15 +5883,11 @@ void RGFW_init_buffer(RGFW_window* win) { OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, win->r.w, win->r.h); #endif #else - RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ + RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area); /*!< if buffer rendering is not being used */ #endif } -void RGFW_window_setDND(RGFW_window* win, b8 allow) { - DragAcceptFiles(win->src.window, allow); -} - -void RGFW_releaseCursor(RGFW_window* win) { +void RGFW_releaseCursor(RGFW_window* win) { RGFW_UNUSED(win); ClipCursor(NULL); const RAWINPUTDEVICE id = { 0x01, 0x02, RIDEV_REMOVE, NULL }; @@ -5582,7 +5909,61 @@ void RGFW_captureCursor(RGFW_window* win, RGFW_rect rect) { #define RGFW_LOAD_LIBRARY(x, lib) if (x == NULL) x = LoadLibraryA(lib) -u32 RGFW_windowsOpen = 0; +#ifdef RGFW_DIRECTX + +#define OEMRESOURCE +#include + +#ifndef __cplusplus + #define __uuidof(T) IID_##T +#endif + +int RGFW_window_createDXSwapChain(RGFW_window* win, IDXGIFactory* pFactory, IUnknown* pDevice, IDXGISwapChain** swapchain) { + if (!win || !pFactory || !pDevice || !swapchain) { + printf("Error: Null argument passed to RGFW_window_createDXSwapChain\n"); + return -1; + } + + static DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 }; + swapChainDesc.BufferCount = 2; + swapChainDesc.BufferDesc.Width = win->r.w; + swapChainDesc.BufferDesc.Height = win->r.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)) { + printf("Error: Failed to create DirectX swap chain! HRESULT: 0x%X\n", hr); + return -2; + } + + return 0; +} +#endif + +void RGFW_win32_makeWindowTransparent(RGFW_window* win) { + if (!(win->_flags & RGFW_windowTransparent)) return; + + #ifndef RGFW_NO_DWM + if (DwmEnableBlurBehindWindowSRC != NULL) { + DWM_BLURBEHIND bb = {0, 0, 0, 0}; + bb.dwFlags = 0x1; + bb.fEnable = TRUE; + bb.hRgnBlur = NULL; + DwmEnableBlurBehindWindowSRC(win->src.window, &bb); + + } else + #endif + { + SetWindowLong(win->src.window, GWL_EXSTYLE, WS_EX_LAYERED); + SetLayeredWindowAttributes(win->src.window, 0, 128, LWA_ALPHA); + } +} RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) { #ifndef RGFW_NO_XINPUT @@ -5591,8 +5972,6 @@ RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowF #endif #ifndef RGFW_NO_DPI - RGFW_LOAD_LIBRARY(RGFW_Shcore_dll, "shcore.dll"); - RGFW_PROC_DEF(RGFW_Shcore_dll, GetDpiForMonitor); #if (_WIN32_WINNT >= 0x0600) SetProcessDPIAware(); #endif @@ -5622,37 +6001,39 @@ RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowF if (name[0] == 0) name = (char*) " "; - RGFW_eventWindow.r = RGFW_RECT(-1, -1, -1, -1); - RGFW_eventWindow.src.window = NULL; - RGFW_window_basic_init(win, rect, flags); + win->src.hIcon = NULL; win->src.maxSize = RGFW_AREA(0, 0); win->src.minSize = RGFW_AREA(0, 0); - + win->src.aspectRatio = RGFW_AREA(0, 0); HINSTANCE inh = GetModuleHandleA(NULL); #ifndef __cplusplus - WNDCLASSA Class = { 0 }; /*!< Setup the Window class. */ + WNDCLASSW Class = { 0 }; /*!< Setup the Window class. */ #else - WNDCLASSA Class = { }; + WNDCLASSW Class = { }; #endif if (RGFW_className == NULL) RGFW_className = (char*)name; - Class.lpszClassName = RGFW_className; + wchar_t wide_class[255]; + 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 = WndProc; + 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); } - RegisterClassA(&Class); + RegisterClassW(&Class); DWORD window_style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; @@ -5666,13 +6047,19 @@ RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowF } else window_style |= WS_POPUP | WS_VISIBLE | WS_SYSMENU | WS_MINIMIZEBOX; - HWND dummyWin = CreateWindowA(Class.lpszClassName, name, window_style, win->r.x, win->r.y, win->r.w, win->r.h, 0, 0, inh, 0); + wchar_t wide_name[255]; + MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_name, 255); + + HWND dummyWin = CreateWindowW(Class.lpszClassName, (wchar_t*)wide_name, window_style, win->r.x, win->r.y, win->r.w, win->r.h, 0, 0, inh, 0); + GetWindowRect(dummyWin, &windowRect); GetClientRect(dummyWin, &clientRect); win->src.hOffset = (windowRect.bottom - windowRect.top) - (clientRect.bottom - clientRect.top); - win->src.window = CreateWindowA(Class.lpszClassName, name, window_style, win->r.x, win->r.y, win->r.w, win->r.h + win->src.hOffset, 0, 0, inh, 0); - + win->src.window = CreateWindowW(Class.lpszClassName, (wchar_t*)wide_name, window_style, win->r.x, win->r.y, win->r.w, win->r.h + win->src.hOffset, 0, 0, inh, 0); + + SetPropA(win->src.window, "RGFW", win); + if (flags & RGFW_windowAllowDND) { win->_flags |= RGFW_windowAllowDND; RGFW_window_setDND(win, 1); @@ -5680,71 +6067,6 @@ RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowF win->src.hdc = GetDC(win->src.window); if ((flags & RGFW_windowNoInitAPI) == 0) { - #ifdef RGFW_DIRECTX - RGFW_ASSERT(FAILED(CreateDXGIFactory(&__uuidof(IDXGIFactory), (void**) &RGFW_dxInfo.pFactory)) == 0); - - if (FAILED(RGFW_dxInfo.pFactory->lpVtbl->EnumAdapters(RGFW_dxInfo.pFactory, 0, &RGFW_dxInfo.pAdapter))) { - #ifdef RGFW_DEBUG - fprintf(stderr, "Failed to enumerate DXGI adapters\n"); - #endif - RGFW_dxInfo.pFactory->lpVtbl->Release(RGFW_dxInfo.pFactory); - return NULL; - } - - D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_0 }; - - if (FAILED(D3D11CreateDevice(RGFW_dxInfo.pAdapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, 0, featureLevels, 1, D3D11_SDK_VERSION, &RGFW_dxInfo.pDevice, NULL, &RGFW_dxInfo.pDeviceContext))) { - #ifdef RGFW_DEBUG - fprintf(stderr, "Failed to create Direct3D device\n"); - #endif - RGFW_dxInfo.pAdapter->lpVtbl->Release(RGFW_dxInfo.pAdapter); - RGFW_dxInfo.pFactory->lpVtbl->Release(RGFW_dxInfo.pFactory); - return NULL; - } - - DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 }; - swapChainDesc.BufferCount = 1; - swapChainDesc.BufferDesc.Width = win->r.w; - swapChainDesc.BufferDesc.Height = win->r.h; - swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swapChainDesc.OutputWindow = win->src.window; - swapChainDesc.SampleDesc.Count = 1; - swapChainDesc.SampleDesc.Quality = 0; - swapChainDesc.Windowed = TRUE; - RGFW_dxInfo.pFactory->lpVtbl->CreateSwapChain(RGFW_dxInfo.pFactory, (IUnknown*) RGFW_dxInfo.pDevice, &swapChainDesc, &win->src.swapchain); - - ID3D11Texture2D* pBackBuffer; - win->src.swapchain->lpVtbl->GetBuffer(win->src.swapchain, 0, &__uuidof(ID3D11Texture2D), (LPVOID*) &pBackBuffer); - RGFW_dxInfo.pDevice->lpVtbl->CreateRenderTargetView(RGFW_dxInfo.pDevice, (ID3D11Resource*) pBackBuffer, NULL, &win->src.renderTargetView); - pBackBuffer->lpVtbl->Release(pBackBuffer); - - D3D11_TEXTURE2D_DESC depthStencilDesc = { 0 }; - depthStencilDesc.Width = win->r.w; - depthStencilDesc.Height = win->r.h; - depthStencilDesc.MipLevels = 1; - depthStencilDesc.ArraySize = 1; - depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; - depthStencilDesc.SampleDesc.Count = 1; - depthStencilDesc.SampleDesc.Quality = 0; - depthStencilDesc.Usage = D3D11_USAGE_DEFAULT; - depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; - - ID3D11Texture2D* pDepthStencilTexture = NULL; - RGFW_dxInfo.pDevice->lpVtbl->CreateTexture2D(RGFW_dxInfo.pDevice, &depthStencilDesc, NULL, &pDepthStencilTexture); - - D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc = { 0 }; - depthStencilViewDesc.Format = depthStencilDesc.Format; - depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; - depthStencilViewDesc.Texture2D.MipSlice = 0; - - RGFW_dxInfo.pDevice->lpVtbl->CreateDepthStencilView(RGFW_dxInfo.pDevice, (ID3D11Resource*) pDepthStencilTexture, &depthStencilViewDesc, &win->src.pDepthStencilView); - - pDepthStencilTexture->lpVtbl->Release(pDepthStencilTexture); - - RGFW_dxInfo.pDeviceContext->lpVtbl->OMSetRenderTargets(RGFW_dxInfo.pDeviceContext, 1, &win->src.renderTargetView, win->src.pDepthStencilView); - #endif - #ifdef RGFW_OPENGL HDC dummy_dc = GetDC(dummyWin); @@ -5817,16 +6139,16 @@ RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowF u32 index = 0; i32 attribs[40]; - if (RGFW_profile == RGFW_glCore) { + if (RGFW_GL_HINTS[RGFW_glProfile]== RGFW_glCore) { SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB); } else { SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB); } - if (RGFW_majorVersion || RGFW_minorVersion) { - SET_ATTRIB(WGL_CONTEXT_MAJOR_VERSION_ARB, RGFW_majorVersion); - SET_ATTRIB(WGL_CONTEXT_MINOR_VERSION_ARB, RGFW_minorVersion); + if (RGFW_GL_HINTS[RGFW_glMinor] || RGFW_GL_HINTS[RGFW_glMajor]) { + SET_ATTRIB(WGL_CONTEXT_MAJOR_VERSION_ARB, RGFW_GL_HINTS[RGFW_glMinor]); + SET_ATTRIB(WGL_CONTEXT_MINOR_VERSION_ARB, RGFW_GL_HINTS[RGFW_glMajor]); } SET_ATTRIB(0, 0); @@ -5856,43 +6178,16 @@ RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowF #endif DestroyWindow(dummyWin); - RGFW_init_buffer(win); - - - #ifndef RGFW_NO_MONITOR - if (flags & RGFW_windowScaleToMonitor) - RGFW_window_scaleToMonitor(win); - #endif - - if (flags & RGFW_windowCenter) { - RGFW_area screenR = RGFW_getScreenSize(); - RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2)); - } #ifdef RGFW_EGL if ((flags & RGFW_windowNoInitAPI) == 0) RGFW_createOpenGLContext(win); #endif - if (flags & RGFW_windowHideMouse) - RGFW_window_showMouse(win, 0); - - if (flags & RGFW_windowTransparent) { - if (DwmEnableBlurBehindWindowSRC != NULL) { - #ifndef RGFW_NO_DWM - DWM_BLURBEHIND bb = {0, 0, 0, 0}; - bb.dwFlags = 0x1; - bb.fEnable = TRUE; - bb.hRgnBlur = NULL; - DwmEnableBlurBehindWindowSRC(win->src.window, &bb); - #endif - } else { - SetWindowLong(win->src.window, GWL_EXSTYLE, WS_EX_LAYERED); - SetLayeredWindowAttributes(win->src.window, 0, 128, LWA_ALPHA); - } - } - ShowWindow(win->src.window, SW_SHOWNORMAL); + RGFW_window_setFlags(win, flags); + + RGFW_win32_makeWindowTransparent(win); #ifdef RGFW_OPENGL if (RGFW_root != win) @@ -5903,12 +6198,11 @@ RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowF printf("RGFW INFO: a window with a rect of {%i, %i, %i, %i} \n", win->r.x, win->r.y, win->r.w, win->r.h); #endif - RGFW_windowsOpen++; - return win; } -void RGFW_window_setBorder(RGFW_window* win, u8 border) { +void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { + RGFW_setBit(&win->_flags, RGFW_windowNoBorder, !border); DWORD style = GetWindowLong(win->src.window, GWL_STYLE); if (border == 0) { @@ -5927,6 +6221,10 @@ void RGFW_window_setBorder(RGFW_window* win, u8 border) { } } +void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow) { + RGFW_setBit(&win->_flags, RGFW_windowAllowDND, allow); + DragAcceptFiles(win->src.window, allow); +} RGFW_area RGFW_getScreenSize(void) { HDC dc = GetDC(NULL); @@ -5942,12 +6240,9 @@ RGFW_point RGFW_getGlobalMousePoint(void) { return RGFW_POINT(p.x, p.y); } -RGFW_point RGFW_window_getMousePoint(RGFW_window* win) { - POINT p; - GetCursorPos(&p); - ScreenToClient(win->src.window, &p); - - return RGFW_POINT(p.x, p.y); +void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) { + RGFW_ASSERT(win != NULL); + win->src.aspectRatio = a; } void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { @@ -5960,19 +6255,72 @@ void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { win->src.maxSize = a; } +void RGFW_window_focus(RGFW_window* win) { + RGFW_ASSERT(win); + SetForegroundWindow(win->src.window); + SetFocus(win->src.window); +} -void RGFW_window_minimize(RGFW_window* win) { +void RGFW_window_raise(RGFW_window* win) { + RGFW_ASSERT(win); + BringWindowToTop(win->src.window); + SetWindowPos(win->src.window, HWND_TOP, win->r.x, win->r.y, win->r.w, win->r.h, SWP_NOSIZE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_FRAMECHANGED); +} + +void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) { RGFW_ASSERT(win != NULL); + + if (fullscreen == RGFW_FALSE) { + RGFW_window_setBorder(win, 1); + SetWindowPos(win->src.window, HWND_NOTOPMOST, win->_oldRect.x, win->_oldRect.y, win->_oldRect.w, win->_oldRect.h + win->src.hOffset, + SWP_NOOWNERZORDER | SWP_FRAMECHANGED); + + win->_flags &= ~RGFW_windowFullscreen; + win->r = win->_oldRect; + return; + } + win->_flags |= RGFW_windowFullscreen; + + RGFW_monitor mon = RGFW_window_getMonitor(win); + RGFW_window_setBorder(win, 0); + SetWindowPos(win->src.window, HWND_TOPMOST, 0, 0, mon.mode.area.w, mon.mode.area.h, SWP_NOOWNERZORDER | SWP_FRAMECHANGED); + + win->_oldRect = win->r; + win->r = RGFW_RECT(0, 0, mon.mode.area.w, mon.mode.area.h); +} + +void RGFW_window_maximize(RGFW_window* win) { + RGFW_ASSERT(win != NULL); + RGFW_window_hide(win); + ShowWindow(win->src.window, SW_MAXIMIZE); +} + +void RGFW_window_minimize(RGFW_window* win) { + RGFW_ASSERT(win != NULL); ShowWindow(win->src.window, SW_MINIMIZE); } +void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) { + RGFW_ASSERT(win != NULL); + if (floating) SetWindowPos(win->src.window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); + else SetWindowPos(win->src.window, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); +} + +void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) { + SetWindowLong(win->src.window, GWL_EXSTYLE, WS_EX_LAYERED); + SetLayeredWindowAttributes(win->src.window, 0, opacity, LWA_ALPHA); +} + void RGFW_window_restore(RGFW_window* win) { RGFW_ASSERT(win != NULL); - ShowWindow(win->src.window, SW_RESTORE); } +RGFW_bool RGFW_window_isFloating(RGFW_window* win) { + return (GetWindowLongPtr(win->src.window, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0; +} + u8 RGFW_xinput2RGFW[] = { RGFW_gamepadA, /* or PS X button */ RGFW_gamepadB, /* or PS circle button */ @@ -6109,39 +6457,20 @@ void RGFW_stopCheckEvents(void) { PostMessageW(RGFW_root->src.window, WM_NULL, 0, 0); } -void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) { +void RGFW_window_eventWait(RGFW_window* win, u32 waitMS) { RGFW_UNUSED(win); - - MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD) (waitMS * 1e3), QS_ALLINPUT); + MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD)waitMS, QS_ALLINPUT); } RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { RGFW_ASSERT(win != NULL); - if (win->event.type == RGFW_quit) { - return NULL; - } - - MSG msg; - - if (RGFW_eventWindow.src.window == win->src.window) { - if (RGFW_eventWindow.r.x != -1) { - win->r.x = RGFW_eventWindow.r.x; - win->r.y = RGFW_eventWindow.r.y; - win->event.type = RGFW_windowMoved; - RGFW_windowMoveCallback(win, win->r); - } - - if (RGFW_eventWindow.r.w != -1) { - win->r.w = RGFW_eventWindow.r.w; - win->r.h = RGFW_eventWindow.r.h; - win->event.type = RGFW_windowResized; - RGFW_windowResizeCallback(win, win->r); - } - - RGFW_eventWindow.src.window = NULL; - RGFW_eventWindow.r = RGFW_RECT(-1, -1, -1, -1); + if (win->event.type == RGFW_quit) return &win->event; + if ((win->event.type == RGFW_windowMoved || win->event.type == RGFW_windowResized) + && !(win->_flags & RGFW_EVENT_PASSED)) + { + win->_flags |= RGFW_EVENT_PASSED; return &win->event; } @@ -6199,6 +6528,7 @@ RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { return &win->event; } + MSG msg; if (PeekMessageA(&msg, win->src.window, 0u, 0u, PM_REMOVE) == 0) return NULL; @@ -6222,19 +6552,24 @@ RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { } break; - case WM_PAINT: win->event.type = RGFW_windowRefresh; RGFW_windowRefreshCallback(win); break; + #if(_WIN32_WINNT >= 0x0600) + case WM_DWMCOMPOSITIONCHANGED: + case WM_DWMCOLORIZATIONCOLORCHANGED: + RGFW_win32_makeWindowTransparent(win); + break; + #endif + case WM_MOUSELEAVE: win->event.type = RGFW_mouseLeave; win->_flags |= RGFW_MOUSE_LEFT; RGFW_mouseNotifyCallBack(win, win->event.point, 0); break; - - case WM_KEYUP: { + case WM_SYSKEYUP: case WM_KEYUP: { i32 scancode = (HIWORD(msg.lParam) & (KF_EXTENDED | 0xff)); if (scancode == 0) scancode = MapVirtualKeyW((u32)msg.wParam, MAPVK_VK_TO_VSC); @@ -6263,12 +6598,12 @@ RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { win->event.type = RGFW_keyReleased; RGFW_keyboard[win->event.key].current = 0; - RGFW_updateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001)); + RGFW_updateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001), (GetKeyState(VK_SCROLL) & 0x0001)); RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 0); break; } - case WM_KEYDOWN: { + case WM_SYSKEYDOWN: case WM_KEYDOWN: { i32 scancode = (HIWORD(msg.lParam) & (KF_EXTENDED | 0xff)); if (scancode == 0) scancode = MapVirtualKeyW((u32)msg.wParam, MAPVK_VK_TO_VSC); @@ -6297,7 +6632,7 @@ RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { win->event.type = RGFW_keyPressed; win->event.repeat = RGFW_isPressed(win, win->event.key); RGFW_keyboard[win->event.key].current = 1; - RGFW_updateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001)); + RGFW_updateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001), (GetKeyState(VK_SCROLL) & 0x0001)); RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 1); break; @@ -6312,25 +6647,14 @@ RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { i32 x = GET_X_LPARAM(msg.lParam); i32 y = GET_Y_LPARAM(msg.lParam); - RGFW_mousePosCallback(win, win->event.point); + RGFW_mousePosCallback(win, win->event.point, win->event.vector); if (win->_flags & RGFW_MOUSE_LEFT) { - win->_flags ^= RGFW_MOUSE_LEFT; + win->_flags &= ~RGFW_MOUSE_LEFT; win->event.type = RGFW_mouseEnter; RGFW_mouseNotifyCallBack(win, win->event.point, 1); } - /*if ((win->_flags & RGFW_HOLD_MOUSE)) { - RGFW_point p = RGFW_getGlobalMousePoint(); - //p = RGFW_POINT(p.x + win->r.x, p.y + win->r.y); - - win->event.point.x = x - win->_lastMousePoint.x; - win->event.point.y = y - win->_lastMousePoint.y; - - win->_lastMousePoint = RGFW_POINT(x, y); - break; - }*/ - win->event.point.x = x; win->event.point.y = y; win->_lastMousePoint = RGFW_POINT(x, y); @@ -6368,41 +6692,41 @@ RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { pos.y += (int) ((raw.data.mouse.lLastY / 65535.f) * height); ScreenToClient(win->src.window, &pos); - win->event.point.x = pos.x - win->_lastMousePoint.x; - win->event.point.y = pos.y - win->_lastMousePoint.y; + win->event.vector.x = pos.x - win->_lastMousePoint.x; + win->event.vector.y = pos.y - win->_lastMousePoint.y; } else { - win->event.point.x = raw.data.mouse.lLastX; - win->event.point.y = raw.data.mouse.lLastY; + win->event.vector.x = raw.data.mouse.lLastX; + win->event.vector.y = raw.data.mouse.lLastY; } win->event.type = RGFW_mousePosChanged; - win->_lastMousePoint.x += win->event.point.x; - win->_lastMousePoint.y += win->event.point.y; + win->_lastMousePoint.x += win->event.vector.x; + win->_lastMousePoint.y += win->event.vector.y; + win->event.point = win->_lastMousePoint; + RGFW_mousePosCallback(win, win->event.point, win->event.vector); break; } - - case WM_LBUTTONDOWN: - win->event.button = RGFW_mouseLeft; - RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; - RGFW_mouseButtons[win->event.button].current = 1; - win->event.type = RGFW_mouseButtonPressed; - RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); - break; - case WM_RBUTTONDOWN: - win->event.button = RGFW_mouseRight; - win->event.type = RGFW_mouseButtonPressed; + case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: case WM_XBUTTONDOWN: + if (msg.message == WM_XBUTTONDOWN) + win->event.button = RGFW_mouseMisc1 + (GET_XBUTTON_WPARAM(msg.wParam) == XBUTTON2); + else win->event.button = (msg.message == WM_LBUTTONDOWN) ? RGFW_mouseLeft : + (msg.message == WM_RBUTTONDOWN) ? RGFW_mouseRight : RGFW_mouseMiddle; + + win->event.type = RGFW_mouseButtonPressed; RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; RGFW_mouseButtons[win->event.button].current = 1; RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); break; - case WM_MBUTTONDOWN: - win->event.button = RGFW_mouseMiddle; - win->event.type = RGFW_mouseButtonPressed; + case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MBUTTONUP: case WM_XBUTTONUP: + if (msg.message == WM_XBUTTONUP) + win->event.button = RGFW_mouseMisc1 + (GET_XBUTTON_WPARAM(msg.wParam) == XBUTTON2); + else win->event.button = (msg.message == WM_LBUTTONUP) ? RGFW_mouseLeft : + (msg.message == WM_RBUTTONUP) ? RGFW_mouseRight : RGFW_mouseMiddle; + win->event.type = RGFW_mouseButtonReleased; RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; - RGFW_mouseButtons[win->event.button].current = 1; - RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); + RGFW_mouseButtons[win->event.button].current = 0; + RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0); break; - case WM_MOUSEWHEEL: if (msg.wParam > 0) win->event.button = RGFW_mouseScrollUp; @@ -6417,32 +6741,6 @@ RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { win->event.type = RGFW_mouseButtonPressed; RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); break; - - case WM_LBUTTONUP: - - win->event.button = RGFW_mouseLeft; - win->event.type = RGFW_mouseButtonReleased; - - RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; - RGFW_mouseButtons[win->event.button].current = 0; - RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0); - break; - case WM_RBUTTONUP: - win->event.button = RGFW_mouseRight; - win->event.type = RGFW_mouseButtonReleased; - - RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; - RGFW_mouseButtons[win->event.button].current = 0; - RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0); - break; - case WM_MBUTTONUP: - win->event.button = RGFW_mouseMiddle; - win->event.type = RGFW_mouseButtonReleased; - - RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; - RGFW_mouseButtons[win->event.button].current = 0; - RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0); - break; case WM_DROPFILES: { win->event.type = RGFW_DNDInit; @@ -6458,19 +6756,6 @@ RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { RGFW_dndInitCallback(win, win->event.point); } break; - case WM_GETMINMAXINFO: - { - MINMAXINFO* mmi = (MINMAXINFO*) msg.lParam; - mmi->ptMinTrackSize.x = win->src.minSize.w; - mmi->ptMinTrackSize.y = win->src.minSize.h; - - if (win->src.maxSize.w == 0 && win->src.maxSize.h == 0) - return RGFW_window_checkEvent(win); - - mmi->ptMaxTrackSize.x = win->src.maxSize.w; - mmi->ptMaxTrackSize.y = win->src.maxSize.h; - return RGFW_window_checkEvent(win); - } default: TranslateMessage(&msg); DispatchMessageA(&msg); @@ -6483,25 +6768,13 @@ RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { return &win->event; } -u8 RGFW_window_isFullscreen(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - - #ifndef __cplusplus - WINDOWPLACEMENT placement = { 0 }; - #else - WINDOWPLACEMENT placement = { }; - #endif - GetWindowPlacement(win->src.window, &placement); - return placement.showCmd == SW_SHOWMAXIMIZED; -} - -u8 RGFW_window_isHidden(RGFW_window* win) { +RGFW_bool RGFW_window_isHidden(RGFW_window* win) { RGFW_ASSERT(win != NULL); return IsWindowVisible(win->src.window) == 0 && !RGFW_window_isMinimized(win); } -u8 RGFW_window_isMinimized(RGFW_window* win) { +RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { RGFW_ASSERT(win != NULL); #ifndef __cplusplus @@ -6513,7 +6786,7 @@ u8 RGFW_window_isMinimized(RGFW_window* win) { return placement.showCmd == SW_SHOWMINIMIZED; } -u8 RGFW_window_isMaximized(RGFW_window* win) { +RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { RGFW_ASSERT(win != NULL); #ifndef __cplusplus @@ -6532,10 +6805,10 @@ BOOL CALLBACK GetMonitorByHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcM RGFW_mInfo* info = (RGFW_mInfo*) dwData; if (info->hMonitor == hMonitor) - return FALSE; + return RGFW_FALSE; info->iIndex++; - return TRUE; + return RGFW_TRUE; } #ifndef RGFW_NO_MONITOR @@ -6552,25 +6825,36 @@ RGFW_monitor win32CreateMonitor(HMONITOR src) { info.hMonitor = src; /* get the monitor's index */ - if (EnumDisplayMonitors(NULL, NULL, GetMonitorByHandle, (LPARAM) &info)) { - DISPLAY_DEVICEA dd; - dd.cb = sizeof(dd); - - /* loop through the devices until you find a device with the monitor's index */ - size_t deviceIndex; - for (deviceIndex = 0; EnumDisplayDevicesA(0, (DWORD) deviceIndex, &dd, 0); deviceIndex++) { - char* deviceName = dd.DeviceName; - if (EnumDisplayDevicesA(deviceName, info.iIndex, &dd, 0)) { - RGFW_MEMCPY(monitor.name, dd.DeviceString, 128); /*!< copy the monitor's name */ - break; - } + DISPLAY_DEVICEA dd; + dd.cb = sizeof(dd); + + for (DWORD deviceNum = 0; EnumDisplayDevicesA(NULL, deviceNum, &dd, 0); deviceNum++) { + if (!(dd.StateFlags & DISPLAY_DEVICE_ACTIVE)) + continue; + + DEVMODE dm; + ZeroMemory(&dm, sizeof(dm)); + dm.dmSize = sizeof(dm); + + if (EnumDisplaySettingsA(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) { + monitor.mode.refreshRate = dm.dmDisplayFrequency; + RGFW_splitBPP(dm.dmBitsPerPel, &monitor.mode); } - } + + DISPLAY_DEVICEA mdd; + mdd.cb = sizeof(mdd); - monitor.rect.x = monitorInfo.rcWork.left; - monitor.rect.y = monitorInfo.rcWork.top; - monitor.rect.w = monitorInfo.rcWork.right - monitorInfo.rcWork.left; - monitor.rect.h = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top; + if (EnumDisplayDevicesA(dd.DeviceName, info.iIndex, &mdd, 0)) { + RGFW_MEMCPY(monitor.name, mdd.DeviceString, 128); + break; + } + } + + + monitor.x = monitorInfo.rcWork.left; + monitor.y = monitorInfo.rcWork.top; + monitor.mode.area.w = monitorInfo.rcWork.right - monitorInfo.rcWork.left; + monitor.mode.area.h = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top; HDC hdc = CreateDC(monitorInfo.szDevice, NULL, NULL, NULL); /* get pixels per inch */ @@ -6579,23 +6863,27 @@ RGFW_monitor win32CreateMonitor(HMONITOR src) { monitor.scaleX = dpiX / 96.0f; monitor.scaleY = dpiY / 96.0f; + monitor.pixelRatio = dpiX >= 192.0f ? 2 : 1; monitor.physW = GetDeviceCaps(hdc, HORZSIZE) / 25.4; monitor.physH = GetDeviceCaps(hdc, VERTSIZE) / 25.4; DeleteDC(hdc); #ifndef RGFW_NO_DPI + RGFW_LOAD_LIBRARY(RGFW_Shcore_dll, "shcore.dll"); + RGFW_PROC_DEF(RGFW_Shcore_dll, GetDpiForMonitor); + if (GetDpiForMonitor != NULL) { u32 x, y; GetDpiForMonitor(src, MDT_EFFECTIVE_DPI, &x, &y); - - monitor.pixelRatio = (float) (x) / (float) dpiX; - monitor.pixelRatio = (float) (y) / (float) dpiY; + monitor.scaleX = (float) (x) / (float) 96.0f; + monitor.scaleY = (float) (y) / (float) 96.0f; + monitor.pixelRatio = dpiX >= 192.0f ? 2 : 1; } #endif #ifdef RGFW_DEBUG - printf("RGFW INFO: monitor found: scale (%s):\n rect: {%i, %i, %i, %i}\n physical size:%f %f\n scale: %f %f\n pixelRatio: %f\n", monitor.name, monitor.rect.x, monitor.rect.y, monitor.rect.w, monitor.rect.h, monitor.physW, monitor.physH, monitor.scaleX, monitor.scaleY, monitor.pixelRatio); + printf("RGFW INFO: monitor found: scale (%s):\n rect: {%i, %i, %i, %i}\n physical size:%f %f\n scale: %f %f\n pixelRatio: %f\n refreshRate: %i\n depth: %i\n", monitor.name, monitor.x, monitor.y, monitor.mode.area.w, monitor.mode.area.h, monitor.physW, monitor.physH, monitor.scaleX, monitor.scaleY, monitor.pixelRatio, monitor.mode.refreshRate, monitor.mode.red + monitor.mode.green + monitor.mode.blue); #endif return monitor; @@ -6641,18 +6929,57 @@ RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { return win32CreateMonitor(src); } +RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { + HMONITOR src = MonitorFromPoint((POINT) { mon.x, mon.y }, MONITOR_DEFAULTTOPRIMARY); + + MONITORINFOEX monitorInfo; + monitorInfo.cbSize = sizeof(MONITORINFOEX); + GetMonitorInfoA(src, (LPMONITORINFO)&monitorInfo); + + DISPLAY_DEVICE dd; + dd.cb = sizeof(dd); + + // Enumerate display devices + for (DWORD deviceNum = 0; EnumDisplayDevicesA(NULL, deviceNum, &dd, 0); deviceNum++) { + if (!(dd.StateFlags & DISPLAY_DEVICE_ACTIVE)) + continue; + + DEVMODE dm; + ZeroMemory(&dm, sizeof(dm)); + dm.dmSize = sizeof(dm); + + if (EnumDisplaySettingsA(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) { + if (request & RGFW_monitorScale) { + dm.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT; + dm.dmPelsWidth = mode.area.w; + dm.dmPelsHeight = mode.area.h; + } + + if (request & RGFW_monitorRefresh) { + dm.dmFields |= DM_DISPLAYFREQUENCY; + dm.dmDisplayFrequency = mode.refreshRate; + } + + if (request & RGFW_monitorRGB) { + dm.dmFields |= DM_BITSPERPEL; + dm.dmBitsPerPel = mode.red + mode.green + mode.blue; + } + + if (ChangeDisplaySettingsEx(dd.DeviceName, &dm, NULL, CDS_TEST, NULL) == DISP_CHANGE_SUCCESSFUL) { + if (ChangeDisplaySettingsEx(dd.DeviceName, &dm, NULL, CDS_UPDATEREGISTRY, NULL) == DISP_CHANGE_SUCCESSFUL) + return RGFW_TRUE; + return RGFW_FALSE; + } else return RGFW_FALSE; + } + } + + return RGFW_FALSE; +} + #endif HICON RGFW_loadHandleImage(u8* src, RGFW_area a, BOOL icon) { - u32 i; - HDC dc; - HICON handle; - HBITMAP color, mask; BITMAPV5HEADER bi; - ICONINFO ii; - u8* target = NULL; - u8* source = src; - ZeroMemory(&bi, sizeof(bi)); bi.bV5Size = sizeof(bi); bi.bV5Width = a.w; @@ -6660,39 +6987,32 @@ HICON RGFW_loadHandleImage(u8* src, RGFW_area a, BOOL icon) { bi.bV5Planes = 1; bi.bV5BitCount = 32; bi.bV5Compression = BI_BITFIELDS; - bi.bV5RedMask = 0x00ff0000; + bi.bV5RedMask = 0x000000ff; bi.bV5GreenMask = 0x0000ff00; - bi.bV5BlueMask = 0x000000ff; + bi.bV5BlueMask = 0x00ff0000; bi.bV5AlphaMask = 0xff000000; - dc = GetDC(NULL); - color = CreateDIBSection(dc, - (BITMAPINFO*) &bi, - DIB_RGB_COLORS, - (void**) &target, - NULL, - (DWORD) 0); - ReleaseDC(NULL, dc); + HDC dc = GetDC(NULL); + u8* target = NULL; - mask = CreateBitmap(a.w, a.h, 1, 1, NULL); + HBITMAP color = CreateDIBSection(dc, + (BITMAPINFO*) &bi, DIB_RGB_COLORS, (void**) &target, + NULL, (DWORD) 0); + + memcpy(target, src, a.w * a.h * 4); + ReleaseDC(NULL, dc); - for (i = 0; i < a.w * a.h; i++) { - target[0] = source[2]; - target[1] = source[1]; - target[2] = source[0]; - target[3] = source[3]; - target += 4; - source += 4; - } + HBITMAP mask = CreateBitmap(a.w, a.h, 1, 1, NULL); + ICONINFO ii; ZeroMemory(&ii, sizeof(ii)); ii.fIcon = icon; - ii.xHotspot = 0; - ii.yHotspot = 0; + ii.xHotspot = a.w / 2; + ii.yHotspot = a.h / 2; ii.hbmMask = mask; ii.hbmColor = color; - handle = CreateIconIndirect(&ii); + HICON handle = CreateIconIndirect(&ii); DeleteObject(color); DeleteObject(mask); @@ -6718,21 +7038,22 @@ void RGFW_freeMouse(RGFW_mouse* mouse) { DestroyCursor((HCURSOR)mouse); } -b32 RGFW_window_setMouseDefault(RGFW_window* win) { +RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) { return RGFW_window_setMouseStandard(win, RGFW_mouseArrow); } -b32 RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) { +RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) { RGFW_ASSERT(win != NULL); - if (mouse > (sizeof(RGFW_mouseIconSrc) / sizeof(u32))) - return 0; + static const u32 mouseIconSrc[] = {OCR_NORMAL, OCR_NORMAL, OCR_IBEAM, OCR_CROSS, OCR_HAND, OCR_SIZEWE, OCR_SIZENS, OCR_SIZENWSE, OCR_SIZENESW, OCR_SIZEALL, OCR_NO}; + if (mouse > (sizeof(mouseIconSrc) / sizeof(u32))) + return RGFW_FALSE; - char* icon = MAKEINTRESOURCEA(RGFW_mouseIconSrc[mouse]); + char* icon = MAKEINTRESOURCEA(mouseIconSrc[mouse]); SetClassLongPtrA(win->src.window, GCLP_HCURSOR, (LPARAM) LoadCursorA(NULL, icon)); SetCursor(LoadCursorA(NULL, icon)); - return 1; + return RGFW_TRUE; } void RGFW_window_hide(RGFW_window* win) { @@ -6747,18 +7068,11 @@ void RGFW_window_show(RGFW_window* win) { void RGFW_window_close(RGFW_window* win) { RGFW_ASSERT(win != NULL); - RGFW_windowsOpen--; #ifdef RGFW_EGL RGFW_closeEGL(win); #endif - #ifdef RGFW_DIRECTX - win->src.swapchain->lpVtbl->Release(win->src.swapchain); - win->src.renderTargetView->lpVtbl->Release(win->src.renderTargetView); - win->src.pDepthStencilView->lpVtbl->Release(win->src.pDepthStencilView); - #endif - #ifdef RGFW_BUFFER DeleteDC(win->src.hdcMem); DeleteObject(win->src.bitmap); @@ -6770,24 +7084,9 @@ void RGFW_window_close(RGFW_window* win) { ReleaseDC(win->src.window, win->src.hdc); /*!< delete device context */ DestroyWindow(win->src.window); /*!< delete window */ - #ifdef RGFW_ALLOC_DROPFILES - { - u32 i; - for (i = 0; i < RGFW_MAX_DROPS; i++) - win->_mem.free(win->_mem.userdata, win->event.droppedFiles[i]); - - win->_mem.free(win->_mem.userdata, win->event.droppedFiles); - } - #endif - - if (RGFW_windowsOpen <= 0) { - #ifdef RGFW_DIRECTX - RGFW_dxInfo.pDeviceContext->lpVtbl->Release(RGFW_dxInfo.pDeviceContext); - RGFW_dxInfo.pDevice->lpVtbl->Release(RGFW_dxInfo.pDevice); - RGFW_dxInfo.pAdapter->lpVtbl->Release(RGFW_dxInfo.pAdapter); - RGFW_dxInfo.pFactory->lpVtbl->Release(RGFW_dxInfo.pFactory); - #endif + if (win->src.hIcon) DestroyIcon(win->src.hIcon); + if (win == RGFW_root) { #ifndef RGFW_NO_XINPUT RGFW_FREE_LIBRARY(RGFW_XInput_dll); #endif @@ -6812,7 +7111,7 @@ void RGFW_window_close(RGFW_window* win) { RGFW_clipboard_switch(NULL); if ((win->_flags & RGFW_WINDOW_ALLOC)) - win->_mem.free(win->_mem.userdata, win); + RGFW_FREE(win); } void RGFW_window_move(RGFW_window* win, RGFW_point v) { @@ -6835,12 +7134,14 @@ void RGFW_window_resize(RGFW_window* win, RGFW_area a) { void RGFW_window_setName(RGFW_window* win, const char* name) { RGFW_ASSERT(win != NULL); - SetWindowTextA(win->src.window, name); + wchar_t wide_name[255]; + MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_name, 255); + SetWindowTextW(win->src.window, wide_name); } #ifndef RGFW_NO_PASSTHROUGH -void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough) { +void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) { RGFW_ASSERT(win != NULL); COLORREF key = 0; @@ -6866,22 +7167,20 @@ void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough) { } #endif -b32 RGFW_window_setIcon(RGFW_window* win, u8* src, RGFW_area a, i32 channels) { +RGFW_bool RGFW_window_setIcon(RGFW_window* win, u8* src, RGFW_area a, i32 channels) { RGFW_ASSERT(win != NULL); #ifndef RGFW_WIN95 RGFW_UNUSED(channels); - - HICON handle = RGFW_loadHandleImage(src, a, TRUE); - - SetClassLongPtrA(win->src.window, GCLP_HICON, (LPARAM) handle); - - DestroyIcon(handle); - return 1; + if (win->src.hIcon) DestroyIcon(win->src.hIcon); + + win->src.hIcon = RGFW_loadHandleImage(src, a, TRUE); + SetClassLongPtrA(win->src.window, GCLP_HICON, (LPARAM) win->src.hIcon); + return RGFW_TRUE; #else RGFW_UNUSED(src); RGFW_UNUSED(a); RGFW_UNUSED(channels); - return 0; + return RGFW_FALSE; #endif } @@ -6964,6 +7263,7 @@ void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { else wglMakeCurrent(win->src.hdc, (HGLRC) win->src.ctx); } +void* RGFW_getCurrent_OpenGL(void) { return wglGetCurrentContext(); } #endif #ifndef RGFW_EGL @@ -7006,6 +7306,9 @@ void RGFW_window_swapBuffers(RGFW_window* win) { if (!(win->_flags & RGFW_NO_CPU_RENDER)) { #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) + if (win->buffer != win->src.bitmapBits) + memcpy(win->src.bitmapBits, win->buffer, win->bufferSize.w * win->bufferSize.h * 4); + HGDIOBJ oldbmp = SelectObject(win->src.hdcMem, win->src.bitmap); BitBlt(win->src.hdc, 0, 0, win->r.w, win->r.h, win->src.hdcMem, 0, 0, SRCCOPY); SelectObject(win->src.hdcMem, oldbmp); @@ -7018,10 +7321,6 @@ void RGFW_window_swapBuffers(RGFW_window* win) { #elif defined(RGFW_OPENGL) SwapBuffers(win->src.hdc); #endif - - #if defined(RGFW_WINDOWS) && defined(RGFW_DIRECTX) - win->src.swapchain->lpVtbl->Present(win->src.swapchain, 0, 0); - #endif } } @@ -7076,6 +7375,16 @@ u64 RGFW_getTime(void) { return (u64) (counter.QuadPart / (double) frequency.QuadPart); } +u64 RGFW_getTimerFreq(void) { + return (u64)RGFW_win32_initTimer().QuadPart; +} + +u64 RGFW_getTimerValue(void) { + LARGE_INTEGER counter; + QueryPerformanceCounter(&counter); + return counter.QuadPart; +} + void RGFW_sleep(u64 ms) { Sleep(ms); } @@ -7114,6 +7423,7 @@ void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { SetThreadPriority #include #include #include +#include typedef CGRect NSRect; typedef CGPoint NSPoint; @@ -7258,6 +7568,16 @@ typedef RGFW_ENUM(NSInteger, NSOpenGLContextParameter) { NSOpenGLContextParametectxaceSurfaceVolatile API_DEPRECATED("", macos(10.0, 10.14)) = 306, /* 1 param. Surface volatile state */ }; +typedef RGFW_ENUM(NSInteger, NSWindowButton) { + NSWindowCloseButton = 0, + NSWindowMiniaturizeButton = 1, + NSWindowZoomButton = 2, + NSWindowToolbarButton = 3, + NSWindowDocumentIconButton = 4, + NSWindowDocumentVersionsButton = 6, + NSWindowFullScreenButton = 7, +}; + void NSOpenGLContext_setValues(id context, const int* vals, NSOpenGLContextParameter param) { SEL func = sel_registerName("setValues:forParameter:"); @@ -7401,8 +7721,6 @@ id NSWindow_contentView(id window) { End of cocoa wrapper */ -const char* RGFW_mouseIconSrc[] = {"arrowCursor", "arrowCursor", "IBeamCursor", "crosshairCursor", "pointingHandCursor", "resizeLeftRightCursor", "resizeUpDownCursor", "_windowResizeNorthWestSouthEastCursor", "_windowResizeNorthEastSouthWestCursor", "closedHandCursor", "operationNotAllowedCursor"}; - #ifdef RGFW_OPENGL CFBundleRef RGFWnsglFramework = NULL; @@ -7429,11 +7747,11 @@ u32 RGFW_OnClose(id self) { object_getInstanceVariable(self, (const char*)"RGFW_window", (void**)&win); if (win == NULL) return true; - + win->event.type = RGFW_quit; RGFW_windowQuitCallback(win); - return true; + return false; } /* NOTE(EimaMei): Fixes the constant clicking when the app is running under a terminal. */ @@ -7458,7 +7776,7 @@ NSDragOperation draggingUpdated(id self, SEL sel, id sender) { } win->event.type = RGFW_DNDInit; - win->src.dndPassed = 0; + win->_flags &= ~RGFW_EVENT_PASSED; NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation")); @@ -7527,7 +7845,7 @@ bool performDragOperation(id self, SEL sel, id sender) { win->event.droppedFilesCount = count; win->event.type = RGFW_DND; - win->src.dndPassed = 0; + win->_flags &= ~RGFW_EVENT_PASSED; NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation")); win->event.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y)); @@ -7747,7 +8065,7 @@ void RGFW_osxInitIOKit(void) { } #endif -void NSMoveToResourceDir(void) { +void RGFW_moveToMacOSResourceDir(void) { char resourcesPath[255]; CFBundleRef bundle = CFBundleGetMainBundle(); @@ -7816,20 +8134,17 @@ void RGFW__osxUpdateLayer(id self, SEL sel) { RGFW_windowRefreshCallback(win); } -RGFWDEF void RGFW_init_buffer(RGFW_window* win); -void RGFW_init_buffer(RGFW_window* win) { +void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area) { #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - if (RGFW_bufferSize.w == 0 && RGFW_bufferSize.h == 0) - RGFW_bufferSize = RGFW_getScreenSize(); - - win->buffer = RGFW_alloc(RGFW_bufferSize.w * RGFW_bufferSize.h * 4); + win->buffer = buffer; + win->bufferSize = area; win->_flags |= RGFW_BUFFER_ALLOC; #ifdef RGFW_OSMESA win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL); OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, win->r.w, win->r.h); #endif #else - RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ + RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area); /*!< if buffer rendering is not being used */ #endif } @@ -7888,8 +8203,6 @@ RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowF macArgs |= NSWindowStyleMaskResizable; if (!(flags & RGFW_windowNoBorder)) macArgs |= NSWindowStyleMaskTitled; - else - macArgs = NSWindowStyleMaskBorderless; { void* nsclass = objc_getClass("NSWindow"); SEL func = sel_registerName("initWithContentRect:styleMask:backing:defer:"); @@ -7961,30 +8274,12 @@ RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowF } #endif - objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), false); + objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), false); - objc_msgSend_void_id((id)win->src.window, sel_registerName("setBackgroundColor:"), - NSColor_colorWithSRGB(0, 0, 0, 0)); + objc_msgSend_void_id((id)win->src.window, sel_registerName("setBackgroundColor:"), + NSColor_colorWithSRGB(0, 0, 0, 0)); } - RGFW_init_buffer(win); - - #ifndef RGFW_NO_MONITOR - if (flags & RGFW_windowScaleToMonitor) - RGFW_window_scaleToMonitor(win); - #endif - - if (flags & RGFW_windowCenter) { - RGFW_area screenR = RGFW_getScreenSize(); - RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2)); - } - - if (flags & RGFW_windowHideMouse) - RGFW_window_showMouse(win, 0); - - if (flags & RGFW_windowCocoaCHDirToRes) - NSMoveToResourceDir(); - Class delegateClass = objc_allocateClassPair(objc_getClass("NSObject"), "WindowDelegate", 0); class_addIvar( @@ -8006,6 +8301,9 @@ RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowF id delegate = objc_msgSend_id(NSAlloc(delegateClass), sel_registerName("init")); + if (RGFW_COCOA_FRAME_NAME) + objc_msgSend_ptr(win->src.view, sel_registerName("setFrameAutosaveName:"), RGFW_COCOA_FRAME_NAME); + object_setInstanceVariable(delegate, "RGFW_window", win); objc_msgSend_void_id((id)win->src.window, sel_registerName("setDelegate:"), delegate); @@ -8031,6 +8329,8 @@ RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowF objc_msgSend_void(win->src.window, sel_registerName("makeKeyWindow")); objc_msgSend_void(NSApp, sel_registerName("finishLaunching")); + + RGFW_window_setFlags(win, flags); NSRetain(win->src.window); NSRetain(NSApp); @@ -8041,481 +8341,537 @@ RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowF return win; } -void RGFW_window_setBorder(RGFW_window* win, u8 border) { - NSBackingStoreType storeType = NSWindowStyleMaskBorderless; - if (!border) { - storeType = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable; - } - if (!(win->_flags & RGFW_windowNoResize)) { - storeType |= NSWindowStyleMaskResizable; - } - - ((void (*)(id, SEL, NSBackingStoreType))objc_msgSend)((id)win->src.window, sel_registerName("setStyleMask:"), storeType); - - objc_msgSend_void_bool(win->src.window, sel_registerName("setHasShadow:"), border); -} - -RGFW_area RGFW_getScreenSize(void) { - static CGDirectDisplayID display = 0; - - if (display == 0) - display = CGMainDisplayID(); - - return RGFW_AREA(CGDisplayPixelsWide(display), CGDisplayPixelsHigh(display)); -} - -RGFW_point RGFW_getGlobalMousePoint(void) { - RGFW_ASSERT(RGFW_root != NULL); + 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")); + float offset = 0; + + RGFW_setBit(&win->_flags, RGFW_windowNoBorder, !border); + NSBackingStoreType storeType = NSWindowStyleMaskBorderless | NSWindowStyleMaskFullSizeContentView; + if (border) + storeType = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable; + if (!(win->_flags & RGFW_windowNoResize)) { + storeType |= NSWindowStyleMaskResizable; + } - CGEventRef e = CGEventCreate(NULL); - CGPoint point = CGEventGetLocation(e); - CFRelease(e); + ((void (*)(id, SEL, NSBackingStoreType))objc_msgSend)((id)win->src.window, sel_registerName("setStyleMask:"), storeType); + + if (!border) { + id miniaturizeButton = objc_msgSend_int((id)win->src.window, sel_registerName("standardWindowButton:"), NSWindowMiniaturizeButton); + id titleBarView = objc_msgSend_id(miniaturizeButton, sel_registerName("superview")); + objc_msgSend_void_bool(titleBarView, sel_registerName("setHidden:"), true); + + offset = frame.size.height - content.size.height; + } + + RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h + offset)); + win->r.h -= offset; + } + + RGFW_area RGFW_getScreenSize(void) { + static CGDirectDisplayID display = 0; + + if (display == 0) + display = CGMainDisplayID(); + + return RGFW_AREA(CGDisplayPixelsWide(display), CGDisplayPixelsHigh(display)); + } + + RGFW_point RGFW_getGlobalMousePoint(void) { + RGFW_ASSERT(RGFW_root != NULL); + + CGEventRef e = CGEventCreate(NULL); + CGPoint point = CGEventGetLocation(e); + CFRelease(e); + + return RGFW_POINT((u32) point.x, (u32) point.y); /*!< the point is loaded during event checks */ + } + + typedef RGFW_ENUM(u32, NSEventType) { /* various types of events */ + NSEventTypeLeftMouseDown = 1, + NSEventTypeLeftMouseUp = 2, + NSEventTypeRightMouseDown = 3, + NSEventTypeRightMouseUp = 4, + NSEventTypeMouseMoved = 5, + NSEventTypeLeftMouseDragged = 6, + NSEventTypeRightMouseDragged = 7, + NSEventTypeMouseEntered = 8, + NSEventTypeMouseExited = 9, + NSEventTypeKeyDown = 10, + NSEventTypeKeyUp = 11, + NSEventTypeFlagsChanged = 12, + NSEventTypeAppKitDefined = 13, + NSEventTypeSystemDefined = 14, + NSEventTypeApplicationDefined = 15, + NSEventTypePeriodic = 16, + NSEventTypeCursorUpdate = 17, + NSEventTypeScrollWheel = 22, + NSEventTypeTabletPoint = 23, + NSEventTypeTabletProximity = 24, + NSEventTypeOtherMouseDown = 25, + NSEventTypeOtherMouseUp = 26, + NSEventTypeOtherMouseDragged = 27, + /* The following event types are available on some hardware on 10.5.2 and later */ + NSEventTypeGesture API_AVAILABLE(macos(10.5)) = 29, + NSEventTypeMagnify API_AVAILABLE(macos(10.5)) = 30, + NSEventTypeSwipe API_AVAILABLE(macos(10.5)) = 31, + NSEventTypeRotate API_AVAILABLE(macos(10.5)) = 18, + NSEventTypeBeginGesture API_AVAILABLE(macos(10.5)) = 19, + NSEventTypeEndGesture API_AVAILABLE(macos(10.5)) = 20, + + NSEventTypeSmartMagnify API_AVAILABLE(macos(10.8)) = 32, + NSEventTypeQuickLook API_AVAILABLE(macos(10.8)) = 33, + + NSEventTypePressure API_AVAILABLE(macos(10.10.3)) = 34, + NSEventTypeDirectTouch API_AVAILABLE(macos(10.10)) = 37, + + NSEventTypeChangeMode API_AVAILABLE(macos(10.15)) = 38, + }; - return RGFW_POINT((u32) point.x, (u32) point.y); /*!< the point is loaded during event checks */ -} + typedef RGFW_ENUM(unsigned long long, NSEventMask) { /* masks for the types of events */ + NSEventMaskLeftMouseDown = 1ULL << NSEventTypeLeftMouseDown, + NSEventMaskLeftMouseUp = 1ULL << NSEventTypeLeftMouseUp, + NSEventMaskRightMouseDown = 1ULL << NSEventTypeRightMouseDown, + NSEventMaskRightMouseUp = 1ULL << NSEventTypeRightMouseUp, + NSEventMaskMouseMoved = 1ULL << NSEventTypeMouseMoved, + NSEventMaskLeftMouseDragged = 1ULL << NSEventTypeLeftMouseDragged, + NSEventMaskRightMouseDragged = 1ULL << NSEventTypeRightMouseDragged, + NSEventMaskMouseEntered = 1ULL << NSEventTypeMouseEntered, + NSEventMaskMouseExited = 1ULL << NSEventTypeMouseExited, + NSEventMaskKeyDown = 1ULL << NSEventTypeKeyDown, + NSEventMaskKeyUp = 1ULL << NSEventTypeKeyUp, + NSEventMaskFlagsChanged = 1ULL << NSEventTypeFlagsChanged, + NSEventMaskAppKitDefined = 1ULL << NSEventTypeAppKitDefined, + NSEventMaskSystemDefined = 1ULL << NSEventTypeSystemDefined, + NSEventMaskApplicationDefined = 1ULL << NSEventTypeApplicationDefined, + NSEventMaskPeriodic = 1ULL << NSEventTypePeriodic, + NSEventMaskCursorUpdate = 1ULL << NSEventTypeCursorUpdate, + NSEventMaskScrollWheel = 1ULL << NSEventTypeScrollWheel, + NSEventMaskTabletPoint = 1ULL << NSEventTypeTabletPoint, + NSEventMaskTabletProximity = 1ULL << NSEventTypeTabletProximity, + NSEventMaskOtherMouseDown = 1ULL << NSEventTypeOtherMouseDown, + NSEventMaskOtherMouseUp = 1ULL << NSEventTypeOtherMouseUp, + NSEventMaskOtherMouseDragged = 1ULL << NSEventTypeOtherMouseDragged, + /* The following event masks are available on some hardware on 10.5.2 and later */ + NSEventMaskGesture API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeGesture, + NSEventMaskMagnify API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeMagnify, + NSEventMaskSwipe API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeSwipe, + NSEventMaskRotate API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeRotate, + NSEventMaskBeginGesture API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeBeginGesture, + NSEventMaskEndGesture API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeEndGesture, + + /* Note: You can only use these event masks on 64 bit. In other words, you cannot setup a local, nor global, event monitor for these event types on 32 bit. Also, you cannot search the event queue for them (nextEventMatchingMask:...) on 32 bit. + */ + NSEventMaskSmartMagnify API_AVAILABLE(macos(10.8)) = 1ULL << NSEventTypeSmartMagnify, + NSEventMaskPressure API_AVAILABLE(macos(10.10.3)) = 1ULL << NSEventTypePressure, + NSEventMaskDirectTouch API_AVAILABLE(macos(10.12.2)) = 1ULL << NSEventTypeDirectTouch, + + NSEventMaskChangeMode API_AVAILABLE(macos(10.15)) = 1ULL << NSEventTypeChangeMode, + + NSEventMaskAny = ULONG_MAX, -RGFW_point RGFW_window_getMousePoint(RGFW_window* win) { - NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)((id)win->src.window, sel_registerName("mouseLocationOutsideOfEventStream")); - - return RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y)); -} - -u32 RGFW_keysPressed[10]; /*10 keys at a time*/ -typedef RGFW_ENUM(u32, NSEventType) { /* various types of events */ - NSEventTypeLeftMouseDown = 1, - NSEventTypeLeftMouseUp = 2, - NSEventTypeRightMouseDown = 3, - NSEventTypeRightMouseUp = 4, - NSEventTypeMouseMoved = 5, - NSEventTypeLeftMouseDragged = 6, - NSEventTypeRightMouseDragged = 7, - NSEventTypeMouseEntered = 8, - NSEventTypeMouseExited = 9, - NSEventTypeKeyDown = 10, - NSEventTypeKeyUp = 11, - NSEventTypeFlagsChanged = 12, - NSEventTypeAppKitDefined = 13, - NSEventTypeSystemDefined = 14, - NSEventTypeApplicationDefined = 15, - NSEventTypePeriodic = 16, - NSEventTypeCursorUpdate = 17, - NSEventTypeScrollWheel = 22, - NSEventTypeTabletPoint = 23, - NSEventTypeTabletProximity = 24, - NSEventTypeOtherMouseDown = 25, - NSEventTypeOtherMouseUp = 26, - NSEventTypeOtherMouseDragged = 27, - /* The following event types are available on some hardware on 10.5.2 and later */ - NSEventTypeGesture API_AVAILABLE(macos(10.5)) = 29, - NSEventTypeMagnify API_AVAILABLE(macos(10.5)) = 30, - NSEventTypeSwipe API_AVAILABLE(macos(10.5)) = 31, - NSEventTypeRotate API_AVAILABLE(macos(10.5)) = 18, - NSEventTypeBeginGesture API_AVAILABLE(macos(10.5)) = 19, - NSEventTypeEndGesture API_AVAILABLE(macos(10.5)) = 20, - - NSEventTypeSmartMagnify API_AVAILABLE(macos(10.8)) = 32, - NSEventTypeQuickLook API_AVAILABLE(macos(10.8)) = 33, - - NSEventTypePressure API_AVAILABLE(macos(10.10.3)) = 34, - NSEventTypeDirectTouch API_AVAILABLE(macos(10.10)) = 37, - - NSEventTypeChangeMode API_AVAILABLE(macos(10.15)) = 38, -}; - -typedef RGFW_ENUM(unsigned long long, NSEventMask) { /* masks for the types of events */ - NSEventMaskLeftMouseDown = 1ULL << NSEventTypeLeftMouseDown, - NSEventMaskLeftMouseUp = 1ULL << NSEventTypeLeftMouseUp, - NSEventMaskRightMouseDown = 1ULL << NSEventTypeRightMouseDown, - NSEventMaskRightMouseUp = 1ULL << NSEventTypeRightMouseUp, - NSEventMaskMouseMoved = 1ULL << NSEventTypeMouseMoved, - NSEventMaskLeftMouseDragged = 1ULL << NSEventTypeLeftMouseDragged, - NSEventMaskRightMouseDragged = 1ULL << NSEventTypeRightMouseDragged, - NSEventMaskMouseEntered = 1ULL << NSEventTypeMouseEntered, - NSEventMaskMouseExited = 1ULL << NSEventTypeMouseExited, - NSEventMaskKeyDown = 1ULL << NSEventTypeKeyDown, - NSEventMaskKeyUp = 1ULL << NSEventTypeKeyUp, - NSEventMaskFlagsChanged = 1ULL << NSEventTypeFlagsChanged, - NSEventMaskAppKitDefined = 1ULL << NSEventTypeAppKitDefined, - NSEventMaskSystemDefined = 1ULL << NSEventTypeSystemDefined, - NSEventMaskApplicationDefined = 1ULL << NSEventTypeApplicationDefined, - NSEventMaskPeriodic = 1ULL << NSEventTypePeriodic, - NSEventMaskCursorUpdate = 1ULL << NSEventTypeCursorUpdate, - NSEventMaskScrollWheel = 1ULL << NSEventTypeScrollWheel, - NSEventMaskTabletPoint = 1ULL << NSEventTypeTabletPoint, - NSEventMaskTabletProximity = 1ULL << NSEventTypeTabletProximity, - NSEventMaskOtherMouseDown = 1ULL << NSEventTypeOtherMouseDown, - NSEventMaskOtherMouseUp = 1ULL << NSEventTypeOtherMouseUp, - NSEventMaskOtherMouseDragged = 1ULL << NSEventTypeOtherMouseDragged, - /* The following event masks are available on some hardware on 10.5.2 and later */ - NSEventMaskGesture API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeGesture, - NSEventMaskMagnify API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeMagnify, - NSEventMaskSwipe API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeSwipe, - NSEventMaskRotate API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeRotate, - NSEventMaskBeginGesture API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeBeginGesture, - NSEventMaskEndGesture API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeEndGesture, - - /* Note: You can only use these event masks on 64 bit. In other words, you cannot setup a local, nor global, event monitor for these event types on 32 bit. Also, you cannot search the event queue for them (nextEventMatchingMask:...) on 32 bit. - */ - NSEventMaskSmartMagnify API_AVAILABLE(macos(10.8)) = 1ULL << NSEventTypeSmartMagnify, - NSEventMaskPressure API_AVAILABLE(macos(10.10.3)) = 1ULL << NSEventTypePressure, - NSEventMaskDirectTouch API_AVAILABLE(macos(10.12.2)) = 1ULL << NSEventTypeDirectTouch, - - NSEventMaskChangeMode API_AVAILABLE(macos(10.15)) = 1ULL << NSEventTypeChangeMode, - - NSEventMaskAny = ULONG_MAX, + }; -}; + typedef enum NSEventModifierFlags { + NSEventModifierFlagCapsLock = 1 << 16, + NSEventModifierFlagShift = 1 << 17, + NSEventModifierFlagControl = 1 << 18, + NSEventModifierFlagOption = 1 << 19, + NSEventModifierFlagCommand = 1 << 20, + NSEventModifierFlagNumericPad = 1 << 21 + } NSEventModifierFlags; -typedef enum NSEventModifierFlags { - NSEventModifierFlagCapsLock = 1 << 16, - NSEventModifierFlagShift = 1 << 17, - NSEventModifierFlagControl = 1 << 18, - NSEventModifierFlagOption = 1 << 19, - NSEventModifierFlagCommand = 1 << 20, - NSEventModifierFlagNumericPad = 1 << 21 -} NSEventModifierFlags; + void RGFW_stopCheckEvents(void) { + id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); + eventPool = objc_msgSend_id(eventPool, sel_registerName("init")); -void RGFW_stopCheckEvents(void) { - id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); - eventPool = objc_msgSend_id(eventPool, sel_registerName("init")); + id e = (id) ((id(*)(id, SEL, NSEventType, NSPoint, NSEventModifierFlags, void*, NSInteger, void**, short, NSInteger, NSInteger))objc_msgSend) + (NSApp, sel_registerName("otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:"), + NSEventTypeApplicationDefined, (NSPoint){0, 0}, (NSEventModifierFlags)0, NULL, (NSInteger)0, NULL, 0, 0, 0); - id e = (id) ((id(*)(id, SEL, NSEventType, NSPoint, NSEventModifierFlags, void*, NSInteger, void**, short, NSInteger, NSInteger))objc_msgSend) - (NSApp, sel_registerName("otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:"), - NSEventTypeApplicationDefined, (NSPoint){0, 0}, (NSEventModifierFlags)0, NULL, (NSInteger)0, NULL, 0, 0, 0); + ((void (*)(id, SEL, id, bool))objc_msgSend) + (NSApp, sel_registerName("postEvent:atStart:"), e, 1); - ((void (*)(id, SEL, id, bool))objc_msgSend) - (NSApp, sel_registerName("postEvent:atStart:"), e, 1); + objc_msgSend_bool_void(eventPool, sel_registerName("drain")); + } - objc_msgSend_bool_void(eventPool, sel_registerName("drain")); -} + void RGFW_window_eventWait(RGFW_window* win, u32 waitMS) { + RGFW_UNUSED(win); -void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) { - RGFW_UNUSED(win); + id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); + eventPool = objc_msgSend_id(eventPool, sel_registerName("init")); - 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 = (void*) ((id(*)(Class, SEL, double))objc_msgSend) - (objc_getClass("NSDate"), sel_registerName("dateWithTimeIntervalSinceNow:"), waitMS); + id e = (id) ((id(*)(id, SEL, NSEventMask, void*, id, bool))objc_msgSend) + (NSApp, sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"), + ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true); - id e = (id) ((id(*)(id, SEL, NSEventMask, void*, id, bool))objc_msgSend) - (NSApp, sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"), - ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true); + if (e) { + ((void (*)(id, SEL, id, bool))objc_msgSend) + (NSApp, sel_registerName("postEvent:atStart:"), e, 1); + } - if (e) { - ((void (*)(id, SEL, id, bool))objc_msgSend) - (NSApp, sel_registerName("postEvent:atStart:"), e, 1); + objc_msgSend_bool_void(eventPool, sel_registerName("drain")); } - objc_msgSend_bool_void(eventPool, sel_registerName("drain")); -} + RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { + RGFW_ASSERT(win != NULL); -RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { - RGFW_ASSERT(win != NULL); + if (win->event.type == RGFW_quit) return &win->event; - if (win->event.type == RGFW_quit) - return NULL; - - if ((win->event.type == RGFW_DND || win->event.type == RGFW_DNDInit) && win->src.dndPassed == 0) { - win->src.dndPassed = 1; - ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); - return &win->event; - } + if ((win->event.type == RGFW_DND || win->event.type == RGFW_DNDInit) && !(win->_flags & RGFW_EVENT_PASSED)) { + win->_flags |= RGFW_EVENT_PASSED; + ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); + return &win->event; + } - #ifndef RGFW_NO_IOKIT - if (RGFW_gamepadEventQueueCount && win == RGFW_root) { - static u8 index = 0; + #ifndef RGFW_NO_IOKIT + if (RGFW_gamepadEventQueueCount && win == RGFW_root) { + static u8 index = 0; - /* check queued events */ - RGFW_gamepadEventQueueCount--; + /* check queued events */ + RGFW_gamepadEventQueueCount--; - RGFW_event ev = RGFW_gamepadEventQueue[index]; - win->event.type = ev.type; - win->event.gamepad = ev.gamepad; - win->event.button = ev.button; - win->event.whichAxis = ev.whichAxis; - for (size_t i = 0; i < 4; i++) - win->event.axis[i] = ev.axis[i]; + RGFW_event ev = RGFW_gamepadEventQueue[index]; + win->event.type = ev.type; + win->event.gamepad = ev.gamepad; + win->event.button = ev.button; + win->event.whichAxis = ev.whichAxis; + for (size_t i = 0; i < 4; i++) + win->event.axis[i] = ev.axis[i]; - if (RGFW_gamepadEventQueueCount) index++; - else index = 0; + if (RGFW_gamepadEventQueueCount) index++; + else index = 0; - ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); - return &win->event; - } - #endif + ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); + return &win->event; + } + #endif - id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); - eventPool = objc_msgSend_id(eventPool, sel_registerName("init")); + id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); + eventPool = objc_msgSend_id(eventPool, sel_registerName("init")); - static SEL eventFunc = (SEL)NULL; - if (eventFunc == NULL) - eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"); + static SEL eventFunc = (SEL)NULL; + if (eventFunc == NULL) + eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"); - if ((win->event.type == RGFW_windowMoved || win->event.type == RGFW_windowResized || win->event.type == RGFW_windowRefresh) && win->event.key != 120) { - win->event.key = 120; - objc_msgSend_bool_void(eventPool, sel_registerName("drain")); - ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); - return &win->event; - } + if ((win->event.type == RGFW_windowMoved || win->event.type == RGFW_windowResized || win->event.type == RGFW_windowRefresh) && win->event.key != 120) { + win->event.key = 120; + objc_msgSend_bool_void(eventPool, sel_registerName("drain")); + ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); + return &win->event; + } - void* date = NULL; + void* date = NULL; - id e = (id) ((id(*)(id, SEL, NSEventMask, void*, id, bool))objc_msgSend) - (NSApp, eventFunc, ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true); + id e = (id) ((id(*)(id, SEL, NSEventMask, void*, id, bool))objc_msgSend) + (NSApp, eventFunc, ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true); - if (e == NULL) { - objc_msgSend_bool_void(eventPool, sel_registerName("drain")); - objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e); - ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); - return NULL; - } + if (e == NULL) { + objc_msgSend_bool_void(eventPool, sel_registerName("drain")); + objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e); + ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); + return NULL; + } - if (objc_msgSend_id(e, sel_registerName("window")) != win->src.window) { - ((void (*)(id, SEL, id, bool))objc_msgSend) - (NSApp, sel_registerName("postEvent:atStart:"), e, 0); + if (objc_msgSend_id(e, sel_registerName("window")) != win->src.window) { + ((void (*)(id, SEL, id, bool))objc_msgSend) + (NSApp, sel_registerName("postEvent:atStart:"), e, 0); - objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e); - objc_msgSend_bool_void(eventPool, sel_registerName("drain")); - ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); - return NULL; - } + objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e); + objc_msgSend_bool_void(eventPool, sel_registerName("drain")); + ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); + return NULL; + } - if (win->event.droppedFilesCount) { - u32 i; - for (i = 0; i < win->event.droppedFilesCount; i++) - win->event.droppedFiles[i][0] = '\0'; - } + if (win->event.droppedFilesCount) { + u32 i; + for (i = 0; i < win->event.droppedFilesCount; i++) + win->event.droppedFiles[i][0] = '\0'; + } - win->event.droppedFilesCount = 0; - win->event.type = 0; + win->event.droppedFilesCount = 0; + win->event.type = 0; - switch (objc_msgSend_uint(e, sel_registerName("type"))) { - case NSEventTypeMouseEntered: { - win->event.type = RGFW_mouseEnter; - NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow")); + u32 type = objc_msgSend_uint(e, sel_registerName("type")); + switch (type) { + case NSEventTypeMouseEntered: { + win->event.type = RGFW_mouseEnter; + NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow")); - win->event.point = RGFW_POINT((i32) p.x, (i32) (win->r.h - p.y)); - RGFW_mouseNotifyCallBack(win, win->event.point, 1); - break; - } + win->event.point = RGFW_POINT((i32) p.x, (i32) (win->r.h - p.y)); + RGFW_mouseNotifyCallBack(win, win->event.point, 1); + break; + } - case NSEventTypeMouseExited: - win->event.type = RGFW_mouseLeave; - RGFW_mouseNotifyCallBack(win, win->event.point, 0); - break; + case NSEventTypeMouseExited: + win->event.type = RGFW_mouseLeave; + RGFW_mouseNotifyCallBack(win, win->event.point, 0); + break; - case NSEventTypeKeyDown: { - u32 key = (u16) objc_msgSend_uint(e, sel_registerName("keyCode")); + case NSEventTypeKeyDown: { + u32 key = (u16) objc_msgSend_uint(e, sel_registerName("keyCode")); - u32 mappedKey = *((u32*)((char*)(const char*) NSString_to_char(objc_msgSend_id(e, sel_registerName("charactersIgnoringModifiers"))))); - if (((u8)mappedKey) == 239) - mappedKey = 0; + u32 mappedKey = *((u32*)((char*)(const char*) NSString_to_char(objc_msgSend_id(e, sel_registerName("charactersIgnoringModifiers"))))); + if (((u8)mappedKey) == 239) + mappedKey = 0; - win->event.keyChar = (u8)mappedKey; + win->event.keyChar = (u8)mappedKey; - win->event.key = RGFW_apiKeyToRGFW(key); - RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current; + win->event.key = RGFW_apiKeyToRGFW(key); + RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current; - win->event.type = RGFW_keyPressed; - win->event.repeat = RGFW_isPressed(win, win->event.key); - RGFW_keyboard[win->event.key].current = 1; + win->event.type = RGFW_keyPressed; + win->event.repeat = RGFW_isPressed(win, win->event.key); + RGFW_keyboard[win->event.key].current = 1; - RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 1); - break; - } + RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 1); + break; + } - case NSEventTypeKeyUp: { - u32 key = (u16) objc_msgSend_uint(e, sel_registerName("keyCode")); + case NSEventTypeKeyUp: { + u32 key = (u16) objc_msgSend_uint(e, sel_registerName("keyCode")); - u32 mappedKey = *((u32*)((char*)(const char*) NSString_to_char(objc_msgSend_id(e, sel_registerName("charactersIgnoringModifiers"))))); - if (((u8)mappedKey) == 239) - mappedKey = 0; + u32 mappedKey = *((u32*)((char*)(const char*) NSString_to_char(objc_msgSend_id(e, sel_registerName("charactersIgnoringModifiers"))))); + if (((u8)mappedKey) == 239) + mappedKey = 0; - win->event.keyChar = (u8)mappedKey; + win->event.keyChar = (u8)mappedKey; - win->event.key = RGFW_apiKeyToRGFW(key); + win->event.key = RGFW_apiKeyToRGFW(key); - RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current; + RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current; - win->event.type = RGFW_keyReleased; + win->event.type = RGFW_keyReleased; - RGFW_keyboard[win->event.key].current = 0; - RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 0); - break; - } + RGFW_keyboard[win->event.key].current = 0; + RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 0); + break; + } - case NSEventTypeFlagsChanged: { - u32 flags = objc_msgSend_uint(e, sel_registerName("modifierFlags")); - RGFW_updateKeyModsPro(win, ((u32)(flags & NSEventModifierFlagCapsLock) % 255), ((flags & NSEventModifierFlagNumericPad) % 255), - ((flags & NSEventModifierFlagControl) % 255), ((flags & NSEventModifierFlagOption) % 255), - ((flags & NSEventModifierFlagShift) % 255), ((flags & NSEventModifierFlagCommand) % 255)); - u8 i; - for (i = 0; i < 9; i++) - RGFW_keyboard[i + RGFW_capsLock].prev = 0; + case NSEventTypeFlagsChanged: { + u32 flags = objc_msgSend_uint(e, sel_registerName("modifierFlags")); + RGFW_updateKeyModsPro(win, ((u32)(flags & NSEventModifierFlagCapsLock) % 255), ((flags & NSEventModifierFlagNumericPad) % 255), + ((flags & NSEventModifierFlagControl) % 255), ((flags & NSEventModifierFlagOption) % 255), + ((flags & NSEventModifierFlagShift) % 255), ((flags & NSEventModifierFlagCommand) % 255), 0); + u8 i; + for (i = 0; i < 9; i++) + RGFW_keyboard[i + RGFW_capsLock].prev = 0; - for (i = 0; i < 5; i++) { - u32 shift = (1 << (i + 16)); - u32 key = i + RGFW_capsLock; + for (i = 0; i < 5; i++) { + u32 shift = (1 << (i + 16)); + u32 key = i + RGFW_capsLock; - if ((flags & shift) && !RGFW_wasPressed(win, key)) { - RGFW_keyboard[key].current = 1; + if ((flags & shift) && !RGFW_wasPressed(win, key)) { + RGFW_keyboard[key].current = 1; - if (key != RGFW_capsLock) - RGFW_keyboard[key+ 4].current = 1; + if (key != RGFW_capsLock) + RGFW_keyboard[key+ 4].current = 1; - win->event.type = RGFW_keyPressed; - win->event.key = key; - break; - } + win->event.type = RGFW_keyPressed; + win->event.key = key; + break; + } - if (!(flags & shift) && RGFW_wasPressed(win, key)) { - RGFW_keyboard[key].current = 0; + if (!(flags & shift) && RGFW_wasPressed(win, key)) { + RGFW_keyboard[key].current = 0; - if (key != RGFW_capsLock) - RGFW_keyboard[key + 4].current = 0; + if (key != RGFW_capsLock) + RGFW_keyboard[key + 4].current = 0; - win->event.type = RGFW_keyReleased; - win->event.key = key; - break; + win->event.type = RGFW_keyReleased; + win->event.key = key; + break; + } } - } - RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, win->event.type == RGFW_keyPressed); + RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, win->event.type == RGFW_keyPressed); - break; - } - case NSEventTypeLeftMouseDragged: - case NSEventTypeOtherMouseDragged: - case NSEventTypeRightMouseDragged: - case NSEventTypeMouseMoved: { - win->event.type = RGFW_mousePosChanged; - NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow")); - win->event.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y)); + break; + } + case NSEventTypeLeftMouseDragged: + case NSEventTypeOtherMouseDragged: + case NSEventTypeRightMouseDragged: + case NSEventTypeMouseMoved: { + win->event.type = RGFW_mousePosChanged; + NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow")); + win->event.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y)); - if ((win->_flags & RGFW_HOLD_MOUSE)) { p.x = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaX")); p.y = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaY")); - - win->event.point = RGFW_POINT((i32)p.x, (i32)p.y); + win->event.vector = RGFW_POINT((i32)p.x, (i32)p.y); + + win->_lastMousePoint = win->event.point; + RGFW_mousePosCallback(win, win->event.point, win->event.vector); + break; } + case NSEventTypeLeftMouseDown: case NSEventTypeRightMouseDown: case NSEventTypeOtherMouseDown: { + u32 buttonNumber = objc_msgSend_uint(e, sel_registerName("buttonNumber")); + switch (buttonNumber) { + case 0: win->event.button = RGFW_mouseLeft; break; + case 1: win->event.button = RGFW_mouseRight; break; + case 2: win->event.button = RGFW_mouseMiddle; break; + default: win->event.button = buttonNumber; + } - RGFW_mousePosCallback(win, win->event.point); - break; - } - case NSEventTypeLeftMouseDown: - win->event.button = RGFW_mouseLeft; - win->event.type = RGFW_mouseButtonPressed; - RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; - RGFW_mouseButtons[win->event.button].current = 1; - RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); - break; - - case NSEventTypeOtherMouseDown: - win->event.button = RGFW_mouseMiddle; - win->event.type = RGFW_mouseButtonPressed; - RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; - RGFW_mouseButtons[win->event.button].current = 1; - RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); - break; + win->event.type = RGFW_mouseButtonPressed; + RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; + RGFW_mouseButtons[win->event.button].current = 1; + RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); + break; + } + case NSEventTypeLeftMouseUp: case NSEventTypeRightMouseUp: case NSEventTypeOtherMouseUp: { + u32 buttonNumber = objc_msgSend_uint(e, sel_registerName("buttonNumber")); + switch (buttonNumber) { + case 0: win->event.button = RGFW_mouseLeft; break; + case 1: win->event.button = RGFW_mouseRight; break; + case 2: win->event.button = RGFW_mouseMiddle; break; + default: win->event.button = buttonNumber; + } + RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; + RGFW_mouseButtons[win->event.button].current = 0; + win->event.type = RGFW_mouseButtonReleased; + RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0); + break; + } + case NSEventTypeScrollWheel: { + double deltaY = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaY")); - case NSEventTypeRightMouseDown: - win->event.button = RGFW_mouseRight; - win->event.type = RGFW_mouseButtonPressed; - RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; - RGFW_mouseButtons[win->event.button].current = 1; - RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); - break; + if (deltaY > 0) { + win->event.button = RGFW_mouseScrollUp; + } + else if (deltaY < 0) { + win->event.button = RGFW_mouseScrollDown; + } - case NSEventTypeLeftMouseUp: - win->event.button = RGFW_mouseLeft; - win->event.type = RGFW_mouseButtonReleased; - RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; - RGFW_mouseButtons[win->event.button].current = 0; - RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0); - break; + RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; + RGFW_mouseButtons[win->event.button].current = 1; - case NSEventTypeOtherMouseUp: - win->event.button = RGFW_mouseMiddle; - RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; - RGFW_mouseButtons[win->event.button].current = 0; - win->event.type = RGFW_mouseButtonReleased; - RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0); - break; + win->event.scroll = deltaY; - case NSEventTypeRightMouseUp: - win->event.button = RGFW_mouseRight; - RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; - RGFW_mouseButtons[win->event.button].current = 0; - win->event.type = RGFW_mouseButtonReleased; - RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0); - break; + win->event.type = RGFW_mouseButtonPressed; + RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); + break; + } - case NSEventTypeScrollWheel: { - double deltaY = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaY")); + default: + objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e); + ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); + return RGFW_window_checkEvent(win); + } - if (deltaY > 0) { - win->event.button = RGFW_mouseScrollUp; - } - else if (deltaY < 0) { - win->event.button = RGFW_mouseScrollDown; - } + objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e); + ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); - RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; - RGFW_mouseButtons[win->event.button].current = 1; + objc_msgSend_bool_void(eventPool, sel_registerName("drain")); + return &win->event; + } - win->event.scroll = deltaY; - win->event.type = RGFW_mouseButtonPressed; - RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); - break; - } + void RGFW_window_move(RGFW_window* win, RGFW_point v) { + RGFW_ASSERT(win != NULL); - default: - objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e); - ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); - return RGFW_window_checkEvent(win); + win->r.x = v.x; + win->r.y = v.y; + ((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend) + ((id)win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{win->r.x, win->r.y}, {win->r.w, win->r.h}}, true, true); } - objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e); - ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); + void RGFW_window_resize(RGFW_window* win, RGFW_area a) { + RGFW_ASSERT(win != NULL); + + NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame")); + NSRect content = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame")); + float offset = frame.size.height - content.size.height; - objc_msgSend_bool_void(eventPool, sel_registerName("drain")); - return &win->event; + win->r.w = a.w; + win->r.h = a.h; + + ((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend) + ((id)win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{win->r.x, win->r.y}, {win->r.w, win->r.h + offset}}, true, true); } +void RGFW_window_focus(RGFW_window* win) { + RGFW_ASSERT(win); + objc_msgSend_void_bool(NSApp, sel_registerName("activateIgnoringOtherApps:"), true); + ((void (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_registerName("makeKeyWindow")); +} -void RGFW_window_move(RGFW_window* win, RGFW_point v) { +void RGFW_window_raise(RGFW_window* win) { RGFW_ASSERT(win != NULL); - - win->r.x = v.x; - win->r.y = v.y; - ((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend) - ((id)win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{win->r.x, win->r.y}, {win->r.w, win->r.h}}, true, true); + ((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_resize(RGFW_window* win, RGFW_area a) { +void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) { RGFW_ASSERT(win != NULL); + if (fullscreen && (win->_flags & RGFW_windowFullscreen)) return; + if (!fullscreen && !(win->_flags & RGFW_windowFullscreen)) return; + + if (fullscreen) { + win->_oldRect = win->r; + RGFW_monitor mon = RGFW_window_getMonitor(win); + win->r = RGFW_RECT(0, 0, mon.x, mon.y); + win->_flags |= RGFW_windowFullscreen; + RGFW_window_resize(win, RGFW_AREA(mon.mode.area.w, mon.mode.area.h)); + RGFW_window_move(win, RGFW_POINT(0, 0)); + } + objc_msgSend_void_SEL(win->src.window, sel_registerName("toggleFullScreen:"), NULL); + + if (!fullscreen) { + win->r = win->_oldRect; + win->_flags &= ~RGFW_windowFullscreen; + + RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h)); + RGFW_window_move(win, RGFW_POINT(win->r.x, win->r.y)); + } +} - win->r.w = a.w; - win->r.h = a.h; - ((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend) - ((id)win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{win->r.x, win->r.y}, {win->r.w, win->r.h}}, true, true); +void RGFW_window_maximize(RGFW_window* win) { + RGFW_ASSERT(win != NULL); + if (RGFW_window_isMaximized(win)) return; + + win->_flags |= RGFW_windowMaximize; + objc_msgSend_void_SEL(win->src.window, sel_registerName("zoom:"), NULL); } void RGFW_window_minimize(RGFW_window* win) { RGFW_ASSERT(win != NULL); - objc_msgSend_void_SEL(win->src.window, sel_registerName("performMiniaturize:"), NULL); } +void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) { + RGFW_ASSERT(win != NULL); + if (floating) objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGFloatingWindowLevelKey); + else objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGNormalWindowLevelKey); +} + +void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) { + objc_msgSend_int(win->src.window, sel_registerName("setAlphaValue:"), opacity); + objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), (opacity < (u8)255)); + + if (opacity) + objc_msgSend_void_id((id)win->src.window, sel_registerName("setBackgroundColor:"), NSColor_colorWithSRGB(0, 0, 0, opacity)); + +} + void RGFW_window_restore(RGFW_window* win) { RGFW_ASSERT(win != NULL); + if (RGFW_window_isMaximized(win)) + objc_msgSend_void_SEL(win->src.window, sel_registerName("zoom:"), NULL); objc_msgSend_void_SEL(win->src.window, sel_registerName("deminiaturize:"), NULL); } +RGFW_bool RGFW_window_isFloating(RGFW_window* win) { + RGFW_ASSERT(win != NULL); + int level = ((int (*)(id, SEL))objc_msgSend) ((id)(win->src.window), (SEL)sel_registerName("level")); + return level > kCGNormalWindowLevelKey; +} + void RGFW_window_setName(RGFW_window* win, const char* name) { RGFW_ASSERT(win != NULL); @@ -8524,28 +8880,33 @@ void RGFW_window_setName(RGFW_window* win, const char* name) { } #ifndef RGFW_NO_PASSTHROUGH -void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough) { +void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) { objc_msgSend_void_bool(win->src.window, sel_registerName("setIgnoresMouseEvents:"), passthrough); } #endif -void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { - if (a.w == 0 && a.h == 0) - return; +void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) { + if (a.w == 0 && a.h == 0) a = RGFW_AREA(1, 1); + + ((void (*)(id, SEL, NSSize))objc_msgSend) + ((id)win->src.window, sel_registerName("setContentAspectRatio:"), (NSSize){a.w, a.h}); +} +void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { ((void (*)(id, SEL, NSSize))objc_msgSend) ((id)win->src.window, sel_registerName("setMinSize:"), (NSSize){a.w, a.h}); } void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { - if (a.w == 0 && a.h == 0) - return; + if (a.w == 0 && a.h == 0) { + a = RGFW_getScreenSize(); + } ((void (*)(id, SEL, NSSize))objc_msgSend) ((id)win->src.window, sel_registerName("setMaxSize:"), (NSSize){a.w, a.h}); } -b32 RGFW_window_setIcon(RGFW_window* win, u8* data, RGFW_area area, i32 channels) { +RGFW_bool RGFW_window_setIcon(RGFW_window* win, u8* data, RGFW_area area, i32 channels) { RGFW_ASSERT(win != NULL); /* code by EimaMei */ @@ -8563,7 +8924,7 @@ b32 RGFW_window_setIcon(RGFW_window* win, u8* data, RGFW_area area, i32 channels NSRelease(dock_image); NSRelease(representation); - return 1; + return RGFW_TRUE; } id NSCursor_arrowStr(const char* str) { @@ -8598,7 +8959,7 @@ RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) { } void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) { - RGFW_ASSERT(win); RGFW_ASSERT(mouse); + RGFW_ASSERT(win != NULL); RGFW_ASSERT(mouse); objc_msgSend_void((id)mouse, sel_registerName("set")); } @@ -8607,36 +8968,32 @@ void RGFW_freeMouse(RGFW_mouse* mouse) { NSRelease((id)mouse); } -b32 RGFW_window_setMouseDefault(RGFW_window* win) { +RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) { return RGFW_window_setMouseStandard(win, RGFW_mouseArrow); } -void RGFW_window_showMouse(RGFW_window* win, i8 show) { - RGFW_UNUSED(win); - - if (show) { - CGDisplayShowCursor(kCGDirectMainDisplay); - } - else { - CGDisplayHideCursor(kCGDirectMainDisplay); - } +void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) { + RGFW_window_showMouseFlags(win, show); + if (show) CGDisplayShowCursor(kCGDirectMainDisplay); + else CGDisplayHideCursor(kCGDirectMainDisplay); } -b32 RGFW_window_setMouseStandard(RGFW_window* win, u8 stdMouses) { - if (stdMouses > ((sizeof(RGFW_mouseIconSrc)) / (sizeof(char*)))) - return 0; +RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 stdMouses) { + static const char* mouseIconSrc[] = {"arrowCursor", "arrowCursor", "IBeamCursor", "crosshairCursor", "pointingHandCursor", "resizeLeftRightCursor", "resizeUpDownCursor", "_windowResizeNorthWestSouthEastCursor", "_windowResizeNorthEastSouthWestCursor", "closedHandCursor", "operationNotAllowedCursor"}; + if (stdMouses > ((sizeof(mouseIconSrc)) / (sizeof(char*)))) + return RGFW_FALSE; - const char* mouseStr = RGFW_mouseIconSrc[stdMouses]; + const char* mouseStr = mouseIconSrc[stdMouses]; id mouse = NSCursor_arrowStr(mouseStr); if (mouse == NULL) - return 0; + return RGFW_FALSE; RGFW_UNUSED(win); CGDisplayShowCursor(kCGDirectMainDisplay); objc_msgSend_void(mouse, sel_registerName("set")); - return 1; + return RGFW_TRUE; } void RGFW_releaseCursor(RGFW_window* win) { @@ -8668,30 +9025,23 @@ void RGFW_window_show(RGFW_window* win) { objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), true); } -u8 RGFW_window_isFullscreen(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - - NSWindowStyleMask mask = (NSWindowStyleMask) objc_msgSend_uint(win->src.window, sel_registerName("styleMask")); - return (mask & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen; -} - -u8 RGFW_window_isHidden(RGFW_window* win) { +RGFW_bool RGFW_window_isHidden(RGFW_window* win) { RGFW_ASSERT(win != NULL); bool visible = objc_msgSend_bool(win->src.window, sel_registerName("isVisible")); return visible == NO && !RGFW_window_isMinimized(win); } -u8 RGFW_window_isMinimized(RGFW_window* win) { +RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { RGFW_ASSERT(win != NULL); return objc_msgSend_bool(win->src.window, sel_registerName("isMiniaturized")) == YES; } -u8 RGFW_window_isMaximized(RGFW_window* win) { +RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { RGFW_ASSERT(win != NULL); - - return objc_msgSend_bool(win->src.window, sel_registerName("isZoomed")); + RGFW_bool b = objc_msgSend_bool(win->src.window, sel_registerName("isZoomed")); + return b; } id RGFW_getNSScreenForDisplayID(CGDirectDisplayID display) { @@ -8715,6 +9065,22 @@ id RGFW_getNSScreenForDisplayID(CGDirectDisplayID display) { return NULL; } + +u32 RGFW_osx_getRefreshRate(CGDirectDisplayID display, CGDisplayModeRef mode) { + if (mode) { + u32 refreshRate = (int)CGDisplayModeGetRefreshRate(mode); + if (refreshRate != 0) return refreshRate; + } + + CVDisplayLinkRef link; + CVDisplayLinkCreateWithCGDisplay(display, &link); + const CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link); + if (!(time.flags & kCVTimeIsIndefinite)) + return (int) (time.timeScale / (double) time.timeValue); + + return 0; +} + RGFW_monitor RGFW_NSCreateMonitor(CGDirectDisplayID display, id screen) { RGFW_monitor monitor; @@ -8722,14 +9088,22 @@ RGFW_monitor RGFW_NSCreateMonitor(CGDirectDisplayID display, id screen) { RGFW_MEMCPY(monitor.name, name, 6); CGRect bounds = CGDisplayBounds(display); - monitor.rect = RGFW_RECT((int) bounds.origin.x, (int) bounds.origin.y, (int) bounds.size.width, (int) bounds.size.height); + monitor.x = bounds.origin.x; + monitor.y = bounds.origin.y; + monitor.mode.area = RGFW_AREA((int) bounds.size.width, (int) bounds.size.height); + + monitor.mode.red = 8; monitor.mode.green = 8; monitor.mode.blue = 8; + + CGDisplayModeRef mode = CGDisplayCopyDisplayMode(display); + monitor.mode.refreshRate = RGFW_osx_getRefreshRate(display, mode); + CFRelease(mode); CGSize screenSizeMM = CGDisplayScreenSize(display); monitor.physW = (float)screenSizeMM.width / 25.4f; monitor.physH = (float)screenSizeMM.height / 25.4f; - float ppi_width = (monitor.rect.w/monitor.physW); - float ppi_height = (monitor.rect.h/monitor.physH); + float ppi_width = (monitor.mode.area.w/monitor.physW); + float ppi_height = (monitor.mode.area.h/monitor.physH); monitor.pixelRatio = ((CGFloat (*)(id, SEL))abi_objc_msgSend_fpret) (screen, sel_registerName("backingScaleFactor")); float dpi = 96.0f * monitor.pixelRatio; @@ -8738,15 +9112,13 @@ RGFW_monitor RGFW_NSCreateMonitor(CGDirectDisplayID display, id screen) { monitor.scaleY = ((i32)(((float) (ppi_height) / dpi) * 10.0f)) / 10.0f; #ifdef RGFW_DEBUG - printf("RGFW INFO: monitor found: scale (%s):\n rect: {%i, %i, %i, %i}\n physical size:%f %f\n scale: %f %f\n pixelRatio: %f\n", monitor.name, monitor.rect.x, monitor.rect.y, monitor.rect.w, monitor.rect.h, monitor.physW, monitor.physH, monitor.scaleX, monitor.scaleY, monitor.pixelRatio); + printf("RGFW INFO: monitor found: scale (%s):\n rect: {%i, %i, %i, %i}\n physical size:%f %f\n scale: %f %f\n pixelRatio: %f\n refreshRate: %i\n depth: %i\n", monitor.name, monitor.x, monitor.y, monitor.mode.area.w, monitor.mode.area.h, monitor.physW, monitor.physH, monitor.scaleX, monitor.scaleY, monitor.pixelRatio, monitor.mode.refreshRate, monitor.mode.red + monitor.mode.green + monitor.mode.blue); #endif return monitor; } -RGFW_monitor RGFW_monitors[7]; - RGFW_monitor* RGFW_getMonitors(void) { static CGDirectDisplayID displays[7]; u32 count; @@ -8754,10 +9126,49 @@ RGFW_monitor* RGFW_getMonitors(void) { if (CGGetActiveDisplayList(6, displays, &count) != kCGErrorSuccess) return NULL; + static RGFW_monitor monitors[7]; + for (u32 i = 0; i < count; i++) - RGFW_monitors[i] = RGFW_NSCreateMonitor(displays[i], RGFW_getNSScreenForDisplayID(displays[i])); + monitors[i] = RGFW_NSCreateMonitor(displays[i], RGFW_getNSScreenForDisplayID(displays[i])); - return RGFW_monitors; + return monitors; +} + +RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { + CGPoint point = { mon.x, mon.y }; + + CGDirectDisplayID display; + uint32_t displayCount = 0; + CGError err = CGGetDisplaysWithPoint(point, 1, &display, &displayCount); + if (err != kCGErrorSuccess || displayCount != 1) + return RGFW_FALSE; + + CFArrayRef allModes = CGDisplayCopyAllDisplayModes(display, NULL); + + if (allModes == NULL) + return RGFW_FALSE; + + for (CFIndex i = 0; i < CFArrayGetCount(allModes); i++) { + CGDisplayModeRef cmode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, i); + + RGFW_monitorMode foundMode; + foundMode.area = RGFW_AREA(CGDisplayModeGetWidth(cmode), CGDisplayModeGetHeight(cmode)); + foundMode.refreshRate = RGFW_osx_getRefreshRate(display, cmode); + foundMode.red = 8; foundMode.green = 8; foundMode.blue = 8; + + if (RGFW_monitorModeCompare(mode, foundMode, request)) { + CGError err = CGDisplaySetDisplayMode(display, cmode, NULL); + if (err == kCGErrorSuccess) { + CFRelease(allModes); + return RGFW_TRUE; + } + break; + } + } + + CFRelease(allModes); + + return RGFW_FALSE; } RGFW_monitor RGFW_getPrimaryMonitor(void) { @@ -8780,7 +9191,7 @@ RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) { size_t clip_len; char* clip = (char*)NSPasteboard_stringForType(NSPasteboard_generalPasteboard(), NSPasteboardTypeString, &clip_len); if (clip == NULL) return -1; - + if (str != NULL) { if (strCapacity < clip_len) return 0; @@ -8807,6 +9218,9 @@ void RGFW_writeClipboard(const char* text, u32 textLen) { RGFW_ASSERT(win != NULL); objc_msgSend_void(win->src.ctx, sel_registerName("makeCurrentContext")); } + void* RGFW_getCurrent_OpenGL(void) { + return objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("currentContext")); + } #endif #if !defined(RGFW_EGL) @@ -8833,7 +9247,7 @@ CGImageRef createImageFromBytes(unsigned char *buffer, int width, int height) buffer, width, height, 8, - RGFW_bufferSize.w * 4, + width * 4, colorSpace, kCGImageAlphaPremultipliedLast); // Create image from bitmap context @@ -8889,28 +9303,17 @@ void RGFW_window_close(RGFW_window* win) { RGFW_ASSERT(win != NULL); NSRelease(win->src.view); - #ifdef RGFW_ALLOC_DROPFILES - { - u32 i; - for (i = 0; i < RGFW_MAX_DROPS; i++) - win->_mem.free(win->_mem.userdata, win->event.droppedFiles[i]); - - - win->_mem.free(win->_mem.userdata, win->event.droppedFiles); - } - #endif - #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) NSRelease(win->src.bitmap); NSRelease(win->src.image); if ((win->_flags & RGFW_BUFFER_ALLOC)) - win->_mem.free(win->_mem.userdata, win->buffer); + RGFW_FREE(win->buffer); #endif RGFW_clipboard_switch(NULL); if ((win->_flags & RGFW_WINDOW_ALLOC)) - win->_mem.free(win->_mem.userdata, win); + RGFW_FREE(win); } u64 RGFW_getTimeNS(void) { @@ -8921,13 +9324,21 @@ u64 RGFW_getTimeNS(void) { return mach_absolute_time() * timebase_info.numer / timebase_info.denom; } -u64 RGFW_getTime(void) { - static mach_timebase_info_data_t timebase_info; - if (timebase_info.denom == 0) { - mach_timebase_info(&timebase_info); +u64 RGFW_osx_initTimer(void) { + static u64 freq = 0; + if (freq == 0) { + mach_timebase_info_data_t info; + mach_timebase_info(&info); + freq = (info.denom * 1e9) / info.numer; } - return (double) mach_absolute_time() * (double) timebase_info.numer / ((double) timebase_info.denom * 1e9); + + return freq; } + +u64 RGFW_getTime(void) { return (double)RGFW_getTimerValue() * RGFW_getTimerFreq(); } +u64 RGFW_getTimerFreq(void) { return (u64)RGFW_osx_initTimer(); } +u64 RGFW_getTimerValue(void) { return (u64)mach_absolute_time(); } + #endif /* RGFW_MACOS */ /* @@ -8935,10 +9346,10 @@ u64 RGFW_getTime(void) { */ /* - WEBASM defines + WASM defines */ -#ifdef RGFW_WEBASM +#ifdef RGFW_WASM RGFW_event RGFW_events[20]; size_t RGFW_eventLen = 0; @@ -9021,15 +9432,13 @@ EM_BOOL Emscripten_on_mousemove(int eventType, const EmscriptenMouseEvent* e, vo RGFW_events[RGFW_eventLen].type = RGFW_mousePosChanged; - if ((RGFW_root->_flags & RGFW_HOLD_MOUSE)) { - RGFW_point p = RGFW_POINT(e->movementX, e->movementY); - RGFW_events[RGFW_eventLen].point = p; - } - else - RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->targetX, e->targetY); + RGFW_point p = RGFW_POINT(e->movementX, e->movementY); + RGFW_events[RGFW_eventLen].vector = p; + RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->targetX, e->targetY); RGFW_eventLen++; - RGFW_mousePosCallback(RGFW_root, RGFW_events[RGFW_eventLen].point); + RGFW_root->_lastMousePoint = RGFW_events[RGFW_eventLen].point; + RGFW_mousePosCallback(RGFW_root, RGFW_events[RGFW_eventLen].point, RGFW_events[RGFW_eventLen].vector); return EM_TRUE; } @@ -9038,8 +9447,10 @@ EM_BOOL Emscripten_on_mousedown(int eventType, const EmscriptenMouseEvent* e, vo RGFW_events[RGFW_eventLen].type = RGFW_mouseButtonPressed; RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->targetX, e->targetY); - RGFW_events[RGFW_eventLen].button = e->button + 1; + RGFW_events[RGFW_eventLen].button = e->button; RGFW_events[RGFW_eventLen].scroll = 0; + if (RGFW_events[RGFW_eventLen].button > 2) + RGFW_events[RGFW_eventLen].button += 2; RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].prev = RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current; RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current = 1; @@ -9052,11 +9463,13 @@ EM_BOOL Emscripten_on_mousedown(int eventType, const EmscriptenMouseEvent* e, vo EM_BOOL Emscripten_on_mouseup(int eventType, const EmscriptenMouseEvent* e, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); - + RGFW_events[RGFW_eventLen].type = RGFW_mouseButtonReleased; - RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->targetX, e->targetY); - RGFW_events[RGFW_eventLen].button = e->button + 1; + RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->targetX, e->targetY); + RGFW_events[RGFW_eventLen].button = e->button; RGFW_events[RGFW_eventLen].scroll = 0; + if (RGFW_events[RGFW_eventLen].button > 2) + RGFW_events[RGFW_eventLen].button += 2; RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].prev = RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current; RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current = 0; @@ -9097,7 +9510,8 @@ EM_BOOL Emscripten_on_touchstart(int eventType, const EmscriptenTouchEvent* e, v RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].prev = RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current; RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current = 1; - RGFW_mousePosCallback(RGFW_root, RGFW_events[RGFW_eventLen].point); + RGFW_root->_lastMousePoint = RGFW_events[RGFW_eventLen].point; + RGFW_mousePosCallback(RGFW_root, RGFW_events[RGFW_eventLen].point, RGFW_events[RGFW_eventLen].vector); RGFW_mouseButtonCallback(RGFW_root, RGFW_events[RGFW_eventLen].button, RGFW_events[RGFW_eventLen].scroll, 1); RGFW_eventLen++; @@ -9113,7 +9527,8 @@ EM_BOOL Emscripten_on_touchmove(int eventType, const EmscriptenTouchEvent* e, vo RGFW_events[RGFW_eventLen].type = RGFW_mousePosChanged; RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->touches[i].targetX, e->touches[i].targetY); - RGFW_mousePosCallback(RGFW_root, RGFW_events[RGFW_eventLen].point); + RGFW_root->_lastMousePoint = RGFW_events[RGFW_eventLen].point; + RGFW_mousePosCallback(RGFW_root, RGFW_events[RGFW_eventLen].point, RGFW_events[RGFW_eventLen].vector); RGFW_eventLen++; } return EM_TRUE; @@ -9176,7 +9591,7 @@ EM_BOOL Emscripten_on_gamepad(int eventType, const EmscriptenGamepadEvent *gamep return 1; // The event was consumed by the callback handler } -u32 RGFW_webasmPhysicalToRGFW(u32 hash) { +u32 RGFW_wASMPhysicalToRGFW(u32 hash) { switch(hash) { /* 0x0000 */ case 0x67243A2DU /* Escape */: return RGFW_escape; /* 0x0001 */ case 0x67251058U /* Digit0 */: return RGFW_0; /* 0x0002 */ @@ -9192,7 +9607,7 @@ u32 RGFW_webasmPhysicalToRGFW(u32 hash) { case 0x92E14DD3U /* Minus */: return RGFW_minus; /* 0x000C */ case 0x92E1FBACU /* Equal */: return RGFW_equals; /* 0x000D */ case 0x36BF1CB5U /* Backspace */: return RGFW_backSpace; /* 0x000E */ - case 0x7B8E51E2U /* Tab */: return RGFW_tab; /* 0x000F */ + case 0x7B8E51E2U /* Tab */: return RGFW_tab; /* 0x000F */ case 0x2C595B51U /* KeyQ */: return RGFW_q; /* 0x0010 */ case 0x2C595B57U /* KeyW */: return RGFW_w; /* 0x0011 */ case 0x2C595B45U /* KeyE */: return RGFW_e; /* 0x0012 */ @@ -9234,7 +9649,7 @@ u32 RGFW_webasmPhysicalToRGFW(u32 hash) { case 0x5D64DA91U /* NumpadMultiply */: return RGFW_multiply; case 0xC914958CU /* AltLeft */: return RGFW_altL; /* 0x0038 */ case 0x92E09CB5U /* Space */: return RGFW_space; /* 0x0039 */ - case 0xB8FAE73BU /* CapsLock */: return RGFW_capsLock; /* 0x003A */ + case 0xB8FAE73BU /* CapsLock */: return RGFW_capsLock; /* 0x003A */ case 0x7174B789U /* F1 */: return RGFW_F1; /* 0x003B */ case 0x7174B78AU /* F2 */: return RGFW_F2; /* 0x003C */ case 0x7174B78BU /* F3 */: return RGFW_F3; /* 0x003D */ @@ -9244,7 +9659,7 @@ u32 RGFW_webasmPhysicalToRGFW(u32 hash) { case 0x7174B78FU /* F7 */: return RGFW_F7; /* 0x0041 */ case 0x7174B780U /* F8 */: return RGFW_F8; /* 0x0042 */ case 0x7174B781U /* F9 */: return RGFW_F9; /* 0x0043 */ - case 0x7B8E57B0U /* F10 */: return RGFW_F10; /* 0x0044 */ + case 0x7B8E57B0U /* F10 */: return RGFW_F10; /* 0x0044 */ case 0xC925FCDFU /* Numpad7 */: return RGFW_multiply; /* 0x0047 */ case 0xC925FCD0U /* Numpad8 */: return RGFW_KP_8; /* 0x0048 */ case 0xC925FCD1U /* Numpad9 */: return RGFW_KP_9; /* 0x0049 */ @@ -9257,17 +9672,17 @@ u32 RGFW_webasmPhysicalToRGFW(u32 hash) { case 0xC925FCDBU /* Numpad3 */: return RGFW_KP_3; /* 0x0051 */ case 0xC925FCD8U /* Numpad0 */: return RGFW_KP_0; /* 0x0052 */ case 0x95852DACU /* NumpadDecimal */: return RGFW_period; /* 0x0053 */ - case 0x7B8E57B1U /* F11 */: return RGFW_F11; /* 0x0057 */ - case 0x7B8E57B2U /* F12 */: return RGFW_F12; /* 0x0058 */ + case 0x7B8E57B1U /* F11 */: return RGFW_F11; /* 0x0057 */ + case 0x7B8E57B2U /* F12 */: return RGFW_F12; /* 0x0058 */ case 0x7393FBACU /* NumpadEqual */: return RGFW_KP_Return; - case 0xB88EBF7CU /* AltRight */: return RGFW_altR; /* 0xE038 */ + case 0xB88EBF7CU /* AltRight */: return RGFW_altR; /* 0xE038 */ case 0xC925873BU /* NumLock */: return RGFW_numLock; /* 0xE045 */ case 0x2C595F45U /* Home */: return RGFW_home; /* 0xE047 */ case 0xC91BB690U /* ArrowUp */: return RGFW_up; /* 0xE048 */ case 0x672F9210U /* PageUp */: return RGFW_pageUp; /* 0xE049 */ case 0x3799258CU /* ArrowLeft */: return RGFW_left; /* 0xE04B */ case 0x4CE33F7CU /* ArrowRight */: return RGFW_right; /* 0xE04D */ - case 0x7B8E55DCU /* End */: return RGFW_end; /* 0xE04F */ + case 0x7B8E55DCU /* End */: return RGFW_end; /* 0xE04F */ case 0x3799379EU /* ArrowDown */: return RGFW_down; /* 0xE050 */ case 0xBA90179EU /* PageDown */: return RGFW_pageDown; /* 0xE051 */ case 0x6723CB2CU /* Insert */: return RGFW_insert; /* 0xE052 */ @@ -9279,13 +9694,13 @@ u32 RGFW_webasmPhysicalToRGFW(u32 hash) { return 0; } -void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyEvent(char* key, char* code, b8 press) { +void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyEvent(char* key, char* code, RGFW_bool press) { const char* iCode = code; u32 hash = 0; while(*iCode) hash = ((hash ^ 0x7E057D79U) << 3) ^ (unsigned int)*iCode++; - u32 physicalKey = RGFW_webasmPhysicalToRGFW(hash); + u32 physicalKey = RGFW_wASMPhysicalToRGFW(hash); u8 mappedKey = (u8)(*((u32*)key)); @@ -9304,13 +9719,10 @@ void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyEvent(char* key, char* code, b8 press) { RGFW_keyboard[physicalKey].current = press; RGFW_keyCallback(RGFW_root, physicalKey, mappedKey, RGFW_root->event.keyMod, press); - - RGFW_free(key); - RGFW_free(code); } -void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyMods(b8 capital, b8 numlock, b8 control, b8 alt, b8 shift, b8 super) { - RGFW_updateKeyModsPro(RGFW_root, capital, numlock, control, alt, shift, super); +void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyMods(RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll) { + RGFW_updateKeyModsPro(RGFW_root, capital, numlock, control, alt, shift, super, scroll); } void EMSCRIPTEN_KEEPALIVE Emscripten_onDrop(size_t count) { @@ -9322,21 +9734,19 @@ void EMSCRIPTEN_KEEPALIVE Emscripten_onDrop(size_t count) { RGFW_eventLen++; } -b8 RGFW_stopCheckEvents_bool = RGFW_FALSE; +RGFW_bool RGFW_stopCheckEvents_bool = RGFW_FALSE; void RGFW_stopCheckEvents(void) { RGFW_stopCheckEvents_bool = RGFW_TRUE; } -void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) { +void RGFW_window_eventWait(RGFW_window* win, u32 waitMS) { RGFW_UNUSED(win); - - if (waitMS == 0) - return; + if (waitMS == 0) return; u32 start = (u32)(((u64)RGFW_getTimeNS()) / 1e+6); while ((RGFW_eventLen == 0) && RGFW_stopCheckEvents_bool == RGFW_FALSE && - (waitMS < 0 || (RGFW_getTimeNS() / 1e+6) - start < waitMS) + (waitMS != RGFW_eventWaitNext || (RGFW_getTimeNS() / 1e+6) - start < waitMS) ) { emscripten_sleep(0); } @@ -9344,20 +9754,16 @@ void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) { RGFW_stopCheckEvents_bool = RGFW_FALSE; } -RGFWDEF void RGFW_init_buffer(RGFW_window* win); -void RGFW_init_buffer(RGFW_window* win) { +void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area){ #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - if (RGFW_bufferSize.w == 0 && RGFW_bufferSize.h == 0) - RGFW_bufferSize = RGFW_getScreenSize(); - - win->buffer = RGFW_alloc(RGFW_bufferSize.w * RGFW_bufferSize.h * 4); - win->_flags |= RGFW_BUFFER_ALLOC; + win->buffer = buffer; + win->bufferSize = area; #ifdef RGFW_OSMESA win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL); OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, win->r.w, win->r.h); #endif #else - RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ + RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area); /*!< if buffer rendering is not being used */ #endif } @@ -9393,22 +9799,21 @@ RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowF #ifndef RGFW_WEBGPU EmscriptenWebGLContextAttributes attrs; - attrs.alpha = EM_TRUE; - attrs.depth = EM_TRUE; - attrs.alpha = EM_TRUE; - attrs.stencil = RGFW_STENCIL; - attrs.antialias = RGFW_SAMPLES; + attrs.alpha = RGFW_GL_HINTS[RGFW_glDepth]; + attrs.depth = RGFW_GL_HINTS[RGFW_glAlpha]; + attrs.stencil = RGFW_GL_HINTS[RGFW_glStencil]; + attrs.antialias = RGFW_GL_HINTS[RGFW_glSamples]; attrs.premultipliedAlpha = EM_TRUE; attrs.preserveDrawingBuffer = EM_FALSE; - if (RGFW_DOUBLE_BUFFER == 0) + if (RGFW_GL_HINTS[RGFW_glDoubleBuffer] == 0) attrs.renderViaOffscreenBackBuffer = 0; else - attrs.renderViaOffscreenBackBuffer = RGFW_AUX_BUFFERS; + attrs.renderViaOffscreenBackBuffer = RGFW_GL_HINTS[RGFW_glAuxBuffers]; attrs.failIfMajorPerformanceCaveat = EM_FALSE; - attrs.majorVersion = (RGFW_majorVersion == 0) ? 1 : RGFW_majorVersion; - attrs.minorVersion = RGFW_minorVersion; + attrs.majorVersion = (RGFW_GL_HINTS[RGFW_glMinor] == 0) ? 1 : RGFW_GL_HINTS[RGFW_glMinor]; + attrs.minorVersion = RGFW_GL_HINTS[RGFW_glMajor]; attrs.enableExtensionsByDefault = EM_TRUE; attrs.explicitSwapControl = EM_TRUE; @@ -9452,14 +9857,18 @@ RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowF EM_ASM({ window.addEventListener("keydown", (event) => { - Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta")); - Module._RGFW_handleKeyEvent(stringToNewUTF8(event.key), stringToNewUTF8(event.code), 1); + var key = stringToNewUTF8(event.key); var code = stringToNewUTF8(event.code); + Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta"), event.getModifierState("ScrollLock")); + Module._RGFW_handleKeyEvent(key, code, 1); + _free(key); _free(code); }, true); window.addEventListener("keyup", (event) => { - Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta")); - Module._RGFW_handleKeyEvent(stringToNewUTF8(event.key), stringToNewUTF8(event.code), 0); + var key = stringToNewUTF8(event.key); var code = stringToNewUTF8(event.code); + Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta"), event.getModifierState("ScrollLock")); + Module._RGFW_handleKeyEvent(key, code, 0); + _free(key); _free(code); }, true); }); @@ -9514,16 +9923,9 @@ RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowF canvas.addEventListener('dragover', function(e) { e.preventDefault(); return false; }, true); }); - RGFW_init_buffer(win); glViewport(0, 0, rect.w, rect.h); - if (flags & RGFW_windowHideMouse) { - RGFW_window_showMouse(win, 0); - } - - if (flags & RGFW_windowFullscreen) { - RGFW_window_resize(win, RGFW_getScreenSize()); - } + RGFW_window_setFlags(win, flags); #ifdef RGFW_DEBUG printf("RGFW INFO: a window with a rect of {%i, %i, %i, %i} \n", win->r.x, win->r.y, win->r.w, win->r.h); @@ -9634,31 +10036,24 @@ RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) { RGFW_UNUSED(ch void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) { RGFW_UNUSED(win); RGFW_UNUSED(mouse); } void RGFW_freeMouse(RGFW_mouse* mouse) { RGFW_UNUSED(mouse); } -const char RGFW_CURSORS[11][12] = { - "default", - "default", - "text", - "crosshair", - "pointer", - "ew-resize", - "ns-resize", - "nwse-resize", - "nesw-resize", - "move", - "not-allowed" -}; +RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) { + static const char cursors[11][12] = { + "default", "default", "text", "crosshair", + "pointer", "ew-resize", "ns-resize", "nwse-resize", "nesw-resize", + "move", "not-allowed" + }; -b32 RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) { RGFW_UNUSED(win); - EM_ASM( { document.getElementById("canvas").style.cursor = UTF8ToString($0); }, RGFW_CURSORS[mouse]); - return 1; + EM_ASM( { document.getElementById("canvas").style.cursor = UTF8ToString($0); }, cursors[mouse]); + return RGFW_TRUE; } -b32 RGFW_window_setMouseDefault(RGFW_window* win) { +RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) { return RGFW_window_setMouseStandard(win, RGFW_mouseNormal); } -void RGFW_window_showMouse(RGFW_window* win, i8 show) { +void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) { + RGFW_window_showMouseFlags(win, show); if (show) RGFW_window_setMouseDefault(win); else @@ -9676,15 +10071,7 @@ RGFW_point RGFW_getGlobalMousePoint(void) { return point; } -RGFW_point RGFW_window_getMousePoint(RGFW_window* win) { - RGFW_UNUSED(win); - - EmscriptenMouseEvent mouseEvent; - emscripten_get_mouse_status(&mouseEvent); - return RGFW_POINT( mouseEvent.targetX, mouseEvent.targetY); -} - -void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough) { +void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) { RGFW_UNUSED(win); EM_ASM_({ @@ -9729,10 +10116,10 @@ void RGFW_window_swapBuffers(RGFW_window* win) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, RGFW_bufferSize.w, RGFW_bufferSize.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, win->buffer); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, win->bufferSize.w, win->bufferSize.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, win->buffer); - float ratioX = ((float)win->r.w / (float)RGFW_bufferSize.w); - float ratioY = ((float)win->r.h / (float)RGFW_bufferSize.h); + float ratioX = ((float)win->r.w / (float)win->bufferSize.w); + float ratioY = ((float)win->r.h / (float)win->bufferSize.h); // Set up the viewport glClear(GL_COLOR_BUFFER_BIT); @@ -9767,6 +10154,10 @@ void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { #endif } +#ifndef RGFW_WEBGPU +void* RGFW_getCurrent_OpenGL(void) { return (void*)emscripten_webgl_get_current_context(); } +#endif + #ifndef RGFW_EGL void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { RGFW_UNUSED(win); RGFW_UNUSED(swapInterval); } #endif @@ -9778,13 +10169,13 @@ void RGFW_window_close(RGFW_window* win) { #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) if ((win->_flags & RGFW_BUFFER_ALLOC)) - win->_mem.free(win->_mem.userdata, win->buffer); + RGFW_FREE(win->buffer); #endif RGFW_clipboard_switch(NULL); if ((win->_flags & RGFW_WINDOW_ALLOC)) - win->_mem.free(win->_mem.userdata, win); + RGFW_FREE(win); } int RGFW_innerWidth(void) { return EM_ASM_INT({ return window.innerWidth; }); } @@ -9802,14 +10193,15 @@ void RGFW_sleep(u64 milisecond) { emscripten_sleep(milisecond); } -u64 RGFW_getTimeNS(void) { - return emscripten_get_now() * 1e+6; -} +u64 RGFW_getTimeNS(void) { return RGFW_getTimerValue(); } u64 RGFW_getTime(void) { return emscripten_get_now() * 1000; } +u64 RGFW_getTimerFreq(void) { return (u64)1000000000LLU; } +u64 RGFW_getTimerValue(void) { return emscripten_get_now() * 1e+6; } + void RGFW_releaseCursor(RGFW_window* win) { RGFW_UNUSED(win); emscripten_exit_pointerlock(); @@ -9827,30 +10219,62 @@ 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); + + RGFW_area screen = RGFW_getScreenSize(); + RGFW_window_move(win, RGFW_POINT(0, 0)); + RGFW_window_resize(win, screen); +} + +void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) { + RGFW_ASSERT(win != NULL); + if (fullscreen) { + win->_flags |= RGFW_windowFullscreen; + EM_ASM( Module.requestFullscreen(false, true); ); + return; + } + win->_flags &= ~RGFW_windowFullscreen; + EM_ASM( Module.exitFullscreen(false, true); ); +} + +void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) { + RGFW_UNUSED(win); + EM_ASM({ + var element = document.getElementById("canvas"); + if (element) + element.style.opacity = $1; + }, "elementId", opacity); +} + /* unsupported functions */ +void RGFW_window_focus(RGFW_window* win) { RGFW_UNUSED(win); } +void RGFW_window_raise(RGFW_window* win) { RGFW_UNUSED(win); } +RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { RGFW_UNUSED(mon); RGFW_UNUSED(mode); RGFW_UNUSED(request); return RGFW_FALSE; } RGFW_monitor* RGFW_getMonitors(void) { return NULL; } RGFW_monitor RGFW_getPrimaryMonitor(void) { return (RGFW_monitor){}; } void RGFW_window_move(RGFW_window* win, RGFW_point v) { RGFW_UNUSED(win); RGFW_UNUSED(v); } +void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win); RGFW_UNUSED(a); } void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win); RGFW_UNUSED(a); } void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win); RGFW_UNUSED(a); } void RGFW_window_minimize(RGFW_window* win) { RGFW_UNUSED(win); } void RGFW_window_restore(RGFW_window* win) { RGFW_UNUSED(win); } -void RGFW_window_setBorder(RGFW_window* win, b8 border) { RGFW_UNUSED(win); RGFW_UNUSED(border); } -b32 RGFW_window_setIcon(RGFW_window* win, u8* icon, RGFW_area a, i32 channels) { RGFW_UNUSED(win); RGFW_UNUSED(icon); RGFW_UNUSED(a); RGFW_UNUSED(channels); return 0; } +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_setIcon(RGFW_window* win, u8* icon, RGFW_area a, i32 channels) { RGFW_UNUSED(win); RGFW_UNUSED(icon); RGFW_UNUSED(a); RGFW_UNUSED(channels); return RGFW_FALSE; } void RGFW_window_hide(RGFW_window* win) { RGFW_UNUSED(win); } void RGFW_window_show(RGFW_window* win) {RGFW_UNUSED(win); } -b8 RGFW_window_isHidden(RGFW_window* win) { RGFW_UNUSED(win); return 0; } -b8 RGFW_window_isMinimized(RGFW_window* win) { RGFW_UNUSED(win); return 0; } -b8 RGFW_window_isMaximized(RGFW_window* win) { RGFW_UNUSED(win); return 0; } +RGFW_bool RGFW_window_isHidden(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; } +RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; } +RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; } +RGFW_bool RGFW_window_isFloating(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; } RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { RGFW_UNUSED(win); return (RGFW_monitor){}; } #endif /* end of web asm defines */ /* unix (macOS, linux, web asm) only stuff */ -#if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WEBASM) || defined(RGFW_WAYLAND) - -/* unix threading */ +#if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WASM) || defined(RGFW_WAYLAND) #ifndef RGFW_NO_THREADS #include @@ -9871,9 +10295,7 @@ void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { RGFW_UNUSED(threa #endif #endif -#ifndef RGFW_WEBASM - -/* unix sleep */ +#ifndef RGFW_WASM void RGFW_sleep(u64 ms) { struct timespec time; time.tv_sec = 0; @@ -9883,7 +10305,6 @@ void RGFW_sleep(u64 ms) { nanosleep(&time, NULL); #endif } - #endif #endif /* end of unix / mac stuff*/ diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c index 710b05f39..ea9980c54 100644 --- a/src/platforms/rcore_desktop_rgfw.c +++ b/src/platforms/rcore_desktop_rgfw.c @@ -48,6 +48,11 @@ * **********************************************************************************************/ +#ifndef RAYLIB_H /* this should never actually happen, it's only here for IDEs */ +#include "raylib.h" +#include "../rcore.c" +#endif + #if defined(PLATFORM_WEB_RGFW) #define RGFW_NO_GL_HEADER #endif @@ -86,8 +91,8 @@ void CloseWindow(void); #define Size NSSIZE #endif -#define RGFW_ALLOC(ptr, size) (RGFW_UNUSED(ptr),RL_MALLOC(size)) -#define RGFW_FREE(ptr, size) (RGFW_UNUSED(ptr),RL_FREE(size)) +#define RGFW_ALLOC RL_MALLOC +#define RGFW_FREE RL_FREE #define RGFW_CALLOC RL_CALLOC #include "../external/RGFW.h" @@ -115,6 +120,7 @@ void CloseWindow(void); //---------------------------------------------------------------------------------- typedef struct { RGFW_window *window; // Native display device (physical screen connection) + RGFW_monitor mon; } PlatformData; //---------------------------------------------------------------------------------- @@ -228,7 +234,8 @@ static const unsigned short keyMappingRGFW[] = { [RGFW_KP_8] = KEY_KP_8, [RGFW_KP_9] = KEY_KP_9, [RGFW_KP_0] = KEY_KP_0, - [RGFW_KP_Period] = KEY_KP_DECIMAL + [RGFW_KP_Period] = KEY_KP_DECIMAL, + [RGFW_scrollLock] = KEY_SCROLL_LOCK, }; //---------------------------------------------------------------------------------- @@ -258,17 +265,64 @@ bool WindowShouldClose(void) // Toggle fullscreen mode void ToggleFullscreen(void) { - RGFW_window_maximize(platform.window); - ToggleBorderlessWindowed(); + if (!CORE.Window.fullscreen) + { + // Store previous window position (in case we exit fullscreen) + CORE.Window.previousPosition = CORE.Window.position; + + platform.mon = RGFW_window_getMonitor(platform.window); + CORE.Window.fullscreen = true; + CORE.Window.flags |= FLAG_FULLSCREEN_MODE; + + RGFW_monitor_scaleToWindow(platform.mon, platform.window); + RGFW_window_fullscreen(platform.window); + } + else + { + CORE.Window.fullscreen = false; + CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE; + + if (platform.mon.mode.area.w) + { + RGFW_monitor monitor = RGFW_window_getMonitor(platform.window); + + RGFW_monitor_scale(monitor, platform.mon.mode.area); + platform.mon.mode.area.w = 0; + } + + // we update the window position right away + CORE.Window.position = CORE.Window.previousPosition; + RGFW_window_move(platform.window, RGFW_POINT(CORE.Window.position.x, CORE.Window.position.y)); + } + + // Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS) + // NOTE: V-Sync can be enabled by graphic driver configuration + if (CORE.Window.flags & FLAG_VSYNC_HINT) RGFW_window_swapInterval(platform.window, 1); } // Toggle borderless windowed mode void ToggleBorderlessWindowed(void) { - if (platform.window != NULL) + if (platform.window == NULL) + return; + + if (CORE.Window.fullscreen) { - RGFW_window_setBorder(platform.window, CORE.Window.flags & FLAG_WINDOW_UNDECORATED); + CORE.Window.previousPosition = CORE.Window.position; + CORE.Window.previousScreen = CORE.Window.screen; + + RGFW_window_setBorder(platform.window, 0); + + RGFW_monitor mon = RGFW_window_getMonitor(platform.window); + RGFW_window_resize(platform.window, mon.mode.area); + } else { + RGFW_window_setBorder(platform.window, 1); + + CORE.Window.position = CORE.Window.previousPosition; + RGFW_window_resize(platform.window, RGFW_AREA(CORE.Window.previousScreen.width, CORE.Window.previousScreen.height)); } + + CORE.Window.fullscreen = !CORE.Window.fullscreen; } // Set window state: maximized, if resizable @@ -286,6 +340,9 @@ void MinimizeWindow(void) // Set window state: not minimized/maximized void RestoreWindow(void) { + if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) + RGFW_window_focus(platform.window); + RGFW_window_restore(platform.window); } @@ -300,17 +357,17 @@ void SetWindowState(unsigned int flags) } if (flags & FLAG_FULLSCREEN_MODE) { - RGFW_window_maximize(platform.window); - ToggleBorderlessWindowed(); + if (!CORE.Window.fullscreen) + ToggleFullscreen(); } if (flags & FLAG_WINDOW_RESIZABLE) { - RGFW_window_setMaxSize(platform.window, RGFW_AREA(platform.window->r.w, platform.window->r.h)); - RGFW_window_setMinSize(platform.window, RGFW_AREA(platform.window->r.w, platform.window->r.h)); + RGFW_window_setMaxSize(platform.window, RGFW_AREA(0, 0)); + RGFW_window_setMinSize(platform.window, RGFW_AREA(0, 0)); } if (flags & FLAG_WINDOW_UNDECORATED) { - ToggleBorderlessWindowed(); + RGFW_window_setBorder(platform.window, 0); } if (flags & FLAG_WINDOW_HIDDEN) { @@ -326,27 +383,27 @@ void SetWindowState(unsigned int flags) } if (flags & FLAG_WINDOW_UNFOCUSED) { - TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_UNFOCUSED is not supported on PLATFORM_DESKTOP_RGFW"); + CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED; } if (flags & FLAG_WINDOW_TOPMOST) { - TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_TOPMOST is not supported on PLATFORM_DESKTOP_RGFW"); + RGFW_window_setFloating(platform.window, RGFW_TRUE); } if (flags & FLAG_WINDOW_ALWAYS_RUN) { - TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_ALWAYS_RUN is not supported on PLATFORM_DESKTOP_RGFW"); + CORE.Window.flags |= FLAG_WINDOW_ALWAYS_RUN; } if (flags & FLAG_WINDOW_TRANSPARENT) { - TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_TRANSPARENT post window creation post window creation is not supported on PLATFORM_DESKTOP_RGFW"); + TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only be configured before window initialization"); } if (flags & FLAG_WINDOW_HIGHDPI) { - TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_HIGHDPI is not supported on PLATFORM_DESKTOP_RGFW"); + TRACELOG(LOG_WARNING, "WINDOW: High DPI can only be configured before window initialization"); } if (flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) { - RGFW_window_setMousePassthrough(platform.window, flags & FLAG_WINDOW_MOUSE_PASSTHROUGH); + RGFW_window_setMousePassthrough(platform.window, 1); } if (flags & FLAG_BORDERLESS_WINDOWED_MODE) { @@ -358,7 +415,7 @@ void SetWindowState(unsigned int flags) } if (flags & FLAG_INTERLACED_HINT) { - TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_INTERLACED_HINT is not supported on PLATFORM_DESKTOP_RGFW"); + TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only be configured before window initialization"); } } @@ -373,60 +430,65 @@ void ClearWindowState(unsigned int flags) } if (flags & FLAG_FULLSCREEN_MODE) { - ToggleBorderlessWindowed(); - RGFW_window_restore(platform.window); - CORE.Window.fullscreen = false; + if (CORE.Window.fullscreen) + ToggleFullscreen(); } if (flags & FLAG_WINDOW_RESIZABLE) { - RGFW_window_setMaxSize(platform.window, RGFW_AREA(0, 0)); - RGFW_window_setMinSize(platform.window, RGFW_AREA(0, 0)); + RGFW_window_setMaxSize(platform.window, RGFW_AREA(platform.window->r.w, platform.window->r.h)); + RGFW_window_setMinSize(platform.window, RGFW_AREA(platform.window->r.w, platform.window->r.h)); } if (flags & FLAG_WINDOW_UNDECORATED) { - ToggleBorderlessWindowed(); + RGFW_window_setBorder(platform.window, 1); } if (flags & FLAG_WINDOW_HIDDEN) { + if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) + RGFW_window_focus(platform.window); RGFW_window_show(platform.window); } if (flags & FLAG_WINDOW_MINIMIZED) { + if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) + RGFW_window_focus(platform.window); + RGFW_window_restore(platform.window); } if (flags & FLAG_WINDOW_MAXIMIZED) { + if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) + RGFW_window_focus(platform.window); RGFW_window_restore(platform.window); } if (flags & FLAG_WINDOW_UNFOCUSED) { - TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_UNFOCUSED is not supported on PLATFORM_DESKTOP_RGFW"); + CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; } if (flags & FLAG_WINDOW_TOPMOST) { - TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_TOPMOST is not supported on PLATFORM_DESKTOP_RGFW"); + RGFW_window_setFloating(platform.window, RGFW_FALSE); } if (flags & FLAG_WINDOW_ALWAYS_RUN) { - TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_ALWAYS_RUN is not supported on PLATFORM_DESKTOP_RGFW"); + CORE.Window.flags &= ~FLAG_WINDOW_ALWAYS_RUN; } if (flags & FLAG_WINDOW_TRANSPARENT) { - TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_TRANSPARENT is not supported on PLATFORM_DESKTOP_RGFW"); + TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only be configured before window initialization"); } if (flags & FLAG_WINDOW_HIGHDPI) { - // NOTE: There also doesn't seem to be a feature to disable high DPI once enabled - TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_HIGHDPI is not supported on PLATFORM_DESKTOP_RGFW"); + TRACELOG(LOG_WARNING, "WINDOW: High DPI can only be configured before window initialization"); } if (flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) { - RGFW_window_setMousePassthrough(platform.window, flags & FLAG_WINDOW_MOUSE_PASSTHROUGH); - TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_MOUSE_PASSTHROUGH is not supported on PLATFORM_DESKTOP_RGFW"); + RGFW_window_setMousePassthrough(platform.window, 0); } if (flags & FLAG_BORDERLESS_WINDOWED_MODE) { - ToggleFullscreen(); + if (CORE.Window.fullscreen) + ToggleBorderlessWindowed(); } if (flags & FLAG_MSAA_4X_HINT) { @@ -434,7 +496,7 @@ void ClearWindowState(unsigned int flags) } if (flags & FLAG_INTERLACED_HINT) { - TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_INTERLACED_HINT is not supported on PLATFORM_DESKTOP_RGFW"); + TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only be configured before window initialization"); } } @@ -490,7 +552,7 @@ void SetWindowIcon(Image image) // Set icon for window void SetWindowIcons(Image *images, int count) { - TRACELOG(LOG_WARNING, "SetWindowIcons() not available on target platform"); + TRACELOG(LOG_WARNING, "SetWindowIcons() unsupported on target platform"); } // Set title for window @@ -540,13 +602,13 @@ void SetWindowSize(int width, int height) // Set window opacity, value opacity is between 0.0 and 1.0 void SetWindowOpacity(float opacity) { - TRACELOG(LOG_WARNING, "SetWindowOpacity() not available on target platform"); + RGFW_window_setOpacity(win, opacity); } // Set window focused void SetWindowFocused(void) { - RGFW_window_show(platform.window); + RGFW_window_focus(platform.window); } // Get native window handle @@ -569,7 +631,7 @@ int GetMonitorCount(void) for (int i = 0; i < 6; i++) { - if (!mons[i].rect.x && !mons[i].rect.y && !mons[i].rect.w && mons[i].rect.h) + if (!mons[i].x && !mons[i].y && !mons[i].mode.area.w && mons[i].mode.area.h) { count = i; break; @@ -587,7 +649,7 @@ int GetCurrentMonitor(void) for (int i = 0; i < 6; i++) { - if ((mons[i].rect.x == mon.rect.x) && (mons[i].rect.y == mon.rect.y)) return i; + if ((mons[i].x == mon.x) && (mons[i].y == mon.y)) return i; } return 0; @@ -598,7 +660,7 @@ Vector2 GetMonitorPosition(int monitor) { RGFW_monitor *mons = RGFW_getMonitors(); - return (Vector2){ (float)mons[monitor].rect.x, (float)mons[monitor].rect.y }; + return (Vector2){ (float)mons[monitor].x, (float)mons[monitor].y }; } // Get selected monitor width (currently used by monitor) @@ -606,7 +668,7 @@ int GetMonitorWidth(int monitor) { RGFW_monitor *mons = RGFW_getMonitors(); - return mons[monitor].rect.w; + return mons[monitor].mode.area.w; } // Get selected monitor height (currently used by monitor) @@ -614,7 +676,7 @@ int GetMonitorHeight(int monitor) { RGFW_monitor *mons = RGFW_getMonitors(); - return mons[monitor].rect.h; + return mons[monitor].mode.area.h; } // Get selected monitor physical width in millimetres @@ -636,8 +698,9 @@ int GetMonitorPhysicalHeight(int monitor) // Get selected monitor refresh rate int GetMonitorRefreshRate(int monitor) { - TRACELOG(LOG_WARNING, "GetMonitorRefreshRate() not implemented on target platform"); - return 0; + RGFW_monitor *mons = RGFW_getMonitors(); + + return (int)mons[monitor].refreshRate; } // Get the human-readable, UTF-8 encoded name of the selected monitor @@ -785,14 +848,14 @@ void OpenURL(const char *url) // Set internal gamepad mappings int SetGamepadMappings(const char *mappings) { - TRACELOG(LOG_WARNING, "SetGamepadMappings() not implemented on target platform"); + TRACELOG(LOG_WARNING, "SetGamepadMappings() unsupported on target platform"); return 0; } // Set gamepad vibration void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration) { - TRACELOG(LOG_WARNING, "SetGamepadVibration() not available on target platform"); + TRACELOG(LOG_WARNING, "SetGamepadVibration() unsupported on target platform"); } // Set mouse position XY @@ -812,7 +875,7 @@ void SetMouseCursor(int cursor) // Get physical key name. const char *GetKeyName(int key) { - TRACELOG(LOG_WARNING, "GetKeyName() not implemented on target platform"); + TRACELOG(LOG_WARNING, "GetKeyName() unsupported on target platform"); return ""; } @@ -925,7 +988,12 @@ void PollInputEvents(void) switch (event->type) { - case RGFW_quit: CORE.Window.shouldClose = true; break; + case RGFW_quit: + if (CORE.Window.flags & FLAG_WINDOW_ALWAYS_RUN) + event->type = 0; + else + CORE.Window.shouldClose = true; + break; case RGFW_DND: // Dropped file { for (int i = 0; i < event->droppedFilesCount; i++) @@ -1047,8 +1115,8 @@ void PollInputEvents(void) { if (platform.window->_flags & RGFW_HOLD_MOUSE) { - CORE.Input.Mouse.currentPosition.x += (float)event->point.x; - CORE.Input.Mouse.currentPosition.y += (float)event->point.y; + CORE.Input.Mouse.currentPosition.x += (float)event->vector.x; + CORE.Input.Mouse.currentPosition.y += (float)event->vector.y; } else { @@ -1161,21 +1229,43 @@ int InitPlatform(void) flags |= RGFW_windowFullscreen; } + if ((CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0) + { + CORE.Window.fullscreen = true; + flags |= RGFW_windowedFullscreen; + } + if ((CORE.Window.flags & FLAG_WINDOW_UNDECORATED) > 0) flags |= RGFW_windowNoBorder; if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) == 0) flags |= RGFW_windowNoResize; if ((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) > 0) flags |= RGFW_windowTransparent; if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) flags |= RGFW_windowFullscreen; + if ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) > 0) flags |= RGFW_windowHide; + if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0) flags |= RGFW_windowMaximize; + // NOTE: Some OpenGL context attributes must be set before window creation // Check selection OpenGL version - if (rlGetVersion() == RL_OPENGL_21) RGFW_setGLVersion(RGFW_glCore, 2, 1); - else if (rlGetVersion() == RL_OPENGL_33) RGFW_setGLVersion(RGFW_glCore, 3, 3); - else if (rlGetVersion() == RL_OPENGL_43) RGFW_setGLVersion(RGFW_glCore, 4, 1); + if (rlGetVersion() == RL_OPENGL_21) + { + RGFW_setGLHint(RGFW_glMajor, 2); + RGFW_setGLHint(RGFW_glMinor, 1); + } + else if (rlGetVersion() == RL_OPENGL_33) + { + RGFW_setGLHint(RGFW_glCore, 3); + RGFW_setGLHint(RGFW_glMinor, 3); + } + else if (rlGetVersion() == RL_OPENGL_43) + { + RGFW_setGLHint(RGFW_glCore, 3); + RGFW_setGLHint(RGFW_glMinor, 3); + } - if (CORE.Window.flags & FLAG_MSAA_4X_HINT) RGFW_setGLSamples(4); + if (CORE.Window.flags & FLAG_MSAA_4X_HINT) RGFW_setGLHint(RGFW_glSamples, 4); platform.window = RGFW_createWindow(CORE.Window.title, RGFW_RECT(0, 0, CORE.Window.screen.width, CORE.Window.screen.height), flags); + platform.mon.mode.area.w = 0; #ifndef PLATFORM_WEB_RGFW RGFW_area screenSize = RGFW_getScreenSize(); @@ -1229,14 +1319,6 @@ int InitPlatform(void) rlLoadExtensions((void *)RGFW_getProcAddress); //---------------------------------------------------------------------------- - // TODO: Initialize input events system - // It could imply keyboard, mouse, gamepad, touch... - // Depending on the platform libraries/SDK it could use a callback mechanism - // For system events and inputs evens polling on a per-frame basis, use PollInputEvents() - //---------------------------------------------------------------------------- - // ... - //---------------------------------------------------------------------------- - // Initialize timing system //---------------------------------------------------------------------------- InitTimer();