]> Pileus Git - ~andy/gtk/blobdiff - gtk/tests/treeview-scrolling.c
filechooserbutton: Don't duplicate tests for GTK_RESPONSE_DELETE_EVENT
[~andy/gtk] / gtk / tests / treeview-scrolling.c
index 6b2d13c9d92eda0e669ffd1a1e1221165883f0a5..77dca9abc44699dce08b76ae569e3767f0b8235b 100644 (file)
@@ -14,9 +14,7 @@
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
 /* Original v1.0 -- December 26, 2006
@@ -26,6 +24,7 @@
 
 #include <gtk/gtk.h>
 #include <unistd.h>
+#include <math.h>
 
 #define VIEW_WIDTH 320
 #define VIEW_HEIGHT 240
  *     chosen paths).
  *   - Convert to proper GTK+ coding style.
  *   - Briefly test scrolling in tree stores as well.
+ *
+ * Important:
+ *   - For tests with "mixed height" models, you must ensure that
+ *     there are only two heights used in total and that the rows with
+ *     height A and B are strictly alternating.  The model creation
+ *     functions already do this for you, but take this into account
+ *     when you write a unit test that adds rows to such a created
+ *     model, you must follow this rule otherwise things will break.
  */
 
 
@@ -109,10 +116,15 @@ scroll_fixture_setup (ScrollFixture *fixture,
        fixture->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
        sw = gtk_scrolled_window_new (NULL, NULL);
+       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
+                                       GTK_POLICY_NEVER,
+                                       GTK_POLICY_ALWAYS);
        gtk_container_add (GTK_CONTAINER (fixture->window), sw);
 
        fixture->tree_view = gtk_tree_view_new_with_model (model);
        g_object_unref (model);
+       gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW (sw), VIEW_WIDTH);
+       gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (sw), VIEW_HEIGHT);
        gtk_widget_set_size_request (fixture->tree_view, VIEW_WIDTH, VIEW_HEIGHT);
 
        renderer = gtk_cell_renderer_text_new ();
@@ -206,6 +218,40 @@ scroll_fixture_tree_setup (ScrollFixture *fixture,
        scroll_fixture_setup (fixture, GTK_TREE_MODEL (store), test_data);
 }
 
+static void
+scroll_fixture_mixed_tree_setup (ScrollFixture *fixture,
+                                gconstpointer   test_data)
+{
+       GtkTreeStore *store;
+       GtkTreeIter iter, child;
+       int i;
+
+       store = gtk_tree_store_new (1, G_TYPE_STRING);
+
+       gtk_tree_store_append (store, &iter, NULL);
+       gtk_tree_store_set (store, &iter, 0, "Root\nnode", -1);
+
+       for (i = 0; i < 5; i++) {
+               gtk_tree_store_append (store, &child, &iter);
+               if (i % 2 != 0)
+                       gtk_tree_store_set (store, &child, 0, "Child node", -1);
+               else
+                       gtk_tree_store_set (store, &child,
+                                           0, "Child\nnode", -1);
+       }
+
+       for (i = 0; i < 5; i++) {
+               gtk_tree_store_append (store, &iter, NULL);
+               if (i % 2 == 0)
+                       gtk_tree_store_set (store, &iter, 0, "Other node", -1);
+               else
+                       gtk_tree_store_set (store, &iter, 0, "Other\nnode", -1);
+       }
+
+       /* The teardown will also destroy the model */
+       scroll_fixture_setup (fixture, GTK_TREE_MODEL (store), test_data);
+}
+
 static void
 scroll_fixture_teardown (ScrollFixture *fixture,
                         gconstpointer  test_data)
@@ -250,33 +296,32 @@ get_row_start_for_index (GtkTreeView *tree_view, int index)
 static enum Pos
 get_pos_from_path (GtkTreeView   *tree_view,
                   GtkTreePath   *path,
-                  gint           row_height,
-                  GtkAdjustment *vadj)
+                  gdouble        row_height,
+                  GtkAdjustment *vadjustment)
 {
        int row_start;
 
        row_start = get_row_start_for_index (tree_view,
                                             gtk_tree_path_get_indices (path)[0]);
 
-       if (row_start + row_height < vadj->page_size)
+       if (row_start + row_height < gtk_adjustment_get_page_size (vadjustment))
                return POS_TOP;
 
-       if (row_start >= vadj->upper - vadj->page_size)
+       if (row_start >= gtk_adjustment_get_upper (vadjustment) - gtk_adjustment_get_page_size (vadjustment))
                return POS_BOTTOM;
 
        return POS_CENTER;
 }
 
