summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--ChangeLog.pre-2-06
-rw-r--r--ChangeLog.pre-2-106
-rw-r--r--ChangeLog.pre-2-26
-rw-r--r--ChangeLog.pre-2-46
-rw-r--r--ChangeLog.pre-2-66
-rw-r--r--ChangeLog.pre-2-86
-rw-r--r--gtk/gtkcontainer.c206
-rw-r--r--gtk/gtkcontainer.h5
-rw-r--r--gtk/testgtk.c111
-rw-r--r--tests/testgtk.c111
11 files changed, 446 insertions, 29 deletions
diff --git a/ChangeLog b/ChangeLog
index 6d3f0fcce..d14b417bc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2001-03-22 Havoc Pennington <hp@redhat.com>
+
+ * gtk/gtkcontainer.c (gtk_container_set_focus_chain):
+ (gtk_container_unset_focus_chain): Add ability to override the
+ focus chain for a container explicitly
+
Thu Mar 22 13:01:44 2001 Tim Janik <timj@gtk.org>
* gtk/gtklabel.[hc]: some cleanups, fixed mnemonic_widget handling,
diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0
index 6d3f0fcce..d14b417bc 100644
--- a/ChangeLog.pre-2-0
+++ b/ChangeLog.pre-2-0
@@ -1,3 +1,9 @@
+2001-03-22 Havoc Pennington <hp@redhat.com>
+
+ * gtk/gtkcontainer.c (gtk_container_set_focus_chain):
+ (gtk_container_unset_focus_chain): Add ability to override the
+ focus chain for a container explicitly
+
Thu Mar 22 13:01:44 2001 Tim Janik <timj@gtk.org>
* gtk/gtklabel.[hc]: some cleanups, fixed mnemonic_widget handling,
diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10
index 6d3f0fcce..d14b417bc 100644
--- a/ChangeLog.pre-2-10
+++ b/ChangeLog.pre-2-10
@@ -1,3 +1,9 @@
+2001-03-22 Havoc Pennington <hp@redhat.com>
+
+ * gtk/gtkcontainer.c (gtk_container_set_focus_chain):
+ (gtk_container_unset_focus_chain): Add ability to override the
+ focus chain for a container explicitly
+
Thu Mar 22 13:01:44 2001 Tim Janik <timj@gtk.org>
* gtk/gtklabel.[hc]: some cleanups, fixed mnemonic_widget handling,
diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2
index 6d3f0fcce..d14b417bc 100644
--- a/ChangeLog.pre-2-2
+++ b/ChangeLog.pre-2-2
@@ -1,3 +1,9 @@
+2001-03-22 Havoc Pennington <hp@redhat.com>
+
+ * gtk/gtkcontainer.c (gtk_container_set_focus_chain):
+ (gtk_container_unset_focus_chain): Add ability to override the
+ focus chain for a container explicitly
+
Thu Mar 22 13:01:44 2001 Tim Janik <timj@gtk.org>
* gtk/gtklabel.[hc]: some cleanups, fixed mnemonic_widget handling,
diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4
index 6d3f0fcce..d14b417bc 100644
--- a/ChangeLog.pre-2-4
+++ b/ChangeLog.pre-2-4
@@ -1,3 +1,9 @@
+2001-03-22 Havoc Pennington <hp@redhat.com>
+
+ * gtk/gtkcontainer.c (gtk_container_set_focus_chain):
+ (gtk_container_unset_focus_chain): Add ability to override the
+ focus chain for a container explicitly
+
Thu Mar 22 13:01:44 2001 Tim Janik <timj@gtk.org>
* gtk/gtklabel.[hc]: some cleanups, fixed mnemonic_widget handling,
diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6
index 6d3f0fcce..d14b417bc 100644
--- a/ChangeLog.pre-2-6
+++ b/ChangeLog.pre-2-6
@@ -1,3 +1,9 @@
+2001-03-22 Havoc Pennington <hp@redhat.com>
+
+ * gtk/gtkcontainer.c (gtk_container_set_focus_chain):
+ (gtk_container_unset_focus_chain): Add ability to override the
+ focus chain for a container explicitly
+
Thu Mar 22 13:01:44 2001 Tim Janik <timj@gtk.org>
* gtk/gtklabel.[hc]: some cleanups, fixed mnemonic_widget handling,
diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8
index 6d3f0fcce..d14b417bc 100644
--- a/ChangeLog.pre-2-8
+++ b/ChangeLog.pre-2-8
@@ -1,3 +1,9 @@
+2001-03-22 Havoc Pennington <hp@redhat.com>
+
+ * gtk/gtkcontainer.c (gtk_container_set_focus_chain):
+ (gtk_container_unset_focus_chain): Add ability to override the
+ focus chain for a container explicitly
+
Thu Mar 22 13:01:44 2001 Tim Janik <timj@gtk.org>
* gtk/gtklabel.[hc]: some cleanups, fixed mnemonic_widget handling,
diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c
index 760e15296..58bdd5674 100644
--- a/gtk/gtkcontainer.c
+++ b/gtk/gtkcontainer.c
@@ -42,6 +42,7 @@ enum {
SET_FOCUS_CHILD,
LAST_SIGNAL
};
+
enum {
ARG_0,
ARG_BORDER_WIDTH,
@@ -626,6 +627,12 @@ gtk_container_destroy (GtkObject *object)
gtk_container_dequeue_resize_handler (container);
if (container->resize_widgets)
gtk_container_clear_resize_widgets (container);
+
+ /* do this before walking child widgets, to avoid
+ * removing children from focus chain one by one.
+ */
+ if (container->has_focus_chain)
+ gtk_container_unset_focus_chain (container);
gtk_container_foreach (container, (GtkCallback) gtk_widget_destroy, NULL);
@@ -1415,13 +1422,48 @@ gtk_container_real_set_focus_child (GtkContainer *container,
}
}
+static GList*
+get_focus_chain (GtkContainer *container)
+{
+ GList *chain;
+
+ chain = g_object_get_data (G_OBJECT (container), "gtk-container-focus-chain");
+
+ return chain;
+}
+
+static GList*
+filter_unfocusable (GtkContainer *container,
+ GList *list)
+{
+ GList *tmp_list;
+ GList *tmp_list2;
+
+ tmp_list = list;
+ while (tmp_list)
+ {
+ if (GTK_WIDGET_IS_SENSITIVE (tmp_list->data) &&
+ GTK_WIDGET_DRAWABLE (tmp_list->data) &&
+ (GTK_IS_CONTAINER (tmp_list->data) || GTK_WIDGET_CAN_FOCUS (tmp_list->data)))
+ tmp_list = tmp_list->next;
+ else
+ {
+ tmp_list2 = tmp_list;
+ tmp_list = tmp_list->next;
+
+ list = g_list_remove_link (list, tmp_list2);
+ g_list_free_1 (tmp_list2);
+ }
+ }
+
+ return list;
+}
+
static gboolean
gtk_container_real_focus (GtkContainer *container,
GtkDirectionType direction)
{
GList *children;
- GList *tmp_list;
- GList *tmp_list2;
gint return_val;
g_return_val_if_fail (container != NULL, FALSE);
@@ -1445,41 +1487,44 @@ gtk_container_real_focus (GtkContainer *container,
}
else
{
- /* Get a list of the containers children
+ /* Get a list of the containers children, allowing focus
+ * chain to override.
*/
- children = NULL;
- gtk_container_forall (container,
- gtk_container_children_callback,
- &children);
- children = g_list_reverse (children);
- /* children = gtk_container_children (container); */
+ if (container->has_focus_chain)
+ {
+ GList *chain;
+
+ chain = get_focus_chain (container);
+
+ children = g_list_copy (chain);
+ }
+ else
+ {
+ children = NULL;
+ gtk_container_forall (container,
+ gtk_container_children_callback,
+ &children);
+ children = g_list_reverse (children);
+ }
if (children)
{
/* Remove any children which are inappropriate for focus movement
*/
- tmp_list = children;
- while (tmp_list)
- {
- if (GTK_WIDGET_IS_SENSITIVE (tmp_list->data) &&
- GTK_WIDGET_DRAWABLE (tmp_list->data) &&
- (GTK_IS_CONTAINER (tmp_list->data) || GTK_WIDGET_CAN_FOCUS (tmp_list->data)))
- tmp_list = tmp_list->next;
- else
- {
- tmp_list2 = tmp_list;
- tmp_list = tmp_list->next;
-
- children = g_list_remove_link (children, tmp_list2);
- g_list_free_1 (tmp_list2);
- }
- }
-
+ children = filter_unfocusable (container, children);
+
switch (direction)
{
case GTK_DIR_TAB_FORWARD:
case GTK_DIR_TAB_BACKWARD:
- return_val = gtk_container_focus_tab (container, children, direction);
+ if (container->has_focus_chain)
+ {
+ if (direction == GTK_DIR_TAB_BACKWARD)
+ children = g_list_reverse (children);
+ return_val = gtk_container_focus_move (container, children, direction);
+ }
+ else
+ return_val = gtk_container_focus_tab (container, children, direction);
break;
case GTK_DIR_UP:
case GTK_DIR_DOWN:
@@ -1864,7 +1909,7 @@ gtk_container_focus_move (GtkContainer *container,
if (!child)
continue;
-
+
if (focus_child)
{
if (focus_child == child)
@@ -1877,7 +1922,8 @@ gtk_container_focus_move (GtkContainer *container,
return TRUE;
}
}
- else if (GTK_WIDGET_DRAWABLE (child))
+ else if (GTK_WIDGET_DRAWABLE (child) &&
+ gtk_widget_is_ancestor (child, GTK_WIDGET (container)))
{
if (GTK_IS_CONTAINER (child))
{
@@ -1906,6 +1952,108 @@ gtk_container_children_callback (GtkWidget *widget,
*children = g_list_prepend (*children, widget);
}
+
+/* Hack-around */
+#define g_signal_handlers_disconnect_by_func(obj, func, data) g_signal_handlers_disconnect_matched (obj, G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL, func, data)
+
+static void
+chain_widget_destroyed (GtkWidget *widget,
+ gpointer user_data)
+{
+ GtkContainer *container;
+ GList *chain;
+
+ container = GTK_CONTAINER (user_data);
+
+ chain = g_object_get_data (G_OBJECT (container),
+ "gtk-container-focus-chain");
+
+ chain = g_list_remove (chain, widget);
+
+ g_signal_handlers_disconnect_by_func (G_OBJECT (widget),
+ chain_widget_destroyed,
+ user_data);
+
+ g_object_set_data (G_OBJECT (container),
+ "gtk-container-focus-chain",
+ chain);
+}
+
+void
+gtk_container_set_focus_chain (GtkContainer *container,
+ GList *focusable_widgets)
+{
+ GList *chain;
+ GList *tmp_list;
+
+ g_return_if_fail (GTK_IS_CONTAINER (container));
+
+ if (container->has_focus_chain)
+ gtk_container_unset_focus_chain (container);
+
+ container->has_focus_chain = TRUE;
+
+ chain = NULL;
+ tmp_list = focusable_widgets;
+ while (tmp_list != NULL)
+ {
+ g_return_if_fail (GTK_IS_WIDGET (tmp_list->data));
+
+ /* In principle each widget in the chain should be a descendant
+ * of the container, but we don't want to check that here, it's
+ * expensive and also it's allowed to set the focus chain before
+ * you pack the widgets, or have a widget in the chain that isn't
+ * always packed. So we check for ancestor during actual traversal.
+ */
+
+ chain = g_list_prepend (chain, tmp_list->data);
+
+ gtk_signal_connect (GTK_OBJECT (tmp_list->data),
+ "destroy",
+ GTK_SIGNAL_FUNC (chain_widget_destroyed),
+ container);
+
+ tmp_list = g_list_next (tmp_list);
+ }
+
+ chain = g_list_reverse (chain);
+
+ g_object_set_data (G_OBJECT (container),
+ "gtk-container-focus-chain",
+ chain);
+}
+
+void
+gtk_container_unset_focus_chain (GtkContainer *container)
+{
+ g_return_if_fail (GTK_IS_CONTAINER (container));
+
+ if (container->has_focus_chain)
+ {
+ GList *chain;
+ GList *tmp_list;
+
+ chain = get_focus_chain (container);
+
+ container->has_focus_chain = FALSE;
+
+ g_object_set_data (G_OBJECT (container), "gtk-container-focus-chain",
+ NULL);
+
+ tmp_list = chain;
+ while (tmp_list != NULL)
+ {
+ g_signal_handlers_disconnect_by_func (G_OBJECT (tmp_list->data),
+ chain_widget_destroyed,
+ container);
+
+ tmp_list = g_list_next (tmp_list);
+ }
+
+ g_list_free (chain);
+ }
+}
+
void
gtk_container_set_focus_vadjustment (GtkContainer *container,
GtkAdjustment *adjustment)
diff --git a/gtk/gtkcontainer.h b/gtk/gtkcontainer.h
index 9b725b89f..fa1c03add 100644
--- a/gtk/gtkcontainer.h
+++ b/gtk/gtkcontainer.h
@@ -62,6 +62,7 @@ struct _GtkContainer
guint need_resize : 1;
guint resize_mode : 2;
guint reallocate_redraws : 1;
+ guint has_focus_chain : 1;
/* The list of children that requested a resize
*/
@@ -134,6 +135,10 @@ void gtk_container_propagate_expose (GtkContainer *container,
GtkWidget *child,
GdkEventExpose *event);
+void gtk_container_set_focus_chain (GtkContainer *container,
+ GList *focusable_widgets);
+void gtk_container_unset_focus_chain (GtkContainer *container);
+
/* Widget-level methods */
void gtk_container_set_reallocate_redraws (GtkContainer *container,
diff --git a/gtk/testgtk.c b/gtk/testgtk.c
index b44d880c6..37ec0b776 100644
--- a/gtk/testgtk.c
+++ b/gtk/testgtk.c
@@ -6216,6 +6216,116 @@ create_flipping (void)
}
/*
+ * Focus test
+ */
+
+static GtkWidget*
+make_focus_table (GList **list)
+{
+ GtkWidget *table;
+ gint i, j;
+
+ table = gtk_table_new (5, 5, FALSE);
+
+ i = 0;
+ j = 0;
+
+ while (i < 5)
+ {
+ j = 0;
+ while (j < 5)
+ {
+ GtkWidget *widget;
+
+ if ((i + j) % 2)
+ widget = gtk_entry_new ();
+ else
+ widget = gtk_button_new_with_label ("Foo");
+
+ *list = g_list_prepend (*list, widget);
+
+ gtk_table_attach (GTK_TABLE (table),
+ widget,
+ i, i + 1,
+ j, j + 1,
+ GTK_EXPAND | GTK_FILL,
+ GTK_EXPAND | GTK_FILL,
+ 5, 5);
+
+ ++j;
+ }
+
+ ++i;
+ }
+
+ *list = g_list_reverse (*list);
+
+ return table;
+}
+
+static void
+create_focus (void)
+{
+ static GtkWidget *window = NULL;
+
+ if (!window)
+ {
+ GtkWidget *table;
+ GtkWidget *frame;
+ GList *list = NULL;
+ GList *first = NULL, *second = NULL, *tmp_list = NULL;
+ gint i;
+
+ window = gtk_dialog_new_with_buttons ("Keyboard focus navigation",
+ NULL, 0,
+ GTK_STOCK_BUTTON_CLOSE,
+ GTK_RESPONSE_NONE,
+ NULL);
+
+ gtk_signal_connect (GTK_OBJECT (window), "destroy",
+ GTK_SIGNAL_FUNC (gtk_widget_destroyed),
+ &window);
+
+ gtk_signal_connect (GTK_OBJECT (window), "response",
+ GTK_SIGNAL_FUNC (gtk_widget_destroy),
+ NULL);
+
+ gtk_window_set_title (GTK_WINDOW (window), "Keyboard Focus Navigation");
+
+ frame = gtk_frame_new ("Weird tab focus chain");
+
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox),
+ frame, TRUE, TRUE, 0);
+
+ table = make_focus_table (&list);
+
+ gtk_container_add (GTK_CONTAINER (frame), table);
+
+ gtk_container_set_focus_chain (GTK_CONTAINER (table),
+ list);
+
+ g_list_free (list);
+
+ frame = gtk_frame_new ("Default tab focus chain");
+
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox),
+ frame, TRUE, TRUE, 0);
+
+ list = NULL;
+ table = make_focus_table (&list);
+
+ g_list_free (list);
+
+ gtk_container_add (GTK_CONTAINER (frame), table);
+ }
+
+ if (!GTK_WIDGET_VISIBLE (window))
+ gtk_widget_show_all (window);
+ else
+ gtk_widget_destroy (window);
+}
+
+/*
* GtkFontSelection
*/
@@ -9705,6 +9815,7 @@ create_main_window (void)
{ "event watcher", create_event_watcher },
{ "file selection", create_file_selection },
{ "flipping", create_flipping },
+ { "focus", create_focus },
{ "font selection", create_font_selection },
{ "gamma curve", create_gamma_curve },
{ "handle box", create_handle_box },
diff --git a/tests/testgtk.c b/tests/testgtk.c
index b44d880c6..37ec0b776 100644
--- a/tests/testgtk.c
+++ b/tests/testgtk.c
@@ -6216,6 +6216,116 @@ create_flipping (void)
}
/*
+ * Focus test
+ */
+
+static GtkWidget*
+make_focus_table (GList **list)
+{
+ GtkWidget *table;
+ gint i, j;
+
+ table = gtk_table_new (5, 5, FALSE);
+
+ i = 0;
+ j = 0;
+
+ while (i < 5)
+ {
+ j = 0;
+ while (j < 5)
+ {
+ GtkWidget *widget;
+
+ if ((i + j) % 2)
+ widget = gtk_entry_new ();
+ else
+ widget = gtk_button_new_with_label ("Foo");
+
+ *list = g_list_prepend (*list, widget);
+
+ gtk_table_attach (GTK_TABLE (table),
+ widget,
+ i, i + 1,
+ j, j + 1,
+ GTK_EXPAND | GTK_FILL,
+ GTK_EXPAND | GTK_FILL,
+ 5, 5);
+
+ ++j;
+ }
+
+ ++i;
+ }
+
+ *list = g_list_reverse (*list);
+
+ return table;
+}
+
+static void
+create_focus (void)
+{
+ static GtkWidget *window = NULL;
+
+ if (!window)
+ {
+ GtkWidget *table;
+ GtkWidget *frame;
+ GList *list = NULL;
+ GList *first = NULL, *second = NULL, *tmp_list = NULL;
+ gint i;
+
+ window = gtk_dialog_new_with_buttons ("Keyboard focus navigation",
+ NULL, 0,
+ GTK_STOCK_BUTTON_CLOSE,
+ GTK_RESPONSE_NONE,
+ NULL);
+
+ gtk_signal_connect (GTK_OBJECT (window), "destroy",
+ GTK_SIGNAL_FUNC (gtk_widget_destroyed),
+ &window);
+
+ gtk_signal_connect (GTK_OBJECT (window), "response",
+ GTK_SIGNAL_FUNC (gtk_widget_destroy),
+ NULL);
+
+ gtk_window_set_title (GTK_WINDOW (window), "Keyboard Focus Navigation");
+
+ frame = gtk_frame_new ("Weird tab focus chain");
+
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox),
+ frame, TRUE, TRUE, 0);
+
+ table = make_focus_table (&list);
+
+ gtk_container_add (GTK_CONTAINER (frame), table);
+
+ gtk_container_set_focus_chain (GTK_CONTAINER (table),
+ list);
+
+ g_list_free (list);
+
+ frame = gtk_frame_new ("Default tab focus chain");
+
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox),
+ frame, TRUE, TRUE, 0);
+
+ list = NULL;
+ table = make_focus_table (&list);
+
+ g_list_free (list);
+
+ gtk_container_add (GTK_CONTAINER (frame), table);
+ }
+
+ if (!GTK_WIDGET_VISIBLE (window))
+ gtk_widget_show_all (window);
+ else
+ gtk_widget_destroy (window);
+}
+
+/*
* GtkFontSelection
*/
@@ -9705,6 +9815,7 @@ create_main_window (void)
{ "event watcher", create_event_watcher },
{ "file selection", create_file_selection },
{ "flipping", create_flipping },
+ { "focus", create_focus },
{ "font selection", create_font_selection },
{ "gamma curve", create_gamma_curve },
{ "handle box", create_handle_box },