From 1549ec5f9b88df5a18437eafb2674f87fb6c2fab Mon Sep 17 00:00:00 2001 From: Alice Mikhaylenko Date: Thu, 1 Jun 2023 06:27:10 +0400 Subject: [PATCH] actionmuxer: Correctly notify actions after reparenting When registering an observer, we send a notification and for that we need to query the action's state and param type. When setting up a muxer parent, same thing happens, except the action is queried on the parent instead. This means that the muxer will notify observers about the parent's actions, but not about its own. Add a test to verify it works. Fixes https://gitlab.gnome.org/GNOME/gtk/-/issues/5861 --- gtk/gtkactionmuxer.c | 2 +- testsuite/gtk/action.c | 55 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/gtk/gtkactionmuxer.c b/gtk/gtkactionmuxer.c index 33e8c0542d..3bb0fb90b1 100644 --- a/gtk/gtkactionmuxer.c +++ b/gtk/gtkactionmuxer.c @@ -452,7 +452,7 @@ notify_observers_added (GtkActionMuxer *muxer, gtk_action_observable_register_observer (GTK_ACTION_OBSERVABLE (parent), action_name, GTK_ACTION_OBSERVER (muxer)); - if (!action_muxer_query_action (parent, action_name, + if (!action_muxer_query_action (muxer, action_name, &enabled, ¶meter_type, NULL, NULL, &state, TRUE)) diff --git a/testsuite/gtk/action.c b/testsuite/gtk/action.c index 95bb071d4b..d99b16c33b 100644 --- a/testsuite/gtk/action.c +++ b/testsuite/gtk/action.c @@ -717,6 +717,60 @@ test_enabled (void) g_object_unref (g_object_ref_sink (text)); } +#define MY_TYPE_GTK_ACTIONABLE (my_gtk_actionable_get_type ()) +G_DECLARE_FINAL_TYPE (MyGtkActionable, my_gtk_actionable, MY, GTK_ACTIONABLE, GtkButton) + +struct _MyGtkActionable +{ + GtkButton parent_instance; +}; + +G_DEFINE_FINAL_TYPE (MyGtkActionable, my_gtk_actionable, GTK_TYPE_BUTTON); + +static void +test_cb (GtkWidget *sender, + const char *name, + GVariant *param) +{ +} + +static void +my_gtk_actionable_init (MyGtkActionable *actionable) +{ + gtk_actionable_set_action_name (GTK_ACTIONABLE (actionable), "test.test"); +} + +static void +my_gtk_actionable_class_init (MyGtkActionableClass *klass) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + gtk_widget_class_install_action (widget_class, "test.test", NULL, test_cb); +} + +/* Test that actions are correctly notified after reparenting */ +static void +test_reparenting (void) +{ + GtkWidget *window, *actionable; + + window = gtk_window_new (); + + actionable = g_object_new (MY_TYPE_GTK_ACTIONABLE, NULL); + gtk_window_set_child (GTK_WINDOW (window), actionable); + g_assert_true (gtk_widget_get_sensitive (actionable)); + + g_object_ref (actionable); + gtk_window_set_child (GTK_WINDOW (window), NULL); + g_assert_false (gtk_widget_get_sensitive (actionable)); + + gtk_window_set_child (GTK_WINDOW (window), actionable); + g_object_unref (actionable); + g_assert_true (gtk_widget_get_sensitive (actionable)); + + g_object_unref (window); +} + int main (int argc, char *argv[]) @@ -732,6 +786,7 @@ main (int argc, g_test_add_func ("/action/overlap2", test_overlap2); g_test_add_func ("/action/introspection", test_introspection); g_test_add_func ("/action/enabled", test_enabled); + g_test_add_func ("/action/reparenting", test_reparenting); return g_test_run(); } -- 2.30.2