power_osx.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /**************************************************************************/
  2. /* power_osx.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. /*
  31. Adapted from corresponding SDL 2.0 code.
  32. */
  33. /*
  34. * Simple DirectMedia Layer
  35. * Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
  36. *
  37. * This software is provided 'as-is', without any express or implied
  38. * warranty. In no event will the authors be held liable for any damages
  39. * arising from the use of this software.
  40. *
  41. * Permission is granted to anyone to use this software for any purpose,
  42. * including commercial applications, and to alter it and redistribute it
  43. * freely, subject to the following restrictions:
  44. *
  45. * 1. The origin of this software must not be misrepresented; you must not
  46. * claim that you wrote the original software. If you use this software
  47. * in a product, an acknowledgment in the product documentation would be
  48. * appreciated but is not required.
  49. * 2. Altered source versions must be plainly marked as such, and must not be
  50. * misrepresented as being the original software.
  51. * 3. This notice may not be removed or altered from any source distribution.
  52. */
  53. #include "power_osx.h"
  54. #include <CoreFoundation/CoreFoundation.h>
  55. #include <IOKit/ps/IOPSKeys.h>
  56. #include <IOKit/ps/IOPowerSources.h>
  57. // CODE CHUNK IMPORTED FROM SDL 2.0
  58. /* CoreFoundation is so verbose... */
  59. #define STRMATCH(a, b) (CFStringCompare(a, b, 0) == kCFCompareEqualTo)
  60. #define GETVAL(k, v) \
  61. CFDictionaryGetValueIfPresent(dict, CFSTR(k), (const void **)v)
  62. /* Note that AC power sources also include a laptop battery it is charging. */
  63. void PowerOSX::checkps(CFDictionaryRef dict, bool *have_ac, bool *have_battery, bool *charging) {
  64. CFStringRef strval; /* don't CFRelease() this. */
  65. CFBooleanRef bval;
  66. CFNumberRef numval;
  67. bool charge = false;
  68. bool choose = false;
  69. bool is_ac = false;
  70. int secs = -1;
  71. int maxpct = -1;
  72. int pct = -1;
  73. if ((GETVAL(kIOPSIsPresentKey, &bval)) && (bval == kCFBooleanFalse)) {
  74. return; /* nothing to see here. */
  75. }
  76. if (!GETVAL(kIOPSPowerSourceStateKey, &strval)) {
  77. return;
  78. }
  79. if (STRMATCH(strval, CFSTR(kIOPSACPowerValue))) {
  80. is_ac = *have_ac = true;
  81. } else if (!STRMATCH(strval, CFSTR(kIOPSBatteryPowerValue))) {
  82. return; /* not a battery? */
  83. }
  84. if ((GETVAL(kIOPSIsChargingKey, &bval)) && (bval == kCFBooleanTrue)) {
  85. charge = true;
  86. }
  87. if (GETVAL(kIOPSMaxCapacityKey, &numval)) {
  88. SInt32 val = -1;
  89. CFNumberGetValue(numval, kCFNumberSInt32Type, &val);
  90. if (val > 0) {
  91. *have_battery = true;
  92. maxpct = (int)val;
  93. }
  94. }
  95. if (GETVAL(kIOPSMaxCapacityKey, &numval)) {
  96. SInt32 val = -1;
  97. CFNumberGetValue(numval, kCFNumberSInt32Type, &val);
  98. if (val > 0) {
  99. *have_battery = true;
  100. maxpct = (int)val;
  101. }
  102. }
  103. if (GETVAL(kIOPSTimeToEmptyKey, &numval)) {
  104. SInt32 val = -1;
  105. CFNumberGetValue(numval, kCFNumberSInt32Type, &val);
  106. /* Mac OS X reports 0 minutes until empty if you're plugged in. :( */
  107. if ((val == 0) && (is_ac)) {
  108. val = -1; /* !!! FIXME: calc from timeToFull and capacity? */
  109. }
  110. secs = (int)val;
  111. if (secs > 0) {
  112. secs *= 60; /* value is in minutes, so convert to seconds. */
  113. }
  114. }
  115. if (GETVAL(kIOPSCurrentCapacityKey, &numval)) {
  116. SInt32 val = -1;
  117. CFNumberGetValue(numval, kCFNumberSInt32Type, &val);
  118. pct = (int)val;
  119. }
  120. if ((pct > 0) && (maxpct > 0)) {
  121. pct = (int)((((double)pct) / ((double)maxpct)) * 100.0);
  122. }
  123. if (pct > 100) {
  124. pct = 100;
  125. }
  126. /*
  127. * We pick the battery that claims to have the most minutes left.
  128. * (failing a report of minutes, we'll take the highest percent.)
  129. */
  130. if ((secs < 0) && (nsecs_left < 0)) {
  131. if ((pct < 0) && (percent_left < 0)) {
  132. choose = true; /* at least we know there's a battery. */
  133. }
  134. if (pct > percent_left) {
  135. choose = true;
  136. }
  137. } else if (secs > nsecs_left) {
  138. choose = true;
  139. }
  140. if (choose) {
  141. nsecs_left = secs;
  142. percent_left = pct;
  143. *charging = charge;
  144. }
  145. }
  146. #undef GETVAL
  147. #undef STRMATCH
  148. // CODE CHUNK IMPORTED FROM SDL 2.0
  149. bool PowerOSX::GetPowerInfo_MacOSX() {
  150. CFTypeRef blob = IOPSCopyPowerSourcesInfo();
  151. nsecs_left = -1;
  152. percent_left = -1;
  153. power_state = OS::POWERSTATE_UNKNOWN;
  154. if (blob != NULL) {
  155. CFArrayRef list = IOPSCopyPowerSourcesList(blob);
  156. if (list != NULL) {
  157. /* don't CFRelease() the list items, or dictionaries! */
  158. bool have_ac = false;
  159. bool have_battery = false;
  160. bool charging = false;
  161. const CFIndex total = CFArrayGetCount(list);
  162. CFIndex i;
  163. for (i = 0; i < total; i++) {
  164. CFTypeRef ps = (CFTypeRef)CFArrayGetValueAtIndex(list, i);
  165. CFDictionaryRef dict = IOPSGetPowerSourceDescription(blob, ps);
  166. if (dict != NULL) {
  167. checkps(dict, &have_ac, &have_battery, &charging);
  168. }
  169. }
  170. if (!have_battery) {
  171. power_state = OS::POWERSTATE_NO_BATTERY;
  172. } else if (charging) {
  173. power_state = OS::POWERSTATE_CHARGING;
  174. } else if (have_ac) {
  175. power_state = OS::POWERSTATE_CHARGED;
  176. } else {
  177. power_state = OS::POWERSTATE_ON_BATTERY;
  178. }
  179. CFRelease(list);
  180. }
  181. CFRelease(blob);
  182. }
  183. return true; /* always the definitive answer on Mac OS X. */
  184. }
  185. bool PowerOSX::UpdatePowerInfo() {
  186. if (GetPowerInfo_MacOSX()) {
  187. return true;
  188. }
  189. return false;
  190. }
  191. OS::PowerState PowerOSX::get_power_state() {
  192. if (UpdatePowerInfo()) {
  193. return power_state;
  194. } else {
  195. return OS::POWERSTATE_UNKNOWN;
  196. }
  197. }
  198. int PowerOSX::get_power_seconds_left() {
  199. if (UpdatePowerInfo()) {
  200. return nsecs_left;
  201. } else {
  202. return -1;
  203. }
  204. }
  205. int PowerOSX::get_power_percent_left() {
  206. if (UpdatePowerInfo()) {
  207. return percent_left;
  208. } else {
  209. return -1;
  210. }
  211. }
  212. PowerOSX::PowerOSX() :
  213. nsecs_left(-1),
  214. percent_left(-1),
  215. power_state(OS::POWERSTATE_UNKNOWN) {
  216. }
  217. PowerOSX::~PowerOSX() {
  218. }