mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-10 10:50:10 +00:00
Add ability to override the focus chain for a container explicitly
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
This commit is contained in:
parent
c2c98d9e12
commit
23b98cc1ec
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -42,6 +42,7 @@ enum {
|
||||
SET_FOCUS_CHILD,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum {
|
||||
ARG_0,
|
||||
ARG_BORDER_WIDTH,
|
||||
@ -627,6 +628,12 @@ gtk_container_destroy (GtkObject *object)
|
||||
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);
|
||||
|
||||
if (GTK_OBJECT_CLASS (parent_class)->destroy)
|
||||
@ -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,40 +1487,43 @@ 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.
|
||||
*/
|
||||
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);
|
||||
/* children = gtk_container_children (container); */
|
||||
}
|
||||
|
||||
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:
|
||||
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:
|
||||
@ -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)
|
||||
|
@ -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,
|
||||
|
111
gtk/testgtk.c
111
gtk/testgtk.c
@ -6215,6 +6215,116 @@ create_flipping (void)
|
||||
gtk_widget_destroy (window);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 },
|
||||
|
111
tests/testgtk.c
111
tests/testgtk.c
@ -6215,6 +6215,116 @@ create_flipping (void)
|
||||
gtk_widget_destroy (window);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 },
|
||||
|
Loading…
Reference in New Issue
Block a user