changeset 3170:b7a48f533966

Initial work on power subsystem for SDL 1.3.
author Ryan C. Gordon <icculus@icculus.org>
date Sun, 07 Jun 2009 06:06:35 +0000
parents f294338ca6eb
children 5ecd475f38e7
files Makefile.dc Makefile.ds Makefile.in Makefile.minimal Makefile.pandora configure.in include/SDL.h include/SDL_config.h.in include/SDL_config_dreamcast.h include/SDL_config_iphoneos.h include/SDL_config_macosx.h include/SDL_config_nintendods.h include/SDL_config_os2.h include/SDL_config_win32.h include/SDL_power.h src/power/SDL_power.c src/power/linux/SDL_syspower.c src/power/macosx/SDL_syspower.c src/power/nds/SDL_syspower.c src/power/os2/SDL_syspower.c src/power/windows/SDL_syspower.c test/Makefile.in test/testpower.c
diffstat 23 files changed, 989 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile.dc	Sun Jun 07 02:45:55 2009 +0000
+++ b/Makefile.dc	Sun Jun 07 06:06:35 2009 +0000
@@ -31,6 +31,7 @@
 	src/events/SDL_quit.c \
 	src/events/SDL_resize.c \
 	src/file/SDL_rwops.c \
+	src/power/SDL_power.c \
 	src/joystick/dc/SDL_sysjoystick.c \
 	src/joystick/SDL_joystick.c \
 	src/loadso/dummy/SDL_sysloadso.c \
--- a/Makefile.ds	Sun Jun 07 02:45:55 2009 +0000
+++ b/Makefile.ds	Sun Jun 07 06:06:35 2009 +0000
@@ -55,6 +55,8 @@
 src/events/SDL_quit.c \
 src/events/SDL_windowevents.c \
 src/file/SDL_rwops.c \
+src/power/SDL_power.c \
+src/power/nds/SDL_syspower.c \
 src/haptic/SDL_haptic.c \
 src/haptic/nds/SDL_syshaptic.c \
 src/joystick/nds/SDL_sysjoystick.c \
--- a/Makefile.in	Sun Jun 07 02:45:55 2009 +0000
+++ b/Makefile.in	Sun Jun 07 06:06:35 2009 +0000
@@ -42,7 +42,7 @@
 
 DIST = acinclude.m4 autogen.sh Borland.html Borland.zip BUGS build-scripts configure configure.in COPYING CREDITS docs docs.html include INSTALL Makefile.dc Makefile.minimal Makefile.in README* sdl-config.in sdl.m4 sdl.pc.in SDL.qpg.in SDL.spec SDL.spec.in src test TODO VisualC.html VisualC VisualCE Watcom-OS2.zip Watcom-Win32.zip WhatsNew Xcode
 
-HDRS = SDL.h SDL_audio.h SDL_cdrom.h SDL_compat.h SDL_cpuinfo.h SDL_endian.h SDL_error.h SDL_events.h SDL_haptic.h SDL_joystick.h SDL_keyboard.h SDL_keysym.h SDL_loadso.h SDL_main.h SDL_mouse.h SDL_mutex.h SDL_name.h SDL_opengl.h SDL_opengles.h SDL_pixels.h SDL_platform.h SDL_quit.h SDL_rect.h SDL_revision.h SDL_rwops.h SDL_scancode.h SDL_stdinc.h SDL_surface.h SDL_syswm.h SDL_thread.h SDL_timer.h SDL_types.h SDL_version.h SDL_video.h begin_code.h close_code.h
+HDRS = SDL.h SDL_audio.h SDL_cdrom.h SDL_compat.h SDL_cpuinfo.h SDL_endian.h SDL_error.h SDL_events.h SDL_haptic.h SDL_joystick.h SDL_keyboard.h SDL_keysym.h SDL_loadso.h SDL_main.h SDL_mouse.h SDL_mutex.h SDL_name.h SDL_opengl.h SDL_opengles.h SDL_pixels.h SDL_platform.h SDL_power.h SDL_quit.h SDL_rect.h SDL_revision.h SDL_rwops.h SDL_scancode.h SDL_stdinc.h SDL_surface.h SDL_syswm.h SDL_thread.h SDL_timer.h SDL_types.h SDL_version.h SDL_video.h begin_code.h close_code.h
 
 LT_AGE      = @LT_AGE@
 LT_CURRENT  = @LT_CURRENT@