-static gboolean
-test_position_with_align (GtkTreeView  *tree_view,
-                         enum Pos      pos,
-                         gint          row_y,
-                         gint          row_start,
-                         gint          row_height,
-                         gfloat        row_align)
+static void
+assert_position_with_align (GtkTreeView  *tree_view,
+                            enum Pos      pos,
+                            gint          row_y,
+                            gint          row_start,
+                            gdouble       row_height,
+                            gdouble       row_align)
 {
-       gboolean passed = TRUE;
-       GtkAdjustment *vadj = gtk_tree_view_get_vadjustment (tree_view);
+       GtkAdjustment *vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (tree_view));
 
        /* Switch on row-align: 0.0, 0.5, 1.0 */
        switch ((int)(row_align * 2.)) {
@@ -288,42 +333,37 @@ test_position_with_align (GtkTreeView  *tree_view,
                         *    - dy should be equal to the top
                         *      y coordinate of the row.
                         */
-                       if (row_y != 0)
-                               passed = FALSE;
-                       if (vadj->value != row_start)
-                               passed = FALSE;
+                       g_assert (row_y == 0);
+                       g_assert (gtk_adjustment_get_value (vadjustment) == row_start);
                } else {
                        /* The row can be anywhere at the last
                         * page of the tree view.
                         *   - dy is set to the start of the
                         *     last page.
                         */
-                       if (vadj->value != vadj->upper - vadj->page_size)
-                               passed = FALSE;
+                       g_assert (gtk_adjustment_get_value (vadjustment) == gtk_adjustment_get_upper (vadjustment) - gtk_adjustment_get_page_size (vadjustment));
                }
                break;
 
        case 1:
                /* 0.5 */
                if (pos == POS_TOP
-                   && row_start < vadj->page_size / 2) {
+                   && row_start < (gtk_adjustment_get_page_size (vadjustment) - row_height) / 2) {
                        /* For the first half of the top view we can't
                         * center the row in the view, instead we
                         * show the first page.
                         *   - dy should be zero
                         */
-                       if (vadj->value != 0)
-                               passed = FALSE;
+                       g_assert (gtk_adjustment_get_value (vadjustment) == 0);
                } else if (pos == POS_BOTTOM
-                          && row_start >= vadj->upper - vadj->page_size / 2) {
+                          && row_start + row_height >= gtk_adjustment_get_upper (vadjustment) - (gtk_adjustment_get_page_size (vadjustment) - row_height) / 2) {
                        /* For the last half of the bottom view we
                         * can't center the row in the view, instead
                         * we show the last page.
                         *   - dy should be the start of the 
                         *     last page.
                         */
-                       if (vadj->value != vadj->upper - vadj->page_size)
-                               passed = FALSE;
+                       g_assert (gtk_adjustment_get_value (vadjustment) == gtk_adjustment_get_upper (vadjustment) - gtk_adjustment_get_page_size (vadjustment));
                } else {
                        /* The row is located in the middle of
                         * the view.
@@ -333,8 +373,8 @@ test_position_with_align (GtkTreeView  *tree_view,
                         *      (ie. the row's center is at the
                         *       center of the view).
                         */
-                       if (row_y != (int)(vadj->page_size / 2 - row_height / 2))
-                               passed = FALSE;
+                       gdouble middle = (gtk_adjustment_get_page_size (vadjustment) - row_height) / 2.0;
+                       g_assert (row_y == ceil (middle) || row_y == floor (middle));
                }
                break;
 
@@ -345,8 +385,7 @@ test_position_with_align (GtkTreeView  *tree_view,
                         * first page of the tree view.
                         *   - dy is zero.
                         */
-                       if (vadj->value != 0)
-                               passed = FALSE;
+                       g_assert (gtk_adjustment_get_value (vadjustment) == 0);
                } else if (pos == POS_CENTER || pos == POS_BOTTOM) {
                        /* The row is the last row visible in the
                         * view.
@@ -356,44 +395,34 @@ test_position_with_align (GtkTreeView  *tree_view,
                         *     (ie we are not on the first page).
                         *   - dy is greater than zero
                         */
-                       if (row_start < vadj->page_size
-                           && row_start + row_height < vadj->page_size)
-                               passed = FALSE;
-                       if (vadj->value <= 0)
-                               passed = FALSE;
-                       if (row_y != vadj->page_size - row_height)
-                               passed = FALSE;
+                       g_assert (row_start >= gtk_adjustment_get_page_size (vadjustment)
+                                 || row_start + row_height >= gtk_adjustment_get_page_size (vadjustment));
+                       g_assert (row_y == gtk_adjustment_get_page_size (vadjustment) - row_height);
                }
                break;
        }
