Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
# Features

* **is** an stb-style single headerfile and is very portable
* **is** primarly written in C99 in mind
* **has** a C89 compatible API
* **is** primarly written in C99 in mind, but supports C++, Objective-C/C++ and zig-cc compilation
* **has** a C89 compatible API on going changes to make the implementation more C89 friendly
* **is** a flexible and can be used in multiple ways to best fit your use case
* **is** very small compared to other libraries
* **is** a general framework and can be used for games, apps or tools
Expand All @@ -27,6 +27,7 @@
* **does** work with X11 (UNIX), Wayland (*experimental*) (LINUX), Cocoa (MacOS), Emscripten (WASM) and WinAPI (tested on windows *XP*, 10, 11, reactOS and has limited 9x support)
* **is** multi-paradigm, with a flexible event system, including multiple ways of handling events (callbacks, queue, state lookups)
* **does** include a large number of examples for learning RGFW
* **has** direct support for multiple compilers, gcc, clang, zig-cc, msvc (cl.exe) and emscripten c compiler (emcc).

* does **not** handle any rendering for you (other than creating your graphics context)
* is **not** an OpenGL focused library, RGFW can be used with ANY graphics API
Expand Down
176 changes: 110 additions & 66 deletions RGFW.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,11 @@
#define RGFW_COCOA_GRAPHICS_SWITCHING - (optional) (cocoa) use automatic graphics switching (allow the system to choose to use GPU or iGPU)
#define RGFW_COCOA_FRAME_NAME (optional) (cocoa) set frame name
#define RGFW_NO_DPI - do not calculate DPI and don't use libShcore (win32)
#define RGFW_NO_XRANDR - do use not XRandr (X11)
#define RGFW_ADVANCED_SMOOTH_RESIZE - use advanced methods for smooth resizing (may result in a spike in memory usage or worse performance) (eg. WM_TIMER and XSyncValue)
#define RGFW_NO_INFO - do not define the RGFW_info struct (without RGFW_IMPLEMENTATION)
#define RGFW_NO_GLXWINDOW - do not use GLXWindow
#define RGFW_NO_ALLOCATE_MONITORS - do not allocate monitors on the heap at all (when there's no pre-allocated space left)
#define RGFW_PREALLOCATED_MONITORS x - choose the default amount of pre-allocated monitors (can be zero)

