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.
This commit is contained in:
+141
-76
@@ -107,6 +107,13 @@ struct _GcalYearView
|
|||||||
|
|
||||||
/* date property */
|
/* date property */
|
||||||
icaltimetype *date;
|
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 {
|
enum {
|
||||||
@@ -676,6 +683,45 @@ calculate_day_month_for_coord (GcalYearView *year_view,
|
|||||||
*out_day = day;
|
*out_day = day;
|
||||||
return TRUE;
|
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
|
static void
|
||||||
draw_month_grid (GcalYearView *year_view,
|
draw_month_grid (GcalYearView *year_view,
|
||||||
@@ -699,8 +745,7 @@ draw_month_grid (GcalYearView *year_view,
|
|||||||
gint days_delay, days, shown_rows, sunday_idx;
|
gint days_delay, days, shown_rows, sunday_idx;
|
||||||
gchar *str, *nr_day, *nr_week;
|
gchar *str, *nr_day, *nr_week;
|
||||||
gboolean selected_day;
|
gboolean selected_day;
|
||||||
GList *events;
|
icaltimetype today;
|
||||||
icaltimetype start_date, end_date;
|
|
||||||
|
|
||||||
now = g_date_time_new_now_local ();
|
now = g_date_time_new_now_local ();
|
||||||
|
|
||||||
@@ -768,18 +813,13 @@ draw_month_grid (GcalYearView *year_view,
|
|||||||
shown_rows = ceil (days / 7.0);
|
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);
|
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;
|
today.year = year_view->date->year;
|
||||||
start_date.month = month_nr + 1;
|
today.month = month_nr + 1;
|
||||||
start_date.year = year_view->date->year;
|
today.day = 1;
|
||||||
start_date.hour = 0;
|
today.hour = 0;
|
||||||
start_date.minute = 0;
|
today.minute = 0;
|
||||||
start_date.second = 0;
|
today.second = 0;
|
||||||
end_date.day = 1;
|
today.zone = gcal_manager_get_system_timezone (year_view->manager);
|
||||||
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;
|
|
||||||
|
|
||||||
for (i = 0; i < 7 * shown_rows; i++)
|
for (i = 0; i < 7 * shown_rows; i++)
|
||||||
{
|
{
|
||||||
@@ -930,23 +970,25 @@ draw_month_grid (GcalYearView *year_view,
|
|||||||
layout);
|
layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
start_date.day = end_date.day = j;
|
/* Update the current day, so we can count the events at this day */
|
||||||
events = gcal_manager_get_events (year_view->manager, &start_date, &end_date);
|
today.day = j;
|
||||||
if (events != NULL)
|
|
||||||
|
if (count_events_at_day (year_view, &today) > 0)
|
||||||
{
|
{
|
||||||
gtk_style_context_save (context);
|
gtk_style_context_save (context);
|
||||||
gtk_style_context_add_class (context, "with-events");
|
gtk_style_context_add_class (context, "with-events");
|
||||||
|
|
||||||
if (selected_day)
|
if (selected_day)
|
||||||
gtk_style_context_add_class (context, "with-events-selected");
|
gtk_style_context_add_class (context, "with-events-selected");
|
||||||
else if (column == sunday_idx)
|
else if (column == sunday_idx)
|
||||||
gtk_style_context_add_class (context, "with-events-sunday");
|
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,
|
gtk_render_background (context, cr,
|
||||||
box_side * column + x + sw * box_padding_start - year_view->k * VISUAL_CLUES_SIDE,
|
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,
|
box_side * (row + 1) + y + box_padding_top + layout_height + 2.0,
|
||||||
VISUAL_CLUES_SIDE, VISUAL_CLUES_SIDE);
|
VISUAL_CLUES_SIDE, VISUAL_CLUES_SIDE);
|
||||||
gtk_style_context_restore (context);
|
gtk_style_context_restore (context);
|
||||||
g_list_free_full (events, g_object_unref);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free (nr_day);
|
g_free (nr_day);
|
||||||
@@ -1503,6 +1545,7 @@ static void
|
|||||||
gcal_year_view_finalize (GObject *object)
|
gcal_year_view_finalize (GObject *object)
|
||||||
{
|
{
|
||||||
GcalYearView *year_view = GCAL_YEAR_VIEW (object);
|
GcalYearView *year_view = GCAL_YEAR_VIEW (object);
|
||||||
|
guint i;
|
||||||
|
|
||||||
g_free (year_view->navigator_grid);
|
g_free (year_view->navigator_grid);
|
||||||
g_free (year_view->selected_data);
|
g_free (year_view->selected_data);
|
||||||
@@ -1514,6 +1557,9 @@ gcal_year_view_finalize (GObject *object)
|
|||||||
|
|
||||||
g_clear_object (&year_view->calendar_settings);
|
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);
|
G_OBJECT_CLASS (gcal_year_view_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1700,17 +1746,12 @@ gcal_year_view_component_added (ECalDataModelSubscriber *subscriber,
|
|||||||
ECalClient *client,
|
ECalClient *client,
|
||||||
ECalComponent *comp)
|
ECalComponent *comp)
|
||||||
{
|
{
|
||||||
GcalYearView *year_view = GCAL_YEAR_VIEW (subscriber);
|
GcalYearView *self = GCAL_YEAR_VIEW (subscriber);
|
||||||
|
GDateTime *event_start, *event_end;
|
||||||
GcalEvent *event;
|
GcalEvent *event;
|
||||||
GError *error;
|
GError *error;
|
||||||
GList **days_widgets_array;
|
|
||||||
GList *l;
|
GList *l;
|
||||||
gint i, days_span;
|
guint i, start_month, end_month;
|
||||||
|
|
||||||
ECalComponentDateTime date;
|
|
||||||
time_t event_start, event_end, range_start, range_end;
|
|
||||||
icaltimezone *zone;
|
|
||||||
|
|
||||||
error = NULL;
|
error = NULL;
|
||||||
event = gcal_event_new (e_client_get_source (E_CLIENT (client)), comp, &error);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
update_selected_dates_from_button_data (year_view);
|
event_start = gcal_event_get_date_start (event);
|
||||||
days_span = icaltime_day_of_year(*(year_view->end_selected_date)) - icaltime_day_of_year(*(year_view->start_selected_date)) + 1;
|
event_end = gcal_event_get_date_end (event);
|
||||||
days_widgets_array = g_new0 (GList*, days_span);
|
|
||||||
|
|
||||||
/* check if event belongs to range */
|
/* Calculate the start & end months */
|
||||||
zone = gcal_manager_get_system_timezone (year_view->manager);
|
start_month = g_date_time_get_month (event_start) - 1;
|
||||||
range_start = icaltime_as_timet_with_zone (*(year_view->start_selected_date), zone);
|
end_month = g_date_time_get_month (event_end) - 1;
|
||||||
range_end = icaltime_as_timet_with_zone (*(year_view->end_selected_date), zone);
|
|
||||||
|
|
||||||
e_cal_component_get_dtstart (comp, &date);
|
if (g_date_time_get_year (event_start) < self->date->year)
|
||||||
event_start = icaltime_as_timet_with_zone (*(date.value), date.value->zone != NULL ? date.value->zone : zone);
|
start_month = 0;
|
||||||
e_cal_component_free_datetime (&date);
|
|
||||||
|
|
||||||
e_cal_component_get_dtend (comp, &date);
|
if (g_date_time_get_year (event_end) > self->date->year)
|
||||||
if (date.value != NULL)
|
end_month = 11;
|
||||||
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 (!((event_start <= range_start && event_end >= range_end) ||
|
/* Add the event to the cache */
|
||||||
(event_start >= range_start && event_end <= range_end) ||
|
for (i = start_month; i <= end_month; i++)
|
||||||
(event_start >= range_start && event_start <= range_end) ||
|
g_ptr_array_add (self->events[i], event);
|
||||||
(event_end >= range_start && event_end <= range_end)))
|
|
||||||
{
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
add_event_to_day_array (year_view, event, days_widgets_array, days_span);
|
update_selected_dates_from_button_data (self);
|
||||||
gtk_stack_set_visible_child_name (GTK_STACK (year_view->navigator_stack), "events-list");
|
update_sidebar (self);
|
||||||
|
|
||||||
for (i = 0; i < days_span; i++)
|
gtk_widget_queue_draw (GTK_WIDGET (self->navigator));
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -1780,12 +1791,15 @@ gcal_year_view_component_changed (ECalDataModelSubscriber *subscriber,
|
|||||||
ECalClient *client,
|
ECalClient *client,
|
||||||
ECalComponent *comp)
|
ECalComponent *comp)
|
||||||
{
|
{
|
||||||
GcalYearView *year_view = GCAL_YEAR_VIEW (subscriber);
|
GcalYearView *self = GCAL_YEAR_VIEW (subscriber);
|
||||||
GList *children, *l;
|
GList *children, *l;
|
||||||
gchar *uuid;
|
gchar *uuid;
|
||||||
|
guint i;
|
||||||
|
|
||||||
uuid = get_uuid_from_component (e_client_get_source (E_CLIENT (client)), comp);
|
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))
|
for (l = children; l != NULL; l = g_list_next (l))
|
||||||
{
|
{
|
||||||
GcalEventWidget *child_widget;
|
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)));
|
child_widget = GCAL_EVENT_WIDGET (gtk_bin_get_child (GTK_BIN (l->data)));
|
||||||
event = gcal_event_widget_get_event (child_widget);
|
event = gcal_event_widget_get_event (child_widget);
|
||||||
|
|
||||||
if (child_widget != NULL && g_strcmp0 (uuid, gcal_event_get_uid (event)) == 0)
|
if (child_widget && g_strcmp0 (uuid, gcal_event_get_uid (event)) == 0)
|
||||||
gtk_widget_destroy (GTK_WIDGET (l->data));
|
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_list_free (children);
|
||||||
g_free (uuid);
|
g_free (uuid);
|
||||||
|
|
||||||
@@ -1813,6 +1849,7 @@ gcal_year_view_component_removed (ECalDataModelSubscriber *subscriber,
|
|||||||
GList *children, *l;
|
GList *children, *l;
|
||||||
ESource *source;
|
ESource *source;
|
||||||
gchar *uuid;
|
gchar *uuid;
|
||||||
|
guint i;
|
||||||
gint number_of_children;
|
gint number_of_children;
|
||||||
|
|
||||||
source = e_client_get_source (E_CLIENT (client));
|
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");
|
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_list_free (children);
|
||||||
g_free (uuid);
|
g_free (uuid);
|
||||||
}
|
}
|
||||||
@@ -1923,6 +1983,11 @@ gcal_year_view_class_init (GcalYearViewClass *klass)
|
|||||||
static void
|
static void
|
||||||
gcal_year_view_init (GcalYearView *self)
|
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));
|
gtk_widget_init_template (GTK_WIDGET (self));
|
||||||
|
|
||||||
if (gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_LTR)
|
if (gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_LTR)
|
||||||
|
|||||||
Reference in New Issue
Block a user