diff options
Diffstat (limited to 'src/platform/cocoa/desktop.m')
| -rw-r--r-- | src/platform/cocoa/desktop.m | 57 |
1 files changed, 46 insertions, 11 deletions
diff --git a/src/platform/cocoa/desktop.m b/src/platform/cocoa/desktop.m index 76aa551..25393d5 100644 --- a/src/platform/cocoa/desktop.m +++ b/src/platform/cocoa/desktop.m @@ -4,7 +4,9 @@ #include "common/desktop.h" #include "common/private_desktop.h" +#include <dispatch/dispatch.h> #include <CoreFoundation/CoreFoundation.h> +#include <errno.h> #include <limits.h> #include <mach-o/dyld.h> #include <stdio.h> @@ -44,7 +46,12 @@ bool desktop_open_uri(const char *uri) @end static YaslNotificationDelegate *notification_delegate; +/* Main-thread state. Notifications made before the answer to the one + * authorization request wait in the queue and are posted when it is granted. */ +static NSMutableArray<UNNotificationRequest *> *notification_queue; static bool authorization_requested; +static bool authorization_granted; +static bool authorization_denied; /* UNUserNotificationCenter raises an exception outside an app bundle. */ static bool notifications_available(void) @@ -56,24 +63,26 @@ static bool notifications_available(void) bool desktop_notify(const char *app_id, const char *title, const char *body) { (void)app_id; - if (!notifications_available()) return false; + if (!notifications_available()) { + errno = ENOTSUP; + return false; + } + if (authorization_denied) { + errno = EACCES; + return false; + } @autoreleasepool { NSString *heading = [NSString stringWithUTF8String:title]; NSString *message = [NSString stringWithUTF8String:body]; - if (!heading || !message) return false; + if (!heading || !message) { + errno = EINVAL; + return false; + } UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; if (!notification_delegate) { notification_delegate = [[YaslNotificationDelegate alloc] init]; center.delegate = notification_delegate; } - if (!authorization_requested) { - authorization_requested = true; - [center requestAuthorizationWithOptions:UNAuthorizationOptionAlert - completionHandler:^(BOOL granted, NSError *error) { - (void)granted; - (void)error; - }]; - } UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init]; content.title = heading; content.body = message; @@ -82,7 +91,33 @@ bool desktop_notify(const char *app_id, const char *title, const char *body) content:content trigger:nil]; [content release]; - [center addNotificationRequest:request withCompletionHandler:nil]; + if (authorization_granted) { + [center addNotificationRequest:request withCompletionHandler:nil]; + return true; + } + if (!notification_queue) + notification_queue = [[NSMutableArray alloc] init]; + [notification_queue addObject:request]; + if (!authorization_requested) { + authorization_requested = true; + [center requestAuthorizationWithOptions:UNAuthorizationOptionAlert + completionHandler:^(BOOL granted, NSError *error) { + (void)error; + /* The handler runs on a background queue; the state is main-thread only. */ + dispatch_async(dispatch_get_main_queue(), ^{ + if (!granted) { + authorization_denied = true; + [notification_queue removeAllObjects]; + return; + } + authorization_granted = true; + UNUserNotificationCenter *granted_center = [UNUserNotificationCenter currentNotificationCenter]; + for (UNNotificationRequest *queued in notification_queue) + [granted_center addNotificationRequest:queued withCompletionHandler:nil]; + [notification_queue removeAllObjects]; + }); + }]; + } return true; } } |
