diff --git a/kitty/cocoa_window.m b/kitty/cocoa_window.m index 9b81b276a..5add7934b 100644 --- a/kitty/cocoa_window.m +++ b/kitty/cocoa_window.m @@ -9,7 +9,9 @@ #include "state.h" #include "monotonic.h" #include +#ifndef KITTY_USE_DEPRECATED_MACOS_NOTIFICATION_API #include +#endif #include // Needed for _NSGetProgname @@ -135,6 +137,68 @@ get_dock_menu(id self UNUSED, SEL _cmd UNUSED, NSApplication *sender UNUSED) { static PyObject *notification_activated_callback = NULL; +static PyObject* +set_notification_activated_callback(PyObject *self UNUSED, PyObject *callback) { + if (notification_activated_callback) Py_DECREF(notification_activated_callback); + notification_activated_callback = callback; + Py_INCREF(callback); + Py_RETURN_NONE; +} + +#ifdef KITTY_USE_DEPRECATED_MACOS_NOTIFICATION_API + +@interface NotificationDelegate : NSObject +@end + +@implementation NotificationDelegate + - (void)userNotificationCenter:(NSUserNotificationCenter *)center + didDeliverNotification:(NSUserNotification *)notification { + (void)(center); (void)(notification); + } + + - (BOOL) userNotificationCenter:(NSUserNotificationCenter *)center + shouldPresentNotification:(NSUserNotification *)notification { + (void)(center); (void)(notification); + return YES; + } + + - (void) userNotificationCenter:(NSUserNotificationCenter *)center + didActivateNotification:(NSUserNotification *)notification { + (void)(center); (void)(notification); + if (notification_activated_callback) { + PyObject *ret = PyObject_CallFunction(notification_activated_callback, "z", + notification.userInfo[@"user_id"] ? [notification.userInfo[@"user_id"] UTF8String] : NULL); + if (ret == NULL) PyErr_Print(); + else Py_DECREF(ret); + } + } +@end + +static PyObject* +cocoa_send_notification(PyObject *self UNUSED, PyObject *args) { + char *identifier = NULL, *title = NULL, *informativeText = NULL, *subtitle = NULL; + if (!PyArg_ParseTuple(args, "zsz|z", &identifier, &title, &informativeText, &subtitle)) return NULL; + NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter]; + if (!center) {PyErr_SetString(PyExc_RuntimeError, "Failed to get the user notification center"); return NULL; } + if (!center.delegate) center.delegate = [[NotificationDelegate alloc] init]; + NSUserNotification *n = [NSUserNotification new]; +#define SET(x) { \ + if (x) { \ + NSString *t = @(x); \ + n.x = t; \ + [t release]; \ + }} + SET(title); SET(subtitle); SET(informativeText); +#undef SET + if (identifier) { + n.userInfo = @{@"user_id": @(identifier)}; + } + [center deliverNotification:n]; + Py_RETURN_NONE; +} + +#else + @interface NotificationDelegate : NSObject @end @@ -213,14 +277,6 @@ drain_pending_notifications(BOOL granted) { } } -PyObject* -set_notification_activated_callback(PyObject *self UNUSED, PyObject *callback) { - if (notification_activated_callback) Py_DECREF(notification_activated_callback); - notification_activated_callback = callback; - Py_INCREF(callback); - Py_RETURN_NONE; -} - static PyObject* cocoa_send_notification(PyObject *self UNUSED, PyObject *args) { char *identifier = NULL, *title = NULL, *body = NULL, *subtitle = NULL; @@ -244,6 +300,8 @@ cocoa_send_notification(PyObject *self UNUSED, PyObject *args) { Py_RETURN_NONE; } +#endif + @interface ServiceProvider : NSObject @end @@ -539,10 +597,14 @@ cleanup() { if (dockMenu) [dockMenu release]; dockMenu = nil; Py_CLEAR(notification_activated_callback); + +#ifndef KITTY_USE_DEPRECATED_MACOS_NOTIFICATION_API drain_pending_notifications(NO); free(notification_queue.notifications); notification_queue.notifications = NULL; notification_queue.capacity = 0; +#endif + } // autoreleasepool } diff --git a/setup.py b/setup.py index 3aaedd36c..fe4eed68b 100755 --- a/setup.py +++ b/setup.py @@ -213,7 +213,10 @@ def get_sanitize_args(cc: str, ccver: Tuple[int, int]) -> List[str]: def test_compile(cc: str, *cflags: str, src: Optional[str] = None) -> bool: src = src or 'int main(void) { return 0; }' - p = subprocess.Popen([cc] + list(cflags) + ['-x', 'c', '-o', os.devnull, '-'], stdin=subprocess.PIPE) + p = subprocess.Popen( + [cc] + list(cflags) + ['-x', 'c', '-o', os.devnull, '-'], + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.PIPE + ) stdin = p.stdin assert stdin is not None try: @@ -336,8 +339,12 @@ def kitty_env() -> Env: if is_macos: platform_libs = [ '-framework', 'CoreText', '-framework', 'CoreGraphics', - '-framework', 'UserNotifications' ] + user_notifications_framework = first_successful_compile(ans.cc, '-framework UserNotifications') + if user_notifications_framework: + platform_libs.extend(shlex.split(user_notifications_framework)) + else: + cppflags.append('-DKITTY_USE_DEPRECATED_MACOS_NOTIFICATION_API') # Apple deprecated OpenGL in Mojave (10.14) silence the endless # warnings about it cppflags.append('-DGL_SILENCE_DEPRECATION')