[cairo-commit] goocanvas/src goocanvasitemsimple.c, 1.8, 1.9 goocanvasitemview.c, 1.7, 1.8 goocanvasitemview.h, 1.7, 1.8 goocanvasview.c, 1.14, 1.15

Damon Chaplin commit at pdx.freedesktop.org
Sat Apr 22 12:17:30 PDT 2006


Committed by: damon

Update of /cvs/cairo/goocanvas/src
In directory kemper:/tmp/cvs-serv26926/src

Modified Files:
	goocanvasitemsimple.c goocanvasitemview.c goocanvasitemview.h 
	goocanvasview.c 
Log Message:
2006-04-22  Damon Chaplin  <damon at gnome.org>

	* src/goocanvasview.c: added support for keyboard focus navigation.
	(I still need to make it scroll to show the focused item if needed.)

	* demo/demo-focus.c: new demo page to test keyboard focus navigation.

	* src/goocanvasitemview.c: added "focus-in-event" & "focus-out-event"
	signals.

	* src/goocanvasitemsimple.c (goo_canvas_item_simple_get_path_bounds): 
	make sure we do min/max over all points of bounds.

	* src/goocanvasview.c (goo_canvas_view_focus_out): emit
	"focus_out_event", not "focus_in_event".



Index: goocanvasitemsimple.c
===================================================================
RCS file: /cvs/cairo/goocanvas/src/goocanvasitemsimple.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- goocanvasitemsimple.c	18 Apr 2006 23:40:44 -0000	1.8
+++ goocanvasitemsimple.c	22 Apr 2006 19:17:28 -0000	1.9
@@ -848,21 +848,33 @@
 					cairo_t             *cr,
 					GooCanvasBounds     *bounds)
 {
-  GooCanvasBounds tmp_bounds;
+  GooCanvasBounds tmp_bounds, tmp_bounds2;
 
   /* Calculate the filled extents. */
   goo_canvas_item_simple_set_fill_options (item, cr);
-  cairo_fill_extents (cr, &bounds->x1, &bounds->y1, &bounds->x2, &bounds->y2);
+  cairo_fill_extents (cr, &tmp_bounds.x1, &tmp_bounds.y1,
+		      &tmp_bounds.x2, &tmp_bounds.y2);
 
   /* Check the stroke. */
   goo_canvas_item_simple_set_stroke_options (item, cr);
-  cairo_stroke_extents (cr, &tmp_bounds.x1, &tmp_bounds.y1,
-			&tmp_bounds.x2, &tmp_bounds.y2);
+  cairo_stroke_extents (cr, &tmp_bounds2.x1, &tmp_bounds2.y1,
+			&tmp_bounds2.x2, &tmp_bounds2.y2);
 
-  bounds->x1 = MIN (bounds->x1, tmp_bounds.x1);
-  bounds->y1 = MIN (bounds->y1, tmp_bounds.y1);
-  bounds->x2 = MAX (bounds->x2, tmp_bounds.x2);
-  bounds->y2 = MAX (bounds->y2, tmp_bounds.y2);
+  bounds->x1 = MIN (tmp_bounds.x1, tmp_bounds.x2);
+  bounds->x1 = MIN (bounds->x1, tmp_bounds2.x1);
+  bounds->x1 = MIN (bounds->x1, tmp_bounds2.x2);
+
+  bounds->x2 = MAX (tmp_bounds.x1, tmp_bounds.x2);
+  bounds->x2 = MAX (bounds->x2, tmp_bounds2.x1);
+  bounds->x2 = MAX (bounds->x2, tmp_bounds2.x2);
+
+  bounds->y1 = MIN (tmp_bounds.y1, tmp_bounds.y2);
+  bounds->y1 = MIN (bounds->y1, tmp_bounds2.y1);
+  bounds->y1 = MIN (bounds->y1, tmp_bounds2.y2);
+
+  bounds->y2 = MAX (tmp_bounds.y1, tmp_bounds.y2);
+  bounds->y2 = MAX (bounds->y2, tmp_bounds2.y1);
+  bounds->y2 = MAX (bounds->y2, tmp_bounds2.y2);
 
   goo_canvas_item_simple_user_bounds_to_device (item, cr, bounds);
 }

