[egg-list-box/flow-box-enhancements: 1/3] Introduce EggFlowBoxChild



commit aa130a1b9763c1b261b860284d09255a716aa745
Author: Matthias Clasen <mclasen redhat com>
Date:   Sat Sep 21 18:32:55 2013 -0400

    Introduce EggFlowBoxChild
    
    This is EggFlowBoxChildInfo turned into a widget.
    We are following the same approach taken by GtkListBox here,
    in having a public child type.

 egg-flow-box-accessible.c |   20 +-
 egg-flow-box-accessible.h |    3 +-
 egg-flow-box.c            | 1116 +++++++++++++++++++++++++++++----------------
 egg-flow-box.h            |   74 +++-
 test-flow-box.c           |    9 +-
 5 files changed, 808 insertions(+), 414 deletions(-)
---
diff --git a/egg-flow-box-accessible.c b/egg-flow-box-accessible.c
index 7b244c3..e799db0 100644
--- a/egg-flow-box-accessible.c
+++ b/egg-flow-box-accessible.c
@@ -78,7 +78,7 @@ egg_flow_box_accessible_add_selection (AtkSelection *selection,
   g_list_free (children);
   if (child)
     {
-      egg_flow_box_select_child (EGG_FLOW_BOX (box), child);
+      egg_flow_box_select_child (EGG_FLOW_BOX (box), EGG_FLOW_BOX_CHILD (child));
       return TRUE;
     }
   return FALSE;
@@ -101,7 +101,7 @@ egg_flow_box_accessible_remove_selection (AtkSelection *selection,
   g_list_free (children);
   if (child)
     {
-      egg_flow_box_unselect_child (EGG_FLOW_BOX (box), child);
+      egg_flow_box_unselect_child (EGG_FLOW_BOX (box), EGG_FLOW_BOX_CHILD (child));
       return TRUE;
     }
   return FALSE;
@@ -140,16 +140,16 @@ typedef struct
 } FindSelectedData;
 
 static void
-find_selected_child (EggFlowBox *box,
-                     GtkWidget  *child,
-                     gpointer    data)
+find_selected_child (EggFlowBox      *box,
+                     EggFlowBoxChild *child,
+                     gpointer         data)
 {
   FindSelectedData *d = data;
 
   if (d->idx == 0)
     {
       if (d->child == NULL)
-        d->child = child;
+        d->child = GTK_WIDGET (child);
     }
   else
     d->idx -= 1;
@@ -181,9 +181,9 @@ egg_flow_box_accessible_ref_selection (AtkSelection *selection,
 }
 
 static void
-count_selected (EggFlowBox *box,
-                GtkWidget  *child,
-                gpointer    data)
+count_selected (EggFlowBox      *box,
+                EggFlowBoxChild *child,
+                gpointer         data)
 {
   gint *count = data;
   *count += 1;
@@ -212,7 +212,7 @@ egg_flow_box_accessible_is_child_selected (AtkSelection *selection,
   GtkWidget *box;
   GtkWidget *widget;
   GList *children;
-  GtkWidget *child;
+  EggFlowBoxChild *child;
 
   box = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
   if (box == NULL)
diff --git a/egg-flow-box-accessible.h b/egg-flow-box-accessible.h
index 779aee4..fac44f5 100644
--- a/egg-flow-box-accessible.h
+++ b/egg-flow-box-accessible.h
@@ -48,7 +48,8 @@ struct _EggFlowBoxAccessibleClass
 GType egg_flow_box_accessible_get_type (void);
 
 void _egg_flow_box_accessible_selection_changed (GtkWidget *box);
-void _egg_flow_box_accessible_update_cursor     (GtkWidget *box, GtkWidget *child);
+void _egg_flow_box_accessible_update_cursor     (GtkWidget *box,
+                                                 GtkWidget *child);
 
 G_END_DECLS
 
diff --git a/egg-flow-box.c b/egg-flow-box.c
index d8ef538..fa295e8 100644
--- a/egg-flow-box.c
+++ b/egg-flow-box.c
@@ -77,6 +77,7 @@ _egg_marshal_VOID__ENUM_INT (GClosure * closure,
   callback (data1, g_value_get_enum (param_values + 1), g_value_get_int (param_values + 2), data2);
 }
 
+#define I_(msgid) (msgid)
 #define P_(msgid) (msgid)
 
 #define DEFAULT_MAX_CHILDREN_PER_LINE 7
@@ -93,6 +94,11 @@ enum {
 };
 
 enum {
+  CHILD_ACTIVATE,
+  CHILD_LAST_SIGNAL
+};
+
+enum {
   PROP_0,
   PROP_ORIENTATION,
   PROP_HOMOGENEOUS,
@@ -106,46 +112,49 @@ enum {
   PROP_ACTIVATE_ON_SINGLE_CLICK
 };
 
-typedef struct _EggFlowBoxChildInfo EggFlowBoxChildInfo;
-
 struct _EggFlowBoxPrivate {
-  GtkOrientation orientation;
-  GtkAlign       halign_policy;
-  GtkAlign       valign_policy;
-  guint          homogeneous : 1;
-  guint          activate_on_single_click : 1;
-  GtkSelectionMode selection_mode;
-  GtkAdjustment *adjustment;
-
-  guint          row_spacing;
-  guint          column_spacing;
-
-  gboolean       active_child_active;
-  EggFlowBoxChildInfo *active_child;
-  EggFlowBoxChildInfo *prelight_child;
-  EggFlowBoxChildInfo *cursor_child;
-  EggFlowBoxChildInfo *selected_child;
-
-  guint16        min_children_per_line;
-  guint16        max_children_per_line;
-  guint16        cur_children_per_line;
-
-  GSequence     *children;
-  GHashTable    *child_hash;
+  GtkOrientation    orientation;
+  GtkAlign          halign_policy;
+  GtkAlign          valign_policy;
+  gboolean          homogeneous;
+
+  guint             row_spacing;
+  guint             column_spacing;
+
+  EggFlowBoxChild  *prelight_child;
+  EggFlowBoxChild  *cursor_child;
+  EggFlowBoxChild  *selected_child;
+
+  gboolean          active_child_active;
+  EggFlowBoxChild  *active_child;
+
+  GtkSelectionMode  selection_mode;
+
+  GtkAdjustment    *adjustment;
+  gboolean          activate_on_single_click;
+
+  guint16           min_children_per_line;
+  guint16           max_children_per_line;
+  guint16           cur_children_per_line;
+
+  GSequence        *children;
 };
 
-struct _EggFlowBoxChildInfo
+typedef struct _EggFlowBoxChildPrivate EggFlowBoxChildPrivate;
+struct _EggFlowBoxChildPrivate
 {
   GSequenceIter *iter;
-  GtkWidget *widget;
-  guint selected : 1;
-  GdkRectangle area;
+  GtkWidget     *widget;
+  guint          selected : 1;
+  GdkRectangle   area;
 };
 
 static guint signals[LAST_SIGNAL] = { 0 };
+static guint child_signals[CHILD_LAST_SIGNAL] = { 0 };
 
 G_DEFINE_TYPE_WITH_CODE (EggFlowBox, egg_flow_box, GTK_TYPE_CONTAINER,
                          G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL))
+G_DEFINE_TYPE_WITH_PRIVATE (EggFlowBoxChild, egg_flow_box_child, GTK_TYPE_BIN)
 
 
 #define ORIENTATION_ALIGN_POLICY(box)                                   \
@@ -158,29 +167,345 @@ G_DEFINE_TYPE_WITH_CODE (EggFlowBox, egg_flow_box, GTK_TYPE_CONTAINER,
    ((EggFlowBox *)(box))->priv->valign_policy :                         \
    ((EggFlowBox *)(box))->priv->halign_policy)
 
-static EggFlowBoxChildInfo*
-egg_flow_box_child_info_new (GtkWidget *widget)
+static void egg_flow_box_update_cursor       (EggFlowBox      *box,
+                                              EggFlowBoxChild *child);
+static void egg_flow_box_select_and_activate (EggFlowBox      *box,
+                                              EggFlowBoxChild *child);
+static void egg_flow_box_update_selection    (EggFlowBox      *box,
+                                              EggFlowBoxChild *child,
+                                              gboolean         modify,
+                                              gboolean         extend);
+
+GtkWidget *
+egg_flow_box_child_new (void)
+{
+  return g_object_new (EGG_TYPE_FLOW_BOX_CHILD, NULL);
+}
+
+static void
+egg_flow_box_child_init (EggFlowBoxChild *child)
+{
+  GtkStyleContext *context;
+
+  gtk_widget_set_can_focus (GTK_WIDGET (child), TRUE);
+  gtk_widget_set_redraw_on_allocate (GTK_WIDGET (child), TRUE);
+
+  context = gtk_widget_get_style_context (GTK_WIDGET (child));
+  gtk_style_context_add_class (context, "grid-child");
+}
+
+static EggFlowBox *
+egg_flow_box_child_get_box (EggFlowBoxChild *child)
 {
-  EggFlowBoxChildInfo *info;
+  GtkWidget *parent;
+
+  parent = gtk_widget_get_parent (GTK_WIDGET (child));
+  if (parent && EGG_IS_FLOW_BOX (parent))
+    return EGG_FLOW_BOX (parent);
 
-  info = g_new0 (EggFlowBoxChildInfo, 1);
-  info->widget = g_object_ref (widget);
-  return info;
+  return NULL;
 }
 
 static void
-egg_flow_box_child_info_free (EggFlowBoxChildInfo *info)
+egg_flow_box_child_set_focus (EggFlowBoxChild *child)
 {
-  g_clear_object (&info->widget);
-  g_free (info);
+  EggFlowBox *box = egg_flow_box_child_get_box (child);
+  GdkModifierType state = 0;
+  gboolean modify_selection_pressed;
+
+  modify_selection_pressed = FALSE;
+  if (gtk_get_current_event_state (&state))
+    {
+      GdkModifierType modify_mod_mask;
+      modify_mod_mask =
+        gtk_widget_get_modifier_mask (GTK_WIDGET (box),
+                                      GDK_MODIFIER_INTENT_MODIFY_SELECTION);
+      if ((state & modify_mod_mask) == modify_mod_mask)
+        modify_selection_pressed = TRUE;
+    }
+
+  if (modify_selection_pressed)
+    egg_flow_box_update_cursor (box, child);
+  else
+    egg_flow_box_update_selection (box, child, FALSE, FALSE);
 }
 
-static EggFlowBoxChildInfo*
-egg_flow_box_lookup_info (EggFlowBox *flow_box, GtkWidget* child)
+static gboolean
+egg_flow_box_child_focus (GtkWidget        *widget,
+                          GtkDirectionType  direction)
 {
-  EggFlowBoxPrivate *priv = flow_box->priv;
+  gboolean had_focus = FALSE;
+  GtkWidget *child;
+
+  child = gtk_bin_get_child (GTK_BIN (widget));
+
+  g_object_get (widget, "has-focus", &had_focus, NULL);
+  if (had_focus)
+    {
+      /* If on row, going right, enter into possible container */
+      if (child &&
+          (direction == GTK_DIR_RIGHT || direction == GTK_DIR_TAB_FORWARD))
+        {
+          if (gtk_widget_child_focus (GTK_WIDGET (child), direction))
+            return TRUE;
+        }
+
+      return FALSE;
+    }
+  else if (gtk_container_get_focus_child (GTK_CONTAINER (widget)) != NULL)
+    {
+      /* Child has focus, always navigate inside it first */
+
+      if (gtk_widget_child_focus (child, direction))
+        return TRUE;
+      /* If exiting child container to the left, select child  */
+      if (direction == GTK_DIR_LEFT || direction == GTK_DIR_TAB_BACKWARD)
+        {
+          egg_flow_box_child_set_focus (EGG_FLOW_BOX_CHILD (widget));
+          return TRUE;
+        }
+
+      return FALSE;
+    }
+  else
+    {
+      /* If coming from the left, enter into possible container */
+      if (child &&
+          (direction == GTK_DIR_LEFT || direction == GTK_DIR_TAB_BACKWARD))
+        {
+          if (gtk_widget_child_focus (child, direction))
+            return TRUE;
+        }
+
+      egg_flow_box_child_set_focus (EGG_FLOW_BOX_CHILD (widget));
+      return TRUE;
+    }
+}
+
+static void
+egg_flow_box_child_activate (EggFlowBoxChild *child)
+{
+  EggFlowBox *box;
+
+  box = egg_flow_box_child_get_box (child);
+  if (box)
+    egg_flow_box_select_and_activate (box, child);
+}
+
+static void
+egg_flow_box_child_visibility_changed (EggFlowBox      *box,
+                                       EggFlowBoxChild *child)
+{
+}
+
+static void
+egg_flow_box_child_show (GtkWidget *widget)
+{
+  EggFlowBoxChild *child = EGG_FLOW_BOX_CHILD (widget);
+  EggFlowBox *box;
+
+  GTK_WIDGET_CLASS (egg_flow_box_child_parent_class)->show (widget);
+
+  box = egg_flow_box_child_get_box (child);
+  if (box)
+    egg_flow_box_child_visibility_changed (box, child);
+}
+
+static void
+egg_flow_box_child_hide (GtkWidget *widget)
+{
+  EggFlowBoxChild *child = EGG_FLOW_BOX_CHILD (widget);
+  EggFlowBox *box;
+
+  GTK_WIDGET_CLASS (egg_flow_box_child_parent_class)->hide (widget);
+
+  box = egg_flow_box_child_get_box (child);
+  if (box)
+    egg_flow_box_child_visibility_changed (box, child);
+}
+
+static gboolean
+egg_flow_box_child_draw (GtkWidget *widget,
+                         cairo_t   *cr)
+{
+  GtkAllocation allocation = {0};
+  GtkStyleContext* context;
+  GtkStateFlags state;
+  GtkBorder border;
+  gint focus_pad;
+
+  gtk_widget_get_allocation (widget, &allocation);
+  context = gtk_widget_get_style_context (widget);
+  state = gtk_widget_get_state_flags (widget);
+
+  gtk_render_background (context, cr, 0, 0, allocation.width, allocation.height);
+  gtk_render_frame (context, cr, 0, 0, allocation.width, allocation.height);
+
+  if (gtk_widget_has_visible_focus (widget))
+    {
+      gtk_style_context_get_border (context, state, &border);
+
+      gtk_style_context_get_style (context,
+                                   "focus-padding", &focus_pad,
+                                   NULL);
+      gtk_render_focus (context, cr, border.left + focus_pad, border.top + focus_pad,
+                        allocation.width - 2 * focus_pad - border.left - border.right,
+                        allocation.height - 2 * focus_pad - border.top - border.bottom);
+    }
+
+  GTK_WIDGET_CLASS (egg_flow_box_child_parent_class)->draw (widget, cr);
+
+  return TRUE;
+}
+
+static void
+egg_flow_box_child_get_full_border (EggFlowBoxChild *child,
+                                    GtkBorder       *full_border)
+{
+  GtkWidget *widget = GTK_WIDGET (child);
+  GtkStyleContext *context;
+  GtkStateFlags state;
+  GtkBorder padding, border;
+  int focus_width, focus_pad;
+
+  context = gtk_widget_get_style_context (widget);
+  state = gtk_style_context_get_state (context);
+
+  gtk_style_context_get_padding (context, state, &padding);
+  gtk_style_context_get_border (context, state, &border);
+  gtk_style_context_get_style (context,
+                               "focus-line-width", &focus_width,
+                               "focus-padding", &focus_pad,
+                               NULL);
+
+  full_border->left = padding.left + border.left + focus_width + focus_pad;
+  full_border->right = padding.right + border.right + focus_width + focus_pad;
+  full_border->top = padding.top + border.top + focus_width + focus_pad;
+  full_border->bottom = padding.bottom + border.bottom + focus_width + focus_pad;
+}
+
+static void
+egg_flow_box_child_get_preferred_height_for_width (GtkWidget *widget,
+                                                   gint       width,
+                                                   gint      *minimum_height_out,
+                                                   gint      *natural_height_out)
+{
+  GtkWidget *child;
+  gint child_min = 0, child_natural = 0;
+  GtkBorder full_border = { 0, };
+
+  egg_flow_box_child_get_full_border (EGG_FLOW_BOX_CHILD (widget), &full_border);
+
+  child = gtk_bin_get_child (GTK_BIN (widget));
+  if (child && gtk_widget_get_visible (child))
+      gtk_widget_get_preferred_height_for_width (child, width - full_border.left - full_border.right,
+                                                 &child_min, &child_natural);
+
+  if (minimum_height_out)
+    *minimum_height_out = full_border.top + child_min + full_border.bottom;
+  if (natural_height_out)
+    *natural_height_out = full_border.top + child_natural + full_border.bottom;
+}
+
+static void
+egg_flow_box_child_get_preferred_width (GtkWidget *widget,
+                                        gint      *minimum_width_out,
+                                        gint      *natural_width_out)
+{
+  GtkWidget *child;
+  gint child_min = 0, child_natural = 0;
+  GtkBorder full_border = { 0, };
+
+  egg_flow_box_child_get_full_border (EGG_FLOW_BOX_CHILD (widget), &full_border);
+
+  child = gtk_bin_get_child (GTK_BIN (widget));
+  if (child && gtk_widget_get_visible (child))
+      gtk_widget_get_preferred_width (child,
+                                      &child_min, &child_natural);
 
-  return g_hash_table_lookup (priv->child_hash, child);
+  if (minimum_width_out)
+    *minimum_width_out = full_border.left + child_min + full_border.right;
+  if (natural_width_out)
+    *natural_width_out = full_border.left + child_natural + full_border.bottom;
+}
+
+static void
+egg_flow_box_child_get_preferred_width_for_height (GtkWidget *widget,
+                                                   gint       height,
+                                                   gint      *minimum_width,
+                                                   gint      *natural_width)
+{
+  egg_flow_box_child_get_preferred_width (widget, minimum_width, natural_width);
+}
+
+static void
+egg_flow_box_child_get_preferred_height (GtkWidget *widget,
+                                         gint      *minimum_height,
+                                         gint      *natural_height)
+{
+  gint natural_width;
+  egg_flow_box_child_get_preferred_width (widget, NULL, &natural_width);
+  egg_flow_box_child_get_preferred_height_for_width (widget, natural_width,
+                                                     minimum_height, natural_height);
+}
+
+static void
+egg_flow_box_child_size_allocate (GtkWidget     *widget,
+                                  GtkAllocation *allocation)
+{
+  GtkWidget *child;
+
+  gtk_widget_set_allocation (widget, allocation);
+
+  child = gtk_bin_get_child (GTK_BIN (widget));
+  if (child && gtk_widget_get_visible (child))
+    {
+      GtkAllocation child_allocation;
+      GtkBorder border = { 0, };
+
+      egg_flow_box_child_get_full_border (EGG_FLOW_BOX_CHILD (widget), &border);
+
+      child_allocation.x = allocation->x + border.left;
+      child_allocation.y = allocation->y + border.top;
+      child_allocation.width = allocation->width - border.left - border.right;
+      child_allocation.height = allocation->height - border.top - border.bottom;
+
+      child_allocation.width  = MAX (1, child_allocation.width);
+      child_allocation.height = MAX (1, child_allocation.height);
+
+      gtk_widget_size_allocate (child, &child_allocation);
+    }
+}
+
+static void
+egg_flow_box_child_class_init (EggFlowBoxChildClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
+
+  widget_class->show = egg_flow_box_child_show;
+  widget_class->hide = egg_flow_box_child_hide;
+  widget_class->draw = egg_flow_box_child_draw;
+  widget_class->get_preferred_height = egg_flow_box_child_get_preferred_height;
+  widget_class->get_preferred_height_for_width = egg_flow_box_child_get_preferred_height_for_width;
+  widget_class->get_preferred_width = egg_flow_box_child_get_preferred_width;
+  widget_class->get_preferred_width_for_height = egg_flow_box_child_get_preferred_width_for_height;
+  widget_class->size_allocate = egg_flow_box_child_size_allocate;
+  widget_class->focus = egg_flow_box_child_focus;
+
+  class->activate = egg_flow_box_child_activate;
+
+  child_signals[CHILD_ACTIVATE] =
+    g_signal_new (I_("activate"),
+                  G_OBJECT_CLASS_TYPE (object_class),
+                  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+                  G_STRUCT_OFFSET (EggFlowBoxChildClass, activate),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+  widget_class->activate_signal = child_signals[CHILD_ACTIVATE];
+
+  gtk_widget_class_set_accessible_role (widget_class, ATK_ROLE_LIST_ITEM);
 }
 
 void
@@ -244,11 +569,13 @@ egg_flow_box_set_homogeneous (EggFlowBox *box,
 }
 
 /* Children are visible if they are shown by the app (visible)
-   and not filtered out (child_visible) by the box */
+ * and not filtered out (child_visible) by the box
+ */
 static gboolean
 child_is_visible (GtkWidget *child)
 {
-  return gtk_widget_get_visible (child) && gtk_widget_get_child_visible (child);
+  return gtk_widget_get_visible (child) &&
+         gtk_widget_get_child_visible (child);
 }
 
 static gint
@@ -262,12 +589,9 @@ get_visible_children (EggFlowBox *box)
        !g_sequence_iter_is_end (iter);
        iter = g_sequence_iter_next (iter))
     {
-      EggFlowBoxChildInfo *child_info;
       GtkWidget *child;
 
-      child_info = g_sequence_get (iter);
-      child = child_info->widget;
-
+      child = g_sequence_get (iter);
       if (!child_is_visible (child))
         continue;
 
@@ -281,10 +605,10 @@ get_visible_children (EggFlowBox *box)
  * equal widths or heights
  */
 static void
-get_average_item_size (EggFlowBox    *box,
-                       GtkOrientation orientation,
-                       gint          *min_size,
-                       gint          *nat_size)
+get_average_item_size (EggFlowBox     *box,
+                       GtkOrientation  orientation,
+                       gint           *min_size,
+                       gint           *nat_size)
 {
   EggFlowBoxPrivate *priv = box->priv;
   GSequenceIter *iter;
@@ -295,12 +619,10 @@ get_average_item_size (EggFlowBox    *box,
        !g_sequence_iter_is_end (iter);
        iter = g_sequence_iter_next (iter))
     {
-      EggFlowBoxChildInfo *child_info;
       GtkWidget *child;
       gint child_min, child_nat;
 
-      child_info = g_sequence_get (iter);
-      child = child_info->widget;
+      child = g_sequence_get (iter);
 
       if (!child_is_visible (child))
         continue;
@@ -325,11 +647,11 @@ get_average_item_size (EggFlowBox    *box,
 /* Gets the largest minimum/natural size for a given size
  * (used to get the largest item heights for a fixed item width and the opposite) */
 static void
-get_largest_size_for_opposing_orientation (EggFlowBox    *box,
-                                           GtkOrientation orientation,
-                                           gint           item_size,
-                                           gint          *min_item_size,
-                                           gint          *nat_item_size)
+get_largest_size_for_opposing_orientation (EggFlowBox     *box,
+                                           GtkOrientation  orientation,
+                                           gint            item_size,
+                                           gint           *min_item_size,
+                                           gint           *nat_item_size)
 {
   EggFlowBoxPrivate *priv = box->priv;
   GSequenceIter *iter;
@@ -340,12 +662,10 @@ get_largest_size_for_opposing_orientation (EggFlowBox    *box,
        !g_sequence_iter_is_end (iter);
        iter = g_sequence_iter_next (iter))
     {
-      EggFlowBoxChildInfo *child_info;
       GtkWidget *child;
       gint       child_min, child_nat;
 
-      child_info = g_sequence_get (iter);
-      child = child_info->widget;
+      child = g_sequence_get (iter);
 
       if (!child_is_visible (child))
         continue;
@@ -395,13 +715,11 @@ get_largest_size_for_line_in_opposing_orientation (EggFlowBox       *box,
        iter = g_sequence_iter_next (iter))
     {
       GtkWidget *child;
-      EggFlowBoxChildInfo *child_info;
       gint child_min, child_nat, this_item_size;
 
-      child_info = g_sequence_get (iter);
-      child = child_info->widget;
+      child = g_sequence_get (iter);
 
-      if (!child_is_visible (child))
+      if (!gtk_widget_is_visible (child))
         continue;
 
       /* Distribute the extra pixels to the first children in the line
@@ -459,14 +777,12 @@ gather_aligned_item_requests (EggFlowBox       *box,
        !g_sequence_iter_is_end (iter);
        iter = g_sequence_iter_next (iter), i++)
     {
-      EggFlowBoxChildInfo *child_info;
       GtkWidget *child;
       GtkAlign item_align;
       gint child_min, child_nat;
       gint position;
 
-      child_info = g_sequence_get (iter);
-      child = child_info->widget;
+      child = g_sequence_get (iter);
 
       if (!child_is_visible (child))
         continue;
@@ -582,8 +898,8 @@ get_offset_pixels (GtkAlign align,
 }
 
 static void
-egg_flow_box_real_size_allocate (GtkWidget     *widget,
-                                 GtkAllocation *allocation)
+egg_flow_box_size_allocate (GtkWidget     *widget,
+                            GtkAllocation *allocation)
 {
   EggFlowBox *box = EGG_FLOW_BOX (widget);
   EggFlowBoxPrivate  *priv = box->priv;
@@ -603,7 +919,6 @@ egg_flow_box_real_size_allocate (GtkWidget     *widget,
   gint extra_line_pixels = 0, extra_per_line = 0, extra_line_extra = 0;
   gint i, this_line_size;
   GSequenceIter *iter;
-  GtkStyleContext *context;
   gint focus_width;
   gint focus_pad;
 
@@ -619,14 +934,9 @@ egg_flow_box_real_size_allocate (GtkWidget     *widget,
                             allocation->x, allocation->y,
                             allocation->width, allocation->height);
 
-  context = gtk_widget_get_style_context (GTK_WIDGET (box));
-  gtk_style_context_get_style (context,
-                               "focus-line-width", &focus_width,
-                               "focus-padding", &focus_pad,
-                               NULL);
-  child_allocation.x = 0 + focus_width + focus_pad;
+  child_allocation.x = 0;
   child_allocation.y = 0;
-  child_allocation.width = allocation->width - 2 * (focus_width + focus_pad);
+  child_allocation.width = allocation->width;
 
   min_items = MAX (1, priv->min_children_per_line);
 
@@ -837,20 +1147,20 @@ egg_flow_box_real_size_allocate (GtkWidget     *widget,
        !g_sequence_iter_is_end (iter);
        iter = g_sequence_iter_next (iter))
     {
-      EggFlowBoxChildInfo *child_info;
       GtkWidget *child;
+      EggFlowBoxChildPrivate *child_priv;
       gint position;
       gint this_item_size;
 
-      child_info = g_sequence_get (iter);
-      child = child_info->widget;
+      child = g_sequence_get (iter);
+      child_priv = egg_flow_box_child_get_instance_private (EGG_FLOW_BOX_CHILD (child));
 
       if (!child_is_visible (child))
         {
-          child_info->area.x = child_allocation.x;
-          child_info->area.y = child_allocation.y;
-          child_info->area.width = 0;
-          child_info->area.height = 0;
+          child_priv->area.x = child_allocation.x;
+          child_priv->area.y = child_allocation.y;
+          child_priv->area.width = 0;
+          child_priv->area.height = 0;
           continue;
         }
 
@@ -955,10 +1265,10 @@ egg_flow_box_real_size_allocate (GtkWidget     *widget,
 
       if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
         child_allocation.x = allocation->x + allocation->width - (child_allocation.x - allocation->x) - 
child_allocation.width;
-      child_info->area.x = child_allocation.x;
-      child_info->area.y = child_allocation.y;
-      child_info->area.width = child_allocation.width;
-      child_info->area.height = child_allocation.height;
+      child_priv->area.x = child_allocation.x;
+      child_priv->area.y = child_allocation.y;
+      child_priv->area.width = child_allocation.width;
+      child_priv->area.height = child_allocation.height;
       gtk_widget_size_allocate (child, &child_allocation);
 
       item_offset += this_item_size;
@@ -972,47 +1282,64 @@ egg_flow_box_real_size_allocate (GtkWidget     *widget,
 }
 
 static void
-egg_flow_box_real_add (GtkContainer *container,
-                       GtkWidget    *child)
+egg_flow_box_add (GtkContainer *container,
+                  GtkWidget    *child)
 {
   EggFlowBox *box = EGG_FLOW_BOX (container);
   EggFlowBoxPrivate *priv = box->priv;
-  EggFlowBoxChildInfo *info;
+  EggFlowBoxChild *info;
+  EggFlowBoxChildPrivate *child_priv;
   GSequenceIter *iter = NULL;
 
   g_return_if_fail (EGG_IS_FLOW_BOX (box));
   g_return_if_fail (GTK_IS_WIDGET (child));
 
-  info = egg_flow_box_child_info_new (child);
-  g_hash_table_insert (priv->child_hash, child, info);
+  if (EGG_IS_FLOW_BOX_CHILD (child))
+    info = EGG_FLOW_BOX_CHILD (child);
+  else
+    {
+      info = EGG_FLOW_BOX_CHILD (egg_flow_box_child_new ());
+      gtk_widget_show (GTK_WIDGET (info));
+      gtk_container_add (GTK_CONTAINER (info), child);
+    }
+
   iter = g_sequence_append (priv->children, info);
-  info->iter = iter;
 
-  gtk_widget_set_parent (child, GTK_WIDGET (box));
+  child_priv = egg_flow_box_child_get_instance_private (info);
+  child_priv->iter = iter;
+  gtk_widget_set_parent (GTK_WIDGET (info), GTK_WIDGET (box));
+  gtk_widget_set_child_visible (GTK_WIDGET (info), TRUE);
 }
 
 static void
-egg_flow_box_real_remove (GtkContainer *container,
-                          GtkWidget    *child)
+egg_flow_box_remove (GtkContainer *container,
+                     GtkWidget    *child)
 {
   EggFlowBox *box = EGG_FLOW_BOX (container);
   EggFlowBoxPrivate *priv = box->priv;
   gboolean was_visible;
   gboolean was_selected;
-  EggFlowBoxChildInfo *child_info;
+  EggFlowBoxChild *child_info;
+  EggFlowBoxChildPrivate *child_priv;
 
   g_return_if_fail (child != NULL);
 
-  was_visible = child_is_visible (child);
-
-  child_info = egg_flow_box_lookup_info (box, child);
-  if (child_info == NULL)
+  if (EGG_IS_FLOW_BOX_CHILD (child))
+    child_info = EGG_FLOW_BOX_CHILD (child);
+  else
     {
-      g_warning ("Tried to remove non-child %p\n", child);
-      return;
+      child_info = (EggFlowBoxChild*)gtk_widget_get_parent (child);
+      if (!EGG_IS_FLOW_BOX_CHILD (child_info))
+        {
+          g_warning ("Tried to remove non-child %p\n", child);
+          return;
+        }
     }
 
-  was_selected = child_info->selected;
+  child_priv = egg_flow_box_child_get_instance_private (child_info);
+
+  was_visible = child_is_visible (GTK_WIDGET (child_info));
+  was_selected = child_priv->selected;
 
   if (child_info == priv->prelight_child)
     priv->prelight_child = NULL;
@@ -1021,9 +1348,8 @@ egg_flow_box_real_remove (GtkContainer *container,
   if (child_info == priv->selected_child)
     priv->selected_child = NULL;
 
-  gtk_widget_unparent (child);
-  g_hash_table_remove (priv->child_hash, child);
-  g_sequence_remove (child_info->iter);
+  gtk_widget_unparent (GTK_WIDGET (child_info));
+  g_sequence_remove (child_priv->iter);
 
   if (was_visible && gtk_widget_get_visible (GTK_WIDGET (box)))
     gtk_widget_queue_resize (GTK_WIDGET (box));
@@ -1033,33 +1359,33 @@ egg_flow_box_real_remove (GtkContainer *container,
 }
 
 static void
-egg_flow_box_real_forall (GtkContainer *container,
-                          gboolean      include_internals,
-                          GtkCallback   callback,
-                          gpointer      callback_target)
+egg_flow_box_forall (GtkContainer *container,
+                     gboolean      include_internals,
+                     GtkCallback   callback,
+                     gpointer      callback_target)
 {
   EggFlowBox *box = EGG_FLOW_BOX (container);
-  EggFlowBoxPrivate *priv   = box->priv;
+  EggFlowBoxPrivate *priv = box->priv;
   GSequenceIter *iter;
-  EggFlowBoxChildInfo *child_info;
+  GtkWidget *child;
 
   iter = g_sequence_get_begin_iter (priv->children);
   while (!g_sequence_iter_is_end (iter))
     {
-      child_info = g_sequence_get (iter);
+      child = g_sequence_get (iter);
       iter = g_sequence_iter_next (iter);
-      callback (child_info->widget, callback_target);
+      callback (child, callback_target);
     }
 }
 
 static GType
-egg_flow_box_real_child_type (GtkContainer *container)
+egg_flow_box_child_type (GtkContainer *container)
 {
-  return GTK_TYPE_WIDGET;
+  return EGG_TYPE_FLOW_BOX_CHILD;
 }
 
 static GtkSizeRequestMode
-egg_flow_box_real_get_request_mode (GtkWidget *widget)
+egg_flow_box_get_request_mode (GtkWidget *widget)
 {
   EggFlowBox *box = EGG_FLOW_BOX (widget);
   EggFlowBoxPrivate *priv   = box->priv;
@@ -1098,13 +1424,10 @@ get_largest_aligned_line_length (EggFlowBox     *box,
        !g_sequence_iter_is_end (iter);
        iter = g_sequence_iter_next (iter))
     {
-      EggFlowBoxChildInfo *child_info;
       GtkWidget *child;
       gint child_min, child_nat;
 
-      child_info = g_sequence_get (iter);
-      child = child_info->widget;
-
+      child = g_sequence_get (iter);
       if (!child_is_visible (child))
         continue;
 
@@ -1145,9 +1468,9 @@ get_largest_aligned_line_length (EggFlowBox     *box,
 
 
 static void
-egg_flow_box_real_get_preferred_width (GtkWidget *widget,
-                                       gint      *minimum_size,
-                                       gint      *natural_size)
+egg_flow_box_get_preferred_width (GtkWidget *widget,
+                                  gint      *minimum_size,
+                                  gint      *natural_size)
 {
   EggFlowBox *box  = EGG_FLOW_BOX (widget);
   EggFlowBoxPrivate *priv = box->priv;
@@ -1162,7 +1485,7 @@ egg_flow_box_real_get_preferred_width (GtkWidget *widget,
     {
       min_width = nat_width = 0;
 
-      if (! priv->homogeneous)
+      if (!priv->homogeneous)
         {
           /* When not homogeneous; horizontally oriented boxes
            * need enough width for the widest row */
@@ -1231,9 +1554,9 @@ egg_flow_box_real_get_preferred_width (GtkWidget *widget,
 }
 
 static void
-egg_flow_box_real_get_preferred_height (GtkWidget *widget,
-                                        gint      *minimum_size,
-                                        gint      *natural_size)
+egg_flow_box_get_preferred_height (GtkWidget *widget,
+                                   gint      *minimum_size,
+                                   gint      *natural_size)
 {
   EggFlowBox *box  = EGG_FLOW_BOX (widget);
   EggFlowBoxPrivate *priv = box->priv;
@@ -1317,10 +1640,10 @@ egg_flow_box_real_get_preferred_height (GtkWidget *widget,
 }
 
 static void
-egg_flow_box_real_get_preferred_height_for_width (GtkWidget *widget,
-                                                  gint       width,
-                                                  gint      *minimum_height,
-                                                  gint      *natural_height)
+egg_flow_box_get_preferred_height_for_width (GtkWidget *widget,
+                                             gint       width,
+                                             gint      *minimum_height,
+                                             gint      *natural_height)
 {
   EggFlowBox *box = EGG_FLOW_BOX (widget);
   EggFlowBoxPrivate *priv   = box->priv;
@@ -1475,10 +1798,10 @@ egg_flow_box_real_get_preferred_height_for_width (GtkWidget *widget,
 }
 
 static void
-egg_flow_box_real_get_preferred_width_for_height (GtkWidget *widget,
-                                                  gint       height,
-                                                  gint      *minimum_width,
-                                                  gint      *natural_width)
+egg_flow_box_get_preferred_width_for_height (GtkWidget *widget,
+                                             gint       height,
+                                             gint      *minimum_width,
+                                             gint      *natural_width)
 {
   EggFlowBox *box = EGG_FLOW_BOX (widget);
   EggFlowBoxPrivate *priv   = box->priv;
@@ -2033,24 +2356,26 @@ egg_flow_box_set_property (GObject      *object,
     }
 }
 
-static EggFlowBoxChildInfo *
+static EggFlowBoxChild *
 egg_flow_box_find_child_at_pos (EggFlowBox *box,
                                 gint        x,
                                 gint        y)
 {
   EggFlowBoxPrivate *priv = box->priv;
-  EggFlowBoxChildInfo *child_info;
+  EggFlowBoxChild *child_info;
   GSequenceIter *iter;
-  EggFlowBoxChildInfo *info;
+  EggFlowBoxChild *info;
+  EggFlowBoxChildPrivate *child_priv;
 
   child_info = NULL;
   for (iter = g_sequence_get_begin_iter (priv->children);
        !g_sequence_iter_is_end (iter);
        iter = g_sequence_iter_next (iter))
     {
-      info = (EggFlowBoxChildInfo *) g_sequence_get (iter);
-      if (x >= info->area.x && x < (info->area.x + info->area.width)
-          && y >= info->area.y && y < (info->area.y + info->area.height))
+      info = (EggFlowBoxChild *) g_sequence_get (iter);
+      child_priv = egg_flow_box_child_get_instance_private (info);
+      if (x >= child_priv->area.x && x < (child_priv->area.x + child_priv->area.width)
+          && y >= child_priv->area.y && y < (child_priv->area.y + child_priv->area.height))
         {
           child_info = info;
           break;
@@ -2062,7 +2387,7 @@ egg_flow_box_find_child_at_pos (EggFlowBox *box,
 
 static void
 egg_flow_box_update_prelight (EggFlowBox          *box,
-                              EggFlowBoxChildInfo *child)
+                              EggFlowBoxChild *child)
 {
   EggFlowBoxPrivate *priv = box->priv;
 
@@ -2075,7 +2400,7 @@ egg_flow_box_update_prelight (EggFlowBox          *box,
 
 static void
 egg_flow_box_update_active (EggFlowBox          *box,
-                            EggFlowBoxChildInfo *child)
+                            EggFlowBoxChild *child)
 {
   EggFlowBoxPrivate *priv = box->priv;
   gboolean val;
@@ -2090,11 +2415,11 @@ egg_flow_box_update_active (EggFlowBox          *box,
 }
 
 static gboolean
-egg_flow_box_real_enter_notify_event (GtkWidget        *widget,
-                                      GdkEventCrossing *event)
+egg_flow_box_enter_notify_event (GtkWidget        *widget,
+                                 GdkEventCrossing *event)
 {
   EggFlowBox *box = EGG_FLOW_BOX (widget);
-  EggFlowBoxChildInfo *child_info;
+  EggFlowBoxChild *child_info;
 
 
   if (event->window != gtk_widget_get_window (GTK_WIDGET (box)))
@@ -2108,11 +2433,11 @@ egg_flow_box_real_enter_notify_event (GtkWidget        *widget,
 }
 
 static gboolean
-egg_flow_box_real_leave_notify_event (GtkWidget        *widget,
-                                      GdkEventCrossing *event)
+egg_flow_box_leave_notify_event (GtkWidget        *widget,
+                                 GdkEventCrossing *event)
 {
   EggFlowBox *box = EGG_FLOW_BOX (widget);
-  EggFlowBoxChildInfo *child_info = NULL;
+  EggFlowBoxChild *child_info = NULL;
 
   if (event->window != gtk_widget_get_window (GTK_WIDGET (box)))
     return FALSE;
@@ -2129,11 +2454,11 @@ egg_flow_box_real_leave_notify_event (GtkWidget        *widget,
 }
 
 static gboolean
-egg_flow_box_real_motion_notify_event (GtkWidget      *widget,
-                                       GdkEventMotion *event)
+egg_flow_box_motion_notify_event (GtkWidget      *widget,
+                                  GdkEventMotion *event)
 {
   EggFlowBox *box = EGG_FLOW_BOX (widget);
-  EggFlowBoxChildInfo *child_info;
+  EggFlowBoxChild *child_info;
   GdkWindow *window;
   GdkWindow *event_window;
   gint relative_x;
@@ -2164,15 +2489,15 @@ egg_flow_box_real_motion_notify_event (GtkWidget      *widget,
 }
 
 static gboolean
-egg_flow_box_real_button_press_event (GtkWidget      *widget,
-                                      GdkEventButton *event)
+egg_flow_box_button_press_event (GtkWidget      *widget,
+                                 GdkEventButton *event)
 {
   EggFlowBox *box = EGG_FLOW_BOX (widget);
   EggFlowBoxPrivate *priv = box->priv;
 
   if (event->button == GDK_BUTTON_PRIMARY)
     {
-      EggFlowBoxChildInfo *child_info;
+      EggFlowBoxChild *child_info;
       child_info = egg_flow_box_find_child_at_pos (box, event->x, event->y);
       if (child_info != NULL)
         {
@@ -2183,7 +2508,7 @@ egg_flow_box_real_button_press_event (GtkWidget      *widget,
               !priv->activate_on_single_click)
             g_signal_emit (box,
                            signals[CHILD_ACTIVATED], 0,
-                           child_info->widget);
+                           child_info);
         }
     }
 
@@ -2192,21 +2517,48 @@ egg_flow_box_real_button_press_event (GtkWidget      *widget,
 
 static void
 egg_flow_box_queue_draw_child (EggFlowBox          *box,
-                               EggFlowBoxChildInfo *child_info)
+                               EggFlowBoxChild *child_info)
 {
+  EggFlowBoxChildPrivate *priv;
   GdkRectangle rect;
   GdkWindow *window;
 
-  rect = child_info->area;
+  priv = egg_flow_box_child_get_instance_private (child_info);
+  rect = priv->area;
 
   window = gtk_widget_get_window (GTK_WIDGET (box));
   gdk_window_invalidate_rect (window, &rect, TRUE);
 }
 
 static gboolean
+egg_flow_box_child_set_selected (EggFlowBoxChild *child,
+                                 gboolean         selected)
+{
+  EggFlowBoxChildPrivate *priv;
+
+  priv = egg_flow_box_child_get_instance_private (child);
+  if (priv->selected != selected)
+    {
+      priv->selected = selected;
+      if (selected)
+        gtk_widget_set_state_flags (GTK_WIDGET (child),
+                                    GTK_STATE_FLAG_SELECTED, FALSE);
+      else
+        gtk_widget_unset_state_flags (GTK_WIDGET (child),
+                                      GTK_STATE_FLAG_SELECTED);
+      gtk_widget_queue_draw (GTK_WIDGET (child));
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
 egg_flow_box_unselect_all_internal (EggFlowBox *box)
 {
-  EggFlowBoxChildInfo *child_info;
+  EggFlowBoxChild *child_info;
+  EggFlowBoxChildPrivate *priv;
   GSequenceIter *iter;
   gboolean dirty = FALSE;
 
@@ -2218,22 +2570,20 @@ egg_flow_box_unselect_all_internal (EggFlowBox *box)
        iter = g_sequence_iter_next (iter))
     {
       child_info = g_sequence_get (iter);
-      if (child_info->selected)
-        {
-          child_info->selected = FALSE;
-          egg_flow_box_queue_draw_child (box, child_info);
-          dirty = TRUE;
-        }
+      dirty != egg_flow_box_child_set_selected (child_info, FALSE);
     }
 
   return dirty;
 }
 
 static void
-egg_flow_box_unselect_child_info (EggFlowBox          *box,
-                                  EggFlowBoxChildInfo *child_info)
+egg_flow_box_unselect_child_info (EggFlowBox      *box,
+                                  EggFlowBoxChild *child_info)
 {
-  if (!child_info->selected)
+  EggFlowBoxChildPrivate *priv;
+
+  priv = egg_flow_box_child_get_instance_private (child_info);
+  if (!priv->selected)
     return;
 
   if (box->priv->selection_mode == GTK_SELECTION_NONE)
@@ -2241,65 +2591,69 @@ egg_flow_box_unselect_child_info (EggFlowBox          *box,
   else if (box->priv->selection_mode != GTK_SELECTION_MULTIPLE)
     egg_flow_box_unselect_all_internal (box);
   else
-    child_info->selected = FALSE;
+    egg_flow_box_child_set_selected (child_info, FALSE);
 
   g_signal_emit (box, signals[SELECTED_CHILDREN_CHANGED], 0);
-
-  egg_flow_box_queue_draw_child (box, child_info);
 }
 
 static void
-egg_flow_box_update_cursor (EggFlowBox          *box,
-                            EggFlowBoxChildInfo *child_info)
+egg_flow_box_update_cursor (EggFlowBox      *box,
+                            EggFlowBoxChild *child)
 {
   EggFlowBoxPrivate *priv = box->priv;
 
-  priv->cursor_child = child_info;
-  gtk_widget_grab_focus (GTK_WIDGET (box));
-  gtk_widget_queue_draw (GTK_WIDGET (box));
-
-  if (child_info != NULL && priv->adjustment != NULL)
-    {
-      GtkAllocation allocation;
-
-      gtk_widget_get_allocation (GTK_WIDGET (box), &allocation);
-      gtk_adjustment_clamp_page (priv->adjustment,
-                                 priv->cursor_child->area.y + allocation.y,
-                                 priv->cursor_child->area.y + allocation.y + 
priv->cursor_child->area.height);
-  }
-
-  _egg_flow_box_accessible_update_cursor (GTK_WIDGET (box), child_info ? child_info->widget : NULL);
+  priv->cursor_child = child;
+  gtk_widget_grab_focus (GTK_WIDGET (child));
+  gtk_widget_queue_draw (GTK_WIDGET (child));
+  _egg_flow_box_accessible_update_cursor (GTK_WIDGET (box), GTK_WIDGET (child));
 }
 
 static void
-egg_flow_box_select_child_info (EggFlowBox          *box,
-                                EggFlowBoxChildInfo *child_info)
+egg_flow_box_select_child_info (EggFlowBox      *box,
+                                EggFlowBoxChild *child_info)
 {
-  if (child_info->selected)
+  EggFlowBoxChildPrivate *child_priv;
+
+  child_priv = egg_flow_box_child_get_instance_private (child_info);
+  if (child_priv->selected)
     return;
   if (box->priv->selection_mode == GTK_SELECTION_NONE)
     return;
-  else if (box->priv->selection_mode != GTK_SELECTION_MULTIPLE)
+  if (box->priv->selection_mode != GTK_SELECTION_MULTIPLE)
     egg_flow_box_unselect_all_internal (box);
 
-  child_info->selected = TRUE;
+  egg_flow_box_child_set_selected (child_info, TRUE);
   box->priv->selected_child = child_info;
 
   g_signal_emit (box, signals[SELECTED_CHILDREN_CHANGED], 0);
 
-  egg_flow_box_queue_draw_child (box, child_info);
   egg_flow_box_update_cursor (box, child_info);
 }
 
 static void
-egg_flow_box_select_all_between (EggFlowBox          *box,
-                                 EggFlowBoxChildInfo *child1,
-                                 EggFlowBoxChildInfo *child2)
+egg_flow_box_select_all_between (EggFlowBox      *box,
+                                 EggFlowBoxChild *child1,
+                                 EggFlowBoxChild *child2)
 {
   GSequenceIter *iter, *iter1, *iter2;
+  EggFlowBoxChildPrivate *priv;
+
+  if (child1)
+    {
+      priv = egg_flow_box_child_get_instance_private (child1);
+      iter1 = priv->iter;
+    }
+  else
+    iter1 = g_sequence_get_begin_iter (box->priv->children);
+
+  if (child2)
+    {
+      priv = egg_flow_box_child_get_instance_private (child2);
+      iter2 = priv->iter;
+    }
+  else
+    iter2 = g_sequence_get_end_iter (box->priv->children);
 
-  iter1 = child1 ? child1->iter : g_sequence_get_begin_iter (box->priv->children);
-  iter2 = child2 ? child2->iter : g_sequence_get_end_iter (box->priv->children);
   if (g_sequence_iter_compare (iter2, iter1) < 0)
     {
       iter = iter1;
@@ -2309,14 +2663,11 @@ egg_flow_box_select_all_between (EggFlowBox          *box,
 
   for (iter = iter1; ; iter = g_sequence_iter_next (iter))
     {
-      EggFlowBoxChildInfo *child_info;
+      GtkWidget *child;
 
-      child_info = g_sequence_get (iter);
-      if (child_info && child_is_visible (child_info->widget))
-        {
-          child_info->selected = TRUE;
-          egg_flow_box_queue_draw_child (box, child_info);
-        }
+      child = g_sequence_get (iter);
+      if (child_is_visible (child))
+        egg_flow_box_child_set_selected (EGG_FLOW_BOX_CHILD (child), TRUE);
 
       if (g_sequence_iter_compare (iter, iter2) == 0)
         break;
@@ -2324,12 +2675,15 @@ egg_flow_box_select_all_between (EggFlowBox          *box,
 }
 
 static void
-egg_flow_box_update_selection (EggFlowBox          *box,
-                               EggFlowBoxChildInfo *child_info,
-                               gboolean             modify,
-                               gboolean             extend)
+egg_flow_box_update_selection (EggFlowBox      *box,
+                               EggFlowBoxChild *child_info,
+                               gboolean         modify,
+                               gboolean         extend)
 {
   EggFlowBoxPrivate *priv = box->priv;
+  EggFlowBoxChildPrivate *child_priv;
+
+  child_priv = egg_flow_box_child_get_instance_private (child_info);
 
   if (priv->selection_mode == GTK_SELECTION_NONE)
     return;
@@ -2337,17 +2691,17 @@ egg_flow_box_update_selection (EggFlowBox          *box,
   if (priv->selection_mode == GTK_SELECTION_BROWSE)
     {
       egg_flow_box_unselect_all_internal (box);
-      child_info->selected = TRUE;
+      egg_flow_box_child_set_selected (child_info, TRUE);
       priv->selected_child = child_info;
     }
   else if (priv->selection_mode == GTK_SELECTION_SINGLE)
     {
       gboolean was_selected;
 
-      was_selected = child_info->selected;
+      was_selected = child_priv->selected;
       egg_flow_box_unselect_all_internal (box);
-      child_info->selected = modify ? !was_selected : TRUE;
-      priv->selected_child = child_info->selected ? child_info : NULL;
+      egg_flow_box_child_set_selected (child_info, modify ? !was_selected : TRUE);
+      priv->selected_child = child_priv->selected ? child_info : NULL;
     }
   else /* GTK_SELECTION_MULTIPLE */
     {
@@ -2356,7 +2710,7 @@ egg_flow_box_update_selection (EggFlowBox          *box,
           egg_flow_box_unselect_all_internal (box);
           if (priv->selected_child == NULL)
             {
-              child_info->selected = TRUE;
+              egg_flow_box_child_set_selected (child_info, TRUE);
               priv->selected_child = child_info;
             }
           else
@@ -2364,26 +2718,25 @@ egg_flow_box_update_selection (EggFlowBox          *box,
         }
       else
         {
-          child_info->selected = modify ? !child_info->selected : TRUE;
+          egg_flow_box_child_set_selected (child_info, modify ? !child_priv->selected : TRUE);
           priv->selected_child = child_info;
         }
     }
 
   g_signal_emit (box, signals[SELECTED_CHILDREN_CHANGED], 0);
 
-  egg_flow_box_queue_draw_child (box, child_info);
   egg_flow_box_update_cursor (box, child_info);
 }
 
 static void
-egg_flow_box_select_and_activate (EggFlowBox          *box,
-                                  EggFlowBoxChildInfo *child_info)
+egg_flow_box_select_and_activate (EggFlowBox      *box,
+                                  EggFlowBoxChild *child_info)
 {
   GtkWidget *w = NULL;
 
   if (child_info != NULL)
     {
-      w = child_info->widget;
+      w = gtk_bin_get_child (GTK_BIN (child_info));
       egg_flow_box_select_child_info (box, child_info);
     }
 
@@ -2392,8 +2745,8 @@ egg_flow_box_select_and_activate (EggFlowBox          *box,
 }
 
 static gboolean
-egg_flow_box_real_button_release_event (GtkWidget      *widget,
-                                        GdkEventButton *event)
+egg_flow_box_button_release_event (GtkWidget      *widget,
+                                   GdkEventButton *event)
 {
   EggFlowBox *box = EGG_FLOW_BOX (widget);
   EggFlowBoxPrivate *priv = box->priv;
@@ -2438,39 +2791,39 @@ egg_flow_box_real_button_release_event (GtkWidget      *widget,
   return FALSE;
 }
 
-static EggFlowBoxChildInfo *
+static EggFlowBoxChild *
 egg_flow_box_get_first_visible (EggFlowBox *box)
 {
   EggFlowBoxPrivate *priv = box->priv;
-  EggFlowBoxChildInfo *child_info;
+  EggFlowBoxChild *child;
   GSequenceIter *iter;
 
   for (iter = g_sequence_get_begin_iter (priv->children);
        !g_sequence_iter_is_end (iter);
        iter = g_sequence_iter_next (iter))
     {
-        child_info = g_sequence_get (iter);
-        if (child_is_visible (child_info->widget))
-          return child_info;
+        child = g_sequence_get (iter);
+        if (child_is_visible (GTK_WIDGET (child)))
+          return child;
     }
 
   return NULL;
 }
 
-static EggFlowBoxChildInfo *
+static EggFlowBoxChild *
 egg_flow_box_get_last_visible (EggFlowBox *box)
 {
   EggFlowBoxPrivate *priv = box->priv;
-  EggFlowBoxChildInfo *child_info;
+  EggFlowBoxChild *child;
   GSequenceIter *iter;
 
   iter = g_sequence_get_end_iter (priv->children);
   while (!g_sequence_iter_is_begin (iter))
     {
       iter = g_sequence_iter_prev (iter);
-      child_info = g_sequence_get (iter);
-      if (child_is_visible (child_info->widget))
-        return child_info;
+      child = g_sequence_get (iter);
+      if (child_is_visible (GTK_WIDGET (child)))
+        return child;
     }
 
   return NULL;
@@ -2480,7 +2833,7 @@ static GSequenceIter *
 egg_flow_box_get_previous_visible (EggFlowBox    *box,
                                    GSequenceIter *iter)
 {
-  EggFlowBoxChildInfo *child_info;
+  EggFlowBoxChild *child;
 
   if (g_sequence_iter_is_begin (iter))
     return NULL;
@@ -2488,8 +2841,8 @@ egg_flow_box_get_previous_visible (EggFlowBox    *box,
   do
     {
       iter = g_sequence_iter_prev (iter);
-      child_info = g_sequence_get (iter);
-      if (child_is_visible (child_info->widget))
+      child = g_sequence_get (iter);
+      if (child_is_visible (GTK_WIDGET (child)))
         return iter;
     }
   while (!g_sequence_iter_is_begin (iter));
@@ -2501,7 +2854,7 @@ static GSequenceIter *
 egg_flow_box_get_next_visible (EggFlowBox    *box,
                                GSequenceIter *iter)
 {
-  EggFlowBoxChildInfo *child_info;
+  EggFlowBoxChild *child;
 
   if (g_sequence_iter_is_end (iter))
     return iter;
@@ -2511,8 +2864,8 @@ egg_flow_box_get_next_visible (EggFlowBox    *box,
       iter = g_sequence_iter_next (iter);
       if (!g_sequence_iter_is_end (iter))
         {
-        child_info = g_sequence_get (iter);
-        if (child_is_visible (child_info->widget))
+        child = g_sequence_get (iter);
+        if (child_is_visible (GTK_WIDGET (child)))
           return iter;
         }
     }
@@ -2525,7 +2878,7 @@ static GSequenceIter *
 egg_flow_box_get_above_visible (EggFlowBox    *box,
                                 GSequenceIter *iter)
 {
-  EggFlowBoxChildInfo *child_info;
+  EggFlowBoxChild *child;
   GSequenceIter *ret = NULL;
   gint i;
 
@@ -2536,8 +2889,8 @@ egg_flow_box_get_above_visible (EggFlowBox    *box,
   do
     {
       iter = g_sequence_iter_prev (iter);
-      child_info = g_sequence_get (iter);
-      if (child_is_visible (child_info->widget))
+      child = g_sequence_get (iter);
+      if (child_is_visible (GTK_WIDGET (child)))
         i++;
     }
   while (!g_sequence_iter_is_begin (iter)
@@ -2553,7 +2906,7 @@ static GSequenceIter *
 egg_flow_box_get_below_visible (EggFlowBox    *box,
                                 GSequenceIter *iter)
 {
-  EggFlowBoxChildInfo *child_info;
+  EggFlowBoxChild *child;
   GSequenceIter *ret = NULL;
   gint i;
 
@@ -2566,8 +2919,8 @@ egg_flow_box_get_below_visible (EggFlowBox    *box,
       iter = g_sequence_iter_next (iter);
       if (!g_sequence_iter_is_end (iter))
         {
-          child_info = g_sequence_get (iter);
-          if (child_is_visible (child_info->widget))
+          child = g_sequence_get (iter);
+          if (child_is_visible (GTK_WIDGET (child)))
             i++;
         }
     }
@@ -2581,40 +2934,29 @@ egg_flow_box_get_below_visible (EggFlowBox    *box,
 }
 
 static gboolean
-egg_flow_box_real_focus (GtkWidget       *widget,
-                         GtkDirectionType direction)
+egg_flow_box_focus (GtkWidget       *widget,
+                    GtkDirectionType direction)
 {
   EggFlowBox *box = EGG_FLOW_BOX (widget);
   EggFlowBoxPrivate *priv = box->priv;
   gboolean had_focus = FALSE;
   GtkWidget *recurse_into;
-  EggFlowBoxChildInfo *current_focus_child;
-  EggFlowBoxChildInfo *next_focus_child;
+  EggFlowBoxChild *current_focus_child;
+  EggFlowBoxChild *next_focus_child;
   gboolean modify_selection_pressed;
   gboolean extend_selection_pressed;
   GdkModifierType state = 0;
+  EggFlowBoxChildPrivate *child_priv;
 
   recurse_into = NULL;
-
-  g_object_get (GTK_WIDGET (box), "has-focus", &had_focus, NULL);
   current_focus_child = NULL;
   next_focus_child = NULL;
 
-  if (had_focus)
-    {
-      /* If on row, going right, enter into possible container */
-      if (direction == GTK_DIR_RIGHT || direction == GTK_DIR_TAB_FORWARD)
-        {
-          if (priv->cursor_child != NULL)
-            recurse_into = priv->cursor_child->widget;
-        }
-      current_focus_child = priv->cursor_child;
-    }
-  else if (gtk_container_get_focus_child ((GtkContainer *) box) != NULL)
+  if (gtk_container_get_focus_child ((GtkContainer *) box) != NULL)
     {
       /* There is a focus child, always navigate inside it first */
       recurse_into = gtk_container_get_focus_child ((GtkContainer *) box);
-      current_focus_child = egg_flow_box_lookup_info (box, recurse_into);
+      current_focus_child = EGG_FLOW_BOX_CHILD (recurse_into);
 
       /* If exiting child container to the left, select row or out */
       if (direction == GTK_DIR_LEFT || direction == GTK_DIR_TAB_BACKWARD)
@@ -2626,7 +2968,7 @@ egg_flow_box_real_focus (GtkWidget       *widget,
       if (direction == GTK_DIR_LEFT || direction == GTK_DIR_TAB_BACKWARD)
         {
           if (priv->selected_child != NULL)
-            recurse_into = priv->selected_child->widget;
+            recurse_into = gtk_bin_get_child (GTK_BIN (priv->selected_child));
         }
    }
 
@@ -2640,31 +2982,33 @@ egg_flow_box_real_focus (GtkWidget       *widget,
     {
       if (current_focus_child != NULL)
         {
-          GSequenceIter *i;
+          GSequenceIter *iter;
+
+          child_priv = egg_flow_box_child_get_instance_private (current_focus_child);
 
           if (direction == GTK_DIR_LEFT)
             {
-              i = egg_flow_box_get_previous_visible (box, current_focus_child->iter);
-              if (i != NULL)
-                next_focus_child = g_sequence_get (i);
+              iter = egg_flow_box_get_previous_visible (box, child_priv->iter);
+              if (iter != NULL)
+                next_focus_child = g_sequence_get (iter);
             }
           else if (direction == GTK_DIR_RIGHT)
             {
-              i = egg_flow_box_get_next_visible (box, current_focus_child->iter);
-              if (i != NULL && !g_sequence_iter_is_end (i))
-                next_focus_child = g_sequence_get (i);
+              iter = egg_flow_box_get_next_visible (box, child_priv->iter);
+              if (iter != NULL && !g_sequence_iter_is_end (iter))
+                next_focus_child = g_sequence_get (iter);
             }
           else if (direction == GTK_DIR_UP)
             {
-              i = egg_flow_box_get_above_visible (box, current_focus_child->iter);
-              if (i != NULL && !g_sequence_iter_is_end (i))
-                next_focus_child = g_sequence_get (i);
+              iter = egg_flow_box_get_above_visible (box, child_priv->iter);
+              if (iter != NULL && !g_sequence_iter_is_end (iter))
+                next_focus_child = g_sequence_get (iter);
             }
           else if (direction == GTK_DIR_DOWN)
             {
-              i = egg_flow_box_get_below_visible (box, current_focus_child->iter);
-              if (i != NULL && !g_sequence_iter_is_end (i))
-                next_focus_child = g_sequence_get (i);
+              iter = egg_flow_box_get_below_visible (box, child_priv->iter);
+              if (iter != NULL && !g_sequence_iter_is_end (iter))
+                next_focus_child = g_sequence_get (iter);
             }
         }
       else
@@ -2725,14 +3069,14 @@ egg_flow_box_real_focus (GtkWidget       *widget,
 }
 
 typedef struct {
-  EggFlowBoxChildInfo *child;
+  EggFlowBoxChild *child;
   GtkStateFlags state;
 } ChildFlags;
 
 static ChildFlags *
 child_flags_find_or_add (ChildFlags          *array,
                          int                 *array_length,
-                         EggFlowBoxChildInfo *to_find)
+                         EggFlowBoxChild *to_find)
 {
   gint i;
 
@@ -2782,7 +3126,7 @@ egg_flow_box_add_move_binding (GtkBindingSet  *binding_set,
 }
 
 static void
-egg_flow_box_real_activate_cursor_child (EggFlowBox *box)
+egg_flow_box_activate_cursor_child (EggFlowBox *box)
 {
   EggFlowBoxPrivate *priv = box->priv;
 
@@ -2790,35 +3134,39 @@ egg_flow_box_real_activate_cursor_child (EggFlowBox *box)
 }
 
 static void
-egg_flow_box_real_toggle_cursor_child (EggFlowBox *box)
+egg_flow_box_toggle_cursor_child (EggFlowBox *box)
 {
   EggFlowBoxPrivate *priv = box->priv;
+  EggFlowBoxChildPrivate *child_priv;
 
   if (priv->cursor_child == NULL)
     return;
 
+  child_priv = egg_flow_box_child_get_instance_private (priv->cursor_child);
+
   if ((priv->selection_mode == GTK_SELECTION_SINGLE ||
        priv->selection_mode == GTK_SELECTION_MULTIPLE) &&
-      priv->cursor_child->selected)
+      child_priv->selected)
     egg_flow_box_unselect_child_info (box, priv->cursor_child);
   else
     egg_flow_box_select_and_activate (box, priv->cursor_child);
 }
 
 static void
-egg_flow_box_real_move_cursor (EggFlowBox     *box,
-                               GtkMovementStep step,
-                               gint            count)
+egg_flow_box_move_cursor (EggFlowBox     *box,
+                          GtkMovementStep step,
+                          gint            count)
 {
   EggFlowBoxPrivate *priv = box->priv;
   GdkModifierType state;
   gboolean extend_selection_pressed;
   gboolean modify_selection_pressed;
-  EggFlowBoxChildInfo *child;
+  EggFlowBoxChild *child;
   GdkModifierType extend_mod_mask;
   GdkModifierType modify_mod_mask;
-  EggFlowBoxChildInfo *prev;
-  EggFlowBoxChildInfo *next;
+  EggFlowBoxChild *prev;
+  EggFlowBoxChild *next;
+  EggFlowBoxChildPrivate *child_priv;
   gint page_size;
   GSequenceIter *iter;
   gint start_y;
@@ -2846,7 +3194,8 @@ egg_flow_box_real_move_cursor (EggFlowBox     *box,
     case GTK_MOVEMENT_VISUAL_POSITIONS:
       if (priv->cursor_child != NULL)
         {
-          iter = priv->cursor_child->iter;
+          child_priv = egg_flow_box_child_get_instance_private (priv->cursor_child);
+          iter = child_priv->iter;
           if (gtk_widget_get_direction (GTK_WIDGET (box)) == GTK_TEXT_DIR_RTL)
             count = - count;
 
@@ -2874,7 +3223,8 @@ egg_flow_box_real_move_cursor (EggFlowBox     *box,
     case GTK_MOVEMENT_DISPLAY_LINES:
       if (priv->cursor_child != NULL)
         {
-          iter = priv->cursor_child->iter;
+          child_priv = egg_flow_box_child_get_instance_private (priv->cursor_child);
+          iter = child_priv->iter;
 
           while (count < 0  && iter != NULL)
             {
@@ -2898,9 +3248,10 @@ egg_flow_box_real_move_cursor (EggFlowBox     *box,
 
       if (priv->cursor_child != NULL)
         {
-          start_y = priv->cursor_child->area.y;
+          child_priv = egg_flow_box_child_get_instance_private (priv->cursor_child);
+          start_y = child_priv->area.y;
           end_y = start_y;
-          iter = priv->cursor_child->iter;
+          iter = child_priv->iter;
 
           child = priv->cursor_child;
           if (count < 0)
@@ -2915,10 +3266,11 @@ egg_flow_box_real_move_cursor (EggFlowBox     *box,
                     break;
 
                   prev = g_sequence_get (iter);
+                  child_priv = egg_flow_box_child_get_instance_private (prev);
 
                   /* go up an even number of rows */
                   if (i % priv->cur_children_per_line == 0
-                      && prev->area.y < start_y - page_size)
+                      && child_priv->area.y < start_y - page_size)
                     break;
 
                   child = prev;
@@ -2937,16 +3289,18 @@ egg_flow_box_real_move_cursor (EggFlowBox     *box,
                     break;
 
                   next = g_sequence_get (iter);
+                  child_priv = egg_flow_box_child_get_instance_private (next);
 
                   if (i % priv->cur_children_per_line == 0
-                      && next->area.y > start_y + page_size)
+                      && child_priv->area.y > start_y + page_size)
                     break;
 
                   child = next;
                   i++;
                 }
             }
-          end_y = child->area.y;
+          child_priv = egg_flow_box_child_get_instance_private (child);
+          end_y = child_priv->area.y;
         }
       break;
     default:
@@ -3009,8 +3363,8 @@ egg_flow_box_unselect_all (EggFlowBox *box)
 }
 
 static gboolean
-egg_flow_box_real_draw (GtkWidget *widget,
-                        cairo_t   *cr)
+egg_flow_box_draw (GtkWidget *widget,
+                   cairo_t   *cr)
 {
   EggFlowBox *box = EGG_FLOW_BOX (widget);
   EggFlowBoxPrivate *priv = box->priv;
@@ -3020,25 +3374,31 @@ egg_flow_box_real_draw (GtkWidget *widget,
   gint focus_pad;
   int i;
   GSequenceIter *iter;
+  EggFlowBoxChildPrivate *child_priv;
 
   gtk_widget_get_allocation (GTK_WIDGET (box), &allocation);
   context = gtk_widget_get_style_context (GTK_WIDGET (box));
-  state = gtk_widget_get_state_flags (widget);
-  gtk_render_background (context, cr, (gdouble) 0, (gdouble) 0, (gdouble) allocation.width, (gdouble) 
allocation.height);
+  gtk_render_background (context, cr, 0, 0, allocation.width, allocation.height);
+
+  GTK_WIDGET_CLASS (egg_flow_box_parent_class)->draw (widget, cr);
 
+  return TRUE;
+
+  state = gtk_widget_get_state_flags (widget);
   for (iter = g_sequence_get_begin_iter (priv->children);
        !g_sequence_iter_is_end (iter);
        iter = g_sequence_iter_next (iter))
     {
-      EggFlowBoxChildInfo *child_info;
+      EggFlowBoxChild *child_info;
       ChildFlags flags[3], *found;
       gint flags_length;
 
       child_info = g_sequence_get (iter);
+      child_priv = egg_flow_box_child_get_instance_private (child_info);
 
       flags_length = 0;
 
-      if (child_info->selected)
+      if (child_priv->selected)
         {
           found = child_flags_find_or_add (flags, &flags_length, child_info);
           found->state |= (state | GTK_STATE_FLAG_SELECTED);
@@ -3059,11 +3419,12 @@ egg_flow_box_real_draw (GtkWidget *widget,
       for (i = 0; i < flags_length; i++)
         {
           ChildFlags *flag = &flags[i];
+          child_priv = egg_flow_box_child_get_instance_private (flag->child);
           gtk_style_context_save (context);
           gtk_style_context_set_state (context, flag->state);
           gtk_render_background (context, cr,
-                                 flag->child->area.x, flag->child->area.y,
-                                 flag->child->area.width, flag->child->area.height);
+                                 child_priv->area.x, child_priv->area.y,
+                                 child_priv->area.width, child_priv->area.height);
           gtk_style_context_restore (context);
         }
     }
@@ -3073,11 +3434,12 @@ egg_flow_box_real_draw (GtkWidget *widget,
       gtk_style_context_get_style (context,
                                    "focus-padding", &focus_pad,
                                    NULL);
+      child_priv = egg_flow_box_child_get_instance_private (priv->cursor_child);
       gtk_render_focus (context, cr,
-                        priv->cursor_child->area.x + focus_pad,
-                        priv->cursor_child->area.y + focus_pad,
-                        priv->cursor_child->area.width - 2 * focus_pad,
-                        priv->cursor_child->area.height - 2 * focus_pad);
+                        child_priv->area.x + focus_pad,
+                        child_priv->area.y + focus_pad,
+                        child_priv->area.width - 2 * focus_pad,
+                        child_priv->area.height - 2 * focus_pad);
     }
 
 
@@ -3087,7 +3449,7 @@ egg_flow_box_real_draw (GtkWidget *widget,
 }
 
 static void
-egg_flow_box_real_realize (GtkWidget *widget)
+egg_flow_box_realize (GtkWidget *widget)
 {
   EggFlowBox *box = EGG_FLOW_BOX (widget);
   GtkAllocation allocation;
@@ -3121,14 +3483,13 @@ egg_flow_box_finalize (GObject *obj)
   EggFlowBoxPrivate *priv = flow_box->priv;
 
   g_sequence_free (priv->children);
-  g_hash_table_unref (priv->child_hash);
   g_clear_object (&priv->adjustment);
 
   G_OBJECT_CLASS (egg_flow_box_parent_class)->finalize (obj);
 }
 
 static void
-egg_flow_box_real_selected_children_changed (EggFlowBox *box)
+egg_flow_box_selected_children_changed (EggFlowBox *box)
 {
   _egg_flow_box_accessible_selection_changed (GTK_WIDGET (box));
 }
@@ -3145,33 +3506,33 @@ egg_flow_box_class_init (EggFlowBoxClass *class)
   object_class->get_property = egg_flow_box_get_property;
   object_class->set_property = egg_flow_box_set_property;
 
-  widget_class->enter_notify_event = egg_flow_box_real_enter_notify_event;
-  widget_class->leave_notify_event = egg_flow_box_real_leave_notify_event;
-  widget_class->motion_notify_event = egg_flow_box_real_motion_notify_event;
-  widget_class->size_allocate = egg_flow_box_real_size_allocate;
-  widget_class->realize = egg_flow_box_real_realize;
-  widget_class->focus = egg_flow_box_real_focus;
-  widget_class->draw = egg_flow_box_real_draw;
-  widget_class->button_press_event = egg_flow_box_real_button_press_event;
-  widget_class->button_release_event = egg_flow_box_real_button_release_event;
-  widget_class->get_request_mode = egg_flow_box_real_get_request_mode;
-  widget_class->get_preferred_width = egg_flow_box_real_get_preferred_width;
-  widget_class->get_preferred_height = egg_flow_box_real_get_preferred_height;
-  widget_class->get_preferred_height_for_width = egg_flow_box_real_get_preferred_height_for_width;
-  widget_class->get_preferred_width_for_height = egg_flow_box_real_get_preferred_width_for_height;
-
-  container_class->add = egg_flow_box_real_add;
-  container_class->remove = egg_flow_box_real_remove;
-  container_class->forall = egg_flow_box_real_forall;
-  container_class->child_type = egg_flow_box_real_child_type;
+  widget_class->enter_notify_event = egg_flow_box_enter_notify_event;
+  widget_class->leave_notify_event = egg_flow_box_leave_notify_event;
+  widget_class->motion_notify_event = egg_flow_box_motion_notify_event;
+  widget_class->size_allocate = egg_flow_box_size_allocate;
+  widget_class->realize = egg_flow_box_realize;
+  widget_class->focus = egg_flow_box_focus;
+  widget_class->draw = egg_flow_box_draw;
+  widget_class->button_press_event = egg_flow_box_button_press_event;
+  widget_class->button_release_event = egg_flow_box_button_release_event;
+  widget_class->get_request_mode = egg_flow_box_get_request_mode;
+  widget_class->get_preferred_width = egg_flow_box_get_preferred_width;
+  widget_class->get_preferred_height = egg_flow_box_get_preferred_height;
+  widget_class->get_preferred_height_for_width = egg_flow_box_get_preferred_height_for_width;
+  widget_class->get_preferred_width_for_height = egg_flow_box_get_preferred_width_for_height;
+
+  container_class->add = egg_flow_box_add;
+  container_class->remove = egg_flow_box_remove;
+  container_class->forall = egg_flow_box_forall;
+  container_class->child_type = egg_flow_box_child_type;
   gtk_container_class_handle_border_width (container_class);
 
-  class->activate_cursor_child = egg_flow_box_real_activate_cursor_child;
-  class->toggle_cursor_child = egg_flow_box_real_toggle_cursor_child;
-  class->move_cursor = egg_flow_box_real_move_cursor;
+  class->activate_cursor_child = egg_flow_box_activate_cursor_child;
+  class->toggle_cursor_child = egg_flow_box_toggle_cursor_child;
+  class->move_cursor = egg_flow_box_move_cursor;
   class->select_all = egg_flow_box_select_all;
   class->unselect_all = egg_flow_box_unselect_all;
-  class->selected_children_changed = egg_flow_box_real_selected_children_changed;
+  class->selected_children_changed = egg_flow_box_selected_children_changed;
 
   g_object_class_override_property (object_class, PROP_ORIENTATION, "orientation");
 
@@ -3412,6 +3773,9 @@ egg_flow_box_init (EggFlowBox *box)
 
   box->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (box, EGG_TYPE_FLOW_BOX, EggFlowBoxPrivate);
 
+  gtk_widget_set_has_window (GTK_WIDGET (box), TRUE);
+  gtk_widget_set_redraw_on_allocate (GTK_WIDGET (box), TRUE);
+
   priv->orientation = GTK_ORIENTATION_HORIZONTAL;
   priv->selection_mode = GTK_SELECTION_SINGLE;
   priv->halign_policy = GTK_ALIGN_FILL;
@@ -3419,12 +3783,9 @@ egg_flow_box_init (EggFlowBox *box)
   priv->max_children_per_line = DEFAULT_MAX_CHILDREN_PER_LINE;
   priv->column_spacing = 0;
   priv->row_spacing = 0;
-  priv->children = g_sequence_new ((GDestroyNotify)egg_flow_box_child_info_free);
-  priv->child_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
   priv->activate_on_single_click = TRUE;
 
-  gtk_widget_set_can_focus (GTK_WIDGET (box), TRUE);
-  gtk_widget_set_has_window (GTK_WIDGET (box), TRUE);
+  priv->children = g_sequence_new (NULL);
 }
 
 /**
@@ -3451,7 +3812,8 @@ egg_flow_box_new (void)
 GList *
 egg_flow_box_get_selected_children (EggFlowBox *box)
 {
-  EggFlowBoxChildInfo *child_info;
+  EggFlowBoxChild *child_info;
+  EggFlowBoxChildPrivate *child_priv;
   GSequenceIter *iter;
   GList *selected = NULL;
 
@@ -3462,65 +3824,47 @@ egg_flow_box_get_selected_children (EggFlowBox *box)
        iter = g_sequence_iter_next (iter))
     {
       child_info = g_sequence_get (iter);
-      if (child_info->selected)
-        selected = g_list_prepend (selected, child_info->widget);
+      child_priv = egg_flow_box_child_get_instance_private (child_info);
+      if (child_priv->selected)
+        selected = g_list_prepend (selected, child_info);
     }
 
   return g_list_reverse (selected);
 }
 
 void
-egg_flow_box_select_child (EggFlowBox *box,
-                           GtkWidget  *child)
+egg_flow_box_select_child (EggFlowBox      *box,
+                           EggFlowBoxChild *child)
 {
-  EggFlowBoxChildInfo *child_info;
-
   g_return_if_fail (EGG_IS_FLOW_BOX (box));
-  g_return_if_fail (child != NULL);
+  g_return_if_fail (EGG_IS_FLOW_BOX_CHILD (child));
 
-  child_info = egg_flow_box_lookup_info (box, child);
-  if (child_info == NULL)
-    {
-      g_warning ("Tried to select non-child %p\n", child);
-      return;
-    }
-
-  egg_flow_box_select_child_info (box, child_info);
+  egg_flow_box_select_child_info (box, child);
 }
 
 void
-egg_flow_box_unselect_child (EggFlowBox *box,
-                             GtkWidget  *child)
+egg_flow_box_unselect_child (EggFlowBox      *box,
+                             EggFlowBoxChild *child)
 {
-  EggFlowBoxChildInfo *child_info;
+  EggFlowBoxChild *child_info;
 
   g_return_if_fail (EGG_IS_FLOW_BOX (box));
-  g_return_if_fail (child != NULL);
+  g_return_if_fail (EGG_IS_FLOW_BOX_CHILD (child));
 
-  child_info = egg_flow_box_lookup_info (box, child);
-  if (child_info == NULL)
-    {
-      g_warning ("Tried to unselect non-child %p\n", child);
-      return;
-    }
-
-  egg_flow_box_unselect_child_info (box, child_info);
+  egg_flow_box_unselect_child_info (box, child);
 }
 
 gboolean
-egg_flow_box_is_child_selected (EggFlowBox *box,
-                                GtkWidget  *child)
+egg_flow_box_is_child_selected (EggFlowBox      *box,
+                                EggFlowBoxChild *child)
 {
-  EggFlowBoxChildInfo *child_info;
+  EggFlowBoxChildPrivate *priv;
 
-  child_info = egg_flow_box_lookup_info (box, child);
-  if (child_info == NULL)
-    {
-      g_warning ("Tried to obtain selection status of non-child %p\n", child);
-      return FALSE;
-    }
+  g_return_if_fail (EGG_IS_FLOW_BOX (box));
+  g_return_if_fail (EGG_IS_FLOW_BOX_CHILD (child));
 
-  return child_info->selected;
+  priv = egg_flow_box_child_get_instance_private (child);
+  return priv->selected;
 }
 
 /**
@@ -3537,7 +3881,8 @@ egg_flow_box_selected_foreach (EggFlowBox           *box,
                                EggFlowBoxForeachFunc func,
                                gpointer              data)
 {
-  EggFlowBoxChildInfo *child_info;
+  EggFlowBoxChild *child_info;
+  EggFlowBoxChildPrivate *priv;
   GSequenceIter *iter;
 
   g_return_if_fail (EGG_IS_FLOW_BOX (box));
@@ -3547,14 +3892,15 @@ egg_flow_box_selected_foreach (EggFlowBox           *box,
        iter = g_sequence_iter_next (iter))
     {
       child_info = g_sequence_get (iter);
-      if (child_info->selected)
-        (* func) (box, child_info->widget, data);
+      priv = egg_flow_box_child_get_instance_private (child_info);
+      if (priv->selected)
+        (* func) (box, child_info, data);
     }
 }
 
 void
-egg_flow_box_set_selection_mode (EggFlowBox *box,
-                                 GtkSelectionMode mode)
+egg_flow_box_set_selection_mode (EggFlowBox       *box,
+                                 GtkSelectionMode  mode)
 {
   gboolean dirty = FALSE;
   g_return_if_fail (EGG_IS_FLOW_BOX (box));
diff --git a/egg-flow-box.h b/egg-flow-box.h
index 3154a9f..d85b147 100644
--- a/egg-flow-box.h
+++ b/egg-flow-box.h
@@ -42,17 +42,21 @@ typedef struct _EggFlowBox            EggFlowBox;
 typedef struct _EggFlowBoxPrivate     EggFlowBoxPrivate;
 typedef struct _EggFlowBoxClass       EggFlowBoxClass;
 
+typedef struct _EggFlowBoxChild       EggFlowBoxChild;
+typedef struct _EggFlowBoxChildClass  EggFlowBoxChildClass;
+
 /**
  * EggFlowBoxForeachFunc:
- * @flow_box: an #EggFlowBox
- * @child: The child #GtkWidget
+ * @box: an #EggFlowBox
+ * @child: The child #EggFlowBoxChild
  * @data: user data
  *
  * A function used by egg_flow_box_selected_foreach() to map all
- * selected children.  It will be called on every selected child in the box.
+ * selected children.  It will be called on every selected child
+ * in the box.
  */
-typedef void (* EggFlowBoxForeachFunc)     (EggFlowBox      *flow_box,
-                                            GtkWidget       *child,
+typedef void (* EggFlowBoxForeachFunc)     (EggFlowBox      *box,
+                                            EggFlowBoxChild *child,
                                             gpointer         data);
 
 struct _EggFlowBox
@@ -67,15 +71,55 @@ struct _EggFlowBoxClass
 {
   GtkContainerClass parent_class;
 
-  void (* child_activated) (EggFlowBox *self, GtkWidget *child);
-  void (* selected_children_changed) (EggFlowBox *self);
-  void (*activate_cursor_child) (EggFlowBox *self);
-  void (*toggle_cursor_child) (EggFlowBox *self);
-  void (*move_cursor) (EggFlowBox *self, GtkMovementStep step, gint count);
-  void (*select_all) (EggFlowBox *self);
-  void (*unselect_all) (EggFlowBox *self);
+  void (*child_activated)            (EggFlowBox        *box,
+                                      EggFlowBoxChild   *child);
+  void (*selected_children_changed)  (EggFlowBox        *box);
+  void (*activate_cursor_child)      (EggFlowBox        *box);
+  void (*toggle_cursor_child)        (EggFlowBox        *box);
+  void (*move_cursor)                (EggFlowBox        *box,
+                                      GtkMovementStep    step,
+                                      gint               count);
+  void (*select_all)                 (EggFlowBox        *box);
+  void (*unselect_all)               (EggFlowBox        *box);
+
+  /* Padding for future expansion */
+  void (*_gtk_reserved1) (void);
+  void (*_gtk_reserved2) (void);
+  void (*_gtk_reserved3) (void);
+  void (*_gtk_reserved4) (void);
+  void (*_gtk_reserved5) (void);
+  void (*_gtk_reserved6) (void);
+};
+
+#define EGG_TYPE_FLOW_BOX_CHILD            (egg_flow_box_child_get_type ())
+#define EGG_FLOW_BOX_CHILD(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_FLOW_BOX_CHILD, 
EggFlowBoxChild))
+#define EGG_FLOW_BOX_CHILD_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_FLOW_BOX_CHILD, 
EggFlowBoxChildClass))
+#define EGG_IS_FLOW_BOX_CHILD(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_FLOW_BOX_CHILD))
+#define EGG_IS_FLOW_BOX_CHILD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_FLOW_BOX_CHILD))
+#define EGG_FLOW_BOX_CHILD_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), EG_TYPE_FLOW_BOX_CHILD, 
EggFlowBoxChildClass))
+
+struct _EggFlowBoxChild
+{
+  GtkBin parent_instance;
+};
+
+struct _EggFlowBoxChildClass
+{
+  GtkBinClass parent_class;
+
+  void (* activate) (EggFlowBoxChild *child);
+
+  /* Padding for future expansion */
+  void (*_gtk_reserved1) (void);
+  void (*_gtk_reserved2) (void);
 };
 
+GType                 egg_flow_box_child_get_type            (void) G_GNUC_CONST;
+GtkWidget*            egg_flow_box_child_new                 (void);
+gint                  egg_flow_box_child_get_index           (EggFlowBoxChild *child);
+void                  egg_flow_box_child_changed             (EggFlowBoxChild *child);
+
+
 GType                 egg_flow_box_get_type                  (void) G_GNUC_CONST;
 
 GtkWidget            *egg_flow_box_new                       (void);
@@ -114,13 +158,13 @@ void                  egg_flow_box_selected_foreach             (EggFlowBox
                                                                  EggFlowBoxForeachFunc func,
                                                                  gpointer           data);
 void                  egg_flow_box_select_child                 (EggFlowBox        *box,
-                                                                 GtkWidget         *child);
+                                                                 EggFlowBoxChild   *child);
 void                  egg_flow_box_unselect_child               (EggFlowBox        *box,
-                                                                 GtkWidget         *child);
+                                                                 EggFlowBoxChild   *child);
 void                  egg_flow_box_select_all                   (EggFlowBox        *box);
 void                  egg_flow_box_unselect_all                 (EggFlowBox        *box);
 gboolean              egg_flow_box_is_child_selected            (EggFlowBox        *box,
-                                                                 GtkWidget         *child);
+                                                                 EggFlowBoxChild   *child);
 GtkSelectionMode      egg_flow_box_get_selection_mode           (EggFlowBox        *box);
 void                  egg_flow_box_set_selection_mode           (EggFlowBox        *box,
                                                                  GtkSelectionMode   mode);
diff --git a/test-flow-box.c b/test-flow-box.c
index 3d2612e..42f714c 100644
--- a/test-flow-box.c
+++ b/test-flow-box.c
@@ -287,11 +287,14 @@ on_child_activated (EggFlowBox *self,
 }
 
 static void
-selection_foreach (EggFlowBox *self,
-                   GtkWidget  *child,
-                   gpointer    data)
+selection_foreach (EggFlowBox      *self,
+                   EggFlowBoxChild *child_info,
+                   gpointer         data)
 {
   const char *id;
+  GtkWidget *child;
+
+  child = gtk_bin_get_child (GTK_BIN (child_info));
   id = g_object_get_data (G_OBJECT (child), "id");
   g_message ("Child selected %p: %s", child, id);
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]