actionmuxer: Correctly notify actions after reparenting
authorAlice Mikhaylenko <alexm@gnome.org>
Thu, 1 Jun 2023 02:27:10 +0000 (06:27 +0400)
committerAlice Mikhaylenko <alexm@gnome.org>
Thu, 1 Jun 2023 02:39:44 +0000 (06:39 +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 33e8c0542dffbe4d4f9ca6ac5422a58bb9a99c20..3bb0fb90b148395bc9a06ea016a288da469e1c14 100644 (file)
@@ -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, &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();
 }