e dbusmenu - fix cross referencing from e menus created from debus menu

this stops crashes when e menu si still up when the dbus menu backing
it has changed/gone away... by referencing the dbusmenu to hang about
like a bad smell while the e gui menu is up until it's dismissed. this
fixes a real segv i saw with steam.

@fix
This commit is contained in:
Carsten Haitzler 2019-08-07 00:43:47 +01:00
parent 2b0735da58
commit df0a64dc7a
4 changed files with 93 additions and 57 deletions

View File

@ -37,11 +37,10 @@ static void proxy_init(E_DBusMenu_Ctx *ctx);
static int static int
id_find(const char *text, const char *array_of_names[], unsigned max) id_find(const char *text, const char *array_of_names[], unsigned max)
{ {
unsigned i; unsigned int i;
for (i = 0; i < max; i++) for (i = 0; i < max; i++)
{ {
if (strcmp(text, array_of_names[i])) if (strcmp(text, array_of_names[i])) continue;
continue;
return i; return i;
} }
return 0; return 0;
@ -90,8 +89,7 @@ dbus_menu_prop_dict_cb(void *data, const void *key, Eldbus_Message_Iter *var)
eldbus_message_iter_arguments_get(var, "ay", &array); eldbus_message_iter_arguments_get(var, "ay", &array);
eldbus_message_iter_fixed_array_get(array, 'y', &img_data, &size); eldbus_message_iter_fixed_array_get(array, 'y', &img_data, &size);
if (!size) if (!size) return;
return;
m->icon_data = malloc(sizeof(unsigned char) * size); m->icon_data = malloc(sizeof(unsigned char) * size);
EINA_SAFETY_ON_FALSE_RETURN(m->icon_data); EINA_SAFETY_ON_FALSE_RETURN(m->icon_data);
memcpy(m->icon_data, img_data, size); memcpy(m->icon_data, img_data, size);
@ -114,19 +112,15 @@ dbus_menu_prop_dict_cb(void *data, const void *key, Eldbus_Message_Iter *var)
{ {
int state; int state;
eldbus_message_iter_arguments_get(var, "i", &state); eldbus_message_iter_arguments_get(var, "i", &state);
if (state == 1) if (state == 1) m->toggle_state = EINA_TRUE;
m->toggle_state = EINA_TRUE; else m->toggle_state = EINA_FALSE;
else
m->toggle_state = EINA_FALSE;
} }
else if (!strcmp(key, "children-display")) else if (!strcmp(key, "children-display"))
{ {
const char *display; const char *display;
eldbus_message_iter_arguments_get(var, "s", &display); eldbus_message_iter_arguments_get(var, "s", &display);
if (!strcmp(display, "submenu")) if (!strcmp(display, "submenu")) m->is_submenu = EINA_TRUE;
m->is_submenu = EINA_TRUE; else m->is_submenu = EINA_FALSE;
else
m->is_submenu = EINA_FALSE;
} }
else if (!strcmp(key, "disposition")) else if (!strcmp(key, "disposition"))
{ {
@ -147,6 +141,7 @@ parse_layout(Eldbus_Message_Iter *layout, E_DBusMenu_Item *parent, E_DBusMenu_Ct
Eldbus_Message_Iter *menu_item_prop, *sub_menu_items_prop, *var; Eldbus_Message_Iter *menu_item_prop, *sub_menu_items_prop, *var;
E_DBusMenu_Item *m = calloc(1, sizeof(E_DBusMenu_Item)); E_DBusMenu_Item *m = calloc(1, sizeof(E_DBusMenu_Item));
EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
m->references = 1;
m->ctx = ctx; m->ctx = ctx;
m->enabled = EINA_TRUE; m->enabled = EINA_TRUE;
m->visible = EINA_TRUE; m->visible = EINA_TRUE;
@ -172,8 +167,7 @@ parse_layout(Eldbus_Message_Iter *layout, E_DBusMenu_Item *parent, E_DBusMenu_Ct
parse_layout(st, m, ctx); parse_layout(st, m, ctx);
} }
if (!parent) if (!parent) return m;
return m;
parent->sub_items = eina_inlist_append(parent->sub_items, EINA_INLIST_GET(m)); parent->sub_items = eina_inlist_append(parent->sub_items, EINA_INLIST_GET(m));
m->parent = parent; m->parent = parent;
@ -186,17 +180,21 @@ dbus_menu_free(E_DBusMenu_Item *m)
Eina_Inlist *inlist; Eina_Inlist *inlist;
E_DBusMenu_Item *child; 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) EINA_INLIST_FOREACH_SAFE(m->sub_items, inlist, child)
dbus_menu_free(child); {
if (m->parent) e_dbusmenu_item_unref(child);
m->parent->sub_items = eina_inlist_remove(m->parent->sub_items, }
EINA_INLIST_GET(m)); EINA_INLIST_FREE(m->sub_items, child)
if (m->icon_data_size) {
free(m->icon_data); m->sub_items = eina_inlist_remove
(m->sub_items, EINA_INLIST_GET(child));
child->parent = NULL;
}
if (m->icon_name) eina_stringshare_del(m->icon_name);
if (m->label) eina_stringshare_del(m->label);
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); free(m);
} }
@ -229,7 +227,7 @@ attempt_hacks(E_DBusMenu_Ctx *ctx)
if ((unsigned int)(p - bus) > sizeof(buf) - 1) return EINA_FALSE; if ((unsigned int)(p - bus) > sizeof(buf) - 1) return EINA_FALSE;
strncpy(buf, bus, p - bus); strncpy(buf, bus, p - bus);
snprintf(buf2, sizeof(buf2), "%s%d", buf, n); snprintf(buf2, sizeof(buf2), "%s%d", buf, n);
E_FREE_FUNC(ctx->root_menu, dbus_menu_free); E_FREE_FUNC(ctx->root_menu, e_dbusmenu_item_unref);
eldbus_proxy_unref(ctx->proxy); eldbus_proxy_unref(ctx->proxy);
eldbus_object_unref(obj); eldbus_object_unref(obj);
@ -267,15 +265,13 @@ layout_get_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EIN
{ {
if (attempt_hacks(ctx)) if (attempt_hacks(ctx))
{ {
dbus_menu_free(m); e_dbusmenu_item_unref(m);
return; return;
} }
} }
if (ctx->update_cb) if (ctx->update_cb) ctx->update_cb(ctx->data, m);
ctx->update_cb(ctx->data, m); if (ctx->root_menu) e_dbusmenu_item_unref(ctx->root_menu);
if (ctx->root_menu)
dbus_menu_free(ctx->root_menu);
ctx->root_menu = m; ctx->root_menu = m;
} }
@ -289,13 +285,11 @@ dbus_menu_find(E_DBusMenu_Ctx *ctx, int id)
EINA_INLIST_FOREACH(ctx->root_menu, m) EINA_INLIST_FOREACH(ctx->root_menu, m)
{ {
E_DBusMenu_Item *child, *found; E_DBusMenu_Item *child, *found;
if (m->id == id) if (m->id == id) return m;
return m;
EINA_INLIST_FOREACH(m->sub_items, child) EINA_INLIST_FOREACH(m->sub_items, child)
{ {
found = dbus_menu_find(ctx, id); found = dbus_menu_find(ctx, id);
if (found) if (found) return found;
return found;
} }
} }
return NULL; return NULL;
@ -316,10 +310,8 @@ menu_pop_request(void *data, const Eldbus_Message *msg)
} }
m = dbus_menu_find(ctx, id); m = dbus_menu_find(ctx, id);
if (!m) if (!m) return;
return; if (ctx->pop_request_cb) ctx->pop_request_cb(ctx->data, m);
if (ctx->pop_request_cb)
ctx->pop_request_cb(ctx->data, m);
} }
static void static void
@ -334,8 +326,7 @@ prop_changed_cb(void *data EINA_UNUSED, const Eldbus_Message *msg)
return; return;
} }
if (strcmp(propname, "IconThemePath")) if (strcmp(propname, "IconThemePath")) return;
return;
if (!eldbus_message_iter_arguments_get(variant, "as", &array)) if (!eldbus_message_iter_arguments_get(variant, "as", &array))
{ {
@ -426,6 +417,19 @@ e_dbusmenu_event_send(E_DBusMenu_Item *m, E_DBusMenu_Item_Event event)
eldbus_proxy_send(m->ctx->proxy, msg, NULL, NULL, -1); eldbus_proxy_send(m->ctx->proxy, msg, NULL, NULL, -1);
} }
E_API void
e_dbusmenu_item_ref(E_DBusMenu_Item *m)
{
m->references++;
}
E_API void
e_dbusmenu_item_unref(E_DBusMenu_Item *m)
{
m->references--;
if (m->references == 0) dbus_menu_free(m);
}
E_API void E_API void
e_dbusmenu_unload(E_DBusMenu_Ctx *ctx) e_dbusmenu_unload(E_DBusMenu_Ctx *ctx)
{ {
@ -433,8 +437,7 @@ e_dbusmenu_unload(E_DBusMenu_Ctx *ctx)
Eldbus_Object *obj; Eldbus_Object *obj;
EINA_SAFETY_ON_NULL_RETURN(ctx); EINA_SAFETY_ON_NULL_RETURN(ctx);
if (ctx->root_menu) if (ctx->root_menu) e_dbusmenu_item_unref(ctx->root_menu);
dbus_menu_free(ctx->root_menu);
obj = eldbus_proxy_object_get(ctx->proxy); obj = eldbus_proxy_object_get(ctx->proxy);
conn = eldbus_object_connection_get(obj); conn = eldbus_object_connection_get(obj);
eldbus_proxy_unref(ctx->proxy); eldbus_proxy_unref(ctx->proxy);

View File

@ -40,8 +40,10 @@ typedef struct _E_DBusMenu_Ctx E_DBusMenu_Ctx;
struct _E_DBusMenu_Item struct _E_DBusMenu_Item
{ {
EINA_INLIST; EINA_INLIST;
unsigned revision; unsigned int revision;
int id; int id;
unsigned int icon_data_size;
int references;
const char *label; const char *label;
E_DBusMenu_Item_Type type; E_DBusMenu_Item_Type type;
E_DBusMenu_Item_Toggle_Type toggle_type; E_DBusMenu_Item_Toggle_Type toggle_type;
@ -52,7 +54,6 @@ struct _E_DBusMenu_Item
Eina_Bool is_submenu; Eina_Bool is_submenu;
const char *icon_name; const char *icon_name;
unsigned char *icon_data; unsigned char *icon_data;
unsigned icon_data_size;
Eina_Inlist *sub_items; Eina_Inlist *sub_items;
E_DBusMenu_Item *parent; E_DBusMenu_Item *parent;
E_DBusMenu_Ctx *ctx; E_DBusMenu_Ctx *ctx;
@ -67,5 +68,7 @@ E_API void e_dbusmenu_update_cb_set(E_DBusMenu_Ctx *menu_data, E_DBusMenu_Update
E_API void e_dbusmenu_pop_request_cb_set(E_DBusMenu_Ctx *menu_data, E_DBusMenu_Pop_Request_Cb cb); E_API void e_dbusmenu_pop_request_cb_set(E_DBusMenu_Ctx *menu_data, E_DBusMenu_Pop_Request_Cb cb);
E_API void e_dbusmenu_event_send(E_DBusMenu_Item *m, E_DBusMenu_Item_Event event); E_API void e_dbusmenu_event_send(E_DBusMenu_Item *m, E_DBusMenu_Item_Event event);
E_API void e_dbusmenu_item_ref(E_DBusMenu_Item *m);
E_API void e_dbusmenu_item_unref(E_DBusMenu_Item *m);
#endif #endif

View File

@ -45,8 +45,22 @@ menu_deactive(E_Menu *m)
{ {
Eina_List *iter; Eina_List *iter;
E_Menu_Item *mi; E_Menu_Item *mi;
E_DBusMenu_Item *item;
item = e_object_data_get(E_OBJECT(m));
if (item)
{
e_object_data_set(E_OBJECT(m), NULL);
e_dbusmenu_item_unref(item);
}
EINA_LIST_FOREACH(m->items, iter, mi) EINA_LIST_FOREACH(m->items, iter, mi)
{ {
item = e_object_data_get(E_OBJECT(mi));
if (item)
{
e_object_data_set(E_OBJECT(m), NULL);
e_dbusmenu_item_unref(item);
}
if (mi->submenu) if (mi->submenu)
{ {
menu_deactive(mi->submenu); menu_deactive(mi->submenu);
@ -81,15 +95,17 @@ item_submenu_new(E_DBusMenu_Item *item, E_Menu_Item *mi)
m = e_menu_new(); m = e_menu_new();
EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
if (mi) e_dbusmenu_item_ref(item);
e_menu_item_submenu_set(mi, m); e_object_data_set(E_OBJECT(m), item);
if (mi) e_menu_item_submenu_set(mi, m);
EINA_INLIST_FOREACH(item->sub_items, child) EINA_INLIST_FOREACH(item->sub_items, child)
{ {
E_Menu_Item *submi; E_Menu_Item *submi;
if (!child->visible) if (!child->visible) continue;
continue;
submi = e_menu_item_new(m); submi = e_menu_item_new(m);
e_dbusmenu_item_ref(child);
e_object_data_set(E_OBJECT(submi), child);
if (child->type == E_DBUSMENU_ITEM_TYPE_SEPARATOR) if (child->type == E_DBUSMENU_ITEM_TYPE_SEPARATOR)
{ {
e_menu_item_separator_set(submi, 1); e_menu_item_separator_set(submi, 1);
@ -97,8 +113,7 @@ item_submenu_new(E_DBusMenu_Item *item, E_Menu_Item *mi)
} }
e_menu_item_label_set(submi, child->label); e_menu_item_label_set(submi, child->label);
e_menu_item_callback_set(submi, sub_item_clicked_cb, child); e_menu_item_callback_set(submi, sub_item_clicked_cb, child);
if (!child->enabled) if (!child->enabled) e_menu_item_disabled_set(submi, 1);
e_menu_item_disabled_set(submi, 1);
if (child->toggle_type) if (child->toggle_type)
{ {
if (child->toggle_type == E_DBUSMENU_ITEM_TOGGLE_TYPE_CHECKMARK) if (child->toggle_type == E_DBUSMENU_ITEM_TOGGLE_TYPE_CHECKMARK)

View File

@ -130,13 +130,25 @@ _menu_post_deactivate(void *data, E_Menu *m)
Eina_List *iter; Eina_List *iter;
E_Menu_Item *mi; E_Menu_Item *mi;
E_Gadcon *gadcon = data; E_Gadcon *gadcon = data;
E_DBusMenu_Item *item;
if (gadcon) item = e_object_data_get(E_OBJECT(m));
e_gadcon_locked_set(gadcon, 0); if (item)
{
e_object_data_set(E_OBJECT(m), NULL);
e_dbusmenu_item_unref(item);
}
if (gadcon) e_gadcon_locked_set(gadcon, 0);
EINA_LIST_FOREACH(m->items, iter, mi) EINA_LIST_FOREACH(m->items, iter, mi)
{ {
if (mi->submenu) item = e_object_data_get(E_OBJECT(mi));
e_menu_deactivate(mi->submenu); if (item)
{
e_object_data_set(E_OBJECT(m), NULL);
e_dbusmenu_item_unref(item);
}
if (mi->submenu) e_menu_deactivate(mi->submenu);
} }
e_object_del(E_OBJECT(m)); e_object_del(E_OBJECT(m));
} }
@ -149,14 +161,17 @@ _item_submenu_new(E_DBusMenu_Item *item, E_Menu_Item *mi)
E_Menu_Item *submi; E_Menu_Item *submi;
m = e_menu_new(); m = e_menu_new();
e_dbusmenu_item_ref(item);
e_object_data_set(E_OBJECT(m), item);
e_menu_post_deactivate_callback_set(m, _menu_post_deactivate, NULL); e_menu_post_deactivate_callback_set(m, _menu_post_deactivate, NULL);
if (mi) if (mi) e_menu_item_submenu_set(mi, m);
e_menu_item_submenu_set(mi, m);
EINA_INLIST_FOREACH(item->sub_items, child) EINA_INLIST_FOREACH(item->sub_items, child)
{ {
if (!child->visible) continue; if (!child->visible) continue;
submi = e_menu_item_new(m); submi = e_menu_item_new(m);
e_dbusmenu_item_ref(child);
e_object_data_set(E_OBJECT(submi), child);
if (child->type == E_DBUSMENU_ITEM_TYPE_SEPARATOR) if (child->type == E_DBUSMENU_ITEM_TYPE_SEPARATOR)
e_menu_item_separator_set(submi, 1); e_menu_item_separator_set(submi, 1);
else else