[egg-list-box/flow-box-enhancements] Reorganize the code



commit b985f1f934c8e1842f2b888fc72dcee0f03e92d0
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Sep 29 12:56:02 2013 -0400

    Reorganize the code
    
    Separate EggFlowBoxChild from EggFlowBox code, and
    keep things a bit more organized.

 egg-flow-box.c | 2673 +++++++++++++++++++++++++++++---------------------------
 1 files changed, 1389 insertions(+), 1284 deletions(-)
---
diff --git a/egg-flow-box.c b/egg-flow-box.c
index e09e25d..a589b8a 100644
--- a/egg-flow-box.c
+++ b/egg-flow-box.c
@@ -23,6 +23,8 @@
  *      William Jon McCann <jmccann redhat com>
  */
 
+/* Preamble {{{1 */
+
 /**
  * SECTION:eggflowbox
  * @Short_Description: A container that allows reflowing its children
@@ -49,41 +51,6 @@
  * Also see #GtkListBox.
  */
 
-/**
- * EggFlowBoxForeachFunc:
- * @box: a #EggFlowBox
- * @child: a #EggFlowBoxChild
- * @user_data: (closure): user data
- *
- * A function used by egg_flow_box_selected_foreach().
- * It will be called on every selected child of tht @box.
- */
-
-/**
- * EggFlowBoxFilterFunc:
- * @child: a #EggFlowBoxChild that may be filtered
- * @user_data: (closure): user data
- *
- * A function that will be called whenrever a child changes
- * or is added. It lets you control if the child should be
- * visible or not.
- *
- * Returns: %TRUE if the row should be visible, %FALSE otherwise
- */
-
-/**
- * EggFlowBoxSortFunc:
- * @child1: the first child
- * @child2: the second child
- * @user_data: (closure): user data
- *
- * A function to compare two children to determine which
- * should come first.
- *
- * Returns: < 0 if @child1 should be before @child2, 0 if
- *     the are equal, and > 0 otherwise
- */
-
 #include <config.h>
 
 #include <gtk/gtk.h>
@@ -122,144 +89,185 @@ _egg_marshal_VOID__ENUM_INT (GClosure * closure,
 #define I_(msgid) (msgid)
 #define P_(msgid) (msgid)
 
-#define DEFAULT_MAX_CHILDREN_PER_LINE 7
-#define RUBBERBAND_START_DISTANCE 32
-#define AUTOSCROLL_FAST_DISTANCE 32
-#define AUTOSCROLL_FACTOR 20
-#define AUTOSCROLL_FACTOR_FAST 10
+/* Forward declarations and utilities {{{1 */
 
-enum {
-  CHILD_ACTIVATED,
-  SELECTED_CHILDREN_CHANGED,
-  ACTIVATE_CURSOR_CHILD,
-  TOGGLE_CURSOR_CHILD,
-  MOVE_CURSOR,
-  SELECT_ALL,
-  UNSELECT_ALL,
-  LAST_SIGNAL
-};
+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);
+static void egg_flow_box_apply_filter        (EggFlowBox      *box,
+                                              EggFlowBoxChild *child);
+static void egg_flow_box_apply_sort          (EggFlowBox      *box,
+                                              EggFlowBoxChild *child);
+static gint egg_flow_box_sort                (EggFlowBoxChild *a,
+                                              EggFlowBoxChild *b,
+                                              EggFlowBox      *box);
 
-enum {
-  CHILD_ACTIVATE,
-  CHILD_LAST_SIGNAL
-};
+static void
+get_current_selection_modifiers (GtkWidget *widget,
+                                 gboolean  *modify,
+                                 gboolean  *extend)
+{
+  GdkModifierType state = 0;
+  GdkModifierType mask;
 
-enum {
-  PROP_0,
-  PROP_ORIENTATION,
-  PROP_HOMOGENEOUS,
-  PROP_HALIGN_POLICY,
-  PROP_VALIGN_POLICY,
-  PROP_COLUMN_SPACING,
-  PROP_ROW_SPACING,
-  PROP_MIN_CHILDREN_PER_LINE,
-  PROP_MAX_CHILDREN_PER_LINE,
-  PROP_SELECTION_MODE,
-  PROP_ACTIVATE_ON_SINGLE_CLICK
-};
+  *modify = FALSE;
+  *extend = FALSE;
 
-typedef struct _EggFlowBoxPrivate EggFlowBoxPrivate;
-struct _EggFlowBoxPrivate {
-  GtkOrientation    orientation;
-  gboolean          homogeneous;
+  if (gtk_get_current_event_state (&state))
+    {
+      mask = gtk_widget_get_modifier_mask (widget, GDK_MODIFIER_INTENT_MODIFY_SELECTION);
+      if ((state & mask) == mask)
+        *modify = TRUE;
+      mask = gtk_widget_get_modifier_mask (widget, GDK_MODIFIER_INTENT_EXTEND_SELECTION);
+      if ((state & mask) == mask)
+        *extend = TRUE;
+    }
+}
 
-  guint             row_spacing;
-  guint             column_spacing;
+static void
+path_from_horizontal_line_rects (cairo_t      *cr,
+                                 GdkRectangle *lines,
+                                 gint          n_lines)
+{
+  gint start_line, end_line;
+  GdkRectangle *r;
+  gint i;
 
-  EggFlowBoxChild  *prelight_child;
-  EggFlowBoxChild  *cursor_child;
-  EggFlowBoxChild  *selected_child;
+  /* Join rows vertically by extending to the middle */
+  for (i = 0; i < n_lines - 1; i++)
+    {
+      GdkRectangle *r1 = &lines[i];
+      GdkRectangle *r2 = &lines[i+1];
+      gint gap, old;
 
-  gboolean          active_child_active;
-  EggFlowBoxChild  *active_child;
+      gap = r2->y - (r1->y + r1->height);
+      r1->height += gap / 2;
+      old = r2->y;
+      r2->y = r1->y + r1->height;
+      r2->height += old - r2->y;
+    }
 
-  GtkSelectionMode  selection_mode;
+  cairo_new_path (cr);
+  start_line = 0;
 
-  GtkAdjustment    *hadjustment;
-  GtkAdjustment    *vadjustment;
-  gboolean          activate_on_single_click;
+  do
+    {
+      for (i = start_line; i < n_lines; i++)
+        {
+          r = &lines[i];
+          if (i == start_line)
+            cairo_move_to (cr, r->x + r->width, r->y);
+          else
+            cairo_line_to (cr, r->x + r->width, r->y);
+          cairo_line_to (cr, r->x + r->width, r->y + r->height);
 
-  guint16           min_children_per_line;
-  guint16           max_children_per_line;
-  guint16           cur_children_per_line;
+          if (i < n_lines - 1 &&
+              (r->x + r->width < lines[i+1].x ||
+              r->x > lines[i+1].x + lines[i+1].width))
+            {
+              i++;
+              break;
+            }
+        }
+      end_line = i;
+      for (i = end_line - 1; i >= start_line; i--)
+        {
+          r = &lines[i];
+          cairo_line_to (cr, r->x, r->y + r->height);
+          cairo_line_to (cr, r->x, r->y);
+        }
+      cairo_close_path (cr);
+      start_line = end_line;
+    }
+  while (end_line < n_lines);
+}
 
-  GSequence        *children;
+static void
+path_from_vertical_line_rects (cairo_t      *cr,
+                               GdkRectangle *lines,
+                               gint          n_lines)
+{
+  gint start_line, end_line;
+  GdkRectangle *r;
+  gint i;
 
-  EggFlowBoxFilterFunc filter_func;
-  gpointer             filter_data;
-  GDestroyNotify       filter_destroy;
+  /* Join rows horizontall by extending to the middle */
+  for (i = 0; i < n_lines - 1; i++)
+    {
+      GdkRectangle *r1 = &lines[i];
+      GdkRectangle *r2 = &lines[i+1];
+      gint gap, old;
 
-  EggFlowBoxSortFunc sort_func;
-  gpointer           sort_data;
-  GDestroyNotify     sort_destroy;
+      gap = r2->x - (r1->x + r1->width);
+      r1->width += gap / 2;
+      old = r2->x;
+      r2->x = r1->x + r1->width;
+      r2->width += old - r2->x;
+    }
 
-  gboolean           track_motion;
-  gboolean           rubberband_select;
-  EggFlowBoxChild   *rubberband_first;
-  EggFlowBoxChild   *rubberband_last;
-  gint               button_down_x;
-  gint               button_down_y;
-  GdkDevice         *rubberband_device;
+  cairo_new_path (cr);
+  start_line = 0;
 
-  GtkScrollType      autoscroll_mode;
-  guint              autoscroll_id;
+  do
+    {
+      for (i = start_line; i < n_lines; i++)
+        {
+          r = &lines[i];
+          if (i == start_line)
+            cairo_move_to (cr, r->x, r->y + r->height);
+          else
+            cairo_line_to (cr, r->x, r->y + r->height);
+          cairo_line_to (cr, r->x + r->width, r->y + r->height);
+
+          if (i < n_lines - 1 &&
+              (r->y + r->height < lines[i+1].y ||
+              r->y > lines[i+1].y + lines[i+1].height))
+            {
+              i++;
+              break;
+            }
+        }
+      end_line = i;
+      for (i = end_line - 1; i >= start_line; i--)
+        {
+          r = &lines[i];
+          cairo_line_to (cr, r->x + r->width, r->y);
+          cairo_line_to (cr, r->x, r->y);
+        }
+      cairo_close_path (cr);
+      start_line = end_line;
+    }
+  while (end_line < n_lines);
+}
+
+/* EggFlowBoxChild {{{1 */
+
+/* GObject boilerplate {{{2 */
+
+enum {
+  CHILD_ACTIVATE,
+  CHILD_LAST_SIGNAL
 };
 
+static guint child_signals[CHILD_LAST_SIGNAL] = { 0 };
+
 typedef struct _EggFlowBoxChildPrivate EggFlowBoxChildPrivate;
 struct _EggFlowBoxChildPrivate
 {
   GSequenceIter *iter;
-  guint          selected : 1;
+  gboolean       selected;
 };
 
-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_ADD_PRIVATE (EggFlowBox)
-                         G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL))
-G_DEFINE_TYPE_WITH_PRIVATE (EggFlowBoxChild, egg_flow_box_child, GTK_TYPE_BIN)
-
-#define BOX_PRIV(box) ((EggFlowBoxPrivate*)egg_flow_box_get_instance_private ((EggFlowBox*)(box)))
 #define CHILD_PRIV(child) ((EggFlowBoxChildPrivate*)egg_flow_box_child_get_instance_private 
((EggFlowBoxChild*)(child)))
 
-#define ORIENTATION_ALIGN(box)                              \
-  (BOX_PRIV(box)->orientation == GTK_ORIENTATION_HORIZONTAL \
-   ? gtk_widget_get_halign (GTK_WIDGET (box))               \
-   : gtk_widget_get_valign (GTK_WIDGET (box)))
-
-#define OPPOSING_ORIENTATION_ALIGN(box)                     \
-  (BOX_PRIV(box)->orientation == GTK_ORIENTATION_HORIZONTAL \
-   ? gtk_widget_get_valign (GTK_WIDGET (box))               \
-   : gtk_widget_get_halign (GTK_WIDGET (box)))
-
-
-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);
-static void egg_flow_box_apply_filter        (EggFlowBox      *box,
-                                              EggFlowBoxChild *child);
-static gint egg_flow_box_sort                (EggFlowBoxChild *a,
-                                              EggFlowBoxChild *b,
-                                              EggFlowBox      *box);
-
-
-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);
+G_DEFINE_TYPE_WITH_PRIVATE (EggFlowBoxChild, egg_flow_box_child, GTK_TYPE_BIN)
 
-  context = gtk_widget_get_style_context (GTK_WIDGET (child));
-  gtk_style_context_add_class (context, "grid-child");
-}
+/* Internal API {{{2 */
 
 static EggFlowBox *
 egg_flow_box_child_get_box (EggFlowBoxChild *child)
@@ -274,28 +282,6 @@ egg_flow_box_child_get_box (EggFlowBoxChild *child)
 }
 
 static void
