[gtk/wip/otte/listview: 298/309] fontchooserwidget: Port to listmodels



commit f85ed6714d01a74453815835b636447175acc92c
Author: Benjamin Otte <otte redhat com>
Date:   Thu Nov 28 04:00:39 2019 +0100

    fontchooserwidget: Port to listmodels
    
    The port is kind of evil, in that it stores either a PangoFontFamily or a
    PangoFontFace in the list, depending on if the fontchooser is configured
    to select fonts or faces.
    It also does not cache the font description anymore, so more calls to
    pango_font_describe() may happen.
    
    If both of these issues turn out problematic, the fontchooser would need
    to resurrect GtkDelayedFontDescription again and put objects of that
    type through the model.
    
    These changes depend on Pango 1.46's introduction of listmodels and
    various new getters, so the dependency has been upgraded.

 gtk/gtkfontchooserwidget.c     | 934 ++++++++++++-----------------------------
 gtk/ui/gtkfontchooserwidget.ui | 108 +++--
 meson.build                    |   2 +-
 3 files changed, 328 insertions(+), 716 deletions(-)
---
diff --git a/gtk/gtkfontchooserwidget.c b/gtk/gtkfontchooserwidget.c
index 93aa5b4921..b29506c85f 100644
--- a/gtk/gtkfontchooserwidget.c
+++ b/gtk/gtkfontchooserwidget.c
@@ -30,20 +30,20 @@
 #include "gtkbuildable.h"
 #include "gtkbox.h"
 #include "gtkbinlayout.h"
-#include "gtkcellrenderertext.h"
-#include "gtkcssnumbervalueprivate.h"
+#include "gtkcustomfilter.h"
 #include "gtkentry.h"
-#include "gtksearchentry.h"
+#include "gtkfilter.h"
 #include "gtkgrid.h"
 #include "gtkfontchooser.h"
 #include "gtkfontchooserutils.h"
 #include "gtkintl.h"
 #include "gtklabel.h"
-#include "gtkliststore.h"
+#include "gtksingleselection.h"
 #include "gtkstack.h"
 #include "gtkprivate.h"
 #include "gtkscale.h"
 #include "gtkscrolledwindow.h"
+#include "gtksearchentry.h"
 #include "gtkspinbutton.h"
 #include "gtkstylecontextprivate.h"
 #include "gtktextview.h"
@@ -57,6 +57,9 @@
 #include "gtkgestureclick.h"
 #include "gtkeventcontrollerscroll.h"
 #include "gtkroot.h"
+#include "gtkfilterlistmodel.h"
+#include "gtkflattenlistmodel.h"
+#include "gtkmaplistmodel.h"
 
 #include <hb-ot.h>
 
@@ -99,12 +102,10 @@ struct _GtkFontChooserWidget
   GtkWidget    *grid;
   GtkWidget    *search_entry;
   GtkWidget    *family_face_list;
-  GtkTreeViewColumn *family_face_column;
-  GtkCellRenderer *family_face_cell;
-  GtkWidget    *list_scrolled_window;
   GtkWidget    *list_stack;
-  GtkTreeModel *model;
-  GtkTreeModel *filter_model;
+  GtkSingleSelection *selection;
+  GtkCustomFilter      *custom_filter;
+  GtkFilterListModel   *filter_model;
 
   GtkWidget       *preview;
   GtkWidget       *preview2;
@@ -125,8 +126,7 @@ struct _GtkFontChooserWidget
   PangoFontDescription *font_desc;
   char                 *font_features;
   PangoLanguage        *language;
-  GtkTreeIter           font_iter;      /* invalid if font not available or pointer into model
-                                           (not filter_model) to the row containing font */
+
   GtkFontFilterFunc filter_func;
   gpointer          filter_data;
   GDestroyNotify    filter_data_destroy;
@@ -153,14 +153,6 @@ enum {
   PROP_TWEAK_ACTION
 };
 
-/* Keep in line with GtkTreeStore defined in gtkfontchooserwidget.ui */
-enum {
-  FAMILY_COLUMN,
-  FACE_COLUMN,
-  FONT_DESC_COLUMN,
-  PREVIEW_TITLE_COLUMN
-};
-
 static void gtk_font_chooser_widget_set_property         (GObject         *object,
                                                           guint            prop_id,
                                                           const GValue    *value,
@@ -171,19 +163,13 @@ static void gtk_font_chooser_widget_get_property         (GObject         *objec
                                                           GParamSpec      *pspec);
 static void gtk_font_chooser_widget_finalize             (GObject         *object);
 
-static gboolean gtk_font_chooser_widget_find_font        (GtkFontChooserWidget *fontchooser,
-                                                          const PangoFontDescription *font_desc,
-                                                          GtkTreeIter          *iter);
-static void     gtk_font_chooser_widget_ensure_selection (GtkFontChooserWidget *fontchooser);
-
 static gchar   *gtk_font_chooser_widget_get_font         (GtkFontChooserWidget *fontchooser);
 static void     gtk_font_chooser_widget_set_font         (GtkFontChooserWidget *fontchooser,
                                                           const gchar          *fontname);
 
 static PangoFontDescription *gtk_font_chooser_widget_get_font_desc  (GtkFontChooserWidget *fontchooser);
 static void                  gtk_font_chooser_widget_merge_font_desc(GtkFontChooserWidget       *fontchooser,
-                                                                     const PangoFontDescription *font_desc,
-                                                                     GtkTreeIter                *iter);
+                                                                     const PangoFontDescription *font_desc);
 static void                  gtk_font_chooser_widget_take_font_desc (GtkFontChooserWidget *fontchooser,
                                                                      PangoFontDescription *font_desc);
 
