src/power/macosx/SDL_syspower.c
author Alex Szpakowski
Sat, 16 May 2015 12:05:42 -0300
changeset 9600 d52c2129c9ac
parent 8149 681eb46b8ac4
child 9619 b94b6d0bff0f
permissions -rw-r--r--
Mac: Use CoreFoundation headers instead of Carbon headers, in GetPowerInfo code.
icculus@3170
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@8149
     3
  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
icculus@3170
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
icculus@3170
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
icculus@3170
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
icculus@3170
    20
*/
icculus@8093
    21
#include "../../SDL_internal.h"
icculus@3170
    22
icculus@3170
    23
#ifndef SDL_POWER_DISABLED
slouken@6044
    24
#if SDL_POWER_MACOSX
icculus@3170
    25
slime73@9600
    26
#include <CoreFoundation/CoreFoundation.h>
icculus@3170
    27
#include <IOKit/ps/IOPowerSources.h>
icculus@3170
    28
#include <IOKit/ps/IOPSKeys.h>
icculus@3170
    29
icculus@3170
    30
#include "SDL_power.h"
icculus@3170
    31
slime73@9600
    32
/* CoreFoundation is so verbose... */
icculus@3170
    33
#define STRMATCH(a,b) (CFStringCompare(a, b, 0) == kCFCompareEqualTo)
icculus@3170
    34
#define GETVAL(k,v) \
icculus@3170
    35
    CFDictionaryGetValueIfPresent(dict, CFSTR(k), (const void **) v)
icculus@3170
    36
icculus@3170
    37
/* Note that AC power sources also include a laptop battery it is charging. */
icculus@3170
    38
static void
slouken@3186
    39
checkps(CFDictionaryRef dict, SDL_bool * have_ac, SDL_bool * have_battery,
slouken@3186
    40
        SDL_bool * charging, int *seconds, int *percent)
icculus@3170
    41
{
slouken@3186
    42
    CFStringRef strval;         /* don't CFRelease() this. */
icculus@3170
    43
    CFBooleanRef bval;
icculus@3170
    44
    CFNumberRef numval;
icculus@3170
    45
    SDL_bool charge = SDL_FALSE;
icculus@3170
    46
    SDL_bool choose = SDL_FALSE;
icculus@3170
    47
    SDL_bool is_ac = SDL_FALSE;
icculus@3170
    48
    int secs = -1;
icculus@3170
    49
    int maxpct = -1;
icculus@3170
    50
    int pct = -1;
icculus@3170
    51
icculus@3170
    52
    if ((GETVAL(kIOPSIsPresentKey, &bval)) && (bval == kCFBooleanFalse)) {
slouken@3186
    53
        return;                 /* nothing to see here. */
icculus@3170
    54
    }
icculus@3170
    55
icculus@3170
    56
    if (!GETVAL(kIOPSPowerSourceStateKey, &strval)) {
icculus@3170
    57
        return;
icculus@3170
    58
    }
icculus@3170
    59
icculus@3170
    60
    if (STRMATCH(strval, CFSTR(kIOPSACPowerValue))) {
icculus@3170
    61
        is_ac = *have_ac = SDL_TRUE;
icculus@3170
    62
    } else if (!STRMATCH(strval, CFSTR(kIOPSBatteryPowerValue))) {
slouken@3186
    63
        return;                 /* not a battery? */
icculus@3170
    64
    }
icculus@3170
    65
icculus@3170
    66
    if ((GETVAL(kIOPSIsChargingKey, &bval)) && (bval == kCFBooleanTrue)) {
icculus@3170
    67
        charge = SDL_TRUE;
icculus@3170
    68
    }
icculus@3170
    69
icculus@3170
    70
    if (GETVAL(kIOPSMaxCapacityKey, &numval)) {
icculus@3170
    71
        SInt32 val = -1;
icculus@3170
    72
        CFNumberGetValue(numval, kCFNumberSInt32Type, &val);
icculus@3170
    73
        if (val > 0) {
icculus@3170
    74
            *have_battery = SDL_TRUE;
icculus@3170
    75
            maxpct = (int) val;
icculus@3170
    76
        }
icculus@3170
    77
    }
icculus@3170
    78
icculus@3170
    79
    if (GETVAL(kIOPSMaxCapacityKey, &numval)) {
icculus@3170
    80
        SInt32 val = -1;
icculus@3170
    81
        CFNumberGetValue(numval, kCFNumberSInt32Type, &val);
icculus@3170
    82
        if (val > 0) {
icculus@3170
    83
            *have_battery = SDL_TRUE;
icculus@3170
    84
            maxpct = (int) val;
icculus@3170
    85
        }
icculus@3170
    86
    }
icculus@3170
    87
icculus@3170
    88
    if (GETVAL(kIOPSTimeToEmptyKey, &numval)) {
icculus@3170
    89
        SInt32 val = -1;
icculus@3170
    90
        CFNumberGetValue(numval, kCFNumberSInt32Type, &val);
icculus@3170
    91
icculus@3170
    92
        /* Mac OS X reports 0 minutes until empty if you're plugged in. :( */
icculus@3170
    93
        if ((val == 0) && (is_ac)) {
slouken@3186
    94
            val = -1;           /* !!! FIXME: calc from timeToFull and capacity? */
icculus@3170
    95
        }
icculus@3170
    96
icculus@3170
    97
        secs = (int) val;
icculus@3170
    98
        if (secs > 0) {
slouken@3186
    99
            secs *= 60;         /* value is in minutes, so convert to seconds. */
icculus@3170
   100
        }
icculus@3170
   101
    }
icculus@3170
   102
icculus@3170
   103
    if (GETVAL(kIOPSCurrentCapacityKey, &numval)) {
icculus@3170
   104
        SInt32 val = -1;
icculus@3170
   105
        CFNumberGetValue(numval, kCFNumberSInt32Type, &val);
icculus@3170
   106
        pct = (int) val;
icculus@3170
   107
    }
icculus@3170
   108
icculus@3170
   109
    if ((pct > 0) && (maxpct > 0)) {
slouken@3186
   110
        pct = (int) ((((double) pct) / ((double) maxpct)) * 100.0);
icculus@3170
   111
    }
icculus@3170
   112
icculus@3170
   113
    if (pct > 100) {
icculus@3170
   114
        pct = 100;
icculus@3170
   115
    }
icculus@3170
   116
icculus@3170
   117
    /*
icculus@3170
   118
     * We pick the battery that claims to have the most minutes left.
icculus@3170
   119
     *  (failing a report of minutes, we'll take the highest percent.)
icculus@3170
   120
     */
icculus@3170
   121
    if ((secs < 0) && (*seconds < 0)) {
icculus@3170
   122
        if ((pct < 0) && (*percent < 0)) {
slouken@3186
   123
            choose = SDL_TRUE;  /* at least we know there's a battery. */
icculus@3170
   124
        }
icculus@3170
   125
        if (pct > *percent) {
icculus@3170
   126
            choose = SDL_TRUE;
icculus@3170
   127
        }
icculus@3170
   128
    } else if (secs > *seconds) {
icculus@3170
   129
        choose = SDL_TRUE;
icculus@3170
   130
    }
icculus@3170
   131
icculus@3170
   132
    if (choose) {
icculus@3170
   133
        *seconds = secs;
icculus@3170
   134
        *percent = pct;
icculus@3170
   135
        *charging = charge;
icculus@3170
   136
    }
icculus@3170
   137
}
icculus@3170
   138