--- a/Makefile.minimal	Sun Jun 07 02:45:55 2009 +0000
+++ b/Makefile.minimal	Sun Jun 07 06:06:35 2009 +0000
@@ -20,6 +20,7 @@
 	src/thread/*.c \
 	src/timer/*.c \
 	src/video/*.c \
+	src/power/*.c \
 	src/audio/dummy/*.c \
 	src/video/dummy/*.c \
 	src/joystick/dummy/*.c \
--- a/Makefile.pandora	Sun Jun 07 02:45:55 2009 +0000
+++ b/Makefile.pandora	Sun Jun 07 06:06:35 2009 +0000
@@ -14,7 +14,7 @@
 
 SOURCES = ./src/*.c ./src/audio/*.c ./src/cdrom/*.c ./src/cpuinfo/*.c ./src/events/*.c \
 	./src/file/*.c ./src/stdlib/*.c ./src/thread/*.c ./src/timer/*.c ./src/video/*.c \
-	./src/joystick/*.c ./src/haptic/*.c ./src/video/dummy/*.c ./src/audio/disk/*.c \
+	./src/joystick/*.c ./src/haptic/*.c ./src/power/*.c ./src/video/dummy/*.c ./src/audio/disk/*.c \
 	./src/audio/dummy/*.c ./src/loadso/dlopen/*.c ./src/audio/dsp/*.c ./src/audio/dma/*.c \
 	./src/thread/pthread/SDL_systhread.c ./src/thread/pthread/SDL_syssem.c \
 	./src/thread/pthread/SDL_sysmutex.c ./src/thread/pthread/SDL_syscond.c \
--- a/configure.in	Sun Jun 07 02:45:55 2009 +0000
+++ b/configure.in	Sun Jun 07 06:06:35 2009 +0000
@@ -250,6 +250,14 @@
 else
     SOURCES="$SOURCES $srcdir/src/haptic/*.c"
 fi
+AC_ARG_ENABLE(power,
+AC_HELP_STRING([--enable-power], [Enable the power subsystem [[default=yes]]]),
+              , enable_power=yes)
+if test x$enable_power != xyes; then
+    AC_DEFINE(SDL_POWER_DISABLED)
+else
+    SOURCES="$SOURCES $srcdir/src/power/*.c"
+fi
 AC_ARG_ENABLE(cdrom,
 AC_HELP_STRING([--enable-cdrom], [Enable the cdrom subsystem [[default=yes]]]),
               , enable_cdrom=yes)
@@ -2446,6 +2454,16 @@
              esac
            fi
         fi
+        # Set up files for the power library
+        if test x$enable_power = xyes; then
+             case $ARCH in
+               linux)
+                   AC_DEFINE(SDL_POWER_LINUX)
+                   SOURCES="$SOURCES $srcdir/src/power/linux/*.c"
+                   have_power=yes
+               ;;
+             esac
+        fi
         # Set up files for the cdrom library
         if test x$enable_cdrom = xyes; then
           case $ARCH in
@@ -2620,6 +2638,12 @@
             SOURCES="$SOURCES $srcdir/src/loadso/win32/*.c"
             have_loadso=yes
         fi
+        # Set up files for the system power library
+        if test x$enable_power = xyes; then
+            AC_DEFINE(SDL_POWER_WINDOWS)
+            SOURCES="$SOURCES $srcdir/src/power/windows/*.c"
+            have_power=yes
+        fi
         # Set up the system libraries we need
         EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lcoredll -lcommctrl -lmmtimer"
         # The Win32 platform requires special setup
@@ -2691,6 +2715,11 @@
                 have_haptic=yes
             fi
         fi
+        if test x$enable_power = xyes; then
+            AC_DEFINE(SDL_POWER_WINDOWS)
+            SOURCES="$SOURCES $srcdir/src/power/windows/SDL_syspower.c"
+            have_power=yes
+        fi
         # Set up files for the cdrom library
         if test x$enable_cdrom = xyes; then
             AC_DEFINE(SDL_CDROM_WIN32)
@@ -2842,6 +2871,12 @@
             have_haptic=yes
             EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,ForceFeedback"
         fi
+        # Set up files for the power library
+        if test x$enable_power = xyes; then
+            AC_DEFINE(SDL_POWER_MACOSX)
+            SOURCES="$SOURCES $srcdir/src/power/macosx/*.c"
+            have_power=yes
+        fi
         # Set up files for the cdrom library
         if test x$enable_cdrom = xyes; then
             AC_DEFINE(SDL_CDROM_MACOSX)
--- a/include/SDL.h	Sun Jun 07 02:45:55 2009 +0000
+++ b/include/SDL.h	Sun Jun 07 06:06:35 2009 +0000
@@ -84,6 +84,7 @@
 #include "SDL_events.h"
 #include "SDL_loadso.h"
 #include "SDL_mutex.h"
+#include "SDL_power.h"
 #include "SDL_rwops.h"
 #include "SDL_thread.h"
 #include "SDL_timer.h"
--- a/include/SDL_config.h.in	Sun Jun 07 02:45:55 2009 +0000
+++ b/include/SDL_config.h.in	Sun Jun 07 06:06:35 2009 +0000
@@ -166,6 +166,7 @@
 #undef SDL_THREADS_DISABLED
 #undef SDL_TIMERS_DISABLED
 #undef SDL_VIDEO_DISABLED
+#undef SDL_POWER_DISABLED
 
 /* Enable various audio drivers */
 #undef SDL_AUDIO_DRIVER_ALSA
@@ -324,6 +325,14 @@
 #undef SDL_VIDEO_OPENGL_OSMESA
 #undef SDL_VIDEO_OPENGL_OSMESA_DYNAMIC
 
+/* Enable system power support */
+#undef SDL_POWER_LINUX
+#undef SDL_POWER_WINDOWS
+#undef SDL_POWER_MACOSX
+#undef SDL_POWER_OS2
+#undef SDL_POWER_NINTENDODS
+#undef SDL_POWER_HARDWIRED
+
 /* Enable assembly routines */
 #undef SDL_ASSEMBLY_ROUTINES
 #undef SDL_ALTIVEC_BLITTERS
--- a/include/SDL_config_dreamcast.h	Sun Jun 07 02:45:55 2009 +0000
+++ b/include/SDL_config_dreamcast.h	Sun Jun 07 06:06:35 2009 +0000
@@ -104,4 +104,6 @@
 #define SDL_VIDEO_DRIVER_DC	1
 #define SDL_VIDEO_DRIVER_DUMMY	1
 
+#define SDL_POWER_HARDWIRED 1
+
 #endif /* _SDL_config_dreamcast_h */
