MythTV  master
mythpowerosx.cpp
Go to the documentation of this file.
1 // MythTV
3 #include "mythlogging.h"
4 #include "mythpowerosx.h"
5 
6 // OSX
7 #include <IOKit/ps/IOPowerSources.h>
8 #include <IOKit/ps/IOPSKeys.h>
9 
10 #define LOC QString("PowerOSX: ")
11 
12 static OSStatus SendAppleEventToSystemProcess(AEEventID EventToSend);
13 
20 {
22 }
23 
25 {
27 
28  // deregister power status change notifications
29  CFRunLoopRemoveSource(CFRunLoopGetCurrent(),
30  IONotificationPortGetRunLoopSource(m_powerNotifyPort),
31  kCFRunLoopDefaultMode );
32  IODeregisterForSystemPower(&m_powerNotifier);
33  IOServiceClose(m_rootPowerDomain);
34  IONotificationPortDestroy(m_powerNotifyPort);
35 
36  // deregister power source change notifcations
37  if (m_powerRef)
38  {
39  CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m_powerRef, kCFRunLoopDefaultMode);
40  CFRelease(m_powerRef);
41  }
42 }
43 
45 {
47 
48  // Register for power status updates
49  m_rootPowerDomain = IORegisterForSystemPower(this, &m_powerNotifyPort, PowerCallBack, &m_powerNotifier);
51  {
52  CFRunLoopAddSource(CFRunLoopGetCurrent(),
53  IONotificationPortGetRunLoopSource(m_powerNotifyPort),
54  kCFRunLoopDefaultMode);
55  }
56  else
57  {
58  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to setup power status callback");
59  }
60 
61  // Is there a battery?
62  CFArrayRef batteryinfo = NULL;
63  if (IOPMCopyBatteryInfo(kIOMasterPortDefault, &batteryinfo) == kIOReturnSuccess)
64  {
65  CFRelease(batteryinfo);
66 
67  // register for notification of power source changes
68  m_powerRef = IOPSNotificationCreateRunLoopSource(PowerSourceCallBack, this);
69  if (m_powerRef)
70  {
71  CFRunLoopAddSource(CFRunLoopGetCurrent(), m_powerRef, kCFRunLoopDefaultMode);
72  Refresh();
73  }
74  }
75 
76  if (!m_powerRef)
77  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to setup power source callback");
78 
80  if (IOPMSleepEnabled())
82 
84 }
85 
86 bool MythPowerOSX::DoFeature(bool /*Delayed*/)
87 {
89  return false;
90 
92  AEEventID event = 0;
93  switch (m_scheduledFeature)
94  {
95  case FeatureSuspend: event = kAESleep; break;
96  case FeatureShutdown: event = kAEShutDown; break;
97  case FeatureRestart: event = kAERestart; break;
98  default: return false;
99  }
100  return SendAppleEventToSystemProcess(event) == noErr;
101 }
102 
104 {
105  if (!m_powerRef)
106  return;
107 
108  int newlevel = UnknownPower;
109  CFTypeRef info = IOPSCopyPowerSourcesInfo();
110  CFArrayRef list = IOPSCopyPowerSourcesList(info);
111 
112  for (int i = 0; i < CFArrayGetCount(list); i++)
113  {
114  CFTypeRef source = CFArrayGetValueAtIndex(list, i);
115  CFDictionaryRef description = IOPSGetPowerSourceDescription(info, source);
116 
117  if (static_cast<CFBooleanRef>(CFDictionaryGetValue(description, CFSTR(kIOPSIsPresentKey))) == kCFBooleanFalse)
118  continue;
119 
120  auto type = static_cast<CFStringRef>(CFDictionaryGetValue(description, CFSTR(kIOPSTransportTypeKey)));
121  if (type && CFStringCompare(type, CFSTR(kIOPSInternalType), 0) == kCFCompareEqualTo)
122  {
123  auto state = static_cast<CFStringRef>(CFDictionaryGetValue(description, CFSTR(kIOPSPowerSourceStateKey)));
124  if (state && CFStringCompare(state, CFSTR(kIOPSACPowerValue), 0) == kCFCompareEqualTo)
125  {
126  newlevel = ACPower;
127  }
128  else if (state && CFStringCompare(state, CFSTR(kIOPSBatteryPowerValue), 0) == kCFCompareEqualTo)
129  {
130  int32_t current;
131  int32_t max;
132  auto capacity = static_cast<CFNumberRef>(CFDictionaryGetValue(description, CFSTR(kIOPSCurrentCapacityKey)));
133  CFNumberGetValue(capacity, kCFNumberSInt32Type, &current);
134  capacity = static_cast<CFNumberRef>(CFDictionaryGetValue(description, CFSTR(kIOPSMaxCapacityKey)));
135  CFNumberGetValue(capacity, kCFNumberSInt32Type, &max);
136  newlevel = static_cast<int>(((static_cast<float>(current) /
137  (static_cast<float>(max))) * 100.0F));
138  }
139  else
140  {
141  newlevel = UnknownPower;
142  }
143  }
144  }
145 
146  CFRelease(list);
147  CFRelease(info);
148  PowerLevelChanged(newlevel);
149 }
150 
156 {
158  auto* power = static_cast<MythPowerOSX*>(Reference);
159  if (power)
160  power->Refresh();
161 }
162 
169 void MythPowerOSX::PowerCallBack(void *Reference, io_service_t /*unused*/,
170  natural_t Type, void *Data)
171 {
173  auto* power = static_cast<MythPowerOSX*>(Reference);
174  if (!power)
175  return;
176 
177  switch (Type)
178  {
179  case kIOMessageCanSystemPowerOff:
180  IOAllowPowerChange(power->m_rootPowerDomain, reinterpret_cast<intptr_t>(Data));
181  power->FeatureHappening(FeatureShutdown);
182  break;
183  case kIOMessageCanSystemSleep:
184  IOAllowPowerChange(power->m_rootPowerDomain, reinterpret_cast<intptr_t>(Data));
185  power->FeatureHappening(FeatureSuspend);
186  break;
187  case kIOMessageSystemWillPowerOff:
188  IOAllowPowerChange(power->m_rootPowerDomain, reinterpret_cast<intptr_t>(Data));
189  power->FeatureHappening(FeatureShutdown);
190  break;
191  case kIOMessageSystemWillRestart:
192  IOAllowPowerChange(power->m_rootPowerDomain, reinterpret_cast<intptr_t>(Data));
193  power->FeatureHappening(FeatureRestart);
194  break;
195  case kIOMessageSystemWillSleep:
196  IOAllowPowerChange(power->m_rootPowerDomain, reinterpret_cast<intptr_t>(Data));
197  power->FeatureHappening(FeatureSuspend);
198  break;
199  case kIOMessageSystemHasPoweredOn:
200  power->DidWakeUp();
201  break;
202  }
203 }
204 
205 // see Technical Q&A QA1134
206 OSStatus SendAppleEventToSystemProcess(AEEventID EventToSend)
207 {
208  AEAddressDesc targetDesc;
209  static const ProcessSerialNumber kPSNOfSystemProcess = { 0, kSystemProcess };
210  AppleEvent eventReply = { typeNull, nullptr };
211  AppleEvent appleEventToSend = { typeNull, nullptr };
212 
213  OSStatus error = noErr;
214  error = AECreateDesc(typeProcessSerialNumber, &kPSNOfSystemProcess,
215  sizeof(kPSNOfSystemProcess), &targetDesc);
216  if (error != noErr)
217  return error;
218 
219  error = AECreateAppleEvent(kCoreEventClass, EventToSend, &targetDesc,
220  kAutoGenerateReturnID, kAnyTransactionID, &appleEventToSend);
221  AEDisposeDesc(&targetDesc);
222  if (error != noErr)
223  return error;
224 
225  error = AESendMessage(&appleEventToSend, &eventReply, kAENormalPriority, kAEDefaultTimeout);
226  AEDisposeDesc(&appleEventToSend);
227  if (error != noErr)
228  return error;
229 
230  AEDisposeDesc(&eventReply);
231  return error;
232 }
MythPowerOSX
Definition: mythpowerosx.h:16
MythPower::ACPower
@ ACPower
Definition: mythpower.h:26
MythPowerOSX::MythPowerOSX
MythPowerOSX()
Power management for OSX.
Definition: mythpowerosx.cpp:19
MythPower::FeatureSuspend
@ FeatureSuspend
Definition: mythpower.h:38
error
static void error(const char *str,...)
Definition: vbi.cpp:42
MythPowerOSX::DoFeature
bool DoFeature(bool Delayed=false) override final
Definition: mythpowerosx.cpp:86
MythPowerOSX::PowerCallBack
static void PowerCallBack(void *Reference, io_service_t Service, natural_t Type, void *Data)
Receive notification of power status changes.
Definition: mythpowerosx.cpp:169
MythPower::m_scheduledFeature
Feature m_scheduledFeature
Definition: mythpower.h:91
MythPower::UnknownPower
@ UnknownPower
Definition: mythpower.h:30
MythPower::FeatureHappening
virtual void FeatureHappening(Feature Spontaneous=FeatureNone)
Signal to the rest of MythTV that the given feature will happen now.
Definition: mythpower.cpp:296
MythPowerOSX::Init
void Init(void) override
Definition: mythpowerosx.cpp:44
MythPower::FeatureShutdown
@ FeatureShutdown
Definition: mythpower.h:37
mythcocoautils.h
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
SendAppleEventToSystemProcess
static OSStatus SendAppleEventToSystemProcess(AEEventID EventToSend)
Definition: mythpowerosx.cpp:206
NULL
#define NULL
Definition: H2645Parser.h:67
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
MythPowerOSX::m_powerNotifier
io_object_t m_powerNotifier
Definition: mythpowerosx.h:38
mythlogging.h
MythPowerOSX::m_powerRef
CFRunLoopSourceRef m_powerRef
Definition: mythpowerosx.h:36
MythPower::PowerLevelChanged
void PowerLevelChanged(int Level)
Definition: mythpower.cpp:340
mythpowerosx.h
MythPowerOSX::Refresh
void Refresh(void) override final
Definition: mythpowerosx.cpp:103
MythPower::m_features
Features m_features
Definition: mythpower.h:90
MythPowerOSX::PowerSourceCallBack
static void PowerSourceCallBack(void *Reference)
Receive notification of changes to the power supply.
Definition: mythpowerosx.cpp:155
MythPowerOSX::m_rootPowerDomain
io_connect_t m_rootPowerDomain
Definition: mythpowerosx.h:37
MythPower::FeatureRestart
@ FeatureRestart
Definition: mythpower.h:40
MythPowerOSX::~MythPowerOSX
~MythPowerOSX() override final
Definition: mythpowerosx.cpp:24
CocoaAutoReleasePool
Definition: mythcocoautils.h:14
LOC
#define LOC
Definition: mythpowerosx.cpp:10
MythPowerOSX::m_powerNotifyPort
IONotificationPortRef m_powerNotifyPort
Definition: mythpowerosx.h:39
MythPower::Init
virtual void Init(void)
Definition: mythpower.cpp:126