# HG changeset patch # User bsmith@81767d24-ef19-dc11-ae90-00e081727c95 # Date 1589462025 0 # Node ID 3ccd0da075147fee6b4d542db423539b7a20525e # Parent 2c2530f8cbefef7259ed63e9d1f7640f5cb18686 Mac: Initial notification support for the Mac. diff -r 2c2530f8cbef -r 3ccd0da07514 configure --- a/configure Thu May 14 01:52:27 2020 +0000 +++ b/configure Thu May 14 13:13:45 2020 +0000 @@ -4676,6 +4676,10 @@ DW_SRC=dw.m DW_DEFINE=__MAC__ LIBS="$LIBS -framework Cocoa -framework WebKit" + OSVER=`uname -r` + if test $OSVER > 17.9.9; then + LIBS="$LIBS -framework UserNotifications" + fi build_gtk="no" ;; *) diff -r 2c2530f8cbef -r 3ccd0da07514 configure.in --- a/configure.in Thu May 14 01:52:27 2020 +0000 +++ b/configure.in Thu May 14 13:13:45 2020 +0000 @@ -176,6 +176,10 @@ DW_SRC=dw.m DW_DEFINE=__MAC__ LIBS="$LIBS -framework Cocoa -framework WebKit" + OSVER=`uname -r` + if test $OSVER > 17.9.9; then + LIBS="$LIBS -framework UserNotifications" + fi build_gtk="no" ;; *) diff -r 2c2530f8cbef -r 3ccd0da07514 mac/dw.m --- a/mac/dw.m Thu May 14 01:52:27 2020 +0000 +++ b/mac/dw.m Thu May 14 13:13:45 2020 +0000 @@ -2,7 +2,7 @@ * Dynamic Windows: * A GTK like implementation of the MacOS GUI using Cocoa * - * (C) 2011-2019 Brian Smith + * (C) 2011-2020 Brian Smith * (C) 2011-2018 Mark Hessling * * Requires 10.5 or later. @@ -32,6 +32,11 @@ #define BUILDING_FOR_LION #endif +/* Create a define to let us know to include Mountain Lion specific features */ +#if defined(MAC_OS_X_VERSION_10_8) && ((defined(MAC_OS_X_VERSION_MAX_ALLOWED) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8) || !defined(MAC_OS_X_VERSION_MAX_ALLOWED)) +#define BUILDING_FOR_MOUNTAIN_LION +#endif + /* Macros to handle local auto-release pools */ #define DW_LOCAL_POOL_IN NSAutoreleasePool *localpool = nil; \ if(DWThread != (DWTID)-1 && pthread_self() != DWThread) \ @@ -146,6 +151,7 @@ #if defined(MAC_OS_X_VERSION_10_14) && ((defined(MAC_OS_X_VERSION_MAX_ALLOWED) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14) || !defined(MAC_OS_X_VERSION_MAX_ALLOWED)) #define DWProgressIndicatorStyleBar NSProgressIndicatorStyleBar #define BUILDING_FOR_MOJAVE +#import #else #define DWProgressIndicatorStyleBar NSProgressIndicatorBarStyle #endif @@ -10690,6 +10696,109 @@ } /* + * Creates a new system notification if possible. + * Parameters: + * title: The short title of the notification. + * pixmap: Handle to an image to display or NULL if none. + * description: A longer description of the notification, + * or NULL if none is necessary. + * Returns: + * A handle to the notification which can be used to attach a "clicked" event if desired, + * or NULL if it fails or notifications are not supported by the system. + * Remarks: + * This will create a system notification that will show in the notifaction panel + * on supported systems, which may be clicked to perform another task. + */ +HWND dw_notification_new(const char *title, HPIXMAP pixmap, const char *description, ...) +{ +#ifdef BUILDING_FOR_MOUNTAIN_LION + char outbuf[1025] = {0}; + HWND retval = NULL; + + if(description) + { + va_list args; + + va_start(args, description); + vsnprintf(outbuf, 1024, description, args); + va_end(args); + } + +#ifdef BUILDING_FOR_MOJAVE + // Configure the notification's payload. + if (@available(macOS 10.14, *)) + { + UNMutableNotificationContent* notification = [[UNMutableNotificationContent alloc] init]; + + if(notification) + { + notification.title = [NSString stringWithUTF8String:title]; + if(description) + notification.body = [NSString stringWithUTF8String:outbuf]; + retval = notification; + } + } + else +#endif + { + // Fallback on earlier versions + NSUserNotification *notification = [[NSUserNotification alloc] init]; + + if(notification) + { + notification.title = [NSString stringWithUTF8String:title]; + notification.informativeText = [NSString stringWithUTF8String:outbuf]; + if(pixmap && pixmap->image) + notification.contentImage = pixmap->image; + retval = notification; + } + } + return retval; +#else + return NULL; +#endif +} + +/* + * Sends a notification created by dw_notification_new() after attaching signal handler. + * Parameters: + * notification: The handle to the notification returned by dw_notification_new(). + * Returns: + * DW_ERROR_NONE on success, DW_ERROR_UNKNOWN on error or not supported. + */ +int dw_notification_send(HWND notification) +{ +#ifdef BUILDING_FOR_MOUNTAIN_LION + if(notification) + { +#ifdef BUILDING_FOR_MOJAVE + // Schedule the notification. + if (@available(macOS 10.14, *)) + { + UNMutableNotificationContent *content = (UNMutableNotificationContent *)notification; + NSString *notid = [NSString stringWithFormat:@"dw-notification-%llu", (unsigned long long)notification]; + UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:notid + content:content trigger:nil]; + + UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter]; + [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) { + _event_handler(notification, nil, 8); + }]; + } + else +#endif + { + // Fallback on earlier versions + [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification]; + } + return DW_ERROR_NONE; + } +#endif + return DW_ERROR_UNKNOWN; +} + + +/* * Returns some information about the current operating environment. * Parameters: * env: Pointer to a DWEnv struct. @@ -11947,6 +12056,15 @@ DWObj = [[DWObject alloc] init]; DWDefaultFont = nil; #ifdef BUILDING_FOR_MOJAVE + if (@available(macOS 10.14, *)) + { + [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:UNAuthorizationOptionAlert + completionHandler:^(BOOL granted, NSError * _Nullable error) { + if (!granted) { + NSLog(@"Unable to get notification permission."); + } + }]; + } _DWDirtyDrawables = [[NSMutableArray alloc] init]; #else /* Create mutexes for thread safety */