packages feed

nano-ui-sdl-0.1.0.1: cbits/nano_ui_display.c

#include <SDL3/SDL.h>
#include <stddef.h>
#include <stdbool.h>

int nano_ui_window_refresh_rate(SDL_Window *window)
{
    if (!window) {
        return 0;
    }
    SDL_DisplayID id = SDL_GetDisplayForWindow(window);
    if (!id) {
        return 0;
    }
    const SDL_DisplayMode *current = SDL_GetCurrentDisplayMode(id);
    if (current && current->refresh_rate > 0) {
        return current->refresh_rate;
    }
    /* Some drivers leave the current mode's refresh at 0 (variable-refresh
     * panels, compositors that report a base rate). Fall back to the highest
     * refresh among display modes at the current size so pacing still
     * targets the panel's real cadence instead of the 60 Hz default. */
    int best = 0;
    int cw = current ? current->w : 0;
    int ch = current ? current->h : 0;
    if (cw <= 0 || ch <= 0) {
        SDL_GetWindowSize(window, &cw, &ch);
    }
    int count = 0;
    SDL_DisplayMode **modes = SDL_GetFullscreenDisplayModes(id, &count);
    for (int i = 0; i < count && modes; i++) {
        if (modes[i] && modes[i]->w == cw && modes[i]->h == ch && modes[i]->refresh_rate > best) {
            best = modes[i]->refresh_rate;
        }
    }
    if (modes) {
        SDL_free(modes);
    }
    return best;
}

typedef void (*nano_ui_resize_cb)(void);

static nano_ui_resize_cb g_resize_cb = NULL;

static bool nano_ui_resize_watch(void *userdata, SDL_Event *event)
{
    (void)userdata;
    if (!g_resize_cb || !event) {
        return true;
    }
    /* Not SDL_EVENT_WINDOW_RESIZED: SDL sends it just before the pixel size
     * change, which is what tells the renderer to resize its swap chain. A
     * frame drawn on RESIZED goes to the old-size backbuffer, shown cropped
     * or with a bare strip, and the size then counts as drawn, so the window
     * trails the drag by a step. */
    if (event->type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED
        || event->type == SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED) {
        g_resize_cb();
    }
    return true;
}

bool nano_ui_install_resize_watch(nano_ui_resize_cb cb)
{
    if (!SDL_AddEventWatch(nano_ui_resize_watch, NULL)) {
        g_resize_cb = NULL;
        return false;
    }
    g_resize_cb = cb;
    return true;
}

void nano_ui_remove_resize_watch(void)
{
    SDL_RemoveEventWatch(nano_ui_resize_watch, NULL);
    g_resize_cb = NULL;
}