-get_current_selection_modifiers (GtkWidget *widget,
-                                 gboolean  *modify,
-                                 gboolean  *extend)
-{
-  GdkModifierType state = 0;
-  GdkModifierType mask;
-
-  *modify = FALSE;
-  *extend = FALSE;
-
-  if (gtk_get_current_event_state (&state))
-    {
-      mask = gtk_widget_get_modifier_mask (widget, GDK_MODIFIER_INTENT_MODIFY_SELECTION);
-      if ((state & mask) == mask)
-        *modify = TRUE;
-      mask = gtk_widget_get_modifier_mask (widget, GDK_MODIFIER_INTENT_EXTEND_SELECTION);
-      if ((state & mask) == mask)
-        *extend = TRUE;
-    }
-}
-
-static void
 egg_flow_box_child_set_focus (EggFlowBoxChild *child)
 {
   EggFlowBox *box = egg_flow_box_child_get_box (child);
@@ -310,6 +296,8 @@ egg_flow_box_child_set_focus (EggFlowBoxChild *child)
     egg_flow_box_update_selection (box, child, FALSE, FALSE);
 }
 
+/* GtkWidget implementation {{{2 */
+
 static gboolean
 egg_flow_box_child_focus (GtkWidget        *widget,
                           GtkDirectionType  direction)
@@ -406,6 +394,8 @@ egg_flow_box_child_draw (GtkWidget *widget,
   return TRUE;
 }
 
+/* Size allocation {{{3 */
+
 static void
 egg_flow_box_child_get_full_border (EggFlowBoxChild *child,
                                     GtkBorder       *full_border)
@@ -600,6 +590,8 @@ egg_flow_box_child_size_allocate (GtkWidget     *widget,
     }
 }
 
+/* GObject implementation {{{2 */
+
 static void
 egg_flow_box_child_class_init (EggFlowBoxChildClass *class)
 {
@@ -630,6 +622,20 @@ egg_flow_box_child_class_init (EggFlowBoxChildClass *class)
   gtk_widget_class_set_accessible_role (widget_class, ATK_ROLE_LIST_ITEM);
 }
 
+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");
+}
+
+/* Public API {{{2 */
+
 /**
  * egg_flow_box_child_new:
  *
@@ -718,95 +724,113 @@ egg_flow_box_child_changed (EggFlowBoxChild *child)
   if (box == NULL)
     return;
 
-  if (BOX_PRIV (box)->sort_func != NULL)
-    {
-      g_sequence_sort_changed (CHILD_PRIV (child)->iter,
-                               (GCompareDataFunc)egg_flow_box_sort, box);
-      gtk_widget_queue_resize (GTK_WIDGET (box));
-    }
-
+  egg_flow_box_apply_sort (box, child);
   egg_flow_box_apply_filter (box, child);
 }
 
-void
-egg_flow_box_set_hadjustment (EggFlowBox    *box,
-                              GtkAdjustment *adjustment)
-{
-  EggFlowBoxPrivate *priv;
+/* EggFlowBox {{{1 */
 
-  g_return_if_fail (EGG_IS_FLOW_BOX (box));
-  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+/* Constants {{{2 */
 
-  priv = BOX_PRIV (box);
+#define DEFAULT_MAX_CHILDREN_PER_LINE 7
+#define RUBBERBAND_START_DISTANCE 32
+#define AUTOSCROLL_FAST_DISTANCE 32
+#define AUTOSCROLL_FACTOR 20
+#define AUTOSCROLL_FACTOR_FAST 10
 
-  g_object_ref (adjustment);
-  if (priv->hadjustment)
-    g_object_unref (priv->hadjustment);
-  priv->hadjustment = adjustment;
-  gtk_container_set_focus_hadjustment (GTK_CONTAINER (box), adjustment);
-}
+/* GObject boilerplate {{{2 */
 
