CF_EXPORT SInt32 CFUserNotificationDisplayAlert(CFTimeInterval timeout, CFOptionFlags flags, CFURLRef iconURL, CFURLRef soundURL, CFURLRef localizationURL, CFStringRef alertHeader, CFStringRef alertMessage, CFStringRef defaultButtonTitle, CFStringRef alternateButtonTitle, CFStringRef otherButtonTitle, CFOptionFlags *responseFlags) { CHECK_FOR_FORK(); CFUserNotificationRef userNotification; SInt32 retval = ERR_SUCCESS; CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (iconURL) CFDictionaryAddValue(dict, kCFUserNotificationIconURLKey, iconURL); if (soundURL) CFDictionaryAddValue(dict, kCFUserNotificationSoundURLKey, soundURL); if (localizationURL) CFDictionaryAddValue(dict, kCFUserNotificationLocalizationURLKey, localizationURL); if (alertHeader) CFDictionaryAddValue(dict, kCFUserNotificationAlertHeaderKey, alertHeader); if (alertMessage) CFDictionaryAddValue(dict, kCFUserNotificationAlertMessageKey, alertMessage); if (defaultButtonTitle) CFDictionaryAddValue(dict, kCFUserNotificationDefaultButtonTitleKey, defaultButtonTitle); if (alternateButtonTitle) CFDictionaryAddValue(dict, kCFUserNotificationAlternateButtonTitleKey, alternateButtonTitle); if (otherButtonTitle) CFDictionaryAddValue(dict, kCFUserNotificationOtherButtonTitleKey, otherButtonTitle); userNotification = CFUserNotificationCreate(kCFAllocatorSystemDefault, timeout, flags, &retval, dict); if (userNotification) { retval = CFUserNotificationReceiveResponse(userNotification, timeout, responseFlags); if (MACH_RCV_TIMED_OUT == retval) { retval = CFUserNotificationCancel(userNotification); if (responseFlags) *responseFlags = kCFUserNotificationCancelResponse; } CFRelease(userNotification); } CFRelease(dict); return retval; }
void Alert_free(Alert * * alert_p_p) { Alert * alert_p = *alert_p_p; if (alert_p) { LIST_REMOVE(alert_p, entries); if (alert_p->rls) { CFRunLoopSourceInvalidate(alert_p->rls); my_CFRelease(&alert_p->rls); } if (alert_p->notif) { (void)CFUserNotificationCancel(alert_p->notif); my_CFRelease(&alert_p->notif); } bzero(alert_p, sizeof(*alert_p)); free(alert_p); } *alert_p_p = NULL; return; }
boolean_t Alert_update(Alert * alert_p, char * title, char * message) { CFDictionaryRef dict = NULL; SInt32 error; dict = make_alert_dict(title, message); if (dict == NULL) { goto failed; } CFUserNotificationCancel(alert_p->notif); error = CFUserNotificationUpdate(alert_p->notif, 0, 0, dict); my_CFRelease(&dict); if (error != 0) { EAPLOG_FL(LOG_NOTICE, "CFUserNotificationUpdate failed, %d", error); goto failed; } return (TRUE); failed: return (FALSE); }
/* PSLowPowerPSChange * * Is the handler that gets notified when power source (battery or UPS) * state changes. We might respond to this by posting a user notification * or performing emergency shutdown. */ __private_extern__ void PSLowPowerPSChange(CFTypeRef ps_blob) { CFTypeRef ups = NULL; CFDictionaryRef ups_info = 0; int t1, t2; CFNumberRef n1, n2; int minutes_remaining; int percent_remaining; CFBooleanRef isPresent; static int last_ups_power_source = _kIOUPSExternalPowerBit; CFStringRef power_source = 0; CFNumberRef ups_id = 0; // Bail immediately if another application (like APC's PowerChute) // is managing emergency UPS shutdown if(!_weManageUPSPower()) { goto _exit_PowerSourcesHaveChanged_; } // *** Inspect UPS power levels // We assume we're only dealing with 1 UPS for simplicity. // The "more than one UPS attached " case is undefined. if((ups = IOPSGetActiveUPS(ps_blob))) { ups_info = isA_CFDictionary(IOPSGetPowerSourceDescription(ps_blob, ups)); if(!ups_info) goto _exit_PowerSourcesHaveChanged_; ups_id = isA_CFNumber(CFDictionaryGetValue(ups_info, CFSTR(kIOPSPowerSourceIDKey))); if(!ups_id) goto _exit_PowerSourcesHaveChanged_; // Check UPS "Is Present" key isPresent = isA_CFBoolean(CFDictionaryGetValue(ups_info, CFSTR(kIOPSIsPresentKey))); if(!isPresent || !CFBooleanGetValue(isPresent)) { #if HAVE_CF_USER_NOTIFICATION if(_UPSAlert) { CFUserNotificationCancel(_UPSAlert); _UPSAlert = 0; } #endif // If UPS isn't active or connected we shouldn't base policy decisions on it goto _exit_PowerSourcesHaveChanged_; } // Check Power Source power_source = isA_CFString(CFDictionaryGetValue(ups_info, CFSTR(kIOPSPowerSourceStateKey))); if(!power_source || !CFEqual(power_source, CFSTR(kIOPSBatteryPowerValue))) { #if HAVE_CF_USER_NOTIFICATION // Running off of AC Power if(_UPSAlert) { CFUserNotificationCancel(_UPSAlert); _UPSAlert = 0; } #endif // we have to be draining the internal battery to do a shutdown, so we'll just exit from here. goto _exit_PowerSourcesHaveChanged_; } // UPS is running off of internal battery power. Show warning if we just switched from AC to battery. if(_kIOUPSExternalPowerBit == last_ups_power_source) { _switchedToUPSPowerTime = CFAbsoluteTimeGetCurrent(); if( _thresh->haltafter[kHaltEnabled] ) { // If there's a "shutdown after X minutes on UPS power" threshold, // set a timer to remind us to check UPS state again after X minutes _reEvaluatePowerSourcesLater(5 + (60*_thresh->haltafter[kHaltValue])); } #if HAVE_CF_USER_NOTIFICATION if(!_UPSAlert) _UPSAlert = _copyUPSWarning(); #endif } // TODO: switch this battery-present check for the IOKit // private API IOPMSystemSupportsUPSShutdown // Is an internal battery present? if(kCFBooleanTrue == IOPSPowerSourceSupported(ps_blob, CFSTR(kIOPMBatteryPowerKey))) { // Do not do UPS shutdown if internal battery is present. // Internal battery may still be providing power. // Don't do any further UPS shutdown processing. // PMU will cause an emergency sleep when the battery runs out - we fall back on that // in the battery case. goto _exit_PowerSourcesHaveChanged_; } // ****** // ****** Perform emergency shutdown if any of the shutdown thresholds is true // Check to make sure that the UPS has been on battery power for a full 10 seconds before initiating a shutdown. // Certain UPS's have reported transient "on battery power with 0% capacity remaining" states for 3-5 seconds. // So we make sure not to heed this shutdown notice unless we've been on battery power for 10 seconds. if(_secondsSpentOnUPSPower() < 10) { _reEvaluatePowerSourcesLater(10); goto _exit_PowerSourcesHaveChanged_; } // Calculate battery percentage remaining n1 = isA_CFNumber(CFDictionaryGetValue(ups_info, CFSTR(kIOPSCurrentCapacityKey))); n2 = isA_CFNumber(CFDictionaryGetValue(ups_info, CFSTR(kIOPSMaxCapacityKey))); if(n1 && n2) { if( CFNumberGetValue(n1, kCFNumberIntType, &t1) && CFNumberGetValue(n2, kCFNumberIntType, &t2)) { percent_remaining = (int)(100.0* ((double)t1) / ((double)t2) ); if( _thresh->haltpercent[kHaltEnabled] ) { if( percent_remaining <= _thresh->haltpercent[kHaltValue] ) { _doPowerEmergencyShutdown(ups_id); } } } } // Get UPS's estimated time remaining n1 = isA_CFNumber(CFDictionaryGetValue(ups_info, CFSTR(kIOPSTimeToEmptyKey))); if(n1) { if(CFNumberGetValue(n1, kCFNumberIntType, &minutes_remaining)) { if( _thresh->haltremain[kHaltEnabled] ) { if( minutes_remaining <= _thresh->haltremain[kHaltValue] ) { _doPowerEmergencyShutdown(ups_id); } } } } // Determine how long we've been running on UPS power if( _thresh->haltafter[kHaltEnabled] ) { if(_minutesSpentOnUPSPower() >= _thresh->haltafter[kHaltValue]) { _doPowerEmergencyShutdown(ups_id); } } } else { // No "active UPS" detected. // One could have just disappeared - if we're showing an alert, clear it. #if HAVE_CF_USER_NOTIFICATION if(_UPSAlert) { CFUserNotificationCancel(_UPSAlert); _UPSAlert = 0; } #endif } // exit point _exit_PowerSourcesHaveChanged_: if(power_source && CFEqual(power_source, CFSTR(kIOPSBatteryPowerValue))) { last_ups_power_source = _kIOUPSInternalPowerBit; } else { last_ups_power_source = _kIOUPSExternalPowerBit; } return; }