CFUserNotificationRef CFUserNotificationCreate(CFAllocatorRef allocator, CFTimeInterval timeout, CFOptionFlags flags, SInt32 *error, CFDictionaryRef dictionary) { CHECK_FOR_FORK(); CFUserNotificationRef userNotification = NULL; SInt32 retval = ERR_SUCCESS; static uint16_t tokenCounter = 0; SInt32 token = ((getpid() << 16) | (tokenCounter++)); CFStringRef sessionID = (dictionary ? CFDictionaryGetValue(dictionary, kCFUserNotificationSessionIDKey) : NULL); mach_port_t replyPort = MACH_PORT_NULL; if (!allocator) allocator = __CFGetDefaultAllocator(); retval = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &replyPort); if (ERR_SUCCESS == retval && MACH_PORT_NULL != replyPort) retval = _CFUserNotificationSendRequest(allocator, sessionID, replyPort, token, timeout, flags, dictionary); if (ERR_SUCCESS == retval) { userNotification = (CFUserNotificationRef)_CFRuntimeCreateInstance(allocator, CFUserNotificationGetTypeID(), sizeof(struct __CFUserNotification) - sizeof(CFRuntimeBase), NULL); if (userNotification) { userNotification->_replyPort = replyPort; userNotification->_token = token; userNotification->_timeout = timeout; userNotification->_requestFlags = flags; userNotification->_responseFlags = 0; userNotification->_sessionID = NULL; userNotification->_responseDictionary = NULL; userNotification->_machPort = NULL; userNotification->_callout = NULL; if (sessionID) userNotification->_sessionID = CFStringCreateCopy(allocator, sessionID); } else { retval = unix_err(ENOMEM); } } else { if (dictionary) CFUserNotificationLog(CFDictionaryGetValue(dictionary, kCFUserNotificationAlertHeaderKey), CFDictionaryGetValue(dictionary, kCFUserNotificationAlertMessageKey)); } if (ERR_SUCCESS != retval && MACH_PORT_NULL != replyPort) mach_port_destroy(mach_task_self(), replyPort); if (error) *error = retval; return userNotification; }
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; }
SInt32 CFUserNotificationCancel(CFUserNotificationRef userNotification) { CHECK_FOR_FORK(); SInt32 retval = ERR_SUCCESS; #if DEPLOYMENT_TARGET_MACOSX if (userNotification && MACH_PORT_NULL != userNotification->_replyPort) retval = _CFUserNotificationSendRequest(CFGetAllocator(userNotification), userNotification->_sessionID, userNotification->_replyPort, userNotification->_token, 0, kCFUserNotificationCancelFlag, NULL); #endif return retval; }
SInt32 CFUserNotificationUpdate(CFUserNotificationRef userNotification, CFTimeInterval timeout, CFOptionFlags flags, CFDictionaryRef dictionary) { CHECK_FOR_FORK(); SInt32 retval = ERR_SUCCESS; #if DEPLOYMENT_TARGET_MACOSX if (userNotification && MACH_PORT_NULL != userNotification->_replyPort) retval = _CFUserNotificationSendRequest(CFGetAllocator(userNotification), userNotification->_sessionID, userNotification->_replyPort, userNotification->_token, timeout, flags|kCFUserNotificationUpdateFlag, dictionary); #endif return retval; }
CFRunLoopSourceRef CFUserNotificationCreateRunLoopSource(CFAllocatorRef allocator, CFUserNotificationRef userNotification, CFUserNotificationCallBack callout, CFIndex order) { CHECK_FOR_FORK(); CFRunLoopSourceRef source = NULL; if (userNotification && callout && !userNotification->_machPort && MACH_PORT_NULL != userNotification->_replyPort) { CFMachPortContext context = {0, userNotification, NULL, NULL, NULL}; userNotification->_machPort = CFMachPortCreateWithPort(CFGetAllocator(userNotification), (mach_port_t)userNotification->_replyPort, _CFUserNotificationMachPortCallBack, &context, NULL); } if (userNotification && userNotification->_machPort) { source = CFMachPortCreateRunLoopSource(allocator, userNotification->_machPort, order); userNotification->_callout = callout; } return source; }
CFStringRef CFUserNotificationGetResponseValue(CFUserNotificationRef userNotification, CFStringRef key, CFIndex idx) { CHECK_FOR_FORK(); CFStringRef retval = NULL; CFTypeRef value = NULL; if (userNotification && userNotification->_responseDictionary) { value = CFDictionaryGetValue(userNotification->_responseDictionary, key); if (CFGetTypeID(value) == CFStringGetTypeID()) { if (0 == idx) retval = (CFStringRef)value; } else if (CFGetTypeID(value) == CFArrayGetTypeID()) { if (0 <= idx && idx < CFArrayGetCount((CFArrayRef)value)) retval = (CFStringRef)CFArrayGetValueAtIndex((CFArrayRef)value, idx); } } return retval; }
SInt32 CFUserNotificationDisplayNotice(CFTimeInterval timeout, CFOptionFlags flags, CFURLRef iconURL, CFURLRef soundURL, CFURLRef localizationURL, CFStringRef alertHeader, CFStringRef alertMessage, CFStringRef defaultButtonTitle) { 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); userNotification = CFUserNotificationCreate(kCFAllocatorSystemDefault, timeout, flags, &retval, dict); if (userNotification) CFRelease(userNotification); CFRelease(dict); return retval; }
SInt32 CFUserNotificationReceiveResponse(CFUserNotificationRef userNotification, CFTimeInterval timeout, CFOptionFlags *responseFlags) { CHECK_FOR_FORK(); SInt32 retval = ERR_SUCCESS; #if DEPLOYMENT_TARGET_MACOSX mach_msg_timeout_t msgtime = (timeout > 0.0 && 1000.0 * timeout < INT_MAX) ? (mach_msg_timeout_t)(1000.0 * timeout) : 0; mach_msg_base_t *msg = NULL; CFIndex size = MAX_STRING_COUNT * MAX_STRING_LENGTH; CFDataRef responseData; if (userNotification && MACH_PORT_NULL != userNotification->_replyPort) { msg = (mach_msg_base_t *)CFAllocatorAllocate(kCFAllocatorSystemDefault, size, 0); if (__CFOASafe) __CFSetLastAllocationEventName(msg, "CFUserNotification (temp)"); if (msg) { memset(msg, 0, size); msg->header.msgh_size = size; if (msgtime > 0) { retval = mach_msg((mach_msg_header_t *)msg, MACH_RCV_MSG|MACH_RCV_TIMEOUT, 0, size, userNotification->_replyPort, msgtime, MACH_PORT_NULL); } else { retval = mach_msg((mach_msg_header_t *)msg, MACH_RCV_MSG, 0, size, userNotification->_replyPort, 0, MACH_PORT_NULL); } if (ERR_SUCCESS == retval) { if (responseFlags) *responseFlags = msg->header.msgh_id; if (msg->header.msgh_size > sizeof(mach_msg_base_t)) { responseData = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)msg + sizeof(mach_msg_base_t), msg->header.msgh_size - sizeof(mach_msg_base_t)); if (responseData) { userNotification->_responseDictionary = CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, responseData, kCFPropertyListImmutable, NULL); CFRelease(responseData); } } if (userNotification->_machPort) { CFMachPortInvalidate(userNotification->_machPort); CFRelease(userNotification->_machPort); userNotification->_machPort = NULL; } mach_port_destroy(mach_task_self(), userNotification->_replyPort); userNotification->_replyPort = MACH_PORT_NULL; } CFAllocatorDeallocate(kCFAllocatorSystemDefault, msg); } else { retval = unix_err(ENOMEM); } } #endif return retval; }
CFDictionaryRef CFUserNotificationGetResponseDictionary(CFUserNotificationRef userNotification) { CHECK_FOR_FORK(); return userNotification ? userNotification->_responseDictionary : NULL; }