Index: /trunk/src/VBox/Main/darwin/HostPowerDarwin.cpp
===================================================================
--- /trunk/src/VBox/Main/darwin/HostPowerDarwin.cpp	(revision 15904)
+++ /trunk/src/VBox/Main/darwin/HostPowerDarwin.cpp	(revision 15905)
@@ -24,11 +24,17 @@
 
 #include <IOKit/IOMessage.h>
+#include <IOKit/ps/IOPowerSources.h>
+#include <IOKit/ps/IOPSKeys.h>
+
+#define POWER_SOURCE_OUTLET 1
+#define POWER_SOURCE_BATTERY 2
 
 HostPowerServiceDarwin::HostPowerServiceDarwin (VirtualBox *aVirtualBox)
-  : HostPowerService (aVirtualBox),
-    mThread (NULL),
-    mRootPort (MACH_PORT_NULL),
-    mNotifyPort (nil),
-    mRunLoop (nil)
+  : HostPowerService (aVirtualBox)
+  , mThread (NULL)
+  , mRootPort (MACH_PORT_NULL)
+  , mNotifyPort (nil)
+  , mRunLoop (nil)
+  , mCritical (false)
 {
     /* Create the new worker thread. */
@@ -57,11 +63,13 @@
 }
 
+
 DECLCALLBACK(int) HostPowerServiceDarwin::powerChangeNotificationThread (RTTHREAD ThreadSelf, void *pInstance)
 {
     HostPowerServiceDarwin *pPowerObj = static_cast<HostPowerServiceDarwin *> (pInstance);
 
-//    OSErr retCode = AEInstallEventHandler(kAEMacPowerMgtEvt, kAEMacLowPowerSaveData,
-//                                          HostPowerServiceDarwin::lowPowerEventHandler,
-//                                          pPowerObj, false);
+    /* We have to initial set the critical state of the battery, cause we want
+     * not the HostPowerService to inform about that state when a VM starts.
+     * See lowPowerHandler for more info. */
+    pPowerObj->checkBatteryCriticalLevel();
 
     /* Register to receive system sleep notifications */
@@ -79,14 +87,22 @@
                         IONotificationPortGetRunLoopSource (pPowerObj->mNotifyPort),
                         kCFRunLoopCommonModes);
+
+    /* Register for all battery change events. The handler will check for low
+     * power events themself. */
+    CFRunLoopSourceRef runLoopSource = IOPSNotificationCreateRunLoopSource(HostPowerServiceDarwin::lowPowerHandler,
+                                                                           pPowerObj);
+    CFRunLoopAddSource(pPowerObj->mRunLoop,
+                       runLoopSource,
+                       kCFRunLoopCommonModes);
+
     /* Start the run loop. This blocks. */
     CFRunLoopRun();
-
     return VINF_SUCCESS;
 }
 
