forked from enlightenment/efl
[elm] Add D-Bus external menu support
Patch by: Henrique Dante de Almeida <hdante@profusion.mobi> SVN revision: 81746
This commit is contained in:
parent
762586961d
commit
58b2fc2cd2
|
@ -839,3 +839,9 @@
|
|||
|
||||
* elm_plug now emits "image,resized" on server-side changes.
|
||||
* elm_plug typo fixed "image.deleted" to "image,deleted" ('.' -> ',')
|
||||
|
||||
2012-12-20 Henrique Dante de Almeida (hdante)
|
||||
|
||||
* Add elm_dbus_menu to support D-Bus external menus.
|
||||
* Add main menu to elm_win, which can be exported via D-Bus
|
||||
* Add configuration: ELM_EXTERNAL_MENU, to switch between internal and external menus
|
||||
|
|
|
@ -23,6 +23,8 @@ Additions:
|
|||
* Add elm_sys_notify.[ch]
|
||||
* Add elm_need_elocation() and Elocation.h support with ELM_ELOCATION macro to integrate elocation.
|
||||
* Add elm_plug signals "image,deleted" (fixed typo) and "image,resized".
|
||||
* Add elm_dbus_menu to support D-Bus external menus.
|
||||
* Add configuration: ELM_EXTERNAL_MENU, to switch between internal and extenal menus
|
||||
|
||||
Improvements:
|
||||
|
||||
|
@ -40,6 +42,7 @@ Improvements:
|
|||
* Conformant widget handles displaymode change related with keypad.
|
||||
* Conformant widget handles indicator service.
|
||||
* Elm_Transit image animation effects supports elm_image object type.
|
||||
* Include a main menu in elm_win, which can be exported via D-Bus.
|
||||
|
||||
Fixes:
|
||||
|
||||
|
|
|
@ -100,6 +100,7 @@ test_launcher.c \
|
|||
test_layout.c \
|
||||
test_list.c \
|
||||
test_map.c \
|
||||
test_main_menu.c \
|
||||
test_menu.c \
|
||||
test_multi.c \
|
||||
test_multibuttonentry.c \
|
||||
|
|
|
@ -153,6 +153,7 @@ void test_label2(void *data, Evas_Object *obj, void *event_info);
|
|||
void test_conformant(void *data, Evas_Object *obj, void *event_info);
|
||||
void test_conformant2(void *data, Evas_Object *obj, void *event_info);
|
||||
void test_conformant_indicator(void *data, Evas_Object *obj, void *event_info);
|
||||
void test_main_menu(void *data, Evas_Object *obj, void *event_info);
|
||||
void test_multi(void *data, Evas_Object *obj, void *event_info);
|
||||
void test_floating(void *data, Evas_Object *obj, void *event_info);
|
||||
void test_launcher(void *data, Evas_Object *obj, void *event_info);
|
||||
|
@ -643,6 +644,8 @@ add_tests:
|
|||
ADD_TEST(NULL, "Selectors", "Radios", test_radio);
|
||||
ADD_TEST(NULL, "Selectors", "Flip Selector", test_flipselector);
|
||||
ADD_TEST(NULL, "Selectors", "Dayselector", test_dayselector);
|
||||
ADD_TEST(NULL, "Selectors", "Main menu", test_main_menu);
|
||||
|
||||
|
||||
//------------------------------//
|
||||
ADD_TEST(NULL, "Cursors", "Cursor", test_cursor);
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
#include <Elementary.h>
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "elementary_config.h"
|
||||
#endif
|
||||
#ifndef ELM_LIB_QUICKLAUNCH
|
||||
|
||||
static void
|
||||
_click_me(void *data __UNUSED__, Evas_Object *obj __UNUSED__,
|
||||
void *event_info __UNUSED__)
|
||||
{
|
||||
fputs(":-)\n", stderr);
|
||||
}
|
||||
|
||||
void
|
||||
test_main_menu(void *data __UNUSED__,
|
||||
Evas_Object *obj __UNUSED__,
|
||||
void *event_info __UNUSED__)
|
||||
{
|
||||
Evas_Object *win, *bg, *menu, *label, *bx;
|
||||
Elm_Object_Item *menu_it, *menu_it1;
|
||||
char *s;
|
||||
Eina_Bool enabled = EINA_FALSE;
|
||||
|
||||
win = elm_win_add(NULL, "menu", ELM_WIN_BASIC);
|
||||
elm_win_title_set(win, "Menu");
|
||||
elm_win_autodel_set(win, EINA_TRUE);
|
||||
elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
|
||||
|
||||
bg = elm_bg_add(win);
|
||||
evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND,
|
||||
EVAS_HINT_EXPAND);
|
||||
|
||||
elm_win_resize_object_add(win, bg);
|
||||
evas_object_show(bg);
|
||||
|
||||
bx = elm_box_add(win);
|
||||
evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
|
||||
elm_win_resize_object_add(win, bx);
|
||||
evas_object_show(bx);
|
||||
|
||||
label = elm_label_add(win);
|
||||
elm_object_text_set(label, "Note: this example requires support from the "
|
||||
"desktop environment to display the application menu");
|
||||
evas_object_size_hint_weight_set(label, EVAS_HINT_EXPAND,
|
||||
EVAS_HINT_EXPAND);
|
||||
elm_win_resize_object_add(win, label);
|
||||
elm_box_pack_end(bx, label);
|
||||
evas_object_show(label);
|
||||
|
||||
s = getenv("ELM_EXTERNAL_MENU");
|
||||
if (s)
|
||||
enabled = !!atoi(s);
|
||||
|
||||
if (!enabled)
|
||||
{
|
||||
label = elm_label_add(win);
|
||||
elm_object_text_set(label, "(ELM_EXTERNAL_MENU environment variable not "
|
||||
"set. Test won't display it)");
|
||||
evas_object_size_hint_weight_set(label, EVAS_HINT_EXPAND,
|
||||
EVAS_HINT_EXPAND);
|
||||
elm_win_resize_object_add(win, label);
|
||||
elm_box_pack_end(bx, label);
|
||||
evas_object_show(label);
|
||||
}
|
||||
|
||||
menu = elm_win_main_menu_get(win);
|
||||
|
||||
menu_it = elm_menu_item_add(menu, NULL, NULL, "first item", NULL, NULL);
|
||||
elm_menu_item_add(menu, menu_it, NULL, "first item", NULL, NULL);
|
||||
menu_it1 = elm_menu_item_add(menu, menu_it, NULL, "submenu", NULL, NULL);
|
||||
elm_menu_item_add(menu, menu_it1, NULL, "first item", NULL, NULL);
|
||||
elm_menu_item_add(menu, menu_it1, NULL, "second item", NULL, NULL);
|
||||
|
||||
menu_it = elm_menu_item_add(menu, NULL, NULL, "second item", NULL, NULL);
|
||||
menu_it1 = elm_menu_item_add(menu, menu_it, NULL, "disabled item", NULL, NULL);
|
||||
elm_object_item_disabled_set(menu_it1, EINA_TRUE);
|
||||
elm_menu_item_add(menu, menu_it, NULL, "click me :-)", _click_me, NULL);
|
||||
elm_menu_item_add(menu, menu_it, NULL, "third item", NULL, NULL);
|
||||
menu_it1 = elm_menu_item_add(menu, menu_it, NULL, "sub menu", NULL, NULL);
|
||||
elm_menu_item_add(menu, menu_it1, NULL, "first item", NULL, NULL);
|
||||
|
||||
evas_object_resize(win, 250, 350);
|
||||
evas_object_show(win);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -238,6 +238,7 @@ elm_conform.c \
|
|||
elm_container.c \
|
||||
elm_datetime.c \
|
||||
elm_dayselector.c \
|
||||
elm_dbus_menu.c \
|
||||
elm_diskselector.c \
|
||||
elm_entry.c \
|
||||
elm_flip.c \
|
||||
|
|
|
@ -424,6 +424,7 @@ _desc_init(void)
|
|||
ELM_CONFIG_VAL(D, T, indicator_service_90, T_STRING);
|
||||
ELM_CONFIG_VAL(D, T, indicator_service_180, T_STRING);
|
||||
ELM_CONFIG_VAL(D, T, indicator_service_270, T_STRING);
|
||||
ELM_CONFIG_VAL(D, T, external_menu, T_UCHAR);
|
||||
#undef T
|
||||
#undef D
|
||||
#undef T_INT
|
||||
|
@ -1123,6 +1124,7 @@ _config_load(void)
|
|||
_elm_config->indicator_service_90 = eina_stringshare_add("elm_indicator_landscape");
|
||||
_elm_config->indicator_service_180 = eina_stringshare_add("elm_indicator_portrait");
|
||||
_elm_config->indicator_service_270 = eina_stringshare_add("elm_indicator_landscape");
|
||||
_elm_config->external_menu = EINA_FALSE;
|
||||
}
|
||||
|
||||
static const char *
|
||||
|
@ -1654,6 +1656,8 @@ _env_get(void)
|
|||
if (s) eina_stringshare_replace(&_elm_config->indicator_service_180, s);
|
||||
s = getenv("ELM_INDICATOR_SERVICE_270");
|
||||
if (s) eina_stringshare_replace(&_elm_config->indicator_service_270, s);
|
||||
s = getenv("ELM_EXTERNAL_MENU");
|
||||
if (s) _elm_config->external_menu = !!atoi(s);
|
||||
}
|
||||
|
||||
EAPI Eina_Bool
|
||||
|
@ -2167,6 +2171,18 @@ elm_config_softcursor_mode_get(void)
|
|||
return _elm_config->softcursor_mode;
|
||||
}
|
||||
|
||||
EAPI Eina_Bool
|
||||
elm_config_external_menu_get(void)
|
||||
{
|
||||
return _elm_config->external_menu;
|
||||
}
|
||||
|
||||
EAPI void
|
||||
elm_config_external_menu_set(Eina_Bool enable)
|
||||
{
|
||||
_elm_config->external_menu = !!enable;
|
||||
}
|
||||
|
||||
EAPI void
|
||||
elm_config_all_flush(void)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,937 @@
|
|||
#include <Elementary.h>
|
||||
#include <stdint.h>
|
||||
#include "elm_priv.h"
|
||||
#include "elm_widget_menu.h"
|
||||
|
||||
#ifdef ELM_EDBUS2
|
||||
|
||||
#define DBUS_PATH "/com/canonical/dbusmenu"
|
||||
#define DBUS_INTERFACE "com.canonical.dbusmenu"
|
||||
#define DBUS_MENU_VERSION 3u
|
||||
|
||||
#define REGISTRAR_NAME "com.canonical.AppMenu.Registrar"
|
||||
#define REGISTRAR_PATH "/com/canonical/AppMenu/Registrar"
|
||||
#define REGISTRAR_INTERFACE REGISTRAR_NAME
|
||||
|
||||
#define DBUS_DATA_KEY "_Elm_DBus_Menu"
|
||||
#endif
|
||||
|
||||
struct _Elm_DBus_Menu
|
||||
{
|
||||
#ifdef ELM_EDBUS2
|
||||
Eo *menu;
|
||||
EDBus_Connection *bus;
|
||||
EDBus_Service_Interface *iface;
|
||||
unsigned timestamp;
|
||||
Eina_Hash *elements;
|
||||
Ecore_Idler *signal_idler;
|
||||
Ecore_X_Window xid;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef ELM_EDBUS2
|
||||
static const EDBus_Service_Interface_Desc _interface;
|
||||
static unsigned last_object_path;
|
||||
|
||||
typedef enum _Elm_DBus_Property
|
||||
{
|
||||
ELM_DBUS_PROPERTY_LABEL,
|
||||
ELM_DBUS_PROPERTY_CHILDREN_DISPLAY,
|
||||
ELM_DBUS_PROPERTY_ENABLED,
|
||||
ELM_DBUS_PROPERTY_VISIBLE,
|
||||
ELM_DBUS_PROPERTY_UNKNOWN,
|
||||
} Elm_DBus_Property;
|
||||
|
||||
enum
|
||||
{
|
||||
ELM_DBUS_SIGNAL_LAYOUT_UPDATED,
|
||||
ELM_DBUS_SIGNAL_ITEM_ACTIVATION_REQUESTED,
|
||||
};
|
||||
|
||||
static Eina_Bool
|
||||
_menu_add_recursive(Elm_DBus_Menu *dbus_menu, Elm_Menu_Item *item)
|
||||
{
|
||||
int32_t id;
|
||||
Eina_List *l;
|
||||
Elm_Menu_Item *subitem;
|
||||
|
||||
id = ++dbus_menu->timestamp;
|
||||
if (!eina_hash_add(dbus_menu->elements, &id, item))
|
||||
return EINA_FALSE;
|
||||
|
||||
item->dbus_idx = id;
|
||||
|
||||
EINA_LIST_FOREACH (item->submenu.items, l, subitem)
|
||||
{
|
||||
if (!_menu_add_recursive(dbus_menu, subitem))
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_layout_idler(void *data)
|
||||
{
|
||||
Elm_DBus_Menu *dbus_menu = data;
|
||||
|
||||
edbus_service_signal_emit(dbus_menu->iface, ELM_DBUS_SIGNAL_LAYOUT_UPDATED,
|
||||
dbus_menu->timestamp, 0);
|
||||
|
||||
dbus_menu->signal_idler = NULL;
|
||||
return ECORE_CALLBACK_CANCEL;
|
||||
}
|
||||
|
||||
static void
|
||||
_layout_signal(Elm_DBus_Menu *dbus_menu)
|
||||
{
|
||||
if (!dbus_menu->bus) return;
|
||||
if (dbus_menu->signal_idler) return;
|
||||
|
||||
dbus_menu->signal_idler = ecore_idler_add(_layout_idler, dbus_menu);
|
||||
}
|
||||
|
||||
static Elm_DBus_Property
|
||||
_str_to_property(const char *str)
|
||||
{
|
||||
if (!strcmp(str, "label"))
|
||||
return ELM_DBUS_PROPERTY_LABEL;
|
||||
else if (!strcmp(str, "children-display"))
|
||||
return ELM_DBUS_PROPERTY_CHILDREN_DISPLAY;
|
||||
else if (!strcmp(str, "enabled"))
|
||||
return ELM_DBUS_PROPERTY_ENABLED;
|
||||
else if (!strcmp(str, "visible"))
|
||||
return ELM_DBUS_PROPERTY_VISIBLE;
|
||||
|
||||
return ELM_DBUS_PROPERTY_UNKNOWN;
|
||||
}
|
||||
|
||||
// Ad-hoc dbusmenu property dictionary subset implementation
|
||||
static void
|
||||
_property_append(Elm_Menu_Item *item,
|
||||
Elm_DBus_Property property,
|
||||
EDBus_Message_Iter *iter)
|
||||
{
|
||||
EDBus_Message_Iter *variant = NULL;
|
||||
Elm_Object_Item *item_obj = (Elm_Object_Item *)item;
|
||||
const char *t;
|
||||
Eina_Bool b;
|
||||
|
||||
switch (property)
|
||||
{
|
||||
case ELM_DBUS_PROPERTY_LABEL:
|
||||
variant = edbus_message_iter_container_new(iter, 'v', "s");
|
||||
t = elm_object_item_part_text_get(item_obj, NULL);
|
||||
if (!t) t = "";
|
||||
edbus_message_iter_basic_append(variant, 's', t);
|
||||
break;
|
||||
|
||||
case ELM_DBUS_PROPERTY_CHILDREN_DISPLAY:
|
||||
variant = edbus_message_iter_container_new(iter, 'v', "s");
|
||||
|
||||
if (eina_list_count(item->submenu.items))
|
||||
t = "submenu";
|
||||
else
|
||||
t = "";
|
||||
|
||||
edbus_message_iter_basic_append(variant, 's', t);
|
||||
break;
|
||||
|
||||
case ELM_DBUS_PROPERTY_ENABLED:
|
||||
variant = edbus_message_iter_container_new(iter, 'v', "b");
|
||||
b = !elm_object_item_disabled_get(item_obj);
|
||||
edbus_message_iter_basic_append(variant, 'b', b);
|
||||
break;
|
||||
|
||||
case ELM_DBUS_PROPERTY_VISIBLE:
|
||||
variant = edbus_message_iter_container_new(iter, 'v', "b");
|
||||
edbus_message_iter_basic_append(variant, 'b', EINA_TRUE);
|
||||
break;
|
||||
|
||||
case ELM_DBUS_PROPERTY_UNKNOWN:
|
||||
ERR("Invalid code path");
|
||||
return;
|
||||
}
|
||||
|
||||
edbus_message_iter_container_close(iter, variant);
|
||||
}
|
||||
|
||||
static void
|
||||
_property_dict_build(Elm_Menu_Item *item,
|
||||
Eina_List *property_list, EDBus_Message_Iter *iter)
|
||||
{
|
||||
char *propstr;
|
||||
Elm_DBus_Property property;
|
||||
EDBus_Message_Iter *array, *pair;
|
||||
Eina_List *l;
|
||||
|
||||
array = edbus_message_iter_container_new(iter, 'a', "{sv}");
|
||||
|
||||
EINA_LIST_FOREACH (property_list, l, propstr)
|
||||
{
|
||||
property = _str_to_property(propstr);
|
||||
|
||||
if (property == ELM_DBUS_PROPERTY_UNKNOWN) continue;
|
||||
|
||||
pair = edbus_message_iter_container_new(array, 'e', NULL);
|
||||
edbus_message_iter_basic_append(pair, 's', propstr);
|
||||
_property_append(item, property, pair);
|
||||
edbus_message_iter_container_close(array, pair);
|
||||
}
|
||||
|
||||
edbus_message_iter_container_close(iter, array);
|
||||
}
|
||||
|
||||
static void
|
||||
_layout_build_recursive(Elm_Menu_Item *item,
|
||||
Eina_List *property_list, unsigned recursion_depth,
|
||||
EDBus_Message_Iter *iter)
|
||||
{
|
||||
Eina_List *l;
|
||||
Elm_Menu_Item *subitem;
|
||||
EDBus_Message_Iter *layout, *array, *variant;
|
||||
|
||||
layout = edbus_message_iter_container_new(iter, 'r', NULL);
|
||||
edbus_message_iter_basic_append(layout, 'i', item->dbus_idx);
|
||||
_property_dict_build(item, property_list, layout);
|
||||
array = edbus_message_iter_container_new(layout, 'a', "v");
|
||||
|
||||
if (recursion_depth > 0)
|
||||
{
|
||||
EINA_LIST_FOREACH (item->submenu.items, l, subitem)
|
||||
{
|
||||
if (subitem->separator) continue;
|
||||
|
||||
variant = edbus_message_iter_container_new(array, 'v',
|
||||
"(ia{sv}av)");
|
||||
_layout_build_recursive(subitem, property_list,
|
||||
recursion_depth - 1, variant);
|
||||
edbus_message_iter_container_close(array, variant);
|
||||
}
|
||||
}
|
||||
|
||||
edbus_message_iter_container_close(layout, array);
|
||||
edbus_message_iter_container_close(iter, layout);
|
||||
}
|
||||
|
||||
static void
|
||||
_root_layout_build(Elm_DBus_Menu *dbus_menu, Eina_List *property_list,
|
||||
unsigned recursion_depth, EDBus_Message_Iter *iter)
|
||||
{
|
||||
char *property;
|
||||
EDBus_Message_Iter *layout, *array, *pair, *variant;
|
||||
const Eina_List *ret = NULL;
|
||||
Eina_List *items;
|
||||
Eina_List *l;
|
||||
Elm_Menu_Item *item;
|
||||
|
||||
layout = edbus_message_iter_container_new(iter, 'r', NULL);
|
||||
edbus_message_iter_basic_append(layout, 'i', 0);
|
||||
array = edbus_message_iter_container_new(layout, 'a', "{sv}");
|
||||
|
||||
EINA_LIST_FOREACH (property_list, l, property)
|
||||
{
|
||||
if (!strcmp(property, "children-display"))
|
||||
{
|
||||
pair = edbus_message_iter_container_new(array, 'e', NULL);
|
||||
edbus_message_iter_basic_append(pair, 's', property);
|
||||
variant = edbus_message_iter_container_new(pair, 'v', "s");
|
||||
edbus_message_iter_basic_append(variant, 's', "submenu");
|
||||
edbus_message_iter_container_close(pair, variant);
|
||||
edbus_message_iter_container_close(array, pair);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
edbus_message_iter_container_close(layout, array);
|
||||
array = edbus_message_iter_container_new(layout, 'a', "v");
|
||||
|
||||
if (recursion_depth > 0)
|
||||
{
|
||||
eo_do(dbus_menu->menu, elm_obj_menu_items_get(&ret));
|
||||
items = (Eina_List *)ret;
|
||||
EINA_LIST_FOREACH (items, l, item)
|
||||
{
|
||||
variant = edbus_message_iter_container_new(array, 'v',
|
||||
"(ia{sv}av)");
|
||||
_layout_build_recursive(item, property_list,
|
||||
recursion_depth - 1, variant);
|
||||
edbus_message_iter_container_close(array, variant);
|
||||
}
|
||||
}
|
||||
|
||||
edbus_message_iter_container_close(layout, array);
|
||||
edbus_message_iter_container_close(iter, layout);
|
||||
}
|
||||
|
||||
static Eina_List *
|
||||
_empty_properties_handle(Eina_List *property_list)
|
||||
{
|
||||
if (!eina_list_count(property_list))
|
||||
{
|
||||
property_list = eina_list_append(property_list, "label");
|
||||
property_list = eina_list_append(property_list, "children-display");
|
||||
property_list = eina_list_append(property_list, "enabled");
|
||||
property_list = eina_list_append(property_list, "visible");
|
||||
}
|
||||
return property_list;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_event_handle(Elm_DBus_Menu *dbus_menu, EDBus_Message_Iter *iter, int *error_id)
|
||||
{
|
||||
Elm_Menu_Item *item;
|
||||
const char *event;
|
||||
int id;
|
||||
int32_t i;
|
||||
EDBus_Message_Iter *data;
|
||||
unsigned *timestamp;
|
||||
|
||||
edbus_message_iter_arguments_get(iter, "isvu", &id, &event, &data,
|
||||
×tamp);
|
||||
i = id;
|
||||
item = eina_hash_find(dbus_menu->elements, &i);
|
||||
if (!item)
|
||||
{
|
||||
if (error_id) *error_id = id;
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
if (!strcmp(event, "clicked"))
|
||||
_elm_dbus_menu_item_select_cb((Elm_Object_Item *)item);
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static Elm_DBus_Menu *
|
||||
_elm_dbus_menu_add(Eo *menu)
|
||||
{
|
||||
Elm_DBus_Menu *dbus_menu;
|
||||
const Eina_List *ret = NULL;
|
||||
Eina_List *items, *l;
|
||||
Elm_Menu_Item *item;
|
||||
|
||||
ELM_MENU_CHECK(menu) NULL;
|
||||
|
||||
dbus_menu = calloc(1, sizeof(Elm_DBus_Menu));
|
||||
if (!dbus_menu)
|
||||
{
|
||||
ERR("Unable to allocate D-Bus data");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dbus_menu->elements = eina_hash_int32_new(NULL);
|
||||
if (!dbus_menu->elements)
|
||||
{
|
||||
ERR("Unable to allocate hash table");
|
||||
goto error_menu;
|
||||
}
|
||||
|
||||
dbus_menu->menu = menu;
|
||||
|
||||
eo_do(menu, elm_obj_menu_items_get(&ret));
|
||||
items = (Eina_List *)ret;
|
||||
EINA_LIST_FOREACH (items, l, item)
|
||||
{
|
||||
if (!_menu_add_recursive(dbus_menu, item))
|
||||
{
|
||||
ERR("Unable to add menu item");
|
||||
goto error_hash;
|
||||
}
|
||||
}
|
||||
|
||||
return dbus_menu;
|
||||
|
||||
error_hash:
|
||||
eina_hash_free(dbus_menu->elements);
|
||||
error_menu:
|
||||
free(dbus_menu);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// com.canonical.dbusmenu
|
||||
// =============================================================================
|
||||
// =============================================================================
|
||||
// Methods
|
||||
// =============================================================================
|
||||
static EDBus_Message *
|
||||
_method_layout_get(const EDBus_Service_Interface *iface,
|
||||
const EDBus_Message *msg)
|
||||
{
|
||||
int parent_id;
|
||||
int32_t id;
|
||||
int r;
|
||||
unsigned recursion_depth;
|
||||
char *property;
|
||||
Eina_List *property_list = NULL;
|
||||
EDBus_Message *reply;
|
||||
EDBus_Message_Iter *iter, *array;
|
||||
Elm_DBus_Menu *dbus_menu;
|
||||
Elm_Menu_Item *item = NULL;
|
||||
|
||||
dbus_menu = edbus_service_object_data_get(iface, DBUS_DATA_KEY);
|
||||
|
||||
if (!edbus_message_arguments_get(msg, "iias", &parent_id, &r, &array))
|
||||
ERR("Invalid arguments in D-Bus message");
|
||||
|
||||
recursion_depth = r;
|
||||
|
||||
while (edbus_message_iter_get_and_next(array, 's', &property))
|
||||
property_list = eina_list_append(property_list, property);
|
||||
|
||||
property_list = _empty_properties_handle(property_list);
|
||||
|
||||
if (parent_id)
|
||||
{
|
||||
id = parent_id;
|
||||
item = eina_hash_find(dbus_menu->elements, &id);
|
||||
if (!item)
|
||||
{
|
||||
reply = edbus_message_error_new(msg, DBUS_INTERFACE ".Error",
|
||||
"Invalid parent");
|
||||
return reply;
|
||||
}
|
||||
}
|
||||
|
||||
reply = edbus_message_method_return_new(msg);
|
||||
iter = edbus_message_iter_get(reply);
|
||||
edbus_message_iter_basic_append(iter, 'u', dbus_menu->timestamp);
|
||||
|
||||
if (parent_id)
|
||||
_layout_build_recursive(item, property_list, recursion_depth, iter);
|
||||
else
|
||||
_root_layout_build(dbus_menu, property_list, recursion_depth, iter);
|
||||
|
||||
eina_list_free(property_list);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static EDBus_Message *
|
||||
_method_group_properties_get(const EDBus_Service_Interface *iface,
|
||||
const EDBus_Message *msg)
|
||||
{
|
||||
Eina_Iterator *hash_iter;
|
||||
EDBus_Message *reply;
|
||||
EDBus_Message_Iter *ids, *property_names;
|
||||
EDBus_Message_Iter *iter, *array, *tuple;
|
||||
Eina_List *property_list = NULL;
|
||||
Elm_DBus_Menu *dbus_menu;
|
||||
Elm_Menu_Item *item;
|
||||
char *property;
|
||||
int id;
|
||||
int32_t i;
|
||||
void *data;
|
||||
|
||||
dbus_menu = edbus_service_object_data_get(iface, DBUS_DATA_KEY);
|
||||
|
||||
if (!edbus_message_arguments_get(msg, "aias", &ids, &property_names))
|
||||
ERR("Invalid arguments in D-Bus message");
|
||||
|
||||
while (edbus_message_iter_get_and_next(property_names, 's', &property))
|
||||
property_list = eina_list_append(property_list, property);
|
||||
|
||||
property_list = _empty_properties_handle(property_list);
|
||||
|
||||
reply = edbus_message_method_return_new(msg);
|
||||
iter = edbus_message_iter_get(reply);
|
||||
array = edbus_message_iter_container_new(iter, 'a', "(ia{sv})");
|
||||
|
||||
if (!edbus_message_iter_get_and_next(ids, 'i', &id))
|
||||
{
|
||||
hash_iter = eina_hash_iterator_data_new(dbus_menu->elements);
|
||||
|
||||
while (eina_iterator_next(hash_iter, &data))
|
||||
{
|
||||
item = data;
|
||||
tuple = edbus_message_iter_container_new(array, 'r', NULL);
|
||||
edbus_message_iter_basic_append(tuple, 'i', item->dbus_idx);
|
||||
_property_dict_build(item, property_list, tuple);
|
||||
edbus_message_iter_container_close(array, tuple);
|
||||
}
|
||||
|
||||
eina_iterator_free(hash_iter);
|
||||
}
|
||||
else
|
||||
do
|
||||
{
|
||||
i = id;
|
||||
item = eina_hash_find(dbus_menu->elements, &i);
|
||||
if (!item) continue;
|
||||
|
||||
tuple = edbus_message_iter_container_new(array, 'r', NULL);
|
||||
edbus_message_iter_basic_append(tuple, 'i', item->dbus_idx);
|
||||
_property_dict_build(item, property_list, tuple);
|
||||
edbus_message_iter_container_close(array, tuple);
|
||||
}
|
||||
while (edbus_message_iter_get_and_next(ids, 'i', &id));
|
||||
|
||||
edbus_message_iter_container_close(iter, array);
|
||||
eina_list_free(property_list);
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
static EDBus_Message *
|
||||
_method_property_get(const EDBus_Service_Interface *iface,
|
||||
const EDBus_Message *msg)
|
||||
{
|
||||
EDBus_Message *reply;
|
||||
EDBus_Message_Iter *iter, *variant;
|
||||
Elm_DBus_Property property;
|
||||
Elm_DBus_Menu *dbus_menu;
|
||||
Elm_Menu_Item *item;
|
||||
int id;
|
||||
int32_t i;
|
||||
char *name;
|
||||
|
||||
dbus_menu = edbus_service_object_data_get(iface, DBUS_DATA_KEY);
|
||||
|
||||
if (!edbus_message_arguments_get(msg, "is", &id, &name))
|
||||
ERR("Invalid arguments in D-Bus message");
|
||||
|
||||
property = _str_to_property(name);
|
||||
|
||||
if (property == ELM_DBUS_PROPERTY_UNKNOWN)
|
||||
{
|
||||
reply = edbus_message_error_new(msg, DBUS_INTERFACE ".Error",
|
||||
"Property not found");
|
||||
return reply;
|
||||
}
|
||||
|
||||
if (!id)
|
||||
{
|
||||
if (property != ELM_DBUS_PROPERTY_CHILDREN_DISPLAY)
|
||||
reply = edbus_message_error_new(msg, DBUS_INTERFACE ".Error",
|
||||
"Property not found");
|
||||
else
|
||||
{
|
||||
reply = edbus_message_method_return_new(msg);
|
||||
iter = edbus_message_iter_get(reply);
|
||||
variant = edbus_message_iter_container_new(iter, 'v', "s");
|
||||
edbus_message_iter_basic_append(variant, 's', "submenu");
|
||||
edbus_message_iter_container_close(iter, variant);
|
||||
}
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
i = id;
|
||||
item = eina_hash_find(dbus_menu->elements, &i);
|
||||
|
||||
if (!item)
|
||||
{
|
||||
reply = edbus_message_error_new(msg, DBUS_INTERFACE ".Error",
|
||||
"Invalid menu identifier");
|
||||
return reply;
|
||||
}
|
||||
|
||||
reply = edbus_message_method_return_new(msg);
|
||||
iter = edbus_message_iter_get(reply);
|
||||
_property_append(item, property, iter);
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
static EDBus_Message *
|
||||
_method_event(const EDBus_Service_Interface *iface,
|
||||
const EDBus_Message *msg)
|
||||
{
|
||||
Elm_DBus_Menu *dbus_menu;
|
||||
EDBus_Message *reply;
|
||||
|
||||
reply = edbus_message_method_return_new(msg);
|
||||
dbus_menu = edbus_service_object_data_get(iface, DBUS_DATA_KEY);
|
||||
|
||||
if (!_event_handle(dbus_menu, edbus_message_iter_get(msg), NULL))
|
||||
reply = edbus_message_error_new(msg, DBUS_INTERFACE ".Error",
|
||||
"Invalid menu");
|
||||
else
|
||||
reply = edbus_message_method_return_new(msg);
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
static EDBus_Message *
|
||||
_method_event_group(const EDBus_Service_Interface *iface,
|
||||
const EDBus_Message *msg)
|
||||
{
|
||||
EDBus_Message *reply;
|
||||
EDBus_Message_Iter *iter, *array, *tuple, *errors;
|
||||
int id;
|
||||
Elm_DBus_Menu *dbus_menu;
|
||||
Eina_Bool return_error = EINA_TRUE;
|
||||
|
||||
dbus_menu = edbus_service_object_data_get(iface, DBUS_DATA_KEY);
|
||||
|
||||
if (!edbus_message_arguments_get(msg, "a(isvu)", &array))
|
||||
ERR("Invalid arguments in D-Bus message");
|
||||
|
||||
reply = edbus_message_method_return_new(msg);
|
||||
iter = edbus_message_iter_get(reply);
|
||||
errors = edbus_message_iter_container_new(iter, 'a', "i");
|
||||
|
||||
while (edbus_message_iter_get_and_next(array, 'r', &tuple))
|
||||
{
|
||||
if (_event_handle(dbus_menu, tuple, &id))
|
||||
return_error = EINA_FALSE;
|
||||
else
|
||||
edbus_message_iter_basic_append(errors, 'i', id);
|
||||
}
|
||||
|
||||
if (return_error)
|
||||
{
|
||||
edbus_message_unref(reply);
|
||||
reply = edbus_message_error_new(msg, DBUS_INTERFACE ".Error",
|
||||
"Invalid menu identifiers");
|
||||
}
|
||||
else
|
||||
edbus_message_iter_container_close(iter, errors);
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
static EDBus_Message *
|
||||
_method_about_to_show(const EDBus_Service_Interface *iface EINA_UNUSED,
|
||||
const EDBus_Message *msg)
|
||||
{
|
||||
EDBus_Message *reply = edbus_message_method_return_new(msg);
|
||||
edbus_message_arguments_append(reply, "b", EINA_TRUE);
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
static EDBus_Message *
|
||||
_method_about_to_show_group(const EDBus_Service_Interface *iface EINA_UNUSED,
|
||||
const EDBus_Message *msg)
|
||||
{
|
||||
EDBus_Message *reply = edbus_message_method_return_new(msg);
|
||||
EDBus_Message_Iter *iter, *array;
|
||||
|
||||
iter = edbus_message_iter_get(reply);
|
||||
array = edbus_message_iter_container_new(iter, 'a', "i");
|
||||
edbus_message_iter_container_close(iter, array);
|
||||
array = edbus_message_iter_container_new(iter, 'a', "i");
|
||||
edbus_message_iter_container_close(iter, array);
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
static const EDBus_Method _methods[] = {
|
||||
{
|
||||
"GetLayout",
|
||||
EDBUS_ARGS({"i", "parentId"},
|
||||
{"i", "recursionDepth"},
|
||||
{"as", "propertyNames"}),
|
||||
EDBUS_ARGS({"u", "revision"}, {"(ia{sv}av)", "layout"}),
|
||||
_method_layout_get,
|
||||
0
|
||||
},
|
||||
{
|
||||
"GetGroupProperties",
|
||||
EDBUS_ARGS({"ai", "ids"}, {"as", "propertyNames"}),
|
||||
EDBUS_ARGS({"a(ia{sv})", "properties"}),
|
||||
_method_group_properties_get,
|
||||
0
|
||||
},
|
||||
{
|
||||
"GetProperty",
|
||||
EDBUS_ARGS({"i", "id"}, {"s", "name"}),
|
||||
EDBUS_ARGS({"v", "value"}),
|
||||
_method_property_get,
|
||||
0
|
||||
},
|
||||
{
|
||||
"Event",
|
||||
EDBUS_ARGS({"i", "id"},
|
||||
{"s", "eventId"},
|
||||
{"v", "data"},
|
||||
{"u", "timestamp"}),
|
||||
NULL,
|
||||
_method_event,
|
||||
0
|
||||
},
|
||||
{
|
||||
"EventGroup",
|
||||
EDBUS_ARGS({"a(isvu)", "events"}),
|
||||
EDBUS_ARGS({"ai", "idErrors"}),
|
||||
_method_event_group,
|
||||
0
|
||||
},
|
||||
{
|
||||
"AboutToShow",
|
||||
EDBUS_ARGS({"i", "id"}),
|
||||
EDBUS_ARGS({"b", "needUpdate"}),
|
||||
_method_about_to_show,
|
||||
0
|
||||
},
|
||||
{
|
||||
"AboutToShowGroup",
|
||||
EDBUS_ARGS({"ai", "ids"}),
|
||||
EDBUS_ARGS({"ai", "updatesNeeded"}, {"ai", "idErrors"}),
|
||||
_method_about_to_show_group,
|
||||
0
|
||||
},
|
||||
|
||||
{NULL, NULL, NULL, NULL, 0}
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
// Signals
|
||||
// =============================================================================
|
||||
static const EDBus_Signal _signals[] = {
|
||||
[ELM_DBUS_SIGNAL_LAYOUT_UPDATED] = {
|
||||
"LayoutUpdated", EDBUS_ARGS({"u", "revision"}, {"i", "parent"}), 0
|
||||
},
|
||||
[ELM_DBUS_SIGNAL_ITEM_ACTIVATION_REQUESTED] = {
|
||||
"ItemActivationRequested", EDBUS_ARGS({"i", "id"}, {"u", "timestamp"}), 0
|
||||
},
|
||||
{NULL, NULL, 0}
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
// Properties
|
||||
// =============================================================================
|
||||
static Eina_Bool
|
||||
_prop_version_get(const EDBus_Service_Interface *iface EINA_UNUSED,
|
||||
const char *propname EINA_UNUSED,
|
||||
EDBus_Message_Iter *iter,
|
||||
const EDBus_Message *request_msg EINA_UNUSED,
|
||||
EDBus_Message **error EINA_UNUSED)
|
||||
{
|
||||
edbus_message_iter_basic_append(iter, 'u', DBUS_MENU_VERSION);
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_prop_text_direction_get(const EDBus_Service_Interface *iface EINA_UNUSED,
|
||||
const char *propname EINA_UNUSED,
|
||||
EDBus_Message_Iter *iter,
|
||||
const EDBus_Message *request_msg EINA_UNUSED,
|
||||
EDBus_Message **error EINA_UNUSED)
|
||||
{
|
||||
if (_elm_config->is_mirrored)
|
||||
edbus_message_iter_basic_append(iter, 's', "rtl");
|
||||
else
|
||||
edbus_message_iter_basic_append(iter, 's', "ltr");
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_prop_status_get(const EDBus_Service_Interface *iface EINA_UNUSED,
|
||||
const char *propname EINA_UNUSED,
|
||||
EDBus_Message_Iter *iter,
|
||||
const EDBus_Message *request_msg EINA_UNUSED,
|
||||
EDBus_Message **error EINA_UNUSED)
|
||||
{
|
||||
static const char *normal = "normal";
|
||||
edbus_message_iter_basic_append(iter, 's', normal);
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_prop_icon_theme_path_get(const EDBus_Service_Interface *iface EINA_UNUSED,
|
||||
const char *propname EINA_UNUSED,
|
||||
EDBus_Message_Iter *iter,
|
||||
const EDBus_Message *request_msg EINA_UNUSED,
|
||||
EDBus_Message **error EINA_UNUSED)
|
||||
{
|
||||
EDBus_Message_Iter *actions;
|
||||
edbus_message_iter_arguments_append(iter, "as", &actions);
|
||||
edbus_message_iter_container_close(iter, actions);
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static const EDBus_Property _properties[] = {
|
||||
{ "Version", "u", _prop_version_get, NULL, 0 },
|
||||
{ "TextDirection", "s", _prop_text_direction_get, NULL, 0 },
|
||||
{ "Status", "s", _prop_status_get, NULL, 0 },
|
||||
{ "IconThemePath", "as", _prop_icon_theme_path_get, NULL, 0 },
|
||||
{ NULL, NULL, NULL, NULL, 0 },
|
||||
};
|
||||
|
||||
static const EDBus_Service_Interface_Desc _interface = {
|
||||
DBUS_INTERFACE, _methods, _signals, _properties, NULL, NULL
|
||||
};
|
||||
// =============================================================================
|
||||
|
||||
const char *
|
||||
_elm_dbus_menu_register(Eo *obj)
|
||||
{
|
||||
char buf[60];
|
||||
ELM_MENU_CHECK(obj) NULL;
|
||||
ELM_MENU_DATA_GET(obj, sd);
|
||||
|
||||
elm_need_edbus();
|
||||
|
||||
if (sd->dbus_menu)
|
||||
goto end;
|
||||
|
||||
sd->dbus_menu = _elm_dbus_menu_add(obj);
|
||||
sd->dbus_menu->bus = edbus_connection_get(EDBUS_CONNECTION_TYPE_SESSION);
|
||||
snprintf(buf, sizeof(buf), "%s/%u", DBUS_PATH, ++last_object_path);
|
||||
sd->dbus_menu->iface = edbus_service_interface_register(sd->dbus_menu->bus,
|
||||
buf,
|
||||
&_interface);
|
||||
edbus_service_object_data_set(sd->dbus_menu->iface, DBUS_DATA_KEY,
|
||||
sd->dbus_menu);
|
||||
|
||||
end:
|
||||
return edbus_service_object_path_get(sd->dbus_menu->iface);
|
||||
}
|
||||
|
||||
void
|
||||
_elm_dbus_menu_unregister(Eo *obj)
|
||||
{
|
||||
// TODO: support refcounting object paths
|
||||
|
||||
ELM_MENU_CHECK(obj);
|
||||
ELM_MENU_DATA_GET(obj, sd);
|
||||
|
||||
if (!sd->dbus_menu) return;
|
||||
|
||||
if (sd->dbus_menu->xid)
|
||||
_elm_dbus_menu_app_menu_unregister(sd->dbus_menu->menu);
|
||||
edbus_service_interface_unregister(sd->dbus_menu->iface);
|
||||
edbus_connection_unref(sd->dbus_menu->bus);
|
||||
if (sd->dbus_menu->signal_idler)
|
||||
ecore_idler_del(sd->dbus_menu->signal_idler);
|
||||
|
||||
eina_hash_free(sd->dbus_menu->elements);
|
||||
free(sd->dbus_menu);
|
||||
sd->dbus_menu = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
_elm_dbus_menu_app_menu_register(Ecore_X_Window xid, Eo *obj)
|
||||
{
|
||||
EDBus_Message *msg;
|
||||
const char *obj_path;
|
||||
|
||||
ELM_MENU_CHECK(obj);
|
||||
ELM_MENU_DATA_GET(obj, sd);
|
||||
|
||||
if (!sd->dbus_menu || !sd->dbus_menu->bus)
|
||||
{
|
||||
ERR("D-Bus is inactive for menu: %p", obj);
|
||||
return;
|
||||
}
|
||||
|
||||
msg = edbus_message_method_call_new(REGISTRAR_NAME, REGISTRAR_PATH,
|
||||
REGISTRAR_INTERFACE, "RegisterWindow");
|
||||
obj_path = edbus_service_object_path_get(sd->dbus_menu->iface);
|
||||
edbus_message_arguments_append(msg, "uo", (unsigned)xid,
|
||||
obj_path);
|
||||
edbus_connection_send(sd->dbus_menu->bus, msg, NULL, NULL, -1);
|
||||
edbus_message_unref(msg);
|
||||
sd->dbus_menu->xid = xid;
|
||||
}
|
||||
|
||||
void
|
||||
_elm_dbus_menu_app_menu_unregister(Eo *obj)
|
||||
{
|
||||
EDBus_Message *msg;
|
||||
|
||||
ELM_MENU_CHECK(obj);
|
||||
ELM_MENU_DATA_GET(obj, sd);
|
||||
|
||||
if (!sd->dbus_menu || !sd->dbus_menu->bus)
|
||||
{
|
||||
ERR("D-Bus is inactive for menu: %p", obj);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sd->dbus_menu->xid) return;
|
||||
|
||||
msg = edbus_message_method_call_new(REGISTRAR_NAME, REGISTRAR_PATH,
|
||||
REGISTRAR_INTERFACE, "UnregisterWindow");
|
||||
edbus_message_arguments_append(msg, "u", (unsigned)sd->dbus_menu->xid);
|
||||
edbus_connection_send(sd->dbus_menu->bus, msg, NULL, NULL, -1);
|
||||
edbus_message_unref(msg);
|
||||
sd->dbus_menu->xid = 0;
|
||||
}
|
||||
|
||||
int
|
||||
_elm_dbus_menu_item_add(Elm_DBus_Menu *dbus_menu, Elm_Object_Item *item_obj)
|
||||
{
|
||||
Elm_Menu_Item *item = (Elm_Menu_Item *)item_obj;
|
||||
int32_t id = dbus_menu->timestamp + 1;
|
||||
|
||||
if (!eina_hash_add(dbus_menu->elements, &id, item))
|
||||
{
|
||||
ERR("Unable to add menu");
|
||||
return -1;
|
||||
}
|
||||
|
||||
_layout_signal(dbus_menu);
|
||||
return ++dbus_menu->timestamp;
|
||||
}
|
||||
|
||||
void
|
||||
_elm_dbus_menu_item_delete(Elm_DBus_Menu *dbus_menu, int id)
|
||||
{
|
||||
int32_t i;
|
||||
|
||||
i = id;
|
||||
|
||||
if (!eina_hash_del_by_key(dbus_menu->elements, &i))
|
||||
{
|
||||
ERR("Invalid menu ID: %d", id);
|
||||
return;
|
||||
}
|
||||
|
||||
dbus_menu->timestamp++;
|
||||
_layout_signal(dbus_menu);
|
||||
}
|
||||
|
||||
void
|
||||
_elm_dbus_menu_update(Elm_DBus_Menu *dbus_menu)
|
||||
{
|
||||
_layout_signal(dbus_menu);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
const char *
|
||||
_elm_dbus_menu_register(Eo *obj EINA_UNUSED)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
_elm_dbus_menu_unregister(Eo *obj EINA_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
_elm_dbus_menu_app_menu_register(Ecore_X_Window xid EINA_UNUSED, Eo *obj EINA_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
_elm_dbus_menu_app_menu_unregister(Eo *obj EINA_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
_elm_dbus_menu_item_add(Elm_DBus_Menu *dbus_menu EINA_UNUSED,
|
||||
Elm_Object_Item *item_obj EINA_UNUSED)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
_elm_dbus_menu_item_delete(Elm_DBus_Menu *dbus_menu EINA_UNUSED, int id EINA_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
_elm_dbus_menu_update(Elm_DBus_Menu *dbus_menu EINA_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
|
@ -372,6 +372,14 @@ _submenu_open_cb(void *data,
|
|||
_submenu_sizing_eval(item);
|
||||
}
|
||||
|
||||
void
|
||||
_elm_dbus_menu_item_select_cb(Elm_Object_Item *obj_item)
|
||||
{
|
||||
Elm_Menu_Item *item = (Elm_Menu_Item *)obj_item;
|
||||
|
||||
if (item->func) item->func((void *)(item->base.data), WIDGET(item), item);
|
||||
}
|
||||
|
||||
static void
|
||||
_menu_item_select_cb(void *data,
|
||||
Evas_Object *obj __UNUSED__,
|
||||
|
@ -549,6 +557,8 @@ _elm_menu_smart_del(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
|
|||
Elm_Menu_Item *item;
|
||||
Elm_Menu_Smart_Data *sd = _pd;
|
||||
|
||||
_elm_dbus_menu_unregister(obj);
|
||||
|
||||
evas_object_event_callback_del_full
|
||||
(sd->parent, EVAS_CALLBACK_RESIZE, _parent_resize_cb, obj);
|
||||
evas_object_event_callback_del_full
|
||||
|
@ -779,6 +789,8 @@ _item_del_pre_hook(Elm_Object_Item *it)
|
|||
Elm_Menu_Item *item = (Elm_Menu_Item *)it;
|
||||
Elm_Object_Item *_item;
|
||||
|
||||
ELM_MENU_DATA_GET(WIDGET(item), sd);
|
||||
|
||||
EINA_LIST_FREE (item->submenu.items, _item)
|
||||
elm_object_item_del(_item);
|
||||
if (item->label) eina_stringshare_del(item->label);
|
||||
|
@ -790,10 +802,10 @@ _item_del_pre_hook(Elm_Object_Item *it)
|
|||
item->parent->submenu.items =
|
||||
eina_list_remove(item->parent->submenu.items, item);
|
||||
else
|
||||
{
|
||||
ELM_MENU_DATA_GET(WIDGET(item), sd);
|
||||
sd->items = eina_list_remove(sd->items, item);
|
||||
}
|
||||
|
||||
if (sd->dbus_menu)
|
||||
_elm_dbus_menu_item_delete(sd->dbus_menu, item->dbus_idx);
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
@ -861,6 +873,9 @@ _item_add(Eo *obj, void *_pd, va_list *list)
|
|||
|
||||
_elm_menu_item_add_helper(obj, (Elm_Menu_Item *)parent, subitem, sd);
|
||||
|
||||
if (sd->dbus_menu)
|
||||
subitem->dbus_idx = _elm_dbus_menu_item_add(sd->dbus_menu, (Elm_Object_Item *)subitem);
|
||||
|
||||
*ret = (Elm_Object_Item *)subitem;
|
||||
}
|
||||
|
||||
|
|
|
@ -234,6 +234,7 @@ struct _Elm_Config
|
|||
const char *indicator_service_180;
|
||||
const char *indicator_service_270;
|
||||
unsigned char selection_clear_enable;
|
||||
unsigned char external_menu;
|
||||
|
||||
/* Not part of the EET file */
|
||||
Eina_Bool is_mirrored : 1;
|
||||
|
@ -397,6 +398,19 @@ void _elm_config_color_set(const char *palette_name,
|
|||
int a);
|
||||
void _elm_config_colors_free(const char *palette_name);
|
||||
|
||||
typedef struct _Elm_DBus_Menu Elm_DBus_Menu;
|
||||
|
||||
const char *_elm_dbus_menu_register(Eo *obj);
|
||||
void _elm_dbus_menu_unregister(Eo *obj);
|
||||
int _elm_dbus_menu_item_add(Elm_DBus_Menu *dbus_menu,
|
||||
Elm_Object_Item *item);
|
||||
void _elm_dbus_menu_item_delete(Elm_DBus_Menu *dbus_menu,
|
||||
int id);
|
||||
|
||||
void _elm_dbus_menu_app_menu_register(Ecore_X_ID xid, Eo *obj);
|
||||
void _elm_dbus_menu_app_menu_unregister(Eo *obj);
|
||||
void _elm_dbus_menu_item_select_cb(Elm_Object_Item *obj_item);
|
||||
|
||||
/* DEPRECATED, will be removed on next release */
|
||||
void _elm_icon_signal_emit(Evas_Object *obj,
|
||||
const char *emission,
|
||||
|
|
|
@ -24,6 +24,8 @@ struct _Elm_Menu_Smart_Data
|
|||
|
||||
Eina_List *items;
|
||||
Evas_Coord xloc, yloc;
|
||||
Elm_DBus_Menu *dbus_menu;
|
||||
|
||||
};
|
||||
|
||||
typedef struct _Elm_Menu_Item Elm_Menu_Item;
|
||||
|
@ -37,6 +39,7 @@ struct _Elm_Menu_Item
|
|||
const char *label;
|
||||
Evas_Smart_Cb func;
|
||||
unsigned int idx;
|
||||
int dbus_idx;
|
||||
|
||||
struct
|
||||
{
|
||||
|
|
|
@ -130,6 +130,8 @@ struct _Elm_Win_Smart_Data
|
|||
const char *icon_name;
|
||||
const char *role;
|
||||
|
||||
Evas_Object *main_menu;
|
||||
|
||||
struct
|
||||
{
|
||||
const char *name;
|
||||
|
@ -1479,6 +1481,8 @@ _elm_win_smart_del(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
|
|||
if (sd->role) eina_stringshare_del(sd->role);
|
||||
if (sd->icon) evas_object_del(sd->icon);
|
||||
|
||||
if (sd->main_menu) evas_object_del(sd->main_menu);
|
||||
|
||||
_elm_win_profile_del(sd);
|
||||
_elm_win_available_profiles_del(sd);
|
||||
|
||||
|
@ -2482,7 +2486,7 @@ elm_win_add(Evas_Object *parent,
|
|||
}
|
||||
|
||||
static void
|
||||
_win_constructor(Eo *obj, void *_pd EINA_UNUSED, va_list *list)
|
||||
_win_constructor(Eo *obj, void *_pd, va_list *list)
|
||||
{
|
||||
Elm_Win_Smart_Data *sd = _pd;
|
||||
sd->obj = obj; // in ctor
|
||||
|
@ -3533,6 +3537,43 @@ _fullscreen_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
|
|||
}
|
||||
}
|
||||
|
||||
EAPI Evas_Object *
|
||||
elm_win_main_menu_get(const Evas_Object *obj)
|
||||
{
|
||||
ELM_WIN_CHECK(obj) NULL;
|
||||
Evas_Object *ret;
|
||||
eo_do((Eo *) obj, elm_obj_win_main_menu_get(&ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
_main_menu_get(Eo *obj, void *_pd, va_list *list)
|
||||
{
|
||||
Eo **ret = va_arg(*list, Eo **);
|
||||
Elm_Win_Smart_Data *sd = _pd;
|
||||
|
||||
if (sd->main_menu) goto end;
|
||||
|
||||
sd->main_menu = elm_menu_add(obj);
|
||||
|
||||
if (_elm_config->external_menu)
|
||||
{
|
||||
#ifdef HAVE_ELEMENTARY_X
|
||||
if (sd->x.xwin)
|
||||
{
|
||||
_elm_dbus_menu_register(sd->main_menu);
|
||||
_elm_dbus_menu_app_menu_register(sd->x.xwin, sd->main_menu);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO: Local version.
|
||||
}
|
||||
end:
|
||||
*ret = sd->main_menu;
|
||||
}
|
||||
|
||||
EAPI void
|
||||
elm_win_maximized_set(Evas_Object *obj,
|
||||
Eina_Bool maximized)
|
||||
|
@ -5143,6 +5184,7 @@ _class_constructor(Eo_Class *klass)
|
|||
EO_OP_FUNC(ELM_OBJ_WIN_ID(ELM_OBJ_WIN_SUB_ID_OVERRIDE_GET), _override_get),
|
||||
EO_OP_FUNC(ELM_OBJ_WIN_ID(ELM_OBJ_WIN_SUB_ID_FULLSCREEN_SET), _fullscreen_set),
|
||||
EO_OP_FUNC(ELM_OBJ_WIN_ID(ELM_OBJ_WIN_SUB_ID_FULLSCREEN_GET), _fullscreen_get),
|
||||
EO_OP_FUNC(ELM_OBJ_WIN_ID(ELM_OBJ_WIN_SUB_ID_MAIN_MENU_GET), _main_menu_get),
|
||||
EO_OP_FUNC(ELM_OBJ_WIN_ID(ELM_OBJ_WIN_SUB_ID_MAXIMIZED_SET), _maximized_set),
|
||||
EO_OP_FUNC(ELM_OBJ_WIN_ID(ELM_OBJ_WIN_SUB_ID_MAXIMIZED_GET), _maximized_get),
|
||||
EO_OP_FUNC(ELM_OBJ_WIN_ID(ELM_OBJ_WIN_SUB_ID_ICONIFIED_SET), _iconified_set),
|
||||
|
@ -5240,6 +5282,7 @@ static const Eo_Op_Description op_desc[] = {
|
|||
EO_OP_DESCRIPTION(ELM_OBJ_WIN_SUB_ID_OVERRIDE_GET, "Get the override state of a window."),
|
||||
EO_OP_DESCRIPTION(ELM_OBJ_WIN_SUB_ID_FULLSCREEN_SET, "Set the fullscreen state of a window."),
|
||||
EO_OP_DESCRIPTION(ELM_OBJ_WIN_SUB_ID_FULLSCREEN_GET, "Get the fullscreen state of a window."),
|
||||
EO_OP_DESCRIPTION(ELM_OBJ_WIN_SUB_ID_MAIN_MENU_GET, "Get the Main Menu of a window."),
|
||||
EO_OP_DESCRIPTION(ELM_OBJ_WIN_SUB_ID_MAXIMIZED_SET, "Set the maximized state of a window."),
|
||||
EO_OP_DESCRIPTION(ELM_OBJ_WIN_SUB_ID_MAXIMIZED_GET, "Get the maximized state of a window."),
|
||||
EO_OP_DESCRIPTION(ELM_OBJ_WIN_SUB_ID_ICONIFIED_SET, "Set the iconified state of a window."),
|
||||
|
|
|
@ -128,6 +128,7 @@ enum
|
|||
ELM_OBJ_WIN_SUB_ID_OVERRIDE_GET,
|
||||
ELM_OBJ_WIN_SUB_ID_FULLSCREEN_SET,
|
||||
ELM_OBJ_WIN_SUB_ID_FULLSCREEN_GET,
|
||||
ELM_OBJ_WIN_SUB_ID_MAIN_MENU_GET,
|
||||
ELM_OBJ_WIN_SUB_ID_MAXIMIZED_SET,
|
||||
ELM_OBJ_WIN_SUB_ID_MAXIMIZED_GET,
|
||||
ELM_OBJ_WIN_SUB_ID_ICONIFIED_SET,
|
||||
|
@ -519,6 +520,20 @@ enum
|
|||
*/
|
||||
#define elm_obj_win_fullscreen_get(ret) ELM_OBJ_WIN_ID(ELM_OBJ_WIN_SUB_ID_FULLSCREEN_GET), EO_TYPECHECK(Eina_Bool *, ret)
|
||||
|
||||
/**
|
||||
* @def elm_obj_win_main_menu_get
|
||||
* @since 1.8
|
||||
*
|
||||
* Get the Main Menu of a window.
|
||||
*
|
||||
* @param[out] ret Main menu.
|
||||
*
|
||||
* @see elm_win_main_menu_get
|
||||
*/
|
||||
#define elm_obj_win_main_menu_get(ret) \
|
||||
ELM_OBJ_WIN_ID(ELM_OBJ_WIN_SUB_ID_MAIN_MENU_GET), \
|
||||
EO_TYPECHECK(Eo **, ret)
|
||||
|
||||
/**
|
||||
* @def elm_obj_win_maximized_set
|
||||
* @since 1.8
|
||||
|
@ -1849,6 +1864,16 @@ EAPI void elm_win_fullscreen_set(Evas_Object *obj, Eina_Bool fu
|
|||
*/
|
||||
EAPI Eina_Bool elm_win_fullscreen_get(const Evas_Object *obj);
|
||||
|
||||
/**
|
||||
* Get the Main Menu of a window.
|
||||
*
|
||||
* @param obj The window object
|
||||
* @return The Main Menu of the window (NULL if error).
|
||||
*
|
||||
* @ingroup Win
|
||||
*/
|
||||
EAPI Evas_Object *elm_win_main_menu_get(const Evas_Object *obj);
|
||||
|
||||
/**
|
||||
* Set the maximized state of a window.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue