Index: src/expr.c
===================================================================
--- src/expr.c	(revision 17165)
+++ src/expr.c	(working copy)
@@ -2191,6 +2191,82 @@
 	return NULL;
 }
 
+static gboolean
+gnm_expr_ready_for_eval (GnmExpr const *expr, GnmEvalPos const *pos)
+{
+	switch (GNM_EXPR_GET_OPER (expr)) {
+	case GNM_EXPR_OP_CONSTANT: {
+		GnmValue const *v = expr->constant.value;
+		if (v->type != VALUE_CELLRANGE)
+			return TRUE;
+
+		return FALSE;  /* Good enough for now.  */
+	}
+
+	case GNM_EXPR_OP_NAME:
+		if (!expr->name.name->active)
+			return TRUE;
+		return gnm_expr_ready_for_eval (expr->name.name->texpr->expr, pos);
+
+	case GNM_EXPR_OP_CELLREF: {
+		GnmCell *cell;
+		GnmCellPos dest;
+		
+		gnm_cellpos_init_cellref (&dest, &expr->cellref.ref, &pos->eval);
+		
+		cell = sheet_cell_get (eval_sheet (expr->cellref.ref.sheet, pos->sheet),
+				       dest.col, dest.row);
+		return !cell || !dependent_needs_recalc (GNM_CELL_TO_DEP (cell));
+	}
+
+	case GNM_EXPR_OP_FUNCALL: {
+		int i;
+		for (i = 0; i < expr->func.argc; i++)
+			if (!gnm_expr_ready_for_eval (expr->func.argv[i], pos))
+				return FALSE;
+		return TRUE;
+	}
+
+	case GNM_EXPR_OP_SET: {
+		int i;
+		for (i = 0; i < expr->set.argc; i++)
+			if (!gnm_expr_ready_for_eval (expr->set.argv[i], pos))
+				return FALSE;
+		return TRUE;
+	}
+
+	case GNM_EXPR_OP_RANGE_CTOR:
+	case GNM_EXPR_OP_INTERSECT:
+	case GNM_EXPR_OP_ANY_BINARY:
+		return (gnm_expr_ready_for_eval (expr->binary.value_a, pos) &&
+			gnm_expr_ready_for_eval (expr->binary.value_b, pos));
+
+	case GNM_EXPR_OP_ANY_UNARY:
+		return gnm_expr_ready_for_eval (expr->unary.value, pos);
+
+	case GNM_EXPR_OP_ARRAY_CORNER:
+		return gnm_expr_ready_for_eval (expr->array_corner.expr, pos);
+
+	case GNM_EXPR_OP_ARRAY_ELEM: {
+		/* The upper left corner manages the recalc of the expr */
+		GnmCell *corner =
+			array_elem_get_corner (&expr->array_elem,
+					       pos->sheet,
+					       &pos->eval);
+		if (corner == NULL)
+			return TRUE;
+		return !dependent_needs_recalc (GNM_CELL_TO_DEP (corner));
+	}
+
+	default:
+		return FALSE;
+	}
+
+	g_assert_not_reached ();
+	return FALSE;
+	
+}
+
 static void
 cellref_boundingbox (GnmCellRef const *cr, GnmRange *bound)
 {
@@ -3053,6 +3129,26 @@
 	}
 }
 
+gboolean
+gnm_expr_top_ready_for_eval (GnmExprTop const *texpr, GnmEvalPos const *pos)
+{
+	g_return_val_if_fail (IS_GNM_EXPR_TOP (texpr), FALSE);
+#if 0
+	{
+		GnmParsePos pp;
+		parse_pos_init_evalpos (&pp, pos);
+		char *s = gnm_expr_top_as_string
+			(texpr, &pp, gnm_conventions_default);
+		g_printerr ("XXX expr=%s %d\n",
+			    s,
+			    gnm_expr_ready_for_eval (texpr->expr, pos));
+		g_free (s);
+	}
+#endif
+	return gnm_expr_ready_for_eval (texpr->expr, pos);
+}
+
+
 /****************************************************************************/
 
 #if USE_EXPR_POOLS
