diff options
author | Owen Taylor <otaylor@redhat.com> | 2000-12-11 17:47:24 +0000 |
---|---|---|
committer | Owen Taylor <otaylor@src.gnome.org> | 2000-12-11 17:47:24 +0000 |
commit | 0cdc00ec0b5364bcbe9b0567be64bd9efdda3074 (patch) | |
tree | 7c15c586d752ed8976d6e22492d00082fc62477a /gtk/gtkcontainer.c | |
parent | 5a188a9f13cd4fd4b4ae243796c92cb771313f64 (diff) | |
download | gtk+-0cdc00ec0b5364bcbe9b0567be64bd9efdda3074.tar.gz |
Add a function to determine if a window is the focus widget within its
Wed Oct 25 14:17:43 2000 Owen Taylor <otaylor@redhat.com>
* gtk/gtkwidget.[ch] (gtk_widget_is_focus): Add a function
to determine if a window is the focus widget within
its toplevel.
* gtk/gtkcontainer.[ch]: Fix the return type of ::focus
to be boolean.
* gtk/gtkcontainer.c (gtk_container_real_focus): Move handling
of the case where the container CAN_FOCUS to here instead
of having it in each individual move-the-focus place.
* gtk/gtkcontainer.c: Rewrite handling of left-right and up-down
focusing to be geometric in a much more obvious sense. Arrowing
around is still non-intuitive because it isn't perfect and
because entries, etc, grab the arrow keys, but it at least
usually will do what you expect now.
* gtk/gtknotebook.[ch]: Many cleanups. Moved docs inline in this
file.
* gtk/gtknotebook.c: Change tabs to be a single item in
the focus chain. Make movement of focus on tabs with arrow
keys wrap around.
* gtk/gtknotebook.c (gtk_notebook_find_child): Add
CHECK_FIND_CHILD macro to give informative error messages
instead of silent returns.
* gtk/gtknotebook.c (gtk_notebook_init): Set the RECEIVES_DEFAULT
flag since we handle GdkReturn on the tabs.
* gtk/gtknotebook.c (gtk_notebook_expose_tabs): Invalidate
windows rather than sending expose events directly.
* gtk/gtknotebook.[ch] docs/Changes-2.0.txt: Move structure
definition for GtkNotebookPage into .c file, since it is private.
* gtk/testgtk.c (create_notebook): Add option for
testing borderless notebook.
* gtk/testgtk.c (page_switch): Removed egregious poking
around in GTK+ internals.
* docs/widget-system.txt: Remove references to GTK_REDRAW_PENDING.
* gtk/gtkclist.[ch]: Remove key press handler, handle focusing
properly through gtk_clist_focus. Make the title headers a
single item in the tab-focus chain, and make left-right wrap
around.
* gtk/gtkwindow.c (gtk_window_focus): Add a custom
focus method so that wrapping around works properly.
* gtk/gtktreeview.c: Remove calls to gtk_container_set_focus_child() -
that is handled for the widget now.
Diffstat (limited to 'gtk/gtkcontainer.c')
-rw-r--r-- | gtk/gtkcontainer.c | 484 |
1 files changed, 273 insertions, 211 deletions
diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c index 053a6a893a..d3ee4fbffa 100644 --- a/gtk/gtkcontainer.c +++ b/gtk/gtkcontainer.c @@ -24,13 +24,15 @@ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ +#include <stdarg.h> #include <string.h> +#include <stdlib.h> + #include "gtkcontainer.h" #include "gtkprivate.h" #include "gtksignal.h" #include "gtkmain.h" -#include <stdarg.h> - +#include "gtkwindow.h" enum { ADD, @@ -59,41 +61,42 @@ struct _GtkChildArgInfo guint seq_id; }; -static void gtk_container_base_class_init (GtkContainerClass *klass); -static void gtk_container_class_init (GtkContainerClass *klass); -static void gtk_container_init (GtkContainer *container); -static void gtk_container_destroy (GtkObject *object); -static void gtk_container_get_arg (GtkObject *object, - GtkArg *arg, - guint arg_id); -static void gtk_container_set_arg (GtkObject *object, - GtkArg *arg, - guint arg_id); -static void gtk_container_add_unimplemented (GtkContainer *container, - GtkWidget *widget); -static void gtk_container_remove_unimplemented (GtkContainer *container, - GtkWidget *widget); -static void gtk_container_real_check_resize (GtkContainer *container); -static gint gtk_container_real_focus (GtkContainer *container, - GtkDirectionType direction); -static void gtk_container_real_set_focus_child (GtkContainer *container, - GtkWidget *widget); -static gint gtk_container_focus_tab (GtkContainer *container, - GList *children, - GtkDirectionType direction); -static gint gtk_container_focus_up_down (GtkContainer *container, - GList *children, - GtkDirectionType direction); -static gint gtk_container_focus_left_right (GtkContainer *container, - GList *children, - GtkDirectionType direction); -static gint gtk_container_focus_move (GtkContainer *container, - GList *children, - GtkDirectionType direction); -static void gtk_container_children_callback (GtkWidget *widget, - gpointer client_data); -static void gtk_container_show_all (GtkWidget *widget); -static void gtk_container_hide_all (GtkWidget *widget); +static void gtk_container_base_class_init (GtkContainerClass *klass); +static void gtk_container_class_init (GtkContainerClass *klass); +static void gtk_container_init (GtkContainer *container); +static void gtk_container_destroy (GtkObject *object); +static void gtk_container_get_arg (GtkObject *object, + GtkArg *arg, + guint arg_id); +static void gtk_container_set_arg (GtkObject *object, + GtkArg *arg, + guint arg_id); +static void gtk_container_add_unimplemented (GtkContainer *container, + GtkWidget *widget); +static void gtk_container_remove_unimplemented (GtkContainer *container, + GtkWidget *widget); +static void gtk_container_real_check_resize (GtkContainer *container); +static gboolean gtk_container_real_focus (GtkContainer *container, + GtkDirectionType direction); +static void gtk_container_real_set_focus_child (GtkContainer *container, + GtkWidget *widget); +static gboolean gtk_container_focus_tab (GtkContainer *container, + GList *children, + GtkDirectionType direction); +static gboolean gtk_container_focus_up_down (GtkContainer *container, + GList **children, + GtkDirectionType direction); +static gboolean gtk_container_focus_left_right (GtkContainer *container, + GList **children, + GtkDirectionType direction); +static gboolean gtk_container_focus_move (GtkContainer *container, + GList *children, + GtkDirectionType direction); +static void gtk_container_children_callback (GtkWidget *widget, + gpointer client_data); +static void gtk_container_show_all (GtkWidget *widget); +static void gtk_container_hide_all (GtkWidget *widget); + static gchar* gtk_container_child_default_composite_name (GtkContainer *container, GtkWidget *child); @@ -1182,7 +1185,7 @@ gtk_container_foreach_full (GtkContainer *container, notify (callback_data); } -gint +gboolean gtk_container_focus (GtkContainer *container, GtkDirectionType direction) { @@ -1342,7 +1345,7 @@ gtk_container_real_set_focus_child (GtkContainer *container, } } -static gint +static gboolean gtk_container_real_focus (GtkContainer *container, GtkDirectionType direction) { @@ -1364,8 +1367,11 @@ gtk_container_real_focus (GtkContainer *container, if (GTK_WIDGET_CAN_FOCUS (container)) { - gtk_widget_grab_focus (GTK_WIDGET (container)); - return_val = TRUE; + if (!GTK_WIDGET_HAS_FOCUS (container)) + { + gtk_widget_grab_focus (GTK_WIDGET (container)); + return_val = TRUE; + } } else { @@ -1407,11 +1413,11 @@ gtk_container_real_focus (GtkContainer *container, break; case GTK_DIR_UP: case GTK_DIR_DOWN: - return_val = gtk_container_focus_up_down (container, children, direction); + return_val = gtk_container_focus_up_down (container, &children, direction); break; case GTK_DIR_LEFT: case GTK_DIR_RIGHT: - return_val = gtk_container_focus_left_right (container, children, direction); + return_val = gtk_container_focus_left_right (container, &children, direction); break; } @@ -1422,7 +1428,7 @@ gtk_container_real_focus (GtkContainer *container, return return_val; } -static gint +static gboolean gtk_container_focus_tab (GtkContainer *container, GList *children, GtkDirectionType direction) @@ -1493,227 +1499,285 @@ gtk_container_focus_tab (GtkContainer *container, return gtk_container_focus_move (container, children, direction); } -static gint -gtk_container_focus_up_down (GtkContainer *container, - GList *children, - GtkDirectionType direction) +static gboolean +old_focus_coords (GtkContainer *container, GdkRectangle *old_focus_rect) { - GtkWidget *child; - GtkWidget *child2; - GList *tmp_list; - gint dist1, dist2; - gint focus_x; - gint focus_width; - guint length; - guint i, j; - - /* return failure if there isn't a focus child */ - if (container->focus_child) + GtkWidget *widget = GTK_WIDGET (container); + GtkWidget *toplevel = gtk_widget_get_toplevel (widget); + + if (toplevel && + GTK_IS_WINDOW (toplevel) && GTK_WINDOW (toplevel)->focus_widget && + GTK_WIDGET_REALIZED (container) && + GTK_WIDGET_REALIZED (GTK_WINDOW (toplevel)->focus_widget)) { - focus_width = container->focus_child->allocation.width / 2; - focus_x = container->focus_child->allocation.x + focus_width; + GtkWidget *old_focus = GTK_WINDOW (toplevel)->focus_widget; + GdkWindow *old_parent_window = old_focus->parent ? old_focus->parent->window : old_focus->window; + GdkWindow *new_parent_window = widget->window; + GdkWindow *toplevel_window = toplevel->window; + + *old_focus_rect = old_focus->allocation; + + /* Translate coordinates to the toplevel */ + + while (old_parent_window != toplevel_window) + { + gint dx, dy; + + gdk_window_get_position (old_parent_window, &dx, &dy); + + old_focus_rect->x += dx; + old_focus_rect->y += dy; + + old_parent_window = gdk_window_get_parent (old_parent_window); + } + + /* Translate coordinates back to the new container */ + + while (new_parent_window != toplevel_window) + { + gint dx, dy; + + gdk_window_get_position (new_parent_window, &dx, &dy); + + old_focus_rect->x -= dx; + old_focus_rect->y -= dy; + + new_parent_window = gdk_window_get_parent (new_parent_window); + } + + return TRUE; } - else + + return FALSE; +} + +typedef struct _CompareInfo CompareInfo; + +struct _CompareInfo +{ + gint x; + gint y; +}; + +static gint +up_down_compare (gconstpointer a, + gconstpointer b, + gpointer data) +{ + const GtkWidget *child1 = a; + const GtkWidget *child2 = b; + CompareInfo *compare = data; + + gint y1 = child1->allocation.y + child1->allocation.height / 2; + gint y2 = child2->allocation.y + child2->allocation.height / 2; + + if (y1 == y2) { - focus_width = GTK_WIDGET (container)->allocation.width; - if (GTK_WIDGET_NO_WINDOW (container)) - focus_x = GTK_WIDGET (container)->allocation.x; + gint x1 = abs (child1->allocation.x + child1->allocation.width / 2 - compare->x); + gint x2 = abs (child2->allocation.x + child2->allocation.width / 2 - compare->x); + + if (compare->y < y1) + return (x1 < x2) ? -1 : ((x1 == x2) ? 0 : 1); else - focus_x = 0; + return (x1 < x2) ? 1 : ((x1 == x2) ? 0 : -1); } + else + return (y1 < y2) ? -1 : 1; +} - length = g_list_length (children); +static gboolean +gtk_container_focus_up_down (GtkContainer *container, + GList **children, + GtkDirectionType direction) +{ + CompareInfo compare; + GList *tmp_list; - /* sort the children in the y direction */ - for (i = 1; i < length; i++) + if (container->focus_child) { - j = i; - tmp_list = g_list_nth (children, j); - child = tmp_list->data; + gint compare_x1; + gint compare_x2; + gint compare_y; + + /* Delete widgets from list that don't match minimum criteria */ - while (j > 0) + compare_x1 = container->focus_child->allocation.x; + compare_x2 = container->focus_child->allocation.x + container->focus_child->allocation.width; + + if (direction == GTK_DIR_UP) + compare_y = container->focus_child->allocation.y; + else + compare_y = container->focus_child->allocation.y + container->focus_child->allocation.height; + + tmp_list = *children; + while (tmp_list) { - child2 = tmp_list->prev->data; - if (child->allocation.y < child2->allocation.y) + GtkWidget *child = tmp_list->data; + GList *next = tmp_list->next; + gint child_x1, child_x2; + + if (child != container->focus_child) { - tmp_list->data = tmp_list->prev->data; - tmp_list = tmp_list->prev; - j--; + child_x1 = child->allocation.x; + child_x2 = child->allocation.x + child->allocation.width; + + if ((child_x2 <= compare_x1 || child_x1 >= compare_x2) /* No horizontal overlap */ || + (direction == GTK_DIR_DOWN && child->allocation.y + child->allocation.height < compare_y) || /* Not below */ + (direction == GTK_DIR_UP && child->allocation.y > compare_y)) /* Not above */ + { + *children = g_list_delete_link (*children, tmp_list); + } } - else - break; + + tmp_list = next; } - tmp_list->data = child; + compare.x = (compare_x1 + compare_x2) / 2; + compare.y = container->focus_child->allocation.y + container->focus_child->allocation.height / 2; } - - /* sort the children in distance in the x direction - * in distance from the current focus child while maintaining the - * sort in the y direction - */ - for (i = 1; i < length; i++) + else { - j = i; - tmp_list = g_list_nth (children, j); - child = tmp_list->data; - dist1 = (child->allocation.x + child->allocation.width / 2) - focus_x; + /* No old focus widget, need to figure out starting x,y some other way + */ + GtkWidget *widget = GTK_WIDGET (container); + GdkRectangle old_focus_rect; - while (j > 0) + if (old_focus_coords (container, &old_focus_rect)) { - child2 = tmp_list->prev->data; - dist2 = (child2->allocation.x + child2->allocation.width / 2) - focus_x; - - if ((dist1 < dist2) && - (child->allocation.y >= child2->allocation.y)) - { - tmp_list->data = tmp_list->prev->data; - tmp_list = tmp_list->prev; - j--; - } + compare.x = old_focus_rect.x + old_focus_rect.width / 2; + } + else + { + if (GTK_WIDGET_NO_WINDOW (widget)) + compare.x = widget->allocation.x + widget->allocation.width / 2; else - break; + compare.x = widget->allocation.width / 2; } - - tmp_list->data = child; + + if (GTK_WIDGET_NO_WINDOW (widget)) + compare.y = (direction == GTK_DIR_DOWN) ? widget->allocation.y : widget->allocation.y + widget->allocation.height; + else + compare.y = (direction == GTK_DIR_DOWN) ? 0 : + widget->allocation.height; } - /* go and invalidate any widget which is too - * far from the focus widget. - */ - if (!container->focus_child && - (direction == GTK_DIR_UP)) - focus_x += focus_width; + *children = g_list_sort_with_data (*children, up_down_compare, &compare); - tmp_list = children; - while (tmp_list) - { - child = tmp_list->data; + if (direction == GTK_DIR_UP) + *children = g_list_reverse (*children); - dist1 = (child->allocation.x + child->allocation.width / 2) - focus_x; - if (((direction == GTK_DIR_DOWN) && (dist1 < 0)) || - ((direction == GTK_DIR_UP) && (dist1 > 0))) - tmp_list->data = NULL; + return gtk_container_focus_move (container, *children, direction); +} - tmp_list = tmp_list->next; - } +static gint +left_right_compare (gconstpointer a, + gconstpointer b, + gpointer data) +{ + const GtkWidget *child1 = a; + const GtkWidget *child2 = b; + CompareInfo *compare = data; - if (direction == GTK_DIR_UP) - children = g_list_reverse (children); + gint x1 = child1->allocation.x + child1->allocation.width / 2; + gint x2 = child2->allocation.x + child2->allocation.width / 2; - return gtk_container_focus_move (container, children, direction); + if (x1 == x2) + { + gint y1 = abs (child1->allocation.y + child1->allocation.height / 2 - compare->y); + gint y2 = abs (child2->allocation.y + child2->allocation.height / 2 - compare->y); + + if (compare->x < x1) + return (y1 < y2) ? -1 : ((y1 == y2) ? 0 : 1); + else + return (y1 < y2) ? 1 : ((y1 == y2) ? 0 : -1); + } + else + return (x1 < x2) ? -1 : 1; } -static gint +static gboolean gtk_container_focus_left_right (GtkContainer *container, - GList *children, + GList **children, GtkDirectionType direction) { - GtkWidget *child; - GtkWidget *child2; + CompareInfo compare; GList *tmp_list; - gint dist1, dist2; - gint focus_y; - gint focus_height; - guint length; - guint i, j; - /* return failure if there isn't a focus child */ if (container->focus_child) { - focus_height = container->focus_child->allocation.height / 2; - focus_y = container->focus_child->allocation.y + focus_height; - } - else - { - focus_height = GTK_WIDGET (container)->allocation.height; - if (GTK_WIDGET_NO_WINDOW (container)) - focus_y = GTK_WIDGET (container)->allocation.y; - else - focus_y = 0; - } + gint compare_y1; + gint compare_y2; + gint compare_x; + + /* Delete widgets from list that don't match minimum criteria */ - length = g_list_length (children); + compare_y1 = container->focus_child->allocation.y; + compare_y2 = container->focus_child->allocation.y + container->focus_child->allocation.height; - /* sort the children in the x direction */ - for (i = 1; i < length; i++) - { - j = i; - tmp_list = g_list_nth (children, j); - child = tmp_list->data; - - while (j > 0) + if (direction == GTK_DIR_LEFT) + compare_x = container->focus_child->allocation.x; + else + compare_x = container->focus_child->allocation.x + container->focus_child->allocation.width; + + tmp_list = *children; + while (tmp_list) { - child2 = tmp_list->prev->data; - if (child->allocation.x < child2->allocation.x) + GtkWidget *child = tmp_list->data; + GList *next = tmp_list->next; + gint child_y1, child_y2; + + if (child != container->focus_child) { - tmp_list->data = tmp_list->prev->data; - tmp_list = tmp_list->prev; - j--; + child_y1 = child->allocation.y; + child_y2 = child->allocation.y + child->allocation.height; + + if ((child_y2 <= compare_y1 || child_y1 >= compare_y2) /* No vertical overlap */ || + (direction == GTK_DIR_RIGHT && child->allocation.x + child->allocation.width < compare_x) || /* Not to left */ + (direction == GTK_DIR_LEFT && child->allocation.x > compare_x)) /* Not to right */ + { + *children = g_list_delete_link (*children, tmp_list); + } } - else - break; + + tmp_list = next; } - tmp_list->data = child; + compare.y = (compare_y1 + compare_y2) / 2; + compare.x = container->focus_child->allocation.x + container->focus_child->allocation.width / 2; } - - /* sort the children in distance in the y direction - * in distance from the current focus child while maintaining the - * sort in the x direction - */ - for (i = 1; i < length; i++) + else { - j = i; - tmp_list = g_list_nth (children, j); - child = tmp_list->data; - dist1 = (child->allocation.y + child->allocation.height / 2) - focus_y; + /* No old focus widget, need to figure out starting x,y some other way + */ + GtkWidget *widget = GTK_WIDGET (container); + GdkRectangle old_focus_rect; - while (j > 0) + if (old_focus_coords (container, &old_focus_rect)) { - child2 = tmp_list->prev->data; - dist2 = (child2->allocation.y + child2->allocation.height / 2) - focus_y; - - if ((dist1 < dist2) && - (child->allocation.x >= child2->allocation.x)) - { - tmp_list->data = tmp_list->prev->data; - tmp_list = tmp_list->prev; - j--; - } + compare.y = old_focus_rect.y + old_focus_rect.height / 2; + } + else + { + if (GTK_WIDGET_NO_WINDOW (widget)) + compare.y = widget->allocation.y + widget->allocation.height / 2; else - break; + compare.y = widget->allocation.height / 2; } - - tmp_list->data = child; + + if (GTK_WIDGET_NO_WINDOW (widget)) + compare.x = (direction == GTK_DIR_RIGHT) ? widget->allocation.x : widget->allocation.x + widget->allocation.width; + else + compare.x = (direction == GTK_DIR_RIGHT) ? 0 : widget->allocation.width; } - /* go and invalidate any widget which is too - * far from the focus widget. - */ - if (!container->focus_child && - (direction == GTK_DIR_LEFT)) - focus_y += focus_height; - - tmp_list = children; - while (tmp_list) - { - child = tmp_list->data; - - dist1 = (child->allocation.y + child->allocation.height / 2) - focus_y; - if (((direction == GTK_DIR_RIGHT) && (dist1 < 0)) || - ((direction == GTK_DIR_LEFT) && (dist1 > 0))) - tmp_list->data = NULL; - - tmp_list = tmp_list->next; - } + *children = g_list_sort_with_data (*children, left_right_compare, &compare); if (direction == GTK_DIR_LEFT) - children = g_list_reverse (children); + *children = g_list_reverse (*children); - return gtk_container_focus_move (container, children, direction); + return gtk_container_focus_move (container, *children, direction); } -static gint +static gboolean gtk_container_focus_move (GtkContainer *container, GList *children, GtkDirectionType direction) @@ -1722,7 +1786,6 @@ gtk_container_focus_move (GtkContainer *container, GtkWidget *child; focus_child = container->focus_child; - gtk_container_set_focus_child (container, NULL); while (children) { @@ -1739,8 +1802,7 @@ gtk_container_focus_move (GtkContainer *container, focus_child = NULL; if (GTK_WIDGET_DRAWABLE (child) && - GTK_IS_CONTAINER (child) && - !GTK_WIDGET_HAS_FOCUS (child)) + GTK_IS_CONTAINER (child)) if (gtk_container_focus (GTK_CONTAINER (child), direction)) return TRUE; } |