diff --git a/testsuite/gtk/focus.c b/testsuite/gtk/focus.c index 0605c8eb53..a6ffeccbad 100644 --- a/testsuite/gtk/focus.c +++ b/testsuite/gtk/focus.c @@ -1,41 +1,186 @@ #include +const char * +widget_name (GtkWidget *widget) +{ + if (gtk_widget_get_name (widget)) + return gtk_widget_get_name (widget); + else if (GTK_IS_LABEL (widget)) + return gtk_label_get_label (GTK_LABEL (widget)); + else if (GTK_IS_EDITABLE (widget)) + return gtk_editable_get_text (GTK_EDITABLE (widget)); + else + return G_OBJECT_TYPE_NAME (widget); +} + +static char * +mode_to_string (GdkCrossingMode mode) +{ + return g_enum_to_string (GDK_TYPE_CROSSING_MODE, mode); +} + +static char * +detail_to_string (GdkNotifyType detail) +{ + return g_enum_to_string (GDK_TYPE_NOTIFY_TYPE, detail); +} + +static void +focus_in (GtkEventController *controller, + GdkCrossingMode mode, + GdkNotifyType detail, + GString *s) +{ + GtkWidget *widget = gtk_event_controller_get_widget (controller); + g_string_append_printf (s, "%s: focus-in %s %s\n", + widget_name (widget), + mode_to_string (mode), + detail_to_string (detail)); +} + +static void +focus_out (GtkEventController *controller, + GdkCrossingMode mode, + GdkNotifyType detail, + GString *s) +{ + GtkWidget *widget = gtk_event_controller_get_widget (controller); + g_string_append_printf (s, "%s: focus-out %s %s\n", + widget_name (widget), + mode_to_string (mode), + detail_to_string (detail)); +} + +static void +add_controller (GtkWidget *widget, GString *s) +{ + GtkEventController *controller; + + controller = gtk_event_controller_key_new (); + g_signal_connect (controller, "focus-in", G_CALLBACK (focus_in), s); + g_signal_connect (controller, "focus-out", G_CALLBACK (focus_out), s); + gtk_widget_add_controller (widget, controller); +} + static void test_window_focus (void) { GtkWidget *window; GtkWidget *box; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *label1; + GtkWidget *label2; GtkWidget *entry1; GtkWidget *entry2; + GString *s = g_string_new (""); + + /* + * The tree look like this, with [] indicating + * focus locations: + * + * window + * | + * +----[box]-----+ + * | | | + * label1 box1 box2------+ + * | | | + * [entry1] label2 [entry2] + */ window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_set_name (window, "window"); + add_controller (window, s); box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_widget_set_can_focus (box, TRUE); + gtk_widget_set_name (box, "box"); + add_controller (box, s); gtk_container_add (GTK_CONTAINER (window), box); - gtk_container_add (GTK_CONTAINER (box), gtk_label_new ("label1")); + label1 = gtk_label_new ("label1"); + gtk_widget_set_name (label1, "label1"); + add_controller (label1, s); + gtk_container_add (GTK_CONTAINER (box), label1); + box1 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + gtk_widget_set_name (box1, "box1"); + add_controller (box1, s); + gtk_container_add (GTK_CONTAINER (box), box1); entry1 = gtk_text_new (); - gtk_container_add (GTK_CONTAINER (box), entry1); - gtk_container_add (GTK_CONTAINER (box), gtk_label_new ("label2")); + gtk_widget_set_name (entry1, "entry1"); + add_controller (entry1, s); + gtk_container_add (GTK_CONTAINER (box1), entry1); + box2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + gtk_widget_set_name (box2, "box2"); + add_controller (box2, s); + gtk_container_add (GTK_CONTAINER (box), box2); + label2 = gtk_label_new ("label2"); + gtk_widget_set_name (label2, "label2"); + add_controller (label2, s); + gtk_container_add (GTK_CONTAINER (box2), label2); entry2 = gtk_text_new (); - gtk_container_add (GTK_CONTAINER (box), entry2); + gtk_widget_set_name (entry2, "entry2"); + add_controller (entry2, s); + gtk_container_add (GTK_CONTAINER (box2), entry2); g_assert_null (gtk_window_get_focus (GTK_WINDOW (window))); - gtk_window_set_focus (GTK_WINDOW (window), entry1); - - g_assert (gtk_window_get_focus (GTK_WINDOW (window)) == entry1); - gtk_widget_show (window); + /* show puts the initial focus on box */ + g_assert (gtk_window_get_focus (GTK_WINDOW (window)) == box); + + if (g_test_verbose ()) + g_print ("-> box\n%s\n", s->str); + + g_assert_cmpstr (s->str, ==, +"window: focus-in GDK_CROSSING_NORMAL GDK_NOTIFY_VIRTUAL\n" +"box: focus-in GDK_CROSSING_NORMAL GDK_NOTIFY_ANCESTOR\n"); + g_string_truncate (s, 0); + + gtk_widget_grab_focus (entry1); + + if (g_test_verbose ()) + g_print ("box -> entry1\n%s\n", s->str); + + g_assert_cmpstr (s->str, ==, +"box: focus-out GDK_CROSSING_NORMAL GDK_NOTIFY_INFERIOR\n" +"box1: focus-in GDK_CROSSING_NORMAL GDK_NOTIFY_VIRTUAL\n" +"entry1: focus-in GDK_CROSSING_NORMAL GDK_NOTIFY_ANCESTOR\n"); + + g_string_truncate (s, 0); + g_assert (gtk_window_get_focus (GTK_WINDOW (window)) == entry1); gtk_widget_grab_focus (entry2); + if (g_test_verbose ()) + g_print ("entry1 -> entry2\n%s\n", s->str); + + g_assert_cmpstr (s->str, ==, +"entry1: focus-out GDK_CROSSING_NORMAL GDK_NOTIFY_NONLINEAR\n" +"box1: focus-out GDK_CROSSING_NORMAL GDK_NOTIFY_NONLINEAR_VIRTUAL\n" +"box2: focus-in GDK_CROSSING_NORMAL GDK_NOTIFY_NONLINEAR_VIRTUAL\n" +"entry2: focus-in GDK_CROSSING_NORMAL GDK_NOTIFY_NONLINEAR\n"); + + g_string_truncate (s, 0); + g_assert (gtk_window_get_focus (GTK_WINDOW (window)) == entry2); + gtk_widget_grab_focus (box); + + if (g_test_verbose ()) + g_print ("entry2 -> box\n%s", s->str); + + g_assert_cmpstr (s->str, ==, +"entry2: focus-out GDK_CROSSING_NORMAL GDK_NOTIFY_ANCESTOR\n" +"box2: focus-out GDK_CROSSING_NORMAL GDK_NOTIFY_VIRTUAL\n" +"box: focus-in GDK_CROSSING_NORMAL GDK_NOTIFY_INFERIOR\n"); + + g_string_truncate (s, 0); + gtk_widget_hide (window); - g_assert (gtk_window_get_focus (GTK_WINDOW (window)) == entry2); - + g_assert (gtk_window_get_focus (GTK_WINDOW (window)) == box); + gtk_window_set_focus (GTK_WINDOW (window), entry1); g_assert (gtk_window_get_focus (GTK_WINDOW (window)) == entry1);