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