| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | /*************************************************************************/ | 
					
						
							| 
									
										
										
										
											2017-09-01 21:07:55 +07:00
										 |  |  | /*  power_osx.cpp                                                        */ | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | /*                       This file is part of:                           */ | 
					
						
							|  |  |  | /*                           GODOT ENGINE                                */ | 
					
						
							| 
									
										
										
										
											2017-08-27 14:16:55 +02:00
										 |  |  | /*                      https://godotengine.org                          */ | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | /*************************************************************************/ | 
					
						
							| 
									
										
										
										
											2018-01-01 14:40:08 +01:00
										 |  |  | /* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur.                 */ | 
					
						
							|  |  |  | /* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md)    */ | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* Permission is hereby granted, free of charge, to any person obtaining */ | 
					
						
							|  |  |  | /* a copy of this software and associated documentation files (the       */ | 
					
						
							|  |  |  | /* "Software"), to deal in the Software without restriction, including   */ | 
					
						
							|  |  |  | /* without limitation the rights to use, copy, modify, merge, publish,   */ | 
					
						
							|  |  |  | /* distribute, sublicense, and/or sell copies of the Software, and to    */ | 
					
						
							|  |  |  | /* permit persons to whom the Software is furnished to do so, subject to */ | 
					
						
							|  |  |  | /* the following conditions:                                             */ | 
					
						
							|  |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* The above copyright notice and this permission notice shall be        */ | 
					
						
							|  |  |  | /* included in all copies or substantial portions of the Software.       */ | 
					
						
							|  |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ | 
					
						
							|  |  |  | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ | 
					
						
							|  |  |  | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ | 
					
						
							|  |  |  | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ | 
					
						
							|  |  |  | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ | 
					
						
							|  |  |  | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ | 
					
						
							|  |  |  | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							| 
									
										
										
										
											2017-05-06 23:38:44 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | Adapted from corresponding SDL 2.0 code. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |   Simple DirectMedia Layer | 
					
						
							|  |  |  |   Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   This software is provided 'as-is', without any express or implied | 
					
						
							|  |  |  |   warranty.  In no event will the authors be held liable for any damages | 
					
						
							|  |  |  |   arising from the use of this software. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Permission is granted to anyone to use this software for any purpose, | 
					
						
							|  |  |  |   including commercial applications, and to alter it and redistribute it | 
					
						
							|  |  |  |   freely, subject to the following restrictions: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   1. The origin of this software must not be misrepresented; you must not | 
					
						
							|  |  |  |      claim that you wrote the original software. If you use this software | 
					
						
							|  |  |  |      in a product, an acknowledgment in the product documentation would be | 
					
						
							|  |  |  |      appreciated but is not required. | 
					
						
							|  |  |  |   2. Altered source versions must be plainly marked as such, and must not be | 
					
						
							|  |  |  |      misrepresented as being the original software. | 
					
						
							|  |  |  |   3. This notice may not be removed or altered from any source distribution. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | #include "power_osx.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <CoreFoundation/CoreFoundation.h>
 | 
					
						
							|  |  |  | #include <IOKit/ps/IOPSKeys.h>
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | #include <IOKit/ps/IOPowerSources.h>
 | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | //  CODE CHUNK IMPORTED FROM SDL 2.0
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* CoreFoundation is so verbose... */ | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | #define STRMATCH(a, b) (CFStringCompare(a, b, 0) == kCFCompareEqualTo)
 | 
					
						
							|  |  |  | #define GETVAL(k, v) \
 | 
					
						
							|  |  |  | 	CFDictionaryGetValueIfPresent(dict, CFSTR(k), (const void **)v) | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* Note that AC power sources also include a laptop battery it is charging. */ | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | void power_osx::checkps(CFDictionaryRef dict, bool *have_ac, bool *have_battery, bool *charging) { | 
					
						
							|  |  |  | 	CFStringRef strval; /* don't CFRelease() this. */ | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | 	CFBooleanRef bval; | 
					
						
							|  |  |  | 	CFNumberRef numval; | 
					
						
							|  |  |  | 	bool charge = false; | 
					
						
							|  |  |  | 	bool choose = false; | 
					
						
							|  |  |  | 	bool is_ac = false; | 
					
						
							|  |  |  | 	int secs = -1; | 
					
						
							|  |  |  | 	int maxpct = -1; | 
					
						
							|  |  |  | 	int pct = -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((GETVAL(kIOPSIsPresentKey, &bval)) && (bval == kCFBooleanFalse)) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		return; /* nothing to see here. */ | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!GETVAL(kIOPSPowerSourceStateKey, &strval)) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (STRMATCH(strval, CFSTR(kIOPSACPowerValue))) { | 
					
						
							|  |  |  | 		is_ac = *have_ac = true; | 
					
						
							|  |  |  | 	} else if (!STRMATCH(strval, CFSTR(kIOPSBatteryPowerValue))) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		return; /* not a battery? */ | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((GETVAL(kIOPSIsChargingKey, &bval)) && (bval == kCFBooleanTrue)) { | 
					
						
							|  |  |  | 		charge = true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (GETVAL(kIOPSMaxCapacityKey, &numval)) { | 
					
						
							|  |  |  | 		SInt32 val = -1; | 
					
						
							|  |  |  | 		CFNumberGetValue(numval, kCFNumberSInt32Type, &val); | 
					
						
							|  |  |  | 		if (val > 0) { | 
					
						
							|  |  |  | 			*have_battery = true; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			maxpct = (int)val; | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (GETVAL(kIOPSMaxCapacityKey, &numval)) { | 
					
						
							|  |  |  | 		SInt32 val = -1; | 
					
						
							|  |  |  | 		CFNumberGetValue(numval, kCFNumberSInt32Type, &val); | 
					
						
							|  |  |  | 		if (val > 0) { | 
					
						
							|  |  |  | 			*have_battery = true; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			maxpct = (int)val; | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (GETVAL(kIOPSTimeToEmptyKey, &numval)) { | 
					
						
							|  |  |  | 		SInt32 val = -1; | 
					
						
							|  |  |  | 		CFNumberGetValue(numval, kCFNumberSInt32Type, &val); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Mac OS X reports 0 minutes until empty if you're plugged in. :( */ | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		if ((val == 0) && (is_ac)) { | 
					
						
							|  |  |  | 			val = -1; /* !!! FIXME: calc from timeToFull and capacity? */ | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		secs = (int)val; | 
					
						
							|  |  |  | 		if (secs > 0) { | 
					
						
							|  |  |  | 			secs *= 60; /* value is in minutes, so convert to seconds. */ | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (GETVAL(kIOPSCurrentCapacityKey, &numval)) { | 
					
						
							|  |  |  | 		SInt32 val = -1; | 
					
						
							|  |  |  | 		CFNumberGetValue(numval, kCFNumberSInt32Type, &val); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		pct = (int)val; | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((pct > 0) && (maxpct > 0)) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		pct = (int)((((double)pct) / ((double)maxpct)) * 100.0); | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	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) && (nsecs_left < 0)) { | 
					
						
							|  |  |  | 		if ((pct < 0) && (percent_left < 0)) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			choose = true; /* at least we know there's a battery. */ | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if (pct > percent_left) { | 
					
						
							|  |  |  | 			choose = true; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else if (secs > nsecs_left) { | 
					
						
							|  |  |  | 		choose = true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (choose) { | 
					
						
							|  |  |  | 		nsecs_left = secs; | 
					
						
							|  |  |  | 		percent_left = pct; | 
					
						
							|  |  |  | 		*charging = charge; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #undef GETVAL
 | 
					
						
							|  |  |  | #undef STRMATCH
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //  CODE CHUNK IMPORTED FROM SDL 2.0
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | bool power_osx::GetPowerInfo_MacOSX() { | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | 	CFTypeRef blob = IOPSCopyPowerSourcesInfo(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	nsecs_left = -1; | 
					
						
							|  |  |  | 	percent_left = -1; | 
					
						
							| 
									
										
										
										
											2017-09-12 22:09:06 +03:00
										 |  |  | 	power_state = OS::POWERSTATE_UNKNOWN; | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (blob != NULL) { | 
					
						
							|  |  |  | 		CFArrayRef list = IOPSCopyPowerSourcesList(blob); | 
					
						
							|  |  |  | 		if (list != NULL) { | 
					
						
							|  |  |  | 			/* don't CFRelease() the list items, or dictionaries! */ | 
					
						
							|  |  |  | 			bool have_ac = false; | 
					
						
							|  |  |  | 			bool have_battery = false; | 
					
						
							|  |  |  | 			bool charging = false; | 
					
						
							|  |  |  | 			const CFIndex total = CFArrayGetCount(list); | 
					
						
							|  |  |  | 			CFIndex i; | 
					
						
							|  |  |  | 			for (i = 0; i < total; i++) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				CFTypeRef ps = (CFTypeRef)CFArrayGetValueAtIndex(list, i); | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | 				CFDictionaryRef dict = IOPSGetPowerSourceDescription(blob, ps); | 
					
						
							|  |  |  | 				if (dict != NULL) { | 
					
						
							|  |  |  | 					checkps(dict, &have_ac, &have_battery, &charging); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (!have_battery) { | 
					
						
							| 
									
										
										
										
											2017-09-12 22:09:06 +03:00
										 |  |  | 				power_state = OS::POWERSTATE_NO_BATTERY; | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | 			} else if (charging) { | 
					
						
							| 
									
										
										
										
											2017-09-12 22:09:06 +03:00
										 |  |  | 				power_state = OS::POWERSTATE_CHARGING; | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | 			} else if (have_ac) { | 
					
						
							| 
									
										
										
										
											2017-09-12 22:09:06 +03:00
										 |  |  | 				power_state = OS::POWERSTATE_CHARGED; | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2017-09-12 22:09:06 +03:00
										 |  |  | 				power_state = OS::POWERSTATE_ON_BATTERY; | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			CFRelease(list); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		CFRelease(blob); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	return true; /* always the definitive answer on Mac OS X. */ | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool power_osx::UpdatePowerInfo() { | 
					
						
							|  |  |  | 	if (GetPowerInfo_MacOSX()) { | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-12 22:09:06 +03:00
										 |  |  | OS::PowerState power_osx::get_power_state() { | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | 	if (UpdatePowerInfo()) { | 
					
						
							|  |  |  | 		return power_state; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2017-09-12 22:09:06 +03:00
										 |  |  | 		return OS::POWERSTATE_UNKNOWN; | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int power_osx::get_power_seconds_left() { | 
					
						
							|  |  |  | 	if (UpdatePowerInfo()) { | 
					
						
							|  |  |  | 		return nsecs_left; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int power_osx::get_power_percent_left() { | 
					
						
							|  |  |  | 	if (UpdatePowerInfo()) { | 
					
						
							|  |  |  | 		return percent_left; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-06 21:36:34 +01:00
										 |  |  | power_osx::power_osx() : | 
					
						
							|  |  |  | 		nsecs_left(-1), | 
					
						
							|  |  |  | 		percent_left(-1), | 
					
						
							|  |  |  | 		power_state(OS::POWERSTATE_UNKNOWN) { | 
					
						
							| 
									
										
										
										
											2016-07-23 13:15:55 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | power_osx::~power_osx() { | 
					
						
							| 
									
										
										
										
											2017-03-05 15:47:28 +01:00
										 |  |  | } |