Index: src/expr.h
===================================================================
--- src/expr.h	(revision 17165)
+++ src/expr.h	(working copy)
@@ -135,6 +135,7 @@
 gboolean	gnm_expr_top_contains_subtotal	(GnmExprTop const *texpr);
 GSList	       *gnm_expr_top_referenced_sheets	(GnmExprTop const *texpr);
 GnmExpr const  *gnm_expr_top_first_funcall	(GnmExprTop const *texpr);
+gboolean        gnm_expr_top_ready_for_eval     (GnmExprTop const *texpr, GnmEvalPos const *pos);
 GnmExprTop const *gnm_expr_top_transpose        (GnmExprTop const *texpr);
 
 struct _GnmExprRelocateInfo {
Index: src/dependent.c
===================================================================
--- src/dependent.c	(revision 17165)
+++ src/dependent.c	(working copy)
@@ -2590,30 +2590,77 @@
 void
 workbook_recalc (Workbook *wb)
 {
-	gboolean redraw = FALSE;
+	GList *l, *deps = NULL;
+	int N, pass;
 
 	g_return_if_fail (IS_WORKBOOK (wb));
 
 	WORKBOOK_FOREACH_DEPENDENT (wb, dep, {
-		if (dependent_needs_recalc (dep)) {
-			redraw = TRUE;
-			dependent_eval (dep);
-		}
+		if (dependent_needs_recalc (dep))
+			deps = g_list_prepend (deps, dep);
 	});
 
+	N = g_list_length (deps);
+
+	if (!deps)
+		return;
+
+	for (pass = 1; N > 0 && pass <= 2; pass++) {
+		GList *next;
+		int n = 0;
+		for (l = deps; l; l = next) {
+			GnmDependent *dep = l->data;
+			next = l->next;
+			if (dependent_needs_recalc (dep)) {
+				GnmEvalPos ep;
+				eval_pos_init_dep (&ep, dep);
+				if (gnm_expr_top_ready_for_eval (dep->texpr, &ep)) {
+					dependent_eval (dep);
+
+					/*
+					 * If we just did an array corner,
+					 * we could now do all the other
+					 * elements.
+					 */
+				}
+			}
+
+			if (!dependent_needs_recalc (dep)) {
+				deps = g_list_delete_link (deps, l);
+				n++;
+			}
+		}
+
+#ifdef DEBUG_EVALUATION
+		g_printerr ("Pass %d handled %d of %d.\n", pass, n, N);
+#endif
+		if (n == 0)
+			break;
+
+		N -= n;
+		deps = g_list_reverse (deps);
+	}
+
+	for (l = deps; l; l = l->next) {
+		GnmDependent *dep = l->data;
+		if (dependent_needs_recalc (dep))
+			dependent_eval (dep);
+	}
+
+	g_list_free (deps);
+
 	/*
 	 * This is a bit of a band-aid.  If anything is recalculated, we
 	 * force a full redraw.  The alternative is to ask for updates
 	 * of every cell that is changed and that is probably more
 	 * expensive.
 	 */
-	if (redraw) {
-		g_signal_emit_by_name (gnm_app_get_app (), "recalc-finished");
+	g_signal_emit_by_name (gnm_app_get_app (), "recalc-finished");
 
-		WORKBOOK_FOREACH_SHEET (wb, sheet, {
-			SHEET_FOREACH_VIEW (sheet, sv, sv_flag_selection_change (sv););
-			sheet_redraw_all (sheet, FALSE);});
-	}
+	WORKBOOK_FOREACH_SHEET (wb, sheet, {
+		SHEET_FOREACH_VIEW (sheet, sv, sv_flag_selection_change (sv););
+		sheet_redraw_all (sheet, FALSE);
+	});
 }
 
 /**