#define RGFW_ALLOC x - choose the default allocation function (defaults to standard malloc)
#define RGFW_FREE x - choose the default deallocation function (defaults to standard free)
Expand Down Expand Up @@ -293,9 +294,10 @@ int main() {
#ifndef RGFW_MAX_EVENTS
#define RGFW_MAX_EVENTS 32
#endif

#ifndef RGFW_MAX_MONITORS
#define RGFW_MAX_MONITORS 6
#ifndef RGFW_PREALLOCATED_MONITORS
#define RGFW_PREALLOCATED_MONITORS 6 /* the number of preallocated monitors */
#elif defined(RGFW_NO_ALLOCATE_MONITORS) && (RGFW_PREALLOCATED_MONITORS == 0)
#warning RGFW monitors have no place to be allocated
#endif

#ifndef RGFW_COCOA_FRAME_NAME
Expand Down Expand Up @@ -1336,12 +1338,21 @@ RGFWDEF RGFW_bool RGFW_monitor_getMode(RGFW_monitor* monitor, RGFW_monitorMode*
RGFWDEF void RGFW_pollMonitors(void);

/**!
* @brief Retrieves an array of all available monitors.
* @param len [OUTPUT] A pointer to store the number of monitors found (maximum of RGFW_MAX_MONITORS [6 by default]).
* @return An array of pointers to RGFW_monitor structures.
* @brief Allocates and returns an array of all available monitors.
* @param len [OUTPUT] A pointer to store the number of monitors found.
* @return An allocated array of pointers to RGFW_monitor structures that must be freed.
*/
RGFWDEF RGFW_monitor** RGFW_getMonitors(size_t* len);

/**!
* @brief fills a pre-allocated array with available monitors.
* @param maximum number of monitors that the passed [monitors] buffer supports, can be zero to get the length alone
* @param pre-allocated buffer of monitors, can be NULL to get the length alone
* @param len [OUTPUT] A pointer to store the number of monitors found, if max is not zero and monitors is not NULL, length will be set to max.
* @return An array of pointers to RGFW_monitor structures or NULL if the function failed.
*/
RGFWDEF RGFW_bool RGFW_getMonitorsPtr(size_t max, RGFW_monitor** monitors, size_t* len);

/**!
* @brief Retrieves the primary monitor.
* @return A pointer to the RGFW_monitor structure representing the primary monitor.
Expand Down Expand Up @@ -2841,10 +2852,8 @@ RGFWDEF RGFW_info* RGFW_getInfo(void);
#include <X11/Xlib.h>
#include <X11/Xutil.h>

#ifndef RGFW_NO_XRANDR
#include <X11/extensions/Xrandr.h>
#include <X11/Xresource.h>
#endif
#include <X11/extensions/Xrandr.h>
#include <X11/Xresource.h>

#ifndef RGFW_XDND_VERSION
#define RGFW_XDND_VERSION 5
Expand Down Expand Up @@ -3046,7 +3055,7 @@ struct RGFW_monitorNode {
RGFW_monitorMode* modes;
size_t modeCount;
#endif
#if defined(RGFW_X11) && !defined(RGFW_NO_XRANDR)
#if defined(RGFW_X11)
i32 screen;
RROutput rrOutput;
RRCrtc crtc;
Expand All @@ -3070,11 +3079,13 @@ typedef struct RGFW_monitorList {

typedef struct RGFW_monitors {
RGFW_monitorList list;
RGFW_monitorList freeList;
size_t count;

RGFW_monitorNode* primary;
RGFW_monitorNode data[RGFW_MAX_MONITORS];
#if (RGFW_PREALLOCATED_MONITORS)
RGFW_monitorList freeList;
RGFW_monitorNode data[RGFW_PREALLOCATED_MONITORS];
#endif
} RGFW_monitors;

RGFWDEF RGFW_monitorNode* RGFW_monitors_add(const RGFW_monitor* mon);
Expand Down Expand Up @@ -3852,14 +3863,16 @@ i32 RGFW_init_ptr(RGFW_info* info) {
_RGFW->useWaylandBool = RGFW_TRUE;
#endif

_RGFW->monitors.freeList.head = &_RGFW->monitors.data[0];
_RGFW->monitors.freeList.cur = _RGFW->monitors.freeList.head;
#if (RGFW_PREALLOCATED_MONITORS)
_RGFW->monitors.freeList.head = &_RGFW->monitors.data[0];
_RGFW->monitors.freeList.cur = _RGFW->monitors.freeList.head;

for (size_t i = 1; i < RGFW_MAX_MONITORS; i++) {
RGFW_monitorNode* newNode = &_RGFW->monitors.data[i];
_RGFW->monitors.freeList.cur->next = newNode;
_RGFW->monitors.freeList.cur = _RGFW->monitors.freeList.cur->next;
}
for (size_t i = 1; i < RGFW_PREALLOCATED_MONITORS; i++) {
RGFW_monitorNode* newNode = &_RGFW->monitors.data[i];
_RGFW->monitors.freeList.cur->next = newNode;
_RGFW->monitors.freeList.cur = _RGFW->monitors.freeList.cur->next;
}
#endif

_RGFW->monitors.list.head = NULL;
_RGFW->monitors.list.head = NULL;
Expand Down Expand Up @@ -4478,14 +4491,22 @@ void RGFW_copyImageData64(u8* dest_data, i32 dest_w, i32 dest_h, RGFW_format des

RGFW_monitorNode* RGFW_monitors_add(const RGFW_monitor* mon) {
RGFW_monitorNode* node = NULL;
if (_RGFW->monitors.freeList.head == NULL) return node;

node = _RGFW->monitors.freeList.head;

_RGFW->monitors.freeList.head = node->next;
if (_RGFW->monitors.freeList.head == NULL) {
_RGFW->monitors.freeList.cur = NULL;
#if (RGFW_PREALLOCATED_MONITORS)
node = _RGFW->monitors.freeList.head;
if (node) {
_RGFW->monitors.freeList.head = node->next;
if (_RGFW->monitors.freeList.head == NULL) {
_RGFW->monitors.freeList.cur = NULL;
}
} else
#elif !defined(RGFW_NO_ALLOCATE_MONITORS)
{
node = (RGFW_monitorNode*)RGFW_ALLOC(sizeof(RGFW_monitorNode));
}
#endif

if (node == NULL) return NULL;

node->next = NULL;

Expand Down Expand Up @@ -4517,14 +4538,23 @@ void RGFW_monitors_remove(RGFW_monitorNode* node, RGFW_monitorNode* prev) {

node->next = NULL;

/* move node to the free list */
if (_RGFW->monitors.freeList.head == NULL) {
_RGFW->monitors.freeList.head = node;
} else {
_RGFW->monitors.freeList.cur->next = node;
}
#if (RGFW_PREALLOCATED_MONITORS)
/* check if the monitor was allocated in the heap or not */
if (node >= _RGFW->monitors.data && node <= &_RGFW->monitors.data[RGFW_PREALLOCATED_MONITORS - 1]) {
/* move node to the free list */
if (_RGFW->monitors.freeList.head == NULL) {
_RGFW->monitors.freeList.head = node;
} else {
_RGFW->monitors.freeList.cur->next = node;
}

_RGFW->monitors.freeList.cur = node;
_RGFW->monitors.freeList.cur = node;
} else
{
#elif !defined(RGFW_NO_ALLOCATE_MONITORS)
RGFW_FREE(node);
#endif
}
}

void RGFW_monitors_refresh(void) {
Expand Down Expand Up @@ -4669,20 +4699,45 @@ RGFW_bool RGFW_monitor_setGamma(RGFW_monitor* monitor, float gamma) {
}

RGFW_monitor** RGFW_getMonitors(size_t* len) {
static RGFW_monitor* monitors[RGFW_MAX_MONITORS];
if (len != NULL) *len = 0;

size_t count = 0;
if (RGFW_getMonitorsPtr(0, NULL, &count) == RGFW_FALSE || count == 0) return NULL;

RGFW_monitor** monitors = (RGFW_monitor**)RGFW_ALLOC(sizeof(RGFW_monitor*) * count);

if (RGFW_getMonitorsPtr(count, monitors, &count) == RGFW_FALSE) {
RGFW_FREE(monitors);
return NULL;
}

if (len != NULL) *len = count;

return monitors;
}

RGFW_bool RGFW_getMonitorsPtr(size_t max, RGFW_monitor** monitors, size_t* len) {
RGFW_init();
if (len != NULL) {
*len = _RGFW->monitors.count;
}

u8 i = 0;
if (monitors == NULL || max == 0) return RGFW_TRUE;


if (len != NULL) {
*len = max;
}

size_t i = 0;
RGFW_monitorNode* cur_node = _RGFW->monitors.list.head;
while (cur_node != NULL) {
while (cur_node != NULL && i < max) {
monitors[i] = &cur_node->mon;
i++;
cur_node = cur_node->next;
}
return monitors;

return RGFW_TRUE;
}

RGFW_monitor* RGFW_getPrimaryMonitor(void) {
Expand Down Expand Up @@ -6682,12 +6737,10 @@ void RGFW_XHandleEvent(void) {
deltaY = 0.0f;
}

#ifndef RGFW_NO_XRANDR
if (E.type == _RGFW->xrandrEventBase + RRNotify) {
RGFW_pollMonitors();
return;
}
#endif

switch (E.type) {
case SelectionRequest:
Expand Down Expand Up @@ -7763,20 +7816,18 @@ void RGFW_XGetSystemContentDPI(float* dpi) {
if (dpi == NULL) return;
float dpiOutput = 96.0f;

#ifndef RGFW_NO_XRANDR
char* rms = XResourceManagerString(_RGFW->display);
if (rms == NULL) return;
char* rms = XResourceManagerString(_RGFW->display);
if (rms == NULL) return;

XrmDatabase db = XrmGetStringDatabase(rms);
if (db == NULL) return;
XrmDatabase db = XrmGetStringDatabase(rms);
if (db == NULL) return;

XrmValue value;
char* type = NULL;
XrmValue value;
char* type = NULL;

if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value) && type && RGFW_STRNCMP(type, "String", 7) == 0)
dpiOutput = (float)RGFW_ATOF(value.addr);
XrmDestroyDatabase(db);
#endif
if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value) && type && RGFW_STRNCMP(type, "String", 7) == 0)
dpiOutput = (float)RGFW_ATOF(value.addr);
XrmDestroyDatabase(db);

if (dpi) *dpi = dpiOutput;
}
Expand Down Expand Up @@ -8021,7 +8072,6 @@ size_t RGFW_FUNC(RGFW_monitor_getModesPtr) (RGFW_monitor* monitor, RGFW_monitorM

size_t RGFW_FUNC(RGFW_monitor_getGammaRampPtr) (RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
RGFW_UNUSED(monitor); RGFW_UNUSED(ramp);
#ifndef RGFW_NO_XRANDR
size_t size = (size_t)XRRGetCrtcGammaSize(_RGFW->display, monitor->node->crtc);
XRRCrtcGamma* gamma = XRRGetCrtcGamma(_RGFW->display, monitor->node->crtc);

Expand All @@ -8033,15 +8083,11 @@ size_t RGFW_FUNC(RGFW_monitor_getGammaRampPtr) (RGFW_monitor* monitor, RGFW_gamm

XRRFreeGamma(gamma);
return size;
#endif

return 0;
}

RGFW_bool RGFW_FUNC(RGFW_monitor_setGammaRamp) (RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
RGFW_UNUSED(monitor); RGFW_UNUSED(ramp);

#ifndef RGFW_NO_XRANDR
size_t size = (size_t)XRRGetCrtcGammaSize(_RGFW->display, monitor->node->crtc);
if (size != ramp->count) {
RGFW_debugCallback(RGFW_typeError, RGFW_errX11, "X11: Gamma ramp size must match current ramp size");
Expand All @@ -8058,8 +8104,6 @@ RGFW_bool RGFW_FUNC(RGFW_monitor_setGammaRamp) (RGFW_monitor* monitor, RGFW_gamm
XRRFreeGamma(gamma);

return RGFW_TRUE;
#endif
return RGFW_FALSE;
}

RGFW_bool RGFW_FUNC(RGFW_monitor_setMode)(RGFW_monitor* mon, RGFW_monitorMode* mode) {
Expand All @@ -8078,7 +8122,6 @@ RGFW_bool RGFW_FUNC(RGFW_monitor_setMode)(RGFW_monitor* mon, RGFW_monitorMode* m
}

RGFW_bool RGFW_FUNC(RGFW_monitor_requestMode)(RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request) {
#ifndef RGFW_NO_XRANDR
RGFW_init();

RGFW_bool output = RGFW_FALSE;
Expand Down Expand Up @@ -8115,8 +8158,6 @@ RGFW_bool RGFW_FUNC(RGFW_monitor_requestMode)(RGFW_monitor* mon, RGFW_monitorMod
XRRFreeCrtcInfo(ci);
XRRFreeScreenResources(res);
return output;
#endif
return RGFW_FALSE;
}

RGFW_monitor* RGFW_FUNC(RGFW_window_getMonitor) (RGFW_window* win) {
Expand Down Expand Up @@ -8501,12 +8542,10 @@ i32 RGFW_initPlatform_X11(void) {

XISelectEvents(_RGFW->display, XDefaultRootWindow(_RGFW->display), &em, 1);

#ifndef RGFW_NO_XRANDR
i32 errorBase;
if (XRRQueryExtension(_RGFW->display, &_RGFW->xrandrEventBase, &errorBase)) {
XRRSelectInput(_RGFW->display, RootWindow(_RGFW->display, DefaultScreen(_RGFW->display)), RROutputChangeNotifyMask);
}
#endif

return 0;
}
Expand Down Expand Up @@ -14196,14 +14235,17 @@ float RGFW_osx_getRefreshRate(CGDirectDisplayID display, CGDisplayModeRef mode)
}

void RGFW_pollMonitors(void) {
static CGDirectDisplayID displays[RGFW_MAX_MONITORS];
u32 count;

if (CGGetActiveDisplayList(RGFW_MAX_MONITORS, displays, &count) != kCGErrorSuccess) {
if (CGGetActiveDisplayList(0, NULL, &count) != kCGErrorSuccess) {
return;
}

CGDirectDisplayID* displays = (CGDirectDisplayID*)RGFW_ALLOC(sizeof(CGDirectDisplayID) * count);
if (CGGetActiveDisplayList(count, displays, &count) != kCGErrorSuccess) {
return;
}

if (count > RGFW_MAX_MONITORS) count = RGFW_MAX_MONITORS;

for (RGFW_monitorNode* node = _RGFW->monitors.list.head; node; node = node->next) {
node->disconnected = RGFW_TRUE;
Expand Down Expand Up @@ -14275,6 +14317,8 @@ void RGFW_pollMonitors(void) {
RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_TRUE);
}

RGFW_FREE(displays);

RGFW_monitors_refresh();
}

Expand Down
Loading