-
-       return passed;
 }
 
-static gboolean
-test_position_without_align (GtkTreeView *tree_view,
-                            gint         row_start,
-                            gint         row_height)
+static void
+assert_position_without_align (GtkTreeView *tree_view,
+                               gdouble      row_start,
+                               gdouble      row_height)
 {
-       GtkAdjustment *vadj = gtk_tree_view_get_vadjustment (tree_view);
-
-       /* Without align the tree view does as less work as possible,
-        * so basically we only have to check whether the row
-        * is visible on the screen.
-        */
-       if (vadj->value <= row_start
-           && vadj->value + vadj->page_size >= row_start + row_height)
-               return TRUE;
-
-       return FALSE;
+  GtkAdjustment *vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (tree_view));
+
+  /* Without align the tree view does as less work as possible,
+   * so basically we only have to check whether the row
+   * is visible on the screen.
+   */
+  g_assert (gtk_adjustment_get_value (vadjustment) <= row_start);
+  g_assert (gtk_adjustment_get_value (vadjustment) + gtk_adjustment_get_page_size (vadjustment) >= row_start + row_height);
 }
 
 static void
 test_position (GtkTreeView *tree_view,
               GtkTreePath *path,
               gboolean     use_align,
-              gfloat       row_align,
-              gfloat       col_align)
+              gdouble      row_align)
 {
        gint pos;
        gchar *path_str;
@@ -411,7 +440,7 @@ test_position (GtkTreeView *tree_view,
        /* Ugh */
        pos = get_pos_from_path (GTK_TREE_VIEW (tree_view),
                                 path, rect.height,
-                                gtk_tree_view_get_vadjustment (GTK_TREE_VIEW (tree_view)));
+                                gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (tree_view)));
 
        /* This is only tested for during test_single() */
        model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
@@ -433,10 +462,10 @@ test_position (GtkTreeView *tree_view,
 
        path_str = gtk_tree_path_to_string (path);
        if (use_align) {
-               g_assert (test_position_with_align (tree_view, pos, rect.y,
-                                                   row_start, rect.height, row_align));
+               assert_position_with_align (tree_view, pos, rect.y,
+                                            row_start, rect.height, row_align);
        } else {
-               g_assert (test_position_without_align (tree_view, row_start, rect.height));
+               assert_position_without_align (tree_view, row_start, rect.height);
        }
 
        g_free (path_str);
@@ -449,11 +478,22 @@ test_position (GtkTreeView *tree_view,
 
 /* Testing scrolling to various positions with various alignments */
 
+static void
+ensure_layout (void)
+{
+        /* HACK: sleep for more than one frame, to give the paint clock
+         * time to prepare the new layout */
+        g_usleep (100 * 1000);
+
+       while (gtk_events_pending ())
+               gtk_main_iteration ();
+}
+
 static void
 scroll (ScrollFixture *fixture,
        GtkTreePath   *path,
        gboolean       use_align,
-       gfloat         row_align)
+       gdouble        row_align)
 {
        gtk_tree_view_set_cursor (GTK_TREE_VIEW (fixture->tree_view), path,
                                  NULL, FALSE);
@@ -463,11 +503,9 @@ scroll (ScrollFixture *fixture,
 
        gtk_widget_show_all (fixture->window);
 
-       while (gtk_events_pending ())
-               gtk_main_iteration ();
-
+        ensure_layout ();
        test_position (GTK_TREE_VIEW (fixture->tree_view), path,
-                      use_align, row_align, 0.0);
+                      use_align, row_align);
 }
 
 static void
@@ -519,7 +557,7 @@ static void
 scroll_after_realize (ScrollFixture *fixture,
                      GtkTreePath   *path,
                      gboolean       use_align,
-                     gfloat         row_align)
+                     gdouble        row_align)
 {
        gtk_widget_show_all (fixture->window);
 
@@ -532,11 +570,9 @@ scroll_after_realize (ScrollFixture *fixture,
                                      path, NULL,
                                      use_align, row_align, 0.0);
 
-       while (gtk_events_pending ())
-               gtk_main_iteration ();
-
+        ensure_layout ();
        test_position (GTK_TREE_VIEW (fixture->tree_view), path,
-                      use_align, row_align, 0.0);
+                      use_align, row_align);
 }
 
 static void
