nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /*
2 * Copyright © 2015 Patrick Griffis
3 *
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 of the License, or (at your option) any later version.
8 *
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.
13 *
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/>.
16 *
17 * Authors: Patrick Griffis
18 */
19  
20 #include "config.h"
21  
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"
32  
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))
35  
36 typedef struct _GCocoaNotificationBackend GCocoaNotificationBackend;
37 typedef GNotificationBackendClass GCocoaNotificationBackendClass;
38 struct _GCocoaNotificationBackend
39 {
40 GNotificationBackend parent;
41 };
42  
43 GType g_cocoa_notification_backend_get_type (void);
44  
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));
48  
49 static NSString *
50 nsstring_from_cstr (const char *cstr)
51 {
52 if (!cstr)
53 return nil;
54  
55 return [[NSString alloc] initWithUTF8String:cstr];
56 }
57  
58 static NSImage*
59 nsimage_from_gicon (GIcon *icon)
60 {
61 if (G_IS_FILE_ICON (icon))
62 {
63 NSImage *image = nil;
64 GFile *file;
65 char *path;
66  
67 file = g_file_icon_get_file (G_FILE_ICON (icon));
68 path = g_file_get_path (file);
69 if (path)
70 {
71 NSString *str_path = nsstring_from_cstr (path);
72 image = [[NSImage alloc] initByReferencingFile:str_path];
73  
74 [str_path release];
75 g_free (path);
76 }
77 return image;
78 }
79 else
80 {
81 g_warning ("This icon type is not handled by this NotificationBackend");
82 return nil;
83 }
84 }
85  
86 static void
87 activate_detailed_action (const char * action)
88 {
89 char *name;
90 GVariant *target;
91  
92 if (!g_str_has_prefix (action, "app."))
93 {
94 g_warning ("Notification action does not have \"app.\" prefix");
95 return;
96 }
97  
98 if (g_action_parse_detailed_name (action, &name, &target, NULL))
99 {
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);
104 }
105 }
106  
107 @interface GNotificationCenterDelegate : NSObject<NSUserNotificationCenterDelegate> @end
108 @implementation GNotificationCenterDelegate
109  
110 -(void) userNotificationCenter:(NSUserNotificationCenter*) center
111 didActivateNotification:(NSUserNotification*) notification
112 {
113 if ([notification activationType] == NSUserNotificationActivationTypeContentsClicked)
114 {
115 const char *action = [[notification userInfo][@"default"] UTF8String];
116 if (action)
117 activate_detailed_action (action);
118 /* OSX Always activates the front window */
119 }
120 else if ([notification activationType] == NSUserNotificationActivationTypeActionButtonClicked)
121 {
122 const char *action = [[notification userInfo][@"button0"] UTF8String];
123 if (action)
124 activate_detailed_action (action);
125 }
126  
127 [center removeDeliveredNotification:notification];
128 }
129  
130 @end
131  
132 static GNotificationCenterDelegate *cocoa_notification_delegate;
133  
134 static gboolean
135 g_cocoa_notification_backend_is_supported (void)
136 {
137 NSBundle *bundle = [NSBundle mainBundle];
138  
139 /* This is always actually supported, but without a bundle it does nothing */
140 if (![bundle bundleIdentifier])
141 return FALSE;
142  
143 return TRUE;
144 }
145  
146 static void
147 add_actions_to_notification (NSUserNotification *userNotification,
148 GNotification *notification)
149 {
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;
154  
155 if (g_notification_get_default_action (notification, &action, &target))
156 {
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];
160  
161 user_info[@"default"] = action_name;
162  
163 [action_name release];
164 g_free (detailed_name);
165 g_clear_pointer (&action, g_free);
166 g_clear_pointer (&target, g_variant_unref);
167 }
168  
169 if (n_buttons)
170 {
171 g_notification_get_button (notification, 0, &label, &action, &target);
172 if (label)
173 {
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);
177  
178 if (!user_info)
179 user_info = [[NSMutableDictionary alloc] init];
180  
181 user_info[@"button0"] = action_name;
182 userNotification.actionButtonTitle = str_label;
183  
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);
190 }
191  
192 if (n_buttons > 1)
193 g_warning ("Only a single button is currently supported by this NotificationBackend");
194 }
195  
196 userNotification.userInfo = user_info;
197 [user_info release];
198 }
199  
200 static void
201 g_cocoa_notification_backend_send_notification (GNotificationBackend *backend,
202 const gchar *cstr_id,
203 GNotification *notification)
204 {
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;
211  
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 */
221  
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);
229  
230 if (!cocoa_notification_delegate)
231 cocoa_notification_delegate = [[GNotificationCenterDelegate alloc] init];
232  
233 center = [NSUserNotificationCenter defaultUserNotificationCenter];
234 center.delegate = cocoa_notification_delegate;
235 [center deliverNotification:userNotification];
236  
237 [str_title release];
238 [str_text release];
239 [str_id release];
240 [content release];
241 [userNotification release];
242 }
243  
244 static void
245 g_cocoa_notification_backend_withdraw_notification (GNotificationBackend *backend,
246 const gchar *cstr_id)
247 {
248 NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
249 NSArray *notifications = [center deliveredNotifications];
250 NSString *str_id = nsstring_from_cstr (cstr_id);
251  
252 for (NSUserNotification *notification in notifications)
253 {
254 if ([notification.identifier compare:str_id] == NSOrderedSame)
255 {
256 [center removeDeliveredNotification:notification];
257 break;
258 }
259 }
260  
261 [notifications release];
262 [str_id release];
263 }
264  
265 static void
266 g_cocoa_notification_backend_init (GCocoaNotificationBackend *backend)
267 {
268 }
269  
270 static void
271 g_cocoa_notification_backend_class_init (GCocoaNotificationBackendClass *klass)
272 {
273 GNotificationBackendClass *backend_class = G_NOTIFICATION_BACKEND_CLASS (klass);
274  
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;
278 }