elm: Support switching between local and D-Bus main menus on the fly

With this patch, the main menu now keeps listening for the app menu
registrar all the time. Whenever it's available, it tries to register
itself. If the registrar exits, the menu switches back to local mode.

Patch by: Henrique Dante de Almeida <hdante@profusion.mobi>



SVN revision: 83098
This commit is contained in:
Henrique Dante de Almeida 2013-01-22 18:51:16 +00:00 committed by Bruno Dilly
parent d10860842d
commit 0fbcdfb49b
4 changed files with 107 additions and 38 deletions

View File

@ -17,6 +17,8 @@
#define DBUS_DATA_KEY "_Elm_DBus_Menu"
#endif
typedef struct _Callback_Data Callback_Data;
struct _Elm_DBus_Menu
{
#ifdef ELM_EDBUS2
@ -26,7 +28,7 @@ struct _Elm_DBus_Menu
unsigned timestamp;
Eina_Hash *elements;
Ecore_Idler *signal_idler;
Ecore_X_Window xid;
Callback_Data *app_menu_data;
#endif
};
@ -53,7 +55,9 @@ enum
typedef struct _Callback_Data
{
void (*result_cb)(Eina_Bool, void *);
void *data;
void *data;
EDBus_Pending *pending_register;
Ecore_X_Window xid;
} Callback_Data;
static Eina_Bool
@ -82,10 +86,49 @@ static void
_app_register_cb(void *data, const EDBus_Message *msg,
EDBus_Pending *pending EINA_UNUSED)
{
Callback_Data *cd = data;
Elm_DBus_Menu *menu = data;
Callback_Data *cd = menu->app_menu_data;
Eina_Bool result;
const char *error_name;
cd->result_cb(!edbus_message_error_get(msg, NULL, NULL), cd->data);
free(cd);
cd->pending_register = NULL;
result = !edbus_message_error_get(msg, &error_name, NULL);
if (!result && !strcmp(error_name, EDBUS_ERROR_PENDING_CANCELED))
{
DBG("Register canceled");
return;
}
if (cd->result_cb) cd->result_cb(result, cd->data);
}
static void
_app_menu_watch_cb(void *data, const char *bus EINA_UNUSED,
const char *old_id EINA_UNUSED, const char *new_id)
{
Elm_DBus_Menu *menu = data;
Callback_Data *cd = menu->app_menu_data;
EDBus_Message *msg;
const char *obj_path;
if (!strcmp(new_id, ""))
{
if (cd->pending_register) edbus_pending_cancel(cd->pending_register);
if (cd->result_cb) cd->result_cb(EINA_FALSE, cd->data);
}
else
{
msg = edbus_message_method_call_new(REGISTRAR_NAME, REGISTRAR_PATH,
REGISTRAR_INTERFACE,
"RegisterWindow");
obj_path = edbus_service_object_path_get(menu->iface);
edbus_message_arguments_append(msg, "uo", (unsigned)cd->xid,
obj_path);
cd->pending_register = edbus_connection_send(menu->bus, msg,
_app_register_cb, data, -1);
}
}
static Eina_Bool
@ -878,8 +921,8 @@ _elm_dbus_menu_unregister(Eo *obj)
if (!sd->dbus_menu) return;
if (sd->dbus_menu->xid)
_elm_dbus_menu_app_menu_unregister(sd->dbus_menu->menu);
if (sd->dbus_menu->app_menu_data)
_elm_dbus_menu_app_menu_unregister(obj);
edbus_service_interface_unregister(sd->dbus_menu->iface);
edbus_connection_unref(sd->dbus_menu->bus);
if (sd->dbus_menu->signal_idler)
@ -894,8 +937,6 @@ void
_elm_dbus_menu_app_menu_register(Ecore_X_Window xid, Eo *obj,
void (*result_cb)(Eina_Bool, void *), void *data)
{
EDBus_Message *msg;
const char *obj_path;
Callback_Data *cd;
ELM_MENU_CHECK(obj);
@ -907,23 +948,31 @@ _elm_dbus_menu_app_menu_register(Ecore_X_Window xid, Eo *obj,
return;
}
msg = edbus_message_method_call_new(REGISTRAR_NAME, REGISTRAR_PATH,
REGISTRAR_INTERFACE, "RegisterWindow");
cd = malloc(sizeof(Callback_Data));
if (sd->dbus_menu->app_menu_data)
{
if (sd->dbus_menu->app_menu_data->xid != xid)
ERR("There's another XID registered: %x",
sd->dbus_menu->app_menu_data->xid);
return;
}
sd->dbus_menu->app_menu_data = malloc(sizeof(Callback_Data));
cd = sd->dbus_menu->app_menu_data;
cd->result_cb = result_cb;
cd->data = data;
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, _app_register_cb,
cd, -1);
sd->dbus_menu->xid = xid;
cd->pending_register = NULL;
cd->xid = xid;
edbus_name_owner_changed_callback_add(sd->dbus_menu->bus, REGISTRAR_NAME,
_app_menu_watch_cb, sd->dbus_menu,
EINA_TRUE);
}
void
_elm_dbus_menu_app_menu_unregister(Eo *obj)
{
EDBus_Message *msg;
Callback_Data *cd;
ELM_MENU_CHECK(obj);
ELM_MENU_DATA_GET(obj, sd);
@ -934,13 +983,21 @@ _elm_dbus_menu_app_menu_unregister(Eo *obj)
return;
}
if (!sd->dbus_menu->xid) return;
cd = sd->dbus_menu->app_menu_data;
if (!cd) return;
if (cd->pending_register)
edbus_pending_cancel(cd->pending_register);
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_message_arguments_append(msg, "u", (unsigned)cd->xid);
edbus_connection_send(sd->dbus_menu->bus, msg, NULL, NULL, -1);
sd->dbus_menu->xid = 0;
edbus_name_owner_changed_callback_del(sd->dbus_menu->bus, REGISTRAR_NAME,
_app_menu_watch_cb, sd->dbus_menu);
free(cd);
sd->dbus_menu->app_menu_data = NULL;
}
int

