summaryrefslogtreecommitdiff
path: root/src/platform/cocoa/desktop.m
diff options
context:
space:
mode:
Diffstat (limited to 'src/platform/cocoa/desktop.m')
-rw-r--r--src/platform/cocoa/desktop.m57
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;
}
}