From 3014654d58633d5b28c476f9c28f4af4867b1f29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Thu, 3 Jan 2013 22:07:26 +0000 Subject: [PATCH] e systray: Initial commit of dbus notifier host MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Patch by: José Roberto de Souza SVN revision: 82111 --- data/themes/edc/systray.edc | 46 +- src/modules/Makefile_systray.am | 5 +- src/modules/systray/e_mod_main.c | 13 + src/modules/systray/e_mod_main.h | 5 + src/modules/systray/e_mod_notifier_host.c | 192 ++++++++ .../systray/e_mod_notifier_host_dbus.c | 429 ++++++++++++++++++ .../systray/e_mod_notifier_host_private.h | 54 +++ 7 files changed, 738 insertions(+), 6 deletions(-) create mode 100644 src/modules/systray/e_mod_notifier_host.c create mode 100644 src/modules/systray/e_mod_notifier_host_dbus.c create mode 100644 src/modules/systray/e_mod_notifier_host_private.h diff --git a/data/themes/edc/systray.edc b/data/themes/edc/systray.edc index 19452943e..6a97f1ae5 100644 --- a/data/themes/edc/systray.edc +++ b/data/themes/edc/systray.edc @@ -17,14 +17,15 @@ group { name: "e/modules/systray/main"; part { name: "e.xembed.size"; type: RECT; mouse_events: 0; description { state: "default" 0.0; visible: 0; - rel1.offset: -1 0; - rel2.offset: 0 -1; + rel1.to: "e.xembed.box"; + rel2.to: "e.xembed.box"; + align: 0.0 0.5; } } part { name: "e.xembed.box"; type: BOX; description { state: "default" 0.0; - rel1.to: "e.xembed.size"; - rel2.to: "e.xembed.size"; + rel2.relative: 0.0 1.0; + align: 0.0 0.5; box { layout: "horizontal"; padding: 2 0; @@ -40,78 +41,113 @@ group { name: "e/modules/systray/main"; } } } + part { name: "e.dbus_notifier.box"; type: BOX; + description { state: "default" 0.0; + align: 1.0 0.5; + rel1 { + relative: 1.0 0.0; + to: "e.xembed.box"; + } + box { + layout: "horizontal"; + padding: 2 0; + align: 0.5 0.5; + min: 1 1; + } + } + description { state: "vertical" 0.0; + inherit: "default" 0.0; + box { + layout: "vertical"; + padding: 0 2; + } + } + } } programs { program { signal: "e,action,orient,horiz"; source: "e"; action: STATE_SET "default" 0.0; target: "e.xembed.box"; + target: "e.dbus_notifier.box"; } program { signal: "e,action,orient,vert"; source: "e"; action: STATE_SET "vertical" 0.0; target: "e.xembed.box"; + target: "e.dbus_notifier.box"; } program { signal: "e,action,orient,left"; source: "e"; action: STATE_SET "vertical" 0.0; target: "e.xembed.box"; + target: "e.dbus_notifier.box"; } program { signal: "e,action,orient,right"; source: "e"; action: STATE_SET "vertical" 0.0; target: "e.xembed.box"; + target: "e.dbus_notifier.box"; } program { signal: "e,action,orient,top"; source: "e"; action: STATE_SET "default" 0.0; target: "e.xembed.box"; + target: "e.dbus_notifier.box"; } program { signal: "e,action,orient,bottom"; source: "e"; action: STATE_SET "default" 0.0; target: "e.xembed.box"; + target: "e.dbus_notifier.box"; } program { signal: "e,action,orient,corner_tl"; source: "e"; action: STATE_SET "default" 0.0; target: "e.xembed.box"; + target: "e.dbus_notifier.box"; } program { signal: "e,action,orient,corner_tr"; source: "e"; action: STATE_SET "default" 0.0; target: "e.xembed.box"; + target: "e.dbus_notifier.box"; } program { signal: "e,action,orient,corner_bl"; source: "e"; action: STATE_SET "default" 0.0; target: "e.xembed.box"; + target: "e.dbus_notifier.box"; } program { signal: "e,action,orient,corner_br"; source: "e"; action: STATE_SET "default" 0.0; target: "e.xembed.box"; + target: "e.dbus_notifier.box"; } program { signal: "e,action,orient,corner_lt"; source: "e"; action: STATE_SET "vertical" 0.0; target: "e.xembed.box"; + target: "e.dbus_notifier.box"; } program { signal: "e,action,orient,corner_rt"; source: "e"; action: STATE_SET "vertical" 0.0; target: "e.xembed.box"; + target: "e.dbus_notifier.box"; } program { signal: "e,action,orient,corner_lb"; source: "e"; action: STATE_SET "vertical" 0.0; target: "e.xembed.box"; + target: "e.dbus_notifier.box"; } program { signal: "e,action,orient,corner_rb"; source: "e"; action: STATE_SET "vertical" 0.0; target: "e.xembed.box"; + target: "e.dbus_notifier.box"; } } } - diff --git a/src/modules/Makefile_systray.am b/src/modules/Makefile_systray.am index 2c3a721b8..38a8ae70e 100644 --- a/src/modules/Makefile_systray.am +++ b/src/modules/Makefile_systray.am @@ -9,7 +9,10 @@ systraypkg_LTLIBRARIES = systray/module.la systray_module_la_SOURCES = systray/e_mod_main.h \ systray/e_mod_main.c \ - systray/e_mod_xembed.c + systray/e_mod_xembed.c \ + systray/e_mod_notifier_host_private.h \ + systray/e_mod_notifier_host.c \ + systray/e_mod_notifier_host_dbus.c .PHONY: systray install-systray systray: $(systraypkg_LTLIBRARIES) $(systray_DATA) diff --git a/src/modules/systray/e_mod_main.c b/src/modules/systray/e_mod_main.c index ff4a62885..894d33281 100644 --- a/src/modules/systray/e_mod_main.c +++ b/src/modules/systray/e_mod_main.c @@ -6,6 +6,7 @@ struct _Instance E_Container *con; Evas *evas; Instance_Xembed *xembed; + Instance_Notifier_Host *notifier; struct { Evas_Object *gadget; @@ -211,6 +212,7 @@ _gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style) _systray_cb_mouse_down, inst); inst->xembed = systray_xembed_new(inst); + inst->notifier = systray_notifier_host_new(inst, inst->gcc->gadcon); instance = inst; return inst->gcc; @@ -228,6 +230,7 @@ _gc_shutdown(E_Gadcon_Client *gcc) return; systray_xembed_free(inst->xembed); + systray_notifier_host_free(inst->notifier); evas_object_del(inst->ui.gadget); @@ -449,6 +452,16 @@ systray_edje_box_append(const Instance *inst, const char *part, edje_object_part_box_append(inst->ui.gadget, part, child); } +void +systray_edje_box_remove(const Instance *inst, const char *part, + Evas_Object *child) +{ + EINA_SAFETY_ON_NULL_RETURN(inst); + EINA_SAFETY_ON_NULL_RETURN(part); + EINA_SAFETY_ON_NULL_RETURN(child); + edje_object_part_box_remove(inst->ui.gadget, part, child); +} + int systray_manager_number_get(const Instance *inst) { diff --git a/src/modules/systray/e_mod_main.h b/src/modules/systray/e_mod_main.h index 988f27969..3ba409adb 100644 --- a/src/modules/systray/e_mod_main.h +++ b/src/modules/systray/e_mod_main.h @@ -11,6 +11,7 @@ EAPI int e_modapi_save(E_Module *m); typedef struct _Instance Instance; typedef struct _Instance_Xembed Instance_Xembed; +typedef struct _Instance_Notifier_Host Instance_Notifier_Host; E_Gadcon_Orient systray_orient_get(const Instance *inst); const E_Gadcon *systray_gadcon_get(const Instance *inst); @@ -21,6 +22,7 @@ Evas *systray_evas_get(const Instance *inst); Evas_Object *systray_edje_get(const Instance *inst); void systray_edje_emit(const Instance *inst, const char *sig); void systray_edje_box_append(const Instance *inst, const char *part, Evas_Object *child); +void systray_edje_box_remove(const Instance *inst, const char *part, Evas_Object *child); int systray_manager_number_get(const Instance *inst); Ecore_X_Window systray_root_get(const Instance *inst); @@ -33,6 +35,9 @@ void systray_xembed_free(Instance_Xembed *xembed); void systray_xembed_orient_set(Instance_Xembed *xembed, E_Gadcon_Orient orient); void systray_xembed_size_updated(Instance_Xembed *xembed); +Instance_Notifier_Host *systray_notifier_host_new(Instance *inst, E_Gadcon *gadcon); +void systray_notifier_host_free(Instance_Notifier_Host *notifier); + /** * @addtogroup Optional_Gadgets * @{ diff --git a/src/modules/systray/e_mod_notifier_host.c b/src/modules/systray/e_mod_notifier_host.c new file mode 100644 index 000000000..e0bf52867 --- /dev/null +++ b/src/modules/systray/e_mod_notifier_host.c @@ -0,0 +1,192 @@ +#include "e_mod_notifier_host_private.h" + +#define WATCHER_BUS "org.kde.StatusNotifierWatcher" +#define WATCHER_PATH "/StatusNotifierWatcher" +#define WATCHER_IFACE "org.kde.StatusNotifierWatcher" + +#define ITEM_IFACE "org.kde.StatusNotifierItem" + +const char *Category_Name[] = { + "unknown", "SystemServices" +}; + +const char *Status_Names[] = { + "unknown", "Active", "Passive", "NeedsAttention" +}; + +static const char *box_part_name = "e.dbus_notifier.box"; + +void +systray_notifier_item_free(Notifier_Item *item) +{ + EDBus_Object *obj; + EDBus_Signal_Handler *sig; + evas_object_del(item->icon_object); + if (item->menu_path) + { + e_dbusmenu_unload(item->menu_data); + //TODO free evas_object of menu + } + eina_stringshare_del(item->bus_id); + eina_stringshare_del(item->path); + if (item->attention_icon_name) + eina_stringshare_del(item->attention_icon_name); + if (item->icon_name) + eina_stringshare_del(item->icon_name); + if (item->icon_path) + eina_stringshare_del(item->icon_path); + if (item->id) + eina_stringshare_del(item->id); + if (item->menu_path) + eina_stringshare_del(item->menu_path); + if (item->title) + eina_stringshare_del(item->title); + EINA_LIST_FREE(item->signals, sig) + edbus_signal_handler_del(sig); + obj = edbus_proxy_object_get(item->proxy); + edbus_proxy_unref(item->proxy); + edbus_object_unref(obj); + item->host_inst->items_list = eina_inlist_remove(item->host_inst->items_list, + EINA_INLIST_GET(item)); + systray_size_updated(item->host_inst->inst); + free(item); +} + +static void +image_load(const char *name, const char *path, Evas_Object *image) +{ + if (path && strlen(path)) + { + char buf[1024]; + sprintf(buf, "%s/%s", path, name); + if (!e_icon_file_set(image, buf)) + e_util_icon_theme_set(image, "dialog-error"); + return; + } + if (!e_util_icon_theme_set(image, name)) + e_util_icon_theme_set(image, "dialog-error"); +} + +void +_clicked_item_cb(void *data __UNUSED__, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event) +{ + Notifier_Item *item = data; + Evas_Event_Mouse_Down *ev = event; + + if (ev->button == 1) + { + DBG("left %s", item->id); + return; + } +} + +static void +image_scale(Notifier_Item *item) +{ + Evas_Coord sz; + switch (systray_gadcon_get(item->host_inst->inst)->orient) + { + case E_GADCON_ORIENT_HORIZ: + case E_GADCON_ORIENT_TOP: + case E_GADCON_ORIENT_BOTTOM: + case E_GADCON_ORIENT_CORNER_TL: + case E_GADCON_ORIENT_CORNER_TR: + case E_GADCON_ORIENT_CORNER_BL: + case E_GADCON_ORIENT_CORNER_BR: + sz = systray_gadcon_get(item->host_inst->inst)->shelf->h; + break; + + case E_GADCON_ORIENT_VERT: + case E_GADCON_ORIENT_LEFT: + case E_GADCON_ORIENT_RIGHT: + case E_GADCON_ORIENT_CORNER_LT: + case E_GADCON_ORIENT_CORNER_RT: + case E_GADCON_ORIENT_CORNER_LB: + case E_GADCON_ORIENT_CORNER_RB: + default: + sz = systray_gadcon_get(item->host_inst->inst)->shelf->w; + } + sz = sz - 5; + evas_object_resize(item->icon_object, sz, sz); +} + +void +systray_notifier_item_update(Notifier_Item *item) +{ + if (!item->icon_object) + { + item->icon_object = e_icon_add(evas_object_evas_get(item->host_inst->edje)); + EINA_SAFETY_ON_NULL_RETURN(item->icon_object); + image_scale(item); + systray_size_updated(item->host_inst->inst); + evas_object_event_callback_add(item->icon_object, EVAS_CALLBACK_MOUSE_DOWN, + _clicked_item_cb, item); + } + + switch (item->status) + { + case STATUS_ACTIVE: + { + image_load(item->icon_name, item->icon_path, item->icon_object); + if (!item->in_box) + { + systray_edje_box_append(item->host_inst->inst, box_part_name, + item->icon_object); + evas_object_show(item->icon_object); + } + item->in_box = EINA_TRUE; + break; + } + case STATUS_PASSIVE: + { + if (item->in_box) + { + systray_edje_box_remove(item->host_inst->inst, box_part_name, + item->icon_object); + evas_object_hide(item->icon_object); + } + item->in_box = EINA_FALSE; + break; + } + case STATUS_ATTENTION: + { + image_load(item->attention_icon_name, item->icon_path, + item->icon_object); + if (!item->in_box) + { + systray_edje_box_append(item->host_inst->inst, box_part_name, + item->icon_object); + evas_object_show(item->icon_object); + } + item->in_box = EINA_TRUE; + break; + } + default: + { + ERR("Status unexpected."); + break; + } + } + systray_size_updated(item->host_inst->inst); +} + +Instance_Notifier_Host * +systray_notifier_host_new(Instance *inst, E_Gadcon *gadcon) +{ + Instance_Notifier_Host *host_inst = NULL; + host_inst = calloc(1, sizeof(Instance_Notifier_Host)); + EINA_SAFETY_ON_NULL_RETURN_VAL(host_inst, NULL); + host_inst->inst = inst; + host_inst->edje = systray_edje_get(inst); + host_inst->gadcon = gadcon; + systray_notifier_dbus_init(host_inst); + + return host_inst; +} + +void +systray_notifier_host_free(Instance_Notifier_Host *notifier) +{ + systray_notifier_dbus_shutdown(notifier); + free(notifier); +} diff --git a/src/modules/systray/e_mod_notifier_host_dbus.c b/src/modules/systray/e_mod_notifier_host_dbus.c new file mode 100644 index 000000000..afc3ad6ed --- /dev/null +++ b/src/modules/systray/e_mod_notifier_host_dbus.c @@ -0,0 +1,429 @@ +#include "e_mod_notifier_host_private.h" + +#define WATCHER_BUS "org.kde.StatusNotifierWatcher" +#define WATCHER_PATH "/StatusNotifierWatcher" +#define WATCHER_IFACE "org.kde.StatusNotifierWatcher" + +#define ITEM_IFACE "org.kde.StatusNotifierItem" + +#define HOST_REGISTRER "/bla" //TODO check what watcher expect we send to him + +extern const char *Category_Name[]; +extern const char *Status_Names[]; + +typedef struct _Notifier_Host_Data { + Instance_Notifier_Host *host_inst; + void *data; +} Notifier_Host_Data; + +static Eina_Bool +service_string_parse(const char *item, const char **path, const char **bus_id) +{ + unsigned i; + for (i = 0; i < strlen(item); i++) + { + if (item[i] != '/') + continue; + *path = eina_stringshare_add(item+i); + *bus_id = eina_stringshare_nprintf(i+1, "%s", item); + return EINA_TRUE; + } + return EINA_FALSE; +} + +static Notifier_Item * +notifier_item_find(const char *path, const char *bus_id, Instance_Notifier_Host *host_inst) +{ + Notifier_Item *item; + EINA_INLIST_FOREACH(host_inst->items_list, item) + { + if (item->bus_id == bus_id && item->path == path) + return item; + } + return NULL; +} + +static int +id_find(const char *text, const char *array_of_names[], unsigned max) +{ + unsigned i; + for (i = 0; i < max; i++) + { + if (strcmp(text, array_of_names[i])) + continue; + return i; + } + return 0; +} + +static void +item_prop_get(void *data, const void *key, EDBus_Message_Iter *var) +{ + Notifier_Item *item = data; + + if (!strcmp(key, "Category")) + { + const char *category; + edbus_message_iter_arguments_get(var, "s", &category); + item->category = id_find(category, Category_Name, CATEGORY_LAST); + } + else if (!strcmp(key, "IconName")) + { + const char *name; + edbus_message_iter_arguments_get(var, "s", &name); + eina_stringshare_replace(&item->icon_name, name); + } + else if (!strcmp(key, "AttentionIconName")) + { + const char *name; + edbus_message_iter_arguments_get(var, "s", &name); + eina_stringshare_replace(&item->attention_icon_name, name); + } + else if (!strcmp(key, "IconThemePath")) + { + const char *path; + edbus_message_iter_arguments_get(var, "s", &path); + eina_stringshare_replace(&item->icon_path, path); + } + else if (!strcmp(key, "Menu")) + { + const char *path; + edbus_message_iter_arguments_get(var, "o", &path); + eina_stringshare_replace(&item->menu_path, path); + } + else if (!strcmp(key, "Status")) + { + const char *status; + edbus_message_iter_arguments_get(var, "s", &status); + item->status = id_find(status, Status_Names, STATUS_LAST); + } + else if (!strcmp(key, "Id")) + { + const char *id; + edbus_message_iter_arguments_get(var, "s", &id); + eina_stringshare_replace(&item->id, id); + } + else if (!strcmp(key, "Title")) + { + const char *title; + edbus_message_iter_arguments_get(var, "s", &title); + eina_stringshare_replace(&item->title, title); + } +} + +//debug +static void +render_menu_itens(void *data, E_DBusMenu_Item *new_root_item) +{ + Notifier_Item *item = data; + E_DBusMenu_Item *child; + //TODO create evas_object of menu + + printf("icon = %s\n", item->id); + EINA_SAFETY_ON_FALSE_RETURN(new_root_item->is_submenu); + + EINA_INLIST_FOREACH(new_root_item->sub_items, child) + { + if (child->type == E_DBUSMENU_ITEM_TYPE_SEPARATOR) + printf("\tseparator\n"); + else + { + printf("\tLabel= %s | Icon name=%s | Toggle type=%d | Toggle state=%d | Visible = %d | Enabled = %d\n", + child->label, child->icon_name, child->toggle_type, + child->toggle_state, child->visible, child->enabled); + } + } +} + +static void +props_changed(void *data, const EDBus_Message *msg) +{ + Notifier_Item *item = data; + const char *interface, *menu = item->menu_path; + EDBus_Message_Iter *changed, *invalidate; + + if (!edbus_message_arguments_get(msg, "sa{sv}as", &interface, &changed, &invalidate)) + { + ERR("Error reading message"); + return; + } + + edbus_message_iter_dict_iterate(changed, "sv", item_prop_get, item); + + if (menu != item->menu_path) + { + EDBus_Connection *conn = edbus_object_connection_get(edbus_proxy_object_get(item->proxy)); + e_dbusmenu_unload(item->menu_data); + item->menu_data = e_dbusmenu_load(conn, item->bus_id, item->menu_path, item); + } +} + +static void +props_get_all_cb(void *data, const EDBus_Message *msg, EDBus_Pending *pending EINA_UNUSED) +{ + const char *error, *error_name; + EDBus_Message_Iter *dict; + Notifier_Item *item = data; + EDBus_Connection *conn; + + if (edbus_message_error_get(msg, &error, &error_name)) + { + ERR("%s %s", error, error_name); + return; + } + + if (!edbus_message_arguments_get(msg, "a{sv}", &dict)) + { + ERR("Error getting arguments."); + return; + } + + edbus_message_iter_dict_iterate(dict, "sv", item_prop_get, item); + + if (!item->menu_path) + ERR("Notifier item %s dont have menu path.", item->menu_path); + + conn = edbus_object_connection_get(edbus_proxy_object_get(item->proxy)); + item->menu_data = e_dbusmenu_load(conn, item->bus_id, item->menu_path, item); + e_dbusmenu_update_cb_set(item->menu_data, render_menu_itens); + + systray_notifier_item_update(item); +} + +static Eina_Bool +basic_prop_get(const char *propname, void *data, const EDBus_Message *msg) +{ + EDBus_Message_Iter *var; + const char *error, *error_msg; + + if (edbus_message_error_get(msg, &error, &error_msg)) + { + ERR("%s %s", error, error_msg); + return EINA_FALSE; + } + + if (!edbus_message_arguments_get(msg, "v", &var)) + { + ERR("Error reading message."); + return EINA_FALSE; + } + item_prop_get(data, propname, var); + return EINA_TRUE; +} + +static void +attention_icon_get_cb(void *data, const EDBus_Message *msg, EDBus_Pending *pending EINA_UNUSED) +{ + Notifier_Item *item = data; + const char *propname = "AttentionIconName"; + basic_prop_get(propname, item, msg); + systray_notifier_item_update(item); +} + +static void +new_attention_icon_cb(void *data, const EDBus_Message *msg EINA_UNUSED) +{ + Notifier_Item *item = data; + edbus_proxy_property_get(item->proxy, "AttentionIconName", attention_icon_get_cb, item); +} + +static void +icon_get_cb(void *data, const EDBus_Message *msg, EDBus_Pending *pending EINA_UNUSED) +{ + Notifier_Item *item = data; + const char *propname = "IconName"; + basic_prop_get(propname, item, msg); + systray_notifier_item_update(item); +} + +static void +new_icon_cb(void *data, const EDBus_Message *msg EINA_UNUSED) +{ + Notifier_Item *item = data; + edbus_proxy_property_get(item->proxy, "IconName", icon_get_cb, item); +} + +static void +title_get_cb(void *data, const EDBus_Message *msg, EDBus_Pending *pending EINA_UNUSED) +{ + Notifier_Item *item = data; + const char *propname = "Title"; + basic_prop_get(propname, item, msg); + systray_notifier_item_update(item); +} + +static void +new_title_cb(void *data, const EDBus_Message *msg EINA_UNUSED) +{ + Notifier_Item *item = data; + edbus_proxy_property_get(item->proxy, "Title", title_get_cb, item); +} + +static void +new_icon_theme_path_cb(void *data, const EDBus_Message *msg) +{ + Notifier_Item *item = data; + const char *path; + if (!edbus_message_arguments_get(msg, "s", &path)) + { + ERR("Error reading message."); + return; + } + eina_stringshare_replace(&item->icon_path, path); + systray_notifier_item_update(item); +} + +static void +new_status_cb(void *data, const EDBus_Message *msg) +{ + Notifier_Item *item = data; + const char *status; + if (!edbus_message_arguments_get(msg, "s", &status)) + { + ERR("Error reading message."); + return; + } + item->status = id_find(status, Status_Names, STATUS_LAST); + systray_notifier_item_update(item); +} + +static void +notifier_item_add(const char *path, const char *bus_id, Instance_Notifier_Host *host_inst) +{ + EDBus_Proxy *proxy; + Notifier_Item *item = calloc(1, sizeof(Notifier_Item)); + EDBus_Signal_Handler *s; + EINA_SAFETY_ON_NULL_RETURN(item); + + item->path = path; + item->bus_id = bus_id; + host_inst->items_list = eina_inlist_append(host_inst->items_list, + EINA_INLIST_GET(item)); + item->host_inst = host_inst; + + proxy = edbus_proxy_get(edbus_object_get(host_inst->conn, bus_id, path), + ITEM_IFACE); + item->proxy = proxy; + edbus_proxy_property_get_all(proxy, props_get_all_cb, item); + s = edbus_proxy_properties_changed_callback_add(proxy, props_changed, item); + item->signals = eina_list_append(item->signals, s); + s = edbus_proxy_signal_handler_add(proxy, "NewAttentionIcon", + new_attention_icon_cb, item); + item->signals = eina_list_append(item->signals, s); + s = edbus_proxy_signal_handler_add(proxy, "NewIcon", + new_icon_cb, item); + item->signals = eina_list_append(item->signals, s); + s = edbus_proxy_signal_handler_add(proxy, "NewIconThemePath", + new_icon_theme_path_cb, item); + item->signals = eina_list_append(item->signals, s); + s = edbus_proxy_signal_handler_add(proxy, "NewStatus", new_status_cb, item); + item->signals = eina_list_append(item->signals, s); + s = edbus_proxy_signal_handler_add(proxy, "NewTitle", new_title_cb, item); + item->signals = eina_list_append(item->signals, s); +} + +static void +notifier_item_add_cb(void *data, const EDBus_Message *msg) +{ + const char *item, *bus, *path; + Instance_Notifier_Host *host_inst = data; + + if (!edbus_message_arguments_get(msg, "s", &item)) + { + ERR("Error getting arguments from msg."); + return; + } + DBG("add %s", item); + if (service_string_parse(item, &path, &bus)) + notifier_item_add(path, bus, host_inst); +} + +static void +notifier_item_del_cb(void *data, const EDBus_Message *msg) +{ + const char *service, *bus, *path; + Notifier_Item *item; + Instance_Notifier_Host *host_inst = data; + + if (!edbus_message_arguments_get(msg, "s", &service)) + { + ERR("Error getting arguments from msg."); + return; + } + DBG("service %s", service); + if (!service_string_parse(service, &path, &bus)) + return; + item = notifier_item_find(path, bus, host_inst); + if (item) + systray_notifier_item_free(item); + eina_stringshare_del(path); + eina_stringshare_del(bus); +} + +static void +notifier_items_get_cb(void *data, const EDBus_Message *msg, EDBus_Pending *pending EINA_UNUSED) +{ + const char *item; + const char *error, *error_msg; + EDBus_Message_Iter *array, *variant; + Instance_Notifier_Host *host_inst = data; + + if (edbus_message_error_get(msg, &error, &error_msg)) + { + ERR("%s %s", error, error_msg); + return; + } + + if (!edbus_message_arguments_get(msg, "v", &variant)) + { + ERR("Error getting arguments from msg."); + return; + } + + if (!edbus_message_iter_arguments_get(variant, "as", &array)) + { + ERR("Error getting arguments from msg."); + return; + } + + while (edbus_message_iter_get_and_next(array, 's', &item)) + { + const char *bus, *path; + if (service_string_parse(item, &path, &bus)) + notifier_item_add(path, bus, host_inst); + } +} + +void systray_notifier_dbus_init(Instance_Notifier_Host *host_inst) +{ + EDBus_Object *obj; + edbus_init(); + + host_inst->conn = edbus_connection_get(EDBUS_CONNECTION_TYPE_SESSION); + obj = edbus_object_get(host_inst->conn, WATCHER_BUS, WATCHER_PATH); + host_inst->watcher = edbus_proxy_get(obj, WATCHER_IFACE); + edbus_proxy_call(host_inst->watcher, "RegisterStatusNotifierHost", NULL, NULL, -1, "s", + HOST_REGISTRER); + edbus_proxy_property_get(host_inst->watcher, "RegisteredStatusNotifierItems", + notifier_items_get_cb, host_inst); + edbus_proxy_signal_handler_add(host_inst->watcher, "StatusNotifierItemRegistered", + notifier_item_add_cb, host_inst); + edbus_proxy_signal_handler_add(host_inst->watcher, "StatusNotifierItemUnregistered", + notifier_item_del_cb, host_inst); +} + +void systray_notifier_dbus_shutdown(Instance_Notifier_Host *host_inst) +{ + Eina_Inlist *safe_list; + Notifier_Item *item; + EDBus_Object *obj; + + EINA_INLIST_FOREACH_SAFE(host_inst->items_list, safe_list, item) + systray_notifier_item_free(item); + + obj = edbus_proxy_object_get(host_inst->watcher); + edbus_proxy_unref(host_inst->watcher); + edbus_object_unref(obj); + edbus_connection_unref(host_inst->conn); + edbus_shutdown(); +} diff --git a/src/modules/systray/e_mod_notifier_host_private.h b/src/modules/systray/e_mod_notifier_host_private.h new file mode 100644 index 000000000..a0a26214f --- /dev/null +++ b/src/modules/systray/e_mod_notifier_host_private.h @@ -0,0 +1,54 @@ +#include "e_mod_main.h" + +typedef enum { + CATEGORY_UNKNOWN = 0, + CATEGORY_SYSTEM_SERVICES, + CATEGORY_LAST +} Category; + +typedef enum { + STATUS_UNKNOWN = 0, + STATUS_ACTIVE, + STATUS_PASSIVE, + STATUS_ATTENTION, + STATUS_LAST +} Status; + +struct _Instance_Notifier_Host +{ + Instance *inst; + Eina_Inlist *items_list; + const Evas_Object *box; + const Evas_Object *edje; + EDBus_Connection *conn; + EDBus_Proxy *watcher; + E_Gadcon *gadcon; +}; + +typedef struct _Notifier_Item +{ + EINA_INLIST; + const char *bus_id; + const char *path; + EDBus_Proxy *proxy; + Category category; + Status status; + const char *id; + const char *title; + const char *icon_name; + const char *attention_icon_name; + const char *icon_path; + Evas_Object *icon_object; + Instance_Notifier_Host *host_inst; + const char *menu_path; + E_DBusMenu_Ctx *menu_data; + Eina_List *signals; + Eina_Bool in_box; +} Notifier_Item; + + +void systray_notifier_item_update(Notifier_Item *item); +void systray_notifier_item_free(Notifier_Item *item); + +void systray_notifier_dbus_init(Instance_Notifier_Host *host_inst); +void systray_notifier_dbus_shutdown(Instance_Notifier_Host *host_inst);