views/week: Port to GPtrArray

GLists are an artifact of times immemorial and we should
avoid using them as much as possible. In this commit, for
example, there were a couple of accidentally quadratic
pieces of code.

Port (mostly of) the week view header to GPtrArray.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-calendar/-/merge_requests/742>
This commit is contained in:
Georges Basile Stavracas Neto
2026-05-03 16:57:51 +00:00
committed by Marge Bot
parent 039b75755e
commit c635db3495
+61 -61
View File
@@ -83,7 +83,7 @@ struct _GcalWeekHeader
* The list will later be iterated after the active date is changed * The list will later be iterated after the active date is changed
* and the events will be placed * and the events will be placed
*/ */
GList *events[N_WEEKDAYS]; GPtrArray *events[N_WEEKDAYS];
GtkWidget *overflow_label[N_WEEKDAYS]; GtkWidget *overflow_label[N_WEEKDAYS];
WeekdayHeader weekday_header[N_WEEKDAYS]; WeekdayHeader weekday_header[N_WEEKDAYS];
@@ -377,12 +377,12 @@ get_event_by_uuid (GcalWeekHeader *self,
for (weekday = 0; weekday < N_WEEKDAYS; weekday++) for (weekday = 0; weekday < N_WEEKDAYS; weekday++)
{ {
GList *l; for (gsize i = 0; i < self->events[weekday]->len; i++)
for (l = self->events[weekday]; l != NULL; l = l->next)
{ {
if (g_strcmp0 (gcal_event_get_uid (l->data), uuid) == 0) GcalEvent *event = g_ptr_array_index (self->events[weekday], i);
return l->data;
if (g_strcmp0 (gcal_event_get_uid (event), uuid) == 0)
return event;
} }
} }
@@ -408,15 +408,15 @@ get_today_column (GcalWeekHeader *self)
} }
static gint static gint
compare_events_by_length (GcalEvent *event1, compare_events_by_length (GcalEvent **event1,
GcalEvent *event2) GcalEvent **event2)
{ {
/* Multiday events should come before single day events */ /* Multiday events should come before single day events */
if (gcal_event_is_multiday (event1) != gcal_event_is_multiday (event2)) if (gcal_event_is_multiday (*event1) != gcal_event_is_multiday (*event2))
return gcal_event_is_multiday (event2) - gcal_event_is_multiday (event1); return gcal_event_is_multiday (*event2) - gcal_event_is_multiday (*event1);
/* Compare with respect to start day */ /* Compare with respect to start day */
return gcal_event_compare (event1, event2); return gcal_event_compare (*event1, *event2);
} }
static gint static gint
@@ -424,14 +424,15 @@ add_event_to_weekday (GcalWeekHeader *self,
GcalEvent *event, GcalEvent *event,
gint weekday) gint weekday)
{ {
GList *l; guint position = 0;
l = self->events[weekday]; g_ptr_array_add (self->events[weekday], g_object_ref (event));
l = g_list_insert_sorted (l, event, (GCompareFunc) compare_events_by_length); g_ptr_array_sort (self->events[weekday], (GCompareFunc) compare_events_by_length);
self->events[weekday] = l; if (!g_ptr_array_find (self->events[weekday], event, &position))
g_assert_not_reached ();
return g_list_index (l, event); return position;
} }
static gboolean static gboolean
@@ -444,7 +445,7 @@ is_event_visible (GcalWeekHeader *self,
if (self->expanded) if (self->expanded)
return TRUE; return TRUE;
show_label = g_list_length (self->events[weekday]) > 3; show_label = self->events[weekday]->len > 3;
return show_label ? position < 2 : position < 3; return show_label ? position < 2 : position < 3;
} }
@@ -464,7 +465,7 @@ update_overflow (GcalWeekHeader *self)
gboolean show_label; gboolean show_label;
gint n_events; gint n_events;
n_events = g_list_length (self->events[i]); n_events = self->events[i]->len;
show_label = n_events > 3; show_label = n_events > 3;
label = self->overflow_label[i]; label = self->overflow_label[i];
@@ -546,17 +547,14 @@ check_mergeable_events (GcalWeekHeader *self)
/* We don't need to check the last column */ /* We don't need to check the last column */
for (weekday = 0; weekday < N_WEEKDAYS - 1; weekday++) for (weekday = 0; weekday < N_WEEKDAYS - 1; weekday++)
{ {
GList *l; gint index = 0;
gint index;
index = 0; for (gsize i = 0; i < self->events[weekday]->len; i++)
for (l = self->events[weekday]; l != NULL; l = l->next)
{ {
GcalEvent *current_event; GcalEvent *current_event;
gint events_to_merge, i; gint events_to_merge;
current_event = l->data; current_event = g_ptr_array_index (self->events[weekday], i);
events_to_merge = 0; events_to_merge = 0;
if (g_list_find (checked_events[weekday], current_event)) if (g_list_find (checked_events[weekday], current_event))
@@ -573,29 +571,31 @@ check_mergeable_events (GcalWeekHeader *self)
* Horizontally check if the next cells have the same event * Horizontally check if the next cells have the same event
* than the current cell. * than the current cell.
*/ */
for (i = 1; i < N_WEEKDAYS - weekday; i++) for (gsize j = 1; j < N_WEEKDAYS - weekday; j++)
{ {
GcalEvent *next_event; GcalEvent *next_event;
next_event = g_list_nth_data (self->events[weekday + i], index); if (index >= self->events[weekday + j]->len)
break;
next_event = g_ptr_array_index (self->events[weekday + j], index);
if (next_event != current_event) if (next_event != current_event)
break; break;
events_to_merge++; events_to_merge++;
/* Add to the list of checked days so we don't check it more times than necessary */ /* Add to the list of checked days so we don't check it more times than necessary */
checked_events[weekday + i] = g_list_prepend (checked_events[weekday + i], current_event); checked_events[weekday + j] = g_list_prepend (checked_events[weekday + j], current_event);
} }
/* We found events to merge. Lets merge them */ /* We found events to merge. Lets merge them */
for (i = 0; i < events_to_merge; i++) for (gsize j = 0; j < events_to_merge; j++)
{ {
GtkWidget *current_widget, *to_be_removed; GtkWidget *current_widget, *to_be_removed;
current_widget = gtk_grid_get_child_at (self->grid, weekday + i, index + 1); current_widget = gtk_grid_get_child_at (self->grid, weekday + j, index + 1);
to_be_removed = gtk_grid_get_child_at (self->grid, weekday + i + 1, index + 1); to_be_removed = gtk_grid_get_child_at (self->grid, weekday + j + 1, index + 1);
/* /*
* We don't want to merge: * We don't want to merge:
@@ -613,7 +613,7 @@ check_mergeable_events (GcalWeekHeader *self)
merge_events (self, current_widget, to_be_removed); merge_events (self, current_widget, to_be_removed);
gtk_widget_set_visible (current_widget, is_event_visible (self, weekday + i, index)); gtk_widget_set_visible (current_widget, is_event_visible (self, weekday + j, index));
} }
index++; index++;
@@ -767,7 +767,7 @@ apply_overflow_at_weekday (GcalWeekHeader *self,
* If we don't need overflow, or we already applied the overflow, * If we don't need overflow, or we already applied the overflow,
* we don't need to do anything els. * we don't need to do anything els.
*/ */
if (self->expanded || self->overflow_label[weekday] || g_list_length (self->events[weekday]) < 4) if (self->expanded || self->overflow_label[weekday] || self->events[weekday]->len < 4)
return; return;
child = gtk_grid_get_child_at (self->grid, weekday, 3); child = gtk_grid_get_child_at (self->grid, weekday, 3);
@@ -897,14 +897,15 @@ static void
update_unchanged_events (GcalWeekHeader *self, update_unchanged_events (GcalWeekHeader *self,
GDateTime *new_date) GDateTime *new_date)
{ {
g_autoptr (GHashTable) events_to_update = NULL;
g_autoptr (GDateTime) new_week_start = NULL; g_autoptr (GDateTime) new_week_start = NULL;
g_autoptr (GDateTime) utc_week_start = NULL; g_autoptr (GDateTime) utc_week_start = NULL;
g_autoptr (GDateTime) new_week_end = NULL; g_autoptr (GDateTime) new_week_end = NULL;
g_autoptr (GDateTime) utc_week_end = NULL; g_autoptr (GDateTime) utc_week_end = NULL;
GList *events_to_update, *l; GHashTableIter iter;
gint weekday; gint weekday;
events_to_update = NULL; events_to_update = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL);
new_week_start = gcal_date_time_get_start_of_week (new_date); new_week_start = gcal_date_time_get_start_of_week (new_date);
new_week_end = gcal_date_time_get_end_of_week (new_date); new_week_end = gcal_date_time_get_end_of_week (new_date);
@@ -917,32 +918,31 @@ update_unchanged_events (GcalWeekHeader *self,
for (weekday = 0; weekday < N_WEEKDAYS; weekday++) for (weekday = 0; weekday < N_WEEKDAYS; weekday++)
{ {
GList *events; for (gsize i = 0; i < self->events[weekday]->len; i++)
events = self->events[weekday];
for (l = events; l != NULL; l = l->next)
{ {
g_autoptr (GDateTime) event_start = NULL; g_autoptr (GDateTime) event_start = NULL;
g_autoptr (GDateTime) event_end = NULL; g_autoptr (GDateTime) event_end = NULL;
GDateTime *week_start, *week_end; GDateTime *week_start, *week_end;
GcalEvent *event;
event = g_ptr_array_index (self->events[weekday], i);
/* /*
* When the event is all day, we must be careful to compare its dates * When the event is all day, we must be careful to compare its dates
* against the UTC variants of the week start and end dates. * against the UTC variants of the week start and end dates.
*/ */
if (gcal_event_get_all_day (l->data)) if (gcal_event_get_all_day (event))
{ {
event_start = g_date_time_ref (gcal_event_get_date_start (l->data)); event_start = g_date_time_ref (gcal_event_get_date_start (event));
event_end = g_date_time_ref (gcal_event_get_date_end (l->data)); event_end = g_date_time_ref (gcal_event_get_date_end (event));
week_start = utc_week_start; week_start = utc_week_start;
week_end = utc_week_end; week_end = utc_week_end;
} }
else else
{ {
event_start = g_date_time_to_local (gcal_event_get_date_start (l->data)); event_start = g_date_time_to_local (gcal_event_get_date_start (event));
event_end = g_date_time_to_local (gcal_event_get_date_end (l->data)); event_end = g_date_time_to_local (gcal_event_get_date_end (event));
week_start = new_week_start; week_start = new_week_start;
week_end = new_week_end; week_end = new_week_end;
@@ -955,20 +955,22 @@ update_unchanged_events (GcalWeekHeader *self,
*/ */
if (g_date_time_compare (event_start, week_end) < 0 && if (g_date_time_compare (event_start, week_end) < 0 &&
g_date_time_compare (event_end, week_start) > 0 && g_date_time_compare (event_end, week_start) > 0 &&
!g_list_find (events_to_update, l->data)) !g_hash_table_contains (events_to_update, event))
{ {
events_to_update = g_list_append (events_to_update, l->data); g_hash_table_add (events_to_update, g_object_ref (event));
} }
} }
} }
for (l = events_to_update; l != NULL; l = l->next) g_hash_table_iter_init (&iter, events_to_update);
{ {
gcal_week_header_remove_event (self, gcal_event_get_uid (l->data)); GcalEvent *event;
gcal_week_header_add_event (self, l->data); while (g_hash_table_iter_next (&iter, (gpointer *) &event, NULL))
{
gcal_week_header_remove_event (self, gcal_event_get_uid (event));
gcal_week_header_add_event (self, event);
}
} }
g_clear_pointer (&events_to_update, g_list_free);
} }
/* Header */ /* Header */
@@ -1438,7 +1440,7 @@ gcal_week_header_finalize (GObject *object)
gcal_clear_date_time (&self->active_date); gcal_clear_date_time (&self->active_date);
for (i = 0; i < N_WEEKDAYS; i++) for (i = 0; i < N_WEEKDAYS; i++)
g_list_free (self->events[i]); g_clear_pointer (&self->events[i], g_ptr_array_unref);
for (i = 0; i < G_N_ELEMENTS (self->weather_infos); i++) for (i = 0; i < G_N_ELEMENTS (self->weather_infos); i++)
wid_clear (&self->weather_infos[i]); wid_clear (&self->weather_infos[i]);
@@ -1545,6 +1547,9 @@ gcal_week_header_init (GcalWeekHeader *self)
GtkDropTarget *drop_target; GtkDropTarget *drop_target;
gint i; gint i;
for (gsize i = 0; i < N_WEEKDAYS; i++)
self->events[i] = g_ptr_array_new_with_free_func (g_object_unref);
self->expanded = FALSE; self->expanded = FALSE;
self->selection.start = -1; self->selection.start = -1;
@@ -1732,18 +1737,13 @@ gcal_week_header_remove_event (GcalWeekHeader *self,
/* Remove from the weekday's GList */ /* Remove from the weekday's GList */
for (weekday = 0; weekday < N_WEEKDAYS; weekday++) for (weekday = 0; weekday < N_WEEKDAYS; weekday++)
{ {
GList *l; guint event_position;
gint event_position;
l = self->events[weekday]; if (!g_ptr_array_find (self->events[weekday], removed_event, &event_position))
event_position = g_list_index (self->events[weekday], removed_event);
if (event_position == -1)
continue; continue;
/* Remove from the current weekday */ /* Remove from the current weekday */
l = g_list_remove (l, removed_event); g_ptr_array_remove_index (self->events[weekday], event_position);
self->events[weekday] = l;
/* Move remaining events up */ /* Move remaining events up */
move_events_at_column (self, UP, weekday, event_position); move_events_at_column (self, UP, weekday, event_position);