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: */
|