@@ -196,25 +182,12 @@ static gboolean gtk_font_chooser_widget_get_show_preview_entry (GtkFontChooserWi
 static void     gtk_font_chooser_widget_set_show_preview_entry (GtkFontChooserWidget *fontchooser,
                                                                 gboolean              show_preview_entry);
 
-static void     gtk_font_chooser_widget_set_cell_size          (GtkFontChooserWidget *fontchooser);
-static void     gtk_font_chooser_widget_load_fonts             (GtkFontChooserWidget *fontchooser,
-                                                                gboolean              force);
 static void     gtk_font_chooser_widget_populate_features      (GtkFontChooserWidget *fontchooser);
-static gboolean visible_func                                   (GtkTreeModel *model,
-                                                               GtkTreeIter  *iter,
-                                                               gpointer      user_data);
-static void     gtk_font_chooser_widget_cell_data_func         (GtkTreeViewColumn *column,
-                                                               GtkCellRenderer   *cell,
-                                                               GtkTreeModel      *tree_model,
-                                                               GtkTreeIter       *iter,
-                                                               gpointer           user_data);
 static void                gtk_font_chooser_widget_set_level (GtkFontChooserWidget *fontchooser,
                                                               GtkFontChooserLevel   level);
 static GtkFontChooserLevel gtk_font_chooser_widget_get_level (GtkFontChooserWidget *fontchooser);
 static void                gtk_font_chooser_widget_set_language (GtkFontChooserWidget *fontchooser,
                                                                  const char           *language);
-static void selection_changed (GtkTreeSelection *selection,
-                               GtkFontChooserWidget *fontchooser);
 static void update_font_features (GtkFontChooserWidget *fontchooser);
 
 static void gtk_font_chooser_widget_iface_init (GtkFontChooserIface *iface);
@@ -223,65 +196,6 @@ G_DEFINE_TYPE_WITH_CODE (GtkFontChooserWidget, gtk_font_chooser_widget, GTK_TYPE
                          G_IMPLEMENT_INTERFACE (GTK_TYPE_FONT_CHOOSER,
                                                 gtk_font_chooser_widget_iface_init))
 
-typedef struct _GtkDelayedFontDescription GtkDelayedFontDescription;
-struct _GtkDelayedFontDescription {
-  PangoFontFace        *face;
-  PangoFontDescription *desc;
-  guint                 ref_count;
-};
-
-static GtkDelayedFontDescription *
-gtk_delayed_font_description_new (PangoFontFace *face)
-{
-  GtkDelayedFontDescription *result;
-  
-  result = g_slice_new0 (GtkDelayedFontDescription);
-
-  result->face = g_object_ref (face);
-  result->desc = NULL;
-  result->ref_count = 1;
-
-  return result;
-}
-
-static GtkDelayedFontDescription *
-gtk_delayed_font_description_ref (GtkDelayedFontDescription *desc)
-{
-  desc->ref_count++;
-
-  return desc;
-}
-
-static void
-gtk_delayed_font_description_unref (GtkDelayedFontDescription *desc)
-{
-  desc->ref_count--;
-
-  if (desc->ref_count > 0)
-    return;
-
-  g_object_unref (desc->face);
-  if (desc->desc)
-    pango_font_description_free (desc->desc);
-
-  g_slice_free (GtkDelayedFontDescription, desc);
-}
-
-static const PangoFontDescription *
-gtk_delayed_font_description_get (GtkDelayedFontDescription *desc)
-{
-  if (desc->desc == NULL)
-    desc->desc = pango_font_face_describe (desc->face);
-
-  return desc->desc;
-}
-
-#define GTK_TYPE_DELAYED_FONT_DESCRIPTION (gtk_delayed_font_description_get_type ())
-GType gtk_delayed_font_description_get_type (void);
-
-G_DEFINE_BOXED_TYPE (GtkDelayedFontDescription, gtk_delayed_font_description,
-                     gtk_delayed_font_description_ref,
-                     gtk_delayed_font_description_unref)
 static void
 gtk_font_chooser_widget_set_property (GObject         *object,
                                       guint            prop_id,
@@ -356,20 +270,6 @@ gtk_font_chooser_widget_get_property (GObject         *object,
     }
 }
 
-static void
-gtk_font_chooser_widget_refilter_font_list (GtkFontChooserWidget *fontchooser)
-{
-  gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (fontchooser->filter_model));
-  gtk_font_chooser_widget_ensure_selection (fontchooser);
-}
-
-static void
-text_changed_cb (GtkEntry             *entry,
-                 GtkFontChooserWidget *fc)
-{
-  gtk_font_chooser_widget_refilter_font_list (fc);
-}
-
 static void
 stop_search_cb (GtkSearchEntry       *entry,
                 GtkFontChooserWidget *fc)
@@ -425,29 +325,31 @@ output_cb (GtkSpinButton *spin,
 }
 
 static void
-gtk_font_chooser_widget_update_marks (GtkFontChooserWidget *fontchooser)
+gtk_font_chooser_widget_update_marks (GtkFontChooserWidget *self)
 {
   GtkAdjustment *adj, *spin_adj;
   const int *sizes;
   gint *font_sizes;
   gint i, n_sizes;
   gdouble value, spin_value;
+  gpointer item;
+
+  item = gtk_single_selection_get_selected_item (self->selection);
 
-  if (gtk_list_store_iter_is_valid (GTK_LIST_STORE (fontchooser->model), &fontchooser->font_iter))
+  if (item)
     {
       PangoFontFace *face;
 
-      gtk_tree_model_get (fontchooser->model, &fontchooser->font_iter,
-                          FACE_COLUMN, &face,
-                          -1);
+      if (PANGO_IS_FONT_FAMILY (item))
+        face = pango_font_family_get_face (item, NULL);
+      else
+        face = item;
 
       pango_font_face_list_sizes (face, &font_sizes, &n_sizes);
 
       /* It seems not many fonts actually have a sane set of sizes */
       for (i = 0; i < n_sizes; i++)
         font_sizes[i] = font_sizes[i] / PANGO_SCALE;
-
-      g_object_unref (face);
     }
   else
     {
@@ -469,11 +371,11 @@ gtk_font_chooser_widget_update_marks (GtkFontChooserWidget *fontchooser)
       sizes = font_sizes;
     }
 
-  gtk_scale_clear_marks (GTK_SCALE (fontchooser->size_slider));
-  gtk_scale_clear_marks (GTK_SCALE (fontchooser->size_slider2));
+  gtk_scale_clear_marks (GTK_SCALE (self->size_slider));
+  gtk_scale_clear_marks (GTK_SCALE (self->size_slider2));
 
-  adj        = gtk_range_get_adjustment (GTK_RANGE (fontchooser->size_slider));
-  spin_adj   = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (fontchooser->size_spin));
+  adj        = gtk_range_get_adjustment (GTK_RANGE (self->size_slider));
+  spin_adj   = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (self->size_spin));
   spin_value = gtk_adjustment_get_value (spin_adj);
 
   if (spin_value < sizes[0])
@@ -484,7 +386,7 @@ gtk_font_chooser_widget_update_marks (GtkFontChooserWidget *fontchooser)
     value = (gdouble)spin_value;
 
   /* ensure clamping doesn't callback into font resizing code */
-  g_signal_handlers_block_by_func (adj, size_change_cb, fontchooser);
+  g_signal_handlers_block_by_func (adj, size_change_cb, self);
   gtk_adjustment_configure (adj,
                             value,
                             sizes[0],
@@ -492,14 +394,14 @@ gtk_font_chooser_widget_update_marks (GtkFontChooserWidget *fontchooser)
                             gtk_adjustment_get_step_increment (adj),
                             gtk_adjustment_get_page_increment (adj),
                             gtk_adjustment_get_page_size (adj));
-  g_signal_handlers_unblock_by_func (adj, size_change_cb, fontchooser);
+  g_signal_handlers_unblock_by_func (adj, size_change_cb, self);
 
   for (i = 0; i < n_sizes; i++)
     {
-      gtk_scale_add_mark (GTK_SCALE (fontchooser->size_slider),
+      gtk_scale_add_mark (GTK_SCALE (self->size_slider),
                           sizes[i],
                           GTK_POS_BOTTOM, NULL);
-      gtk_scale_add_mark (GTK_SCALE (fontchooser->size_slider2),
+      gtk_scale_add_mark (GTK_SCALE (self->size_slider2),
                           sizes[i],
                           GTK_POS_BOTTOM, NULL);
     }
@@ -508,10 +410,9 @@ gtk_font_chooser_widget_update_marks (GtkFontChooserWidget *fontchooser)
 }
 
 static void
-row_activated_cb (GtkTreeView       *view,
-                  GtkTreePath       *path,
-                  GtkTreeViewColumn *column,
-                  gpointer           user_data)
+row_activated_cb (GtkWidget *view,
+                  guint      pos,
+                  gpointer   user_data)
 {
   GtkFontChooserWidget *fontchooser = user_data;
   gchar *fontname;
@@ -522,54 +423,96 @@ row_activated_cb (GtkTreeView       *view,
 }
 
 static void
-cursor_changed_cb (GtkTreeView *treeview,
-                   gpointer     user_data)
+resize_by_scroll_cb (GtkEventControllerScroll *controller,
+                     double                    dx,
+                     double                    dy,
+                     gpointer                  user_data)
 {
-  GtkFontChooserWidget *fontchooser = user_data;
-  GtkDelayedFontDescription *desc;
-  GtkTreeIter filter_iter, iter;
-  GtkTreePath *path = NULL;
+  GtkFontChooserWidget *self = user_data;
+  GtkAdjustment *adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (self->size_spin));
 
-  gtk_tree_view_get_cursor (treeview, &path, NULL);
+  gtk_adjustment_set_value (adj,
+                            gtk_adjustment_get_value (adj) +
+                            gtk_adjustment_get_step_increment (adj) * dx);
+}
 
-  if (!path)
-    return;
+static void
+selection_changed_cb (GtkSingleSelection   *selection,
+                      GParamSpec           *pspec,
+                      GtkFontChooserWidget *self)
+{
+  gpointer item;
 
-  if (!gtk_tree_model_get_iter (fontchooser->filter_model, &filter_iter, path))
+  item = gtk_single_selection_get_selected_item (selection);
+  if (item)
     {
-      gtk_tree_path_free (path);
-      return;
-    }
+      PangoFontFace *face;
+      PangoFontDescription *desc;
 
-  gtk_tree_path_free (path);
+      if (PANGO_IS_FONT_FAMILY (item))
+        face = pango_font_family_get_face (item, NULL);
+      else
+        face = item;
+      desc = pango_font_face_describe (face);
+      pango_font_description_set_variations (self->font_desc, NULL);
+      gtk_font_chooser_widget_merge_font_desc (self, desc);
+      pango_font_description_free (desc);
+      g_simple_action_set_enabled (G_SIMPLE_ACTION (self->tweak_action), TRUE);
+    }
+  else
+    {
+      g_simple_action_set_state (G_SIMPLE_ACTION (self->tweak_action), g_variant_new_boolean (FALSE));
+      g_simple_action_set_enabled (G_SIMPLE_ACTION (self->tweak_action), FALSE);
+    }
 
-  gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (fontchooser->filter_model),
-                                                    &iter,
-                                                    &filter_iter);
-  gtk_tree_model_get (fontchooser->model, &iter,
-                      FONT_DESC_COLUMN, &desc,
-                      -1);
+  g_object_notify (G_OBJECT (self), "font");
+  g_object_notify (G_OBJECT (self), "font-desc");
+}
 
