--- gtk+-2.6.4/gtk/gtkcontainer.c 2005-03-01 08:28:55.000000000 +0200 +++ gtk+-2.6.4/gtk/gtkcontainer.c 2005-04-06 16:19:36.410003200 +0300 @@ -37,10 +37,13 @@ #include "gtkwindow.h" #include "gtkintl.h" #include "gtktoolbar.h" +#include "gtkmenu.h" +#include "gtkentry.h" +#include "gtktextview.h" +#include "gtkwidget.h" #include #include - enum { ADD, REMOVE, @@ -56,6 +59,19 @@ PROP_CHILD }; +enum { + FOCUS_MOVE_OK, + FOCUS_MOVE_OK_NO_MOVE, + FOCUS_MOVE_FAIL_NO_TEXT +}; + +typedef struct +{ + GtkWidget *menu; + void *func; + GtkWidgetTapAndHoldFlags flags; +} GtkContainerTAH; + #define PARAM_SPEC_PARAM_ID(pspec) ((pspec)->param_id) #define PARAM_SPEC_SET_PARAM_ID(pspec, id) ((pspec)->param_id = (id)) @@ -87,6 +103,9 @@ static gboolean gtk_container_focus_move (GtkContainer *container, GList *children, GtkDirectionType direction); +static gint gtk_container_focus_move_with_tab (GtkContainer *container, + GtkDirectionType direction, + GtkWidget **fallback); static void gtk_container_children_callback (GtkWidget *widget, gpointer client_data); static void gtk_container_show_all (GtkWidget *widget); @@ -95,10 +114,14 @@ GdkEventExpose *event); static void gtk_container_map (GtkWidget *widget); static void gtk_container_unmap (GtkWidget *widget); - +static void gtk_container_tap_and_hold_setup (GtkWidget *widget, + GtkWidget *menu, GtkCallback func, GtkWidgetTapAndHoldFlags flags); static gchar* gtk_container_child_default_composite_name (GtkContainer *container, GtkWidget *child); +static void gtk_container_tap_and_hold_setup_forall( GtkWidget *widget, + GtkContainerTAH *tah ); +static void gtk_container_grab_focus( GtkWidget *focus_widget ); /* --- variables --- */ static const gchar vadjustment_key[] = "gtk-vadjustment"; @@ -190,7 +213,9 @@ widget_class->map = gtk_container_map; widget_class->unmap = gtk_container_unmap; widget_class->focus = gtk_container_focus; - + widget_class->tap_and_hold_setup = gtk_container_tap_and_hold_setup; + widget_class->grab_focus = gtk_container_grab_focus; + class->add = gtk_container_add_unimplemented; class->remove = gtk_container_remove_unimplemented; class->check_resize = gtk_container_real_check_resize; @@ -2011,6 +2036,24 @@ GtkWidget *focus_child; GtkWidget *child; + /* + * If there's an item focus already and tab was pressed, only go thru + * GtkEntries and GtkTextviews. Do _not_ jump from last widget to the first + * one and vice verca. + */ + if ((direction == GTK_DIR_TAB_FORWARD || direction == GTK_DIR_TAB_BACKWARD) && + container->focus_child != NULL) + { + GtkWidget *fallback; + fallback = NULL; + if (gtk_container_focus_move_with_tab (container, direction, &fallback) + != FOCUS_MOVE_FAIL_NO_TEXT) + return TRUE; + + if (fallback && gtk_widget_child_focus (fallback, direction)) + return TRUE; + } + focus_child = container->focus_child; while (children) @@ -2019,7 +2062,7 @@ children = children->next; if (!child) - continue; + continue; if (focus_child) { @@ -2027,8 +2070,8 @@ { focus_child = NULL; - if (gtk_widget_child_focus (child, direction)) - return TRUE; + if (gtk_widget_child_focus (child, direction)) + return TRUE; } } else if (GTK_WIDGET_DRAWABLE (child) && @@ -2042,6 +2085,105 @@ return FALSE; } +static gint +gtk_container_focus_move_with_tab (GtkContainer *container, + GtkDirectionType direction, + GtkWidget **fallback) +{ + GList *children, *sorted_children; + GtkWidget *child; + GtkWidget *focus_child; + gboolean found_text; + gint ret; + + found_text = FALSE; + focus_child = container->focus_child; + + /* This part is copied from gtk_container_focus() */ + if (container->has_focus_chain) + children = g_list_copy (get_focus_chain (container)); + else + children = gtk_container_get_all_children (container); + + if (container->has_focus_chain && + (direction == GTK_DIR_TAB_FORWARD || + direction == GTK_DIR_TAB_BACKWARD)) + { + sorted_children = g_list_copy (children); + + if (direction == GTK_DIR_TAB_BACKWARD) + sorted_children = g_list_reverse (sorted_children); + } + else + sorted_children = _gtk_container_focus_sort (container, children, + direction, NULL); + g_list_free(children); + children = sorted_children; + + while (children) + { + child = children->data; + children = children->next; + + if (!child) + continue; + + if (GTK_IS_ENTRY (child) || GTK_IS_TEXT_VIEW (child)) + found_text = TRUE; + + if (focus_child) + { + if (child == focus_child) + { + focus_child = NULL; + if (GTK_IS_CONTAINER (child)) + { + ret = gtk_container_focus_move_with_tab (GTK_CONTAINER (child), + direction, + fallback); + if (ret == FOCUS_MOVE_OK) + { + g_list_free (sorted_children); + return FOCUS_MOVE_OK; + } + else if (ret == FOCUS_MOVE_OK_NO_MOVE) + found_text = TRUE; + } + } + } + else if (GTK_WIDGET_DRAWABLE (child) && + gtk_widget_is_ancestor (child, GTK_WIDGET (container))) + { + if (GTK_IS_ENTRY (child) || GTK_IS_TEXT_VIEW (child)) + { + if (gtk_widget_child_focus (child, direction)) + { + g_list_free (sorted_children); + return FOCUS_MOVE_OK; + } + } + else if (GTK_IS_CONTAINER (child)) + { + ret = gtk_container_focus_move_with_tab (GTK_CONTAINER (child), + direction, + fallback); + if (ret == FOCUS_MOVE_OK) + { + g_list_free (sorted_children); + return FOCUS_MOVE_OK; + } + else if (ret == FOCUS_MOVE_OK_NO_MOVE) + found_text = TRUE; + } + if (GTK_WIDGET_CAN_FOCUS (child) && *fallback == NULL) + *fallback = child; + } + } + + g_list_free (sorted_children); + + return found_text ? FOCUS_MOVE_OK_NO_MOVE : FOCUS_MOVE_FAIL_NO_TEXT; +} static void gtk_container_children_callback (GtkWidget *widget, @@ -2463,3 +2605,58 @@ gdk_event_free (child_event); } } + +static void gtk_container_tap_and_hold_setup_forall( GtkWidget *widget, + GtkContainerTAH *tah ) +{ + gtk_widget_tap_and_hold_setup( widget, tah->menu, tah->func, + tah->flags ); +} + +static void gtk_container_tap_and_hold_setup( GtkWidget *widget, + GtkWidget *menu, GtkCallback func, GtkWidgetTapAndHoldFlags flags ) +{ + GtkContainerTAH tah; + g_return_if_fail( GTK_IS_WIDGET(widget)); + g_return_if_fail( menu == NULL || GTK_IS_MENU(menu) ); + tah.menu = menu; + tah.func = func; + tah.flags = flags; + if (flags & GTK_TAP_AND_HOLD_NO_INTERNALS) + gtk_container_foreach( GTK_CONTAINER(widget), + (GtkCallback)gtk_container_tap_and_hold_setup_forall, &tah ); + else + gtk_container_forall( GTK_CONTAINER(widget), + (GtkCallback)gtk_container_tap_and_hold_setup_forall, &tah ); + parent_class->tap_and_hold_setup (widget, menu, func, flags); +} + +static void gtk_container_grab_focus( GtkWidget *focus_widget ) +{ + if( GTK_WIDGET_CAN_FOCUS(focus_widget) ) + parent_class->grab_focus( focus_widget ); + else + { + GList *first = NULL; + GList *children = NULL; + GtkWidget *old_focus = NULL; + GtkWidget *toplevel = NULL; + + toplevel = gtk_widget_get_toplevel( focus_widget ); + if( !GTK_IS_WINDOW(toplevel) ) + return; + + old_focus = GTK_WINDOW(toplevel)->focus_widget; + first = gtk_container_get_all_children( + GTK_CONTAINER(focus_widget) ); + children = g_list_last( first ); + + while( children && GTK_WINDOW(toplevel)->focus_widget == old_focus ) + { + gtk_widget_grab_focus( GTK_WIDGET(children->data) ); + children = children->prev; + } + g_list_free( first ); + } +} +