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