-  pango_font_description_set_variations (fontchooser->font_desc, NULL);
-  gtk_font_chooser_widget_merge_font_desc (fontchooser,
-                                           gtk_delayed_font_description_get (desc),
-                                           &iter);
+static char *
+get_font_name (GObject  *ignore,
+               gpointer  item)
+{
+  if (item == NULL)
+    return NULL;
 
-  gtk_delayed_font_description_unref (desc);
+  if (PANGO_IS_FONT_FACE (item))
+    {
+      return g_strconcat (pango_font_family_get_name (pango_font_face_get_family (item)),
+                          " ",
+                          pango_font_face_get_face_name (item),
+                          NULL);
+    }
+  else
+    {
+      return g_strdup (pango_font_family_get_name (item));
+    }
 }
 
-static void
-resize_by_scroll_cb (GtkEventControllerScroll *controller,
-                     double                    dx,
-                     double                    dy,
-                     gpointer                  user_data)
+static PangoAttrList *
+get_font_attributes (GObject  *ignore,
+                     gpointer  item)
 {
-  GtkFontChooserWidget *fc = user_data;
-  GtkAdjustment *adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (fc->size_spin));
+  PangoAttribute *attribute;
+  PangoAttrList *attrs;
 
-  gtk_adjustment_set_value (adj,
-                            gtk_adjustment_get_value (adj) +
-                            gtk_adjustment_get_step_increment (adj) * dx);
+  attrs = pango_attr_list_new ();
+
+  if (item)
+    {
+      PangoFontFace *face;
+      PangoFontDescription *font_desc;
+
+      if (PANGO_IS_FONT_FAMILY (item))
+        face = pango_font_family_get_face (item, NULL);
+      else
+        face = item;
+      font_desc = pango_font_face_describe (face);
+      attribute = pango_attr_font_desc_new (font_desc);
+      pango_attr_list_insert (attrs, attribute);
+    }
+
+  return attrs;
 }
 
 static void
@@ -595,17 +538,17 @@ gtk_font_chooser_widget_update_preview_attributes (GtkFontChooserWidget *fontcho
 }
 
 static void
-rows_changed_cb (GtkFontChooserWidget *fontchooser)
+rows_changed_cb (GtkFontChooserWidget *self)
 {
   const char *page;
 
-  if (gtk_tree_model_iter_n_children (fontchooser->filter_model, NULL) == 0)
+  if (g_list_model_get_n_items (G_LIST_MODEL (self->selection)) == 0)
     page = "empty";
   else
     page = "list";
 
-  if (strcmp (gtk_stack_get_visible_child_name (GTK_STACK (fontchooser->list_stack)), page) != 0)
-    gtk_stack_set_visible_child_name (GTK_STACK (fontchooser->list_stack), page);
+  if (strcmp (gtk_stack_get_visible_child_name (GTK_STACK (self->list_stack)), page) != 0)
+    gtk_stack_set_visible_child_name (GTK_STACK (self->list_stack), page);
 }
 
 static void
@@ -657,40 +600,21 @@ gtk_font_chooser_widget_unmap (GtkWidget *widget)
   GTK_WIDGET_CLASS (gtk_font_chooser_widget_parent_class)->unmap (widget);
 }
 
-static void
-fontconfig_changed (GtkFontChooserWidget *fontchooser)
-{
-  gtk_font_chooser_widget_load_fonts (fontchooser, TRUE);
-}
-
 static void
 gtk_font_chooser_widget_root (GtkWidget *widget)
 {
-  GtkSettings *settings;
-
   GTK_WIDGET_CLASS (gtk_font_chooser_widget_parent_class)->root (widget);
 
   g_signal_connect_swapped (gtk_widget_get_root (widget), "notify::focus-widget",
                             G_CALLBACK (update_key_capture), widget);
-
-  settings = gtk_widget_get_settings (widget);
-  g_signal_connect_object (settings, "notify::gtk-fontconfig-timestamp",
-                           G_CALLBACK (fontconfig_changed), widget, G_CONNECT_SWAPPED);
-
-  gtk_font_chooser_widget_load_fonts (GTK_FONT_CHOOSER_WIDGET (widget), FALSE);
- }
+}
 
 static void
 gtk_font_chooser_widget_unroot (GtkWidget *widget)
 {
-  GtkSettings *settings;
-
   g_signal_handlers_disconnect_by_func (gtk_widget_get_root (widget),
                                         update_key_capture, widget);
 
-  settings = gtk_widget_get_settings (widget);
-  g_signal_handlers_disconnect_by_func (settings, fontconfig_changed, widget);
-
   GTK_WIDGET_CLASS (gtk_font_chooser_widget_parent_class)->unroot (widget);
 }
 