--- a/include/SDL_config_iphoneos.h	Sun Jun 07 02:45:55 2009 +0000
+++ b/include/SDL_config_iphoneos.h	Sun Jun 07 06:06:35 2009 +0000
@@ -131,6 +131,9 @@
 #define SDL_VIDEO_OPENGL_ES	1
 #define SDL_VIDEO_RENDER_OGL_ES	1
 
+/* Enable system power support */
+#define SDL_POWER_MACOSX 1
+
 /* enable iPhone keyboard support */
 #define SDL_IPHONE_KEYBOARD 1
 
--- a/include/SDL_config_macosx.h	Sun Jun 07 02:45:55 2009 +0000
+++ b/include/SDL_config_macosx.h	Sun Jun 07 06:06:35 2009 +0000
@@ -137,6 +137,9 @@
 #define SDL_VIDEO_OPENGL_CGL	1
 #define SDL_VIDEO_RENDER_OGL	1
 
+/* Enable system power support */
+#define SDL_POWER_MACOSX 1
+
 /* Enable assembly routines */
 #define SDL_ASSEMBLY_ROUTINES	1
 #ifdef __ppc__
--- a/include/SDL_config_nintendods.h	Sun Jun 07 02:45:55 2009 +0000
+++ b/include/SDL_config_nintendods.h	Sun Jun 07 06:06:35 2009 +0000
@@ -116,4 +116,7 @@
 #define SDL_VIDEO_DRIVER_NDS	1
 /*#define SDL_VIDEO_DRIVER_DUMMY	1 TODO: uncomment this later*/
 
+/* Enable system power support */
+#define SDL_POWER_NINTENDODS 1
+
 #endif /* _SDL_config_nintendods_h */
--- a/include/SDL_config_os2.h	Sun Jun 07 02:45:55 2009 +0000
+++ b/include/SDL_config_os2.h	Sun Jun 07 06:06:35 2009 +0000
@@ -136,6 +136,9 @@
 /* Enable OpenGL support */
 /* Nothing here yet for OS/2... :( */
 
+/* Enable system power support */
+#define SDL_POWER_OS2 1
+
 /* Enable assembly routines where available */
 #define SDL_ASSEMBLY_ROUTINES	1
 
--- a/include/SDL_config_win32.h	Sun Jun 07 02:45:55 2009 +0000
+++ b/include/SDL_config_win32.h	Sun Jun 07 06:06:35 2009 +0000
@@ -185,6 +185,9 @@
 #define SDL_VIDEO_RENDER_OGL	1
 #endif
 
+/* Enable system power support */
+#define SDL_POWER_WINDOWS 1
+
 /* Enable assembly routines (Win64 doesn't have inline asm) */
 #ifndef _WIN64
 #define SDL_ASSEMBLY_ROUTINES	1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/SDL_power.h	Sun Jun 07 06:06:35 2009 +0000
