summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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]]
+ }
+ }
+ }
+}
+