View File

@ -610,6 +610,16 @@ _elm_menu_smart_del(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
eo_do_super(obj, evas_obj_smart_del());
}
void
_elm_menu_menu_bar_hide(Eo *obj)
{
ELM_MENU_DATA_GET_OR_RETURN(obj, sd);
evas_object_hide(sd->hv);
evas_object_hide(obj);
_menu_hide(obj, NULL, NULL);
}
void
_elm_menu_menu_bar_set(Eo *obj, Eina_Bool menu_bar)
{

View File

@ -415,6 +415,7 @@ void _elm_dbus_menu_app_menu_unregister(Eo *obj);
void _elm_dbus_menu_item_select_cb(Elm_Object_Item *obj_item);
void _elm_menu_menu_bar_set(Eo *obj, Eina_Bool menu_bar);
void _elm_menu_menu_bar_hide(Eo *obj);
/* DEPRECATED, will be removed on next release */
void _elm_icon_signal_emit(Evas_Object *obj,

View File

@ -3573,22 +3573,23 @@ elm_win_main_menu_get(const Evas_Object *obj)
}
static void
_local_menu_set(Eo *obj)
_dbus_menu_set(Eina_Bool connect, void *data)
{
ELM_WIN_DATA_GET_OR_RETURN(obj, sd);
ELM_WIN_DATA_GET_OR_RETURN(data, sd);
edje_object_part_swallow(sd->layout, "elm.swallow.menu", sd->main_menu);
edje_object_signal_emit(sd->layout, "elm,action,show_menu", "elm");
_elm_menu_menu_bar_set(sd->main_menu, EINA_TRUE);
}
static void
_dbus_result_cb(Eina_Bool result, void *data)
{
if (!result)
if (connect)
{
ERR("D-Bus menu error. Using local menu");
_local_menu_set(data);
DBG("Setting menu to D-Bus");
edje_object_part_unswallow(sd->layout, sd->main_menu);
edje_object_signal_emit(sd->layout, "elm,action,hide_menu", "elm");
_elm_menu_menu_bar_hide(sd->main_menu);
}
else
{
DBG("Setting menu to local mode");
edje_object_part_swallow(sd->layout, "elm.swallow.menu", sd->main_menu);
edje_object_signal_emit(sd->layout, "elm,action,show_menu", "elm");
evas_object_show(sd->main_menu);
}
}
@ -3602,19 +3603,19 @@ _main_menu_get(Eo *obj, void *_pd, va_list *list)
if (sd->main_menu) goto end;
sd->main_menu = elm_menu_add(obj);
_elm_menu_menu_bar_set(sd->main_menu, EINA_TRUE);
#ifdef HAVE_ELEMENTARY_X
if (_elm_config->external_menu && sd->x.xwin) use_dbus = EINA_TRUE;
#endif
if (use_dbus)
if (use_dbus && _elm_dbus_menu_register(sd->main_menu))
{
_elm_dbus_menu_register(sd->main_menu);
_elm_dbus_menu_app_menu_register(sd->x.xwin, sd->main_menu,
_dbus_result_cb, obj);
_dbus_menu_set, obj);
}
else
_local_menu_set(obj);
_dbus_menu_set(EINA_FALSE, obj);
end:
*ret = sd->main_menu;