@@ -0,0 +1,84 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997-2009 Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+
+#ifndef _SDL_power_h
+#define _SDL_power_h
+
+/**
+ * \file SDL_power.h
+ *
+ * Header for the SDL power management routines
+ */
+
+#include "SDL_stdinc.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+/* *INDENT-OFF* */
+extern "C" {
+/* *INDENT-ON* */
+#endif
+
+/**
+ * \enum SDL_PowerState
+ *
+ * \brief The basic state for the system's power supply.
+ */
+typedef enum
+{
+    SDL_POWERSTATE_UNKNOWN,      /**< cannot determine power status */
+    SDL_POWERSTATE_ON_BATTERY,   /**< Not plugged in, running on the battery */
+    SDL_POWERSTATE_NO_BATTERY,   /**< Plugged in, no battery available */
+    SDL_POWERSTATE_CHARGING,     /**< Plugged in, charging battery */
+    SDL_POWERSTATE_CHARGED,      /**< Plugged in, battery charged */
+} SDL_PowerState;
+
+
+/**
+ * \fn int SDL_GetPowerInfo(void)
+ *
+ * \brief Get the current power supply details.
+ *
+ * \param secs Seconds of battery life left. You can pass a NULL here if
+ *                you don't care. Will return -1 if we can't determine a
+ *                value, or we're not running on a battery.
+ *
+ * \param pct Percentage of battery life left, between 0 and 100. You can
+ *                pass a NULL here if you don't care. Will return -1 if we
+ *                can't determine a value, or we're not running on a battery.
+ *
+ * \return The state of the battery (if any).
+ */
+extern DECLSPEC SDL_PowerState SDLCALL SDL_GetPowerInfo(int *secs, int *pct);
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+/* *INDENT-OFF* */
+}
+/* *INDENT-ON* */
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_power_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/power/SDL_power.c	Sun Jun 07 06:06:35 2009 +0000
@@ -0,0 +1,110 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997-2009 Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+#include "SDL_config.h"
+#include "SDL_power.h"
+
+/*
+ * Returns SDL_TRUE if we have a definitive answer.
+ * SDL_FALSE to try next implementation.
+ */
+typedef SDL_bool
+(*SDL_GetPowerInfo_Impl)(SDL_PowerState *state, int *seconds, int *percent);
+
+SDL_bool SDL_GetPowerInfo_Linux_sys_power(SDL_PowerState*, int*, int*);
+SDL_bool SDL_GetPowerInfo_Linux_proc_apci(SDL_PowerState*, int*, int*);
+SDL_bool SDL_GetPowerInfo_Linux_proc_apm(SDL_PowerState*, int*, int*);
+SDL_bool SDL_GetPowerInfo_Windows(SDL_PowerState*, int*, int*);
+SDL_bool SDL_GetPowerInfo_MacOSX(SDL_PowerState*, int*, int*);
+SDL_bool SDL_GetPowerInfo_OS2(SDL_PowerState*, int*, int*);
+SDL_bool SDL_GetPowerInfo_NintendoDS(SDL_PowerState*, int*, int*);
+
+#ifndef SDL_POWER_DISABLED
+#ifdef SDL_POWER_HARDWIRED
+/* This is for things that _never_ have a battery, like the Dreamcast, etc. */
+static SDL_bool
+SDL_GetPowerInfo_Hardwired(SDL_PowerState *state, int *seconds, int *percent)
+{
+    *seconds = -1;
+    *percent = -1;
+    *state = SDL_POWERSTATE_NO_BATTERY;
+    return SDL_TRUE;
+}
+#endif
+#endif
+
+
+static SDL_GetPowerInfo_Impl implementations[] = {
+#ifndef SDL_POWER_DISABLED
+#ifdef SDL_POWER_LINUX /* in order of preference. More than could work. */
+    SDL_GetPowerInfo_Linux_sys_power,
+    SDL_GetPowerInfo_Linux_proc_apci,
+    SDL_GetPowerInfo_Linux_proc_apm,
+#endif
+#ifdef SDL_POWER_WINDOWS /* handles Win32, Win64, PocketPC. */
+    SDL_GetPowerInfo_Windows,
+#endif
+#ifdef SDL_POWER_MACOSX  /* handles Mac OS X, Darwin, iPhone. */
+    SDL_GetPowerInfo_MacOSX,
+#endif
+#ifdef SDL_POWER_OS2  /* handles OS/2, Warp, eComStation. */
+    SDL_GetPowerInfo_OS2,
+#endif
+#ifdef SDL_POWER_NINTENDODS  /* handles Nintendo DS. */
+    SDL_GetPowerInfo_NintendoDS,
+#endif
+#ifdef SDL_POWER_HARDWIRED
+    SDL_GetPowerInfo_Hardwired,
+#endif
+#endif
+};
+
+SDL_PowerState
+SDL_GetPowerInfo(int *seconds, int *percent)
+{
+    const int total = sizeof (implementations) / sizeof (implementations[0]);
+    int _seconds, _percent;
+    SDL_PowerState retval;
+    int i;
+
+    /* Make these never NULL for platform-specific implementations. */
+    if (seconds == NULL) {
+        seconds = &_seconds;
+    }
+
+    if (percent == NULL) {
+        percent = &_percent;
+    }
+
+    for (i = 0; i < total; i++) {
+        if (implementations[i](&retval, seconds, percent)) {
+            return retval;
+        }
+    }
+
+    /* nothing was definitive. */
+    *seconds = -1;
+    *percent = -1;
+    return SDL_POWERSTATE_UNKNOWN;
+}
+
+/* vi: set ts=4 sw=4 expandtab: */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/power/linux/SDL_syspower.c	Sun Jun 07 06:06:35 2009 +0000
@@ -0,0 +1,207 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997-2009 Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef SDL_POWER_DISABLED
+#ifdef SDL_POWER_LINUX
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include "SDL_power.h"
+
+SDL_bool
+SDL_GetPowerInfo_Linux_sys_power(SDL_PowerState *state,
+                                 int *seconds, int *percent)
+{
+    return SDL_FALSE;  /* !!! FIXME: write me. */
+#if 0
+    const int fd = open("/sys/power", O_RDONLY);
+    if (fd == -1) {
+        return SDL_FALSE;  /* can't use this interface. */
+    }
+    return SDL_TRUE;
+#endif
+}
+
+SDL_bool
+SDL_GetPowerInfo_Linux_sys_proc_acpi(SDL_PowerState *state,
+                                     int *seconds, int *percent)
+{
+    return SDL_FALSE;  /* !!! FIXME: write me. */
+#if 0
+    const int fd = open("/proc/acpi", O_RDONLY);
+    if (fd == -1) {
+        return SDL_FALSE;  /* can't use this interface. */
+    }
+    return SDL_TRUE;
+#endif
+}
+
+static SDL_bool
+next_string(char **_ptr, char **_str)
+{
+    char *ptr = *_ptr;
+    char *str = *_str;
+
+    while (*ptr == ' ') {  /* skip any spaces... */
+        ptr++;
+    }
+
+    if (*ptr == '\0') {
+        return SDL_FALSE;
+    }
+
+    str = ptr;
+    while ((*ptr != ' ') && (*ptr != '\0'))
+        ptr++;
+
+    if (*ptr != '\0')
+        *(ptr++) = '\0';
+
+    *_str = str;
+    *_ptr = ptr;
+    return SDL_TRUE;
+}
+
+static SDL_bool
+int_string(char *str, int *val)
+{
+    char *endptr = NULL;
+    *val = (int) strtol(str+2, &endptr, 16);
+    return ((*str != '\0') && (*endptr == '\0'));
+}
+
+/* http://lxr.linux.no/linux+v2.6.29/drivers/char/apm-emulation.c */
+SDL_bool
+SDL_GetPowerInfo_Linux_sys_proc_apm(SDL_PowerState *state,
+                                    int *seconds, int *percent)
+{
+    SDL_bool need_details = SDL_FALSE;
+    int ac_status = 0;
+    int battery_status = 0;
+    int battery_flag = 0;
+    int battery_percent = 0;
+    int battery_time = 0;
+    const int fd = open("/proc/apm", O_RDONLY);
+    char buf[128];
+    char *ptr = &buf[0];
+    char *str = NULL;
+    ssize_t br;
+
+    if (fd == -1) {
+        return SDL_FALSE;  /* can't use this interface. */
+    }
+
+    br = read(fd, buf, sizeof (buf) - 1);
+    close(fd);
+
+    if (br < 0) {
+        return SDL_FALSE;
+    }
+
+    buf[br] = '\0';  // null-terminate the string.
+    if (!next_string(&ptr, &str)) {  /* driver version */
+        return SDL_FALSE;
+    }
+    if (!next_string(&ptr, &str)) {  /* BIOS version */
+        return SDL_FALSE;
+    }
+    if (!next_string(&ptr, &str)) {  /* APM flags */
+        return SDL_FALSE;
+    }
+
+    if (!next_string(&ptr, &str)) {  /* AC line status */
+        return SDL_FALSE;
+    } else if (!int_string(str, &ac_status)) {
+        return SDL_FALSE;
+    }
+
+    if (!next_string(&ptr, &str)) {  /* battery status */
+        return SDL_FALSE;
+    } else if (!int_string(str, &battery_status)) {
+        return SDL_FALSE;
+    }
+    if (!next_string(&ptr, &str)) {  /* battery flag */
+        return SDL_FALSE;
+    } else if (!int_string(str, &battery_flag)) {
+        return SDL_FALSE;
+    }
+    if (!next_string(&ptr, &str)) {  /* remaining battery life percent */
+        return SDL_FALSE;
+    }
+    if (str[strlen(str) - 1] == '%') {
+        str[strlen(str) - 1] = '\0';
+    }
+    if (!int_string(str, &battery_percent)) {
+        return SDL_FALSE;
+    }
+
+    if (!next_string(&ptr, &str)) {  /* remaining battery life time */
+        return SDL_FALSE;
+    } else if (!int_string(str, &battery_time)) {
+        return SDL_FALSE;
+    }
+
+    if (!next_string(&ptr, &str)) {  /* remaining battery life time units */
+        return SDL_FALSE;
+    } else if (strcmp(str, "min") == 0) {
+        battery_time *= 60;
+    }
+
+    if (battery_flag == 0xFF) {  /* unknown state */
+        *state = SDL_POWERSTATE_UNKNOWN;
+    } else if (battery_flag & (1 << 7)) {  /* no battery */
+        *state = SDL_POWERSTATE_NO_BATTERY;
+    } else if (battery_flag & (1 << 3)) {  /* charging */
+        *state = SDL_POWERSTATE_CHARGING;
+        need_details = SDL_TRUE;
+    } else if (ac_status == 1) {
+        *state = SDL_POWERSTATE_CHARGED;  /* on AC, not charging. */
+        need_details = SDL_TRUE;
+    } else {
+        *state = SDL_POWERSTATE_ON_BATTERY;
+        need_details = SDL_TRUE;
+    }
+
+    *percent = -1;
+    *seconds = -1;
+    if (need_details) {
+        const int pct = battery_percent;
+        const int secs = battery_time;
+
+        if (pct >= 0) {  /* -1 == unknown */
+            *percent = (pct > 100) ? 100 : pct;  /* clamp between 0%, 100% */
+        }
+        if (secs >= 0) {  /* -1 == unknown */
+            *seconds = secs;
+        }
+    }
+
+    return SDL_TRUE;
+}
+
+#endif /* SDL_POWER_LINUX */
+#endif /* SDL_POWER_DISABLED */
+
+/* vi: set ts=4 sw=4 expandtab: */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/power/macosx/SDL_syspower.c	Sun Jun 07 06:06:35 2009 +0000
@@ -0,0 +1,193 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997-2009 Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef SDL_POWER_DISABLED
+#ifdef SDL_POWER_MACOSX
+
+#include <Carbon/Carbon.h>
+#include <IOKit/ps/IOPowerSources.h>
+#include <IOKit/ps/IOPSKeys.h>
+
+#include "SDL_power.h"
+
+/* Carbon is so verbose... */
+#define STRMATCH(a,b) (CFStringCompare(a, b, 0) == kCFCompareEqualTo)
+#define GETVAL(k,v) \
+    CFDictionaryGetValueIfPresent(dict, CFSTR(k), (const void **) v)
+
+/* Note that AC power sources also include a laptop battery it is charging. */
+static void
+checkps(CFDictionaryRef dict, SDL_bool *have_ac, SDL_bool *have_battery,
+        SDL_bool *charging, int *seconds, int *percent)
+{
+    CFStringRef strval;  /* don't CFRelease() this. */
+    CFBooleanRef bval;
+    CFNumberRef numval;
+    SDL_bool charge = SDL_FALSE;
+    SDL_bool choose = SDL_FALSE;
+    SDL_bool is_ac = SDL_FALSE;
+    int secs = -1;
+    int maxpct = -1;
+    int pct = -1;
+
+    if ((GETVAL(kIOPSIsPresentKey, &bval)) && (bval == kCFBooleanFalse)) {
+        return;  /* nothing to see here. */
+    }
+
+    if (!GETVAL(kIOPSPowerSourceStateKey, &strval)) {
+        return;
+    }
+
+    if (STRMATCH(strval, CFSTR(kIOPSACPowerValue))) {
+        is_ac = *have_ac = SDL_TRUE;
+    } else if (!STRMATCH(strval, CFSTR(kIOPSBatteryPowerValue))) {
+        return;  /* not a battery? */
+    }
+
+    if ((GETVAL(kIOPSIsChargingKey, &bval)) && (bval == kCFBooleanTrue)) {
+        charge = SDL_TRUE;
+    }
+
+    if (GETVAL(kIOPSMaxCapacityKey, &numval)) {
+        SInt32 val = -1;
+        CFNumberGetValue(numval, kCFNumberSInt32Type, &val);
+        if (val > 0) {
+            *have_battery = SDL_TRUE;
+            maxpct = (int) val;
+        }
+    }
+
+    if (GETVAL(kIOPSMaxCapacityKey, &numval)) {
+        SInt32 val = -1;
+        CFNumberGetValue(numval, kCFNumberSInt32Type, &val);
+        if (val > 0) {
+            *have_battery = SDL_TRUE;
+            maxpct = (int) val;
+        }
+    }
+
+    if (GETVAL(kIOPSTimeToEmptyKey, &numval)) {
+        SInt32 val = -1;
+        CFNumberGetValue(numval, kCFNumberSInt32Type, &val);
+
+        /* Mac OS X reports 0 minutes until empty if you're plugged in. :( */
+        if ((val == 0) && (is_ac)) {
+            val = -1;  /* !!! FIXME: calc from timeToFull and capacity? */
+        }
+
+        secs = (int) val;
+        if (secs > 0) {
+            secs *= 60;  /* value is in minutes, so convert to seconds. */
+        }
+    }
+
+    if (GETVAL(kIOPSCurrentCapacityKey, &numval)) {
+        SInt32 val = -1;
+        CFNumberGetValue(numval, kCFNumberSInt32Type, &val);
+        pct = (int) val;
+    }
+
+    if ((pct > 0) && (maxpct > 0)) {
+    	pct = (int) ((((double)pct)/((double)maxpct)) * 100.0);
+    }
+
+    if (pct > 100) {
+        pct = 100;
+    }
+
+    /*
+     * We pick the battery that claims to have the most minutes left.
+     *  (failing a report of minutes, we'll take the highest percent.)
+     */
+    if ((secs < 0) && (*seconds < 0)) {
+        if ((pct < 0) && (*percent < 0)) {
+            choose = SDL_TRUE; /* at least we know there's a battery. */
+        }
+        if (pct > *percent) {
+            choose = SDL_TRUE;
+        }
+    } else if (secs > *seconds) {
+        choose = SDL_TRUE;
+    }
+
+    if (choose) {
+        *seconds = secs;
+        *percent = pct;
+        *charging = charge;
+    }
+}
+
+#undef GETVAL
+#undef STRMATCH
+
+
+SDL_bool
+SDL_GetPowerInfo_MacOSX(SDL_PowerState *state, int *seconds, int *percent)
+{
+    CFTypeRef blob = IOPSCopyPowerSourcesInfo();
+
+    *seconds = -1;
+    *percent = -1;
+    *state = SDL_POWERSTATE_UNKNOWN;
+
+    if (blob != NULL) {
+        CFArrayRef list = IOPSCopyPowerSourcesList(blob);
+        if (list != NULL) {
+            /* don't CFRelease() the list items, or dictionaries! */
+            SDL_bool have_ac = SDL_FALSE;
+            SDL_bool have_battery = SDL_FALSE;
+            SDL_bool charging = SDL_FALSE;
+            const CFIndex total = CFArrayGetCount(list);
+            CFIndex i;
+            for (i = 0; i < total; i++) {
+                CFTypeRef ps = (CFTypeRef) CFArrayGetValueAtIndex(list, i);
+                CFDictionaryRef dict = IOPSGetPowerSourceDescription(blob, ps);
+                if (dict != NULL) {
+                    checkps(dict, &have_ac, &have_battery, &charging,
+                            seconds, percent);
+                }
+            }
+
+            if (!have_battery) {
+                *state = SDL_POWERSTATE_NO_BATTERY;
+            } else if (charging) {
+                *state = SDL_POWERSTATE_CHARGING;
+            } else if (have_ac) {
+                *state = SDL_POWERSTATE_CHARGED;
+            } else {
+                *state = SDL_POWERSTATE_ON_BATTERY;
+            }
+
+            CFRelease(list);
+        }
+        CFRelease(blob);
+    }
+
+    return SDL_TRUE;  /* always the definitive answer on Mac OS X. */
+}
+
+#endif /* SDL_POWER_MACOSX */
+#endif /* SDL_POWER_DISABLED */
+
+/* vi: set ts=4 sw=4 expandtab: */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/power/nds/SDL_syspower.c	Sun Jun 07 06:06:35 2009 +0000
@@ -0,0 +1,45 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997-2009 Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef SDL_POWER_DISABLED
+#ifdef SDL_POWER_NINTENDODS
+
+#include "SDL_power.h"
+
+SDL_bool
+SDL_GetPowerInfo_NintendoDS(SDL_PowerState *state, int *seconds, int *percent)
+{
+    /* !!! FIXME: write me. */
+
+    *state = SDL_POWERSTATE_UNKNOWN;
+    *percent = -1;
+    *seconds = -1;
+
+    return SDL_TRUE;  /* always the definitive answer on Nintendo DS. */
+}
+
+#endif /* SDL_POWER_NINTENDODS */
+#endif /* SDL_POWER_DISABLED */
+
+/* vi: set ts=4 sw=4 expandtab: */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/power/os2/SDL_syspower.c	Sun Jun 07 06:06:35 2009 +0000
@@ -0,0 +1,135 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997-2009 Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/* !!! FIXME:
+ * Please note that this code has not been tested (or even compiled!). It
+ *  should, in theory, run on any version of OS/2, and work with any system
+ *  that has APM.SYS loaded. I don't know if ACPI.SYS works.
+ */
+
+#ifndef SDL_POWER_DISABLED
+#ifdef SDL_POWER_OS2
+
+#define INCL_DOSFILEMGR
+#define INCL_DOSDEVICES
+#define INCL_DOSDEVIOCTL
+#define INCL_DOSERRORS
+#include <os2.h>
+
+#include "SDL_power.h"
+
+typedef struct {
+    USHORT len;
+    USHORT flags;
+    UCHAR ac_status;
+    UCHAR battery_status;
+    UCHAR battery_life;
+    UCHAR battery_time_form;
+    USHORT battery_time;
+    UCHAR battery_flags;
+} PowerStatus;
+extern int CompilerAssertPowerStatus[(sizeof (PowerStatus) == 10) ? 1 : -1];
+
+
+SDL_bool
+SDL_GetPowerInfo_OS2(SDL_PowerState *state, int *seconds, int *percent)
+{
+    PowerStatus status;
+    HFILE hfile = 0;
+    ULONG action = 0;
+    APIRET rc = 0;
+
+    *state = SDL_POWERSTATE_UNKNOWN;
+    *percent = -1;
+    *seconds = -1;
+
+    /* open the power management device */
+    rc = DosOpen("APM$", &hfile, &action, 0, FILE_NORMAL, FILE_OPEN,
+                 OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE, 0);
+
+    if (rc == NO_ERROR) {
+        USHORT iorc = 0;
+        ULONG iorclen = sizeof (iorc);
+        ULONG statuslen = sizeof (status);
+
+        SDL_memset(&status, '\0', sizeof (status));
+        status.len = sizeof (status);
+
+        rc = DosDevIOCtl(hfile, IOCTL_POWER, POWER_GETPOWERSTATUS, &status,
+                         statuslen, &statuslen, &iorc, iorclen, &iorclen);
+        DosClose(hfile);
+
+        /* (status.flags & 0x1) == power subsystem enabled. */
+        if ((rc == NO_ERROR) && (status.flags & 0x1)) {
+            if (statuslen == 7) {  /* older OS/2 APM driver? Less fields. */
+                status.battery_time_form = 0xFF;
+                status.battery_time = 0;
+                if (status.battery_status == 0xFF) {
+                    status.battery_flags = 0xFF;
+                } else {
+                    status.battery_flags = (1 << status.battery_status);
+                }
+            }
+
+            if (status.battery_flags == 0xFF) {  /* unknown state */
+                *state = SDL_POWERSTATE_UNKNOWN;
+            } else if (status.battery_flags & (1 << 7)) {  /* no battery */
+                *state = SDL_POWERSTATE_NO_BATTERY;
+            } else if (status.battery_flags & (1 << 3)) {  /* charging */
+                *state = SDL_POWERSTATE_CHARGING;
+                need_details = SDL_TRUE;
+            } else if (status.ac_status == 1) {
+                *state = SDL_POWERSTATE_CHARGED;  /* on AC, not charging. */
+                need_details = SDL_TRUE;
+            } else {
+                *state = SDL_POWERSTATE_ON_BATTERY;  /* not on AC. */
+                need_details = SDL_TRUE;
+            }
+
+            if (need_details) {
+                const int pct = (int) status.battery_life;
+                const int secs = (int) status.battery_time;
+
+                if (pct != 0xFF) {  /* 255 == unknown */
+                    *percent = (pct > 100) ? 100 : pct;
+                }
+
+                if (status.battery_time_form == 0xFF) {  /* unknown */
+                    *seconds = -1;
+                } else if (status.battery_time_form == 1) {  /* minutes */
+                    *seconds = secs * 60;
+                } else {
+                    *seconds = secs;
+                }
+            }
+        }
+    }
+
+    return SDL_TRUE;  /* always the definitive answer on OS/2. */
+}
+
+#endif /* SDL_POWER_OS2 */
+#endif /* SDL_POWER_DISABLED */
+
+/* vi: set ts=4 sw=4 expandtab: */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/power/windows/SDL_syspower.c	Sun Jun 07 06:06:35 2009 +0000
@@ -0,0 +1,78 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997-2009 Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef SDL_POWER_DISABLED
+#ifdef SDL_POWER_WINDOWS
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#include "SDL_power.h"
+
+SDL_bool
+SDL_GetPowerInfo_Windows(SDL_PowerState *state, int *seconds, int *percent)
+{
+    SYSTEM_POWER_STATUS status;
+    SDL_bool need_details = SDL_FALSE;
+
+    /* This API should exist back to Win95 and Windows CE. */
+    if (!GetSystemPowerStatus(&status)) {
+        /* !!! FIXME: push GetLastError() into SDL_GetError() */
+        *state = SDL_POWERSTATE_UNKNOWN;
+    } else if (status.BatteryFlag == 0xFF) {  /* unknown state */
+        *state = SDL_POWERSTATE_UNKNOWN;
+    } else if (status.BatteryFlag & (1 << 7)) {  /* no battery */
+        *state = SDL_POWERSTATE_NO_BATTERY;
+    } else if (status.BatteryFlag & (1 << 3)) {  /* charging */
+        *state = SDL_POWERSTATE_CHARGING;
+        need_details = SDL_TRUE;
+    } else if (status.ACLineStatus == 1) {
+        *state = SDL_POWERSTATE_CHARGED;  /* on AC, not charging. */
+        need_details = SDL_TRUE;
+    } else {
+        *state = SDL_POWERSTATE_ON_BATTERY;  /* not on AC. */
+        need_details = SDL_TRUE;
+    }
+
+    *percent = -1;
+    *seconds = -1;
+    if (need_details) {
+        const int pct = (int) status.BatteryLifePercent;
+        const int secs = (int) status.BatteryLifeTime;
+
+        if (pct != 255) {  /* 255 == unknown */
+            *percent = (pct > 100) ? 100 : pct;  /* clamp between 0%, 100% */
+        }
+        if (secs != 0xFFFFFFFF) {  /* ((DWORD)-1) == unknown */
+            *seconds = secs;
+        }
+    }
+
+    return SDL_TRUE;  /* always the definitive answer on Windows. */
+}
+
+#endif /* SDL_POWER_WINDOWS */
+#endif /* SDL_POWER_DISABLED */
+
+/* vi: set ts=4 sw=4 expandtab: */
+
--- a/test/Makefile.in	Sun Jun 07 02:45:55 2009 +0000
+++ b/test/Makefile.in	Sun Jun 07 06:06:35 2009 +0000
@@ -7,7 +7,7 @@
 CFLAGS  = @CFLAGS@
 LIBS	= @LIBS@
 
-TARGETS = checkkeys$(EXE) graywin$(EXE) loopwave$(EXE) testresample$(EXE) testaudioinfo$(EXE) testmultiaudio$(EXE) testalpha$(EXE) testbitmap$(EXE) testblitspeed$(EXE) testcdrom$(EXE) testcursor$(EXE) testintersections$(EXE) testdraw2$(EXE) testdyngl$(EXE) testdyngles$(EXE) testerror$(EXE) testfile$(EXE) testgamma$(EXE) testgl$(EXE) testgl2$(EXE) testgles$(EXE) testhread$(EXE) testiconv$(EXE) testjoystick$(EXE) testkeys$(EXE) testlock$(EXE) testoverlay2$(EXE) testoverlay$(EXE) testpalette$(EXE) testplatform$(EXE) testsem$(EXE) testsprite$(EXE) testsprite2$(EXE) testtimer$(EXE) testver$(EXE) testvidinfo$(EXE) testwin$(EXE) testwm$(EXE) testwm2$(EXE) threadwin$(EXE) torturethread$(EXE) testloadso$(EXE) testhaptic$(EXE) testmmousetablet$(EXE)
+TARGETS = checkkeys$(EXE) graywin$(EXE) loopwave$(EXE) testresample$(EXE) testaudioinfo$(EXE) testmultiaudio$(EXE) testpower$(EXE) testalpha$(EXE) testbitmap$(EXE) testblitspeed$(EXE) testcdrom$(EXE) testcursor$(EXE) testintersections$(EXE) testdraw2$(EXE) testdyngl$(EXE) testdyngles$(EXE) testerror$(EXE) testfile$(EXE) testgamma$(EXE) testgl$(EXE) testgl2$(EXE) testgles$(EXE) testhread$(EXE) testiconv$(EXE) testjoystick$(EXE) testkeys$(EXE) testlock$(EXE) testoverlay2$(EXE) testoverlay$(EXE) testpalette$(EXE) testplatform$(EXE) testsem$(EXE) testsprite$(EXE) testsprite2$(EXE) testtimer$(EXE) testver$(EXE) testvidinfo$(EXE) testwin$(EXE) testwm$(EXE) testwm2$(EXE) threadwin$(EXE) torturethread$(EXE) testloadso$(EXE) testhaptic$(EXE) testmmousetablet$(EXE)
 
 all: Makefile $(TARGETS)
 
