raster pushed a commit to branch master.

http://git.enlightenment.org/core/enlightenment.git/commit/?id=df0a64dc7ad348935af9a57ed1bef62b7424db58

commit df0a64dc7ad348935af9a57ed1bef62b7424db58
Author: Carsten Haitzler (Rasterman) <[email protected]>
Date:   Wed Aug 7 00:43:47 2019 +0100

    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
---
 src/bin/e_dbusmenu.c                       | 89 +++++++++++++++---------------
 src/bin/e_dbusmenu.h                       |  7 ++-
 src/modules/appmenu/e_mod_appmenu_render.c | 27 +++++++--
 src/modules/systray/e_mod_notifier_host.c  | 27 +++++++--
 4 files changed, 93 insertions(+), 57 deletions(-)

diff --git a/src/bin/e_dbusmenu.c b/src/bin/e_dbusmenu.c
index b3e254987..5a94b9be8 100644
--- a/src/bin/e_dbusmenu.c
+++ b/src/bin/e_dbusmenu.c
@@ -37,11 +37,10 @@ static void proxy_init(E_DBusMenu_Ctx *ctx);
 static int
 id_find(const char *text, const char *array_of_names[], unsigned max)
 {
-   unsigned i;
+   unsigned int i;
    for (i = 0; i < max; i++)
      {
-        if (strcmp(text, array_of_names[i]))
-          continue;
+        if (strcmp(text, array_of_names[i])) continue;
         return i;
      }
    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_fixed_array_get(array, 'y', &img_data, &size);
-        if (!size)
-          return;
+        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);
@@ -114,19 +112,15 @@ dbus_menu_prop_dict_cb(void *data, const void *key, 
Eldbus_Message_Iter *var)
      {
         int state;
         eldbus_message_iter_arguments_get(var, "i", &state);
-        if (state == 1)
-          m->toggle_state = EINA_TRUE;
-        else
-          m->toggle_state = EINA_FALSE;
+        if (state == 1) m->toggle_state = EINA_TRUE;
+        else m->toggle_state = EINA_FALSE;
      }
    else if (!strcmp(key, "children-display"))
      {
         const char *display;
         eldbus_message_iter_arguments_get(var, "s", &display);
-        if (!strcmp(display, "submenu"))
-          m->is_submenu = EINA_TRUE;
-        else
-          m->is_submenu = EINA_FALSE;
+        if (!strcmp(display, "submenu")) m->is_submenu = EINA_TRUE;
+        else m->is_submenu = EINA_FALSE;
      }
    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;
    E_DBusMenu_Item *m = calloc(1, sizeof(E_DBusMenu_Item));
    EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
+   m->references = 1;
    m->ctx = ctx;
    m->enabled = 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);
      }
 
-   if (!parent)
-     return m;
+   if (!parent) return m;
 
    parent->sub_items = eina_inlist_append(parent->sub_items, 
EINA_INLIST_GET(m));
    m->parent = parent;
@@ -186,17 +180,21 @@ 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);
+     {
+        e_dbusmenu_item_unref(child);
+     }
+   EINA_INLIST_FREE(m->sub_items, child)
+     {
+        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);
 }
 
@@ -229,7 +227,7 @@ attempt_hacks(E_DBusMenu_Ctx *ctx)
    if ((unsigned int)(p - bus) > sizeof(buf) - 1) return EINA_FALSE;
    strncpy(buf, bus, p - bus);
    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_object_unref(obj);
 
@@ -267,15 +265,13 @@ layout_get_cb(void *data, const Eldbus_Message *msg, 
Eldbus_Pending *pending EIN
      {
         if (attempt_hacks(ctx))
           {
-             dbus_menu_free(m);
+             e_dbusmenu_item_unref(m);
              return;
           }
      }
 
-   if (ctx->update_cb)
-     ctx->update_cb(ctx->data, m);
-   if (ctx->root_menu)
-     dbus_menu_free(ctx->root_menu);
+   if (ctx->update_cb) ctx->update_cb(ctx->data, m);
+   if (ctx->root_menu) e_dbusmenu_item_unref(ctx->root_menu);
    ctx->root_menu = m;
 }
 
@@ -289,13 +285,11 @@ dbus_menu_find(E_DBusMenu_Ctx *ctx, int id)
    EINA_INLIST_FOREACH(ctx->root_menu, m)
      {
         E_DBusMenu_Item *child, *found;
-        if (m->id == id)
-          return m;
+        if (m->id == id) return m;
         EINA_INLIST_FOREACH(m->sub_items, child)
           {
              found = dbus_menu_find(ctx, id);
-             if (found)
-               return found;
+             if (found) return found;
           }
      }
    return NULL;
@@ -316,10 +310,8 @@ menu_pop_request(void *data, const Eldbus_Message *msg)
      }
 
    m = dbus_menu_find(ctx, id);