@@ -699,8 +623,9 @@ gtk_font_chooser_widget_dispose (GObject *object)
 {
   GtkFontChooserWidget *self = GTK_FONT_CHOOSER_WIDGET (object);
 
-  if (self->family_face_list)
-    gtk_tree_view_set_model (GTK_TREE_VIEW (self->family_face_list), NULL);
+  self->filter_func = NULL;
+  g_clear_pointer (&self->filter_data, self->filter_data_destroy);
+
   g_clear_pointer (&self->stack, gtk_widget_unparent);
 
   G_OBJECT_CLASS (gtk_font_chooser_widget_parent_class)->dispose (object);
@@ -713,7 +638,6 @@ gtk_font_chooser_widget_class_init (GtkFontChooserWidgetClass *klass)
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
   GParamSpec *pspec;
 
-  g_type_ensure (GTK_TYPE_DELAYED_FONT_DESCRIPTION);
   g_type_ensure (G_TYPE_THEMED_ICON);
 
   widget_class->root = gtk_font_chooser_widget_root;
@@ -751,12 +675,10 @@ gtk_font_chooser_widget_class_init (GtkFontChooserWidgetClass *klass)
 
   gtk_widget_class_bind_template_child (widget_class, GtkFontChooserWidget, search_entry);
   gtk_widget_class_bind_template_child (widget_class, GtkFontChooserWidget, family_face_list);
-  gtk_widget_class_bind_template_child (widget_class, GtkFontChooserWidget, family_face_column);
-  gtk_widget_class_bind_template_child (widget_class, GtkFontChooserWidget, family_face_cell);
-  gtk_widget_class_bind_template_child (widget_class, GtkFontChooserWidget, list_scrolled_window);
   gtk_widget_class_bind_template_child (widget_class, GtkFontChooserWidget, list_stack);
-  gtk_widget_class_bind_template_child (widget_class, GtkFontChooserWidget, model);
   gtk_widget_class_bind_template_child (widget_class, GtkFontChooserWidget, filter_model);
+  gtk_widget_class_bind_template_child (widget_class, GtkFontChooserWidget, selection);
+  gtk_widget_class_bind_template_child (widget_class, GtkFontChooserWidget, custom_filter);
   gtk_widget_class_bind_template_child (widget_class, GtkFontChooserWidget, preview);
   gtk_widget_class_bind_template_child (widget_class, GtkFontChooserWidget, preview2);
   gtk_widget_class_bind_template_child (widget_class, GtkFontChooserWidget, size_label);
@@ -769,14 +691,14 @@ gtk_font_chooser_widget_class_init (GtkFontChooserWidgetClass *klass)
   gtk_widget_class_bind_template_child (widget_class, GtkFontChooserWidget, feature_box);
   gtk_widget_class_bind_template_child (widget_class, GtkFontChooserWidget, axis_grid);
 
-  gtk_widget_class_bind_template_callback (widget_class, text_changed_cb);
+  gtk_widget_class_bind_template_callback (widget_class, get_font_name);
+  gtk_widget_class_bind_template_callback (widget_class, get_font_attributes);
   gtk_widget_class_bind_template_callback (widget_class, stop_search_cb);
-  gtk_widget_class_bind_template_callback (widget_class, cursor_changed_cb);
   gtk_widget_class_bind_template_callback (widget_class, row_activated_cb);
   gtk_widget_class_bind_template_callback (widget_class, rows_changed_cb);
   gtk_widget_class_bind_template_callback (widget_class, size_change_cb);
   gtk_widget_class_bind_template_callback (widget_class, output_cb);
-  gtk_widget_class_bind_template_callback (widget_class, selection_changed);
+  gtk_widget_class_bind_template_callback (widget_class, selection_changed_cb);
   gtk_widget_class_bind_template_callback (widget_class, resize_by_scroll_cb);
 
   gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
@@ -853,51 +775,59 @@ axis_free (gpointer v)
 }
 
 static void