@@ -32,6 +32,9 @@
 testmultiaudio$(EXE): $(srcdir)/testmultiaudio.c
 	$(CC) -o $@ $? $(CFLAGS) $(LIBS)
 
+testpower$(EXE): $(srcdir)/testpower.c
+	$(CC) -o $@ $? $(CFLAGS) $(LIBS)
+
 testalpha$(EXE): $(srcdir)/testalpha.c
 	$(CC) -o $@ $? $(CFLAGS) $(LIBS) @MATHLIB@
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testpower.c	Sun Jun 07 06:06:35 2009 +0000
@@ -0,0 +1,65 @@
+/* Simple test of power subsystem. */
+
+#include <stdio.h>
+#include "SDL.h"
+
+static void report_power(void)
+{
+    int seconds, percent;
+    const SDL_PowerState state = SDL_GetPowerInfo(&seconds, &percent);
+    char *statestr = NULL;
+
+    printf("SDL-reported power info...\n");
+    switch(state)
+    {
+        case SDL_POWERSTATE_UNKNOWN:
+            statestr = "Unknown";
+            break;
+        case SDL_POWERSTATE_ON_BATTERY:
+            statestr = "On battery";
+            break;
+        case SDL_POWERSTATE_NO_BATTERY:
+            statestr = "No battery";
+            break;
+        case SDL_POWERSTATE_CHARGING:
+            statestr = "Charging";
+            break;
+        case SDL_POWERSTATE_CHARGED:
+            statestr = "Charged";
+            break;
+        default:
+            statestr = "!!API ERROR!!";
+            break;
+    }
+
+    printf("State: %s\n", statestr);
+
+    if (percent == -1) {
+        printf("Percent left: unknown\n");
+    } else {
+        printf("Percent left: %d%%\n", percent);
+    }
+
+    if (seconds == -1) {
+        printf("Time left: unknown\n");
+    } else {
+        printf("Time left: %d minutes, %d seconds\n", (int) (seconds / 60), (int) (seconds % 60));
+    }
+}
+
+
+int main(int argc, char *argv[])
+{
+    if (SDL_Init(SDL_INIT_VIDEO) == -1) {
+        fprintf(stderr, "SDL_Init() failed: %s\n", SDL_GetError());
+        return 1;
+    }
+
+    report_power();
+
+    SDL_Quit();
+    return 0;
+}
+
+/* end of testpower.c ... */
+