1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4
5 #include <Elementary.h>
6
7 #include "elm_priv.h"
8
9 #include "elm_sys_notify_interface_eo.h"
10 #include "elm_sys_notify_eo.h"
11 #include "elm_sys_notify_dbus_eo.h"
12 #include "elm_sys_notify_dbus_eo.legacy.h"
13
14 #define MY_CLASS ELM_SYS_NOTIFY_DBUS_CLASS
15
16 #define OBJ "/org/freedesktop/Notifications"
17 #define BUS "org.freedesktop.Notifications"
18 #define INTERFACE "org.freedesktop.Notifications"
19
20 static Eldbus_Connection *_elm_sysnotif_conn = NULL;
21 static Eldbus_Object *_elm_sysnotif_obj = NULL;
22 static Eldbus_Proxy *_elm_sysnotif_proxy = NULL;
23
24 static Eina_Bool _has_markup = EINA_FALSE;
25
26 typedef struct _Elm_Sys_Notify_Send_Data
27 {
28 Elm_Sys_Notify_Send_Cb cb;
29 const void *data;
30 } Elm_Sys_Notify_Send_Data;
31
32 static void
_elm_sys_notify_marshal_dict_byte(Eldbus_Message_Iter * array,const char * key,const char value)33 _elm_sys_notify_marshal_dict_byte(Eldbus_Message_Iter *array,
34 const char *key,
35 const char value)
36 {
37 Eldbus_Message_Iter *var, *entry;
38
39 eldbus_message_iter_arguments_append(array, "{sv}", &entry);
40 eldbus_message_iter_basic_append(entry, 's', key);
41
42 var = eldbus_message_iter_container_new(entry, 'v', "y");
43 eldbus_message_iter_basic_append(var, 'y', value);
44 eldbus_message_iter_container_close(entry, var);
45 eldbus_message_iter_container_close(array, entry);
46 }
47
48 static void
_elm_sys_notify_marshal_dict_string(Eldbus_Message_Iter * array,const char * key,const char * value)49 _elm_sys_notify_marshal_dict_string(Eldbus_Message_Iter *array,
50 const char *key,
51 const char *value)
52 {
53 Eldbus_Message_Iter *var, *entry;
54
55 eldbus_message_iter_arguments_append(array, "{sv}", &entry);
56 eldbus_message_iter_basic_append(entry, 's', key);
57
58 var = eldbus_message_iter_container_new(entry, 'v', "s");
59 eldbus_message_iter_basic_append(var, 's', value);
60 eldbus_message_iter_container_close(entry, var);
61 eldbus_message_iter_container_close(array, entry);
62 }
63
64 static void
_get_capabilities_cb(void * data EINA_UNUSED,const Eldbus_Message * msg,Eldbus_Pending * pending EINA_UNUSED)65 _get_capabilities_cb(void *data EINA_UNUSED,
66 const Eldbus_Message *msg,
67 Eldbus_Pending *pending EINA_UNUSED)
68 {
69 char *val;
70 Eldbus_Message_Iter *arr;
71
72 if (eldbus_message_error_get(msg, NULL, NULL) ||
73 !eldbus_message_arguments_get(msg, "as", &arr)) goto end;
74
75 while (eldbus_message_iter_get_and_next(arr, 's', &val))
76 if (!strcmp(val, "body-markup"))
77 {
78 _has_markup = EINA_TRUE;
79 return;
80 }
81
82 end:
83 _has_markup = EINA_FALSE;
84 }
85
86 void
_elm_sys_notify_capabilities_get(void)87 _elm_sys_notify_capabilities_get(void)
88 {
89 EINA_SAFETY_ON_NULL_RETURN(_elm_sysnotif_proxy);
90
91 if (!eldbus_proxy_call(_elm_sysnotif_proxy, "GetCapabilities",
92 _get_capabilities_cb, NULL, -1, ""))
93 ERR("Error sending message: "INTERFACE".GetCapabilities.");
94 }
95
96 static void
_close_notification_cb(void * data EINA_UNUSED,const Eldbus_Message * msg,Eldbus_Pending * pending EINA_UNUSED)97 _close_notification_cb(void *data EINA_UNUSED,
98 const Eldbus_Message *msg,
99 Eldbus_Pending *pending EINA_UNUSED)
100 {
101 const char *errname, *errmsg;
102
103 if (eldbus_message_error_get(msg, &errname, &errmsg))
104 {
105 if (errmsg && errmsg[0] == '\0')
106 INF("Notification no longer exists.");
107 else
108 ERR("Eldbus Error: %s %s", errname, errmsg);
109 }
110 }
111
112 EOLIAN static void
_elm_sys_notify_dbus_elm_sys_notify_interface_close(const Eo * obj EINA_UNUSED,void * sd EINA_UNUSED,unsigned int id)113 _elm_sys_notify_dbus_elm_sys_notify_interface_close(const Eo *obj EINA_UNUSED,
114 void *sd EINA_UNUSED,
115 unsigned int id)
116 {
117 EINA_SAFETY_ON_NULL_RETURN(_elm_sysnotif_proxy);
118
119 if (!eldbus_proxy_call(_elm_sysnotif_proxy, "CloseNotification",
120 _close_notification_cb, NULL, -1, "u", id))
121 ERR("Error sending message: "INTERFACE".CloseNotification.");
122 }
123
124 static void
_notify_cb(void * data,const Eldbus_Message * msg,Eldbus_Pending * pending EINA_UNUSED)125 _notify_cb(void *data,
126 const Eldbus_Message *msg,
127 Eldbus_Pending *pending EINA_UNUSED)
128 {
129 const char *errname, *errmsg;
130 Elm_Sys_Notify_Send_Data *d = data;
131 unsigned int id = 0;
132
133 if (eldbus_message_error_get(msg, &errname, &errmsg))
134 ERR("Error: %s %s", errname, errmsg);
135 else if (!eldbus_message_arguments_get(msg, "u", &id))
136 {
137 ERR("Error getting return values of "INTERFACE".Notify.");
138 id = 0;
139 }
140
141 if (d->cb) d->cb((void *)d->data, id);
142 free(d);
143 }
144
145 EOLIAN static void
_elm_sys_notify_dbus_elm_sys_notify_interface_send(const Eo * obj EINA_UNUSED,void * sd EINA_UNUSED,unsigned int replaces_id,const char * icon,const char * summary,const char * body,Elm_Sys_Notify_Urgency urgency,int timeout,Elm_Sys_Notify_Send_Cb cb,const void * cb_data)146 _elm_sys_notify_dbus_elm_sys_notify_interface_send(const Eo *obj EINA_UNUSED,
147 void *sd EINA_UNUSED,
148 unsigned int replaces_id,
149 const char *icon,
150 const char *summary,
151 const char *body,
152 Elm_Sys_Notify_Urgency urgency,
153 int timeout,
154 Elm_Sys_Notify_Send_Cb cb,
155 const void *cb_data)
156 {
157 Eldbus_Message *msg;
158 Eldbus_Message_Iter *iter, *actions, *hints;
159 Elm_Sys_Notify_Send_Data *data;
160 char *body_free = NULL;
161 char *desk_free = NULL;
162 const char *deskentry = elm_app_desktop_entry_get();
163 const char *appname = elm_app_name_get();
164
165 EINA_SAFETY_ON_NULL_RETURN(_elm_sysnotif_proxy);
166
167 data = malloc(sizeof(Elm_Sys_Notify_Send_Data));
168 EINA_SAFETY_ON_NULL_GOTO(data, error);
169 data->cb = cb;
170 data->data = cb_data;
171
172 if (!icon) icon = "";
173 if (!summary) summary = "";
174 if (!body)
175 body = "";
176 else if (!_has_markup)
177 body = body_free = elm_entry_markup_to_utf8(body);
178
179 msg = eldbus_proxy_method_call_new(_elm_sysnotif_proxy, "Notify");
180
181 iter = eldbus_message_iter_get(msg);
182 eldbus_message_iter_arguments_append(iter, "susssas", appname, replaces_id,
183 icon, summary, body, &actions);
184 /* actions */
185 eldbus_message_iter_container_close(iter, actions);
186
187 /* hints */
188 eldbus_message_iter_arguments_append(iter, "a{sv}", &hints);
189 _elm_sys_notify_marshal_dict_byte(hints, "urgency", (char) urgency);
190
191 if (strcmp(deskentry, ""))
192 {
193 deskentry = ecore_file_file_get(deskentry);
194 deskentry = desk_free = ecore_file_strip_ext(deskentry);
195 _elm_sys_notify_marshal_dict_string(hints, "desktop_entry", deskentry);
196 }
197 eldbus_message_iter_container_close(iter, hints);
198
199 /* timeout */
200 eldbus_message_iter_arguments_append(iter, "i", timeout);
201
202 eldbus_proxy_send(_elm_sysnotif_proxy, msg, _notify_cb, data, -1);
203 free(desk_free);
204 free(body_free);
205 return;
206
207 error:
208 if (cb) cb((void *)cb_data, 0);
209 }
210
211 EOLIAN static void
_elm_sys_notify_dbus_elm_sys_notify_interface_simple_send(const Eo * obj,void * sd,const char * icon,const char * summary,const char * body)212 _elm_sys_notify_dbus_elm_sys_notify_interface_simple_send(const Eo *obj,
213 void *sd,
214 const char *icon,
215 const char *summary,
216 const char *body)
217 {
218 _elm_sys_notify_dbus_elm_sys_notify_interface_send(obj, sd,
219 0, icon, summary, body,
220 ELM_SYS_NOTIFY_URGENCY_NORMAL,
221 -1, NULL, NULL);
222 }
223
224 static void
_on_notification_closed(void * data EINA_UNUSED,const Eldbus_Message * msg)225 _on_notification_closed(void *data EINA_UNUSED,
226 const Eldbus_Message *msg)
227 {
228 const char *errname;
229 const char *errmsg;
230 Elm_Sys_Notify_Notification_Closed *d;
231
232 if (eldbus_message_error_get(msg, &errname, &errmsg))
233 {
234 ERR("Eldbus Error: %s %s", errname, errmsg);
235 return;
236 }
237
238 d = malloc(sizeof(*d));
239
240 if (!eldbus_message_arguments_get(msg, "uu", &(d->id), &(d->reason)))
241 {
242 ERR("Error processing signal: "INTERFACE".NotificationClosed.");
243 goto cleanup;
244 }
245
246 if (!ecore_event_add(ELM_EVENT_SYS_NOTIFY_NOTIFICATION_CLOSED, d,
247 NULL, NULL)) goto cleanup;
248
249 return;
250
251 cleanup:
252 free(d);
253 }
254
255 static void
_ev_action_invoked_free(void * data EINA_UNUSED,void * ev_data)256 _ev_action_invoked_free(void *data EINA_UNUSED,
257 void *ev_data)
258 {
259 Elm_Sys_Notify_Action_Invoked *d = ev_data;
260
261 free(d->action_key);
262 free(d);
263 }
264
265 static void
_on_action_invoked(void * data EINA_UNUSED,const Eldbus_Message * msg)266 _on_action_invoked(void *data EINA_UNUSED,
267 const Eldbus_Message *msg)
268 {
269 const char *errname;
270 const char *aux;
271
272 Elm_Sys_Notify_Action_Invoked *d;
273
274 if (eldbus_message_error_get(msg, &errname, &aux))
275 {
276 ERR("Eldbus Error: %s %s", errname, aux);
277 return;
278 }
279
280 d = calloc(1, sizeof(*d));
281 if (!d)
282 {
283 ERR("Fail to allocate memory");
284 return;
285 }
286
287 if (!eldbus_message_arguments_get(msg, "us", &(d->id), &aux))
288 {
289 ERR("Error processing signal: "INTERFACE".ActionInvoked.");
290 goto cleanup;
291 }
292
293 d->action_key = strdup(aux);
294
295 if (!ecore_event_add(ELM_EVENT_SYS_NOTIFY_ACTION_INVOKED, d,
296 _ev_action_invoked_free, NULL)) goto cleanup;
297
298 return;
299
300 cleanup:
301 free(d->action_key);
302 free(d);
303 }
304
305 static void
_release(void)306 _release(void)
307 {
308 if (_elm_sysnotif_proxy)
309 {
310 eldbus_proxy_unref(_elm_sysnotif_proxy);
311 _elm_sysnotif_proxy = NULL;
312 }
313
314 if (_elm_sysnotif_obj)
315 {
316 eldbus_object_unref(_elm_sysnotif_obj);
317 _elm_sysnotif_obj = NULL;
318 }
319 }
320
321 static void
_update(void)322 _update(void)
323 {
324 _release();
325 _elm_sysnotif_obj = eldbus_object_get(_elm_sysnotif_conn, BUS, OBJ);
326 _elm_sysnotif_proxy = eldbus_proxy_get(_elm_sysnotif_obj, INTERFACE);
327 _elm_sys_notify_capabilities_get();
328
329 eldbus_proxy_signal_handler_add(_elm_sysnotif_proxy, "NotificationClosed",
330 _on_notification_closed, NULL);
331
332 eldbus_proxy_signal_handler_add(_elm_sysnotif_proxy, "ActionInvoked",
333 _on_action_invoked, NULL);
334 }
335
336 static void
_name_owner_get_cb(void * data EINA_UNUSED,const Eldbus_Message * msg,Eldbus_Pending * pending EINA_UNUSED)337 _name_owner_get_cb(void *data EINA_UNUSED,
338 const Eldbus_Message *msg,
339 Eldbus_Pending *pending EINA_UNUSED)
340 {
341 const char *errname, *errmsg;
342
343 if (eldbus_message_error_get(msg, &errname, &errmsg))
344 ERR("Eldbus Error: %s %s", errname, errmsg);
345 else
346 _update();
347 }
348
349 static void
_name_owner_changed_cb(void * data EINA_UNUSED,const char * bus EINA_UNUSED,const char * old_id EINA_UNUSED,const char * new_id)350 _name_owner_changed_cb(void *data EINA_UNUSED,
351 const char *bus EINA_UNUSED,
352 const char *old_id EINA_UNUSED,
353 const char *new_id)
354 {
355 if ((!new_id) || (*new_id == '\0'))
356 _release();
357 else
358 _update();
359 }
360
361 EOLIAN static Efl_Object *
_elm_sys_notify_dbus_efl_object_constructor(Eo * obj,void * sd EINA_UNUSED)362 _elm_sys_notify_dbus_efl_object_constructor(Eo *obj,
363 void *sd EINA_UNUSED)
364 {
365 /* Don't create the same object twice (singleton) */
366 if (!_elm_sysnotif_conn)
367 {
368 if (!elm_need_eldbus()) return NULL;
369
370 _elm_sysnotif_conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION);
371 if (!_elm_sysnotif_conn) return NULL;
372
373 eldbus_name_owner_changed_callback_add(_elm_sysnotif_conn, BUS,
374 _name_owner_changed_cb, NULL,
375 EINA_FALSE);
376
377 eldbus_name_owner_get(_elm_sysnotif_conn, BUS, _name_owner_get_cb, NULL);
378
379 obj = efl_constructor(efl_super(obj, MY_CLASS));
380 return obj;
381 }
382
383 ERR("Elm.Sys_Notify.Dbus is a singleton. It has already been created");
384 return NULL;
385 }
386
387 EOLIAN static void
_elm_sys_notify_dbus_efl_object_destructor(Eo * obj,void * sd EINA_UNUSED)388 _elm_sys_notify_dbus_efl_object_destructor(Eo *obj,
389 void *sd EINA_UNUSED)
390 {
391 _release();
392
393 eldbus_connection_unref(_elm_sysnotif_conn);
394 _elm_sysnotif_conn = NULL;
395 efl_destructor(efl_super(obj, MY_CLASS));
396 }
397
398
399 #include "elm_sys_notify_dbus_eo.c"
400
401