summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean Guyomarc'h <jean.guyomarch@gmail.com>2015-08-09 22:07:15 +0200
committerJean Guyomarc'h <jean.guyomarch@gmail.com>2015-08-09 22:07:15 +0200
commit96ff993a04c6514d4e736cc9cb97bb22283a0688 (patch)
tree0a048a3ab566e6d5b404b004771d3354b69dcb63
parent9a44777481eb2426d334209631c0ff97d83c0cb0 (diff)
downloadelementary-devs/jayji/sys_notify.tar.gz
sys_notify: support several notification serversdevs/jayji/sys_notify
An Eo class Elm.Sys_Notify acts as a manager of notification servers. A manager registers and unregisters notification servers. Notification servers implement the Elm.Sys_Notify_Interface which allows to send and close notifications. Currently, only the DBus server is implemented (legacy code). Even though there are many changes in the code, there should be no API nor ABI breaks.
-rw-r--r--src/lib/Makefile.am7
-rw-r--r--src/lib/elm_sys_notify.c513
-rw-r--r--src/lib/elm_sys_notify.eo90
-rw-r--r--src/lib/elm_sys_notify.h92
-rw-r--r--src/lib/elm_sys_notify_dbus.c398
-rw-r--r--src/lib/elm_sys_notify_dbus.eo14
-rw-r--r--src/lib/elm_sys_notify_interface.c9
-rw-r--r--src/lib/elm_sys_notify_interface.eo66
8 files changed, 827 insertions, 362 deletions
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 41f5ec303..f819785b4 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -345,6 +345,8 @@ elm_systray_eo.h \
elm_systray_common.h \
elm_systray_watcher.h \
elm_sys_notify.h \
+elm_sys_notify.eo.h \
+elm_sys_notify_dbus.eo.h \
elm_table.h \
elm_table_eo.h \
elm_table_legacy.h \
@@ -479,7 +481,9 @@ elm_spinner.c \
elm_store.c \
elm_systray.c \
elm_systray_watcher.c \
+elm_sys_notify_interface.c \
elm_sys_notify.c \
+elm_sys_notify_dbus.c \
elm_table.c \
elm_theme.c \
elm_thumb.c \
@@ -604,6 +608,9 @@ elm_separator.eo \
elm_slider.eo \
elm_slideshow.eo \
elm_spinner.eo \
+elm_sys_notify_interface.eo \
+elm_sys_notify.eo \
+elm_sys_notify_dbus.eo \
elm_systray.eo \
elm_table.eo \
elm_thumb.eo \
diff --git a/src/lib/elm_sys_notify.c b/src/lib/elm_sys_notify.c
index 23c936f2f..87536b806 100644
--- a/src/lib/elm_sys_notify.c
+++ b/src/lib/elm_sys_notify.c
@@ -6,372 +6,291 @@
#include "elm_priv.h"
-#define OBJ "/org/freedesktop/Notifications"
-#define BUS "org.freedesktop.Notifications"
-#define INTERFACE "org.freedesktop.Notifications"
+#include "elm_sys_notify_dbus.eo.h"
+#include "elm_sys_notify_dbus.eo.legacy.h"
+
+#define MY_CLASS ELM_SYS_NOTIFY_CLASS
+
+#define MY_CLASS_NAME "Elm_Sys_Notify"
+#define MY_CLASS_NAME_LEGACY "elm_sys_notify"
EAPI int ELM_EVENT_SYS_NOTIFY_NOTIFICATION_CLOSED = 0;
EAPI int ELM_EVENT_SYS_NOTIFY_ACTION_INVOKED = 0;
-static Eina_Bool _elm_need_sys_notify = EINA_FALSE;
+typedef const Eo_Class *(*Class_Get_Func)(void);
-static Eldbus_Connection *_elm_sysnotif_conn = NULL;
-static Eldbus_Object *_elm_sysnotif_obj = NULL;
-static Eldbus_Proxy *_elm_sysnotif_proxy = NULL;
+static Elm_Sys_Notify *_singleton = NULL;
-static Eina_Bool _has_markup = EINA_FALSE;
+/*
+ * Registration of notification servers is done UNIQUELY
+ * in the two structures below.
+ * 1) ALWAYS add a SRV_XXX before __SRV_LAST
+ * 2) copy the #if ... #else ... #endif with the appropriate class
+ * getter (generated by Eolian) or NULL when unsupported
+ *
+ * The rest of the code relies on the Srv enum and _class_getters
+ * to register/unregister notification servers.
+ */
-typedef struct _Elm_Sys_Notify_Send_Data
+typedef enum
{
- Elm_Sys_Notify_Send_Cb cb;
- const void *data;
-} Elm_Sys_Notify_Send_Data;
-
-static void
-_elm_sys_notify_marshal_dict_byte(Eldbus_Message_Iter *array,
- const char *key,
- const char value)
+ SRV_DBUS = 0,
+ __SRV_LAST /* Sentinel */
+} Srv;
+
+static Class_Get_Func _class_getters[__SRV_LAST] =
{
- Eldbus_Message_Iter *var, *entry;
+#ifdef ELM_SYS_NOTIFY_DBUS_CLASS
+ [SRV_DBUS] = elm_sys_notify_dbus_class_get
+#else
+ [SRV_DBUS] = NULL
+#endif
+};
- eldbus_message_iter_arguments_append(array, "{sv}", &entry);
- eldbus_message_iter_basic_append(entry, 's', key);
- var = eldbus_message_iter_container_new(entry, 'v', "y");
- eldbus_message_iter_basic_append(var, 'y', value);
- eldbus_message_iter_container_close(entry, var);
- eldbus_message_iter_container_close(array, entry);
-}
-static void
-_elm_sys_notify_marshal_dict_string(Eldbus_Message_Iter *array,
- const char *key,
- const char *value)
+typedef struct
{
- Eldbus_Message_Iter *var, *entry;
+ Eo *servers[__SRV_LAST];
+} Elm_Sys_Notify_Data;
- eldbus_message_iter_arguments_append(array, "{sv}", &entry);
- eldbus_message_iter_basic_append(entry, 's', key);
+/*============================================================================*
+ * Constructor/Destructor - Singleton setup *
+ *============================================================================*/
- var = eldbus_message_iter_container_new(entry, 'v', "s");
- eldbus_message_iter_basic_append(var, 's', value);
- eldbus_message_iter_container_close(entry, var);
- eldbus_message_iter_container_close(array, entry);
-}
-
-static void
-_get_capabilities_cb(void *data EINA_UNUSED,
- const Eldbus_Message *msg,
- Eldbus_Pending *pending EINA_UNUSED)
+EOLIAN static Eo_Base *
+_elm_sys_notify_eo_base_constructor(Eo *obj,
+ Elm_Sys_Notify_Data *sd EINA_UNUSED)
{
- char *val;
- Eldbus_Message_Iter *arr;
-
- if (eldbus_message_error_get(msg, NULL, NULL) ||
- !eldbus_message_arguments_get(msg, "as", &arr)) goto end;
+ if (_singleton != NULL)
+ {
+ ERR("Attempted to create another system notification manager");
+ return NULL;
+ }
- while (eldbus_message_iter_get_and_next(arr, 's', &val))
- if (!strcmp(val, "body-markup"))
- {
- _has_markup = EINA_TRUE;
- return;
- }
+ obj = eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+ _singleton = obj;
-end:
- _has_markup = EINA_FALSE;
+ return obj;
}
-void
-_elm_sys_notify_capabilities_get(void)
+EOLIAN static void
+_elm_sys_notify_eo_base_destructor(Eo *obj,
+ Elm_Sys_Notify_Data *sd EINA_UNUSED)
{
- EINA_SAFETY_ON_NULL_RETURN(_elm_sysnotif_proxy);
-
- if (!eldbus_proxy_call(_elm_sysnotif_proxy, "GetCapabilities",
- _get_capabilities_cb, NULL, -1, ""))
- ERR("Error sending message: "INTERFACE".GetCapabilities.");
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+ _singleton = NULL;
}
-static void
-_close_notification_cb(void *data EINA_UNUSED,
- const Eldbus_Message *msg,
- Eldbus_Pending *pending EINA_UNUSED)
-{
- const char *errname, *errmsg;
-
- if (eldbus_message_error_get(msg, &errname, &errmsg))
- {
- if (errmsg && errmsg[0] == '\0')
- INF("Notification no longer exists.");
- else
- ERR("Eldbus Error: %s %s", errname, errmsg);
- }
-}
-EAPI void
-elm_sys_notify_close(unsigned int id)
+/*============================================================================*
+ * Notification Interface *
+ *============================================================================*/
+
+EOLIAN static void
+_elm_sys_notify_elm_sys_notify_interface_send(const Eo *obj EINA_UNUSED,
+ Elm_Sys_Notify_Data *sd,
+ 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)
{
- EINA_SAFETY_ON_FALSE_RETURN(_elm_need_sys_notify);
- EINA_SAFETY_ON_NULL_RETURN(_elm_sysnotif_proxy);
-
- if (!eldbus_proxy_call(_elm_sysnotif_proxy, "CloseNotification",
- _close_notification_cb, NULL, -1, "u", id))
- ERR("Error sending message: "INTERFACE".CloseNotification.");
+ Srv i;
+
+ /* Propagate to all registered servers */
+ for (i = SRV_DBUS; i < __SRV_LAST; ++i)
+ if (sd->servers[i])
+ eo_do(sd->servers[i],
+ elm_obj_sys_notify_interface_send(replaces_id,
+ icon, summary, body,
+ urgency, timeout,
+ cb, cb_data));
}
-static void
-_notify_cb(void *data,
- const Eldbus_Message *msg,
- Eldbus_Pending *pending EINA_UNUSED)
+EOLIAN static void
+_elm_sys_notify_elm_sys_notify_interface_simple_send(const Eo *obj EINA_UNUSED,
+ Elm_Sys_Notify_Data *sd,
+ const char *icon,
+ const char *summary,
+ const char *body)
{
- const char *errname, *errmsg;
- Elm_Sys_Notify_Send_Data *d = data;
- unsigned int id = 0;
+ Srv i;
- if (eldbus_message_error_get(msg, &errname, &errmsg))
- ERR("Error: %s %s", errname, errmsg);
- else if (!eldbus_message_arguments_get(msg, "u", &id))
- {
- ERR("Error getting return values of "INTERFACE".Notify.");
- id = 0;
- }
-
- if (d->cb) d->cb((void *)d->data, id);
- free(d);
+ /* Propagate to all registered servers */
+ for (i = SRV_DBUS; i < __SRV_LAST; ++i)
+ if (sd->servers[i])
+ eo_do(sd->servers[i],
+ elm_obj_sys_notify_interface_simple_send(icon, summary, body));
}
-EAPI void
-elm_sys_notify_send(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)
+EOLIAN static void
+_elm_sys_notify_elm_sys_notify_interface_close(const Eo *obj EINA_UNUSED,
+ Elm_Sys_Notify_Data *sd,
+ unsigned int id)
{
- Eldbus_Message *msg;
- Eldbus_Message_Iter *iter, *actions, *hints;
- Elm_Sys_Notify_Send_Data *data;
- char *body_free = NULL;
- char *desk_free = NULL;
- const char *deskentry = elm_app_desktop_entry_get();
- const char *appname = elm_app_name_get();
-
- EINA_SAFETY_ON_FALSE_RETURN(_elm_need_sys_notify);
- EINA_SAFETY_ON_NULL_RETURN(_elm_sysnotif_proxy);
-
- data = malloc(sizeof(Elm_Sys_Notify_Send_Data));
- EINA_SAFETY_ON_NULL_GOTO(data, error);
- data->cb = cb;
- data->data = cb_data;
-
- if (!icon) icon = "";
- if (!summary) summary = "";
- if (!body)
- body = "";
- else if (!_has_markup)
- body = body_free = elm_entry_markup_to_utf8(body);
-
- msg = eldbus_proxy_method_call_new(_elm_sysnotif_proxy, "Notify");
-
- iter = eldbus_message_iter_get(msg);
- eldbus_message_iter_arguments_append(iter, "susssas", appname, replaces_id,
- icon, summary, body, &actions);
- /* actions */
- eldbus_message_iter_container_close(iter, actions);
-
- /* hints */
- eldbus_message_iter_arguments_append(iter, "a{sv}", &hints);
- _elm_sys_notify_marshal_dict_byte(hints, "urgency", (char) urgency);
-
- if (strcmp(deskentry, ""))
- {
- deskentry = ecore_file_file_get(deskentry);
- deskentry = desk_free = ecore_file_strip_ext(deskentry);
- _elm_sys_notify_marshal_dict_string(hints, "desktop_entry", deskentry);
- }
- eldbus_message_iter_container_close(iter, hints);
+ Srv i;
- /* timeout */
- eldbus_message_iter_arguments_append(iter, "i", timeout);
+ /* Propagate to all registered servers */
+ for (i = SRV_DBUS; i < __SRV_LAST; ++i)
+ if (sd->servers[i])
+ eo_do(sd->servers[i],
+ elm_obj_sys_notify_interface_close(id));
+}
- eldbus_proxy_send(_elm_sysnotif_proxy, msg, _notify_cb, data, -1);
- free(desk_free);
- free(body_free);
- return;
-error:
- if (cb) cb((void *)cb_data, 0);
-}
+/*============================================================================*
+ * Methods *
+ *============================================================================*/
-static void
-_on_notification_closed(void *data EINA_UNUSED,
- const Eldbus_Message *msg)
+EOLIAN static Eina_Bool
+_elm_sys_notify_servers_set(Eo *obj EINA_UNUSED,
+ Elm_Sys_Notify_Data *sd,
+ Elm_Sys_Notify_Server servers)
{
- const char *errname;
- const char *errmsg;
- Elm_Sys_Notify_Notification_Closed *d;
+ Srv i;
+ Class_Get_Func class_get;
- if (eldbus_message_error_get(msg, &errname, &errmsg))
+ /* Update the notification servers */
+ for (i = SRV_DBUS; i < __SRV_LAST; ++i)
{
- ERR("Eldbus Error: %s %s", errname, errmsg);
- return;
+ if (sd->servers[i])
+ {
+ /* Delete if server type is not provided */
+ if (!(servers & (1 << i)))
+ eo_del(sd->servers[i]);
+ }
+ else
+ {
+ /* If server is required, create when nonexistant */
+ if (servers & (1 << i))
+ {
+ class_get = _class_getters[i];
+ if (!class_get)
+ {
+ CRI("Unsupported notification server");
+ return EINA_FALSE;
+ }
+
+ sd->servers[i] = eo_add(class_get(), NULL);
+ if (EINA_UNLIKELY(!(sd->servers[i])))
+ {
+ CRI("Failed to create notification server");
+ return EINA_FALSE;
+ }
+ }
+ }
}
- d = malloc(sizeof(*d));
-
- if (!eldbus_message_arguments_get(msg, "uu", &(d->id), &(d->reason)))
- {
- ERR("Error processing signal: "INTERFACE".NotificationClosed.");
- goto cleanup;
- }
+ return EINA_TRUE;
+}
- if (!ecore_event_add(ELM_EVENT_SYS_NOTIFY_NOTIFICATION_CLOSED, d,
- NULL, NULL)) goto cleanup;
+EOLIAN static Elm_Sys_Notify_Server
+_elm_sys_notify_servers_get(Eo *obj EINA_UNUSED,
+ Elm_Sys_Notify_Data *sd)
+{
+ Elm_Sys_Notify_Server servers = ELM_SYS_NOTIFY_SERVER_NONE;
+ Srv i;
- return;
+ for (i = SRV_DBUS; i < __SRV_LAST; ++i)
+ if (sd->servers[i])
+ servers |= (1 << i);
-cleanup:
- free(d);
+ return servers;
}
-static void
-_ev_action_invoked_free(void *data EINA_UNUSED,
- void *ev_data)
+EOLIAN static Elm_Sys_Notify *
+_elm_sys_notify_singleton_get(Eo *obj EINA_UNUSED,
+ void *sd EINA_UNUSED)
{
- Elm_Sys_Notify_Action_Invoked *d = ev_data;
-
- free(d->action_key);
- free(d);
+ if (!_singleton)
+ _singleton = eo_add(MY_CLASS, NULL);
+ return _singleton;
}
-static void
-_on_action_invoked(void *data EINA_UNUSED,
- const Eldbus_Message *msg)
+EOLIAN static void
+_elm_sys_notify_class_constructor(Eo_Class *klass EINA_UNUSED)
{
- const char *errname;
- const char *aux;
-
- Elm_Sys_Notify_Action_Invoked *d;
-
- if (eldbus_message_error_get(msg, &errname, &aux))
- {
- ERR("Eldbus Error: %s %s", errname, aux);
- return;
- }
-
- d = calloc(1, sizeof(*d));
- if (!d)
- {
- ERR("Fail to allocate memory");
- return;
- }
-
- if (!eldbus_message_arguments_get(msg, "us", &(d->id), &aux))
- {
- ERR("Error processing signal: "INTERFACE".ActionInvoked.");
- goto cleanup;
- }
-
- d->action_key = strdup(aux);
-
- if (!ecore_event_add(ELM_EVENT_SYS_NOTIFY_ACTION_INVOKED, d,
- _ev_action_invoked_free, NULL)) goto cleanup;
+ ELM_EVENT_SYS_NOTIFY_NOTIFICATION_CLOSED = ecore_event_type_new();
+ ELM_EVENT_SYS_NOTIFY_ACTION_INVOKED = ecore_event_type_new();
+}
- return;
+/*============================================================================*
+ * Legacy API *
+ *============================================================================*/
-cleanup:
- free(d->action_key);
- free(d);
+void
+_elm_unneed_sys_notify(void)
+{
+ eo_do(_singleton,
+ elm_obj_sys_notify_servers_set(ELM_SYS_NOTIFY_SERVER_NONE));
+ eo_del(_singleton);
}
-static void
-_release(void)
+EAPI Eina_Bool
+elm_need_sys_notify(void)
{
- if (_elm_sysnotif_proxy)
+ Elm_Sys_Notify_Server servers = ELM_SYS_NOTIFY_SERVER_NONE;
+ Elm_Sys_Notify *manager;
+ Srv i;
+
+ /* In theory, there can be N notification managers, but
+ * in the implementation there will be only one: the
+ * singleton which is initialized here. */
+ manager = elm_sys_notify_singleton_get();
+ if (EINA_UNLIKELY(!manager))
{
- eldbus_proxy_unref(_elm_sysnotif_proxy);
- _elm_sysnotif_proxy = NULL;
+ CRI("Failed to get notification manager");
+ return EINA_FALSE;
}
- if (_elm_sysnotif_obj)
+ /* If servers have alread been configured, this is not the right
+ * function to be called! */
+ if (elm_sys_notify_servers_get(manager) != ELM_SYS_NOTIFY_SERVER_NONE)
{
- eldbus_object_unref(_elm_sysnotif_obj);
- _elm_sysnotif_obj = NULL;
+ ERR("Notification servers have already been configured. "
+ "Use elm_sys_notify_servers_set() instead.");
+ return EINA_FALSE;
}
-}
-static void
-_update(void)
-{
- _release();
- _elm_sysnotif_obj = eldbus_object_get(_elm_sysnotif_conn, BUS, OBJ);
- _elm_sysnotif_proxy = eldbus_proxy_get(_elm_sysnotif_obj, INTERFACE);
- _elm_sys_notify_capabilities_get();
-
- eldbus_proxy_signal_handler_add(_elm_sysnotif_proxy, "NotificationClosed",
- _on_notification_closed, NULL);
+ /* Register available notification servers */
+ for (i = SRV_DBUS; i < __SRV_LAST; ++i)
+ if (_class_getters[i])
+ servers |= (1 << i);
- eldbus_proxy_signal_handler_add(_elm_sysnotif_proxy, "ActionInvoked",
- _on_action_invoked, NULL);
-}
-
-static void
-_name_owner_get_cb(void *data EINA_UNUSED,
- const Eldbus_Message *msg,
- Eldbus_Pending *pending EINA_UNUSED)
-{
- const char *errname, *errmsg;
+ /* If no server are available, don't even bother... */
+ if (servers == ELM_SYS_NOTIFY_SERVER_NONE)
+ return EINA_FALSE;
- if (eldbus_message_error_get(msg, &errname, &errmsg))
- ERR("Eldbus Error: %s %s", errname, errmsg);
- else
- _update();
+ return elm_sys_notify_servers_set(manager, servers);
}
-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)
+EAPI void
+elm_sys_notify_send(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)
{
- if ((!new_id) || (*new_id == '\0'))
- _release();
- else
- _update();
+ eo_do(_singleton,
+ elm_obj_sys_notify_interface_send(replaces_id,
+ icon, summary, body,
+ urgency, timeout,
+ cb, cb_data));
}
-EAPI Eina_Bool
-elm_need_sys_notify(void)
+EAPI void
+elm_sys_notify_close(unsigned int id)
{
- if (_elm_need_sys_notify) return EINA_TRUE;
-
- if (!elm_need_eldbus()) return EINA_FALSE;
-
- if (!ELM_EVENT_SYS_NOTIFY_NOTIFICATION_CLOSED)
- ELM_EVENT_SYS_NOTIFY_NOTIFICATION_CLOSED = ecore_event_type_new();
-
- if (!ELM_EVENT_SYS_NOTIFY_ACTION_INVOKED)
- ELM_EVENT_SYS_NOTIFY_ACTION_INVOKED = ecore_event_type_new();
-
- _elm_sysnotif_conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION);
-
- eldbus_name_owner_changed_callback_add(_elm_sysnotif_conn, BUS,
- _name_owner_changed_cb, NULL,
- EINA_FALSE);
-
- eldbus_name_owner_get(_elm_sysnotif_conn, BUS, _name_owner_get_cb, NULL);
-
- _elm_need_sys_notify = EINA_TRUE;
-
- return EINA_TRUE;
+ eo_do(_singleton,
+ elm_obj_sys_notify_interface_close(id));
}
-void
-_elm_unneed_sys_notify(void)
-{
- if (!_elm_need_sys_notify) return;
-
- _elm_need_sys_notify = EINA_FALSE;
+#include "elm_sys_notify.eo.c"
- _release();
-
- eldbus_connection_unref(_elm_sysnotif_conn);
- _elm_sysnotif_conn = NULL;
-}
diff --git a/src/lib/elm_sys_notify.eo b/src/lib/elm_sys_notify.eo
new file mode 100644
index 000000000..7eb0df2df
--- /dev/null
+++ b/src/lib/elm_sys_notify.eo
@@ -0,0 +1,90 @@
+enum Elm.Sys_Notify.Server
+{
+ none = 0, [[No notificationserver (disables notifications)]]
+ dbus = 1 << 0 [[Use DBus as a notification server]]
+}
+
+enum Elm.Sys_Notify.Closed_Reason
+{
+ [[The reason the notification was closed
+
+ @since 1.8
+ ]]
+
+ legacy: elm_sys_notify_closed;
+
+ expired, [[The notification expired]]
+ dismissed, [[The notification was dismissed by the user]]
+ requested, [[The notification was closed by a call to CloseNotification method]]
+ undefined [[Undefined/reserved reasons]]
+}
+
+struct Elm.Sys_Notify.Notification_Closed
+{
+ [[Data on event when notification closed is emitted
+
+ @since 1.8
+ ]]
+ id: uint; [[ID of the notification]]
+ reason: Elm.Sys_Notify.Closed_Reason; [[The reason the notification was closed]]
+}
+
+struct Elm.Sys_Notify.Action_Invoked
+{
+ [[Data on event when the action invoked is emitted
+
+ @since 1.8
+ ]]
+ id: uint; [[ID of the notification]]
+ action_key: char *; [[The key of the action invoked. These match the
+ keys sent over in the list of actions]]
+}
+
+class Elm.Sys_Notify (Eo.Base, Elm.Sys_Notify_Interface)
+{
+ legacy_prefix: elm_sys_notify;
+ eo_prefix: elm_obj_sys_notify;
+
+ methods {
+ @property servers {
+ get {
+ [[Get the notification servers that have been registered
+
+ @since 1.16
+ ]]
+ }
+ set {
+ [[Set the notifications server to be used.
+
+ Note: This is an advanced function that should be used only to
+ fullfill very specific purposes. Use elm_need_sys_notify()
+ which activates the default available notification
+ servers.
+ ]]
+ return: bool; [[$true on success, $false on failure]]
+ }
+ values {
+ servers: Elm.Sys_Notify.Server; [[Binary mask of servers to enable.
+ If a server is not present in the binary mask but was previously
+ registered, it will be unregistered.]]
+ }
+ }
+
+ singleton_get @class {
+ [[Returns the singleton instance of the notification manager
+ Elm.Sys_Notify. It is initialized upon the first call of this
+ function]]
+ return: Elm.Sys_Notify *; [[The unique notification manager]]
+ }
+ }
+
+ implements {
+ class.constructor;
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ Elm.Sys_Notify_Interface.send;
+ Elm.Sys_Notify_Interface.simple_send;
+ Elm.Sys_Notify_Interface.close;
+ }
+}
+
diff --git a/src/lib/elm_sys_notify.h b/src/lib/elm_sys_notify.h
index aeff5a006..4534838ca 100644
--- a/src/lib/elm_sys_notify.h
+++ b/src/lib/elm_sys_notify.h
@@ -1,67 +1,25 @@
#ifndef ELM_SYS_NOTIFY_H
#define ELM_SYS_NOTIFY_H
-/**
- * The reason the notification was closed
- *
- * @since 1.8
- */
-typedef enum _Elm_Sys_Notify_Closed_Reason
-{
- ELM_SYS_NOTIFY_CLOSED_EXPIRED, /** The notification expired. */
- ELM_SYS_NOTIFY_CLOSED_DISMISSED, /** The notification was dismissed by the user. */
- ELM_SYS_NOTIFY_CLOSED_REQUESTED, /** The notification was closed by a call to CloseNotification method. */
- ELM_SYS_NOTIFY_CLOSED_UNDEFINED /** Undefined/reserved reasons. */
-} Elm_Sys_Notify_Closed_Reason;
-
-/**
- * Urgency levels of a notification
- *
- * @see elm_sys_notify_send()
- *
- * @since 1.8
- */
-typedef enum _Elm_Sys_Notify_Urgency
-{
- ELM_SYS_NOTIFY_URGENCY_LOW,
- ELM_SYS_NOTIFY_URGENCY_NORMAL,
- ELM_SYS_NOTIFY_URGENCY_CRITICAL
-} Elm_Sys_Notify_Urgency;
-
typedef void (*Elm_Sys_Notify_Send_Cb)(void *data, unsigned int id);
+#include "elm_sys_notify_interface.eo.h"
+#include "elm_sys_notify_interface.eo.legacy.h"
+#include "elm_sys_notify.eo.h"
+#include "elm_sys_notify.eo.legacy.h"
+
/**
* Emitted when the signal NotificationClosed is received.
+ * @since 1.8
*/
EAPI extern int ELM_EVENT_SYS_NOTIFY_NOTIFICATION_CLOSED;
/**
* Emitted when the signal ActionInvoked is received.
- */
-EAPI extern int ELM_EVENT_SYS_NOTIFY_ACTION_INVOKED; /**< A Action has been invoked. */
-
-/**
- * Data on event when Notification Closed is emitted.
- *
* @since 1.8
*/
-typedef struct _Elm_Sys_Notify_Notification_Closed
-{
- unsigned int id; /**< ID of the notification. */
- Elm_Sys_Notify_Closed_Reason reason; /**< The Reason the notification was closed. */
-} Elm_Sys_Notify_Notification_Closed;
-
+EAPI extern int ELM_EVENT_SYS_NOTIFY_ACTION_INVOKED; /**< A Action has been invoked. */
-/**
- * Data on event when Action Invoked is emitted.
- *
- * @since 1.8
- */
-typedef struct _Elm_Sys_Notify_Action_Invoked
-{
- unsigned int id; /**< ID of the notification. */
- char *action_key; /**< The key of the action invoked. These match the keys sent over in the list of actions. */
-} Elm_Sys_Notify_Action_Invoked;
/**
* @def elm_sys_notify_simple_send
@@ -82,22 +40,9 @@ typedef struct _Elm_Sys_Notify_Action_Invoked
-1, NULL, NULL)
/**
- * Causes a notification to be forcefully closed and removed from the user's
- * view. It can be used, for example, in the event that what the notification
- * pertains to is no longer relevant, or to cancel a notification * with no
- * expiration time.
- *
- * @param id Notification id
- *
- * @note If the notification no longer exists,
- * an empty D-BUS Error message is sent back.
- *
- * @since 1.8
- */
-EAPI void elm_sys_notify_close(unsigned int id);
-
-/**
- * Sends a notification to the notification server.
+ * Sends a notification to the notification servers that have
+ * been registered by elm_need_sys_notify() or
+ * elm_sys_notify_servers_set().
*
* @param replaces_id Notification ID that this notification replaces.
* The value 0 means a new notification.
@@ -120,4 +65,21 @@ EAPI void elm_sys_notify_send(unsigned int replaces_id,
int timeout,
Elm_Sys_Notify_Send_Cb cb,
const void *cb_data);
+
+/**
+ * Causes a notification to be forcefully closed and removed from the user's
+ * view. It can be used, for example, in the event that what the notification
+ * pertains to is no longer relevant, or to cancel a notification * with no
+ * expiration time.
+ *
+ * @param id Notification id
+ *
+ * @note If the notification no longer exists,
+ * an empty D-BUS Error message is sent back.
+ *
+ * @since 1.8
+ */
+EAPI void elm_sys_notify_close(unsigned int id);
+
#endif
+
diff --git a/src/lib/elm_sys_notify_dbus.c b/src/lib/elm_sys_notify_dbus.c
new file mode 100644
index 000000000..bd0fa1e05
--- /dev/null
+++ b/src/lib/elm_sys_notify_dbus.c
@@ -0,0 +1,398 @@
+#ifdef HAVE_CONFIG_H
+# include "elementary_config.h"
+#endif
+
+#include <Elementary.h>
+
+#include "elm_priv.h"
+
+#include "elm_sys_notify_dbus.eo.h"
+#include "elm_sys_notify_dbus.eo.legacy.h"
+
+#define MY_CLASS ELM_SYS_NOTIFY_DBUS_CLASS
+
+#define OBJ "/org/freedesktop/Notifications"
+#define BUS "org.freedesktop.Notifications"
+#define INTERFACE "org.freedesktop.Notifications"
+
+static Eldbus_Connection *_elm_sysnotif_conn = NULL;
+static Eldbus_Object *_elm_sysnotif_obj = NULL;
+static Eldbus_Proxy *_elm_sysnotif_proxy = NULL;
+
+static Eina_Bool _has_markup = EINA_FALSE;
+
+typedef struct _Elm_Sys_Notify_Send_Data
+{
+ Elm_Sys_Notify_Send_Cb cb;
+ const void *data;
+} Elm_Sys_Notify_Send_Data;
+
+static void
+_elm_sys_notify_marshal_dict_byte(Eldbus_Message_Iter *array,
+ const char *key,
+ const char value)
+{
+ Eldbus_Message_Iter *var, *entry;
+
+ eldbus_message_iter_arguments_append(array, "{sv}", &entry);
+ eldbus_message_iter_basic_append(entry, 's', key);
+
+ var = eldbus_message_iter_container_new(entry, 'v', "y");
+ eldbus_message_iter_basic_append(var, 'y', value);
+ eldbus_message_iter_container_close(entry, var);
+ eldbus_message_iter_container_close(array, entry);
+}
+
+static void
+_elm_sys_notify_marshal_dict_string(Eldbus_Message_Iter *array,
+ const char *key,
+ const char *value)
+{
+ Eldbus_Message_Iter *var, *entry;
+
+ eldbus_message_iter_arguments_append(array, "{sv}", &entry);
+ eldbus_message_iter_basic_append(entry, 's', key);
+
+ var = eldbus_message_iter_container_new(entry, 'v', "s");
+ eldbus_message_iter_basic_append(var, 's', value);
+ eldbus_message_iter_container_close(entry, var);
+ eldbus_message_iter_container_close(array, entry);
+}
+
+static void
+_get_capabilities_cb(void *data EINA_UNUSED,
+ const Eldbus_Message *msg,
+ Eldbus_Pending *pending EINA_UNUSED)
+{
+ char *val;
+ Eldbus_Message_Iter *arr;
+
+ if (eldbus_message_error_get(msg, NULL, NULL) ||
+ !eldbus_message_arguments_get(msg, "as", &arr)) goto end;
+
+ while (eldbus_message_iter_get_and_next(arr, 's', &val))
+ if (!strcmp(val, "body-markup"))
+ {
+ _has_markup = EINA_TRUE;
+ return;
+ }
+
+end:
+ _has_markup = EINA_FALSE;
+}
+
+void
+_elm_sys_notify_capabilities_get(void)
+{
+ EINA_SAFETY_ON_NULL_RETURN(_elm_sysnotif_proxy);
+
+ if (!eldbus_proxy_call(_elm_sysnotif_proxy, "GetCapabilities",
+ _get_capabilities_cb, NULL, -1, ""))
+ ERR("Error sending message: "INTERFACE".GetCapabilities.");
+}
+
+static void
+_close_notification_cb(void *data EINA_UNUSED,
+ const Eldbus_Message *msg,
+ Eldbus_Pending *pending EINA_UNUSED)
+{
+ const char *errname, *errmsg;
+
+ if (eldbus_message_error_get(msg, &errname, &errmsg))
+ {
+ if (errmsg && errmsg[0] == '\0')
+ INF("Notification no longer exists.");
+ else
+ ERR("Eldbus Error: %s %s", errname, errmsg);
+ }
+}
+
+EOLIAN static void
+_elm_sys_notify_dbus_elm_sys_notify_interface_close(const Eo *obj EINA_UNUSED,
+ void *sd EINA_UNUSED,
+ unsigned int id)
+{
+ EINA_SAFETY_ON_NULL_RETURN(_elm_sysnotif_proxy);
+
+ if (!eldbus_proxy_call(_elm_sysnotif_proxy, "CloseNotification",
+ _close_notification_cb, NULL, -1, "u", id))
+ ERR("Error sending message: "INTERFACE".CloseNotification.");
+}
+
+static void
+_notify_cb(void *data,
+ const Eldbus_Message *msg,
+ Eldbus_Pending *pending EINA_UNUSED)
+{
+ const char *errname, *errmsg;
+ Elm_Sys_Notify_Send_Data *d = data;
+ unsigned int id = 0;
+
+ if (eldbus_message_error_get(msg, &errname, &errmsg))
+ ERR("Error: %s %s", errname, errmsg);
+ else if (!eldbus_message_arguments_get(msg, "u", &id))
+ {
+ ERR("Error getting return values of "INTERFACE".Notify.");
+ id = 0;
+ }
+
+ if (d->cb) d->cb((void *)d->data, id);
+ free(d);
+}
+
+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)
+{
+ Eldbus_Message *msg;
+ Eldbus_Message_Iter *iter, *actions, *hints;
+ Elm_Sys_Notify_Send_Data *data;
+ char *body_free = NULL;
+ char *desk_free = NULL;
+ const char *deskentry = elm_app_desktop_entry_get();
+ const char *appname = elm_app_name_get();
+
+ EINA_SAFETY_ON_NULL_RETURN(_elm_sysnotif_proxy);
+
+ data = malloc(sizeof(Elm_Sys_Notify_Send_Data));
+ EINA_SAFETY_ON_NULL_GOTO(data, error);
+ data->cb = cb;
+ data->data = cb_data;
+
+ if (!icon) icon = "";
+ if (!summary) summary = "";
+ if (!body)
+ body = "";
+ else if (!_has_markup)
+ body = body_free = elm_entry_markup_to_utf8(body);
+
+ msg = eldbus_proxy_method_call_new(_elm_sysnotif_proxy, "Notify");
+
+ iter = eldbus_message_iter_get(msg);
+ eldbus_message_iter_arguments_append(iter, "susssas", appname, replaces_id,
+ icon, summary, body, &actions);
+ /* actions */
+ eldbus_message_iter_container_close(iter, actions);
+
+ /* hints */
+ eldbus_message_iter_arguments_append(iter, "a{sv}", &hints);
+ _elm_sys_notify_marshal_dict_byte(hints, "urgency", (char) urgency);
+
+ if (strcmp(deskentry, ""))
+ {
+ deskentry = ecore_file_file_get(deskentry);
+ deskentry = desk_free = ecore_file_strip_ext(deskentry);
+ _elm_sys_notify_marshal_dict_string(hints, "desktop_entry", deskentry);
+ }
+ eldbus_message_iter_container_close(iter, hints);
+
+ /* timeout */
+ eldbus_message_iter_arguments_append(iter, "i", timeout);
+
+ eldbus_proxy_send(_elm_sysnotif_proxy, msg, _notify_cb, data, -1);
+ free(desk_free);
+ free(body_free);
+ return;
+
+error:
+ if (cb) cb((void *)cb_data, 0);
+}
+
+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)
+{
+ _elm_sys_notify_dbus_elm_sys_notify_interface_send(obj, sd,
+ 0, icon, summary, body,
+ ELM_SYS_NOTIFY_URGENCY_NORMAL,
+ -1, NULL, NULL);
+}
+
+static void
+_on_notification_closed(void *data EINA_UNUSED,
+ const Eldbus_Message *msg)
+{
+ const char *errname;
+ const char *errmsg;
+ Elm_Sys_Notify_Notification_Closed *d;
+
+ if (eldbus_message_error_get(msg, &errname, &errmsg))
+ {
+ ERR("Eldbus Error: %s %s", errname, errmsg);
+ return;
+ }
+
+ d = malloc(sizeof(*d));
+
+ if (!eldbus_message_arguments_get(msg, "uu", &(d->id), &(d->reason)))
+ {
+ ERR("Error processing signal: "INTERFACE".NotificationClosed.");
+ goto cleanup;
+ }
+
+ if (!ecore_event_add(ELM_EVENT_SYS_NOTIFY_NOTIFICATION_CLOSED, d,
+ NULL, NULL)) goto cleanup;
+
+ return;
+
+cleanup:
+ free(d);
+}
+
+static void
+_ev_action_invoked_free(void *data EINA_UNUSED,
+ void *ev_data)
+{
+ Elm_Sys_Notify_Action_Invoked *d = ev_data;
+
+ free(d->action_key);
+ free(d);
+}
+
+static void
+_on_action_invoked(void *data EINA_UNUSED,
+ const Eldbus_Message *msg)
+{
+ const char *errname;
+ const char *aux;
+
+ Elm_Sys_Notify_Action_Invoked *d;
+
+ if (eldbus_message_error_get(msg, &errname, &aux))
+ {
+ ERR("Eldbus Error: %s %s", errname, aux);
+ return;
+ }
+
+ d = calloc(1, sizeof(*d));
+ if (!d)
+ {
+ ERR("Fail to allocate memory");
+ return;
+ }
+
+ if (!eldbus_message_arguments_get(msg, "us", &(d->id), &aux))
+ {
+ ERR("Error processing signal: "INTERFACE".ActionInvoked.");
+ goto cleanup;
+ }
+
+ d->action_key = strdup(aux);
+
+ if (!ecore_event_add(ELM_EVENT_SYS_NOTIFY_ACTION_INVOKED, d,
+ _ev_action_invoked_free, NULL)) goto cleanup;
+
+ return;
+
+cleanup:
+ free(d->action_key);
+ free(d);
+}
+
+static void
+_release(void)
+{
+ if (_elm_sysnotif_proxy)
+ {
+ eldbus_proxy_unref(_elm_sysnotif_proxy);
+ _elm_sysnotif_proxy = NULL;
+ }
+
+ if (_elm_sysnotif_obj)
+ {
+ eldbus_object_unref(_elm_sysnotif_obj);
+ _elm_sysnotif_obj = NULL;
+ }
+}
+
+static void
+_update(void)
+{
+ _release();
+ _elm_sysnotif_obj = eldbus_object_get(_elm_sysnotif_conn, BUS, OBJ);
+ _elm_sysnotif_proxy = eldbus_proxy_get(_elm_sysnotif_obj, INTERFACE);
+ _elm_sys_notify_capabilities_get();
+
+ eldbus_proxy_signal_handler_add(_elm_sysnotif_proxy, "NotificationClosed",
+ _on_notification_closed, NULL);
+
+ eldbus_proxy_signal_handler_add(_elm_sysnotif_proxy, "ActionInvoked",
+ _on_action_invoked, NULL);
+}
+
+static void
+_name_owner_get_cb(void *data EINA_UNUSED,
+ const Eldbus_Message *msg,
+ Eldbus_Pending *pending EINA_UNUSED)
+{
+ const char *errname, *errmsg;
+
+ if (eldbus_message_error_get(msg, &errname, &errmsg))
+ ERR("Eldbus Error: %s %s", errname, errmsg);
+ else
+ _update();
+}
+
+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)
+{
+ if ((!new_id) || (*new_id == '\0'))
+ _release();
+ else
+ _update();
+}
+
+EOLIAN static Eo_Base *
+_elm_sys_notify_dbus_eo_base_constructor(Eo *obj,
+ void *sd EINA_UNUSED)
+{
+ /* Don't create the same object twice (singleton) */
+ if (!_elm_sysnotif_conn)
+ {
+ if (!elm_need_eldbus()) return NULL;
+
+ _elm_sysnotif_conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION);
+ if (!_elm_sysnotif_conn) return NULL;
+
+ eldbus_name_owner_changed_callback_add(_elm_sysnotif_conn, BUS,
+ _name_owner_changed_cb, NULL,
+ EINA_FALSE);
+
+ eldbus_name_owner_get(_elm_sysnotif_conn, BUS, _name_owner_get_cb, NULL);
+
+ obj = eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+ return obj;
+ }
+
+ ERR("Elm.Sys_Notify.Dbus is a singleton. It has already been created");
+ return NULL;
+}
+
+EOLIAN static void
+_elm_sys_notify_dbus_eo_base_destructor(Eo *obj,
+ void *sd EINA_UNUSED)
+{
+ _release();
+
+ eldbus_connection_unref(_elm_sysnotif_conn);
+ _elm_sysnotif_conn = NULL;
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+
+#include "elm_sys_notify_dbus.eo.c"
+
diff --git a/src/lib/elm_sys_notify_dbus.eo b/src/lib/elm_sys_notify_dbus.eo
new file mode 100644
index 000000000..df8eb9c85
--- /dev/null
+++ b/src/lib/elm_sys_notify_dbus.eo
@@ -0,0 +1,14 @@
+class Elm.Sys_Notify.Dbus (Eo.Base, Elm.Sys_Notify_Interface)
+{
+ eo_prefix: elm_obj_sys_notify_dbus;
+ data: null;
+
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ Elm.Sys_Notify_Interface.send;
+ Elm.Sys_Notify_Interface.simple_send;
+ Elm.Sys_Notify_Interface.close;
+ }
+}
+
diff --git a/src/lib/elm_sys_notify_interface.c b/src/lib/elm_sys_notify_interface.c
new file mode 100644
index 000000000..c630afec6
--- /dev/null
+++ b/src/lib/elm_sys_notify_interface.c
@@ -0,0 +1,9 @@
+#ifdef HAVE_CONFIG_H
+# include "elementary_config.h"
+#endif
+
+#include <Elementary.h>
+
+#include "elm_priv.h"
+#include "elm_sys_notify_interface.eo.c"
+
diff --git a/src/lib/elm_sys_notify_interface.eo b/src/lib/elm_sys_notify_interface.eo
new file mode 100644
index 000000000..627586b09
--- /dev/null
+++ b/src/lib/elm_sys_notify_interface.eo
@@ -0,0 +1,66 @@
+enum Elm.Sys_Notify.Urgency
+{
+ [[Urgency levels of a notification
+
+ @since 1.8
+ ]]
+ low, [[Low urgency]]
+ normal, [[Normal urgency]]
+ critical [[Critical urgency]]
+}
+
+interface Elm.Sys_Notify_Interface
+{
+ eo_prefix: elm_obj_sys_notify_interface;
+ legacy_prefix: elm_sys_notify_interface;
+
+ methods {
+ send @const {
+ [[Causes a notification to be forcefully closed and removed from the
+ user's view. It can be used, for example, in the event that what the
+ notification pertains to is no longer relevant, or to cancel a
+ notification with no expiration time.
+
+ @since 1.8
+ ]]
+ params {
+ @in replaces_id: uint; [[Notification ID that this notification replaces.
+ The value 0 means a new notification.]]
+ @in icon: const(char) *; [[The optional program icon of the calling application]]
+ @in summary: const(char) *; [[The summary text briefly describing the notification]]
+ @in body: const(char) * @optional; [[The optional detailed body text. Can be empty]]
+ @in urgency: Elm.Sys_Notify.Urgency; [[The urgency level]]
+ @in timeout: int; [[Timeout display in milliseconds]]
+ @in cb: Elm_Sys_Notify_Send_Cb; [[Callback used to retrieve the notification id
+ returned by the Notification Server]]
+ @in cb_data: const(void) * @optional; [[Optional context data]]
+ }
+ }
+ simple_send @const {
+ [[Create a new notification just with Icon, Body and Summary.
+ It is a helper that wraps the send method
+
+ @since 1.16
+ ]]
+
+ params {
+ @in icon: const(char) *; [[The optional program icon of the calling application]]
+ @in summary: const(char) *; [[The summary text briefly describing the notification]]
+ @in body: const(char) *; [[The optional detailed body text. Can be empty]]
+ }
+ }
+ close @const {
+ [[Causes a notification to be forcefully closed and removed from the
+ user's view. It can be used, for example, in the event that what the
+ notification pertains to is no longer relevant, or to cancel a
+ notification with no expiration time.
+
+ @since 1.8
+ ]]
+ params {
+ @in id: uint; [[Notification ID]]
+ }
+ }
+ }
+}
+