@@ -588,7 +624,7 @@ static void
 scroll_both_realize (ScrollFixture *fixture,
                     GtkTreePath   *path,
                     gboolean       use_align,
-                    gfloat         row_align)
+                    gdouble        row_align)
 {
        GtkTreePath *end;
 
@@ -614,11 +650,9 @@ scroll_both_realize (ScrollFixture *fixture,
                                      path, NULL,
                                      use_align, row_align, 0.0);
 
-       while (gtk_events_pending ())
-               gtk_main_iteration ();
-
+        ensure_layout ();
        test_position (GTK_TREE_VIEW (fixture->tree_view), path,
-                      use_align, row_align, 0.0);
+                      use_align, row_align);
 }
 
 static void
@@ -677,11 +711,21 @@ create_new_row (GtkListStore *store,
                        gtk_list_store_prepend (store, iter);
                        break;
 
+                case 3:
+                       /* Add a row in the middle of the visible area */
+                       gtk_list_store_insert (store, iter, 3);
+                       break;
+
                case 4:
                        /* Add a row in the middle of the visible area */
                        gtk_list_store_insert (store, iter, 4);
                        break;
 
+                case 5:
+                       /* Add a row which is not completely visible */
+                       gtk_list_store_insert (store, iter, 5);
+                       break;
+
                case 8:
                        /* Add a row which is not completely visible */
                        gtk_list_store_insert (store, iter, 8);
@@ -719,13 +763,10 @@ test_editable_position (GtkWidget   *tree_view,
 {
         GtkAllocation allocation;
        GdkRectangle rect;
-       GtkAdjustment *vadj;
 
        gtk_tree_view_get_background_area (GTK_TREE_VIEW (tree_view),
                                           cursor_path, NULL, &rect);
 
-       vadj = gtk_tree_view_get_vadjustment (GTK_TREE_VIEW (tree_view));
-
        /* There are all in bin_window coordinates */
         gtk_widget_get_allocation (editable, &allocation);
         g_assert (allocation.y == rect.y + ((rect.height - allocation.height) / 2));
@@ -776,12 +817,11 @@ scroll_new_row (ScrollFixture *fixture,
                                  column,
                                  TRUE);
 
-       while (gtk_events_pending ())
-               gtk_main_iteration ();
+        ensure_layout ();
 
        /* Test position */
        test_position (GTK_TREE_VIEW (fixture->tree_view), scroll_path,
-                      FALSE, 0.0, 0.0);
+                      FALSE, 0.0);
        test_editable_position (fixture->tree_view, editable, scroll_path);
 
        gtk_tree_path_free (scroll_path);
@@ -813,7 +853,7 @@ scroll_new_row_tree (ScrollFixture *fixture,
                gtk_main_iteration ();
 
        model = gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view));
-       vadjustment = gtk_tree_view_get_vadjustment (GTK_TREE_VIEW (fixture->tree_view));
+       vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (fixture->tree_view));
 
        for (i = 0; i < 5; i++) {
                GtkTreeIter scroll_iter;
@@ -829,11 +869,10 @@ scroll_new_row_tree (ScrollFixture *fixture,
                                              scroll_path, NULL, FALSE, 0.0, 0.0);
                gtk_tree_path_free (scroll_path);
 
-               while (gtk_events_pending ())
-                       gtk_main_iteration ();
+                ensure_layout ();
 
                /* Test position, the scroll bar must be at the end */
-               g_assert (vadjustment->value == vadjustment->upper - vadjustment->page_size);
+               g_assert (gtk_adjustment_get_value (vadjustment) == gtk_adjustment_get_upper (vadjustment) - gtk_adjustment_get_page_size (vadjustment));
        }
 }
 
