SDL Examples

This example code reports power status (plugged in, battery level, etc).

Note that only Chrome-based browsers support this API currently. Firefox and Safari will report this as unknown, but this may change later!
/* power.c ... */

/*
 * This example code reports power status (plugged in, battery level, etc).
 *
 * This code is public domain. Feel free to use it for any purpose!
 */

#define SDL_MAIN_USE_CALLBACKS 1  /* use the callbacks instead of main() */
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>

/* We will use this renderer to draw into this window every frame. */
static SDL_Window *window = NULL;
static SDL_Renderer *renderer = NULL;

/* This function runs once at startup. */
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
    SDL_SetAppMetadata("Example Misc Power", "1.0", "com.example.misc-power");

    if (!SDL_Init(SDL_INIT_VIDEO)) {
        SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }

    if (!SDL_CreateWindowAndRenderer("examples/misc/power", 640, 480, 0, &window, &renderer)) {
        SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }

    return SDL_APP_CONTINUE;  /* carry on with the program! */
}

/* This function runs when a new event (mouse input, keypresses, etc) occurs. */
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
    if (event->type == SDL_EVENT_QUIT) {
        return SDL_APP_SUCCESS;  /* end the program, reporting success to the OS. */
    }
    return SDL_APP_CONTINUE;  /* carry on with the program! */
}

/* This function runs once per frame, and is the heart of the program. */
SDL_AppResult SDL_AppIterate(void *appstate)
{
    const SDL_FRect frame = { 100, 200, 440, 80 };  /* the percentage bar dimensions. */

    /* Query for battery info */
    int seconds = 0, percent = 0;
    const SDL_PowerState state = SDL_GetPowerInfo(&seconds, &percent);

    /* We set up different drawing details for each power state, then
       run it all through the same drawing code. */
    int clearr = 0, clearg = 0, clearb = 0;  /* clear window to this color. */
    int textr = 255, textg = 255, textb = 255;  /* draw messages in this color. */
    int framer = 255, frameg = 255, frameb = 255;  /* draw a percentage bar frame in this color. */
    int barr = 0, barg = 0, barb = 0;  /* draw a percentage bar in this color. */
    const char *msg = NULL;
    const char *msg2 = NULL;

    switch (state) {
        case SDL_POWERSTATE_ERROR:
            msg2 = "ERROR GETTING POWER STATE";
            msg = SDL_GetError();
            clearr = 255;  /* red background */
            break;

        default:  /* in case this does something unexpected later, treat it as unknown. */
        case SDL_POWERSTATE_UNKNOWN:
            msg = "Power state is unknown.";
            clearr = clearb = clearg = 50;  /* grey background */
            break;

        case SDL_POWERSTATE_ON_BATTERY:
            msg = "Running on battery.";
            barr = 255;  /* draw in red */
            break;

        case SDL_POWERSTATE_NO_BATTERY:
            msg = "Plugged in, no battery available.";
            clearg = 50;  /* green background */
            break;

        case SDL_POWERSTATE_CHARGING:
            msg = "Charging.";
            barb = barg = 255;  /* draw in cyan */
            break;

        case SDL_POWERSTATE_CHARGED:
            msg = "Charged.";
            barg = 255;  /* draw in green */
            break;
    }

    SDL_SetRenderDrawColor(renderer, clearr, clearg, clearb, 255);
    SDL_RenderClear(renderer);

    if (percent >= 0) {
        float x, y;
        SDL_FRect pctrect;
        char remainstr[64];
        char msgbuf[128];
        
        SDL_copyp(&pctrect, &frame);
        pctrect.w *= percent / 100.0f;

        if (seconds < 0) {
            SDL_strlcpy(remainstr, "unknown time", sizeof (remainstr));
        } else {
            int hours, minutes;
            hours = seconds / (60 * 60);
            seconds -= hours * (60 * 60);
            minutes = seconds / 60;
            seconds -= minutes * 60;
            SDL_snprintf(remainstr, sizeof (remainstr), "%02d:%02d:%02d", hours, minutes, seconds);
        }

        SDL_snprintf(msgbuf, sizeof (msgbuf), "Battery: %3d percent, %s remaining", percent, remainstr);
        x  = frame.x + ((frame.w - (SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * SDL_strlen(msgbuf))) / 2.0f);
        y = frame.y + frame.h + SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE;

        SDL_SetRenderDrawColor(renderer, barr, barg, barb, 255);  /* draw percent bar. */
        SDL_RenderFillRect(renderer, &pctrect);
        SDL_SetRenderDrawColor(renderer, framer, frameg, frameb, 255);  /* draw frame on top of bar. */
        SDL_RenderRect(renderer, &frame);
        SDL_SetRenderDrawColor(renderer, textr, textg, textb, 255);
        SDL_RenderDebugText(renderer, x, y, msgbuf);  /* draw text about battery level */
    }

    if (msg) {
        const float x = frame.x + ((frame.w - (SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * SDL_strlen(msg))) / 2.0f);
        const float y = frame.y - (SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * 2);
        SDL_SetRenderDrawColor(renderer, textr, textg, textb, 255);
        SDL_RenderDebugText(renderer, x, y, msg);
    }

    if (msg2) {
        const float x = frame.x + ((frame.w - (SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * SDL_strlen(msg2))) / 2.0f);
        const float y = frame.y - (SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * 4);
        SDL_SetRenderDrawColor(renderer, textr, textg, textb, 255);
        SDL_RenderDebugText(renderer, x, y, msg2);
    }

    /* put the new rendering on the screen. */
    SDL_RenderPresent(renderer);

    return SDL_APP_CONTINUE;  /* carry on with the program! */
}

/* This function runs once at shutdown. */
void SDL_AppQuit(void *appstate, SDL_AppResult result)
{
    /* SDL will clean up the window/renderer for us. */
}