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
+63 -63
View File
@@ -83,7 +83,7 @@ struct _GcalWeekHeader
* The list will later be iterated after the active date is changed
* and the events will be placed
*/
GList *events[N_WEEKDAYS];
GPtrArray *events[N_WEEKDAYS];
GtkWidget *overflow_label[N_WEEKDAYS];
WeekdayHeader weekday_header[N_WEEKDAYS];
@@ -377,12 +377,12 @@ get_event_by_uuid (GcalWeekHeader *self,
for (weekday = 0; weekday < N_WEEKDAYS; weekday++)
{
GList *l;
for (l = self->events[weekday]; l != NULL; l = l->next)
for (gsize i = 0; i < self->events[weekday]->len; i++)
{
if (g_strcmp0 (gcal_event_get_uid (l->data), uuid) == 0)
return l->data;
GcalEvent *event = g_ptr_array_index (self->events[weekday], i);
if (g_strcmp0 (gcal_event_get_uid (event), uuid) == 0)
return event;
}
}
@@ -408,15 +408,15 @@ get_today_column (GcalWeekHeader *self)
}
static gint
compare_events_by_length (GcalEvent *event1,
GcalEvent *event2)
compare_events_by_length (GcalEvent **event1,
GcalEvent **event2)
{
/* Multiday events should come before single day events */
if (gcal_event_is_multiday (event1) != gcal_event_is_multiday (event2))
return gcal_event_is_multiday (event2) - gcal_event_is_multiday (event1);
if (gcal_event_is_multiday (*event1) != gcal_event_is_multiday (*event2))
return gcal_event_is_multiday (*event2) - gcal_event_is_multiday (*event1);
/* Compare with respect to start day */
return gcal_event_compare (event1, event2);
return gcal_event_compare (*event1, *event2);
}
static gint
@@ -424,14 +424,15 @@ add_event_to_weekday (GcalWeekHeader *self,
GcalEvent *event,
gint weekday)
{
GList *l;
guint position = 0;
l = self->events[weekday];
l = g_list_insert_sorted (l, event, (GCompareFunc) compare_events_by_length);
g_ptr_array_add (self->events[weekday], g_object_ref (event));
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
@@ -444,7 +445,7 @@ is_event_visible (GcalWeekHeader *self,
if (self->expanded)
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;
}
@@ -464,7 +465,7 @@ update_overflow (GcalWeekHeader *self)
gboolean show_label;
gint n_events;
n_events = g_list_length (self->events[i]);
n_events = self->events[i]->len;
show_label = n_events > 3;
label = self->overflow_label[i];
@@ -546,17 +547,14 @@ check_mergeable_events (GcalWeekHeader *self)
/* We don't need to check the last column */
for (weekday = 0; weekday < N_WEEKDAYS - 1; weekday++)
{
GList *l;
gint index;
gint index = 0;
index = 0;
for (l = self->events[weekday]; l != NULL; l = l->next)
for (gsize i = 0; i < self->events[weekday]->len; i++)
{
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;
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
* than the current cell.
*/
for (i = 1; i < N_WEEKDAYS - weekday; i++)
for (gsize j = 1; j < N_WEEKDAYS - weekday; j++)
{
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)
break;
events_to_merge++;
/* 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 */
for (i = 0; i < events_to_merge; i++)
for (gsize j = 0; j < events_to_merge; j++)
{
GtkWidget *current_widget, *to_be_removed;
current_widget = gtk_grid_get_child_at (self->grid, weekday + i, index + 1);
to_be_removed = gtk_grid_get_child_at (self->grid, weekday + i + 1, 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 + j + 1, index + 1);
/*
* We don't want to merge:
@@ -613,7 +613,7 @@ check_mergeable_events (GcalWeekHeader *self)
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++;
@@ -767,7 +767,7 @@ apply_overflow_at_weekday (GcalWeekHeader *self,
* If we don't need overflow, or we already applied the overflow,
* 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;
child = gtk_grid_get_child_at (self->grid, weekday, 3);
@@ -897,14 +897,15 @@ static void
update_unchanged_events (GcalWeekHeader *self,
GDateTime *new_date)
{
g_autoptr (GHashTable) events_to_update = NULL;
g_autoptr (GDateTime) new_week_start = NULL;
g_autoptr (GDateTime) utc_week_start = NULL;
g_autoptr (GDateTime) new_week_end = NULL;
g_autoptr (GDateTime) utc_week_end = NULL;
GList *events_to_update, *l;
GHashTableIter iter;
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_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++)
{
GList *events;
events = self->events[weekday];
for (l = events; l != NULL; l = l->next)
for (gsize i = 0; i < self->events[weekday]->len; i++)
{
g_autoptr (GDateTime) event_start = NULL;
g_autoptr (GDateTime) event_end = NULL;
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
* 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_end = g_date_time_ref (gcal_event_get_date_end (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 (event));
week_start = utc_week_start;
week_end = utc_week_end;
}
else
{
event_start = g_date_time_to_local (gcal_event_get_date_start (l->data));
event_end = g_date_time_to_local (gcal_event_get_date_end (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 (event));
week_start = new_week_start;
week_end = new_week_end;
@@ -955,20 +955,22 @@ update_unchanged_events (GcalWeekHeader *self,
*/
if (g_date_time_compare (event_start, week_end) < 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)
{
gcal_week_header_remove_event (self, gcal_event_get_uid (l->data));
gcal_week_header_add_event (self, l->data);
}
g_clear_pointer (&events_to_update, g_list_free);
g_hash_table_iter_init (&iter, events_to_update);
{
GcalEvent *event;
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);
}
}
}
/* Header */
@@ -1438,7 +1440,7 @@ gcal_week_header_finalize (GObject *object)
gcal_clear_date_time (&self->active_date);
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++)
wid_clear (&self->weather_infos[i]);
@@ -1545,6 +1547,9 @@ gcal_week_header_init (GcalWeekHeader *self)
GtkDropTarget *drop_target;
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->selection.start = -1;
@@ -1732,18 +1737,13 @@ gcal_week_header_remove_event (GcalWeekHeader *self,
/* Remove from the weekday's GList */
for (weekday = 0; weekday < N_WEEKDAYS; weekday++)
{
GList *l;
gint event_position;
guint event_position;
l = self->events[weekday];
event_position = g_list_index (self->events[weekday], removed_event);
if (event_position == -1)
if (!g_ptr_array_find (self->events[weekday], removed_event, &event_position))
continue;
/* Remove from the current weekday */
l = g_list_remove (l, removed_event);
self->events[weekday] = l;
g_ptr_array_remove_index (self->events[weekday], event_position);
/* Move remaining events up */
move_events_at_column (self, UP, weekday, event_position);