-gtk_font_chooser_widget_init (GtkFontChooserWidget *fontchooser)
+update_fontlist (GtkFontChooserWidget *self)
+{
+  PangoFontMap *fontmap;
+  GListModel *model;
+
+  fontmap = self->font_map;
+  if (!fontmap)
+    fontmap = pango_cairo_font_map_get_default ();
+
+  if ((self->level & GTK_FONT_CHOOSER_LEVEL_STYLE) == 0)
+    model = g_object_ref (G_LIST_MODEL (fontmap));
+  else
+    model = G_LIST_MODEL (gtk_flatten_list_model_new (PANGO_TYPE_FONT_FACE, G_LIST_MODEL (fontmap)));
+  gtk_filter_list_model_set_model (self->filter_model, model);
+  g_object_unref (model);
+}
+
+static void
+gtk_font_chooser_widget_init (GtkFontChooserWidget *self)
 {
-  gtk_widget_init_template (GTK_WIDGET (fontchooser));
+  gtk_widget_init_template (GTK_WIDGET (self));
 
-  fontchooser->axes = g_hash_table_new_full (axis_hash, axis_equal, NULL, axis_free);
+  self->axes = g_hash_table_new_full (axis_hash, axis_equal, NULL, axis_free);
 
   /* Default preview string  */
-  fontchooser->preview_text = g_strdup (pango_language_get_sample_string (NULL));
-  fontchooser->show_preview_entry = TRUE;
-  fontchooser->font_desc = pango_font_description_new ();
-  fontchooser->level = GTK_FONT_CHOOSER_LEVEL_FAMILY |
+  self->preview_text = g_strdup (pango_language_get_sample_string (NULL));
+  self->show_preview_entry = TRUE;
+  self->font_desc = pango_font_description_new ();
+  self->level = GTK_FONT_CHOOSER_LEVEL_FAMILY |
                 GTK_FONT_CHOOSER_LEVEL_STYLE |
                 GTK_FONT_CHOOSER_LEVEL_SIZE;
-  fontchooser->language = pango_language_get_default ();
+  self->language = pango_language_get_default ();
 
   /* Set default preview text */
-  gtk_editable_set_text (GTK_EDITABLE (fontchooser->preview), fontchooser->preview_text);
+  gtk_editable_set_text (GTK_EDITABLE (self->preview), self->preview_text);
 
-  gtk_font_chooser_widget_update_preview_attributes (fontchooser);
+  gtk_font_chooser_widget_update_preview_attributes (self);
 
   /* Set the upper values of the spin/scale with G_MAXINT / PANGO_SCALE */
-  gtk_spin_button_set_range (GTK_SPIN_BUTTON (fontchooser->size_spin),
+  gtk_spin_button_set_range (GTK_SPIN_BUTTON (self->size_spin),
                             1.0, (gdouble)(G_MAXINT / PANGO_SCALE));
-  gtk_adjustment_set_upper (gtk_range_get_adjustment (GTK_RANGE (fontchooser->size_slider)),
+  gtk_adjustment_set_upper (gtk_range_get_adjustment (GTK_RANGE (self->size_slider)),
                            (gdouble)(G_MAXINT / PANGO_SCALE));
 
-  /* Setup treeview/model auxiliary functions */
-  gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (fontchooser->filter_model),
-                                          visible_func, (gpointer)fontchooser, NULL);
-
-  gtk_tree_view_column_set_cell_data_func (fontchooser->family_face_column,
-                                           fontchooser->family_face_cell,
-                                           gtk_font_chooser_widget_cell_data_func,
-                                           fontchooser,
-                                           NULL);
+  self->tweak_action = G_ACTION (g_simple_action_new_stateful ("tweak", NULL, g_variant_new_boolean 
(FALSE)));
+  g_signal_connect (self->tweak_action, "change-state", G_CALLBACK (change_tweak), self);
 
-  fontchooser->tweak_action = G_ACTION (g_simple_action_new_stateful ("tweak", NULL, g_variant_new_boolean 
(FALSE)));
-  g_signal_connect (fontchooser->tweak_action, "change-state", G_CALLBACK (change_tweak), fontchooser);
+  update_fontlist (self);
 
   /* Load data and set initial style-dependent parameters */
-  gtk_font_chooser_widget_load_fonts (fontchooser, TRUE);
-  gtk_font_chooser_widget_populate_features (fontchooser);
+  gtk_font_chooser_widget_populate_features (self);
 
-  gtk_font_chooser_widget_set_cell_size (fontchooser);
-  gtk_font_chooser_widget_take_font_desc (fontchooser, NULL);
+  gtk_font_chooser_widget_take_font_desc (self, NULL);
 }
 
 /**
@@ -913,271 +843,6 @@ gtk_font_chooser_widget_new (void)
   return g_object_new (GTK_TYPE_FONT_CHOOSER_WIDGET, NULL);
 }
 
-static int
-cmp_families (const void *a,
-              const void *b)
-{
-  const char *a_name = pango_font_family_get_name (*(PangoFontFamily **)a);
-  const char *b_name = pango_font_family_get_name (*(PangoFontFamily **)b);
-
-  return g_utf8_collate (a_name, b_name);
-}
-
-static void
-gtk_font_chooser_widget_load_fonts (GtkFontChooserWidget *fontchooser,
-                                    gboolean              force)
-{
-  GtkListStore *list_store;
-  gint n_families, i;
-  PangoFontFamily **families;
-  guint fontconfig_timestamp;
-  gboolean need_reload;
-  PangoFontMap *font_map;
-
-  g_object_get (gtk_widget_get_settings (GTK_WIDGET (fontchooser)),
-                "gtk-fontconfig-timestamp", &fontconfig_timestamp,
-                NULL);
-
-  /* The fontconfig timestamp is only set on systems with fontconfig; every
-   * other platform will set it to 0. For those systems, we fall back to
-   * reloading the fonts every time.
-   */
-  need_reload = fontconfig_timestamp == 0 ||
-                fontconfig_timestamp != fontchooser->last_fontconfig_timestamp;
-
-  fontchooser->last_fontconfig_timestamp = fontconfig_timestamp;
-
-  if (!need_reload && !force)
-    return;
-
-  list_store = GTK_LIST_STORE (fontchooser->model);
-
-  if (fontchooser->font_map)
-    font_map = fontchooser->font_map;
-  else
-    font_map = pango_cairo_font_map_get_default ();
-  pango_font_map_list_families (font_map, &families, &n_families);
-
-  qsort (families, n_families, sizeof (PangoFontFamily *), cmp_families);
-
-  g_signal_handlers_block_by_func (fontchooser->family_face_list, cursor_changed_cb, fontchooser);
-  g_signal_handlers_block_by_func (fontchooser->filter_model, rows_changed_cb, fontchooser);
-  gtk_list_store_clear (list_store);
-
-  /* Iterate over families and faces */
-  for (i = 0; i < n_families; i++)
-    {
-      GtkTreeIter     iter;
-      PangoFontFace **faces;
-      int             j, n_faces;
-      const gchar    *fam_name = pango_font_family_get_name (families[i]);
-
-      pango_font_family_list_faces (families[i], &faces, &n_faces);
-
-      for (j = 0; j < n_faces; j++)
-        {
-          GtkDelayedFontDescription *desc;
-          const gchar *face_name;
-          char *title;
-
-          face_name = pango_font_face_get_face_name (faces[j]);
-
-          if ((fontchooser->level & GTK_FONT_CHOOSER_LEVEL_STYLE) != 0)
-            title = g_strconcat (fam_name, " ", face_name, NULL);
-          else
-            title = g_strdup (fam_name);
-
-          desc = gtk_delayed_font_description_new (faces[j]);
-
-          gtk_list_store_insert_with_values (list_store, &iter, -1,
-                                             FAMILY_COLUMN, families[i],
-                                             FACE_COLUMN, faces[j],
-                                             FONT_DESC_COLUMN, desc,
-                                             PREVIEW_TITLE_COLUMN, title,
-                                             -1);
-
-          g_free (title);
-          gtk_delayed_font_description_unref (desc);
-
-          if ((fontchooser->level & GTK_FONT_CHOOSER_LEVEL_STYLE) == 0)
-            break;
-        }
-
-      g_free (faces);
-    }
-
-  g_free (families);
-
-  rows_changed_cb (fontchooser);
-
-  g_signal_handlers_unblock_by_func (fontchooser->filter_model, rows_changed_cb, fontchooser);
-  g_signal_handlers_unblock_by_func (fontchooser->family_face_list, cursor_changed_cb, fontchooser);
-
-  /* now make sure the font list looks right */
-  if (!gtk_font_chooser_widget_find_font (fontchooser, fontchooser->font_desc, &fontchooser->font_iter))
-    memset (&fontchooser->font_iter, 0, sizeof (GtkTreeIter));
-
-  gtk_font_chooser_widget_ensure_selection (fontchooser);
-}
-
-static gboolean
-visible_func (GtkTreeModel *model,
-              GtkTreeIter  *iter,
-              gpointer      user_data)
-{
-  GtkFontChooserWidget *fontchooser = user_data;
-  gboolean result = TRUE;
-  const gchar *search_text;
-  gchar **split_terms;
-  gchar *font_name, *font_name_casefold;
-  guint i;
-
-  if (fontchooser->filter_func != NULL)
-    {
-      PangoFontFamily *family;
-      PangoFontFace *face;
-
-      gtk_tree_model_get (model, iter,
-                          FAMILY_COLUMN, &family,
-                          FACE_COLUMN, &face,
-                          -1);
-
-      result = fontchooser->filter_func (family, face, fontchooser->filter_data);
-
-      g_object_unref (family);
-      g_object_unref (face);
-      
-      if (!result)
-        return FALSE;
-    }
-
-  /* If there's no filter string we show the item */
-  search_text = gtk_editable_get_text (GTK_EDITABLE (fontchooser->search_entry));
-  if (strlen (search_text) == 0)
-    return TRUE;
-
-  gtk_tree_model_get (model, iter,
-                      PREVIEW_TITLE_COLUMN, &font_name,
-                      -1);
-
-  if (font_name == NULL)
-    return FALSE;
-
-  split_terms = g_strsplit (search_text, " ", 0);
-  font_name_casefold = g_utf8_casefold (font_name, -1);
-
-  for (i = 0; split_terms[i] && result; i++)
-    {
-      gchar* term_casefold = g_utf8_casefold (split_terms[i], -1);
-
-      if (!strstr (font_name_casefold, term_casefold))
-        result = FALSE;
-
-      g_free (term_casefold);
-    }
-
-  g_free (font_name_casefold);
-  g_free (font_name);
-  g_strfreev (split_terms);
-
-  return result;
-}
-
-/* in pango units */
-static int
-gtk_font_chooser_widget_get_preview_text_height (GtkFontChooserWidget *fontchooser)
-{
-  GtkWidget *treeview = fontchooser->family_face_list;
-  GtkStyleContext *context;
-  double font_size;
-
-  context = gtk_widget_get_style_context (treeview);
-  font_size = _gtk_css_number_value_get (_gtk_style_context_peek_property (context,
-                                                                     GTK_CSS_PROPERTY_FONT_SIZE),
-                                         100);
-
-  return PANGO_SCALE_X_LARGE * font_size * PANGO_SCALE;
-}
-
-static PangoAttrList *
-gtk_font_chooser_widget_get_preview_attributes (GtkFontChooserWidget       *fontchooser,
-                                                const PangoFontDescription *font_desc)
-{
-  PangoAttribute *attribute;
-  PangoAttrList *attrs;
-
-  attrs = pango_attr_list_new ();
-
-  if (font_desc)
-    {
-      attribute = pango_attr_font_desc_new (font_desc);
-      pango_attr_list_insert (attrs, attribute);
-    }
-
-  attribute = pango_attr_size_new_absolute (gtk_font_chooser_widget_get_preview_text_height (fontchooser));
-  pango_attr_list_insert (attrs, attribute);
-
-  return attrs;
-}
-
-static void
-gtk_font_chooser_widget_cell_data_func (GtkTreeViewColumn *column,
-                                        GtkCellRenderer   *cell,
-                                        GtkTreeModel      *tree_model,
-                                        GtkTreeIter       *iter,
-                                        gpointer           user_data)
-{
-  GtkFontChooserWidget *fontchooser = user_data;
-  GtkDelayedFontDescription *desc;
-  PangoAttrList *attrs;
-  char *preview_title;
-
-  gtk_tree_model_get (tree_model, iter,
-                      PREVIEW_TITLE_COLUMN, &preview_title,
-                      FONT_DESC_COLUMN, &desc,
-                      -1);
-
-  attrs = gtk_font_chooser_widget_get_preview_attributes (fontchooser,
-                                                          gtk_delayed_font_description_get (desc));
-
-  g_object_set (cell,
-                "xpad", 20,
-                "ypad", 10,
-                "attributes", attrs,
-                "text", preview_title,
-                NULL);
-
-  gtk_delayed_font_description_unref (desc);
-  pango_attr_list_unref (attrs);
-  g_free (preview_title);
-}
-
-static void
-gtk_font_chooser_widget_set_cell_size (GtkFontChooserWidget *fontchooser)
-{
-  PangoAttrList *attrs;
-  GtkRequisition size;
-
-  gtk_cell_renderer_set_fixed_size (fontchooser->family_face_cell, -1, -1);
-
-  attrs = gtk_font_chooser_widget_get_preview_attributes (fontchooser, NULL);
-  
-  g_object_set (fontchooser->family_face_cell,
-                "xpad", 20,
-                "ypad", 10,
-                "attributes", attrs,
-                "text", "x",
-                NULL);
-
-  pango_attr_list_unref (attrs);
-
-  gtk_cell_renderer_get_preferred_size (fontchooser->family_face_cell,
-                                        fontchooser->family_face_list,
-                                        &size,
-                                        NULL);
-  gtk_cell_renderer_set_fixed_size (fontchooser->family_face_cell, size.width, size.height);
-}
-
 static void
 gtk_font_chooser_widget_finalize (GObject *object)
 {
@@ -1211,89 +876,86 @@ my_pango_font_family_equal (const char *familya,
   return g_ascii_strcasecmp (familya, familyb) == 0;
 }
 
-static gboolean
-gtk_font_chooser_widget_find_font (GtkFontChooserWidget        *fontchooser,
-                                   const PangoFontDescription  *font_desc,
-                                   /* out arguments */
-                                   GtkTreeIter                 *iter)
+static void
+gtk_font_chooser_widget_ensure_matching_selection (GtkFontChooserWidget *self)
 {
-  gboolean valid;
+  const char *desc_family;
+  guint i, n;
 
-  if (pango_font_description_get_family (font_desc) == NULL)
-    return FALSE;
+  desc_family = pango_font_description_get_family (self->font_desc);
+  if (desc_family == NULL)
+    {
+      gtk_single_selection_set_selected (self->selection, GTK_INVALID_LIST_POSITION);
+      return;
+    }
 
-  for (valid = gtk_tree_model_get_iter_first (fontchooser->model, iter);
-       valid;
-       valid = gtk_tree_model_iter_next (fontchooser->model, iter))
+  n = g_list_model_get_n_items (G_LIST_MODEL (self->selection));
+  for (i = 0; i < n; i++)
     {
-      GtkDelayedFontDescription *desc;
-      PangoFontDescription *merged;
+      gpointer item = g_list_model_get_item (G_LIST_MODEL (self->selection), i);
+      PangoFontFace *face;
       PangoFontFamily *family;
+      PangoFontDescription *merged;
 
-      gtk_tree_model_get (fontchooser->model, iter,
-                          FAMILY_COLUMN, &family,
-                          FONT_DESC_COLUMN, &desc,
-                          -1);
-
-      if (!my_pango_font_family_equal (pango_font_description_get_family (font_desc),
-                                       pango_font_family_get_name (family)))
+      if (PANGO_IS_FONT_FAMILY (item))
+        {
+          family = item;
+          face = pango_font_family_get_face (family, NULL);
+        }
+      else
+        {
+          face = item;
+          family = pango_font_face_get_family (face);
+        }
+      if (!my_pango_font_family_equal (desc_family, pango_font_family_get_name (family)))
         {
-          gtk_delayed_font_description_unref (desc);
-          g_object_unref (family);
+          g_object_unref (face);
           continue;
         }
 
-      merged = pango_font_description_copy_static (gtk_delayed_font_description_get (desc));
+      merged = pango_font_face_describe (face);
+      pango_font_description_merge_static (merged, self->font_desc, FALSE);
+      g_object_unref (face);
 
-      pango_font_description_merge_static (merged, font_desc, FALSE);
-      if (pango_font_description_equal (merged, font_desc))
+      if (pango_font_description_equal (merged, self->font_desc))
         {
-          gtk_delayed_font_description_unref (desc);
           pango_font_description_free (merged);
-          g_object_unref (family);
           break;
         }
 
-      gtk_delayed_font_description_unref (desc);
       pango_font_description_free (merged);
-      g_object_unref (family);
     }
 
-  return valid;
+  gtk_single_selection_set_selected (self->selection, i);
 }
 
-static PangoFontFamily *
-gtk_font_chooser_widget_get_family (GtkFontChooser *chooser)
+static PangoFontFace *
+gtk_font_chooser_widget_get_face (GtkFontChooser *chooser)
 {
-  GtkFontChooserWidget *fontchooser = GTK_FONT_CHOOSER_WIDGET (chooser);
-  PangoFontFamily *family;
+  GtkFontChooserWidget *self = GTK_FONT_CHOOSER_WIDGET (chooser);
+  gpointer item;
 
-  if (!gtk_list_store_iter_is_valid (GTK_LIST_STORE (fontchooser->model), &fontchooser->font_iter))
-    return NULL;
-
-  gtk_tree_model_get (fontchooser->model, &fontchooser->font_iter,
-                      FAMILY_COLUMN, &family,
-                      -1);
-  g_object_unref (family);
-
-  return family;
+  item = gtk_single_selection_get_selected_item (self->selection);
+  if (PANGO_IS_FONT_FAMILY (item))
+    return pango_font_family_get_face (item, NULL);
+  else
+    return item;
 }
 
-static PangoFontFace *
-gtk_font_chooser_widget_get_face (GtkFontChooser *chooser)
+static PangoFontFamily *
+gtk_font_chooser_widget_get_family (GtkFontChooser *chooser)
 {
-  GtkFontChooserWidget *fontchooser = GTK_FONT_CHOOSER_WIDGET (chooser);
-  PangoFontFace *face;
+  GtkFontChooserWidget *self = GTK_FONT_CHOOSER_WIDGET (chooser);
+  gpointer item;
 
-  if (!gtk_list_store_iter_is_valid (GTK_LIST_STORE (fontchooser->model), &fontchooser->font_iter))
+  item = gtk_single_selection_get_selected_item (self->selection);
+  if (item == NULL)
     return NULL;
 
-  gtk_tree_model_get (fontchooser->model, &fontchooser->font_iter,
-                      FACE_COLUMN, &face,
-                      -1);
-  g_object_unref (face);
-
-  return face;
+  if (PANGO_IS_FONT_FAMILY (item))
+    return item;
+  else
+    return pango_font_face_get_family (item);
 }
 
 static gint
@@ -1320,13 +982,10 @@ gtk_font_chooser_widget_get_font (GtkFontChooserWidget *fontchooser)
 }
 
 static PangoFontDescription *
