dwlb

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 6ac814595fcfed4b54d103b84e1851d3737db24b
parent af603e19de7ba882b924df0fa30376b1b8336f3b
Author: Janne Veteläinen <janne.vetelainen@elisanet.fi>
Date:   Mon, 24 Jun 2024 19:11:47 +0300

Go back to updating entire layout on updates

This is simpler and incremental updates didn't fix the problem (cannot update menu while popover is visible)

Diffstat:
Msystray/sndbusmenu.c | 139+++++++++++++++++++------------------------------------------------------------
1 file changed, 33 insertions(+), 106 deletions(-)

diff --git a/systray/sndbusmenu.c b/systray/sndbusmenu.c @@ -14,8 +14,6 @@ struct _SnDbusmenu { GObject parent_instance; - GMutex mutex; - char* busname; char* busobj; SnItem* snitem; @@ -24,6 +22,7 @@ struct _SnDbusmenu { GDBusProxy* proxy; uint32_t revision; + gboolean update_pending; gboolean reschedule; }; @@ -232,6 +231,9 @@ layout_update(SnDbusmenu *self) { GError *err = NULL; + g_debug("%s running menu layout update", self->busname); + self->update_pending = FALSE; + GVariant *data = g_dbus_proxy_call_sync(self->proxy, "GetLayout", g_variant_new("(iias)", 0, -1, NULL), @@ -258,15 +260,19 @@ layout_update(SnDbusmenu *self) self->reschedule = TRUE; g_debug("Popover was visible, couldn't update menu %s", self->busname); } else { + GMenu *newmenu = create_menumodel(menuitems, self); + // sn_item_remove_all_actions(self->snitem); + sn_item_set_menu_model(self->snitem, newmenu); g_object_unref(self->menu); - sn_item_remove_all_actions(self->snitem); self->menu = create_menumodel(menuitems, self); - sn_item_set_menu_model(self->snitem, self->menu); } g_variant_unref(menuitems); g_variant_unref(layout); g_variant_unref(data); + + g_object_unref(self->snitem); + g_object_unref(self); } static void @@ -280,94 +286,19 @@ reschedule_update(SnItem *snitem, GParamSpec *pspec, void *data) if (popover_visible || !self->reschedule) return; + g_debug("%s rescheduling layout update", self->busname); + self->reschedule = FALSE; + g_object_ref(self); g_object_ref(self->snitem); layout_update(self); - g_object_unref(self->snitem); -} - -static gboolean -find_menuid(GMenuModel *menu, int id, GVariant *menu_data, SnDbusmenu *self) -{ - gboolean ret = FALSE; - - g_assert(G_IS_MENU_MODEL(menu)); - int len = g_menu_model_get_n_items(menu); - - int idattr; - for (int i = 0; i < len; i++) { - GMenuModel *submenu = g_menu_model_get_item_link(menu, i, G_MENU_LINK_SUBMENU); - if (submenu) { - ret = find_menuid(submenu, id, menu_data, self); - g_object_unref(submenu); - } - - if (!ret) { - g_menu_model_get_item_attribute(menu, i, "itemid", "i", &idattr); - if (idattr == id) { - GMenuModel *link = g_menu_model_get_item_link(menu, i, G_MENU_LINK_SUBMENU); - g_menu_remove(G_MENU(menu), i); - if (menu_data) { - GMenuItem *item = create_menuitem(id, menu_data, NULL, self); - if (item && link) - g_menu_item_set_link(item, G_MENU_LINK_SUBMENU, link); - if (item) { - g_menu_insert_item(G_MENU(menu), i, item); - g_object_unref(item); - } - } - if (link) - g_object_unref(link); - - ret = TRUE; - break; - } - } - } - - return ret; -} - -static void -props_removed_handler(GVariant *props, SnDbusmenu *self) -{ - // a(ias) - GVariant *data; - GMenuModel *menu = G_MENU_MODEL(self->menu); - int id; - - GVariantIter iter; - g_variant_iter_init(&iter, props); - while ((data = g_variant_iter_next_value(&iter))) { - g_variant_get_child(data, 0, "i", &id); - find_menuid(menu, id, NULL, self); - char *action_name = g_strdup_printf("menuitem.%i", id); - sn_item_remove_action(self->snitem, action_name); - g_free(action_name); - g_variant_unref(data); - } } -static void -props_updated_handler(GVariant *props, SnDbusmenu *self) -{ - // a(ia{sv}) - GVariant *data; - GMenuModel *menu = G_MENU_MODEL(self->menu); - int id; - GVariant *menuitem_data; +// Update signals are often received multiple times in row, +// we throttle update frequency to 100ms - GVariantIter iter; - g_variant_iter_init(&iter, props); - while ((data = g_variant_iter_next_value(&iter))) { - g_variant_get_child(data, 0, "i", &id); - menuitem_data = g_variant_get_child_value(data, 1); - find_menuid(menu, id, menuitem_data, self); - g_variant_unref(menuitem_data); - g_variant_unref(data); - } -} +static const int update_freq = 100; static void proxy_signal_handler(GDBusProxy *proxy, @@ -380,39 +311,35 @@ proxy_signal_handler(GDBusProxy *proxy, g_return_if_fail(SN_IS_ITEM(self->snitem)); - g_mutex_lock(&self->mutex); - g_object_ref(self->snitem); - if (strcmp(signal, "LayoutUpdated") == 0) { - gboolean popover_visible = sn_item_get_popover_visible(self->snitem); - uint32_t revision; int32_t parentid; g_variant_get(params, "(ui)", &revision, &parentid); g_debug("%s got LayoutUpdated, revision %i, parentid %i", self->busname, revision, parentid); - if (!popover_visible && (self->revision == UINT32_MAX || self->revision < revision)) { - layout_update(self); + + if (self->revision == UINT32_MAX || self->revision < revision) { self->revision = revision; - } else if (popover_visible) { - self->reschedule = TRUE; + } + + if (!self->update_pending) { + self->update_pending = TRUE; + g_object_ref(self->snitem); + g_timeout_add_once(update_freq, (GSourceOnceFunc)layout_update, g_object_ref(self)); + } else { + g_debug("skipping update"); } } else if (strcmp(signal, "ItemsPropertiesUpdated") == 0) { g_debug("%s got ItemsPropertiesUpdated", self->busname); - GVariant *removed_props = g_variant_get_child_value(params, 1); - GVariant *updated_props = g_variant_get_child_value(params, 0); - if (removed_props) { - props_removed_handler(removed_props, self); - g_variant_unref(removed_props); - } - if (updated_props) { - props_updated_handler(updated_props, self); - g_variant_unref(updated_props); + if (!self->update_pending) { + self->update_pending = TRUE; + g_object_ref(self->snitem); + g_timeout_add_once(update_freq, (GSourceOnceFunc)layout_update, g_object_ref(self)); + } else { + g_debug("skipping update"); } } - g_object_unref(self->snitem); - g_mutex_unlock(&self->mutex); } static void @@ -442,7 +369,6 @@ menulayout_ready_handler(GObject *obj, GAsyncResult *res, void *data) GVariant *layout; GVariant *menuitems; - g_variant_get_child(retvariant, 0, "u", &revision); layout = g_variant_get_child_value(retvariant, 1); @@ -626,6 +552,7 @@ sn_dbusmenu_init(SnDbusmenu *self) { // When reschedule is TRUE, menu will be updated next time it is closed. self->reschedule = FALSE; + self->update_pending = FALSE; } static void