Index: dependent.c
===================================================================
RCS file: /cvs/gnome/gnumeric/src/dependent.c,v
retrieving revision 1.214
diff -u -r1.214 dependent.c
--- dependent.c	21 Jul 2003 18:12:09 -0000	1.214
+++ dependent.c	21 Jul 2003 19:08:29 -0000
@@ -1753,6 +1753,60 @@
 
 /*******************************************************************/
 
+/*
+ * Return a list of unevalled dependencies in deepest-first order.
+ * This will typically include itself at the end.
+ */
+GSList *
+dependent_unevalled_deps (GSList *deps)
+{
+	GSList *result = NULL, *lastresult = NULL;
+
+	while (deps) {
+		GSList *stack = g_slist_prepend (NULL, deps->data);
+		GSList *thisresult = NULL;
+
+		deps = deps->next;
+
+		while (stack) {
+			Dependent *dep = stack->data;
+			GSList *next;
+
+			next = stack->next;
+			g_slist_free_1 (stack);
+			stack = next;
+
+			if (dependent_is_cell (dep) &&
+			    dependent_needs_recalc (dep) &&
+			    (dep->flags & DEPENDENT_BEING_CALCULATED) == 0 &&
+			    cell_has_expr ((const Cell *)dep)) {
+				Cell *cell = (Cell *)dep;
+				EvalPos pos;
+
+				dep->flags |= DEPENDENT_BEING_CALCULATED;
+				eval_pos_init_cell (&pos, cell);
+				gnm_expr_unevalled_deps (cell->base.expression, &pos, &stack);
+				thisresult = g_slist_prepend (thisresult, cell);
+			}
+		}
+
+		if (lastresult)
+			lastresult->next = thisresult;
+		else
+			result = lastresult = thisresult;
+		lastresult = g_slist_last (lastresult);
+	}
+
+	for (deps = result; deps; deps = deps->next) {
+		Dependent *dep = deps->data;
+		dep->flags &= ~DEPENDENT_BEING_CALCULATED;
+	}
+
+	return result;
+}
+
+/*******************************************************************/
+
 inline static void
 invalidate_refs (Dependent *dep, GnmExprRewriteInfo const *rwinfo)
 {
@@ -2042,10 +2096,50 @@
 workbook_recalc (Workbook *wb)
 {
 	gboolean redraw = FALSE;
+	GSList *dirty = NULL, *dirty_order, *tmp;
 
 	g_return_if_fail (IS_WORKBOOK (wb));
 
-	WORKBOOK_FOREACH_DEPENDENT (wb, dep, redraw |= dependent_eval (dep););
+	WORKBOOK_FOREACH_DEPENDENT (wb, dep, {
+		if (dependent_needs_recalc (dep))
+			dirty = g_slist_prepend (dirty, dep);
+	});
+	dirty_order = dependent_unevalled_deps (dirty);
+
+	for (tmp = dirty_order; tmp; tmp = tmp->next) {
+		Dependent *dep = tmp->data;
+
+		if (!dependent_needs_recalc (dep)) {
+			g_print ("Dependent %s turned non-dirty.\n",
+				 dependent_is_cell (dep)
+				 ? cellpos_as_string (&((Cell *)dep)->pos)
+				 : "(non-cell)");
+			continue;
+		}
+
+		if (dependent_is_cell (dep)) {
+			g_print ("Doing %s...\n",
+				 cellpos_as_string (&((Cell *)dep)->pos));
+		} else {
+			g_print ("Doing non-cell...\n");
+		}
+
+		redraw |= dependent_eval (dep);
+	}
+	g_slist_free (dirty_order);
+
+	for (tmp = dirty; tmp; tmp = tmp->next) {
+		Dependent *dep = tmp->data;
+
+		if (!dependent_needs_recalc (dep))
+			continue;
+
+		g_print ("Unexpected dirty dependent.\n");
+
+		redraw |= dependent_eval (dep);
+	}
+	g_slist_free (dirty);
+
 	if (redraw) {
 		WORKBOOK_FOREACH_SHEET (wb, sheet, sheet_redraw_all (sheet, FALSE););
 	}
Index: dependent.h
===================================================================
RCS file: /cvs/gnome/gnumeric/src/dependent.h,v
retrieving revision 1.61
diff -u -r1.61 dependent.h
--- dependent.h	27 Mar 2003 19:35:24 -0000	1.61
+++ dependent.h	21 Jul 2003 19:08:29 -0000
@@ -107,6 +107,8 @@
 	}								\
 }
 
+GSList *dependent_unevalled_deps (GSList *deps);
+
 void sheet_region_queue_recalc	 (Sheet const *sheet, Range const *range);
 void sheet_deps_destroy		 (Sheet *sheet);
 void workbook_deps_destroy	 (Workbook *wb);
Index: expr.c
===================================================================
RCS file: /cvs/gnome/gnumeric/src/expr.c,v
retrieving revision 1.325
diff -u -r1.325 expr.c
--- expr.c	7 Jul 2003 16:39:22 -0000	1.325
+++ expr.c	21 Jul 2003 19:08:30 -0000
@@ -1101,6 +1101,132 @@
 	return value_new_error (pos, _("Unknown evaluation error"));
 }
 
