docs: Small improvements to glib-mkenums man page
[glib.git] / gio / gcocoanotificationbackend.c
blobae4ad883363ecc967f338cb2747daf42aac56339
1 /*
2 * Copyright © 2015 Patrick Griffis
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General
15 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 * Authors: Patrick Griffis
20 #include "config.h"
22 #import <Cocoa/Cocoa.h>
23 #include "gnotificationbackend.h"
24 #include "gapplication.h"
25 #include "gaction.h"
26 #include "gactiongroup.h"
27 #include "giomodule-priv.h"
28 #include "gnotification-private.h"
29 #include "gthemedicon.h"
30 #include "gfileicon.h"
31 #include "gfile.h"
33 #define G_TYPE_COCOA_NOTIFICATION_BACKEND (g_cocoa_notification_backend_get_type ())
34 #define G_COCOA_NOTIFICATION_BACKEND(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_COCOA_NOTIFICATION_BACKEND, GCocoaNotificationBackend))
36 typedef struct _GCocoaNotificationBackend GCocoaNotificationBackend;
37 typedef GNotificationBackendClass GCocoaNotificationBackendClass;
38 struct _GCocoaNotificationBackend
40 GNotificationBackend parent;
43 GType g_cocoa_notification_backend_get_type (void);
45 G_DEFINE_TYPE_WITH_CODE (GCocoaNotificationBackend, g_cocoa_notification_backend, G_TYPE_NOTIFICATION_BACKEND,
46 _g_io_modules_ensure_extension_points_registered ();
47 g_io_extension_point_implement (G_NOTIFICATION_BACKEND_EXTENSION_POINT_NAME, g_define_type_id, "cocoa", 0));
49 static NSString *
50 nsstring_from_cstr (const char *cstr)
52 if (!cstr)
53 return nil;
55 return [[NSString alloc] initWithUTF8String:cstr];
58 static NSImage*
59 nsimage_from_gicon (GIcon *icon)
61 if (G_IS_FILE_ICON (icon))
63 NSImage *image = nil;
64 GFile *file;
65 char *path;
67 file = g_file_icon_get_file (G_FILE_ICON (icon));
68 path = g_file_get_path (file);
69 if (path)
71 NSString *str_path = nsstring_from_cstr (path);
72 image = [[NSImage alloc] initByReferencingFile:str_path];
74 [str_path release];
75 g_free (path);
77 return image;
79 else
81 g_warning ("This icon type is not handled by this NotificationBackend");
82 return nil;
86 static void
87 activate_detailed_action (const char * action)
89 char *name;
90 GVariant *target;
92 if (!g_str_has_prefix (action, "app."))
94 g_warning ("Notification action does not have \"app.\" prefix");
95 return;
98 if (g_action_parse_detailed_name (action, &name, &target, NULL))
100 g_action_group_activate_action (G_ACTION_GROUP (g_application_get_default()), name + 4, target);
101 g_free (name);
102 if (target)
103 g_variant_unref (target);
107 @interface GNotificationCenterDelegate : NSObject<NSUserNotificationCenterDelegate> @end
108 @implementation GNotificationCenterDelegate
110 -(void) userNotificationCenter:(NSUserNotificationCenter*) center
111 didActivateNotification:(NSUserNotification*) notification
113 if ([notification activationType] == NSUserNotificationActivationTypeContentsClicked)
115 const char *action = [[notification userInfo][@"default"] UTF8String];
116 if (action)
117 activate_detailed_action (action);
118 /* OSX Always activates the front window */
120 else if ([notification activationType] == NSUserNotificationActivationTypeActionButtonClicked)
122 const char *action = [[notification userInfo][@"button0"] UTF8String];
123 if (action)
124 activate_detailed_action (action);
127 [center removeDeliveredNotification:notification];
130 @end
132 static GNotificationCenterDelegate *cocoa_notification_delegate;
134 static gboolean
135 g_cocoa_notification_backend_is_supported (void)
137 NSBundle *bundle = [NSBundle mainBundle];
139 /* This is always actually supported, but without a bundle it does nothing */
140 if (![bundle bundleIdentifier])
141 return FALSE;
143 return TRUE;
146 static void
147 add_actions_to_notification (NSUserNotification *userNotification,
148 GNotification *notification)
150 guint n_buttons = g_notification_get_n_buttons (notification);
151 char *action = NULL, *label = NULL;
152 GVariant *target = NULL;
153 NSMutableDictionary *user_info = nil;
155 if (g_notification_get_default_action (notification, &action, &target))
157 char *detailed_name = g_action_print_detailed_name (action, target);
158 NSString *action_name = nsstring_from_cstr (detailed_name);
159 user_info = [[NSMutableDictionary alloc] init];
161 user_info[@"default"] = action_name;
163 [action_name release];
164 g_free (detailed_name);
165 g_clear_pointer (&action, g_free);
166 g_clear_pointer (&target, g_variant_unref);
169 if (n_buttons)
171 g_notification_get_button (notification, 0, &label, &action, &target);
172 if (label)
174 NSString *str_label = nsstring_from_cstr (label);
175 char *detailed_name = g_action_print_detailed_name (action, target);
176 NSString *action_name = nsstring_from_cstr (detailed_name);
178 if (!user_info)
179 user_info = [[NSMutableDictionary alloc] init];
181 user_info[@"button0"] = action_name;
182 userNotification.actionButtonTitle = str_label;
184 [str_label release];
185 [action_name release];
186 g_free (label);
187 g_free (action);
188 g_free (detailed_name);
189 g_clear_pointer (&target, g_variant_unref);
192 if (n_buttons > 1)
193 g_warning ("Only a single button is currently supported by this NotificationBackend");
196 userNotification.userInfo = user_info;
197 [user_info release];
200 static void
201 g_cocoa_notification_backend_send_notification (GNotificationBackend *backend,
202 const gchar *cstr_id,
203 GNotification *notification)
205 NSString *str_title = nil, *str_text = nil, *str_id = nil;
206 NSImage *content = nil;
207 const char *cstr;
208 GIcon *icon;
209 NSUserNotification *userNotification;
210 NSUserNotificationCenter *center;
212 if ((cstr = g_notification_get_title (notification)))
213 str_title = nsstring_from_cstr (cstr);
214 if ((cstr = g_notification_get_body (notification)))
215 str_text = nsstring_from_cstr (cstr);
216 if (cstr_id != NULL)
217 str_id = nsstring_from_cstr (cstr_id);
218 if ((icon = g_notification_get_icon (notification)))
219 content = nsimage_from_gicon (icon);
220 /* NOTE: There is no priority */
222 userNotification = [NSUserNotification new];
223 userNotification.title = str_title;
224 userNotification.informativeText = str_text;
225 userNotification.identifier = str_id;
226 userNotification.contentImage = content;
227 /* NOTE: Buttons only show up if your bundle has NSUserNotificationAlertStyle set to "alerts" */
228 add_actions_to_notification (userNotification, notification);
230 if (!cocoa_notification_delegate)
231 cocoa_notification_delegate = [[GNotificationCenterDelegate alloc] init];
233 center = [NSUserNotificationCenter defaultUserNotificationCenter];
234 center.delegate = cocoa_notification_delegate;
235 [center deliverNotification:userNotification];
237 [str_title release];
238 [str_text release];
239 [str_id release];
240 [content release];
241 [userNotification release];
244 static void
245 g_cocoa_notification_backend_withdraw_notification (GNotificationBackend *backend,
246 const gchar *cstr_id)
248 NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
249 NSArray *notifications = [center deliveredNotifications];
250 NSString *str_id = nsstring_from_cstr (cstr_id);
252 for (NSUserNotification *notification in notifications)
254 if ([notification.identifier compare:str_id] == NSOrderedSame)
256 [center removeDeliveredNotification:notification];
257 break;
261 [notifications release];
262 [str_id release];
265 static void
266 g_cocoa_notification_backend_init (GCocoaNotificationBackend *backend)
270 static void
271 g_cocoa_notification_backend_class_init (GCocoaNotificationBackendClass *klass)
273 GNotificationBackendClass *backend_class = G_NOTIFICATION_BACKEND_CLASS (klass);
275 backend_class->is_supported = g_cocoa_notification_backend_is_supported;
276 backend_class->send_notification = g_cocoa_notification_backend_send_notification;
277 backend_class->withdraw_notification = g_cocoa_notification_backend_withdraw_notification;