views/month: Rebuild layout blocks at once per frame

Instead of rebuilding them all every time an event is added or removed,
rebuild it once per frame. In case the month view isn't visible, don't
do anything, and wait until it's mapped to actually rebuild the event
blocks.

Related: https://gitlab.gnome.org/GNOME/gnome-calendar/-/issues/1381
Related: https://gitlab.gnome.org/GNOME/gnome-calendar/-/issues/1125
This commit is contained in:
Georges Basile Stavracas Neto
2025-03-11 17:52:14 -03:00
parent 67a6d0a002
commit 03e6e39433
+69 -2
View File
@@ -51,6 +51,7 @@ struct _GcalMonthViewRow
GListStore *events;
GHashTable *layout_blocks;
gboolean layout_blocks_valid;
GcalContext *context;
};
@@ -62,6 +63,10 @@ static gint compare_events_cb (gconstpointer
static void on_event_widget_activated_cb (GcalEventWidget *widget,
GcalMonthViewRow *self);
static gboolean widget_tick_cb (GtkWidget *widget,
GdkFrameClock *frame_clock,
gpointer user_data);
G_DEFINE_FINAL_TYPE (GcalMonthViewRow, gcal_month_view_row, GTK_TYPE_WIDGET)
enum
@@ -173,6 +178,8 @@ prepare_layout_blocks (GcalMonthViewRow *self,
guint weekday_heights[7] = { 0, };
guint n_events;
g_assert (self->layout_blocks_valid);
n_events = g_list_model_get_n_items (G_LIST_MODEL (self->events));
for (guint i = 0; i < 7; i++)
@@ -274,6 +281,10 @@ recalculate_layout_blocks (GcalMonthViewRow *self)
guint events_at_weekday[7] = { 0, };
guint n_events;
GCAL_ENTRY;
g_assert (!self->layout_blocks_valid);
range_start = gcal_range_get_start (self->range);
n_events = g_list_model_get_n_items (G_LIST_MODEL (self->events));
@@ -363,6 +374,29 @@ recalculate_layout_blocks (GcalMonthViewRow *self)
g_hash_table_insert (self->layout_blocks, event, g_steal_pointer (&blocks));
}
self->layout_blocks_valid = TRUE;
GCAL_EXIT;
}
static void
invalidate_layout_blocks (GcalMonthViewRow *self)
{
GCAL_ENTRY;
if (!self->layout_blocks_valid)
GCAL_RETURN ();
if (gtk_widget_get_mapped (GTK_WIDGET (self)))
{
gtk_widget_add_tick_callback (GTK_WIDGET (self), widget_tick_cb, self, NULL);
gtk_widget_queue_allocate (GTK_WIDGET (self));
}
self->layout_blocks_valid = FALSE;
GCAL_EXIT;
}
@@ -399,11 +433,40 @@ on_month_cell_show_overflow_cb (GcalMonthCell *cell,
g_signal_emit (self, signals[SHOW_OVERFLOW], 0, cell);
}
static gboolean
widget_tick_cb (GtkWidget *widget,
GdkFrameClock *frame_clock,
gpointer user_data)
{
GcalMonthViewRow *self = (GcalMonthViewRow *) widget;
GCAL_ENTRY;
g_assert (GCAL_IS_MONTH_VIEW_ROW (self));
recalculate_layout_blocks (self);
GCAL_RETURN (G_SOURCE_REMOVE);
}
/*
* GtkWidget overrides
*/
static void
gcal_month_view_row_map (GtkWidget *widget)
{
GcalMonthViewRow *self = (GcalMonthViewRow *) widget;
g_assert (GCAL_IS_MONTH_VIEW_ROW (self));
GTK_WIDGET_CLASS (gcal_month_view_row_parent_class)->map (widget);
if (!self->layout_blocks_valid)
recalculate_layout_blocks (self);
}
static void
gcal_month_view_row_measure (GtkWidget *widget,
GtkOrientation orientation,
@@ -485,6 +548,7 @@ gcal_month_view_row_size_allocate (GtkWidget *widget,
}
/* Event widgets */
if (self->layout_blocks_valid)
{
gdouble cell_y[7];
guint overflows[7] = { 0, };
@@ -610,6 +674,7 @@ gcal_month_view_row_class_init (GcalMonthViewRowClass *klass)
object_class->get_property = gcal_month_view_row_get_property;
object_class->set_property = gcal_month_view_row_set_property;
widget_class->map = gcal_month_view_row_map;
widget_class->measure = gcal_month_view_row_measure;
widget_class->size_allocate = gcal_month_view_row_size_allocate;
@@ -645,6 +710,7 @@ gcal_month_view_row_init (GcalMonthViewRow *self)
{
self->events = g_list_store_new (GCAL_TYPE_EVENT);
self->layout_blocks = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) g_ptr_array_unref);
self->layout_blocks_valid = TRUE;
for (guint i = 0; i < 7; i++)
{
@@ -712,6 +778,7 @@ gcal_month_view_row_set_range (GcalMonthViewRow *self,
/* Preemptively remove all event widgets */
g_list_store_remove_all (self->events);
g_hash_table_remove_all (self->layout_blocks);
invalidate_layout_blocks (self);
start = gcal_range_get_start (range);
for (guint i = 0; i < 7; i++)
@@ -729,7 +796,7 @@ gcal_month_view_row_add_event (GcalMonthViewRow *self,
g_assert (GCAL_IS_EVENT (event));
g_list_store_insert_sorted (self->events, event, compare_events_cb, self);
recalculate_layout_blocks (self);
invalidate_layout_blocks (self);
}
void
@@ -753,7 +820,7 @@ gcal_month_view_row_remove_event (GcalMonthViewRow *self,
}
g_list_store_remove (self->events, position);
recalculate_layout_blocks (self);
invalidate_layout_blocks (self);
GCAL_EXIT;
}