icculus@3170
   139
#undef GETVAL
icculus@3170
   140
#undef STRMATCH
icculus@3170
   141
icculus@3170
   142
icculus@3170
   143
SDL_bool
slouken@3186
   144
SDL_GetPowerInfo_MacOSX(SDL_PowerState * state, int *seconds, int *percent)
icculus@3170
   145
{
icculus@3170
   146
    CFTypeRef blob = IOPSCopyPowerSourcesInfo();
icculus@3170
   147
icculus@3170
   148
    *seconds = -1;
icculus@3170
   149
    *percent = -1;
icculus@3170
   150
    *state = SDL_POWERSTATE_UNKNOWN;
icculus@3170
   151
icculus@3170
   152
    if (blob != NULL) {
icculus@3170
   153
        CFArrayRef list = IOPSCopyPowerSourcesList(blob);
icculus@3170
   154
        if (list != NULL) {
icculus@3170
   155
            /* don't CFRelease() the list items, or dictionaries! */
icculus@3170
   156
            SDL_bool have_ac = SDL_FALSE;
icculus@3170
   157
            SDL_bool have_battery = SDL_FALSE;
icculus@3170
   158
            SDL_bool charging = SDL_FALSE;
icculus@3170
   159
            const CFIndex total = CFArrayGetCount(list);
icculus@3170
   160
            CFIndex i;
icculus@3170
   161
            for (i = 0; i < total; i++) {
icculus@3170
   162
                CFTypeRef ps = (CFTypeRef) CFArrayGetValueAtIndex(list, i);
slouken@3186
   163
                CFDictionaryRef dict =
slouken@3186
   164
                    IOPSGetPowerSourceDescription(blob, ps);
icculus@3170
   165
                if (dict != NULL) {
icculus@3170
   166
                    checkps(dict, &have_ac, &have_battery, &charging,
icculus@3170
   167
                            seconds, percent);
icculus@3170
   168
                }
icculus@3170
   169
            }
icculus@3170
   170
icculus@3170
   171
            if (!have_battery) {
icculus@3170
   172
                *state = SDL_POWERSTATE_NO_BATTERY;
icculus@3170
   173
            } else if (charging) {
icculus@3170
   174
                *state = SDL_POWERSTATE_CHARGING;
icculus@3170
   175
            } else if (have_ac) {
icculus@3170
   176
                *state = SDL_POWERSTATE_CHARGED;
icculus@3170
   177
            } else {
icculus@3170
   178
                *state = SDL_POWERSTATE_ON_BATTERY;
icculus@3170
   179
            }
icculus@3170
   180
icculus@3170
   181
            CFRelease(list);
icculus@3170
   182
        }
icculus@3170
   183
        CFRelease(blob);
icculus@3170
   184
    }
icculus@3170
   185
slouken@3186
   186
    return SDL_TRUE;            /* always the definitive answer on Mac OS X. */
icculus@3170
   187
}
icculus@3170
   188
icculus@3170
   189
#endif /* SDL_POWER_MACOSX */
icculus@3170
   190
#endif /* SDL_POWER_DISABLED */
icculus@3170
   191
icculus@3170
   192
/* vi: set ts=4 sw=4 expandtab: */