-void
-egg_flow_box_set_vadjustment (EggFlowBox    *box,
-                              GtkAdjustment *adjustment)
-{
-  EggFlowBoxPrivate *priv;
+enum {
+  CHILD_ACTIVATED,
+  SELECTED_CHILDREN_CHANGED,
+  ACTIVATE_CURSOR_CHILD,
+  TOGGLE_CURSOR_CHILD,
+  MOVE_CURSOR,
+  SELECT_ALL,
+  UNSELECT_ALL,
+  LAST_SIGNAL
+};
 
-  g_return_if_fail (EGG_IS_FLOW_BOX (box));
-  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+static guint signals[LAST_SIGNAL] = { 0 };
 
-  priv = BOX_PRIV (box);
+enum {
+  PROP_0,
+  PROP_ORIENTATION,
+  PROP_HOMOGENEOUS,
+  PROP_HALIGN_POLICY,
+  PROP_VALIGN_POLICY,
+  PROP_COLUMN_SPACING,
+  PROP_ROW_SPACING,
+  PROP_MIN_CHILDREN_PER_LINE,
+  PROP_MAX_CHILDREN_PER_LINE,
+  PROP_SELECTION_MODE,
+  PROP_ACTIVATE_ON_SINGLE_CLICK
+};
 
-  g_object_ref (adjustment);
-  if (priv->vadjustment)
-    g_object_unref (priv->vadjustment);
-  priv->vadjustment = adjustment;
-  gtk_container_set_focus_vadjustment (GTK_CONTAINER (box), adjustment);
-}
+typedef struct _EggFlowBoxPrivate EggFlowBoxPrivate;
+struct _EggFlowBoxPrivate {
+  GtkOrientation    orientation;
+  gboolean          homogeneous;
 
-/**
- * egg_flow_box_get_homogeneous:
- * @box: a #EggFlowBox
- *
- * Returns whether the box is homogeneous (all children are the
- * same size). See gtk_box_set_homogeneous().
- *
- * Return value: %TRUE if the box is homogeneous.
- **/
-gboolean
-egg_flow_box_get_homogeneous (EggFlowBox *box)
-{
-  g_return_val_if_fail (EGG_IS_FLOW_BOX (box), FALSE);
+  guint             row_spacing;
+  guint             column_spacing;
 
-  return BOX_PRIV (box)->homogeneous;
-}
+  EggFlowBoxChild  *prelight_child;
+  EggFlowBoxChild  *cursor_child;
+  EggFlowBoxChild  *selected_child;
 
-/**
- * egg_flow_box_set_homogeneous:
- * @box: a #EggFlowBox
- * @homogeneous: a boolean value, %TRUE to create equal allotments,
- *   %FALSE for variable allotments
- *
- * Sets the #EggFlowBox:homogeneous property of @box, controlling
- * whether or not all children of @box are given equal space
- * in the box.
- */
-void
-egg_flow_box_set_homogeneous (EggFlowBox *box,
-                              gboolean    homogeneous)
-{
-  g_return_if_fail (EGG_IS_FLOW_BOX (box));
+  gboolean          active_child_active;
+  EggFlowBoxChild  *active_child;
 
-  homogeneous = homogeneous != FALSE;
+  GtkSelectionMode  selection_mode;
 
-  if (BOX_PRIV (box)->homogeneous != homogeneous)
-    {
-      BOX_PRIV (box)->homogeneous = homogeneous;
+  GtkAdjustment    *hadjustment;
+  GtkAdjustment    *vadjustment;
+  gboolean          activate_on_single_click;
 
-      g_object_notify (G_OBJECT (box), "homogeneous");
-      gtk_widget_queue_resize (GTK_WIDGET (box));
-    }
-}
+  guint16           min_children_per_line;
+  guint16           max_children_per_line;
+  guint16           cur_children_per_line;
+
+  GSequence        *children;
+
+  EggFlowBoxFilterFunc filter_func;
+  gpointer             filter_data;
+  GDestroyNotify       filter_destroy;
+
+  EggFlowBoxSortFunc sort_func;
+  gpointer           sort_data;
+  GDestroyNotify     sort_destroy;
+
+  gboolean           track_motion;
+  gboolean           rubberband_select;
+  EggFlowBoxChild   *rubberband_first;
+  EggFlowBoxChild   *rubberband_last;
+  gint               button_down_x;
+  gint               button_down_y;
+  GdkDevice         *rubberband_device;
+
+  GtkScrollType      autoscroll_mode;
+  guint              autoscroll_id;
+};
+
+#define BOX_PRIV(box) ((EggFlowBoxPrivate*)egg_flow_box_get_instance_private ((EggFlowBox*)(box)))
+
+G_DEFINE_TYPE_WITH_CODE (EggFlowBox, egg_flow_box, GTK_TYPE_CONTAINER,
+                         G_ADD_PRIVATE (EggFlowBox)
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL))
+
+/* Internal API, utilities {{{2 */
+
+#define ORIENTATION_ALIGN(box)                              \
+  (BOX_PRIV(box)->orientation == GTK_ORIENTATION_HORIZONTAL \
+   ? gtk_widget_get_halign (GTK_WIDGET (box))               \
+   : gtk_widget_get_valign (GTK_WIDGET (box)))
+
+#define OPPOSING_ORIENTATION_ALIGN(box)                     \
+  (BOX_PRIV(box)->orientation == GTK_ORIENTATION_HORIZONTAL \
+   ? gtk_widget_get_valign (GTK_WIDGET (box))               \
+   : gtk_widget_get_halign (GTK_WIDGET (box)))
 
 /* Children are visible if they are shown by the app (visible)
  * and not filtered out (child_visible) by the box
@@ -838,6 +862,379 @@ get_visible_children (EggFlowBox *box)
   return i;
 }
 
+static EggFlowBoxChild *
+egg_flow_box_find_child_at_pos (EggFlowBox *box,
+                                gint        x,
+                                gint        y)
+{
+  GtkWidget *child;
+  GSequenceIter *iter;
+  GtkAllocation allocation;
+
+  for (iter = g_sequence_get_begin_iter (BOX_PRIV (box)->children);
+       !g_sequence_iter_is_end (iter);
+       iter = g_sequence_iter_next (iter))
+    {
+      child = g_sequence_get (iter);
+      if (!child_is_visible (child))
+        continue;
+      gtk_widget_get_allocation (child, &allocation);
+      if (x >= allocation.x && x < (allocation.x + allocation.width) &&
+          y >= allocation.y && y < (allocation.y + allocation.height))
+        return EGG_FLOW_BOX_CHILD (child);
+    }
+
+  return NULL;
+}
+
+static void
+egg_flow_box_update_prelight (EggFlowBox      *box,
+                              EggFlowBoxChild *child)
+{
+  EggFlowBoxPrivate *priv = BOX_PRIV (box);
+
+  if (child != priv->prelight_child)
+    {
+      priv->prelight_child = child;
+      gtk_widget_queue_draw (GTK_WIDGET (box));
+    }
+}
+
+static void
+egg_flow_box_update_active (EggFlowBox      *box,
+                            EggFlowBoxChild *child)
+{
+  EggFlowBoxPrivate *priv = BOX_PRIV (box);
+  gboolean val;
+
+  val = priv->active_child == child;
+  if (priv->active_child != NULL &&
+      val != priv->active_child_active)
+    {
+      priv->active_child_active = val;
+      gtk_widget_queue_draw (GTK_WIDGET (box));
+    }
+}
+
+/* Selection utilities {{{3 */
+
+static gboolean
+egg_flow_box_child_set_selected (EggFlowBoxChild *child,
+                                 gboolean         selected)
+{
+  EggFlowBox *box;
+
+  if (CHILD_PRIV (child)->selected != selected)
+    {
+      CHILD_PRIV (child)->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);
+
+      box = egg_flow_box_child_get_box (child);
+      _egg_flow_box_accessible_selection_changed (GTK_WIDGET (box));
+
+      gtk_widget_queue_draw (GTK_WIDGET (child));
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+egg_flow_box_unselect_all_internal (EggFlowBox *box)
+{
+  EggFlowBoxChild *child;
+  GSequenceIter *iter;
+  gboolean dirty = FALSE;
+
+  if (BOX_PRIV (box)->selection_mode == GTK_SELECTION_NONE)
+    return FALSE;
+
+  for (iter = g_sequence_get_begin_iter (BOX_PRIV (box)->children);
+       !g_sequence_iter_is_end (iter);
+       iter = g_sequence_iter_next (iter))
+    {
+      child = g_sequence_get (iter);
+      dirty |= egg_flow_box_child_set_selected (child, FALSE);
+    }
+
+  return dirty;
+}
+
+static void
+egg_flow_box_unselect_child_info (EggFlowBox      *box,
+                                  EggFlowBoxChild *child)
+{
+  if (!CHILD_PRIV (child)->selected)
+    return;
+
+  if (BOX_PRIV (box)->selection_mode == GTK_SELECTION_NONE)
+    return;
+  else if (BOX_PRIV (box)->selection_mode != GTK_SELECTION_MULTIPLE)
+    egg_flow_box_unselect_all_internal (box);
+  else
+    egg_flow_box_child_set_selected (child, FALSE);
+
+  g_signal_emit (box, signals[SELECTED_CHILDREN_CHANGED], 0);
+}
+
+static void
+egg_flow_box_update_cursor (EggFlowBox      *box,
+                            EggFlowBoxChild *child)
+{
+  BOX_PRIV (box)->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,
+                                EggFlowBoxChild *child)
+{
+  if (CHILD_PRIV (child)->selected)
+    return;
+
+  if (BOX_PRIV (box)->selection_mode == GTK_SELECTION_NONE)
+    return;
+  if (BOX_PRIV (box)->selection_mode != GTK_SELECTION_MULTIPLE)
+    egg_flow_box_unselect_all_internal (box);
+
+  egg_flow_box_child_set_selected (child, TRUE);
+  BOX_PRIV (box)->selected_child = child;
+
+  g_signal_emit (box, signals[SELECTED_CHILDREN_CHANGED], 0);
+
+  egg_flow_box_update_cursor (box, child);
+}
+
+static void
+egg_flow_box_select_all_between (EggFlowBox      *box,
+                                 EggFlowBoxChild *child1,
+                                 EggFlowBoxChild *child2)
+{
+  GSequenceIter *iter, *iter1, *iter2;
+
+  if (child1)
+    iter1 = CHILD_PRIV (child1)->iter;
+  else
+    iter1 = g_sequence_get_begin_iter (BOX_PRIV (box)->children);
+
+  if (child2)
+    iter2 = CHILD_PRIV (child2)->iter;
+  else
+    iter2 = g_sequence_get_end_iter (BOX_PRIV (box)->children);
+
+  if (g_sequence_iter_compare (iter2, iter1) < 0)
+    {
+      iter = iter1;
+      iter1 = iter2;
+      iter2 = iter;
+    }
+
+  for (iter = iter1;
+       !g_sequence_iter_is_end (iter);
+       iter = g_sequence_iter_next (iter))
+    {
+      GtkWidget *child;
+
+      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;
+    }
+}
+
+static void
+egg_flow_box_update_selection (EggFlowBox      *box,
+                               EggFlowBoxChild *child,
+                               gboolean         modify,
+                               gboolean         extend)
+{
+  EggFlowBoxPrivate *priv = BOX_PRIV (box);
+
+  egg_flow_box_update_cursor (box, child);
+
+  if (priv->selection_mode == GTK_SELECTION_NONE)
+    return;
+
+  if (priv->selection_mode == GTK_SELECTION_BROWSE)
+    {
+      egg_flow_box_unselect_all_internal (box);
+      egg_flow_box_child_set_selected (child, TRUE);
+      priv->selected_child = child;
+    }
+  else if (priv->selection_mode == GTK_SELECTION_SINGLE)
+    {
+      gboolean was_selected;
+
+      was_selected = CHILD_PRIV (child)->selected;
+      egg_flow_box_unselect_all_internal (box);
+      egg_flow_box_child_set_selected (child, modify ? !was_selected : TRUE);
+      priv->selected_child = CHILD_PRIV (child)->selected ? child : NULL;
+    }
+  else /* GTK_SELECTION_MULTIPLE */
+    {
+      if (extend)
+        {
+          egg_flow_box_unselect_all_internal (box);
+          if (priv->selected_child == NULL)
+            {
+              egg_flow_box_child_set_selected (child, TRUE);
+              priv->selected_child = child;
+            }
+          else
+            egg_flow_box_select_all_between (box, priv->selected_child, child);
+        }
+      else
+        {
+          egg_flow_box_child_set_selected (child, modify ? !CHILD_PRIV (child)->selected : TRUE);
+          priv->selected_child = child;
+        }
+    }
+
+  g_signal_emit (box, signals[SELECTED_CHILDREN_CHANGED], 0);
+}
+
+static void
+egg_flow_box_select_and_activate (EggFlowBox      *box,
+                                  EggFlowBoxChild *child)
+{
+  if (child != NULL)
+    {
+      egg_flow_box_select_child_info (box, child);
+      g_signal_emit (box, signals[CHILD_ACTIVATED], 0, child);
+    }
+}
+
+/* Focus utilities {{{3 */
+
+static GSequenceIter *
+egg_flow_box_get_previous_focusable (EggFlowBox    *box,
+                                     GSequenceIter *iter)
+{
+  EggFlowBoxChild *child;
+
+  while (!g_sequence_iter_is_begin (iter))
+    {
+      iter = g_sequence_iter_prev (iter);
+      child = g_sequence_get (iter);
+      if (child_is_visible (GTK_WIDGET (child)) &&
+          gtk_widget_is_sensitive (GTK_WIDGET (child)))
+        return iter;
+    }
+
+  return NULL;
+}
+
+static GSequenceIter *
+egg_flow_box_get_next_focusable (EggFlowBox    *box,
+                                 GSequenceIter *iter)
+{
+  EggFlowBoxChild *child;
+
+  while (TRUE)
+    {
+      iter = g_sequence_iter_next (iter);
+      if (g_sequence_iter_is_end (iter))
+        return iter;
+      child = g_sequence_get (iter);
+      if (child_is_visible (GTK_WIDGET (child)) &&
+          gtk_widget_is_sensitive (GTK_WIDGET (child)))
+        return iter;
+    }
+
+  return NULL;
+}
+
+static GSequenceIter *
+egg_flow_box_get_first_focusable (EggFlowBox *box)
+{
+  GSequenceIter *iter;
+  EggFlowBoxChild *child;
+
+  iter = g_sequence_get_begin_iter (BOX_PRIV (box)->children);
+  child = g_sequence_get (iter);
+  if (child_is_visible (GTK_WIDGET (child)) &&
+      gtk_widget_is_sensitive (GTK_WIDGET (child)))
+    return iter;
+
+  return egg_flow_box_get_next_focusable (box, iter);
+}
+
+static GSequenceIter *
+egg_flow_box_get_last_focusable (EggFlowBox *box)
+{
+  GSequenceIter *iter;
+
+  iter = g_sequence_get_end_iter (BOX_PRIV (box)->children);
+  return egg_flow_box_get_previous_focusable (box, iter);
+}
+
+
+static GSequenceIter *
+egg_flow_box_get_above_focusable (EggFlowBox    *box,
+                                  GSequenceIter *iter)
+{
+  EggFlowBoxChild *child = NULL;
+  gint i;
+
+  while (TRUE)
+    {
+      i = 0;
+      while (i < BOX_PRIV (box)->cur_children_per_line)
+        {
+          if (g_sequence_iter_is_begin (iter))
+            return NULL;
+          iter = g_sequence_iter_prev (iter);
+          child = g_sequence_get (iter);
+          if (child_is_visible (GTK_WIDGET (child)))
+            i++;
+        }
+      if (child && gtk_widget_get_sensitive (GTK_WIDGET (child)))
+        return iter;
+    }
+
+  return NULL;
+}
+
+static GSequenceIter *
+egg_flow_box_get_below_focusable (EggFlowBox    *box,
+                                  GSequenceIter *iter)
+{
+  EggFlowBoxChild *child;
+  gint i;
+
+  while (TRUE)
+    {
+      i = 0;
+      while (i < BOX_PRIV (box)->cur_children_per_line)
+        {
+          iter = g_sequence_iter_next (iter);
+          if (g_sequence_iter_is_end (iter))
+            return iter;
+          child = g_sequence_get (iter);
+          if (child_is_visible (GTK_WIDGET (child)))
+            i++;
+        }
+      if (child && gtk_widget_get_sensitive (GTK_WIDGET (child)))
+        return iter;
+    }
+
+  return NULL;
+}
+
+/* GtkWidget implementation {{{2 */
+
+/* Size allocation {{{3 */
+
 /* Used in columned modes where all items share at least their
  * equal widths or heights
  */
@@ -1504,79 +1901,6 @@ egg_flow_box_size_allocate (GtkWidget     *widget,
   g_free (line_sizes);
 }
 
-static void
-egg_flow_box_add (GtkContainer *container,
-                  GtkWidget    *child)
-{
-  egg_flow_box_insert (EGG_FLOW_BOX (container), child, -1);
-}
-
-static void
-egg_flow_box_remove (GtkContainer *container,
-                     GtkWidget    *widget)
-{
-  EggFlowBox *box = EGG_FLOW_BOX (container);
-  EggFlowBoxPrivate *priv = BOX_PRIV (box);
-  gboolean was_visible;
-  gboolean was_selected;
-  EggFlowBoxChild *child;
-
-  if (EGG_IS_FLOW_BOX_CHILD (widget))
-    child = EGG_FLOW_BOX_CHILD (widget);
-  else
-    {
-      child = (EggFlowBoxChild*)gtk_widget_get_parent (widget);
-      if (!EGG_IS_FLOW_BOX_CHILD (child))
-        {
-          g_warning ("Tried to remove non-child %p\n", widget);
-          return;
-        }
-    }
-
-  was_visible = child_is_visible (GTK_WIDGET (child));
-  was_selected = CHILD_PRIV (child)->selected;
-
-  if (child == priv->prelight_child)
-    priv->prelight_child = NULL;
-  if (child == priv->active_child)
-    priv->active_child = NULL;
-  if (child == priv->selected_child)
-    priv->selected_child = NULL;
-
-  gtk_widget_unparent (GTK_WIDGET (child));
-  g_sequence_remove (CHILD_PRIV (child)->iter);
-
-  if (was_visible && gtk_widget_get_visible (GTK_WIDGET (box)))
-    gtk_widget_queue_resize (GTK_WIDGET (box));
-
-  if (was_selected)
-    g_signal_emit (box, signals[SELECTED_CHILDREN_CHANGED], 0);
-}
-
-static void
-egg_flow_box_forall (GtkContainer *container,
-                     gboolean      include_internals,
-                     GtkCallback   callback,
-                     gpointer      callback_target)
-{
-  GSequenceIter *iter;
-  GtkWidget *child;
-
-  iter = g_sequence_get_begin_iter (BOX_PRIV (container)->children);
-  while (!g_sequence_iter_is_end (iter))
-    {
-      child = g_sequence_get (iter);
-      iter = g_sequence_iter_next (iter);
-      callback (child, callback_target);
-    }
-}
-
-static GType
-egg_flow_box_child_type (GtkContainer *container)
-{
-  return EGG_TYPE_FLOW_BOX_CHILD;
-}
-
 static GtkSizeRequestMode
 egg_flow_box_get_request_mode (GtkWidget *widget)
 {
@@ -2152,379 +2476,126 @@ egg_flow_box_get_preferred_width_for_height (GtkWidget *widget,
     *natural_width = nat_width;
 }
 
-/**
- * egg_flow_box_set_row_spacing:
- * @box: An #EggFlowBox
- * @spacing: The spacing to use
- *
- * Sets the vertical space to add between children.
- */
-void
-egg_flow_box_set_row_spacing (EggFlowBox *box,
-                              guint       spacing)
-{
-  g_return_if_fail (EGG_IS_FLOW_BOX (box));
-
-  if (BOX_PRIV (box)->row_spacing != spacing)
-    {
-      BOX_PRIV (box)->row_spacing = spacing;
-
-      gtk_widget_queue_resize (GTK_WIDGET (box));
-      g_object_notify (G_OBJECT (box), "vertical-spacing");
-    }
-}
-
-/**
- * egg_flow_box_get_row_spacing:
- * @box: An #EggFlowBox
- *
- * Gets the vertical spacing.
- *
- * Returns: The vertical spacing.
- */
-guint
-egg_flow_box_get_row_spacing (EggFlowBox *box)
-{
-  g_return_val_if_fail (EGG_IS_FLOW_BOX (box), FALSE);
-
-  return BOX_PRIV (box)->row_spacing;
-}
+/* Drawing {{{3 */
 
-/**
- * egg_flow_box_set_column_spacing:
- * @box: An #EggFlowBox
- * @spacing: The spacing to use
- *
- * Sets the horizontal space to add between children.
- */
-void
-egg_flow_box_set_column_spacing (EggFlowBox *box,
-                                 guint       spacing)
-{
-  g_return_if_fail (EGG_IS_FLOW_BOX (box));
-
-  if (BOX_PRIV (box)->column_spacing != spacing)
-    {
-      BOX_PRIV (box)->column_spacing = spacing;
-
-      gtk_widget_queue_resize (GTK_WIDGET (box));
-      g_object_notify (G_OBJECT (box), "horizontal-spacing");
-    }
-}
-
-/**
- * egg_flow_box_get_column_spacing:
- * @box: An #EggFlowBox
- *
- * Gets the horizontal spacing.
- *
- * Returns: The horizontal spacing.
- */
-guint
-egg_flow_box_get_column_spacing (EggFlowBox *box)
-{
-  g_return_val_if_fail (EGG_IS_FLOW_BOX (box), FALSE);
-
-  return BOX_PRIV (box)->column_spacing;
-}
-
-/**
- * egg_flow_box_set_min_children_per_line:
- * @box: An #EggFlowBox
- * @n_children: The minimum number of children per line
- *
- * Sets the minimum number of children to line up
- * in @box's orientation before flowing.
- */
-void
-egg_flow_box_set_min_children_per_line (EggFlowBox *box,
-                                        guint       n_children)
-{
-  g_return_if_fail (EGG_IS_FLOW_BOX (box));
-
-  if (BOX_PRIV (box)->min_children_per_line != n_children)
-    {
-      BOX_PRIV (box)->min_children_per_line = n_children;
-
-      gtk_widget_queue_resize (GTK_WIDGET (box));
-      g_object_notify (G_OBJECT (box), "min-children-per-line");
-    }
-}
-
-/**
- * egg_flow_box_get_min_children_per_line:
- * @box: An #EggFlowBox
- *
- * Gets the minimum number of children per line.
- *
- * Returns: The minimum number of children per line.
- */
-guint
-egg_flow_box_get_min_children_per_line (EggFlowBox *box)
+static gboolean
+egg_flow_box_draw (GtkWidget *widget,
+                   cairo_t   *cr)
 {
-  g_return_val_if_fail (EGG_IS_FLOW_BOX (box), FALSE);
+  EggFlowBox *box = EGG_FLOW_BOX (widget);
+  EggFlowBoxPrivate *priv = BOX_PRIV (box);
+  GtkAllocation allocation = { 0, };
+  GtkStyleContext* context;
 
-  return BOX_PRIV (box)->min_children_per_line;
-}
+  gtk_widget_get_allocation (GTK_WIDGET (box), &allocation);
+  context = gtk_widget_get_style_context (GTK_WIDGET (box));
+  gtk_render_background (context, cr, 0, 0, allocation.width, allocation.height);
 
-/**
- * egg_flow_box_set_max_children_per_line:
- * @box: An #EggFlowBox
- * @n_children: The maximum number of children per line.
- *
- * Sets the maximum number of children to request and
- * allocate space for in @box's orientation.
- *
- * Setting the maximum number of children per line
- * limits the overall natural size request to be no more
- * than @n_children children long in the given orientation.
- */
-void
-egg_flow_box_set_max_children_per_line (EggFlowBox *box,
-                                        guint       n_children)
-{
-  g_return_if_fail (EGG_IS_FLOW_BOX (box));
+  GTK_WIDGET_CLASS (egg_flow_box_parent_class)->draw (widget, cr);
 
-  if (BOX_PRIV (box)->max_children_per_line != n_children)
+  if (priv->rubberband_first && priv->rubberband_last)
     {
-      BOX_PRIV (box)->max_children_per_line = n_children;
-
-      gtk_widget_queue_resize (GTK_WIDGET (box));
-      g_object_notify (G_OBJECT (box), "max-children-per-line");
-    }
-}
+      GSequenceIter *iter, *iter1, *iter2;
+      GdkRectangle line_rect, rect;
+      GArray *lines;
+      gboolean vertical;
 
-/**
- * egg_flow_box_get_max_children_per_line:
- * @box: An #EggFlowBox
- *
- * Gets the maximum number of children per line.
- *
- * Returns: The maximum number of children per line.
- */
-guint
-egg_flow_box_get_max_children_per_line (EggFlowBox *box)
-{
-  g_return_val_if_fail (EGG_IS_FLOW_BOX (box), FALSE);
+      vertical = priv->orientation == GTK_ORIENTATION_VERTICAL;
 
-  return BOX_PRIV (box)->max_children_per_line;
-}
+      cairo_save (cr);
 
-/**
- * egg_flow_box_set_activate_on_single_click:
- * @box: An #EggFlowBox
- * @single: %TRUE to emit child-activated on a single click
- *
- * If @single is %TRUE, rows will be activated when you click
- * on them, otherwise you need to double-click.
- */
-void
-egg_flow_box_set_activate_on_single_click (EggFlowBox *box,
-                                           gboolean    single)
-{
-  g_return_if_fail (EGG_IS_FLOW_BOX (box));
+      context = gtk_widget_get_style_context (widget);
+      gtk_style_context_save (context);
+      gtk_style_context_add_class (context, GTK_STYLE_CLASS_RUBBERBAND);
 
-  single = single != FALSE;
+      iter1 = CHILD_PRIV (priv->rubberband_first)->iter;
+      iter2 = CHILD_PRIV (priv->rubberband_last)->iter;
 
-  if (BOX_PRIV (box)->activate_on_single_click != single)
-    {
-      BOX_PRIV (box)->activate_on_single_click = single;
-      g_object_notify (G_OBJECT (box), "activate-on-single-click");
-    }
-}
+      if (g_sequence_iter_compare (iter2, iter1) < 0)
+        {
+          iter = iter1;
+          iter1 = iter2;
+          iter2 = iter;
+        }
 
-/**
- * egg_flow_box_get_activate_on_single_click:
- * @box: An #EggFlowBox
- *
- * Returns whether rows activate on single clicks.
- *
- * Returns: %TRUE if rows are activated on single click,
- *     %FALSE otherwise
- */
-gboolean
-egg_flow_box_get_activate_on_single_click (EggFlowBox *box)
-{
-  g_return_val_if_fail (EGG_IS_FLOW_BOX (box), FALSE);
+      line_rect.width = 0;
+      lines = g_array_new (FALSE, FALSE, sizeof (GdkRectangle));
 
-  return BOX_PRIV (box)->activate_on_single_click;
-}
+      for (iter = iter1;
+           !g_sequence_iter_is_end (iter);
+           iter = g_sequence_iter_next (iter))
+        {
+          GtkWidget *child;
 
-static void
-egg_flow_box_get_property (GObject    *object,
-                           guint       prop_id,
-                           GValue     *value,
-                           GParamSpec *pspec)
-{
-  EggFlowBox *box = EGG_FLOW_BOX (object);
-  EggFlowBoxPrivate *priv = BOX_PRIV (box);
+          child = g_sequence_get (iter);
+          gtk_widget_get_allocation (GTK_WIDGET (child), &rect);
+          if (line_rect.width == 0)
+            line_rect = rect;
+          else
+            {
+              if ((vertical && rect.x == line_rect.x) ||
+                  (!vertical && rect.y == line_rect.y))
+                gdk_rectangle_union (&rect, &line_rect, &line_rect);
+              else
+                {
+                  g_array_append_val (lines, line_rect);
+                  line_rect = rect;
+                }
+            }
 
-  switch (prop_id)
-    {
-    case PROP_ORIENTATION:
-      g_value_set_enum (value, priv->orientation);
-      break;
-    case PROP_HOMOGENEOUS:
-      g_value_set_boolean (value, priv->homogeneous);
-      break;
-    case PROP_COLUMN_SPACING:
-      g_value_set_uint (value, priv->column_spacing);
-      break;
-    case PROP_ROW_SPACING:
-      g_value_set_uint (value, priv->row_spacing);
-      break;
-    case PROP_MIN_CHILDREN_PER_LINE:
-      g_value_set_uint (value, priv->min_children_per_line);
-      break;
-    case PROP_MAX_CHILDREN_PER_LINE:
-      g_value_set_uint (value, priv->max_children_per_line);
-      break;
-    case PROP_SELECTION_MODE:
-      g_value_set_enum (value, priv->selection_mode);
-      break;
-    case PROP_ACTIVATE_ON_SINGLE_CLICK:
-      g_value_set_boolean (value, priv->activate_on_single_click);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
+          if (g_sequence_iter_compare (iter, iter2) == 0)
+            break;
+        }
 
-static void
-egg_flow_box_set_property (GObject      *object,
-                           guint         prop_id,
-                           const GValue *value,
-                           GParamSpec   *pspec)
-{
-  EggFlowBox *box = EGG_FLOW_BOX (object);
-  EggFlowBoxPrivate *priv = BOX_PRIV (box);
+      if (line_rect.width != 0)
+        g_array_append_val (lines, line_rect);
 
-  switch (prop_id)
-    {
-    case PROP_ORIENTATION:
-      priv->orientation = g_value_get_enum (value);
-      /* Re-box the children in the new orientation */
-      gtk_widget_queue_resize (GTK_WIDGET (box));
-      break;
-    case PROP_HOMOGENEOUS:
-      egg_flow_box_set_homogeneous (box, g_value_get_boolean (value));
-      break;
-    case PROP_COLUMN_SPACING:
-      egg_flow_box_set_column_spacing (box, g_value_get_uint (value));
-      break;
-    case PROP_ROW_SPACING:
-      egg_flow_box_set_row_spacing (box, g_value_get_uint (value));
-      break;
-    case PROP_MIN_CHILDREN_PER_LINE:
-      egg_flow_box_set_min_children_per_line (box, g_value_get_uint (value));
-      break;
-    case PROP_MAX_CHILDREN_PER_LINE:
-      egg_flow_box_set_max_children_per_line (box, g_value_get_uint (value));
-      break;
-    case PROP_SELECTION_MODE:
-      egg_flow_box_set_selection_mode (box, g_value_get_enum (value));
-      break;
-    case PROP_ACTIVATE_ON_SINGLE_CLICK:
-      egg_flow_box_set_activate_on_single_click (box, g_value_get_boolean (value));
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
+      if (lines->len > 0)
+        {
+          GtkStateFlags state;
+          cairo_path_t *path;
+          GtkBorder border;
+          GdkRGBA border_color;
 
-static EggFlowBoxChild *
-egg_flow_box_find_child_at_pos (EggFlowBox *box,
-                                gint        x,
-                                gint        y)
-{
-  GtkWidget *child;
-  GSequenceIter *iter;
-  GtkAllocation allocation;
+          if (vertical)
+            path_from_vertical_line_rects (cr, (GdkRectangle *)lines->data, lines->len);
+          else
+            path_from_horizontal_line_rects (cr, (GdkRectangle *)lines->data, lines->len);
 
-  for (iter = g_sequence_get_begin_iter (BOX_PRIV (box)->children);
-       !g_sequence_iter_is_end (iter);
-       iter = g_sequence_iter_next (iter))
-    {
-      child = g_sequence_get (iter);
-      if (!child_is_visible (child))
-        continue;
-      gtk_widget_get_allocation (child, &allocation);
-      if (x >= allocation.x && x < (allocation.x + allocation.width) &&
-          y >= allocation.y && y < (allocation.y + allocation.height))
-        return EGG_FLOW_BOX_CHILD (child);
-    }
+          /* For some reason we need to copy and reapply the path,
+           * or it gets eaten by gtk_render_background()
+           */
+          path = cairo_copy_path (cr);
 
-  return NULL;
-}
+          cairo_save (cr);
+          cairo_clip (cr);
+          gtk_widget_get_allocation (widget, &allocation);
+          gtk_render_background (context, cr,
+                                 0, 0,
+                                 allocation.width, allocation.height);
+          cairo_restore (cr);
 
-static void
-egg_flow_box_update_prelight (EggFlowBox      *box,
-                              EggFlowBoxChild *child)
-{
-  EggFlowBoxPrivate *priv = BOX_PRIV (box);
+          cairo_append_path (cr, path);
+          cairo_path_destroy (path);
 
-  if (child != priv->prelight_child)
-    {
-      priv->prelight_child = child;
-      gtk_widget_queue_draw (GTK_WIDGET (box));
-    }
-}
+          state = gtk_widget_get_state_flags (widget);
+          gtk_style_context_get_border_color (context, state, &border_color);
+          gtk_style_context_get_border (context, state, &border);
 
-static void
-egg_flow_box_update_active (EggFlowBox      *box,
-                            EggFlowBoxChild *child)
-{
-  EggFlowBoxPrivate *priv = BOX_PRIV (box);
-  gboolean val;
+          cairo_set_line_width (cr, border.left);
+          gdk_cairo_set_source_rgba (cr, &border_color);
+          cairo_stroke (cr);
+        }
+      g_array_free (lines, TRUE);
 
-  val = priv->active_child == child;
-  if (priv->active_child != NULL &&
-      val != priv->active_child_active)
-    {
-      priv->active_child_active = val;
-      gtk_widget_queue_draw (GTK_WIDGET (box));
+      gtk_style_context_restore (context);
+      cairo_restore (cr);
     }
-}
-
-static gboolean
-egg_flow_box_enter_notify_event (GtkWidget        *widget,
-                                 GdkEventCrossing *event)
-{
-  EggFlowBox *box = EGG_FLOW_BOX (widget);
-  EggFlowBoxChild *child;
-
-  if (event->window != gtk_widget_get_window (GTK_WIDGET (box)))
-    return FALSE;
 
-  child = egg_flow_box_find_child_at_pos (box, event->x, event->y);
-  egg_flow_box_update_prelight (box, child);
-  egg_flow_box_update_active (box, child);
-
-  return FALSE;
+  return TRUE;
 }
 
-static gboolean
-egg_flow_box_leave_notify_event (GtkWidget        *widget,
-                                 GdkEventCrossing *event)
-{
-  EggFlowBox *box = EGG_FLOW_BOX (widget);
-  EggFlowBoxChild *child = NULL;
-
-  if (event->window != gtk_widget_get_window (GTK_WIDGET (box)))
-    return FALSE;
-
-  if (event->detail != GDK_NOTIFY_INFERIOR)
-    child = NULL;
-  else
-    child = egg_flow_box_find_child_at_pos (box, event->x, event->y);
-
-  egg_flow_box_update_prelight (box, child);
-  egg_flow_box_update_active (box, child);
-
-  return FALSE;
-}
+/* Autoscrolling {{{3 */
 
 static void
 remove_autoscroll (EggFlowBox *box)
@@ -2680,6 +2751,46 @@ update_autoscroll_mode (EggFlowBox *box,
     }
 }
 
+/* Event handling {{{3 */
+
+static gboolean
+egg_flow_box_enter_notify_event (GtkWidget        *widget,
+                                 GdkEventCrossing *event)
+{
+  EggFlowBox *box = EGG_FLOW_BOX (widget);
+  EggFlowBoxChild *child;
+
+  if (event->window != gtk_widget_get_window (GTK_WIDGET (box)))
+    return FALSE;
+
+  child = egg_flow_box_find_child_at_pos (box, event->x, event->y);
+  egg_flow_box_update_prelight (box, child);
+  egg_flow_box_update_active (box, child);
+
+  return FALSE;
+}
+
+static gboolean
+egg_flow_box_leave_notify_event (GtkWidget        *widget,
+                                 GdkEventCrossing *event)
+{
+  EggFlowBox *box = EGG_FLOW_BOX (widget);
+  EggFlowBoxChild *child = NULL;
+
+  if (event->window != gtk_widget_get_window (GTK_WIDGET (box)))
+    return FALSE;
+
+  if (event->detail != GDK_NOTIFY_INFERIOR)
+    child = NULL;
+  else
+    child = egg_flow_box_find_child_at_pos (box, event->x, event->y);
+
+  egg_flow_box_update_prelight (box, child);
+  egg_flow_box_update_active (box, child);
+
+  return FALSE;
+}
+
 static gboolean
 egg_flow_box_motion_notify_event (GtkWidget      *widget,
                                   GdkEventMotion *event)
@@ -2777,202 +2888,6 @@ egg_flow_box_button_press_event (GtkWidget      *widget,
 }
 
 static gboolean
-egg_flow_box_child_set_selected (EggFlowBoxChild *child,
-                                 gboolean         selected)
-{
-  EggFlowBox *box;
-
-  if (CHILD_PRIV (child)->selected != selected)
-    {
-      CHILD_PRIV (child)->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);
-
-      box = egg_flow_box_child_get_box (child);
-      _egg_flow_box_accessible_selection_changed (GTK_WIDGET (box));
-
-      gtk_widget_queue_draw (GTK_WIDGET (child));
-
-      return TRUE;
-    }
-
-  return FALSE;
-}
-
-static gboolean
-egg_flow_box_unselect_all_internal (EggFlowBox *box)
-{
-  EggFlowBoxChild *child;
-  GSequenceIter *iter;
-  gboolean dirty = FALSE;
-
-  if (BOX_PRIV (box)->selection_mode == GTK_SELECTION_NONE)
-    return FALSE;
-
-  for (iter = g_sequence_get_begin_iter (BOX_PRIV (box)->children);
-       !g_sequence_iter_is_end (iter);
-       iter = g_sequence_iter_next (iter))
-    {
-      child = g_sequence_get (iter);
-      dirty |= egg_flow_box_child_set_selected (child, FALSE);
-    }
-
-  return dirty;
-}
-
-static void
-egg_flow_box_unselect_child_info (EggFlowBox      *box,
-                                  EggFlowBoxChild *child)
-{
-  if (!CHILD_PRIV (child)->selected)
-    return;
-
-  if (BOX_PRIV (box)->selection_mode == GTK_SELECTION_NONE)
-    return;
-  else if (BOX_PRIV (box)->selection_mode != GTK_SELECTION_MULTIPLE)
-    egg_flow_box_unselect_all_internal (box);
-  else
-    egg_flow_box_child_set_selected (child, FALSE);
-
-  g_signal_emit (box, signals[SELECTED_CHILDREN_CHANGED], 0);
-}
-
-static void
-egg_flow_box_update_cursor (EggFlowBox      *box,
-                            EggFlowBoxChild *child)
-{
-  BOX_PRIV (box)->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,
-                                EggFlowBoxChild *child)
-{
-  if (CHILD_PRIV (child)->selected)
-    return;
-
-  if (BOX_PRIV (box)->selection_mode == GTK_SELECTION_NONE)
-    return;
-  if (BOX_PRIV (box)->selection_mode != GTK_SELECTION_MULTIPLE)
-    egg_flow_box_unselect_all_internal (box);
-
-  egg_flow_box_child_set_selected (child, TRUE);
-  BOX_PRIV (box)->selected_child = child;
-
-  g_signal_emit (box, signals[SELECTED_CHILDREN_CHANGED], 0);
-
-  egg_flow_box_update_cursor (box, child);
-}
-
-static void
-egg_flow_box_select_all_between (EggFlowBox      *box,
-                                 EggFlowBoxChild *child1,
-                                 EggFlowBoxChild *child2)
-{
-  GSequenceIter *iter, *iter1, *iter2;
-
-  if (child1)
-    iter1 = CHILD_PRIV (child1)->iter;
-  else
-    iter1 = g_sequence_get_begin_iter (BOX_PRIV (box)->children);
-
-  if (child2)
-    iter2 = CHILD_PRIV (child2)->iter;
-  else
-    iter2 = g_sequence_get_end_iter (BOX_PRIV (box)->children);
-
-  if (g_sequence_iter_compare (iter2, iter1) < 0)
-    {
-      iter = iter1;
-      iter1 = iter2;
-      iter2 = iter;
-    }
-
-  for (iter = iter1;
-       !g_sequence_iter_is_end (iter);
-       iter = g_sequence_iter_next (iter))
-    {
-      GtkWidget *child;
-
-      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;
-    }
-}
-
-static void
-egg_flow_box_update_selection (EggFlowBox      *box,
-                               EggFlowBoxChild *child,
-                               gboolean         modify,
-                               gboolean         extend)
-{
-  EggFlowBoxPrivate *priv = BOX_PRIV (box);
-
-  egg_flow_box_update_cursor (box, child);
-
-  if (priv->selection_mode == GTK_SELECTION_NONE)
-    return;
-
-  if (priv->selection_mode == GTK_SELECTION_BROWSE)
-    {
-      egg_flow_box_unselect_all_internal (box);
-      egg_flow_box_child_set_selected (child, TRUE);
-      priv->selected_child = child;
-    }
-  else if (priv->selection_mode == GTK_SELECTION_SINGLE)
-    {
-      gboolean was_selected;
-
-      was_selected = CHILD_PRIV (child)->selected;
-      egg_flow_box_unselect_all_internal (box);
-      egg_flow_box_child_set_selected (child, modify ? !was_selected : TRUE);
-      priv->selected_child = CHILD_PRIV (child)->selected ? child : NULL;
-    }
-  else /* GTK_SELECTION_MULTIPLE */
-    {
-      if (extend)
-        {
-          egg_flow_box_unselect_all_internal (box);
-          if (priv->selected_child == NULL)
-            {
-              egg_flow_box_child_set_selected (child, TRUE);
-              priv->selected_child = child;
-            }
-          else
-            egg_flow_box_select_all_between (box, priv->selected_child, child);
-        }
-      else
-        {
-          egg_flow_box_child_set_selected (child, modify ? !CHILD_PRIV (child)->selected : TRUE);
-          priv->selected_child = child;
-        }
-    }
-
-  g_signal_emit (box, signals[SELECTED_CHILDREN_CHANGED], 0);
-}
-
-static void
-egg_flow_box_select_and_activate (EggFlowBox      *box,
-                                  EggFlowBoxChild *child)
-{
-  if (child != NULL)
-    {
-      egg_flow_box_select_child_info (box, child);
-      g_signal_emit (box, signals[CHILD_ACTIVATED], 0, child);
-    }
-}
-
-static gboolean
 egg_flow_box_button_release_event (GtkWidget      *widget,
                                    GdkEventButton *event)
 {
@@ -3012,121 +2927,127 @@ egg_flow_box_button_release_event (GtkWidget      *widget,
   return FALSE;
 }
 
-static GSequenceIter *
-egg_flow_box_get_previous_focusable (EggFlowBox    *box,
-                                     GSequenceIter *iter)
-{
-  EggFlowBoxChild *child;
-
-  while (!g_sequence_iter_is_begin (iter))
-    {
-      iter = g_sequence_iter_prev (iter);
-      child = g_sequence_get (iter);
-      if (child_is_visible (GTK_WIDGET (child)) &&
-          gtk_widget_is_sensitive (GTK_WIDGET (child)))
-        return iter;
-    }
-
-  return NULL;
-}
+/* Realize and map {{{3 */
 
-static GSequenceIter *
-egg_flow_box_get_next_focusable (EggFlowBox    *box,
-                                 GSequenceIter *iter)
+static void
+egg_flow_box_realize (GtkWidget *widget)
 {
-  EggFlowBoxChild *child;
+  EggFlowBox *box = EGG_FLOW_BOX (widget);
+  GtkAllocation allocation;
+  GdkWindowAttr attributes = {0};
+  GdkWindow *window;
 
-  while (TRUE)
-    {
-      iter = g_sequence_iter_next (iter);
-      if (g_sequence_iter_is_end (iter))
-        return iter;
-      child = g_sequence_get (iter);
-      if (child_is_visible (GTK_WIDGET (child)) &&
-          gtk_widget_is_sensitive (GTK_WIDGET (child)))
-        return iter;
-    }
+  gtk_widget_get_allocation (GTK_WIDGET (box), &allocation);
+  gtk_widget_set_realized (GTK_WIDGET (box), TRUE);
 
-  return NULL;
+  attributes.x = allocation.x;
+  attributes.y = allocation.y;
+  attributes.width = allocation.width;
+  attributes.height = allocation.height;
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.event_mask = gtk_widget_get_events (GTK_WIDGET (box))
+                                | GDK_ENTER_NOTIFY_MASK
+                                | GDK_LEAVE_NOTIFY_MASK
+                                | GDK_POINTER_MOTION_MASK
+                                | GDK_EXPOSURE_MASK
+                                | GDK_BUTTON_PRESS_MASK
+                                | GDK_BUTTON_RELEASE_MASK;
+  attributes.wclass = GDK_INPUT_OUTPUT;
+
+  window = gdk_window_new (gtk_widget_get_parent_window (GTK_WIDGET (box)),
+                           &attributes, GDK_WA_X | GDK_WA_Y);
+  gtk_style_context_set_background (gtk_widget_get_style_context (GTK_WIDGET (box)), window);
+  gtk_widget_register_window (GTK_WIDGET (box), window);
+  gtk_widget_set_window (GTK_WIDGET (box), window);
 }
 
-static GSequenceIter *
-egg_flow_box_get_first_focusable (EggFlowBox *box)
+static void
+egg_flow_box_unmap (GtkWidget *widget)
 {
-  GSequenceIter *iter;
-  EggFlowBoxChild *child;
+  EggFlowBox *box = EGG_FLOW_BOX (widget);
 
-  iter = g_sequence_get_begin_iter (BOX_PRIV (box)->children);
-  child = g_sequence_get (iter);
-  if (child_is_visible (GTK_WIDGET (child)) &&
-      gtk_widget_is_sensitive (GTK_WIDGET (child)))
-    return iter;
+  remove_autoscroll (box);
 
-  return egg_flow_box_get_next_focusable (box, iter);
+  GTK_WIDGET_CLASS (egg_flow_box_parent_class)->unmap (widget);
 }
 
-static GSequenceIter *
-egg_flow_box_get_last_focusable (EggFlowBox *box)
-{
-  GSequenceIter *iter;
+/* GtkContainer implementation {{{2 */
 
-  iter = g_sequence_get_end_iter (BOX_PRIV (box)->children);
-  return egg_flow_box_get_previous_focusable (box, iter);
+static void
+egg_flow_box_add (GtkContainer *container,
+                  GtkWidget    *child)
+{
+  egg_flow_box_insert (EGG_FLOW_BOX (container), child, -1);
 }
 
-
-static GSequenceIter *
-egg_flow_box_get_above_focusable (EggFlowBox    *box,
-                                  GSequenceIter *iter)
+static void
+egg_flow_box_remove (GtkContainer *container,
+                     GtkWidget    *widget)
 {
-  EggFlowBoxChild *child = NULL;
-  gint i;
+  EggFlowBox *box = EGG_FLOW_BOX (container);
+  EggFlowBoxPrivate *priv = BOX_PRIV (box);
+  gboolean was_visible;
+  gboolean was_selected;
+  EggFlowBoxChild *child;
 
-  while (TRUE)
+  if (EGG_IS_FLOW_BOX_CHILD (widget))
+    child = EGG_FLOW_BOX_CHILD (widget);
+  else
     {
-      i = 0;
-      while (i < BOX_PRIV (box)->cur_children_per_line)
+      child = (EggFlowBoxChild*)gtk_widget_get_parent (widget);
+      if (!EGG_IS_FLOW_BOX_CHILD (child))
         {
-          if (g_sequence_iter_is_begin (iter))
-            return NULL;
-          iter = g_sequence_iter_prev (iter);
-          child = g_sequence_get (iter);
-          if (child_is_visible (GTK_WIDGET (child)))
-            i++;
+          g_warning ("Tried to remove non-child %p\n", widget);
+          return;
         }
-      if (child && gtk_widget_get_sensitive (GTK_WIDGET (child)))
-        return iter;
     }
 
-  return NULL;
+  was_visible = child_is_visible (GTK_WIDGET (child));
+  was_selected = CHILD_PRIV (child)->selected;
+
+  if (child == priv->prelight_child)
+    priv->prelight_child = NULL;
+  if (child == priv->active_child)
+    priv->active_child = NULL;
+  if (child == priv->selected_child)
+    priv->selected_child = NULL;
+
+  gtk_widget_unparent (GTK_WIDGET (child));
+  g_sequence_remove (CHILD_PRIV (child)->iter);
+
+  if (was_visible && gtk_widget_get_visible (GTK_WIDGET (box)))
+    gtk_widget_queue_resize (GTK_WIDGET (box));
+
+  if (was_selected)
+    g_signal_emit (box, signals[SELECTED_CHILDREN_CHANGED], 0);
 }
 
-static GSequenceIter *
-egg_flow_box_get_below_focusable (EggFlowBox    *box,
-                                  GSequenceIter *iter)
+static void
+egg_flow_box_forall (GtkContainer *container,
+                     gboolean      include_internals,
+                     GtkCallback   callback,
+                     gpointer      callback_target)
 {
-  EggFlowBoxChild *child;
-  gint i;
+  GSequenceIter *iter;
+  GtkWidget *child;
 
-  while (TRUE)
+  iter = g_sequence_get_begin_iter (BOX_PRIV (container)->children);
+  while (!g_sequence_iter_is_end (iter))
     {
-      i = 0;
-      while (i < BOX_PRIV (box)->cur_children_per_line)
-        {
-          iter = g_sequence_iter_next (iter);
-          if (g_sequence_iter_is_end (iter))
-            return iter;
-          child = g_sequence_get (iter);
-          if (child_is_visible (GTK_WIDGET (child)))
-            i++;
-        }
-      if (child && gtk_widget_get_sensitive (GTK_WIDGET (child)))
-        return iter;
+      child = g_sequence_get (iter);
+      iter = g_sequence_iter_next (iter);
+      callback (child, callback_target);
     }
+}
 
-  return NULL;
+static GType
+egg_flow_box_child_type (GtkContainer *container)
+{
+  return EGG_TYPE_FLOW_BOX_CHILD;
 }
 
+/* Keynav {{{2 */
+
 static gboolean
 egg_flow_box_focus (GtkWidget        *widget,
                     GtkDirectionType  direction)
@@ -3441,279 +3362,98 @@ egg_flow_box_move_cursor (EggFlowBox      *box,
   egg_flow_box_update_selection (box, child, modify_selection, extend_selection);
 }
 
+/* Selection {{{2 */
+
 static void
-path_from_horizontal_line_rects (cairo_t      *cr,
-                                 GdkRectangle *lines,
-                                 gint          n_lines)
+egg_flow_box_selected_children_changed (EggFlowBox *box)
 {
-  gint start_line, end_line;
-  GdkRectangle *r;
-  gint i;
-
-  /* Join rows vertically by extending to the middle */
-  for (i = 0; i < n_lines - 1; i++)
-    {
-      GdkRectangle *r1 = &lines[i];
-      GdkRectangle *r2 = &lines[i+1];
-      gint gap, old;
-
-      gap = r2->y - (r1->y + r1->height);
-      r1->height += gap / 2;
-      old = r2->y;
-      r2->y = r1->y + r1->height;
-      r2->height += old - r2->y;
-    }
-
-  cairo_new_path (cr);
-  start_line = 0;
-
-  do
-    {
-      for (i = start_line; i < n_lines; i++)
-        {
-          r = &lines[i];
-          if (i == start_line)
-            cairo_move_to (cr, r->x + r->width, r->y);
-          else
-            cairo_line_to (cr, r->x + r->width, r->y);
-          cairo_line_to (cr, r->x + r->width, r->y + r->height);
-
-          if (i < n_lines - 1 &&
-              (r->x + r->width < lines[i+1].x ||
-              r->x > lines[i+1].x + lines[i+1].width))
-            {
-              i++;
-              break;
-            }
-        }
-      end_line = i;
-      for (i = end_line - 1; i >= start_line; i--)
-        {
-          r = &lines[i];
-          cairo_line_to (cr, r->x, r->y + r->height);
-          cairo_line_to (cr, r->x, r->y);
-        }
-      cairo_close_path (cr);
-      start_line = end_line;
-    }
-  while (end_line < n_lines);
+  _egg_flow_box_accessible_selection_changed (GTK_WIDGET (box));
 }
 
+/* GObject implementation {{{2 */
+
 static void
-path_from_vertical_line_rects (cairo_t      *cr,
-                               GdkRectangle *lines,
-                               gint          n_lines)
+egg_flow_box_get_property (GObject    *object,
+                           guint       prop_id,
+                           GValue     *value,
+                           GParamSpec *pspec)
 {
-  gint start_line, end_line;
-  GdkRectangle *r;
-  gint i;
-
-  /* Join rows horizontall by extending to the middle */
-  for (i = 0; i < n_lines - 1; i++)
-    {
-      GdkRectangle *r1 = &lines[i];
-      GdkRectangle *r2 = &lines[i+1];
-      gint gap, old;
-
-      gap = r2->x - (r1->x + r1->width);
-      r1->width += gap / 2;
-      old = r2->x;
-      r2->x = r1->x + r1->width;
-      r2->width += old - r2->x;
-    }
-
-  cairo_new_path (cr);
-  start_line = 0;
+  EggFlowBox *box = EGG_FLOW_BOX (object);
+  EggFlowBoxPrivate *priv = BOX_PRIV (box);
 
-  do
+  switch (prop_id)
     {
-      for (i = start_line; i < n_lines; i++)
-        {
-          r = &lines[i];
-          if (i == start_line)
-            cairo_move_to (cr, r->x, r->y + r->height);
-          else
-            cairo_line_to (cr, r->x, r->y + r->height);
-          cairo_line_to (cr, r->x + r->width, r->y + r->height);
-
-          if (i < n_lines - 1 &&
-              (r->y + r->height < lines[i+1].y ||
-              r->y > lines[i+1].y + lines[i+1].height))
-            {
-              i++;
-              break;
-            }
-        }
-      end_line = i;
-      for (i = end_line - 1; i >= start_line; i--)
-        {
-          r = &lines[i];
-          cairo_line_to (cr, r->x + r->width, r->y);
-          cairo_line_to (cr, r->x, r->y);
-        }
-      cairo_close_path (cr);
-      start_line = end_line;
+    case PROP_ORIENTATION:
+      g_value_set_enum (value, priv->orientation);
+      break;
+    case PROP_HOMOGENEOUS:
+      g_value_set_boolean (value, priv->homogeneous);
+      break;
+    case PROP_COLUMN_SPACING:
+      g_value_set_uint (value, priv->column_spacing);
+      break;
+    case PROP_ROW_SPACING:
+      g_value_set_uint (value, priv->row_spacing);
+      break;
+    case PROP_MIN_CHILDREN_PER_LINE:
+      g_value_set_uint (value, priv->min_children_per_line);
+      break;
+    case PROP_MAX_CHILDREN_PER_LINE:
+      g_value_set_uint (value, priv->max_children_per_line);
+      break;
+    case PROP_SELECTION_MODE:
+      g_value_set_enum (value, priv->selection_mode);
+      break;
+    case PROP_ACTIVATE_ON_SINGLE_CLICK:
+      g_value_set_boolean (value, priv->activate_on_single_click);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
     }
-  while (end_line < n_lines);
 }
 
-static gboolean
-egg_flow_box_draw (GtkWidget *widget,
-                   cairo_t   *cr)
+static void
+egg_flow_box_set_property (GObject      *object,
+                           guint         prop_id,
+                           const GValue *value,
+                           GParamSpec   *pspec)
 {
-  EggFlowBox *box = EGG_FLOW_BOX (widget);
+  EggFlowBox *box = EGG_FLOW_BOX (object);
   EggFlowBoxPrivate *priv = BOX_PRIV (box);
-  GtkAllocation allocation = { 0, };
-  GtkStyleContext* context;
-
-  gtk_widget_get_allocation (GTK_WIDGET (box), &allocation);
-  context = gtk_widget_get_style_context (GTK_WIDGET (box));
-  gtk_render_background (context, cr, 0, 0, allocation.width, allocation.height);
-
-  GTK_WIDGET_CLASS (egg_flow_box_parent_class)->draw (widget, cr);
 
-  if (priv->rubberband_first && priv->rubberband_last)
+  switch (prop_id)
     {
-      GSequenceIter *iter, *iter1, *iter2;
-      GdkRectangle line_rect, rect;
-      GArray *lines;
-      gboolean vertical;
-
-      vertical = priv->orientation == GTK_ORIENTATION_VERTICAL;
-
-      cairo_save (cr);
-
-      context = gtk_widget_get_style_context (widget);
-      gtk_style_context_save (context);
-      gtk_style_context_add_class (context, GTK_STYLE_CLASS_RUBBERBAND);
-
-      iter1 = CHILD_PRIV (priv->rubberband_first)->iter;
-      iter2 = CHILD_PRIV (priv->rubberband_last)->iter;
-
-      if (g_sequence_iter_compare (iter2, iter1) < 0)
-        {
-          iter = iter1;
-          iter1 = iter2;
-          iter2 = iter;
-        }
-
-      line_rect.width = 0;
-      lines = g_array_new (FALSE, FALSE, sizeof (GdkRectangle));
-
-      for (iter = iter1;
-           !g_sequence_iter_is_end (iter);
-           iter = g_sequence_iter_next (iter))
-        {
-          GtkWidget *child;
-
-          child = g_sequence_get (iter);
-          gtk_widget_get_allocation (GTK_WIDGET (child), &rect);
-          if (line_rect.width == 0)
-            line_rect = rect;
-          else
-            {
-              if ((vertical && rect.x == line_rect.x) ||
-                  (!vertical && rect.y == line_rect.y))
-                gdk_rectangle_union (&rect, &line_rect, &line_rect);
-              else
-                {
-                  g_array_append_val (lines, line_rect);
-                  line_rect = rect;
-                }
-            }
-
-          if (g_sequence_iter_compare (iter, iter2) == 0)
-            break;
-        }
-
-      if (line_rect.width != 0)
-        g_array_append_val (lines, line_rect);
-
-      if (lines->len > 0)
-        {
-          GtkStateFlags state;
-          cairo_path_t *path;
-          GtkBorder border;
-          GdkRGBA border_color;
-
-          if (vertical)
-            path_from_vertical_line_rects (cr, (GdkRectangle *)lines->data, lines->len);
-          else
-            path_from_horizontal_line_rects (cr, (GdkRectangle *)lines->data, lines->len);
-
-          /* For some reason we need to copy and reapply the path,
-           * or it gets eaten by gtk_render_background()
-           */
-          path = cairo_copy_path (cr);
-
-          cairo_save (cr);
-          cairo_clip (cr);
-          gtk_widget_get_allocation (widget, &allocation);
-          gtk_render_background (context, cr,
-                                 0, 0,
-                                 allocation.width, allocation.height);
-          cairo_restore (cr);
-
-          cairo_append_path (cr, path);
-          cairo_path_destroy (path);
-
-          state = gtk_widget_get_state_flags (widget);
-          gtk_style_context_get_border_color (context, state, &border_color);
-          gtk_style_context_get_border (context, state, &border);
-
-          cairo_set_line_width (cr, border.left);
-          gdk_cairo_set_source_rgba (cr, &border_color);
-          cairo_stroke (cr);
-        }
-      g_array_free (lines, TRUE);
-
-      gtk_style_context_restore (context);
-      cairo_restore (cr);
+    case PROP_ORIENTATION:
+      priv->orientation = g_value_get_enum (value);
+      /* Re-box the children in the new orientation */
+      gtk_widget_queue_resize (GTK_WIDGET (box));
+      break;
+    case PROP_HOMOGENEOUS:
+      egg_flow_box_set_homogeneous (box, g_value_get_boolean (value));
+      break;
+    case PROP_COLUMN_SPACING:
+      egg_flow_box_set_column_spacing (box, g_value_get_uint (value));
+      break;
+    case PROP_ROW_SPACING:
+      egg_flow_box_set_row_spacing (box, g_value_get_uint (value));
+      break;
+    case PROP_MIN_CHILDREN_PER_LINE:
+      egg_flow_box_set_min_children_per_line (box, g_value_get_uint (value));
+      break;
+    case PROP_MAX_CHILDREN_PER_LINE:
+      egg_flow_box_set_max_children_per_line (box, g_value_get_uint (value));
+      break;
+    case PROP_SELECTION_MODE:
+      egg_flow_box_set_selection_mode (box, g_value_get_enum (value));
+      break;
+    case PROP_ACTIVATE_ON_SINGLE_CLICK:
+      egg_flow_box_set_activate_on_single_click (box, g_value_get_boolean (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
     }
-
-  return TRUE;
-}
-
-static void
-egg_flow_box_realize (GtkWidget *widget)
-{
-  EggFlowBox *box = EGG_FLOW_BOX (widget);
-  GtkAllocation allocation;
-  GdkWindowAttr attributes = {0};
-  GdkWindow *window;
-
-  gtk_widget_get_allocation (GTK_WIDGET (box), &allocation);
-  gtk_widget_set_realized (GTK_WIDGET (box), TRUE);
-
-  attributes.x = allocation.x;
-  attributes.y = allocation.y;
-  attributes.width = allocation.width;
-  attributes.height = allocation.height;
-  attributes.window_type = GDK_WINDOW_CHILD;
-  attributes.event_mask = gtk_widget_get_events (GTK_WIDGET (box))
-                                | GDK_ENTER_NOTIFY_MASK
-                                | GDK_LEAVE_NOTIFY_MASK
-                                | GDK_POINTER_MOTION_MASK
-                                | GDK_EXPOSURE_MASK
-                                | GDK_BUTTON_PRESS_MASK
-                                | GDK_BUTTON_RELEASE_MASK;
-  attributes.wclass = GDK_INPUT_OUTPUT;
-
-  window = gdk_window_new (gtk_widget_get_parent_window (GTK_WIDGET (box)),
-                           &attributes, GDK_WA_X | GDK_WA_Y);
-  gtk_style_context_set_background (gtk_widget_get_style_context (GTK_WIDGET (box)), window);
-  gtk_widget_register_window (GTK_WIDGET (box), window);
-  gtk_widget_set_window (GTK_WIDGET (box), window);
-}
-
-static void
-egg_flow_box_unmap (GtkWidget *widget)
-{
-  EggFlowBox *box = EGG_FLOW_BOX (widget);
-
-  remove_autoscroll (box);
-
-  GTK_WIDGET_CLASS (egg_flow_box_parent_class)->unmap (widget);
 }
 
 static void
@@ -3734,12 +3474,6 @@ egg_flow_box_finalize (GObject *obj)
 }
 
 static void
-egg_flow_box_selected_children_changed (EggFlowBox *box)
-{
-  _egg_flow_box_accessible_selection_changed (GTK_WIDGET (box));
-}
-
-static void
 egg_flow_box_class_init (EggFlowBoxClass *class)
 {
   GObjectClass      *object_class = G_OBJECT_CLASS (class);
@@ -3998,6 +3732,8 @@ egg_flow_box_init (EggFlowBox *box)
 
   priv->children = g_sequence_new (NULL);
 }
+ 
+/* Public API {{{1 */
 
 /**
  * egg_flow_box_new:
@@ -4013,6 +3749,403 @@ egg_flow_box_new (void)
 }
 
 /**
+ * egg_flow_box_insert:
+ * @box: a #EggFlowBox
+ * @widget: the #GtkWidget to add
+ * @position: the position to insert @child in
+ *
+ * Inserts the @child into @box at @position.
+ *
+ * If a sort function is set, the widget will actually be inserted
+ * at the calculated position and this function has the same effect
+ * as gtk_container_add().
+ *
+ * If @position is -1, or larger than the total number of children
+ * in the @box, then the @child will be appended to the end.
+ */
+void
+egg_flow_box_insert (EggFlowBox *box,
+                     GtkWidget  *widget,
+                     gint        position)
+{
+  EggFlowBoxPrivate *priv;
+  EggFlowBoxChild *child;
+  GSequenceIter *iter;
+
+  g_return_if_fail (EGG_IS_FLOW_BOX (box));
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+
+  priv = BOX_PRIV (box);
+
+  if (EGG_IS_FLOW_BOX_CHILD (widget))
+    child = EGG_FLOW_BOX_CHILD (widget);
+  else
+    {
+      child = EGG_FLOW_BOX_CHILD (egg_flow_box_child_new ());
+      gtk_widget_show (GTK_WIDGET (child));
+      gtk_container_add (GTK_CONTAINER (child), widget);
+    }
+
+  if (priv->sort_func != NULL)
+    iter = g_sequence_insert_sorted (priv->children, child,
+                                     (GCompareDataFunc)egg_flow_box_sort, box);
+  else if (position == 0)
+    iter = g_sequence_prepend (priv->children, child);
+  else if (position == -1)
+    iter = g_sequence_append (priv->children, child);
+  else
+    {
+      GSequenceIter *pos;
+      pos = g_sequence_get_iter_at_pos (priv->children, position);
+      iter = g_sequence_insert_before (pos, child);
+    }
+
+  CHILD_PRIV (child)->iter = iter;
+  gtk_widget_set_parent (GTK_WIDGET (child), GTK_WIDGET (box));
+  egg_flow_box_apply_filter (box, child);
+}
+
+/**
+ * egg_flow_box_get_child_at_index:
+ * @box: a #EggFlowBox
+ * @idx: the position of the child
+ *
+ * Gets the nth child in the @box.
+ *
+ * Returns: (transfer none): the child #GtkWidget
+ */
+EggFlowBoxChild *
+egg_flow_box_get_child_at_index (EggFlowBox *box,
+                                 gint        idx)
+{
+  GSequenceIter *iter;
+
+  g_return_val_if_fail (EGG_IS_FLOW_BOX (box), NULL);
+
+  iter = g_sequence_get_iter_at_pos (BOX_PRIV (box)->children, idx);
+  if (iter)
+    return g_sequence_get (iter);
+
+  return NULL;
+}
+
+/**
+ * egg_flow_box_set_hadjustment:
+ * @box: a #EggFlowBox
+ * @adjustment: an adjustment which should be adjusted
+ *    when the focus is moved among the descendents of @container
+ *
+ * Hooks up an adjustment to focus handling in @box. The
+ * adjustment is also used for autoscrolling during
+ * rubberband selection. See gtk_scrolled_window_get_hadjustment()
+ * for a typical way of obtaining the adjustment, and
+ * egg_flow_box_set_vadjustment()for setting the vertical
+ * adjustment.
+ *
+ * The adjustments have to be in pixel units and in the same
+ * coordinate system as the allocation for immediate children
+ * of the box.
+ */
+void
+egg_flow_box_set_hadjustment (EggFlowBox    *box,
+                              GtkAdjustment *adjustment)
+{
+  EggFlowBoxPrivate *priv;
+
+  g_return_if_fail (EGG_IS_FLOW_BOX (box));
+  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+
+  priv = BOX_PRIV (box);
+
+  g_object_ref (adjustment);
+  if (priv->hadjustment)
+    g_object_unref (priv->hadjustment);
+  priv->hadjustment = adjustment;
+  gtk_container_set_focus_hadjustment (GTK_CONTAINER (box), adjustment);
+}
+
+/**
+ * egg_flow_box_set_vadjustment:
+ * @box: a #EggFlowBox
+ * @adjustment: an adjustment which should be adjusted
+ *    when the focus is moved among the descendents of @container
+ *
+ * Hooks up an adjustment to focus handling in @box. The
+ * adjustment is also used for autoscrolling during
+ * rubberband selection. See gtk_scrolled_window_get_vadjustment()
+ * for a typical way of obtaining the adjustment, and
+ * egg_flow_box_set_hadjustment()for setting the horizontal.
+ * adjustment.
+ *
+ * The adjustments have to be in pixel units and in the same
+ * coordinate system as the allocation for immediate children
+ * of the box.
+ */
+void
+egg_flow_box_set_vadjustment (EggFlowBox    *box,
+                              GtkAdjustment *adjustment)
+{
+  EggFlowBoxPrivate *priv;
+
+  g_return_if_fail (EGG_IS_FLOW_BOX (box));
+  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+
+  priv = BOX_PRIV (box);
+
+  g_object_ref (adjustment);
+  if (priv->vadjustment)
+    g_object_unref (priv->vadjustment);
+  priv->vadjustment = adjustment;
+  gtk_container_set_focus_vadjustment (GTK_CONTAINER (box), adjustment);
+}
+
+/* Setters and getters {{{2 */
+
+/**
+ * egg_flow_box_get_homogeneous:
+ * @box: a #EggFlowBox
+ *
+ * Returns whether the box is homogeneous (all children are the
+ * same size). See gtk_box_set_homogeneous().
+ *
+ * Return value: %TRUE if the box is homogeneous.
+ **/
+gboolean
+egg_flow_box_get_homogeneous (EggFlowBox *box)
+{
+  g_return_val_if_fail (EGG_IS_FLOW_BOX (box), FALSE);
+
+  return BOX_PRIV (box)->homogeneous;
+}
+
+/**
+ * egg_flow_box_set_homogeneous:
+ * @box: a #EggFlowBox
+ * @homogeneous: a boolean value, %TRUE to create equal allotments,
+ *   %FALSE for variable allotments
+ *
+ * Sets the #EggFlowBox:homogeneous property of @box, controlling
+ * whether or not all children of @box are given equal space
+ * in the box.
+ */
+void
+egg_flow_box_set_homogeneous (EggFlowBox *box,
+                              gboolean    homogeneous)
+{
+  g_return_if_fail (EGG_IS_FLOW_BOX (box));
+
+  homogeneous = homogeneous != FALSE;
+
+  if (BOX_PRIV (box)->homogeneous != homogeneous)
+    {
+      BOX_PRIV (box)->homogeneous = homogeneous;
+
+      g_object_notify (G_OBJECT (box), "homogeneous");
+      gtk_widget_queue_resize (GTK_WIDGET (box));
+    }
+}
+
+/**
+ * egg_flow_box_set_row_spacing:
+ * @box: An #EggFlowBox
+ * @spacing: The spacing to use
+ *
+ * Sets the vertical space to add between children.
+ */
+void
+egg_flow_box_set_row_spacing (EggFlowBox *box,
+                              guint       spacing)
+{
+  g_return_if_fail (EGG_IS_FLOW_BOX (box));
+
+  if (BOX_PRIV (box)->row_spacing != spacing)
+    {
+      BOX_PRIV (box)->row_spacing = spacing;
+
+      gtk_widget_queue_resize (GTK_WIDGET (box));
+      g_object_notify (G_OBJECT (box), "vertical-spacing");
+    }
+}
+
+/**
+ * egg_flow_box_get_row_spacing:
+ * @box: An #EggFlowBox
+ *
+ * Gets the vertical spacing.
+ *
+ * Returns: The vertical spacing.
+ */
+guint
+egg_flow_box_get_row_spacing (EggFlowBox *box)
+{
+  g_return_val_if_fail (EGG_IS_FLOW_BOX (box), FALSE);
+
+  return BOX_PRIV (box)->row_spacing;
+}
+
+/**
+ * egg_flow_box_set_column_spacing:
+ * @box: An #EggFlowBox
+ * @spacing: The spacing to use
+ *
+ * Sets the horizontal space to add between children.
+ */
+void
+egg_flow_box_set_column_spacing (EggFlowBox *box,
+                                 guint       spacing)
+{
+  g_return_if_fail (EGG_IS_FLOW_BOX (box));
+
+  if (BOX_PRIV (box)->column_spacing != spacing)
+    {
+      BOX_PRIV (box)->column_spacing = spacing;
+
+      gtk_widget_queue_resize (GTK_WIDGET (box));
+      g_object_notify (G_OBJECT (box), "horizontal-spacing");
+    }
+}
+
+/**
+ * egg_flow_box_get_column_spacing:
+ * @box: An #EggFlowBox
+ *
+ * Gets the horizontal spacing.
+ *
+ * Returns: The horizontal spacing.
+ */
+guint
+egg_flow_box_get_column_spacing (EggFlowBox *box)
+{
+  g_return_val_if_fail (EGG_IS_FLOW_BOX (box), FALSE);
+
+  return BOX_PRIV (box)->column_spacing;
+}
+
+/**
+ * egg_flow_box_set_min_children_per_line:
+ * @box: An #EggFlowBox
+ * @n_children: The minimum number of children per line
+ *
+ * Sets the minimum number of children to line up
+ * in @box's orientation before flowing.
+ */
+void
+egg_flow_box_set_min_children_per_line (EggFlowBox *box,
+                                        guint       n_children)
+{
+  g_return_if_fail (EGG_IS_FLOW_BOX (box));
+
+  if (BOX_PRIV (box)->min_children_per_line != n_children)
+    {
+      BOX_PRIV (box)->min_children_per_line = n_children;
+
+      gtk_widget_queue_resize (GTK_WIDGET (box));
+      g_object_notify (G_OBJECT (box), "min-children-per-line");
+    }
+}
+
+/**
+ * egg_flow_box_get_min_children_per_line:
+ * @box: An #EggFlowBox
+ *
+ * Gets the minimum number of children per line.
+ *
+ * Returns: The minimum number of children per line.
+ */
+guint
+egg_flow_box_get_min_children_per_line (EggFlowBox *box)
+{
+  g_return_val_if_fail (EGG_IS_FLOW_BOX (box), FALSE);
+
+  return BOX_PRIV (box)->min_children_per_line;
+}
+
+/**
+ * egg_flow_box_set_max_children_per_line:
+ * @box: An #EggFlowBox
+ * @n_children: The maximum number of children per line.
+ *
+ * Sets the maximum number of children to request and
+ * allocate space for in @box's orientation.
+ *
+ * Setting the maximum number of children per line
+ * limits the overall natural size request to be no more
+ * than @n_children children long in the given orientation.
+ */
+void
+egg_flow_box_set_max_children_per_line (EggFlowBox *box,
+                                        guint       n_children)
+{
+  g_return_if_fail (EGG_IS_FLOW_BOX (box));
+
+  if (BOX_PRIV (box)->max_children_per_line != n_children)
+    {
+      BOX_PRIV (box)->max_children_per_line = n_children;
+
+      gtk_widget_queue_resize (GTK_WIDGET (box));
+      g_object_notify (G_OBJECT (box), "max-children-per-line");
+    }
+}
+
+/**
+ * egg_flow_box_get_max_children_per_line:
+ * @box: An #EggFlowBox
+ *
+ * Gets the maximum number of children per line.
+ *
+ * Returns: The maximum number of children per line.
+ */
+guint
+egg_flow_box_get_max_children_per_line (EggFlowBox *box)
+{
+  g_return_val_if_fail (EGG_IS_FLOW_BOX (box), FALSE);
+
+  return BOX_PRIV (box)->max_children_per_line;
+}
+
+/**
+ * egg_flow_box_set_activate_on_single_click:
+ * @box: An #EggFlowBox
+ * @single: %TRUE to emit child-activated on a single click
+ *
+ * If @single is %TRUE, rows will be activated when you click
+ * on them, otherwise you need to double-click.
+ */
+void
+egg_flow_box_set_activate_on_single_click (EggFlowBox *box,
+                                           gboolean    single)
+{
+  g_return_if_fail (EGG_IS_FLOW_BOX (box));
+
+  single = single != FALSE;
+
+  if (BOX_PRIV (box)->activate_on_single_click != single)
+    {
+      BOX_PRIV (box)->activate_on_single_click = single;
+      g_object_notify (G_OBJECT (box), "activate-on-single-click");
+    }
+}
+
+/**
+ * egg_flow_box_get_activate_on_single_click:
+ * @box: An #EggFlowBox
+ *
+ * Returns whether rows activate on single clicks.
+ *
+ * Returns: %TRUE if rows are activated on single click,
+ *     %FALSE otherwise
+ */
+gboolean
+egg_flow_box_get_activate_on_single_click (EggFlowBox *box)
+{
+  g_return_val_if_fail (EGG_IS_FLOW_BOX (box), FALSE);
+
+  return BOX_PRIV (box)->activate_on_single_click;
+}
+
+/* Selection handling {{{2 */
+
+/**
  * egg_flow_box_get_selected_children:
  * @box: a #EggFlowBox
  *
@@ -4125,6 +4258,16 @@ egg_flow_box_unselect_all (EggFlowBox *box)
 }
 
 /**
+ * EggFlowBoxForeachFunc:
+ * @box: a #EggFlowBox
+ * @child: a #EggFlowBoxChild
+ * @user_data: (closure): user data
+ *
+ * A function used by egg_flow_box_selected_foreach().
+ * It will be called on every selected child of tht @box.
+ */
+
+/**
  * egg_flow_box_selected_foreach:
  * @box: a #EggFlowBox
  * @func: (scope call): the function to call for each selected child
@@ -4205,6 +4348,8 @@ egg_flow_box_get_selection_mode (EggFlowBox *box)
   return BOX_PRIV (box)->selection_mode;
 }
 
+/* Filtering {{{2 */
+
 static void
 egg_flow_box_apply_filter (EggFlowBox      *box,
                            EggFlowBoxChild *child)
@@ -4236,6 +4381,18 @@ egg_flow_box_apply_filter_all (EggFlowBox *box)
 }
 
 /**
+ * EggFlowBoxFilterFunc:
+ * @child: a #EggFlowBoxChild that may be filtered
+ * @user_data: (closure): user data
+ *
+ * A function that will be called whenrever a child changes
+ * or is added. It lets you control if the child should be
+ * visible or not.
+ *
+ * Returns: %TRUE if the row should be visible, %FALSE otherwise
+ */
+
+/**
  * egg_flow_box_set_filter_func:
  * @box: a #EggFlowBox
  * @filter_func: (closure user_data) (allow-none): callback that
@@ -4295,6 +4452,33 @@ egg_flow_box_invalidate_filter (EggFlowBox *box)
   gtk_widget_queue_resize (GTK_WIDGET (box));
 }
 
+/* Sorting {{{2 */
+
+static void
+egg_flow_box_apply_sort (EggFlowBox      *box,
+                         EggFlowBoxChild *child)
+{
+  if (BOX_PRIV (box)->sort_func != NULL)
+    {
+      g_sequence_sort_changed (CHILD_PRIV (child)->iter,
+                               (GCompareDataFunc)egg_flow_box_sort, box);
+      gtk_widget_queue_resize (GTK_WIDGET (box));
+    }
+}
+
+/**
+ * EggFlowBoxSortFunc:
+ * @child1: the first child
+ * @child2: the second child
+ * @user_data: (closure): user data
+ *
+ * A function to compare two children to determine which
+ * should come first.
+ *
+ * Returns: < 0 if @child1 should be before @child2, 0 if
+ *     the are equal, and > 0 otherwise
+ */
+
 /**
  * egg_flow_box_set_sort_func:
  * @box: a #EggFlowBox
@@ -4369,83 +4553,4 @@ egg_flow_box_invalidate_sort (EggFlowBox *box)
     }
 }
 
-/**
- * egg_flow_box_insert:
- * @box: a #EggFlowBox
- * @widget: the #GtkWidget to add
- * @position: the position to insert @child in
- *
- * Inserts the @child into @box at @position.
- *
- * If a sort function is set, the widget will actually be inserted
- * at the calculated position and this function has the same effect
- * as gtk_container_add().
- *
- * If @position is -1, or larger than the total number of children
- * in the @box, then the @child will be appended to the end.
- */
-void
-egg_flow_box_insert (EggFlowBox *box,
-                     GtkWidget  *widget,
-                     gint        position)
-{
-  EggFlowBoxPrivate *priv;
-  EggFlowBoxChild *child;
-  GSequenceIter *iter;
-
-  g_return_if_fail (EGG_IS_FLOW_BOX (box));
-  g_return_if_fail (GTK_IS_WIDGET (widget));
-
-  priv = BOX_PRIV (box);
-
-  if (EGG_IS_FLOW_BOX_CHILD (widget))
-    child = EGG_FLOW_BOX_CHILD (widget);
-  else
-    {
-      child = EGG_FLOW_BOX_CHILD (egg_flow_box_child_new ());
-      gtk_widget_show (GTK_WIDGET (child));
-      gtk_container_add (GTK_CONTAINER (child), widget);
-    }
-
-  if (priv->sort_func != NULL)
-    iter = g_sequence_insert_sorted (priv->children, child,
-                                     (GCompareDataFunc)egg_flow_box_sort, box);
-  else if (position == 0)
-    iter = g_sequence_prepend (priv->children, child);
-  else if (position == -1)
-    iter = g_sequence_append (priv->children, child);
-  else
-    {
-      GSequenceIter *pos;
-      pos = g_sequence_get_iter_at_pos (priv->children, position);
-      iter = g_sequence_insert_before (pos, child);
-    }
-
-  CHILD_PRIV (child)->iter = iter;
-  gtk_widget_set_parent (GTK_WIDGET (child), GTK_WIDGET (box));
-  egg_flow_box_apply_filter (box, child);
-}
-
-/**
- * egg_flow_box_get_child_at_index:
- * @box: a #EggFlowBox
- * @idx: the position of the child
- *
- * Gets the nth child in the @box.
- *
- * Returns: (transfer none): the child #GtkWidget
- */
-EggFlowBoxChild *
-egg_flow_box_get_child_at_index (EggFlowBox *box,
-                                 gint        idx)
-{
-  GSequenceIter *iter;
-
-  g_return_val_if_fail (EGG_IS_FLOW_BOX (box), NULL);
-
-  iter = g_sequence_get_iter_at_pos (BOX_PRIV (box)->children, idx);
-  if (iter)
-    return g_sequence_get (iter);
-
-  return NULL;
-}
+/* vim:set foldmethod=marker: */


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