+/*
+ * Input:   [e1,e2,...,en] and res
+ * Output:  f(e1) @ f(e2) @ ... @ f(en) @ res
+ *
+ * The f calls are performed left-to-right (which is important since they
+ * set and test flags).
+ */
+static void
+gnm_expr_unevalled_deps_list (const GSList *exprs, EvalPos const *pos, GSList **pres)
+{
+	GSList *results = NULL;
+
+	while (exprs) {
+		GSList *thisres = NULL;
+		gnm_expr_unevalled_deps (exprs->data, pos, &thisres);
+		results = g_slist_prepend (results, thisres);
+		exprs = exprs->next;
+	}
+
+	while (results) {
+		GSList *thisres = results->data;
+		GSList *next = results->next;
+
+		g_slist_free_1 (results);
+		results = next;
+
+		if (thisres) {
+			g_slist_last (thisres)->next = *pres;
+			*pres = thisres;
+		}
+	}
+}
+
+static Value *
+cb_gnm_expr_unevalled_deps (Sheet *sheet, int col, int row,
+			    Cell *cell, gpointer user_data)
+{
+	GSList **pres = user_data;
+	Dependent *dep = (Dependent *)cell;
+
+	if (cell &&
+	    cell_needs_recalc (cell) &&
+	    (dep->flags & DEPENDENT_BEING_CALCULATED) == 0)
+		(*pres) = g_slist_prepend (*pres, cell);
+
+	return NULL;
+}
+
+
+void
+gnm_expr_unevalled_deps (const GnmExpr *expr, EvalPos const *pos, GSList **pres)
+{
+	switch (expr->any.oper) {
+	case GNM_EXPR_OP_RANGE_CTOR:
+	case GNM_EXPR_OP_INTERSECT:
+	case GNM_EXPR_OP_ANY_BINARY: {
+		GSList *l = NULL;
+
+		l = g_slist_prepend (l, (gpointer)expr->binary.value_b);
+		l = g_slist_prepend (l, (gpointer)expr->binary.value_a);
+		gnm_expr_unevalled_deps_list (l, pos, pres);
+		g_slist_free (l);
+		return;
+	}
+
+	case GNM_EXPR_OP_ANY_UNARY:
+		gnm_expr_unevalled_deps (expr->unary.value, pos, pres);
+		return;
+
+	case GNM_EXPR_OP_FUNCALL:
+		gnm_expr_unevalled_deps_list (expr->func.arg_list, pos, pres);
+		return;
+
+	case GNM_EXPR_OP_NAME:
+		g_warning ("FIXME");
+		return;
+
+	case GNM_EXPR_OP_CELLREF: {
+		CellRef const * const ref = &expr->cellref.ref;
+		Cell *cell;
+		CellPos dest;
+		const Dependent *dep;
+
+		cellref_get_abs_pos (ref, &pos->eval, &dest);
+
+		cell = sheet_cell_get (eval_sheet (ref->sheet, pos->sheet),
+				       dest.col, dest.row);
+		dep = (const Dependent *)cell;
+		if (cell &&
+		    cell_needs_recalc (cell) &&
+		    (dep->flags & DEPENDENT_BEING_CALCULATED) == 0)
+			(*pres) = g_slist_prepend (*pres, cell);
+
+		return;
+	}
+
+	case GNM_EXPR_OP_CONSTANT: {
+		Value const *v = expr->constant.value;
+
+		if (v->type != VALUE_CELLRANGE)
+			return;
+
+		workbook_foreach_cell_in_range (pos, v, CELL_ITER_IGNORE_BLANK,
+						cb_gnm_expr_unevalled_deps,
+						pres);
+		return;
+	}
+
+	case GNM_EXPR_OP_ARRAY: {
+		int const x = expr->array.x;
+		int const y = expr->array.y;
+		if (x == 0 || y == 0)
+			gnm_expr_unevalled_deps (expr->array.corner.expr,
+						 pos, pres);
+		return;
+        }
+
+	case GNM_EXPR_OP_SET:
+		/* FIXME: should this just return as gnm_expr_eval does?  */
+		gnm_expr_unevalled_deps_list (expr->set.set, pos, pres);
+		return;
+	}
+}
+
+
+
 static void
 gnm_expr_list_as_string (GString *target,
 			 GnmExprList const *list, ParsePos const *pp,
Index: expr.h
===================================================================
RCS file: /cvs/gnome/gnumeric/src/expr.h,v
retrieving revision 1.144
diff -u -r1.144 expr.h
--- expr.h	27 Mar 2003 19:35:25 -0000	1.144
+++ expr.h	21 Jul 2003 19:08:30 -0000
@@ -111,6 +111,9 @@
 Value *gnm_expr_eval (GnmExpr const *expr, EvalPos const *pos,
 		      GnmExprEvalFlags flags);
 
+void gnm_expr_unevalled_deps (const GnmExpr *expr, EvalPos const *pos,
+			      GSList **pres);
+
 /*****************************************************************************/
 
 #define gnm_expr_list_nth(l,n)	   (GnmExpr const *)g_slist_nth_data ((l), n)