Index: goocanvasitemview.c
===================================================================
RCS file: /cvs/cairo/goocanvas/src/goocanvasitemview.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- goocanvasitemview.c	18 Apr 2006 15:43:07 -0000	1.7
+++ goocanvasitemview.c	22 Apr 2006 19:17:28 -0000	1.8
@@ -30,6 +30,8 @@
   BUTTON_RELEASE_EVENT,
 
   /* Keyboard events. */
+  FOCUS_IN_EVENT,
+  FOCUS_OUT_EVENT,
   KEY_PRESS_EVENT,
   KEY_RELEASE_EVENT,
 
@@ -204,6 +206,52 @@
       /* Keyboard events. */
 
       /**
+       * GooCanvasItemView::focus-in-event
+       * @view: the item view that received the signal.
+       * @target_view: the target of the event.
+       * @event: the event data.
+       *
+       * Emitted when the item receives the keyboard focus.
+       *
+       * Returns: %TRUE to stop the signal emission, or %FALSE to let it
+       *  continue.
+       */
+      canvas_item_view_signals[FOCUS_IN_EVENT] =
+	g_signal_new ("focus_in_event",
+		      iface_type,
+		      G_SIGNAL_RUN_LAST,
+		      G_STRUCT_OFFSET (GooCanvasItemViewIface,
+				       focus_in_event),
+		      NULL, NULL,
+		      goo_canvas_marshal_BOOLEAN__OBJECT_BOXED,
+		      G_TYPE_BOOLEAN, 2,
+		      GOO_TYPE_CANVAS_ITEM_VIEW,
+		      GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
+
+      /**
+       * GooCanvasItemView::focus-out-event
+       * @view: the item view that received the signal.
+       * @target_view: the target of the event.
+       * @event: the event data.
+       *
+       * Emitted when the item loses the keyboard focus.
+       *
+       * Returns: %TRUE to stop the signal emission, or %FALSE to let it
+       *  continue.
+       */
+      canvas_item_view_signals[FOCUS_OUT_EVENT] =
+	g_signal_new ("focus_out_event",
+		      iface_type,
+		      G_SIGNAL_RUN_LAST,
+		      G_STRUCT_OFFSET (GooCanvasItemViewIface,
+				       focus_out_event),
+		      NULL, NULL,
+		      goo_canvas_marshal_BOOLEAN__OBJECT_BOXED,
+		      G_TYPE_BOOLEAN, 2,
+		      GOO_TYPE_CANVAS_ITEM_VIEW,
+		      GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
+
+      /**
        * GooCanvasItemView::key-press-event
        * @view: the item view that received the signal.
        * @target_view: the target of the event.
@@ -528,6 +576,9 @@
  *
  * This entails checking the item's own visibility setting, as well as those
  * of its ancestors.
+ *
+ * Note that this the item may be scrolled off the screen and so may not
+ * be actually visible to the user.
  * 
  * Returns: %TRUE if the item is visible.
  **/

Index: goocanvasitemview.h
===================================================================
RCS file: /cvs/cairo/goocanvas/src/goocanvasitemview.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- goocanvasitemview.h	18 Apr 2006 15:43:07 -0000	1.7
+++ goocanvasitemview.h	22 Apr 2006 19:17:28 -0000	1.8
@@ -91,6 +91,12 @@
   gboolean	       (* button_release_event)	(GooCanvasItemView   *view,
 						 GooCanvasItemView   *target,
 						 GdkEventButton      *event);
+  gboolean	       (* focus_in_event)	(GooCanvasItemView   *view,
+						 GooCanvasItemView   *target,
+						 GdkEventFocus       *event);
+  gboolean	       (* focus_out_event)	(GooCanvasItemView   *view,
+						 GooCanvasItemView   *target,
+						 GdkEventFocus       *event);
   gboolean	       (* key_press_event)	(GooCanvasItemView   *view,
 						 GooCanvasItemView   *target,
 						 GdkEventKey         *event);

Index: goocanvasview.c
===================================================================
RCS file: /cvs/cairo/goocanvas/src/goocanvasview.c,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -d -r1.14 -r1.15
--- goocanvasview.c	18 Apr 2006 15:43:07 -0000	1.14
+++ goocanvasview.c	22 Apr 2006 19:17:28 -0000	1.15
@@ -121,6 +121,7 @@
  *
  */
 #include <config.h>
+#include <math.h>
 #include <gtk/gtk.h>
 #include "goocanvasatk.h"
 #include "goocanvasview.h"
@@ -156,6 +157,8 @@
 						 GdkEventButton   *event);
 static gboolean goo_canvas_view_motion          (GtkWidget        *widget,
 						 GdkEventMotion   *event);
+static gboolean goo_canvas_view_focus		(GtkWidget        *widget,
+						 GtkDirectionType  direction);
 static gboolean goo_canvas_view_key_press       (GtkWidget        *widget,
 						 GdkEventKey      *event);
 static gboolean goo_canvas_view_key_release     (GtkWidget        *widget,
@@ -196,6 +199,7 @@
   widget_class->button_press_event   = goo_canvas_view_button_press;
   widget_class->button_release_event = goo_canvas_view_button_release;
   widget_class->motion_notify_event  = goo_canvas_view_motion;
+  widget_class->focus                = goo_canvas_view_focus;
   widget_class->key_press_event      = goo_canvas_view_key_press;
   widget_class->key_release_event    = goo_canvas_view_key_release;
   widget_class->enter_notify_event   = goo_canvas_view_crossing;
@@ -1154,8 +1158,6 @@
   if (!view->root_view)
     return FALSE;
 
-  /*sleep (1);*/
-
   if (event->window != view->canvas_window)
     return FALSE;
 
@@ -1600,7 +1602,7 @@
 
   if (view->focused_item_view)
     return propagate_event (view, view->focused_item_view,
-			    "focus_in_event", (GdkEvent*) event);
+			    "focus_out_event", (GdkEvent*) event);
   else
     return FALSE;
 }
