dwlb

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

commit bcca07fdc49189e59ff4b0222dc7c48ab5f3fbab
parent 1bb5070e109c023e719c0922bf1a4baa2d41b45a
Author: Janne Veteläinen <janne.vetelainen@elisanet.fi>
Date:   Fri, 17 May 2024 01:29:38 +0300

Freeze menu updates when popover is visible

Diffstat:
Msystray/sndbusmenu.c | 86++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Msystray/snhost.c | 2++
Msystray/snitem.c | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Msystray/snitem.h | 1+
4 files changed, 136 insertions(+), 26 deletions(-)

diff --git a/systray/sndbusmenu.c b/systray/sndbusmenu.c @@ -18,6 +18,7 @@ struct _SnDbusmenu { GDBusProxy *proxy; uint32_t revision; + gboolean reschedule; }; G_DEFINE_FINAL_TYPE(SnDbusmenu, sn_dbusmenu, G_TYPE_OBJECT) @@ -305,21 +306,64 @@ on_layout_updated(GDBusProxy *proxy, GAsyncResult *res, void *data) return; } - GVariant *layout; - GVariant *menuitems; + gboolean isvisible = sn_item_get_popover_visible(dbusmenu->snitem); + char status[1024]; - layout = g_variant_get_child_value(retvariant, 1); - menuitems = g_variant_get_child_value(layout, 2); + if (isvisible) + strcpy(status, "visible"); + else + strcpy(status, "notvisibile"); - GMenu *newmenu = create_menumodel(menuitems, dbusmenu); - sn_item_set_menu_model(dbusmenu->snitem, newmenu); + if (isvisible) { + dbusmenu->reschedule = TRUE; + g_debug("Popover was visible, couldn't update menu %s", dbusmenu->busname); + } else { + + g_debug("Running menu update: name %s, revision %i\n \ + popover status: %s", + dbusmenu->busname, + dbusmenu->revision, + status); + + GVariant *layout; + GVariant *menuitems; + + layout = g_variant_get_child_value(retvariant, 1); + menuitems = g_variant_get_child_value(layout, 2); + + GMenu *newmenu = create_menumodel(menuitems, dbusmenu); + sn_item_set_menu_model(dbusmenu->snitem, newmenu); + g_variant_unref(menuitems); + g_variant_unref(layout); + } - g_variant_unref(menuitems); - g_variant_unref(layout); g_variant_unref(retvariant); g_object_unref(dbusmenu); } +void +reschedule_update(SnItem *snitem, GParamSpec *pspec, void *data) +{ + SnDbusmenu *dbusmenu = SN_DBUSMENU(data); + + gboolean popover_visible = sn_item_get_popover_visible(snitem); + if (popover_visible || !dbusmenu->reschedule) + return; + + + dbusmenu->reschedule = FALSE; + + g_debug("sending reschedule call %s", dbusmenu->busname); + g_dbus_proxy_call(dbusmenu->proxy, + "GetLayout", + g_variant_new("(iias)", 0, -1, NULL), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + (GAsyncReadyCallback)on_layout_updated, + g_object_ref(dbusmenu)); +} + // We just rebuild the entire menu every time... // ItemsPropertiesUpdated signal would carry data of @@ -333,17 +377,26 @@ on_menuproxy_signal(GDBusProxy *proxy, void *data) { SnDbusmenu *dbusmenu = SN_DBUSMENU(data); + + // Stop updates when popover is visible + gboolean popover_visible = sn_item_get_popover_visible(dbusmenu->snitem); + if (strcmp(signal, "LayoutUpdated") == 0) { - uint32_t revision = UINT32_MAX; + uint32_t revision; int32_t parentid; g_variant_get(params, "(ui)", &revision, &parentid); if (dbusmenu->revision != UINT32_MAX && revision <= dbusmenu->revision) { - // g_debug("%s got %s, but menurevision didn't change. Ignoring\n", snitem->busname, signal); + g_debug("early return on signal %s, reason: revision", dbusmenu->busname); + return; + } else if (popover_visible) { + g_debug("early return on signal %s, reason: popover visible", dbusmenu->busname); + dbusmenu->reschedule = TRUE; return; - } else { - dbusmenu->revision = revision; } + dbusmenu->revision = revision; + + g_debug("sending menuupdate call %s", dbusmenu->busname); g_dbus_proxy_call(dbusmenu->proxy, "GetLayout", g_variant_new("(iias)", 0, -1, NULL), @@ -354,6 +407,12 @@ on_menuproxy_signal(GDBusProxy *proxy, g_object_ref(dbusmenu)); } else if (strcmp(signal, "ItemsPropertiesUpdated") == 0) { + if (popover_visible) { + g_debug("early return on signal %s, reason: popover visible", dbusmenu->busname); + dbusmenu->reschedule = TRUE; + return; + } + g_debug("sending menuupdate call %s", dbusmenu->busname); g_dbus_proxy_call(dbusmenu->proxy, "GetLayout", g_variant_new("(iias)", 0, -1, NULL), @@ -524,6 +583,7 @@ menuproxy_ready_cb(GObject *obj, GAsyncResult *res, void *data) static void sn_dbusmenu_init(SnDbusmenu *self) { + self->reschedule = FALSE; } static void @@ -543,6 +603,8 @@ sn_dbusmenu_constructed(GObject *obj) g_object_ref(self)); g_dbus_node_info_unref(nodeinfo); + g_signal_connect(self->snitem, "notify::menuvisible", G_CALLBACK(reschedule_update), self); + G_OBJECT_CLASS(sn_dbusmenu_parent_class)->constructed(obj); } diff --git a/systray/snhost.c b/systray/snhost.c @@ -147,8 +147,10 @@ sn_host_unregister_item(SnHost *self, SnItem *snitem) self->trayitems = g_slist_remove(self->trayitems, snitem); + g_object_ref(snitem); gtk_box_remove(GTK_BOX(self), GTK_WIDGET(snitem)); g_object_run_dispose(G_OBJECT(snitem)); + g_object_unref(snitem); self->nitems = self->nitems - 1; diff --git a/systray/snitem.c b/systray/snitem.c @@ -29,6 +29,7 @@ struct _SnItem gboolean ready; gboolean exiting; + gboolean menu_visible; }; G_DEFINE_FINAL_TYPE(SnItem, sn_item, GTK_TYPE_WIDGET) @@ -41,6 +42,7 @@ enum PROP_PROXY, PROP_ACTIONGROUP, PROP_DBUSMENU, + PROP_MENUVISIBLE, N_PROPERTIES }; @@ -384,6 +386,22 @@ sn_item_proxy_ready_handler(GObject *obj, GAsyncResult *res, void *data) g_object_unref(self); } +void +sn_item_popup(SnItem *self) +{ + g_object_set(self, "menuvisible", TRUE, NULL); + g_debug("popping up %s", self->busname); + gtk_popover_popup(GTK_POPOVER(self->popovermenu)); +} + +void +sn_item_notify_closed(GtkPopover *popover, void *data) +{ + SnItem *self = SN_ITEM(data); + g_object_set(self, "menuvisible", FALSE, NULL); +} + + static void sn_item_leftclick_handler(GtkGestureClick *click, int n_press, @@ -428,8 +446,7 @@ sn_item_rightclick_handler_helper(GObject *obj, GAsyncResult *res, void *data) g_strrstr(err->message, "error occured in AboutToShow") == 0) { g_error_free(err); - gtk_popover_popup(GTK_POPOVER(self->popovermenu)); - + sn_item_popup(self); // Report rest of possible errors } else if (err) { g_warning("%s\n", err->message); @@ -438,7 +455,7 @@ sn_item_rightclick_handler_helper(GObject *obj, GAsyncResult *res, void *data) } else { g_variant_unref(val); - gtk_popover_popup(GTK_POPOVER(self->popovermenu)); + sn_item_popup(self); } g_object_unref(self); @@ -470,13 +487,14 @@ sn_item_rightclick_handler(GtkGestureClick *click, g_object_unref(menuproxy); } -static void sn_item_measure(GtkWidget *widget, - GtkOrientation orientation, - int for_size, - int *minimum, - int *natural, - int *minimum_baseline, - int *natural_baseline) +static void +sn_item_measure(GtkWidget *widget, + GtkOrientation orientation, + int for_size, + int *minimum, + int *natural, + int *minimum_baseline, + int *natural_baseline) { SnItem *self = SN_ITEM(widget); @@ -496,10 +514,11 @@ static void sn_item_measure(GtkWidget *widget, } } -static void sn_item_size_allocate(GtkWidget *widget, - int width, - int height, - int baseline) +static void +sn_item_size_allocate(GtkWidget *widget, + int width, + int height, + int baseline) { SnItem *self = SN_ITEM(widget); gtk_widget_size_allocate(self->image, &(GtkAllocation) {0, 0, width, height}, -1); @@ -530,6 +549,9 @@ sn_item_set_property(GObject *object, uint property_id, const GValue *value, GPa case PROP_DBUSMENU: self->dbusmenu = g_value_get_object(value); break; + case PROP_MENUVISIBLE: + self->menu_visible = g_value_get_boolean(value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); } @@ -556,6 +578,9 @@ sn_item_get_property(GObject *object, uint property_id, GValue *value, GParamSpe case PROP_DBUSMENU: g_value_set_object(value, self->dbusmenu); break; + case PROP_MENUVISIBLE: + g_value_set_boolean(value, self->menu_visible); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); } @@ -608,6 +633,13 @@ sn_item_class_init(SnItemClass *klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_MENUVISIBLE] = + g_param_spec_boolean("menuvisible", NULL, NULL, + FALSE, + G_PARAM_CONSTRUCT | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + widget_class->measure = sn_item_measure; widget_class->size_allocate = sn_item_size_allocate; @@ -659,6 +691,8 @@ sn_item_init(SnItem *self) gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(rightclick), 3); g_signal_connect(rightclick, "pressed", G_CALLBACK(sn_item_rightclick_handler), self); gtk_widget_add_controller(widget, GTK_EVENT_CONTROLLER(rightclick)); + + g_signal_connect(self->popovermenu, "closed", G_CALLBACK(sn_item_notify_closed), self); } static void @@ -687,6 +721,7 @@ sn_item_dispose(GObject *obj) { SnItem *self = SN_ITEM(obj); self->exiting = TRUE; + gtk_popover_popdown(GTK_POPOVER(self->popovermenu)); g_debug("Disposing snitem %s %s", self->busname, self->busobj); @@ -756,6 +791,16 @@ sn_item_get_busname(SnItem *self) return busname; } +gboolean +sn_item_get_popover_visible(SnItem *self) +{ + gboolean visible; + + g_object_get(self, "menuvisible", &visible, NULL); + + return visible; +} + SnItem* sn_item_new(const char *busname, const char *busobj, int iconsize) { diff --git a/systray/snitem.h b/systray/snitem.h @@ -16,6 +16,7 @@ SnItem* sn_item_new (const char *busname, void sn_item_set_menu_model (SnItem *widget, GMenu *menu); void sn_item_add_action (SnItem *self, GSimpleAction *action); char* sn_item_get_busname (SnItem *self); +gboolean sn_item_get_popover_visible (SnItem *self); G_END_DECLS