[gnome-calendar] year-view: optimize drawing



commit a7d7726a357b837613f2aa7e8749035e5ecf4fff
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Sat Mar 25 11:19:51 2017 -0300

    year-view: optimize drawing
    
    The current Year view drawing routine gathers events
    every single time we draw the navigator. This is, to
    the best case, slow to death. In fact, this is why
    year view's navigator is so memory and processor
    consuming.
    
    To fix that, cache the added components and simply
    query them at drawing time.

 src/views/gcal-year-view.c |  217 ++++++++++++++++++++++++++++---------------
 1 files changed, 141 insertions(+), 76 deletions(-)
---
diff --git a/src/views/gcal-year-view.c b/src/views/gcal-year-view.c
index feea657..d374b9f 100644
--- a/src/views/gcal-year-view.c
+++ b/src/views/gcal-year-view.c
@@ -107,6 +107,13 @@ struct _GcalYearView
 
   /* date property */
   icaltimetype *date;
+
+  /*
+   * Array with the events at every month. Events
+   * that span multiple months are added multiple
+   * times to the array.
+   */
+  GPtrArray    *events[12];
 };
 
 enum {
@@ -676,6 +683,45 @@ calculate_day_month_for_coord (GcalYearView *year_view,
   *out_day = day;
   return TRUE;
 }
+static guint
+count_events_at_day (GcalYearView *self,
+                     icaltimetype *today)
+{
+  g_autoptr (GDateTime) today_start, today_end;
+  GPtrArray *events;
+  guint i, n_events;
+
+  events = self->events[today->month - 1];
+  n_events = 0;
+  today_start = icaltime_to_datetime (today);
+  today_end = g_date_time_add_days (today_start, 1);
+
+  for (i = 0; i < events->len; i++)
+    {
+      g_autoptr (GDateTime) event_start, event_end;
+      GcalEvent *event;
+
+      event = g_ptr_array_index (events, i);
+
+      event_start = g_date_time_ref (gcal_event_get_date_start (event));
+
+      if (gcal_event_get_all_day (event))
+          event_end = g_date_time_add_days (gcal_event_get_date_end (event), -1);
+      else
+          event_end = g_date_time_ref (gcal_event_get_date_end (event));
+
+
+      if (datetime_compare_date (event_start, today_end) >= 0 ||
+          datetime_compare_date (event_end, today_start) < 0)
+        {
+          continue;
+        }
+
+      n_events++;
+    }
+
+  return n_events;
+}
 
 static void
 draw_month_grid (GcalYearView *year_view,
@@ -699,8 +745,7 @@ draw_month_grid (GcalYearView *year_view,
   gint days_delay, days, shown_rows, sunday_idx;
   gchar *str, *nr_day, *nr_week;
   gboolean selected_day;
-  GList *events;
-  icaltimetype start_date, end_date;
+  icaltimetype today;
 
   now = g_date_time_new_now_local ();
 
@@ -768,18 +813,13 @@ draw_month_grid (GcalYearView *year_view,
   shown_rows = ceil (days / 7.0);
   sunday_idx = year_view->k * 7 + sw * ((7 - year_view->first_weekday) % 7) + year_view->show_week_numbers * 
(1 - year_view->k);
 
-  start_date.day    = 1;
-  start_date.month  = month_nr + 1;
-  start_date.year   = year_view->date->year;
-  start_date.hour   = 0;
-  start_date.minute = 0;
-  start_date.second = 0;
-  end_date.day    = 1;
-  end_date.month  = month_nr + 1;
-  end_date.year   = year_view->date->year;
-  end_date.hour   = 23;
-  end_date.minute = 59;
-  end_date.second = 59;
+  today.year = year_view->date->year;
+  today.month = month_nr + 1;
+  today.day = 1;
+  today.hour = 0;
+  today.minute = 0;
+  today.second = 0;
+  today.zone = gcal_manager_get_system_timezone (year_view->manager);
 
   for (i = 0; i < 7 * shown_rows; i++)
     {
@@ -930,23 +970,25 @@ draw_month_grid (GcalYearView *year_view,
                              layout);
         }
 
-      start_date.day = end_date.day = j;
-      events = gcal_manager_get_events (year_view->manager, &start_date, &end_date);
-      if (events != NULL)
+      /* Update the current day, so we can count the events at this day */
+      today.day = j;
+
+      if (count_events_at_day (year_view, &today) > 0)
         {
           gtk_style_context_save (context);
           gtk_style_context_add_class (context, "with-events");
+
           if (selected_day)
             gtk_style_context_add_class (context, "with-events-selected");
           else if (column == sunday_idx)
             gtk_style_context_add_class (context, "with-events-sunday");
-          box_padding_start = (box_side - VISUAL_CLUES_SIDE) / 2 > 0 ? (box_side - VISUAL_CLUES_SIDE) / 2 : 
0;
+
+          box_padding_start = MAX (0, (box_side - VISUAL_CLUES_SIDE) / 2);
           gtk_render_background (context, cr,
                                  box_side * column + x + sw * box_padding_start - year_view->k * 
VISUAL_CLUES_SIDE,
                                  box_side * (row + 1) + y + box_padding_top + layout_height + 2.0,
                                  VISUAL_CLUES_SIDE, VISUAL_CLUES_SIDE);
           gtk_style_context_restore (context);
-          g_list_free_full (events, g_object_unref);
         }
 
       g_free (nr_day);
@@ -1503,6 +1545,7 @@ static void
 gcal_year_view_finalize (GObject *object)
 {
   GcalYearView *year_view = GCAL_YEAR_VIEW (object);
+  guint i;
 
   g_free (year_view->navigator_grid);
   g_free (year_view->selected_data);
@@ -1514,6 +1557,9 @@ gcal_year_view_finalize (GObject *object)
 
   g_clear_object (&year_view->calendar_settings);
 
+  for (i = 0; i < 12; i++)
+    g_clear_pointer (&year_view->events[i], g_ptr_array_unref);
+
   G_OBJECT_CLASS (gcal_year_view_parent_class)->finalize (object);
 }
 
@@ -1700,17 +1746,12 @@ gcal_year_view_component_added (ECalDataModelSubscriber *subscriber,
                                 ECalClient              *client,
                                 ECalComponent           *comp)
 {
-  GcalYearView *year_view = GCAL_YEAR_VIEW (subscriber);
-
+  GcalYearView *self = GCAL_YEAR_VIEW (subscriber);
+  GDateTime *event_start, *event_end;
   GcalEvent *event;
   GError *error;
-  GList **days_widgets_array;
   GList *l;
-  gint i, days_span;
-
-  ECalComponentDateTime date;
-  time_t event_start, event_end, range_start, range_end;
-  icaltimezone *zone;
+  guint i, start_month, end_month;
 
   error = NULL;
   event = gcal_event_new (e_client_get_source (E_CLIENT (client)), comp, &error);
@@ -1722,57 +1763,27 @@ gcal_year_view_component_added (ECalDataModelSubscriber *subscriber,
       return;
     }
 
-  update_selected_dates_from_button_data (year_view);
-  days_span = icaltime_day_of_year(*(year_view->end_selected_date)) - 
icaltime_day_of_year(*(year_view->start_selected_date)) + 1;
-  days_widgets_array = g_new0 (GList*, days_span);
+  event_start = gcal_event_get_date_start (event);
+  event_end = gcal_event_get_date_end (event);
 
-  /* check if event belongs to range */
-  zone = gcal_manager_get_system_timezone (year_view->manager);
-  range_start = icaltime_as_timet_with_zone (*(year_view->start_selected_date), zone);
-  range_end = icaltime_as_timet_with_zone (*(year_view->end_selected_date), zone);
+  /* Calculate the start & end months */
+  start_month = g_date_time_get_month (event_start) - 1;
+  end_month = g_date_time_get_month (event_end) - 1;
 
-  e_cal_component_get_dtstart (comp, &date);
-  event_start = icaltime_as_timet_with_zone (*(date.value), date.value->zone != NULL ? date.value->zone : 
zone);
-  e_cal_component_free_datetime (&date);
+  if (g_date_time_get_year (event_start) < self->date->year)
+    start_month = 0;
 
-  e_cal_component_get_dtend (comp, &date);
-  if (date.value != NULL)
-    event_end = icaltime_as_timet_with_zone (*(date.value), date.value->zone != NULL ? date.value->zone : 
zone);
-  else
-    event_end = event_start;
-  e_cal_component_free_datetime (&date);
+  if (g_date_time_get_year (event_end) > self->date->year)
+    end_month = 11;
 
-  if (!((event_start <= range_start && event_end >= range_end) ||
-        (event_start >= range_start && event_end <= range_end) ||
-        (event_start >= range_start && event_start <= range_end) ||
-        (event_end >= range_start && event_end <= range_end)))
-    {
-      goto out;
-    }
+  /* Add the event to the cache */
+  for (i = start_month; i <= end_month; i++)
+    g_ptr_array_add (self->events[i], event);
 
-  add_event_to_day_array (year_view, event, days_widgets_array, days_span);
-  gtk_stack_set_visible_child_name (GTK_STACK (year_view->navigator_stack), "events-list");
+  update_selected_dates_from_button_data (self);
+  update_sidebar (self);
 
-  for (i = 0; i < days_span; i++)
-    {
-      GList *current_day = days_widgets_array[i];
-      for (l = current_day; l != NULL; l = g_list_next (l))
-        {
-          GtkWidget *child_widget = l->data;
-          gtk_widget_show (child_widget);
-          g_signal_connect (child_widget, "activate", G_CALLBACK (event_activated), year_view);
-          g_object_set_data (G_OBJECT (child_widget), "shift", GINT_TO_POINTER (i));
-          gtk_container_add (GTK_CONTAINER (year_view->events_sidebar), child_widget);
-        }
-
-      g_list_free (current_day);
-    }
-
-  gtk_widget_queue_draw (year_view->navigator);
-
-out:
-  g_clear_object (&event);
-  g_free (days_widgets_array);
+  gtk_widget_queue_draw (GTK_WIDGET (self->navigator));
 }
 
 static void
@@ -1780,12 +1791,15 @@ gcal_year_view_component_changed (ECalDataModelSubscriber *subscriber,
                                   ECalClient              *client,
                                   ECalComponent           *comp)
 {
-  GcalYearView *year_view = GCAL_YEAR_VIEW (subscriber);
+  GcalYearView *self = GCAL_YEAR_VIEW (subscriber);
   GList *children, *l;
   gchar *uuid;
+  guint i;
 
   uuid = get_uuid_from_component (e_client_get_source (E_CLIENT (client)), comp);
-  children = gtk_container_get_children (GTK_CONTAINER (year_view->events_sidebar));
+  children = gtk_container_get_children (GTK_CONTAINER (self->events_sidebar));
+
+  /* Remove from the sidebar */
   for (l = children; l != NULL; l = g_list_next (l))
     {
       GcalEventWidget *child_widget;
@@ -1794,9 +1808,31 @@ gcal_year_view_component_changed (ECalDataModelSubscriber *subscriber,
       child_widget = GCAL_EVENT_WIDGET (gtk_bin_get_child (GTK_BIN (l->data)));
       event = gcal_event_widget_get_event (child_widget);
 
-      if (child_widget != NULL && g_strcmp0 (uuid, gcal_event_get_uid (event)) == 0)
-        gtk_widget_destroy (GTK_WIDGET (l->data));
+      if (child_widget && g_strcmp0 (uuid, gcal_event_get_uid (event)) == 0)
+        gtk_widget_destroy (l->data);
     }
+
+  /* Also remove from the cached list of events */
+  for (i = 0; i < 12; i++)
+    {
+      GPtrArray *events;
+      guint j;
+
+      events = self->events[i];
+
+      for (j = 0; j < events->len; j++)
+        {
+          GcalEvent *event;
+
+          event = g_ptr_array_index (events, j);
+
+          if (g_strcmp0 (gcal_event_get_uid (event), uuid) != 0)
+            continue;
+
+          g_ptr_array_remove (events, event);
+        }
+    }
+
   g_list_free (children);
   g_free (uuid);
 
@@ -1813,6 +1849,7 @@ gcal_year_view_component_removed (ECalDataModelSubscriber *subscriber,
   GList *children, *l;
   ESource *source;
   gchar *uuid;
+  guint i;
   gint number_of_children;
 
   source = e_client_get_source (E_CLIENT (client));
@@ -1849,6 +1886,29 @@ gcal_year_view_component_removed (ECalDataModelSubscriber *subscriber,
       gtk_stack_set_visible_child_name (GTK_STACK (year_view->navigator_stack), "no-events");
     }
 
+  /* Also remove from the cached list of events */
+  for (i = 0; i < 12; i++)
+    {
+      GPtrArray *events;
+      guint j;
+
+      events = year_view->events[i];
+
+      for (j = 0; j < events->len; j++)
+        {
+          GcalEvent *event;
+
+          event = g_ptr_array_index (events, j);
+
+          if (g_strcmp0 (gcal_event_get_uid (event), uuid) != 0)
+            continue;
+
+          g_ptr_array_remove (events, event);
+        }
+    }
+
+  gtk_widget_queue_draw (GTK_WIDGET (year_view->navigator));
+
   g_list_free (children);
   g_free (uuid);
 }
@@ -1923,6 +1983,11 @@ gcal_year_view_class_init (GcalYearViewClass *klass)
 static void
 gcal_year_view_init (GcalYearView *self)
 {
+  guint i;
+
+  for (i = 0; i < 12; i++)
+    self->events[i] = g_ptr_array_new ();
+
   gtk_widget_init_template (GTK_WIDGET (self));
 
   if (gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_LTR)


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