fontsel: defer expensive selection updates

Based on the openSUSE gtk2-bnc130159-bgo319483-async-selection-in-gtk-font-selection.diff.

Coalesce font family, style and size selection updates with short timeouts to keep GtkFontSelection responsive while preserving immediate updates for internal programmatic selection changes.
This commit is contained in:
Daemonratte 2026-05-13 13:20:06 +02:00
commit 3501d8c4f5

View file

@ -585,6 +585,79 @@ gtk_font_selection_new (void)
return GTK_WIDGET (fontsel);
}
static GQuark
font_selection_font_timeout_quark (void)
{
return g_quark_from_static_string ("gtk-font-selection-font-timeout");
}
static GQuark
font_selection_style_timeout_quark (void)
{
return g_quark_from_static_string ("gtk-font-selection-style-timeout");
}
static GQuark
font_selection_size_timeout_quark (void)
{
return g_quark_from_static_string ("gtk-font-selection-size-timeout");
}
static GQuark
font_selection_immediate_quark (void)
{
return g_quark_from_static_string ("gtk-font-selection-immediate");
}
static void
gtk_font_selection_remove_timeout (GtkFontSelection *fontsel,
GQuark quark)
{
guint timeout_id;
timeout_id = GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (fontsel), quark));
if (timeout_id)
{
g_source_remove (timeout_id);
g_object_set_qdata (G_OBJECT (fontsel), quark, NULL);
}
}
static gboolean
gtk_font_selection_get_immediate (GtkFontSelection *fontsel)
{
return GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (fontsel),
font_selection_immediate_quark ())) != 0;
}
static void
gtk_font_selection_set_immediate (GtkFontSelection *fontsel,
gboolean immediate)
{
g_object_set_qdata (G_OBJECT (fontsel),
font_selection_immediate_quark (),
GUINT_TO_POINTER (immediate ? 1 : 0));
}
static void
gtk_font_selection_schedule_selection (GtkFontSelection *fontsel,
GQuark quark,
GSourceFunc func)
{
guint timeout_id;
gtk_font_selection_remove_timeout (fontsel, quark);
if (gtk_font_selection_get_immediate (fontsel))
{
func (fontsel);
return;
}
timeout_id = g_timeout_add (200, func, fontsel);
g_object_set_qdata (G_OBJECT (fontsel), quark, GUINT_TO_POINTER (timeout_id));
}
static void
gtk_font_selection_finalize (GObject *object)
{
@ -594,6 +667,10 @@ gtk_font_selection_finalize (GObject *object)
fontsel = GTK_FONT_SELECTION (object);
gtk_font_selection_remove_timeout (fontsel, font_selection_font_timeout_quark ());
gtk_font_selection_remove_timeout (fontsel, font_selection_style_timeout_quark ());
gtk_font_selection_remove_timeout (fontsel, font_selection_size_timeout_quark ());
if (fontsel->font)
gdk_font_unref (fontsel->font);
@ -632,6 +709,8 @@ gtk_font_selection_reload_fonts (GtkFontSelection *fontsel)
PangoFontDescription *desc;
desc = gtk_font_selection_get_font_description (fontsel);
gtk_font_selection_set_immediate (fontsel, TRUE);
gtk_font_selection_show_available_fonts (fontsel);
gtk_font_selection_show_available_sizes (fontsel, TRUE);
gtk_font_selection_show_available_styles (fontsel);
@ -639,6 +718,8 @@ gtk_font_selection_reload_fonts (GtkFontSelection *fontsel)
gtk_font_selection_select_font_desc (fontsel, desc, NULL, NULL);
gtk_font_selection_scroll_to_selection (fontsel);
gtk_font_selection_set_immediate (fontsel, FALSE);
pango_font_description_free (desc);
}
}
@ -715,11 +796,11 @@ gtk_font_selection_scroll_on_map (GtkWidget *widget,
}
/* This is called when a family is selected in the list. */
static void
gtk_font_selection_select_font (GtkTreeSelection *selection,
gpointer data)
static gboolean
gtk_font_selection_real_select_font (gpointer data)
{
GtkFontSelection *fontsel;
GtkTreeSelection *selection;
GtkTreeModel *model;
GtkTreeIter iter;
#ifdef INCLUDE_FONT_ENTRIES
@ -727,6 +808,7 @@ gtk_font_selection_select_font (GtkTreeSelection *selection,
#endif
fontsel = GTK_FONT_SELECTION (data);
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->family_list));
if (gtk_tree_selection_get_selected (selection, &model, &iter))
{
@ -734,20 +816,35 @@ gtk_font_selection_select_font (GtkTreeSelection *selection,
gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
if (fontsel->family != family)
{
gtk_font_selection_ref_family (fontsel, family);
{
gtk_font_selection_ref_family (fontsel, family);
#ifdef INCLUDE_FONT_ENTRIES
family_name = pango_font_family_get_name (fontsel->family);
gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry), family_name);
family_name = pango_font_family_get_name (fontsel->family);
gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry), family_name);
#endif
gtk_font_selection_show_available_styles (fontsel);
gtk_font_selection_select_best_style (fontsel, TRUE);
}
gtk_font_selection_show_available_styles (fontsel);
gtk_font_selection_select_best_style (fontsel, TRUE);
}
g_object_unref (family);
}
g_object_set_qdata (G_OBJECT (fontsel), font_selection_font_timeout_quark (), NULL);
return FALSE;
}
static void
gtk_font_selection_select_font (GtkTreeSelection *selection,
gpointer data)
{
GtkFontSelection *fontsel = GTK_FONT_SELECTION (data);
gtk_font_selection_schedule_selection (fontsel,
font_selection_font_timeout_quark (),
gtk_font_selection_real_select_font);
}
static int
@ -950,14 +1047,16 @@ gtk_font_selection_select_best_style (GtkFontSelection *fontsel,
/* This is called when a style is selected in the list. */
static void
gtk_font_selection_select_style (GtkTreeSelection *selection,
gpointer data)
static gboolean
gtk_font_selection_real_select_style (gpointer data)
{
GtkFontSelection *fontsel = GTK_FONT_SELECTION (data);
GtkTreeSelection *selection;
GtkTreeModel *model;
GtkTreeIter iter;
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->face_list));
if (gtk_tree_selection_get_selected (selection, &model, &iter))
{
PangoFontFace *face;
@ -969,6 +1068,21 @@ gtk_font_selection_select_style (GtkTreeSelection *selection,
gtk_font_selection_show_available_sizes (fontsel, FALSE);
gtk_font_selection_select_best_size (fontsel);
g_object_set_qdata (G_OBJECT (fontsel), font_selection_style_timeout_quark (), NULL);
return FALSE;
}
static void
gtk_font_selection_select_style (GtkTreeSelection *selection,
gpointer data)
{
GtkFontSelection *fontsel = GTK_FONT_SELECTION (data);
gtk_font_selection_schedule_selection (fontsel,
font_selection_style_timeout_quark (),
gtk_font_selection_real_select_style);
}
static void
@ -1101,22 +1215,38 @@ gtk_font_selection_size_focus_out (GtkWidget *w,
}
/* This is called when a size is selected in the list. */
static void
gtk_font_selection_select_size (GtkTreeSelection *selection,
gpointer data)
static gboolean
gtk_font_selection_real_select_size (gpointer data)
{
GtkFontSelection *fontsel;
GtkTreeSelection *selection;
GtkTreeModel *model;
GtkTreeIter iter;
gint new_size;
fontsel = GTK_FONT_SELECTION (data);
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list));
if (gtk_tree_selection_get_selected (selection, &model, &iter))
{
gtk_tree_model_get (model, &iter, SIZE_COLUMN, &new_size, -1);
gtk_font_selection_set_size (fontsel, new_size * PANGO_SCALE);
}
g_object_set_qdata (G_OBJECT (fontsel), font_selection_size_timeout_quark (), NULL);
return FALSE;
}
static void
gtk_font_selection_select_size (GtkTreeSelection *selection,
gpointer data)
{
GtkFontSelection *fontsel = GTK_FONT_SELECTION (data);
gtk_font_selection_schedule_selection (fontsel,
font_selection_size_timeout_quark (),
gtk_font_selection_real_select_size);
}
static void
@ -1450,6 +1580,8 @@ gtk_font_selection_select_font_desc (GtkFontSelection *fontsel,
if (!new_family)
return FALSE;
gtk_font_selection_set_immediate (fontsel, TRUE);
if (pfamily)
*pfamily = new_family;
else
@ -1500,6 +1632,8 @@ gtk_font_selection_select_font_desc (GtkFontSelection *fontsel,
gtk_font_selection_set_size (fontsel, pango_font_description_get_size (new_desc));
gtk_font_selection_set_immediate (fontsel, FALSE);
return TRUE;
}