dwlb

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

commit 08db85ee4882d9b51e589f58e5fa258cb74b7bca
parent c7f278b85ef9d554586ebec0007fc439eee546f7
Author: Janne Veteläinen <janne.vetelainen@elisanet.fi>
Date:   Tue, 21 May 2024 02:24:38 +0300

Delay popup for 100ms to catch possible pending update

Diffstat:
Msystray/sndbusmenu.c | 316++++++++++++++++++++++++++++++++++++-------------------------------------------
1 file changed, 144 insertions(+), 172 deletions(-)

diff --git a/systray/sndbusmenu.c b/systray/sndbusmenu.c @@ -20,7 +20,6 @@ struct _SnDbusmenu { uint32_t revision; gboolean reschedule; - gboolean updating; }; G_DEFINE_FINAL_TYPE(SnDbusmenu, sn_dbusmenu, G_TYPE_OBJECT) @@ -138,7 +137,7 @@ get_n_sections(GVariant *data) */ static void -action_activated_cb(GSimpleAction *action, GVariant* param, ActionCallbackData *data) +action_activated_handler(GSimpleAction *action, GVariant* param, ActionCallbackData *data) { g_dbus_proxy_call(data->proxy, "Event", @@ -173,7 +172,7 @@ create_action(uint32_t id, SnDbusmenu *self) g_signal_connect_data(action, "activate", - G_CALLBACK(action_activated_cb), + G_CALLBACK(action_activated_handler), data, action_free, G_CONNECT_DEFAULT); @@ -318,12 +317,12 @@ create_menumodel(GVariant *data, SnDbusmenu *self) } static void -on_layout_updated(GDBusProxy *proxy, GAsyncResult *res, void *data) +layout_updated_handler(GObject *obj, GAsyncResult *res, void *data) { - SnDbusmenu *dbusmenu = SN_DBUSMENU(data); + SnDbusmenu *self = SN_DBUSMENU(data); GError *err = NULL; - GVariant *retvariant = g_dbus_proxy_call_finish(proxy, res, &err); + GVariant *retvariant = g_dbus_proxy_call_finish(self->proxy, res, &err); // Errors which might occur when the tray is running slowly (eg under valgrind) // and user is spam clicking already exited icons @@ -331,161 +330,132 @@ on_layout_updated(GDBusProxy *proxy, GAsyncResult *res, void *data) // "No such object path '/MenuBar' if (err && g_error_matches(err, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_OBJECT)) { g_error_free(err); - dbusmenu->updating = FALSE; - g_object_unref(dbusmenu); + g_object_unref(self); return; // "The name is not activatable" } else if (err && g_error_matches(err, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)) { g_error_free(err); - dbusmenu->updating = FALSE; - g_object_unref(dbusmenu); + g_object_unref(self); return; // "Remote peer disconnected" } else if (err && g_error_matches(err, G_DBUS_ERROR, G_DBUS_ERROR_NO_REPLY)) { g_error_free(err); - dbusmenu->updating = FALSE; - g_object_unref(dbusmenu); + g_object_unref(self); return; } else if (err) { g_warning("%s\n", err->message); g_error_free(err); - dbusmenu->updating = FALSE; - g_object_unref(dbusmenu); + g_object_unref(self); return; } - gboolean isvisible = sn_item_get_popover_visible(dbusmenu->snitem); - char status[1024]; + GVariant *layout; + GVariant *menuitems; - if (isvisible) - strcpy(status, "visible"); - else - strcpy(status, "notvisibile"); + layout = g_variant_get_child_value(retvariant, 1); + menuitems = g_variant_get_child_value(layout, 2); + GMenu *newmenu = create_menumodel(menuitems, self); + + gboolean isvisible = sn_item_get_popover_visible(self->snitem); if (isvisible) { - dbusmenu->reschedule = TRUE; - g_debug("Popover was visible, couldn't update menu %s", dbusmenu->busname); + self->reschedule = TRUE; + g_debug("Popover was visible, couldn't update menu %s", self->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); + sn_item_set_menu_model(self->snitem, newmenu); } + g_object_unref(newmenu); + g_variant_unref(menuitems); + g_variant_unref(layout); + g_variant_unref(retvariant); - dbusmenu->updating = FALSE; - g_object_unref(dbusmenu); + g_object_unref(self); } void reschedule_update(SnItem *snitem, GParamSpec *pspec, void *data) { - SnDbusmenu *dbusmenu = SN_DBUSMENU(data); + SnDbusmenu *self = SN_DBUSMENU(data); gboolean popover_visible = sn_item_get_popover_visible(snitem); - if (popover_visible || !dbusmenu->reschedule) + if (popover_visible || !self->reschedule) return; + self->reschedule = FALSE; - dbusmenu->reschedule = FALSE; - - g_debug("sending reschedule call %s", dbusmenu->busname); - dbusmenu->updating = TRUE; - g_dbus_proxy_call(dbusmenu->proxy, + g_dbus_proxy_call(self->proxy, "GetLayout", g_variant_new("(iias)", 0, -1, NULL), G_DBUS_CALL_FLAGS_NONE, -1, NULL, - (GAsyncReadyCallback)on_layout_updated, - g_object_ref(dbusmenu)); + (GAsyncReadyCallback)layout_updated_handler, + g_object_ref(self)); } -// We just rebuild the entire menu every time... -// ItemsPropertiesUpdated signal would carry data of -// which menuitems got updated and which got removed -// but the GMenu api doesn't allow easy manipulation as it is +// TODO: Optimize this, lots of unneccessary work being done. static void -on_menuproxy_signal(GDBusProxy *proxy, - const char *sender, - const char *signal, - GVariant *params, - void *data) +proxy_signal_handler(GDBusProxy *proxy, + const char *sender, + const char *signal, + GVariant *params, + void *data) { - SnDbusmenu *dbusmenu = SN_DBUSMENU(data); + SnDbusmenu *self = SN_DBUSMENU(data); // Stop updates when popover is visible - gboolean popover_visible = sn_item_get_popover_visible(dbusmenu->snitem); + gboolean popover_visible = sn_item_get_popover_visible(self->snitem); if (strcmp(signal, "LayoutUpdated") == 0) { uint32_t revision; int32_t parentid; g_variant_get(params, "(ui)", &revision, &parentid); - if (dbusmenu->revision != UINT32_MAX && revision <= dbusmenu->revision) { - g_debug("early return on signal %s, reason: revision", dbusmenu->busname); + if (self->revision != UINT32_MAX && revision <= self->revision) { return; } else if (popover_visible) { - g_debug("early return on signal %s, reason: popover visible", dbusmenu->busname); - dbusmenu->reschedule = TRUE; + self->reschedule = TRUE; return; } - dbusmenu->revision = revision; + self->revision = revision; - g_debug("sending menuupdate call %s", dbusmenu->busname); - dbusmenu->updating = TRUE; - g_dbus_proxy_call(dbusmenu->proxy, + g_dbus_proxy_call(self->proxy, "GetLayout", g_variant_new("(iias)", 0, -1, NULL), G_DBUS_CALL_FLAGS_NONE, -1, NULL, - (GAsyncReadyCallback)on_layout_updated, - g_object_ref(dbusmenu)); + layout_updated_handler, + g_object_ref(self)); } else if (strcmp(signal, "ItemsPropertiesUpdated") == 0) { if (popover_visible) { - g_debug("early return on signal %s, reason: popover visible", dbusmenu->busname); - dbusmenu->reschedule = TRUE; + self->reschedule = TRUE; return; } - g_debug("sending menuupdate call %s", dbusmenu->busname); - dbusmenu->updating = TRUE; - g_dbus_proxy_call(dbusmenu->proxy, + g_dbus_proxy_call(self->proxy, "GetLayout", g_variant_new("(iias)", 0, -1, NULL), G_DBUS_CALL_FLAGS_NONE, -1, NULL, - (GAsyncReadyCallback)on_layout_updated, - g_object_ref(dbusmenu)); + layout_updated_handler, + g_object_ref(self)); } } static void -on_menulayout_ready(GDBusProxy *proxy, GAsyncResult *res, void *data) +menulayout_ready_handler(GObject *obj, GAsyncResult *res, void *data) { - SnDbusmenu *dbusmenu = SN_DBUSMENU(data); + SnDbusmenu *self = SN_DBUSMENU(data); GError *err = NULL; - GVariant *retvariant = g_dbus_proxy_call_finish(proxy, res, &err); + GVariant *retvariant = g_dbus_proxy_call_finish(self->proxy, res, &err); // (u(ia{sv}av)) // "No such object path '/NO_DBUSMENU'" @@ -493,12 +463,12 @@ on_menulayout_ready(GDBusProxy *proxy, GAsyncResult *res, void *data) // and replaces it later if (err && g_error_matches(err, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_OBJECT)) { g_error_free(err); - g_object_unref(dbusmenu); + g_object_unref(self); return; } else if (err) { g_warning("%s\n", err->message); g_error_free(err); - g_object_unref(dbusmenu); + g_object_unref(self); return; } @@ -511,14 +481,99 @@ on_menulayout_ready(GDBusProxy *proxy, GAsyncResult *res, void *data) layout = g_variant_get_child_value(retvariant, 1); menuitems = g_variant_get_child_value(layout, 2); - GMenu *menu = create_menumodel(menuitems, dbusmenu); - sn_item_set_menu_model(dbusmenu->snitem, menu); + GMenu *menu = create_menumodel(menuitems, self); + sn_item_set_menu_model(self->snitem, menu); g_object_unref(menu); g_variant_unref(menuitems); g_variant_unref(layout); g_variant_unref(retvariant); - g_object_unref(dbusmenu); + g_object_unref(self); +} + +static void +about_to_show_timeout_handler(void *data) +{ + SnDbusmenu *self = SN_DBUSMENU(data); + + g_signal_emit(self, signals[ABOUT_TO_SHOW_HANDLED], 0); + g_object_unref(self); +} + +static void +about_to_show_handler(GObject *obj, GAsyncResult *res, void *data) +{ + SnDbusmenu *self = SN_DBUSMENU(data); + + GError *err = NULL; + GVariant *val = g_dbus_proxy_call_finish(self->proxy, res, &err); + + // Discord generates the following error here: + // 'G_DBUS_ERROR' 'G_DBUS_ERROR_FAILED' 'error occurred in AboutToShow' + // We ignore it. + if (err && !g_error_matches(err, G_DBUS_ERROR, G_DBUS_ERROR_FAILED) && + g_strrstr(err->message, "error occured in AboutToShow") != 0) { + g_warning("%s\n", err->message); + + } else { + // This dbusmenu call might have triggered a menu update, + // give it a chance to finish. nm-applet update takes 60ms, give 100ms. + g_timeout_add_once(100, about_to_show_timeout_handler, g_object_ref(self)); + } + + err ? g_error_free(err) : g_variant_unref(val); + g_object_unref(self); +} + + +static void +rightclick_handler(GObject *obj, void *data) +{ + SnDbusmenu *self = SN_DBUSMENU(data); + + g_assert(SN_IS_DBUSMENU(self)); + g_dbus_proxy_call(self->proxy, + "AboutToShow", + g_variant_new("(i)", 0), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + about_to_show_handler, + g_object_ref(self)); +} + +static void +proxy_ready_handler(GObject *obj, GAsyncResult *res, void *data) +{ + SnDbusmenu *self = SN_DBUSMENU(data); + + GError *err = NULL; + GDBusProxy *proxy = g_dbus_proxy_new_for_bus_finish(res, &err); + + if (err) { + g_warning("Failed to construct gdbusproxy for menu: %s\n", err->message); + g_error_free(err); + g_object_unref(self); + return; + } + + g_debug("Created gdbusproxy for menu %s %s", + g_dbus_proxy_get_name(proxy), + g_dbus_proxy_get_object_path(proxy)); + + g_object_set(self, "proxy", proxy, NULL); + + g_dbus_proxy_call(self->proxy, + "GetLayout", + g_variant_new ("(iias)", 0, -1, NULL), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + menulayout_ready_handler, + g_object_ref(self)); + + g_signal_connect(self->proxy, "g-signal", G_CALLBACK(proxy_signal_handler), self); + g_object_unref(self); } static void @@ -601,93 +656,10 @@ sn_dbusmenu_class_init(SnDbusmenuClass *klass) } static void -menuproxy_ready_cb(GObject *obj, GAsyncResult *res, void *data) -{ - SnDbusmenu *self = SN_DBUSMENU(data); - - GError *err = NULL; - GDBusProxy *proxy = g_dbus_proxy_new_for_bus_finish(res, &err); - - if (err) { - g_warning("Failed to construct gdbusproxy for menu: %s\n", err->message); - g_error_free(err); - g_object_unref(self); - return; - } - - g_debug("Created gdbusproxy for menu %s %s", - g_dbus_proxy_get_name(proxy), - g_dbus_proxy_get_object_path(proxy)); - - g_object_set(self, "proxy", proxy, NULL); - - g_dbus_proxy_call(self->proxy, - "GetLayout", - g_variant_new ("(iias)", 0, -1, NULL), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - (GAsyncReadyCallback)on_menulayout_ready, - g_object_ref(self)); - - g_signal_connect(self->proxy, "g-signal", G_CALLBACK(on_menuproxy_signal), self); - g_object_unref(self); -} - -static void sn_dbusmenu_init(SnDbusmenu *self) { + // When reschedule is TRUE, menu will be updated next time it is closed. self->reschedule = FALSE; - self->updating = FALSE; -} - -static void -on_timeout(void *data) -{ - SnDbusmenu *self = SN_DBUSMENU(data); - g_signal_emit(self, signals[ABOUT_TO_SHOW_HANDLED], 0); - g_object_unref(self); -} - -static void -about_to_show_handler(GObject *obj, GAsyncResult *res, void *data) -{ - SnDbusmenu *self = SN_DBUSMENU(data); - - GError *err = NULL; - GVariant *val = g_dbus_proxy_call_finish(self->proxy, res, &err); - - // Discord generates the following error here: - // 'G_DBUS_ERROR' 'G_DBUS_ERROR_FAILED' 'error occurred in AboutToShow' - // We ignore it. - if (err && !g_error_matches(err, G_DBUS_ERROR, G_DBUS_ERROR_FAILED) && - g_strrstr(err->message, "error occured in AboutToShow") != 0) { - g_warning("%s\n", err->message); - - } else { - // This dbusmenu call might have triggered a menu update, - // give it a chance to finish. - g_timeout_add_once(200, on_timeout, g_object_ref(self)); - } - - err ? g_error_free(err) : g_variant_unref(val); - g_object_unref(self); -} - - -static void -about_to_show_request(GObject *obj, void *data) -{ - SnDbusmenu *self = SN_DBUSMENU(data); - g_assert(SN_IS_DBUSMENU(self)); - g_dbus_proxy_call(self->proxy, - "AboutToShow", - g_variant_new("(i)", 0), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - about_to_show_handler, - g_object_ref(self)); } static void @@ -703,13 +675,13 @@ sn_dbusmenu_constructed(GObject *obj) self->busobj, "com.canonical.dbusmenu", NULL, - (GAsyncReadyCallback)menuproxy_ready_cb, + (GAsyncReadyCallback)proxy_ready_handler, g_object_ref(self)); g_dbus_node_info_unref(nodeinfo); g_signal_connect(self->snitem, "notify::menuvisible", G_CALLBACK(reschedule_update), self); - g_signal_connect(self->snitem, "rightclick", G_CALLBACK(about_to_show_request), self); + g_signal_connect(self->snitem, "rightclick", G_CALLBACK(rightclick_handler), self); G_OBJECT_CLASS(sn_dbusmenu_parent_class)->constructed(obj); }