2014-08-02 09:17:18 +00:00
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
2019-03-08 04:25:50 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2014-08-02 09:17:18 +00:00
|
|
|
static void
|
|
|
|
test_window_focus (void)
|
|
|
|
{
|
|
|
|
GtkWidget *window;
|
|
|
|
GtkWidget *box;
|
2019-03-08 04:25:50 +00:00
|
|
|
GtkWidget *box1;
|
|
|
|
GtkWidget *box2;
|
|
|
|
GtkWidget *label1;
|
|
|
|
GtkWidget *label2;
|
2014-08-02 09:17:18 +00:00
|
|
|
GtkWidget *entry1;
|
|
|
|
GtkWidget *entry2;
|
2019-03-08 04:25:50 +00:00
|
|
|
GString *s = g_string_new ("");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The tree look like this, with [] indicating
|
|
|
|
* focus locations:
|
|
|
|
*
|
|
|
|
* window
|
|
|
|
* |
|
|
|
|
* +----[box]-----+
|
|
|
|
* | | |
|
|
|
|
* label1 box1 box2------+
|
|
|
|
* | | |
|
|
|
|
* [entry1] label2 [entry2]
|
|
|
|
*/
|
2014-08-02 09:17:18 +00:00
|
|
|
|
|
|
|
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
2019-03-08 04:25:50 +00:00
|
|
|
gtk_widget_set_name (window, "window");
|
|
|
|
add_controller (window, s);
|
2014-08-02 09:17:18 +00:00
|
|
|
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
2019-03-08 04:25:50 +00:00
|
|
|
gtk_widget_set_can_focus (box, TRUE);
|
|
|
|
gtk_widget_set_name (box, "box");
|
|
|
|
add_controller (box, s);
|
2014-08-02 09:17:18 +00:00
|
|
|
gtk_container_add (GTK_CONTAINER (window), box);
|
2019-03-08 04:25:50 +00:00
|
|
|
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);
|
2019-02-17 20:51:31 +00:00
|
|
|
entry1 = gtk_text_new ();
|
2019-03-08 04:25:50 +00:00
|
|
|
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);
|
2019-02-17 20:51:31 +00:00
|
|
|
entry2 = gtk_text_new ();
|
2019-03-08 04:25:50 +00:00
|
|
|
gtk_widget_set_name (entry2, "entry2");
|
|
|
|
add_controller (entry2, s);
|
|
|
|
gtk_container_add (GTK_CONTAINER (box2), entry2);
|
2014-08-02 09:17:18 +00:00
|
|
|
|
|
|
|
g_assert_null (gtk_window_get_focus (GTK_WINDOW (window)));
|
|
|
|
|
2019-03-08 04:25:50 +00:00
|
|
|
gtk_widget_show (window);
|
2014-08-02 09:17:18 +00:00
|
|
|
|
2019-03-08 04:25:50 +00:00
|
|
|
/* show puts the initial focus on box */
|
|
|
|
g_assert (gtk_window_get_focus (GTK_WINDOW (window)) == box);
|
2014-08-02 09:17:18 +00:00
|
|
|
|
2019-03-08 04:25:50 +00:00
|
|
|
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);
|
2014-08-02 09:17:18 +00:00
|
|
|
|
|
|
|
g_assert (gtk_window_get_focus (GTK_WINDOW (window)) == entry1);
|
|
|
|
|
|
|
|
gtk_widget_grab_focus (entry2);
|
|
|
|
|
2019-03-08 04:25:50 +00:00
|
|
|
if (g_test_verbose ())
|
|
|
|
g_print ("entry1 -> entry2\n%s\n", s->str);
|
2014-08-02 09:17:18 +00:00
|
|
|
|
2019-03-08 04:25:50 +00:00
|
|
|
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);
|
2014-08-02 09:17:18 +00:00
|
|
|
|
|
|
|
g_assert (gtk_window_get_focus (GTK_WINDOW (window)) == entry2);
|
|
|
|
|
2019-03-08 04:25:50 +00:00
|
|
|
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)) == box);
|
|
|
|
|
2014-08-02 09:17:18 +00:00
|
|
|
gtk_window_set_focus (GTK_WINDOW (window), entry1);
|
|
|
|
|
|
|
|
g_assert (gtk_window_get_focus (GTK_WINDOW (window)) == entry1);
|
|
|
|
|
|
|
|
gtk_widget_destroy (window);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
main (int argc, char *argv[])
|
|
|
|
{
|
|
|
|
gtk_test_init (&argc, &argv);
|
|
|
|
|
|
|
|
g_test_add_func ("/focus/window", test_window_focus);
|
|
|
|
|
|
|
|
return g_test_run ();
|
|
|
|
}
|