[gnumeric] Deps: delay redraws triggered by conditional styling.



commit 7aa3a3542ca82dc1c848f0cbcba85fdf9f2bf481
Author: Morten Welinder <terra gnome org>
Date:   Sun Apr 26 16:26:11 2020 -0400

    Deps: delay redraws triggered by conditional styling.
    
    Do them in the main loop.

 ChangeLog       | 10 +++++++
 NEWS            |  2 +-
 src/dependent.c | 15 ++++++----
 src/sheet.c     | 85 +++++++++++++++++++++++++++++++++++++++++++--------------
 src/sheet.h     |  6 +++-
 5 files changed, 90 insertions(+), 28 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 7b616e757..679e3dd97 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2020-04-26  Morten Welinder  <terra gnome org>
+
+       * src/dependent.c (style_dep_unrender): Queue the redraw instead
+       of doing it.
+
+       * src/sheet.c (sheet_redraw_region): We don't need the redraw-all
+       hack here.  It's also in sc_redraw_range.
+       (sheet_queue_redraw_range): New function for queueing redraws that
+       we cannot actually handle happening right now.
+
 2020-04-26  Jean Brefort  <jean brefort normalesup org>
 
        * src/sheet-object-component.c (sheet_object_component_new): really fix
diff --git a/NEWS b/NEWS
index 3503bb0c9..c9ecb7631 100644
--- a/NEWS
+++ b/NEWS
@@ -13,7 +13,7 @@ Morten:
        * Doc fixes.
        * Fix CELL crash.  [#479]
        * Handle export options for ssconvert --export-graphs.
-       * Fix deps cash.  [#480]
+       * Fix deps crash.  [#480]
 
 --------------------------------------------------------------------------
 Gnumeric 1.12.46
diff --git a/src/dependent.c b/src/dependent.c
index 432385309..988641b76 100644
--- a/src/dependent.c
+++ b/src/dependent.c
@@ -1377,6 +1377,7 @@ style_dep_unrender (GnmDependent *dep, const char *what)
        GnmCellPos const *pos = dependent_pos (dep);
        GnmCell *cell;
        Sheet *sheet = dep->sheet;
+       GnmRange r;
 
        if (debug_style_deps ())
                g_printerr ("StyleDep %p at %s %s\n",
@@ -1390,9 +1391,12 @@ style_dep_unrender (GnmDependent *dep, const char *what)
        if (cell)
                gnm_cell_unrender (cell);
 
-       sheet_redraw_region (sheet,
-                            pos->col, pos->row,
-                            pos->col, pos->row);
+       // Redraws may involve computation (via conditional styling,
+       // for example) so doing it now is no good.  See #480 for a
+       // particular nasty example involving conditional styling and
+       // dynamic dependents.
+       range_init_cellpos (&r, pos);
+       sheet_queue_redraw_range (sheet, &r);
 }
 
 static void
@@ -2881,11 +2885,10 @@ dynamic_dep_free (DynamicDep *dyn)
 {
        GnmDependent *dep = dyn->container;
        GnmCellPos const *pos = dependent_pos (dep);
-       GnmRangeRef *rr;
        GSList *ptr;
 
        for (ptr = dyn->singles ; ptr != NULL ; ptr = ptr->next) {
-               rr = ptr->data;
+               GnmRangeRef *rr = ptr->data;
                unlink_single_dep (&dyn->base, pos, &rr->a);
                g_free (rr);
        }
@@ -2893,7 +2896,7 @@ dynamic_dep_free (DynamicDep *dyn)
        dyn->singles = NULL;
 
        for (ptr = dyn->ranges ; ptr != NULL ; ptr = ptr->next) {
-               rr = ptr->data;
+               GnmRangeRef *rr = ptr->data;
                link_unlink_cellrange_dep (&dyn->base, pos,
                                           &rr->a, &rr->b, FALSE);
                g_free (rr);
diff --git a/src/sheet.c b/src/sheet.c
index 02cd6e503..f44620c87 100644
--- a/src/sheet.c
+++ b/src/sheet.c
@@ -853,6 +853,8 @@ gnm_sheet_init (Sheet *sheet)
        sheet->style_data = NULL;
 
        sheet->index_in_wb = -1;
+
+       sheet->pending_redraw_src = 0;
 }
 
 static Sheet the_invalid_sheet;
@@ -3204,45 +3206,85 @@ void
 sheet_redraw_region (Sheet const *sheet,
                     int start_col, int start_row,
                     int end_col,   int end_row)
+{
+       GnmRange r;
+       g_return_if_fail (IS_SHEET (sheet));
+
+       range_init (&r, start_col, start_row, end_col, end_row);
+       sheet_redraw_range (sheet, &r);
+}
+
+
+/**
+ * sheet_redraw_range:
+ * @sheet: sheet to redraw
+ * @range: range to redraw
+ *
+ * Redraw the indicated range, or at least the visible parts of it.
+ */
+void
+sheet_redraw_range (Sheet const *sheet, GnmRange const *range)
 {
        GnmRange bound;
 
        g_return_if_fail (IS_SHEET (sheet));
+       g_return_if_fail (range != NULL);
 
-       /*
-        * Getting the bounding box causes row respans to be done if
-        * needed.  That can be expensive, so just redraw the whole
-        * sheet if the row count is too big.
-        */
-       if (end_row - start_row > 500) {
-               sheet_redraw_all (sheet, FALSE);
-               return;
-       }
-
-       /* We potentially do a lot of recalcs as part of this, so make sure
-          stuff that caches sub-computations see the whole thing instead
-          of clearing between cells.  */
+       // We potentially do a lot of recalcs as part of this, so make sure
+       // stuff that caches sub-computations see the whole thing instead
+       // of clearing between cells.
        gnm_app_recalc_start ();
 
-       sheet_range_bounding_box (sheet,
-               range_init (&bound, start_col, start_row, end_col, end_row));
+       bound = *range;
+       sheet_range_bounding_box (sheet, &bound);
+
        SHEET_FOREACH_CONTROL (sheet, view, control,
                sc_redraw_range (control, &bound););
 
        gnm_app_recalc_finish ();
 }
 
+static gboolean
+cb_pending_redraw_handler (Sheet *sheet)
+{
+       while (sheet->pending_redraw) {
+               GnmRange *r = sheet->pending_redraw->data;
+               sheet->pending_redraw =
+                       g_slist_delete_link (sheet->pending_redraw,
+                                            sheet->pending_redraw);
+               sheet_redraw_range (sheet, r);
+               g_free (r);
+       }
+
+       sheet->pending_redraw_src = 0;
+       return FALSE;
+}
+
+/**
+ * sheet_queue_redraw_range:
+ * @sheet: sheet to redraw
+ * @range: range to redraw
+ *
+ * This queues a redraw for the indicated range.  The redraw will happen
+ * when Gnumeric returns to the gui main loop.
+ */
 void
-sheet_redraw_range (Sheet const *sheet, GnmRange const *range)
+sheet_queue_redraw_range (Sheet *sheet, GnmRange const *range)
 {
        g_return_if_fail (IS_SHEET (sheet));
        g_return_if_fail (range != NULL);
 
-       sheet_redraw_region (sheet,
-                            range->start.col, range->start.row,
-                            range->end.col, range->end.row);
+       sheet->pending_redraw =
+               g_slist_prepend (sheet->pending_redraw,
+                                g_memdup (range, sizeof (*range)));
+       if (sheet->pending_redraw_src == 0)
+               sheet->pending_redraw_src =
+                       g_timeout_add (0,
+                                      (GSourceFunc)cb_pending_redraw_handler,
+                                      sheet);
 }
 
+
 /****************************************************************************/
 
 gboolean
@@ -4852,7 +4894,10 @@ gnm_sheet_finalize (GObject *obj)
 
        sheet_style_shutdown (sheet);
 
-       (void) g_idle_remove_by_data (sheet);
+       if (sheet->pending_redraw_src) {
+               g_source_remove (sheet->pending_redraw_src);
+               sheet->pending_redraw_src = 0;
+       }
 
        if (debug_FMR) {
                g_printerr ("Sheet %p is %s\n", sheet, sheet->name_quoted);
diff --git a/src/sheet.h b/src/sheet.h
index 83b56e238..4ec65cc50 100644
--- a/src/sheet.h
+++ b/src/sheet.h
@@ -107,6 +107,9 @@ struct _Sheet {
 
        GnmDepContainer *deps;
 
+       GSList *pending_redraw;
+       guint pending_redraw_src;
+
        GSList           *slicers;
        GSList           *filters;
        GSList           *list_merged;
@@ -316,7 +319,8 @@ gconstpointer gnm_sheet_find_sort_setup (Sheet *sheet, char const *key);
 /* Redraw */
 #define sheet_is_visible(_sheet) ((_sheet)->visibility == GNM_SHEET_VISIBILITY_VISIBLE)
 void     sheet_redraw_all       (Sheet const *sheet, gboolean header);
-void     sheet_redraw_range     (Sheet const *sheet, GnmRange const *r);
+void     sheet_redraw_range     (Sheet const *sheet, GnmRange const *range);
+void     sheet_queue_redraw_range (Sheet *sheet, GnmRange const *range);
 void     sheet_redraw_region    (Sheet const *sheet,
                                 int start_col, int start_row,
                                 int end_col,   int end_row);


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