-void HostPowerServiceDarwin::powerChangeNotificationHandler (void *pData, io_service_t service, natural_t messageType, void *pMessageArgument)
-{
-    HostPowerServiceDarwin *pPowerObj = static_cast<HostPowerServiceDarwin *> (pData);
-//    printf( "messageType %08lx, arg %08lx\n", (long unsigned int)messageType, (long unsigned int)pMessageArgument );
+void HostPowerServiceDarwin::powerChangeNotificationHandler (void *pvData, io_service_t service, natural_t messageType, void *pMessageArgument)
+{
+    HostPowerServiceDarwin *pPowerObj = static_cast<HostPowerServiceDarwin *> (pvData);
+    Log (( "powerChangeNotificationHandler: messageType %08lx, arg %08lx\n", (long unsigned int)messageType, (long unsigned int)pMessageArgument));
 
     switch (messageType)
@@ -132,11 +148,98 @@
 }
 
-OSErr HostPowerServiceDarwin::lowPowerEventHandler (const AppleEvent *event, AppleEvent *replyEvent, long data)
-{
-    printf ("low power event\n");
-    LogRel (("low power event\n"));
-//    HostPowerServiceDarwin *pPowerObj = reinterpret_cast<HostPowerServiceDarwin *> (data);
-//    pPowerObj->notify(HostPowerEvent_BatteryLow);
-    return noErr;
-}
-
+void HostPowerServiceDarwin::lowPowerHandler (void *pvData)
+{
+    HostPowerServiceDarwin *pPowerObj = static_cast<HostPowerServiceDarwin *> (pvData);
+
+    /* Following role for sending the BatteryLow event (5% is critical):
+     * - Not at VM start even if the battery is in an critical state already.
+     * - When the power cord is removed so the power supply change from AC to
+     *   battery & the battery is in an critical state nothing is triggered.
+     *   This has to be discussed.
+     * - When the power supply is the battery & the state of the battery level
+     *   changed from normal to critical. The state transition from critical to
+     *   normal triggers nothing. */
+    bool fCriticalStateChanged = false;
+    pPowerObj->checkBatteryCriticalLevel (&fCriticalStateChanged);
+    if (fCriticalStateChanged)
+        pPowerObj->notify (HostPowerEvent_BatteryLow);
+}
+
+void HostPowerServiceDarwin::checkBatteryCriticalLevel (bool *pfCriticalChanged)
+{
+    CFTypeRef pBlob = IOPSCopyPowerSourcesInfo();
+    CFArrayRef pSources = IOPSCopyPowerSourcesList (pBlob);
+
+    CFDictionaryRef pSource = NULL;
+    const void *psValue;
+    bool result;
+    int powerSource = POWER_SOURCE_OUTLET;
+    bool critical = false;
+
+    if (CFArrayGetCount (pSources) > 0)
+    {
+        for(int i = 0; i < CFArrayGetCount (pSources); ++i)
+        {
+            pSource = IOPSGetPowerSourceDescription (pBlob, CFArrayGetValueAtIndex (pSources, i));
+            /* If the source is empty skip over to the next one. */
+            if(!pSource)
+                continue;
+            /* Skip all power sources which are currently not present like a
+             * second battery. */
+            if (CFDictionaryGetValue (pSource, CFSTR (kIOPSIsPresentKey)) == kCFBooleanFalse)
+                continue;
+            /* Only internal power types are of interest. */
+            result = CFDictionaryGetValueIfPresent (pSource, CFSTR (kIOPSTransportTypeKey), &psValue);
+            if (result &&
+                CFStringCompare ((CFStringRef)psValue, CFSTR (kIOPSInternalType), 0) == kCFCompareEqualTo)
+            {
+                /* First check which power source we are connect on. */
+                result = CFDictionaryGetValueIfPresent (pSource, CFSTR (kIOPSPowerSourceStateKey), &psValue);
+                if (result &&
+                    CFStringCompare ((CFStringRef)psValue, CFSTR (kIOPSACPowerValue), 0) == kCFCompareEqualTo)
+                    powerSource = POWER_SOURCE_OUTLET;
+                else if (result &&
+                         CFStringCompare ((CFStringRef)psValue, CFSTR (kIOPSBatteryPowerValue), 0) == kCFCompareEqualTo)
+                    powerSource = POWER_SOURCE_BATTERY;
+
+                int curCapacity = 0;
+                int maxCapacity = 1;
+                float remCapacity = 0.0f;
+
+                /* Fetch the current capacity value of the power source */
+                result = CFDictionaryGetValueIfPresent (pSource, CFSTR (kIOPSCurrentCapacityKey), &psValue);
+                if (result)
+                    CFNumberGetValue ((CFNumberRef)psValue, kCFNumberSInt32Type, &curCapacity);
+                /* Fetch the maximum capacity value of the power source */
+                result = CFDictionaryGetValueIfPresent (pSource, CFSTR (kIOPSMaxCapacityKey), &psValue);
+                if (result)
+                    CFNumberGetValue ((CFNumberRef)psValue, kCFNumberSInt32Type, &maxCapacity);
+
+                /* Calculate the remaining capacity in percent */
+                remCapacity = ((float)curCapacity/(float)maxCapacity * 100.0);
+
+                /* Check for critical. 5 percent is default. */
+                int criticalValue = 5;
+                result = CFDictionaryGetValueIfPresent (pSource, CFSTR (kIOPSDeadWarnLevelKey), &psValue);
+                if (result)
+                    CFNumberGetValue ((CFNumberRef)psValue, kCFNumberSInt32Type, &criticalValue);
+                critical = (remCapacity < criticalValue);
+                /* We have to take action only if we are on battery, the
+                 * previous state wasn't critical, the state has changed & the
+                 * user requested that info. */
+                if (powerSource == POWER_SOURCE_BATTERY &&
+                    mCritical == false &&
+                    mCritical != critical &&
+                    pfCriticalChanged)
+                    *pfCriticalChanged = true;
+                Log (("checkBatteryCriticalLevel: Remains: %.0f%% Critical: %d Critical State Changed: %d\n", remCapacity, critical, pfCriticalChanged?*pfCriticalChanged:-1));
+            }
+        }
+    }
+    /* Save the new state */
+    mCritical = critical;
+
+    CFRelease (pBlob);
+    CFRelease (pSources);
+}
+
Index: /trunk/src/VBox/Main/include/HostPower.h
===================================================================
--- /trunk/src/VBox/Main/include/HostPower.h	(revision 15904)
+++ /trunk/src/VBox/Main/include/HostPower.h	(revision 15905)
@@ -91,6 +91,8 @@
 
     static DECLCALLBACK(int) powerChangeNotificationThread (RTTHREAD ThreadSelf, void *pInstance);
-    static void powerChangeNotificationHandler (void *pData, io_service_t service, natural_t messageType, void *pMessageArgument);
-    static OSErr lowPowerEventHandler (const AppleEvent * theAppleEvent, AppleEvent * replyAppleEvent, long refCon);
+    static void powerChangeNotificationHandler (void *pvData, io_service_t service, natural_t messageType, void *pMessageArgument);
+    static void lowPowerHandler (void *pvData);
+
+    void checkBatteryCriticalLevel (bool *pfCriticalChanged = NULL);
 
     /* Private member vars */
@@ -101,4 +103,6 @@
     io_object_t mNotifierObject; /* Notifier object, used to deregister later */
     CFRunLoopRef mRunLoop; /* A reference to the local thread run loop */
+
+    bool mCritical; /* Indicate if the battery was in the critical state last checked */
 };
 # endif /* RT_OS_DARWIN */
