actionmuxer: Correctly notify actions after reparenting
authorAlice Mikhaylenko <alexm@gnome.org>
Thu, 1 Jun 2023 02:27:10 +0000 (06:27 +0400)
committerMatthias Clasen <mclasen@redhat.com>
Mon, 5 Jun 2023 12:02:33 +0000 (08:02 -0400)
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
testsuite/gtk/action.c

index 47aaf0c92c7887013faeb5675054de605df20c3d..d4cce2f918b3c2a2f281834510dc0cc7d1d82ea2 100644 (file)
@@ -455,7 +455,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, &parameter_type,
                                       NULL, NULL, &state,
                                       TRUE))
index 95bb071d4b9dcfb966b21e0cc040002559908f7b..d99b16c33b116b4675891f0926a04da7362fb1ef 100644 (file)
@@ -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();
 }