-gtk_font_chooser_widget_get_font_desc (GtkFontChooserWidget *fontchooser)
+gtk_font_chooser_widget_get_font_desc (GtkFontChooserWidget *self)
 {
-  GtkTreeSelection *selection;
-
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontchooser->family_face_list));
-  if (gtk_tree_selection_count_selected_rows (selection) > 0)
-    return fontchooser->font_desc;
+  if (gtk_single_selection_get_selected_item (self->selection))
+    return self->font_desc;
 
   return NULL;
 }
@@ -1341,95 +1000,6 @@ gtk_font_chooser_widget_set_font (GtkFontChooserWidget *fontchooser,
   gtk_font_chooser_widget_take_font_desc (fontchooser, font_desc);
 }
 
-static void
-gtk_font_chooser_widget_update_font_name (GtkFontChooserWidget *fontchooser,
-                                          GtkTreeSelection     *selection)
-{
-  GtkTreeModel *model;
-  GtkTreeIter iter;
-  PangoFontFamily *family;
-  PangoFontFace *face;
-  GtkDelayedFontDescription *desc;
-  const PangoFontDescription *font_desc;
-  PangoAttrList *attrs;
-  const char *fam_name;
-  const char *face_name;
-  char *title;
-
-  gtk_tree_selection_get_selected (selection, &model, &iter);
-  gtk_tree_model_get (model, &iter,
-                      FAMILY_COLUMN, &family,
-                      FACE_COLUMN, &face,
-                      FONT_DESC_COLUMN, &desc,
-                      -1);
-
-  fam_name = pango_font_family_get_name (family);
-  face_name = pango_font_face_get_face_name (face);
-  font_desc = gtk_delayed_font_description_get (desc);
-
-  g_object_unref (family);
-  g_object_unref (face);
-  gtk_delayed_font_description_unref (desc);
-
-  if ((fontchooser->level & GTK_FONT_CHOOSER_LEVEL_STYLE) != 0)
-    title = g_strconcat (fam_name, " ", face_name, NULL);
-  else
-    title = g_strdup (fam_name);
-
-  attrs = gtk_font_chooser_widget_get_preview_attributes (fontchooser, font_desc);
-  gtk_label_set_attributes (GTK_LABEL (fontchooser->font_name_label), attrs);
-  pango_attr_list_unref (attrs);
-
-  gtk_label_set_label (GTK_LABEL (fontchooser->font_name_label), title);
-  g_free (title);
-}
-
-static void
-selection_changed (GtkTreeSelection     *selection,
-                   GtkFontChooserWidget *fontchooser)
-{
-  g_object_notify (G_OBJECT (fontchooser), "font");
-  g_object_notify (G_OBJECT (fontchooser), "font-desc");
-
-  if (gtk_tree_selection_count_selected_rows (selection) > 0)
-    {
-      gtk_font_chooser_widget_update_font_name (fontchooser, selection);
-      g_simple_action_set_enabled (G_SIMPLE_ACTION (fontchooser->tweak_action), TRUE);
-    }
-  else
-    {
-      g_simple_action_set_state (G_SIMPLE_ACTION (fontchooser->tweak_action), g_variant_new_boolean (FALSE));
-      g_simple_action_set_enabled (G_SIMPLE_ACTION (fontchooser->tweak_action), FALSE);
-    }
-}
-
-static void
-gtk_font_chooser_widget_ensure_selection (GtkFontChooserWidget *fontchooser)
-{
-  GtkTreeSelection *selection;
-  GtkTreeIter filter_iter;
-
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontchooser->family_face_list));
-
-  if (gtk_list_store_iter_is_valid (GTK_LIST_STORE (fontchooser->model), &fontchooser->font_iter) &&
-      gtk_tree_model_filter_convert_child_iter_to_iter (GTK_TREE_MODEL_FILTER (fontchooser->filter_model),
-                                                        &filter_iter,
-                                                        &fontchooser->font_iter))
-    {
-      GtkTreePath *path = gtk_tree_model_get_path (GTK_TREE_MODEL (fontchooser->filter_model),
-                                                   &filter_iter);
-
-      gtk_tree_selection_select_iter (selection, &filter_iter);
-      gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (fontchooser->family_face_list),
-                                    path, NULL, FALSE, 0.0, 0.0);
-      gtk_tree_path_free (path);
-    }
-  else
-    {
-      gtk_tree_selection_unselect_all (selection);
-    }
-}
-
 /* OpenType variations */
 
 static void