@@ -1971,6 +1973,17 @@
 }
 
 
+static void
+goo_canvas_view_convert_from_window_pixels (GooCanvasView     *canvas_view,
+					    gdouble           *x,
+					    gdouble           *y)
+{
+  *x += canvas_view->hadjustment->value;
+  *y += canvas_view->vadjustment->value;
+  goo_canvas_view_convert_from_pixels (canvas_view, x, y);
+}
+
+
 /**
  * goo_canvas_view_convert_to_item_space:
  * @canvas_view: a #GooCanvasView.
@@ -2063,3 +2076,399 @@
 }
 
 
+/*
+ * Keyboard focus navigation.
+ */
+
+typedef struct _GooCanvasViewFocusData GooCanvasViewFocusData;
+struct _GooCanvasViewFocusData
+{
+  /* The current focused item view, or NULL. */
+  GooCanvasItemView *focused_item_view;
+
+  /* The bounds of the current focused item view. We try to find the next
+     closest one in the desired direction. */
+  GooCanvasBounds focused_bounds;
+  gdouble focused_center_x, focused_center_y;
+
+  /* The direction to move the focus in. */
+  GtkDirectionType  direction;
+
+  /* The text direction of the widget. */
+  GtkTextDirection text_direction;
+
+  /* The best view found so far, and the offsets for it. */
+  GooCanvasItemView *best_item_view;
+  gdouble best_x_offset, best_y_offset, best_score;
+
+  /* The offsets for the item being tested. */
+  GooCanvasBounds *current_bounds;
+  gdouble current_x_offset, current_y_offset, current_score;
+};
+
+
+/* This tries to figure out the bounds of the currently focused canvas item
+   view or widget. */
+static void
+goo_canvas_view_get_current_focus_bounds (GooCanvasView          *view,
+					  GooCanvasViewFocusData *data)
+{
+  GooCanvasBounds *bounds;
+  GtkWidget *toplevel, *focus_widget;
+  GtkAllocation *allocation;
+  gint focus_widget_x, focus_widget_y;
+
+  /* If an item view is currently focused, we just need its bounds. */
+  if (data->focused_item_view)
+    {
+      bounds = goo_canvas_item_view_get_bounds (data->focused_item_view);
+      data->focused_bounds = *bounds;
+      return;
+    }
+
+  /* Otherwise try to get the currently focused widget in the window. */
+  toplevel = gtk_widget_get_toplevel (GTK_WIDGET (view));
+  bounds = &data->focused_bounds;
+  if (toplevel && GTK_IS_WINDOW (toplevel)
+      && GTK_WINDOW (toplevel)->focus_widget)
+    {
+      focus_widget = GTK_WINDOW (toplevel)->focus_widget;
+
+      /* Translate the allocation to be relative to the GooCanvasView.
+	 Skip ancestor widgets as the coords won't help. */
+      if (!gtk_widget_is_ancestor (GTK_WIDGET (view), focus_widget)
+	  && gtk_widget_translate_coordinates (focus_widget, GTK_WIDGET (view),
+					       0, 0, &focus_widget_x,
+					       &focus_widget_y))
+	{
+	  /* Translate into device units. */
+	  bounds->x1 = focus_widget_x;
+	  bounds->y1 = focus_widget_y;
+	  bounds->x2 = focus_widget_x + focus_widget->allocation.width;
+	  bounds->y2 = focus_widget_y + focus_widget->allocation.height;
+
+	  goo_canvas_view_convert_from_window_pixels (view, &bounds->x1,
+						      &bounds->y1);
+	  goo_canvas_view_convert_from_window_pixels (view, &bounds->x2,
+						      &bounds->y2);
+	  return;
+	}
+    }
+
+  /* As a last resort, we guess a starting position based on the direction. */
+  allocation = &GTK_WIDGET (view)->allocation;
+  switch (data->direction)
+    {
+    case GTK_DIR_DOWN:
+    case GTK_DIR_RIGHT:
+      /* Start from top-left. */
+      bounds->x1 = 0.0;
+      bounds->y1 = 0.0;
+      break;
+
+    case GTK_DIR_UP:
+      /* Start from bottom-left. */
+      bounds->x1 = 0.0;
+      bounds->y1 = allocation->height;
+      break;
+
+    case GTK_DIR_LEFT:
+      /* Start from top-right. */
+      bounds->x1 = allocation->width;
+      bounds->y1 = 0.0;
+      break;
+
+    case GTK_DIR_TAB_FORWARD:
+      bounds->y1 = 0.0;
+      if (data->text_direction == GTK_TEXT_DIR_RTL)
+	/* Start from top-right. */
+	bounds->x1 = allocation->width;
+      else
+	/* Start from top-left. */
+	bounds->x1 = 0.0;
+      break;
+
+    case GTK_DIR_TAB_BACKWARD:
+      bounds->y1 = allocation->height;
+      if (data->text_direction == GTK_TEXT_DIR_RTL)
+	/* Start from bottom-left. */
+	bounds->x1 = 0.0;
+      else
+	/* Start from bottom-right. */
+	bounds->x1 = allocation->width;
+      break;
+    }
+
+  goo_canvas_view_convert_from_window_pixels (view, &bounds->x1, &bounds->y1);
+  bounds->x2 = bounds->x1;
+  bounds->y2 = bounds->y1;
+}
+
+
+/* Check if the given item view is a better candidate for the focus than
+   the current best one in the data struct. */
+static gboolean
+goo_canvas_view_focus_check_is_best (GooCanvasView          *view,
+				     GooCanvasItemView      *item_view,
+				     GooCanvasViewFocusData *data)
+{
+  gdouble center_x, center_y;
+  gdouble abs_x_offset, abs_y_offset;
+
+  data->current_score = 0.0;
+
+  data->current_bounds = goo_canvas_item_view_get_bounds (item_view);
+  center_x = (data->current_bounds->x1 + data->current_bounds->x2) / 2.0;
+  center_y = (data->current_bounds->y1 + data->current_bounds->y2) / 2.0;
+
+  /* Calculate the offsets of the center of this item view from the center
+     of the current focus item view or widget. */
+  data->current_x_offset = center_x - data->focused_center_x;
+  data->current_y_offset = center_y - data->focused_center_y;
+
+  abs_x_offset = fabs (data->current_x_offset);
+  abs_y_offset = fabs (data->current_y_offset);
+
+  switch (data->direction)
+    {
+    case GTK_DIR_UP:
+      /* If the y offset is > 0 we can discard this item view. */
+      if (data->current_y_offset >= 0)
+	return FALSE;
+
+      /* Compute a score (lower is best) and check if it is the best. */
+      data->current_score = abs_x_offset * 2 + abs_y_offset;
+      if (!data->best_item_view || data->current_score < data->best_score)
+	return TRUE;
+      break;
+
+    case GTK_DIR_DOWN:
+      /* If the y offset is < 0 we can discard this item view. */
+      if (data->current_y_offset <= 0)
+	return FALSE;
+
+      /* Compute a score (lower is best) and check if it is the best. */
+      data->current_score = abs_x_offset * 2 + abs_y_offset;
+      if (!data->best_item_view || data->current_score < data->best_score)
+	return TRUE;
+      break;
+
+    case GTK_DIR_LEFT:
+      /* If the x offset is > 0 we can discard this item view. */
+      if (data->current_x_offset >= 0)
+	return FALSE;
+
+      /* Compute a score (lower is best) and check if it is the best. */
+      data->current_score = abs_y_offset * 2 + abs_x_offset;
+      if (!data->best_item_view || data->current_score < data->best_score)
+	return TRUE;
+      break;
+
+    case GTK_DIR_RIGHT:
+      /* If the x offset is < 0 we can discard this item view. */
+      if (data->current_x_offset <= 0)
+	return FALSE;
+
+      /* Compute a score (lower is best) and check if it is the best. */
+      data->current_score = abs_y_offset * 2 + abs_x_offset;
+      if (!data->best_item_view || data->current_score < data->best_score)
+	return TRUE;
+      break;
+
+    case GTK_DIR_TAB_BACKWARD:
+      /* We need to handle this differently depending on text direction. */
+      if (data->text_direction == GTK_TEXT_DIR_RTL)
+	{
+	  /* If the y offset is > 0, or it is 0 and the x offset > 0 we can
+	     discard this item view. */
+	  if (data->current_y_offset > 0
+	      || (data->current_y_offset == 0 && data->current_x_offset < 0))
+	    return FALSE;
+
+	  /* If the y offset is > the current best y offset, this is best. */
+	  if (!data->best_item_view || data->current_y_offset > data->best_y_offset)
+	    return TRUE;
+
+	  /* If the y offsets are the same, choose the largest x offset. */
+	  if (data->current_y_offset == data->best_y_offset
+	      && data->current_x_offset < data->best_x_offset)
+	    return TRUE;
+	}
+      else
+	{
+	  /* If the y offset is > 0, or it is 0 and the x offset > 0 we can
+	     discard this item view. */
+	  if (data->current_y_offset > 0
+	      || (data->current_y_offset == 0 && data->current_x_offset > 0))
+	    return FALSE;
+
+	  /* If the y offset is > the current best y offset, this is best. */
+	  if (!data->best_item_view || data->current_y_offset > data->best_y_offset)
+	    return TRUE;
+
+	  /* If the y offsets are the same, choose the largest x offset. */
+	  if (data->current_y_offset == data->best_y_offset
+	      && data->current_x_offset > data->best_x_offset)
+	    return TRUE;
+	}
+      break;
+
+    case GTK_DIR_TAB_FORWARD:
+      /* We need to handle this differently depending on text direction. */
+      if (data->text_direction == GTK_TEXT_DIR_RTL)
+	{
+	  /* If the y offset is < 0, or it is 0 and the x offset > 0 we can
+	     discard this item view. */
+	  if (data->current_y_offset < 0
+	      || (data->current_y_offset == 0 && data->current_x_offset > 0))
+	    return FALSE;
+
+	  /* If the y offset is < the current best y offset, this is best. */
+	  if (!data->best_item_view || data->current_y_offset < data->best_y_offset)
+	    return TRUE;
+
+	  /* If the y offsets are the same, choose the largest x offset. */
+	  if (data->current_y_offset == data->best_y_offset
+	      && data->current_x_offset > data->best_x_offset)
+	    return TRUE;
+	}
+      else
+	{
+	  /* If the y offset is < 0, or it is 0 and the x offset < 0 we can
+	     discard this item view. */
+	  if (data->current_y_offset < 0
+	      || (data->current_y_offset == 0 && data->current_x_offset < 0))
+	    return FALSE;
+
+	  /* If the y offset is < the current best y offset, this is best. */
+	  if (!data->best_item_view || data->current_y_offset < data->best_y_offset)
+	    return TRUE;
+
+	  /* If the y offsets are the same, choose the smallest x offset. */
+	  if (data->current_y_offset == data->best_y_offset
+	      && data->current_x_offset < data->best_x_offset)
+	    return TRUE;
+	}
+      break;
+    }
+
+  return FALSE;
+}
+
+
+/* Recursively look for the next best item view in the desired direction. */
+static void
+goo_canvas_view_focus_recurse (GooCanvasView          *view,
+			       GooCanvasItemView      *item_view,
+			       GooCanvasViewFocusData *data)
+{
+  GooCanvasItem *item = goo_canvas_item_view_get_item (item_view);
+  GooCanvasItemView *child_view;
+  gboolean can_focus = FALSE, is_best;
+  gint n_children, i;
+
+  /* If the item is not a possible candidate, just return. */
+  is_best = goo_canvas_view_focus_check_is_best (view, item_view, data);
+
+  if (is_best && goo_canvas_item_view_is_visible (item_view, view->scale))
+    {
+      /* Check if the item view can take the focus. */
+      g_object_get (item_view, "can-focus", &can_focus, NULL);
+
+      /* If the item view can take the focus itself, and it isn't the current
+	 focus item, save its score and return. (If it is a container it takes
+	 precedence over its children). */
+      if (can_focus && item_view != data->focused_item_view)
+	{
+	  data->best_item_view = item_view;
+	  data->best_x_offset = data->current_x_offset;
+	  data->best_y_offset = data->current_y_offset;
+	  data->best_score = data->current_score;
+	  return;
+	}
+    }
+
+  /* If the item view is a container view, check the children recursively. */
+  n_children = goo_canvas_item_view_get_n_children (item_view);
+  if (n_children)
+    {
+      /* Check if we can skip the entire group. */
+      switch (data->direction)
+	{
+	case GTK_DIR_UP:
+	  /* If the group is below the bottom of the current focused item
+	     view we can skip it. */
+	  if (data->current_bounds->y1 > data->focused_bounds.y2)
+	    return;
+	  break;
+	case GTK_DIR_DOWN:
+	  /* If the group is above the top of the current focused item
+	     view we can skip it. */
+	  if (data->current_bounds->y2 < data->focused_bounds.y1)
+	    return;
+	  break;
+	case GTK_DIR_LEFT:
+	  /* If the group is to the right of the current focused item
+	     view we can skip it. */
+	  if (data->current_bounds->x1 > data->focused_bounds.x2)
+	    return;
+	  break;
+	case GTK_DIR_RIGHT:
+	  /* If the group is to the left of the current focused item
+	     view we can skip it. */
+	  if (data->current_bounds->x2 < data->focused_bounds.x1)
+	    return;
+	  break;
+	default:
+	  break;
+	}
+
+      for (i = 0; i < n_children; i++)
+	{
+	  child_view = goo_canvas_item_view_get_child (item_view, i);
+	  goo_canvas_view_focus_recurse (view, child_view, data);
+	}
+    }
+}
+
+
+static gboolean
+goo_canvas_view_focus (GtkWidget        *widget,
+		       GtkDirectionType  direction)
+{
+  GooCanvasView *view;
+  GooCanvasViewFocusData data;
+
+  g_return_val_if_fail (GOO_IS_CANVAS_VIEW (widget), FALSE);
+
+  view = GOO_CANVAS_VIEW (widget);
+
+  /* If keyboard navigation has been turned off for the canvas, return FALSE.*/
+  if (!GTK_WIDGET_CAN_FOCUS (view))
+    return FALSE;
+
+  data.direction = direction;
+  data.text_direction = gtk_widget_get_direction (widget);
+  data.best_item_view = NULL;
+  data.focused_item_view = NULL;
+
+  if (GTK_WIDGET_HAS_FOCUS (view))
+    data.focused_item_view = view->focused_item_view;
+
+  /* Get the bounds of the currently focused item or widget. */
+  goo_canvas_view_get_current_focus_bounds (view, &data);
+  data.focused_center_x = (data.focused_bounds.x1 + data.focused_bounds.x2) / 2.0;
+  data.focused_center_y = (data.focused_bounds.y1 + data.focused_bounds.y2) / 2.0;
+
+  /* Recursively look for the next best item view in the desired direction. */
+  goo_canvas_view_focus_recurse (view, view->root_view, &data);
+
+  /* If we found an item view to focus, grab the focus and return TRUE. */
+  if (data.best_item_view)
+    {
+      goo_canvas_view_grab_focus (view, data.best_item_view);
+      return TRUE;
+    }
+
+  return FALSE;
+}



More information about the cairo-commit mailing list