views/agenda: Rework scrolling to use gtk_list_view_scroll_to

Since we refactored all events widgets and date headers to be
constructed by GtkListView directly, we are able to use
`gtk_list_view_scroll_to` to jump to the top of the list when opening
the agenda view, and changing date, instead of needing a complicated
timer and GSource callback

Part-of: <https://gitlab.gnome.org/GNOME/gnome-calendar/-/merge_requests/809>
This commit is contained in:
Zelda Ahmed
2026-09-26 13:02:27 +01:00
parent 3fe8eadcd9
commit 11ef9db5c2
+3 -94
View File
@@ -47,6 +47,7 @@ struct _GcalAgendaView
GtkBox parent;
GtkWidget *scrolled_window;
GtkListView *list_view;
/* property */
GDateTime *date;
@@ -54,15 +55,10 @@ struct _GcalAgendaView
GtkFilterListModel *filtered_days;
GtkFlattenListModel *flatten_model;
guint scroll_grid_timeout_id;
gulong stack_page_changed_id;
gint events_on_date;
gint clicked_cell;
};
static void schedule_position_scroll (GcalAgendaView *self);
static void gcal_view_interface_init (GcalViewInterface *iface);
static void gcal_timeline_subscriber_interface_init (GcalTimelineSubscriberInterface *iface);
@@ -119,94 +115,6 @@ new_date_header_string (GDateTime *date)
* Callbacks
*/
static void
stack_visible_child_changed_cb (AdwViewStack *stack,
GParamSpec *pspec,
GcalAgendaView *self)
{
if (adw_view_stack_get_visible_child (stack) != (GtkWidget*) self)
return;
schedule_position_scroll (self);
g_clear_signal_handler (&self->stack_page_changed_id, stack);
}
static gboolean
update_grid_scroll_position (GcalAgendaView *self)
{
g_autoptr(GDateTime) week_start = NULL;
g_autoptr(GDateTime) week_end = NULL;
g_autoptr(GDateTime) now = NULL;
GtkAdjustment *vadjustment;
gdouble minutes, real_value;
gdouble max, page, page_increment, value;
gboolean dummy;
/* While the scrolled window is not mapped, we keep waiting */
if (!gtk_widget_get_realized (self->scrolled_window) ||
!gtk_widget_get_mapped (self->scrolled_window))
{
if (self->stack_page_changed_id == 0)
{
GtkWidget *stack = gtk_widget_get_ancestor (GTK_WIDGET (self), ADW_TYPE_VIEW_STACK);
self->stack_page_changed_id = g_signal_connect_object (stack,
"notify::visible-child",
G_CALLBACK (stack_visible_child_changed_cb),
self,
0);
}
self->scroll_grid_timeout_id = 0;
GCAL_RETURN (G_SOURCE_REMOVE);
}
now = g_date_time_new_now_local ();
week_start = gcal_date_time_get_start_of_week (self->date);
week_end = gcal_date_time_get_end_of_week (self->date);
/* Don't animate when not today */
if (gcal_date_time_compare_date (now, week_start) < 0 || gcal_date_time_compare_date (now, week_end) >= 0)
GCAL_GOTO (out);
vadjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (self->scrolled_window));
minutes = g_date_time_get_hour (now) * 60 + g_date_time_get_minute (now);
page = gtk_adjustment_get_page_size (vadjustment);
max = gtk_adjustment_get_upper (vadjustment);
real_value = max / GCAL_MINUTES_PER_DAY * minutes - (page / 2.0);
page_increment = gtk_adjustment_get_page_increment (vadjustment);
value = gtk_adjustment_get_value (vadjustment);
gtk_adjustment_set_page_increment (vadjustment, real_value - value);
g_signal_emit_by_name (self->scrolled_window,
"scroll-child",
GTK_SCROLL_PAGE_FORWARD,
FALSE,
&dummy);
gtk_adjustment_set_page_increment (vadjustment, page_increment);
out:
self->scroll_grid_timeout_id = 0;
GCAL_RETURN (G_SOURCE_REMOVE);
}
static void
schedule_position_scroll (GcalAgendaView *self)
{
/* Nothing is scheduled, we should do it now */
if (self->scroll_grid_timeout_id > 0)
g_source_remove (self->scroll_grid_timeout_id);
self->scroll_grid_timeout_id = g_timeout_add (200,
(GSourceFunc) update_grid_scroll_position,
self);
}
static gboolean
n_items_and_date_to_boolean (GcalAgendaViewDay *day,
unsigned int n_items,
@@ -348,7 +256,7 @@ gcal_agenda_view_set_date (GcalView *view,
gcal_agenda_view_day_set_date (day, next_date);
}
schedule_position_scroll (self);
gtk_list_view_scroll_to (self->list_view, 0, GTK_LIST_SCROLL_FOCUS, NULL);
gcal_timeline_subscriber_range_changed (GCAL_TIMELINE_SUBSCRIBER (view));
@@ -538,6 +446,7 @@ gcal_agenda_view_class_init (GcalAgendaViewClass *klass)
gtk_widget_class_bind_template_child (widget_class, GcalAgendaView, flatten_model);
gtk_widget_class_bind_template_child (widget_class, GcalAgendaView, filtered_days);
gtk_widget_class_bind_template_child (widget_class, GcalAgendaView, scrolled_window);
gtk_widget_class_bind_template_child (widget_class, GcalAgendaView, list_view);
gtk_widget_class_bind_template_callback (widget_class, agenda_header_setup_cb);
gtk_widget_class_bind_template_callback (widget_class, agenda_header_bind_cb);