-   if (!m)
-     return;
-   if (ctx->pop_request_cb)
-     ctx->pop_request_cb(ctx->data, m);
+   if (!m) return;
+   if (ctx->pop_request_cb) ctx->pop_request_cb(ctx->data, m);
 }
 
 static void
@@ -334,8 +326,7 @@ prop_changed_cb(void *data EINA_UNUSED, const 
Eldbus_Message *msg)
         return;
      }
 
-   if (strcmp(propname, "IconThemePath"))
-     return;
+   if (strcmp(propname, "IconThemePath")) return;
 
    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);
 }
 
+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_dbusmenu_unload(E_DBusMenu_Ctx *ctx)
 {
@@ -433,8 +437,7 @@ e_dbusmenu_unload(E_DBusMenu_Ctx *ctx)
    Eldbus_Object *obj;
    EINA_SAFETY_ON_NULL_RETURN(ctx);
 
-   if (ctx->root_menu)
-     dbus_menu_free(ctx->root_menu);
+   if (ctx->root_menu) e_dbusmenu_item_unref(ctx->root_menu);
    obj = eldbus_proxy_object_get(ctx->proxy);
    conn = eldbus_object_connection_get(obj);
    eldbus_proxy_unref(ctx->proxy);
diff --git a/src/bin/e_dbusmenu.h b/src/bin/e_dbusmenu.h
index cbc9df45f..835c45ecf 100644
--- a/src/bin/e_dbusmenu.h
+++ b/src/bin/e_dbusmenu.h
@@ -40,8 +40,10 @@ typedef struct _E_DBusMenu_Ctx E_DBusMenu_Ctx;
 struct _E_DBusMenu_Item
 {
    EINA_INLIST;
-   unsigned revision;
+   unsigned int revision;
    int id;
+   unsigned int icon_data_size;
+   int references;
    const char *label;
    E_DBusMenu_Item_Type type;
    E_DBusMenu_Item_Toggle_Type toggle_type;
@@ -52,7 +54,6 @@ struct _E_DBusMenu_Item
    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 *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_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
diff --git a/src/modules/appmenu/e_mod_appmenu_render.c 
b/src/modules/appmenu/e_mod_appmenu_render.c
index 082181cde..32c424058 100644
--- a/src/modules/appmenu/e_mod_appmenu_render.c
+++ b/src/modules/appmenu/e_mod_appmenu_render.c
@@ -45,8 +45,22 @@ menu_deactive(E_Menu *m)
 {
    Eina_List *iter;
    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)
      {
+        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)
           {
              menu_deactive(mi->submenu);
@@ -81,15 +95,17 @@ item_submenu_new(E_DBusMenu_Item *item, E_Menu_Item *mi)
 
    m = e_menu_new();
    EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
-   if (mi)
-     e_menu_item_submenu_set(mi, m);
+   e_dbusmenu_item_ref(item);
+   e_object_data_set(E_OBJECT(m), item);
+   if (mi) e_menu_item_submenu_set(mi, m);
 
    EINA_INLIST_FOREACH(item->sub_items, child)
      {
         E_Menu_Item *submi;
-        if (!child->visible)
-          continue;
+        if (!child->visible) continue;
         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)
           {
              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_callback_set(submi, sub_item_clicked_cb, child);
-        if (!child->enabled)
-          e_menu_item_disabled_set(submi, 1);
+        if (!child->enabled) e_menu_item_disabled_set(submi, 1);
         if (child->toggle_type)
           {
              if (child->toggle_type == E_DBUSMENU_ITEM_TOGGLE_TYPE_CHECKMARK)
diff --git a/src/modules/systray/e_mod_notifier_host.c 
b/src/modules/systray/e_mod_notifier_host.c
index 46a239502..90f6929e2 100644
--- a/src/modules/systray/e_mod_notifier_host.c
+++ b/src/modules/systray/e_mod_notifier_host.c
@@ -130,13 +130,25 @@ _menu_post_deactivate(void *data, E_Menu *m)
    Eina_List *iter;
    E_Menu_Item *mi;
    E_Gadcon *gadcon = data;
+   E_DBusMenu_Item *item;
 
-   if (gadcon)
-     e_gadcon_locked_set(gadcon, 0);
+   item = e_object_data_get(E_OBJECT(m));
+   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)
      {
-        if (mi->submenu)
-          e_menu_deactivate(mi->submenu);
+        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) e_menu_deactivate(mi->submenu);
      }
    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;
 
    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);
-   if (mi)
-     e_menu_item_submenu_set(mi, m);
+   if (mi) e_menu_item_submenu_set(mi, m);
 
    EINA_INLIST_FOREACH(item->sub_items, child)
      {
         if (!child->visible) continue;
         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)
           e_menu_item_separator_set(submi, 1);
         else

-- 


Reply via email to