@@ -2238,8 +1808,7 @@ update_font_features (GtkFontChooserWidget *fontchooser)
 
 static void
 gtk_font_chooser_widget_merge_font_desc (GtkFontChooserWidget       *fontchooser,
-                                         const PangoFontDescription *font_desc,
-                                         GtkTreeIter                *iter)
+                                         const PangoFontDescription *font_desc)
 {
   PangoFontMask mask;
 
@@ -2268,16 +1837,6 @@ gtk_font_chooser_widget_merge_font_desc (GtkFontChooserWidget       *fontchooser
     {
       gboolean has_tweak = FALSE;
 
-      if (&fontchooser->font_iter != iter)
-        {
-          if (iter == NULL)
-            memset (&fontchooser->font_iter, 0, sizeof (GtkTreeIter));
-          else
-            memcpy (&fontchooser->font_iter, iter, sizeof (GtkTreeIter));
-
-          gtk_font_chooser_widget_ensure_selection (fontchooser);
-        }
-
       gtk_font_chooser_widget_update_marks (fontchooser);
 
       if (gtk_font_chooser_widget_update_font_features (fontchooser))
@@ -2304,19 +1863,12 @@ gtk_font_chooser_widget_take_font_desc (GtkFontChooserWidget *fontchooser,
     font_desc = pango_font_description_from_string (GTK_FONT_CHOOSER_DEFAULT_FONT_NAME);
 
   mask = pango_font_description_get_set_fields (font_desc);
+  gtk_font_chooser_widget_merge_font_desc (fontchooser, font_desc);
+
   if (mask & (PANGO_FONT_MASK_FAMILY | PANGO_FONT_MASK_STYLE | PANGO_FONT_MASK_VARIANT |
               PANGO_FONT_MASK_WEIGHT | PANGO_FONT_MASK_STRETCH))
     {
-      GtkTreeIter iter;
-
-      if (gtk_font_chooser_widget_find_font (fontchooser, font_desc, &iter))
-        gtk_font_chooser_widget_merge_font_desc (fontchooser, font_desc, &iter);
-      else
-        gtk_font_chooser_widget_merge_font_desc (fontchooser, font_desc, NULL);
-    }
-  else
-    {
-      gtk_font_chooser_widget_merge_font_desc (fontchooser, font_desc, &fontchooser->font_iter);
+      gtk_font_chooser_widget_ensure_matching_selection (fontchooser);
     }
 
   pango_font_description_free (font_desc);
@@ -2339,10 +1891,6 @@ gtk_font_chooser_widget_set_preview_text (GtkFontChooserWidget *fontchooser,
   gtk_editable_set_text (GTK_EDITABLE (fontchooser->preview), text);
 
   g_object_notify (G_OBJECT (fontchooser), "preview-text");
-
-  /* XXX: There's no API to tell the treeview that a column has changed,
-   * so we just */
-  gtk_widget_queue_draw (fontchooser->family_face_list);
 }
 
 static gboolean
@@ -2387,7 +1935,7 @@ gtk_font_chooser_widget_set_font_map (GtkFontChooser *chooser,
       context = gtk_widget_get_pango_context (fontchooser->preview);
       pango_context_set_font_map (context, fontmap);
 
-      gtk_font_chooser_widget_load_fonts (fontchooser, TRUE);
+      update_fontlist (fontchooser);
     }
 }
 
@@ -2399,22 +1947,54 @@ gtk_font_chooser_widget_get_font_map (GtkFontChooser *chooser)
   return fontchooser->font_map;
 }
 
+static gboolean
+gtk_font_chooser_widget_filter_cb (gpointer item,
+                                   gpointer data)
+{
+  GtkFontChooserWidget *self = GTK_FONT_CHOOSER_WIDGET (data);
+  PangoFontFamily *family;
+  PangoFontFace *face;
+
+  if (PANGO_IS_FONT_FAMILY (item))
+    {
+      family = item;
+      face = pango_font_family_get_face (family, NULL);
+    }
+  else
+    {
+      face = item;
+      family = pango_font_face_get_family (face);
+    }
+
+  return self->filter_func (family, face, self->filter_data);
+}
+
 static void
-gtk_font_chooser_widget_set_filter_func (GtkFontChooser  *chooser,
+gtk_font_chooser_widget_set_filter_func (GtkFontChooser   *chooser,
                                          GtkFontFilterFunc filter,
                                          gpointer          data,
                                          GDestroyNotify    destroy)
 {
-  GtkFontChooserWidget *fontchooser = GTK_FONT_CHOOSER_WIDGET (chooser);
+  GtkFontChooserWidget *self = GTK_FONT_CHOOSER_WIDGET (chooser);
 
-  if (fontchooser->filter_data_destroy)
-    fontchooser->filter_data_destroy (fontchooser->filter_data);
+  if (self->filter_data_destroy)
+    self->filter_data_destroy (self->filter_data);
 
-  fontchooser->filter_func = filter;
-  fontchooser->filter_data = data;
-  fontchooser->filter_data_destroy = destroy;
+  self->filter_func = filter;
+  self->filter_data = data;
+  self->filter_data_destroy = destroy;
 
-  gtk_font_chooser_widget_refilter_font_list (fontchooser);
+  if (filter)
+    {
+      gtk_custom_filter_set_filter_func (self->custom_filter,
+                                         gtk_font_chooser_widget_filter_cb,
+                                         self,
+                                         NULL);
+    }
+  else
+    {
+      gtk_custom_filter_set_filter_func (self->custom_filter, NULL, NULL, NULL);
+    }
 }
 
 static void
@@ -2439,7 +2019,7 @@ gtk_font_chooser_widget_set_level (GtkFontChooserWidget *fontchooser,
       gtk_widget_hide (fontchooser->size_spin);
    }
 
-  gtk_font_chooser_widget_load_fonts (fontchooser, TRUE);
+  update_fontlist (fontchooser);
 
   g_object_notify (G_OBJECT (fontchooser), "level");
 }
diff --git a/gtk/ui/gtkfontchooserwidget.ui b/gtk/ui/gtkfontchooserwidget.ui
index ac50802f91..01a3816677 100644
--- a/gtk/ui/gtkfontchooserwidget.ui
+++ b/gtk/ui/gtkfontchooserwidget.ui
@@ -1,17 +1,30 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface domain="gtk40">
-  <object class="GtkListStore" id="model">
-    <columns>
-      <column type="PangoFontFamily"/>
-      <column type="PangoFontFace"/>
-      <column type="GtkDelayedFontDescription"/>
-      <column type="gchararray"/>
-    </columns>
-  </object>
-  <object class="GtkTreeModelFilter" id="filter_model">
-    <property name="child-model">model</property>
-    <signal name="row-deleted" handler="rows_changed_cb" swapped="yes"/>
-    <signal name="row-inserted" handler="rows_changed_cb" swapped="yes"/>
+  <object class="GtkSingleSelection" id="selection">
+    <signal name="notify::selected-item" handler="selection_changed_cb" object="GtkFontChooserWidget" 
swapped="0" />
+    <signal name="items-changed" handler="rows_changed_cb" object="GtkFontChooserWidget" swapped="1" />
+    <property name="model">
+      <object class="GtkFilterListModel" id="filter_model">
+        <property name="filter">
+          <object class="GtkEveryFilter">
+            <child>
+              <object class="GtkStringFilter">
+                <binding name="search">
+                  <lookup name="text">search_entry</lookup>
+                </binding>
+                <property name="expression">
+                  <closure type="gchararray" swapped="1" function="get_font_name" />
+                </property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkCustomFilter" id="custom_filter">
+              </object>
+            </child>
+          </object>
+        </property>
+      </object>
+    </property>
   </object>
   <object class="GtkAdjustment" id="slider_adjustment">
     <property name="upper">100</property>
@@ -40,7 +53,6 @@
                     <property name="hexpand">1</property>
                     <property name="activates-default">1</property>
                     <property name="placeholder-text" translatable="yes">Search font name</property>
-                    <signal name="search-changed" handler="text_changed_cb" swapped="no"/>
                     <signal name="stop-search" handler="stop_search_cb" swapped="no"/>
                     <layout>
                       <property name="left-attach">0</property>
@@ -54,11 +66,11 @@
                       <object class="GtkStackPage">
                         <property name="name">list</property>
                         <property name="child">
-                          <object class="GtkGrid" id="font_grid">
+                          <object class="GtkGrid">
                             <property name="row-spacing">6</property>
                             <property name="column-spacing">6</property>
                             <child>
-                              <object class="GtkScrolledWindow" id="list_scrolled_window">
+                              <object class="GtkScrolledWindow">
                                 <property name="width-request">400</property>
                                 <property name="height-request">300</property>
                                 <property name="hexpand">1</property>
@@ -66,30 +78,40 @@
                                 <property name="hscrollbar-policy">never</property>
                                 <property name="has-frame">1</property>
                                 <child>
-                                  <object class="GtkTreeView" id="family_face_list">
-                                    <property name="model">filter_model</property>
-                                    <property name="headers-visible">0</property>
-                                    <property name="enable-search">0</property>
-                                    <property name="fixed-height-mode">1</property>
-                                    <signal name="cursor-changed" handler="cursor_changed_cb" swapped="no"/>
-                                    <signal name="row-activated" handler="row_activated_cb" swapped="no"/>
-                                    <child internal-child="selection">
-                                      <object class="GtkTreeSelection" id="treeview-selection1">
-                                        <property name="mode">browse</property>
-                                        <signal name="changed" handler="selection_changed"/>
-                                      </object>
-                                    </child>
-                                    <child>
-                                      <object class="GtkTreeViewColumn" id="family_face_column">
-                                        <property name="sizing">fixed</property>
-                                        <property name="title" translatable="yes">Font Family</property>
-                                        <child>
-                                          <object class="GtkCellRendererText" id="family_face_cell">
-                                            <property name="ellipsize">end</property>
-                                          </object>
-                                        </child>
+                                  <object class="GtkListView" id="family_face_list">
+                                    <property name="can-focus">1</property>
+                                    <property name="model">selection</property>
+                                    <signal name="activate" handler="row_activated_cb" swapped="no"/>
+                                    <property name="factory">
+                                      <object class="GtkBuilderListItemFactory">
+                                        <property name="bytes"><![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="GtkListItem">
+    <property name="child">
+      <object class="GtkLabel">
+        <property name="margin-start">20</property>
+        <property name="margin-end">20</property>
+        <property name="margin-top">10</property>
+        <property name="margin-bottom">10</property>
+        <property name="ellipsize">end</property>
+        <binding name="label">
+          <closure type="gchararray" function="get_font_name">
+            <lookup name="item">GtkListItem</lookup>
+          </closure>
+        </binding>
+        <binding name="attributes">
+          <closure type="PangoAttrList" function="get_font_attributes">
+            <lookup name="item">GtkListItem</lookup>
+          </closure>
+        </binding>
+      </object>
+    </property>
+  </template>
+</interface>
+                                        ]]></property>
                                       </object>
-                                    </child>
+                                    </property>
                                   </object>
                                 </child>
                                 <layout>
@@ -224,6 +246,16 @@
                     <property name="margin-end">12</property>
                     <property name="ellipsize">end</property>
                     <property name="xalign">0</property>
+                    <binding name="label" object="GtkFontChooserWidget">
+                      <closure type="gchararray" function="get_font_name">
+                        <lookup name="selected-item">selection</lookup>
+                      </closure>
+                    </binding>
+                    <binding name="attributes" object="GtkFontChooserWidget">
+                      <closure type="PangoAttrList" function="get_font_attributes">
+                        <lookup name="selected-item">selection</lookup>
+                      </closure>
+                    </binding>
                   </object>
                 </child>
                 <child>
diff --git a/meson.build b/meson.build
index 07f27c3b57..ec1897bef8 100644
--- a/meson.build
+++ b/meson.build
@@ -27,7 +27,7 @@ else
 endif
 
 glib_req           = '>= @0@.@1@.@2@'.format(glib_major_req, glib_minor_req, glib_micro_req)
-pango_req          = '>= 1.44.4'
+pango_req          = '>= 1.45.0'
 fribidi_req        = '>= 0.19.7'
 atk_req            = '>= 2.15.1'
 cairo_req          = '>= 1.14.0'


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]