Patch by: José Roberto de Souza <zehortigoza@profusion.mobi> SVN revision: 82091devs/asdfuser/comp-sounds
parent
e0ef1e75ad
commit
805d32b831
4 changed files with 502 additions and 0 deletions
@ -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, ×tamp)) |
||||
{ |
||||
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; |
||||
} |
@ -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 |
Loading…
Reference in new issue