@@ -846,7 +885,7 @@ test_bug316689 (ScrollFixture *fixture,
 {
        GtkTreeIter iter;
        GtkTreePath *path;
-       GtkAdjustment *vadj;
+       GtkAdjustment *vadjustment;
        GtkTreeModel *model;
 
        /* The aim of this test is to scroll to the bottom of a TreeView,
@@ -876,10 +915,10 @@ test_bug316689 (ScrollFixture *fixture,
        while (gtk_events_pending ())
                gtk_main_iteration ();
 
-       vadj = gtk_tree_view_get_vadjustment (GTK_TREE_VIEW (fixture->tree_view));
+       vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (fixture->tree_view));
 
-       g_assert (vadj->value + vadj->page_size <= vadj->upper);
-       g_assert (vadj->value == vadj->upper - vadj->page_size);
+       g_assert (gtk_adjustment_get_value (vadjustment) + gtk_adjustment_get_page_size (vadjustment) <= gtk_adjustment_get_upper (vadjustment));
+       g_assert (gtk_adjustment_get_value (vadjustment) == gtk_adjustment_get_upper (vadjustment) - gtk_adjustment_get_page_size (vadjustment));
 }
 
 
@@ -946,6 +985,215 @@ test_bug359231 (void)
        scroll_fixture_teardown (fixture, NULL);
 }
 
+/* Test for GNOME bugzilla bug 93584.  We add 150 rows to an existing
+ * small model, and scroll to one of these with alignment.
+ */
+static void
+test_bug93584 (ScrollFixture *fixture,
+              gconstpointer  test_data)
+{
+       int row, i;
+       GtkTreeStore *store;
+       GtkTreePath *path;
+
+       g_test_bug ("93584");
+
+       /* Mimic state as in original test case */
+       g_signal_connect (G_OBJECT (fixture->tree_view), "realize",
+                         G_CALLBACK (gtk_tree_view_expand_all), NULL);
+       gtk_widget_show_all (fixture->window);
+
+       store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view)));
+
+       /* Add 150 rows */
+       for (i = 0; i < 150; i++) {
+               GtkTreeIter iter;
+
+               gtk_tree_store_append (store, &iter, NULL);
+               gtk_tree_store_set (store, &iter, 0, "Row", -1);
+       }
+
+       row = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), NULL);
+       row -= 20;
+
+       while (gtk_events_pending ())
+               gtk_main_iteration ();
+
+       path = gtk_tree_path_new_from_indices (row, -1);
+       scroll (fixture, path, TRUE, 0.5);
+       gtk_tree_path_free (path);
+}
+
+/* GNOME bugzilla bug 111500.  Expand a row and immediately scroll
+ * to its first child.  Make sure that expansion happens in currently
+ * invisible area.
+ */
+static void
+test_bug111500 (ScrollFixture *fixture,
+               gconstpointer  test_data)
+{
+       int i, len;
+       GtkTreeStore *store;
+       GtkTreeIter parent;
+       GtkTreePath *path;
+
+       g_test_bug ("111500");
+
+       gtk_widget_show_all (fixture->window);
+
+       /* Make sure all events have been processed and the window
+        * is visible.
+        */
+       while (gtk_events_pending ())
+               gtk_main_iteration ();
+
+       /* Further prepare model */
+       store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view)));
+
+       for (i = 0; i < 15; i++) {
+               GtkTreeIter iter;
+
+               gtk_tree_store_append (store, &iter, NULL);
+               gtk_tree_store_set (store, &iter, 0, "Other node", -1);
+       }
+
+       len = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), NULL);
+       gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &parent,
+                                      NULL, len - 1);
+
+       for (i = 0; i < 5; i++) {
+               GtkTreeIter iter;
+
+               gtk_tree_store_append (store, &iter, &parent);
+               gtk_tree_store_set (store, &iter, 0, "Row", -1);
+       }
+
+       path = gtk_tree_path_new_from_indices (len - 1, -1);
+       gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view),
+                                 path, FALSE);
+
+       gtk_tree_path_down (path);
+
+       scroll (fixture, path, FALSE, 0.5);
+       gtk_tree_path_free (path);
+}
+
+static void
+test_bug111500_mixed (ScrollFixture *fixture,
+                     gconstpointer  test_data)
+{
+       int i, len;
+       GtkTreeStore *store;
+       GtkTreeIter parent;
+       GtkTreePath *path;
+
+       g_test_bug ("111500");
+
+       gtk_widget_show_all (fixture->window);
+
+       /* Make sure all events have been processed and the window
+        * is visible.
+        */
+       while (gtk_events_pending ())
+               gtk_main_iteration ();
+
+       /* Further prepare model */
+       store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view)));
+
+       for (i = 0; i < 15; i++) {
+               GtkTreeIter iter;
+
+               gtk_tree_store_append (store, &iter, NULL);
+               if (i % 2 == 0)
+                       gtk_tree_store_set (store, &iter, 0, "Other node", -1);
+               else
+                       gtk_tree_store_set (store, &iter, 0, "Other\nnode", -1);
+       }
+
+       len = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), NULL);
+       gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &parent,
+                                      NULL, len - 1);
+
+       for (i = 0; i < 5; i++) {
+               GtkTreeIter iter;
+
+               gtk_tree_store_append (store, &iter, &parent);
+               if (i % 2 != 0)
+                       gtk_tree_store_set (store, &iter, 0, "Row", -1);
+               else
+                       gtk_tree_store_set (store, &iter, 0, "Row\nRow", -1);
+       }
+
+       path = gtk_tree_path_new_from_indices (len - 1, -1);
+       gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view),
+                                 path, FALSE);
+
+       gtk_tree_path_down (path);
+
+       scroll (fixture, path, FALSE, 0.5);
+       gtk_tree_path_free (path);
+}
+
+/* Test for GNOME bugzilla bug 163214.  Invalidate a couple of rows,
+ * then scroll to one of these.
+ */
+static void
+test_bug163214 (ScrollFixture *fixture,
+               gconstpointer  test_data)
+{
+       int i;
+       GtkListStore *store;
+       GtkTreePath *path;
+
+       g_test_bug ("163214");
+
+       gtk_widget_show_all (fixture->window);
+
+       /* Make sure all events have been processed and the window
+        * is visible.
+        */
+       while (gtk_events_pending ())
+               gtk_main_iteration ();
+
+       store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view)));
+
+       /* Invalidate a page of rows */
+       for (i = 100; i < 110; i++) {
+               GtkTreeIter iter;
+
+               gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter,
+                                              NULL, i);
+               gtk_list_store_set (store, &iter, 0, "Row", -1);
+       }
+
+       /* Then scroll to that page. */
+       path = gtk_tree_path_new_from_indices (105, -1);
+       scroll (fixture, path, TRUE, 0.5);
+       gtk_tree_path_free (path);
+
+       /* Make sure all events have been processed and the window
+        * is visible.
+        */
+       while (gtk_events_pending ())
+               gtk_main_iteration ();
+
+       store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view)));
+
+       /* Invalidate a page of rows */
+       for (i = 300; i < 310; i++) {
+               GtkTreeIter iter;
+
+               gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter,
+                                              NULL, i);
+               gtk_list_store_set (store, &iter, 0, "Row", -1);
+       }
+
+       /* Then scroll to the first row */
+       path = gtk_tree_path_new_from_indices (0, -1);
+       scroll (fixture, path, TRUE, 0.5);
+       gtk_tree_path_free (path);
+}
+
 /* Infrastructure for automatically adding tests */
 enum
 {
@@ -973,7 +1221,7 @@ test_type_string (int test_type)
 
 static char *
 align_string (gboolean use_align,
-             gfloat   row_align)
+             gdouble  row_align)
 {
        char *ret;
 
@@ -989,7 +1237,7 @@ add_test (const char *path,
          gboolean    mixed,
          int         test_type,
          gboolean    use_align,
-         gfloat      row_align,
+         gdouble     row_align,
          void (* setup) (ScrollFixture *, gconstpointer),
          void (* scroll_func) (ScrollFixture *, gconstpointer))
 {
@@ -1014,7 +1262,7 @@ static void
 add_tests (gboolean mixed,
           int test_type,
           gboolean use_align,
-          gfloat row_align,
+          gdouble  row_align,
           void (*scroll_func) (ScrollFixture *, gconstpointer))
 {
        void (* setup) (ScrollFixture *, gconstpointer);
@@ -1181,6 +1429,43 @@ main (int argc, char **argv)
                    scroll_new_row_tree,
                    scroll_fixture_teardown);
 
+       /* Test scrolling to a newly created row, in a mixed height model */
+       g_test_add ("/TreeView/scrolling/new-row-mixed/path-0", ScrollFixture,
+                   GINT_TO_POINTER (0),
+                   scroll_fixture_mixed_setup,
+                   scroll_new_row,
+                   scroll_fixture_teardown);
+       g_test_add ("/TreeView/scrolling/new-row-mixed/path-3", ScrollFixture,
+                   GINT_TO_POINTER (3),
+                   scroll_fixture_mixed_setup,
+                   scroll_new_row,
+                   scroll_fixture_teardown);
+       /* We scroll to 8 to test a partial visible row.  The 8 is
+        * based on my font setting of "Vera Sans 11" and
+        * the separators set to 0.  (This should be made dynamic; FIXME).
+        */
+       g_test_add ("/TreeView/scrolling/new-row-mixed/path-5", ScrollFixture,
+                   GINT_TO_POINTER (5),
+                   scroll_fixture_mixed_setup,
+                   scroll_new_row,
+                   scroll_fixture_teardown);
+       g_test_add ("/TreeView/scrolling/new-row-mixed/path-500", ScrollFixture,
+                   GINT_TO_POINTER (500),
+                   scroll_fixture_mixed_setup,
+                   scroll_new_row,
+                   scroll_fixture_teardown);
+       g_test_add ("/TreeView/scrolling/new-row-mixed/path-999", ScrollFixture,
+                   GINT_TO_POINTER (999),
+                   scroll_fixture_mixed_setup,
+                   scroll_new_row,
+                   scroll_fixture_teardown);
+
+       g_test_add ("/TreeView/scrolling/new-row-mixed/tree", ScrollFixture,
+                   NULL,
+                   scroll_fixture_mixed_tree_setup,
+                   scroll_new_row_tree,
+                   scroll_fixture_teardown);
+
        /* Misc. tests */
        g_test_add ("/TreeView/scrolling/specific/bug-316689",
                        ScrollFixture, NULL,
@@ -1188,6 +1473,22 @@ main (int argc, char **argv)
                    scroll_fixture_teardown);
        g_test_add_func ("/TreeView/scrolling/specific/bug-359231",
                        test_bug359231);
+       g_test_add ("/TreeView/scrolling/specific/bug-93584",
+                   ScrollFixture, NULL,
+                   scroll_fixture_tree_setup, test_bug93584,
+                   scroll_fixture_teardown);
+       g_test_add ("/TreeView/scrolling/specific/bug-111500",
+                   ScrollFixture, NULL,
+                   scroll_fixture_tree_setup, test_bug111500,
+                   scroll_fixture_teardown);
+       g_test_add ("/TreeView/scrolling/specific/bug-111500-mixed",
+                   ScrollFixture, NULL,
+                   scroll_fixture_mixed_tree_setup, test_bug111500_mixed,
+                   scroll_fixture_teardown);
+       g_test_add ("/TreeView/scrolling/specific/bug-163214",
+                   ScrollFixture, NULL,
+                   scroll_fixture_constant_setup, test_bug163214,
+                   scroll_fixture_teardown);
 
        return g_test_run ();
 }