e: Add dbusmenu API
authorJosé Roberto de Souza <zehortigoza@profusion.mobi>
Thu, 3 Jan 2013 18:16:09 +0000 (18:16 +0000)
committerLucas De Marchi <lucas.demarchi@profusion.mobi>
Thu, 3 Jan 2013 18:16:09 +0000 (18:16 +0000)
Patch by: José Roberto de Souza  <zehortigoza@profusion.mobi>

SVN revision: 82091

src/bin/Makefile.am
src/bin/e_dbusmenu.c [new file with mode: 0644]
src/bin/e_dbusmenu.h [new file with mode: 0644]
src/bin/e_includes.h

index 0e6065a..c430852 100644 (file)
@@ -63,6 +63,7 @@ e_configure_option.h \
 e_confirm_dialog.h \
 e_container.h \
 e_datastore.h \
+e_dbusmenu.h \
 e_desk.h \
 e_deskenv.h \
 e_desklock.h \
@@ -221,6 +222,7 @@ e_configure_option.c \
 e_confirm_dialog.c \
 e_container.c \
 e_datastore.c \
+e_dbusmenu.c \
 e_desk.c \
 e_deskenv.c \
 e_desklock.c \
diff --git a/src/bin/e_dbusmenu.c b/src/bin/e_dbusmenu.c
new file mode 100644 (file)
index 0000000..42da7cd
--- /dev/null
@@ -0,0 +1,429 @@
+#include "e.h"
+
+#define DBUS_MENU_IFACE "com.canonical.dbusmenu"
+
+struct _E_DBusMenu_Ctx
+{
+   EDBus_Proxy *proxy;
+   E_DBusMenu_Item *root_menu;
+   void *data;
+   E_DBusMenu_Pop_Request_Cb pop_request_cb;
+   E_DBusMenu_Itens_Update_Cb update_cb;
+};
+
+static const char *Menu_Item_Type_Names[] =
+{
+   "standard", "separator"
+};
+
+static const char *Menu_Item_Toogle_Type_Names[] =
+{
+   "", "checkmark", "radio"
+};
+
+static const char *Menu_Item_Dispostion_Names[] =
+{
+   "normal", "informative", "warning", "alert"
+};
+
+static const char *Menu_Item_Event_Names[] =
+{
+   "clicked", "hovered", "opened", "closed"
+};
+
+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
+dbus_menu_prop_dict_cb(void *data, const void *key, EDBus_Message_Iter *var)
+{
+   E_DBusMenu_Item *m = data;
+   if (!strcmp(key, "label"))
+     {
+        const char *label;
+        Eina_Strbuf *label_buf = eina_strbuf_new();
+        int i;
+
+        edbus_message_iter_arguments_get(var, "s", &label);
+        for (i = 0; label[i]; i++)
+          {
+             if (label[i] != '_')
+               {
+                  eina_strbuf_append_char(label_buf, label[i]);
+                  continue;
+               }
+
+             if (label[i+1] == '_')
+               {
+                  eina_strbuf_append_char(label_buf, label[i]);
+                  i++;
+                  continue;
+               }
+          }
+        eina_stringshare_replace(&m->label, eina_strbuf_string_get(label_buf));
+        eina_strbuf_free(label_buf);
+     }
+   else if (!strcmp(key, "type"))
+     {
+        const char *type;
+        edbus_message_iter_arguments_get(var, "s", &type);
+        m->type = id_find(type, Menu_Item_Type_Names, E_DBUSMENU_ITEM_TYPE_LAST);
+     }
+   else if (!strcmp(key, "icon-data"))
+     {
+        EDBus_Message_Iter *array;
+        int size;
+        const unsigned char *img_data;
+
+        edbus_message_iter_arguments_get(var, "ay", &array);
+        edbus_message_iter_fixed_array_get(array, 'y', &img_data, &size);
+        if (!size)
+          return;
+        m->icon_data = malloc(sizeof(unsigned char) * size);
+        EINA_SAFETY_ON_FALSE_RETURN(m->icon_data);
+        memcpy(m->icon_data, img_data, size);
+        m->icon_data_size = size;
+     }
+   else if (!strcmp(key, "icon-name"))
+     {
+        const char *icon_name;
+        edbus_message_iter_arguments_get(var, "s", &icon_name);
+        eina_stringshare_replace(&m->icon_name, icon_name);
+     }
+   else if (!strcmp(key, "toggle-type"))
+     {
+        const char *toogle_type;
+        edbus_message_iter_arguments_get(var, "s", &toogle_type);
+        m->toogle_type = id_find(toogle_type, Menu_Item_Toogle_Type_Names,
+                                 MENU_ITEM_TOOGLE_TYPE_LAST);
+     }
+   else if (!strcmp(key, "toggle-state"))
+     {
+        int state;
+        edbus_message_iter_arguments_get(var, "i", &state);
+        if (state == 1)
+          m->toogle_state = EINA_TRUE;
+        else
+          m->toogle_state = EINA_FALSE;
+     }
+   else if (!strcmp(key, "children-display"))
+     {
+        const char *display;
+        edbus_message_iter_arguments_get(var, "s", &display);
+        if (!strcmp(display, "submenu"))
+          m->is_submenu = EINA_TRUE;
+        else
+          m->is_submenu = EINA_FALSE;
+     }
+   else if (!strcmp(key, "disposition"))
+     {
+        const char *disposition;
+        edbus_message_iter_arguments_get(var, "s", &disposition);
+        m->disposition = id_find(disposition, Menu_Item_Dispostion_Names,
+                                 E_DBUSMENU_ITEM_DISPOSTION_LAST);
+     }
+   else if (!strcmp(key, "enabled"))
+     edbus_message_iter_arguments_get(var, "b", &m->enabled);
+   else if (!strcmp(key, "visible"))
+     edbus_message_iter_arguments_get(var, "b", &m->visible);
+}
+
+static E_DBusMenu_Item *
+parse_layout(EDBus_Message_Iter *layout, E_DBusMenu_Item *parent, E_DBusMenu_Ctx *menu_data)
+{
+   EDBus_Message_Iter *menu_item_prop, *sub_menu_itens_prop, *var;
+   E_DBusMenu_Item *m = calloc(1, sizeof(E_DBusMenu_Item));
+   EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
+   m->internal_ctx = menu_data;
+   m->enabled = EINA_TRUE;//default values
+   m->visible = EINA_TRUE;
+
+   if (!edbus_message_iter_arguments_get(layout, "ia{sv}av", &m->id,
+                                         &menu_item_prop, &sub_menu_itens_prop))
+     {
+        ERR("Error reading message");
+        free(m);
+        return NULL;
+     }
+
+   edbus_message_iter_dict_iterate(menu_item_prop, "sv", dbus_menu_prop_dict_cb, m);
+
+   while (edbus_message_iter_get_and_next(sub_menu_itens_prop, 'v', &var))
+     {
+        EDBus_Message_Iter *st;
+        if (!edbus_message_iter_arguments_get(var, "(ia{sv}av)", &st))
+          {
+             ERR("Error readding message.");
+             continue;
+          }
+        parse_layout(st, m, menu_data);
+     }
+
+   if (!parent)
+     return m;
+
+   parent->sub_items = eina_inlist_append(parent->sub_items, EINA_INLIST_GET(m));
+   m->parent = parent;
+   return NULL;
+}
+
+static void
+dbus_menu_free(E_DBusMenu_Item *m)
+{
+   Eina_Inlist *inlist;
+   E_DBusMenu_Item *child;
+
+   if (m->icon_name)
+     eina_stringshare_del(m->icon_name);
+   if (m->label)
+    eina_stringshare_del(m->label);
+   EINA_INLIST_FOREACH_SAFE(m->sub_items, inlist, child)
+     dbus_menu_free(child);
+   if (m->parent)
+     m->parent->sub_items = eina_inlist_remove(m->parent->sub_items,
+                                               EINA_INLIST_GET(m));
+   if (m->icon_data_size)
+     free(m->icon_data);
+   free(m);
+}
+
+static void
+layout_get_cb(void *data, const EDBus_Message *msg, EDBus_Pending *pending EINA_UNUSED)
+{
+   E_DBusMenu_Item *m;
+   const char *error, *error_msg;
+   EDBus_Message_Iter *layout;
+   unsigned revision;
+   E_DBusMenu_Ctx *menu_data = data;
+
+   if (edbus_message_error_get(msg, &error, &error_msg))
+     {
+        ERR("%s %s", error, error_msg);
+        return;
+     }
+
+   if (!edbus_message_arguments_get(msg, "u(ia{sv}av)", &revision, &layout))
+     {
+        ERR("Error reading message");
+        return;
+     }
+
+   m = parse_layout(layout, NULL, menu_data);
+   m->revision = revision;
+   if (menu_data->update_cb)
+     menu_data->update_cb(menu_data->data, m);
+   if (menu_data->root_menu)
+     dbus_menu_free(menu_data->root_menu);
+   menu_data->root_menu = m;
+}
+
+static E_DBusMenu_Item *
+dbus_menu_find(E_DBusMenu_Ctx *menu_data, int id)
+{
+   E_DBusMenu_Item *m;
+   if (!menu_data)
+     return NULL;
+
+   EINA_INLIST_FOREACH(menu_data->root_menu, m)
+     {
+        E_DBusMenu_Item *child, *found;
+        if (m->id == id)
+          return m;
+        EINA_INLIST_FOREACH(m->sub_items, child)
+          {
+             found = dbus_menu_find(menu_data, id);
+             if (found)
+               return found;
+          }
+     }
+   return NULL;
+}
+
+static void
+menu_pop_request(void *data, const EDBus_Message *msg)
+{
+   E_DBusMenu_Ctx *menu_data = data;
+   int id;
+   unsigned timestamp;
+   E_DBusMenu_Item *m;
+
+   if (!edbus_message_arguments_get(msg, "iu", &id, &timestamp))
+     {
+        ERR("Error reading values.");
+        return;
+     }
+
+   m = dbus_menu_find(menu_data, id);
+   if (!m)
+     return;
+   if (menu_data->pop_request_cb)
+     menu_data->pop_request_cb(menu_data->data, m);
+}
+
+static void
+icon_theme_path_get_cb(void *data EINA_UNUSED, const EDBus_Message *msg, EDBus_Pending *pending EINA_UNUSED)
+{
+   const char *error, *error_msg;
+   EDBus_Message_Iter *var, *array;
+   const char *path;
+   //DBus_Menu_Ctx *menu_data = data;
+
+   if (edbus_message_error_get(msg, &error, &error_msg))
+     {
+        ERR("%s %s", error, error_msg);
+        return;
+     }
+
+   if (!edbus_message_arguments_get(msg, "v", &var) ||
+       !edbus_message_iter_arguments_get(var, "as", &array))
+     {
+        ERR("Error reading message.");
+        return;
+     }
+
+   while (edbus_message_iter_get_and_next(array, 's', &path))
+     {
+        //TODO
+     }
+}
+
+static void
+prop_changed_cb(void *data EINA_UNUSED, const EDBus_Message *msg)
+{
+   const char *interface, *propname;
+   EDBus_Message_Iter *variant, *array;
+   //DBus_Menu_Ctx *menu_data = data;
+
+   if (!edbus_message_arguments_get(msg, "ssv", &interface, &propname, &variant))
+     {
+        ERR("Error getting values");
+        return;
+     }
+
+   if (strcmp(propname, "IconThemePath"))
+     return;
+
+   if (!edbus_message_iter_arguments_get(variant, "as", &array))
+     {
+        //TODO
+     }
+}
+
+static void
+layout_update(E_DBusMenu_Ctx *menu_data)
+{
+   EDBus_Message *msg;
+   EDBus_Message_Iter *main_iter, *array;
+
+   msg = edbus_proxy_method_call_new(menu_data->proxy, "GetLayout");
+   main_iter = edbus_message_iter_get(msg);
+   edbus_message_iter_arguments_append(main_iter, "iias", 0, -1, &array);
+   edbus_message_iter_container_close(main_iter, array);
+   edbus_proxy_send(menu_data->proxy, msg, layout_get_cb, menu_data, -1);
+}
+
+static void
+layout_updated_cb(void *data, const EDBus_Message *msg EINA_UNUSED)
+{
+   E_DBusMenu_Ctx *menu_data = data;
+   layout_update(menu_data);
+}
+
+E_DBusMenu_Ctx *
+e_dbusmenu_load(EDBus_Connection *conn, const char *bus, const char *path, const void *data)
+{
+   EDBus_Object *obj;
+   E_DBusMenu_Ctx *menu_data;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(bus, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
+
+   menu_data = calloc(1, sizeof(E_DBusMenu_Ctx));
+   EINA_SAFETY_ON_NULL_RETURN_VAL(menu_data, NULL);
+
+   menu_data->data = (void *)data;
+
+   edbus_connection_ref(conn);
+   obj = edbus_object_get(conn, bus, path);
+   menu_data->proxy = edbus_proxy_get(obj, DBUS_MENU_IFACE);
+
+   layout_update(menu_data);
+   edbus_proxy_signal_handler_add(menu_data->proxy,
+                                  "ItemActivationRequested",
+                                  menu_pop_request, menu_data);
+
+   edbus_proxy_property_get(menu_data->proxy, "IconThemePath",
+                            icon_theme_path_get_cb, menu_data);
+   edbus_proxy_properties_changed_callback_add(menu_data->proxy,
+                                               prop_changed_cb, menu_data);
+
+   edbus_proxy_signal_handler_add(menu_data->proxy, "ItemsPropertiesUpdated",
+                                  layout_updated_cb, menu_data);
+   edbus_proxy_signal_handler_add(menu_data->proxy, "LayoutUpdated",
+                                  layout_updated_cb, menu_data);
+   return menu_data;
+}
+
+void
+e_dbusmenu_event_send(E_DBusMenu_Item *m, E_DBus_Menu_Item_Event event)
+{
+   EDBus_Message *msg;
+   EDBus_Message_Iter *main_iter, *var;
+   unsigned int timestamp = (unsigned int)time(NULL);
+
+   EINA_SAFETY_ON_NULL_RETURN(m);
+   EINA_SAFETY_ON_FALSE_RETURN(event < E_DBUSMENU_ITEM_EVENT_LAST);
+   EINA_SAFETY_ON_NULL_RETURN(m->internal_ctx);
+
+   msg = edbus_proxy_method_call_new(m->internal_ctx->proxy, "Event");
+   main_iter = edbus_message_iter_get(msg);
+   edbus_message_iter_arguments_append(main_iter, "is", m->id,
+                                       Menu_Item_Event_Names[event]);
+
+   var = edbus_message_iter_container_new(main_iter, 'v', "s");
+   edbus_message_iter_arguments_append(var, "s", "");//dummy data
+   edbus_message_iter_container_close(main_iter, var);
+
+   edbus_message_iter_arguments_append(main_iter, "u", timestamp);
+
+   edbus_proxy_send(m->internal_ctx->proxy, msg, NULL, NULL, -1);
+   edbus_message_unref(msg);
+}
+
+void
+e_dbusmenu_unload(E_DBusMenu_Ctx *menu_data)
+{
+   EDBus_Connection *conn;
+   EDBus_Object *obj;
+   EINA_SAFETY_ON_NULL_RETURN(menu_data);
+
+   if (menu_data->root_menu)
+     dbus_menu_free(menu_data->root_menu);
+   obj = edbus_proxy_object_get(menu_data->proxy);
+   conn = edbus_object_connection_get(obj);
+   edbus_proxy_unref(menu_data->proxy);
+   edbus_object_unref(obj);
+   edbus_connection_unref(conn);
+   free(menu_data);
+}
+
+void
+e_dbusmenu_pop_request_callback_set(E_DBusMenu_Ctx *menu_data, E_DBusMenu_Pop_Request_Cb cb)
+{
+   menu_data->pop_request_cb = cb;
+}
+
+void
+e_dbusmenu_update_callback_set(E_DBusMenu_Ctx *menu_data, E_DBusMenu_Itens_Update_Cb cb)
+{
+   menu_data->update_cb = cb;
+}
diff --git a/src/bin/e_dbusmenu.h b/src/bin/e_dbusmenu.h
new file mode 100644 (file)
index 0000000..b52c1ed
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef _E_DBUSMENU_H_
+#define _E_DBUSMENU_H_
+
+#include <Eina.h>
+#include <EDBus.h>
+
+typedef enum {
+   E_DBUSMENU_ITEM_TYPE_STANDARD = 0,
+   E_DBUSMENU_ITEM_TYPE_SEPARATOR,
+   E_DBUSMENU_ITEM_TYPE_LAST
+} E_DBusMenu_Item_Type;
+
+typedef enum {
+   MENU_ITEM_TOOGLE_TYPE_NONE = 0,
+   MENU_ITEM_TOOGLE_TYPE_CHECKMARK,
+   MENU_ITEM_TOOGLE_TYPE_RADIO,
+   MENU_ITEM_TOOGLE_TYPE_LAST
+} E_DBusMenu_Item_Toogle_Type;
+
+typedef enum {
+   E_DBUSMENU_ITEM_DISPOSITION_NORMAL = 0,
+   E_DBUSMENU_ITEM_DISPOSITION_INFORMATIVE,
+   E_DBUSMENU_ITEM_DISPOSITION_WARNING,
+   E_DBUSMENU_ITEM_DISPOSITION_ALERT,
+   E_DBUSMENU_ITEM_DISPOSTION_LAST
+} E_DBusMenu_Item_Disposition;
+
+typedef struct _E_DBusMenu_Item  E_DBusMenu_Item;
+typedef struct _E_DBusMenu_Ctx E_DBusMenu_Ctx;
+
+struct _E_DBusMenu_Item
+{
+   EINA_INLIST;
+   unsigned revision;
+   int id;
+   const char *label;
+   E_DBusMenu_Item_Type type;
+   E_DBusMenu_Item_Toogle_Type toogle_type;
+   E_DBusMenu_Item_Disposition disposition;
+   Eina_Bool toogle_state;
+   Eina_Bool enabled;
+   Eina_Bool visible;
+   Eina_Bool is_submenu;
+   const char *icon_name;
+   unsigned char *icon_data;
+   unsigned icon_data_size;
+   Eina_Inlist *sub_items;
+   E_DBusMenu_Item *parent;
+   E_DBusMenu_Ctx *internal_ctx;
+};
+
+typedef void (*E_DBusMenu_Pop_Request_Cb)(void *data, const E_DBusMenu_Item *item);
+typedef void (*E_DBusMenu_Itens_Update_Cb)(void *data, E_DBusMenu_Item *new_root_item);
+
+typedef enum
+{
+   E_DBUSMENU_ITEM_EVENT_CLICKED = 0,
+   E_DBUSMENU_ITEM_EVENT_HOVERED,
+   E_DBUSMENU_ITEM_EVENT_OPENED,
+   E_DBUSMENU_ITEM_EVENT_CLOSED,
+   E_DBUSMENU_ITEM_EVENT_LAST
+} E_DBus_Menu_Item_Event;
+
+E_DBusMenu_Ctx * e_dbusmenu_load(EDBus_Connection *conn, const char *bus, const char *path, const void *data);
+void e_dbusmenu_unload(E_DBusMenu_Ctx *menu_data);
+void e_dbusmenu_update_callback_set(E_DBusMenu_Ctx *menu_data, E_DBusMenu_Itens_Update_Cb cb);
+void e_dbusmenu_pop_request_callback_set(E_DBusMenu_Ctx *menu_data, E_DBusMenu_Pop_Request_Cb cb);
+void e_dbusmenu_event_send(E_DBusMenu_Item *m, E_DBus_Menu_Item_Event event);
+
+#endif
index 40a48a6..d1d7966 100644 (file)
 #include "e_import_config_dialog.h"
 #include "e_grab_dialog.h"
 #include "e_widget_filepreview.h"
+#include "e_dbusmenu.h"