e systray: Initial commit of dbus notifier host
authorJosé Roberto de Souza <zehortigoza@profusion.mobi>
Thu, 3 Jan 2013 22:07:26 +0000 (22:07 +0000)
committerLucas De Marchi <lucas.demarchi@profusion.mobi>
Thu, 3 Jan 2013 22:07:26 +0000 (22:07 +0000)
Patch by: José Roberto de Souza  <zehortigoza@profusion.mobi>

SVN revision: 82111

data/themes/edc/systray.edc
src/modules/Makefile_systray.am
src/modules/systray/e_mod_main.c
src/modules/systray/e_mod_main.h
src/modules/systray/e_mod_notifier_host.c [new file with mode: 0644]
src/modules/systray/e_mod_notifier_host_dbus.c [new file with mode: 0644]
src/modules/systray/e_mod_notifier_host_private.h [new file with mode: 0644]

index 1945294..6a97f1a 100644 (file)
@@ -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";
       }
    }
 }
-   
index 2c3a721..38a8ae7 100644 (file)
@@ -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)
index ff4a628..894d332 100644 (file)
@@ -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)
 {
index 988f279..3ba409a 100644 (file)
@@ -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 (file)
index 0000000..e0bf528
--- /dev/null
@@ -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 (file)
index 0000000..afc3ad6
--- /dev/null
@@ -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 (file)
index 0000000..a0a2621
--- /dev/null
@@ -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);