enlightenment/src/modules/systray/e_mod_notifier_watcher.c

183 lines
5.9 KiB
C

#include "e_mod_notifier_host_private.h"
#define PATH "/StatusNotifierWatcher"
#define IFACE "org.kde.StatusNotifierWatcher"
#define PROTOCOL_VERSION 1
#define ERROR_HOST_ALREADY_REGISTERED "org.kde.StatusNotifierWatcher.Host.AlreadyRegistered"
#define ERROR_ITEM_ALREADY_REGISTERED "org.kde.StatusNotifierWatcher.Item.AlreadyRegistered"
static Eldbus_Connection *conn = NULL;
static Eldbus_Service_Interface *iface = NULL;
static Eina_List *items;
static const char *host_service = NULL;
static E_Notifier_Watcher_Item_Registered_Cb registered_cb;
static E_Notifier_Watcher_Item_Unregistered_Cb unregistered_cb;
static void *user_data;
enum
{
ITEM_REGISTERED = 0,
ITEM_UNREGISTERED,
HOST_REGISTERED,
HOST_UNREGISTERED
};
static void
item_name_monitor_cb(void *data, const char *bus, const char *old_id EINA_UNUSED, const char *new_id)
{
const char *service = data;
if (strcmp(new_id, ""))
return;
eldbus_service_signal_emit(iface, ITEM_UNREGISTERED, service);
items = eina_list_remove(items, service);
if (unregistered_cb)
unregistered_cb(user_data, service);
eina_stringshare_del(service);
eldbus_name_owner_changed_callback_del(conn, bus, item_name_monitor_cb, service);
}
static Eldbus_Message *
register_item_cb(const Eldbus_Service_Interface *s_iface, const Eldbus_Message *msg)
{
const char *service;
char buf[1024];
if (!eldbus_message_arguments_get(msg, "s", &service))
return NULL;
snprintf(buf, sizeof(buf), "%s%s", eldbus_message_sender_get(msg), service);
service = eina_stringshare_add(buf);
if (eina_list_data_find(items, service))
{
eina_stringshare_del(service);
return eldbus_message_error_new(msg, ERROR_ITEM_ALREADY_REGISTERED, "");
}
items = eina_list_append(items, service);
eldbus_service_signal_emit(s_iface, ITEM_REGISTERED, service);
eldbus_name_owner_changed_callback_add(conn, eldbus_message_sender_get(msg),
item_name_monitor_cb, service,
EINA_FALSE);
if (registered_cb)
registered_cb(user_data, service);
return eldbus_message_method_return_new(msg);
}
static void
host_name_monitor_cb(void *data EINA_UNUSED, const char *bus, const char *old_id EINA_UNUSED, const char *new_id)
{
if (strcmp(new_id, ""))
return;
eldbus_service_signal_emit(iface, HOST_UNREGISTERED);
eina_stringshare_del(host_service);
host_service = NULL;
eldbus_name_owner_changed_callback_del(conn, bus, host_name_monitor_cb, NULL);
}
static Eldbus_Message *
register_host_cb(const Eldbus_Service_Interface *s_iface, const Eldbus_Message *msg)
{
if (host_service)
return eldbus_message_error_new(msg, ERROR_HOST_ALREADY_REGISTERED, "");
if (!eldbus_message_arguments_get(msg, "s", &host_service))
return NULL;
host_service = eina_stringshare_add(host_service);
eldbus_service_signal_emit(s_iface, HOST_REGISTERED);
eldbus_name_owner_changed_callback_add(conn, eldbus_message_sender_get(msg),
host_name_monitor_cb, NULL, EINA_FALSE);
return eldbus_message_method_return_new(msg);
}
static Eina_Bool
properties_get(const Eldbus_Service_Interface *s_iface EINA_UNUSED, const char *propname, Eldbus_Message_Iter *iter, const Eldbus_Message *request_msg EINA_UNUSED, Eldbus_Message **error EINA_UNUSED)
{
if (!strcmp(propname, "ProtocolVersion"))
eldbus_message_iter_basic_append(iter, 'i', PROTOCOL_VERSION);
else if (!strcmp(propname, "RegisteredStatusNotifierItems"))
{
Eldbus_Message_Iter *array;
Eina_List *l;
const char *service;
eldbus_message_iter_arguments_append(iter, "as", &array);
EINA_LIST_FOREACH(items, l, service)
eldbus_message_iter_arguments_append(array, "s", service);
eldbus_message_iter_container_close(iter, array);
}
else if (!strcmp(propname, "IsStatusNotifierHostRegistered"))
eldbus_message_iter_arguments_append(iter, "b", host_service ? EINA_TRUE : EINA_FALSE);
return EINA_TRUE;
}
static const Eldbus_Property properties[] =
{
{ "RegisteredStatusNotifierItems", "as", NULL, NULL, 0 },
{ "IsStatusNotifierHostRegistered", "b", NULL, NULL, 0 },
{ "ProtocolVersion", "i", NULL, NULL, 0 },
{ NULL, NULL, NULL, NULL, 0 }
};
static const Eldbus_Signal signals[] = {
{ "StatusNotifierItemRegistered", ELDBUS_ARGS({"s", "service"}), 0 },
{ "StatusNotifierItemUnregistered", ELDBUS_ARGS({"s", "service"}), 0 },
{ "StatusNotifierHostRegistered", NULL, 0 },
{ "StatusNotifierHostUnregistered", NULL, 0 },
{ NULL, NULL, 0 }
};
static const Eldbus_Method methods[] =
{
{ "RegisterStatusNotifierItem", ELDBUS_ARGS({"s", "service"}), NULL,
register_item_cb, 0 },
{ "RegisterStatusNotifierHost", ELDBUS_ARGS({"s", "service"}), NULL,
register_host_cb, 0 },
{ NULL, NULL, NULL, NULL, 0 }
};
static const Eldbus_Service_Interface_Desc iface_desc = {
IFACE, methods, signals, properties, properties_get, NULL
};
void
systray_notifier_dbus_watcher_start(Eldbus_Connection *connection, E_Notifier_Watcher_Item_Registered_Cb registered, E_Notifier_Watcher_Item_Unregistered_Cb unregistered, const void *data)
{
EINA_SAFETY_ON_TRUE_RETURN(!!conn);
conn = connection;
iface = eldbus_service_interface_register(conn, PATH, &iface_desc);
registered_cb = registered;
unregistered_cb = unregistered;
user_data = (void *)data;
host_service = eina_stringshare_add("internal");
}
void
systray_notifier_dbus_watcher_stop(void)
{
const char *txt;
eldbus_service_interface_unregister(iface);
EINA_LIST_FREE(items, txt)
{
char *bus;
int i;
for (i = 0; txt[i] != '/'; i++);
i++;
bus = malloc(sizeof(char) * i);
snprintf(bus, i, "%s", txt);
eldbus_name_owner_changed_callback_del(conn, bus, item_name_monitor_cb, txt);
free(bus);
eina_stringshare_del(txt);
}
if (host_service)
eina_stringshare_del(host_service);
conn = NULL;
}