[gnome-font-viewer/wip/ewlsh/gtk4: 51/51] Port to GTK4




commit d7fd5e7214166c56be4eec569f66065f1621fbf1
Author: Evan Welsh <contact evanwelsh com>
Date:   Sun Jan 9 17:57:56 2022 -0800

    Port to GTK4

 flatpak/org.gnome.font-viewer.json      |   1 +
 flatpak/org.gnome.font-viewerDevel.json |   1 +
 meson.build                             |   9 +-
 src/font-model.c                        |  57 ++-
 src/font-model.h                        |   5 +-
 src/font-view.c                         | 664 ++++++++++----------------------
 src/meson.build                         |   2 +-
 src/sushi-font-widget.c                 |  64 ++-
 8 files changed, 298 insertions(+), 505 deletions(-)
---
diff --git a/flatpak/org.gnome.font-viewer.json b/flatpak/org.gnome.font-viewer.json
index 1b50f30..c903c5c 100644
--- a/flatpak/org.gnome.font-viewer.json
+++ b/flatpak/org.gnome.font-viewer.json
@@ -26,6 +26,7 @@
         {
             "name": "gnome-desktop",
             "buildsystem": "meson",
+            "config-opts": ["-Dbuild_gtk4=true"],
             "sources": [
                 {
                     "type": "git",
diff --git a/flatpak/org.gnome.font-viewerDevel.json b/flatpak/org.gnome.font-viewerDevel.json
index b05406e..88af4ef 100644
--- a/flatpak/org.gnome.font-viewerDevel.json
+++ b/flatpak/org.gnome.font-viewerDevel.json
@@ -30,6 +30,7 @@
         {
             "name": "gnome-desktop",
             "buildsystem": "meson",
+            "config-opts": ["-Dbuild_gtk4=true"],
             "sources": [
                 {
                     "type": "git",
diff --git a/meson.build b/meson.build
index 2602c7d..dc0c8df 100644
--- a/meson.build
+++ b/meson.build
@@ -23,17 +23,16 @@ servicesdir = join_paths(datadir, 'dbus-1', 'services')
 thumbnailerdir = join_paths(datadir, 'thumbnailers')
 
 glib_req_version = '>= 2.56.0'
-gtk_req_version = '>= 3.24.1'
-libhandy_req_version = '>= 1.0.0'
+gtk_req_version = '>= 4.5.0'
 harfbuzz_req_version = '>= 0.9.9'
 
 glib_dep = dependency('glib-2.0', version: glib_req_version)
-gtk_dep = dependency('gtk+-3.0', version: gtk_req_version)
-libhandy_dep = dependency('libhandy-1', version: libhandy_req_version)
+gtk_dep = dependency('gtk4', version: gtk_req_version)
+libadwaita_dep = dependency('libadwaita-1')
 harfbuzz_dep = dependency('harfbuzz', version: harfbuzz_req_version)
 fontconfig_dep = dependency('fontconfig')
 freetype2_dep = dependency('freetype2')
-gnomedesktop_dep = dependency('gnome-desktop-3.0')
+gnomedesktop_dep = dependency('gnome-desktop-4')
 mathlib_dep = cc.find_library('m')
 
 if get_option('profile') == 'development'
diff --git a/src/font-model.c b/src/font-model.c
index b951732..33b6f21 100644
--- a/src/font-model.c
+++ b/src/font-model.c
@@ -26,7 +26,7 @@
 
 #include <gio/gio.h>
 #include <gtk/gtk.h>
-
+#include <pango/pango.h>
 #include <ft2build.h>
 #include FT_FREETYPE_H
 #include <fontconfig/fontconfig.h>
@@ -57,8 +57,9 @@ struct _FontViewModelItem
 {
     GObject parent_instance;
 
-    gchar *collation_key;
     gchar *font_name;
+    gchar *font_preview_text;
+    PangoFontDescription *font_description;
     GFile *file;
     int face_index;
 };
@@ -70,7 +71,6 @@ font_view_model_item_finalize (GObject *obj)
 {
     FontViewModelItem *self = FONT_VIEW_MODEL_ITEM (obj);
 
-    g_clear_pointer (&self->collation_key, g_free);
     g_clear_pointer (&self->font_name, g_free);
     g_clear_object (&self->file);
 
@@ -91,13 +91,16 @@ font_view_model_item_init (FontViewModelItem *self)
 
 static FontViewModelItem *
 font_view_model_item_new (const gchar *font_name,
+                          const gchar *font_preview_text,
+                          const PangoFontDescription* font_description,
                           GFile       *file,
                           int          face_index)
 {
     FontViewModelItem *item = g_object_new (FONT_VIEW_TYPE_MODEL_ITEM, NULL);
 
-    item->collation_key = g_utf8_collate_key (font_name, -1);
     item->font_name = g_strdup (font_name);
+    item->font_preview_text = g_strdup (font_preview_text);
+    item->font_description =  pango_font_description_copy(font_description);
     item->file = g_object_ref (file);
     item->face_index = face_index;
 
@@ -105,15 +108,21 @@ font_view_model_item_new (const gchar *font_name,
 }
 
 const gchar *
-font_view_model_item_get_collation_key (FontViewModelItem *self)
+font_view_model_item_get_font_name (FontViewModelItem *self)
 {
-    return self->collation_key;
+    return self->font_name;
 }
 
 const gchar *
-font_view_model_item_get_font_name (FontViewModelItem *self)
+font_view_model_item_get_font_preview_text (FontViewModelItem *self)
 {
-    return self->font_name;
+    return self->font_preview_text;
+}
+
+const PangoFontDescription*
+font_view_model_item_get_font_description (FontViewModelItem *self)
+{
+    return self->font_description;
 }
 
 GFile *
@@ -179,6 +188,25 @@ static const gchar* weight_to_name(int weight) {
     return NULL;
 }
 
+static const PangoWeight fc_weight_to_pango_weight(int weight) {
+    switch (weight) {
+        case FC_WEIGHT_THIN: return PANGO_WEIGHT_THIN;
+        case FC_WEIGHT_EXTRALIGHT: return PANGO_WEIGHT_ULTRALIGHT;
+        case FC_WEIGHT_LIGHT: return PANGO_WEIGHT_LIGHT;
+        case FC_WEIGHT_SEMILIGHT: return PANGO_WEIGHT_SEMILIGHT;
+        case FC_WEIGHT_BOOK: return PANGO_WEIGHT_BOOK;
+        case FC_WEIGHT_REGULAR: return PANGO_WEIGHT_NORMAL;
+        case FC_WEIGHT_MEDIUM: return PANGO_WEIGHT_MEDIUM;
+        case FC_WEIGHT_SEMIBOLD: return PANGO_WEIGHT_SEMIBOLD;
+        case FC_WEIGHT_BOLD: return PANGO_WEIGHT_BOLD;
+        case FC_WEIGHT_EXTRABOLD: return PANGO_WEIGHT_ULTRABOLD;
+        case FC_WEIGHT_HEAVY: return PANGO_WEIGHT_HEAVY;
+        case FC_WEIGHT_EXTRABLACK: return PANGO_WEIGHT_ULTRAHEAVY;
+    }
+
+    return PANGO_WEIGHT_NORMAL;
+}
+
 static const gchar* slant_to_name(int slant) {
     switch (slant) {
         case FC_SLANT_ROMAN: return NULL;
@@ -264,11 +292,22 @@ load_font_infos (GTask *task,
         g_mutex_unlock (&self->font_list_mutex);
 
         file = g_file_new_for_path ((const gchar *) path);
+
         font_name = build_font_name(style_name, family_name, slant, weight, TRUE);
         if (!font_name)
             continue;
+        
+        // TODO: Support scripts which don't contain "Aa"
+        const char* font_preview_text = g_strdup ("Aa");
+
+        PangoFontDescription* font_description = pango_font_description_new();
+
+        pango_font_description_set_family(font_description, family_name);
+        pango_font_description_set_weight(font_description, fc_weight_to_pango_weight(weight));
+        // TODO: Support italics
+        pango_font_description_set_style(font_description, PANGO_STYLE_NORMAL);
 
-        item = font_view_model_item_new (font_name, file, index);
+        item = font_view_model_item_new (font_name, font_preview_text, font_description, file, index);
         g_ptr_array_add (items, item);
     }
 
diff --git a/src/font-model.h b/src/font-model.h
index 68edf6a..e86d576 100644
--- a/src/font-model.h
+++ b/src/font-model.h
@@ -27,6 +27,7 @@
 #define __FONT_VIEW_MODEL_H__
 
 #include <gtk/gtk.h>
+#include <pango/pango.h>
 
 G_BEGIN_DECLS
 
@@ -35,7 +36,6 @@ typedef enum {
   COLUMN_PATH,
   COLUMN_FACE_INDEX,
   COLUMN_ICON,
-  COLUMN_COLLATION_KEY,
   NUM_COLUMNS
 } FontViewModelColumns;
 
@@ -56,9 +56,10 @@ G_DECLARE_FINAL_TYPE (FontViewModelItem, font_view_model_item,
                       GObject)
 
 gint font_view_model_item_get_face_index (FontViewModelItem *self);
-const gchar *font_view_model_item_get_collation_key (FontViewModelItem *self);
 GFile *font_view_model_item_get_font_file (FontViewModelItem *self);
 const gchar *font_view_model_item_get_font_name (FontViewModelItem *self);
+const gchar *font_view_model_item_get_font_preview_text (FontViewModelItem *self);
+const PangoFontDescription *font_view_model_item_get_font_description (FontViewModelItem *self);
 
 G_END_DECLS
 
diff --git a/src/font-view.c b/src/font-view.c
index 9980e28..224631b 100644
--- a/src/font-view.c
+++ b/src/font-view.c
@@ -32,8 +32,9 @@
 #include <fontconfig/fontconfig.h>
 #include <gio/gio.h>
 #include <gtk/gtk.h>
+#include <gdk/gdk.h>
 #include <glib/gi18n.h>
-#include <libhandy-1/handy.h>
+#include <libadwaita-1/adwaita.h>
 #include <hb.h>
 #include <hb-ot.h>
 #include <hb-ft.h>
@@ -54,29 +55,28 @@ G_DECLARE_FINAL_TYPE (FontViewApplication, font_view_application,
 struct _FontViewApplication {
     GtkApplication parent;
 
-    GtkWidget *main_window;
+    GtkApplicationWindow *main_window;
     GtkWidget *main_grid;
     GtkWidget *header;
     GtkWidget *title_label;
     GtkWidget *side_grid;
     GtkWidget *font_widget;
-    GtkWidget *info_button;
-    GtkWidget *install_button;
-    GtkWidget *install_label;
-    GtkWidget *installing_label;
-    GtkWidget *installed_label;
-    GtkWidget *install_failed_label;
+    GtkToggleButton *info_button;
+    GtkButton *install_button;
     GtkWidget *back_button;
     GtkWidget *stack;
     GtkWidget *swin_view;
     GtkWidget *swin_preview;
     GtkWidget *swin_info;
-    GtkWidget *flow_box;
+    GtkWidget *grid_view;
     GtkWidget *search_bar;
     GtkWidget *search_entry;
     GtkWidget *search_toggle;
     GtkWidget *menu_button;
 
+    GtkFilter* filter;
+    GtkSorter* sorter;
+
     FontViewModel *model;
 
     GFile *font_file;
@@ -94,48 +94,21 @@ G_DECLARE_FINAL_TYPE (FontViewItem, font_view_item,
 struct _FontViewItem {
     GtkFlowBoxChild parent;
 
-    GtkWidget *image;
+    GtkWidget *font_preview;
     GtkWidget *label;
-    FontViewModelItem *item;
 
     GCancellable *thumbnail_cancellable;
 };
 
 #define FONT_VIEW_TYPE_ITEM (font_view_item_get_type ())
-G_DEFINE_TYPE (FontViewItem, font_view_item, GTK_TYPE_FLOW_BOX_CHILD)
-
-static cairo_surface_t *
-load_fallback_icon (gint scale_factor)
-{
-    static cairo_surface_t *fallback_icon = NULL;
-    g_autoptr(GIcon) icon = NULL;
-    g_autoptr(GtkIconInfo) icon_info = NULL;
-    GtkIconTheme *icon_theme;
-    const char *mimetype = "font/ttf";
-
-    if (fallback_icon != NULL)
-        return fallback_icon;
-
-    icon_theme = gtk_icon_theme_get_default ();
-    icon = g_content_type_get_icon (mimetype);
-    icon_info = gtk_icon_theme_lookup_by_gicon_for_scale (icon_theme, icon,
-                                                          128, scale_factor,
-                                                          GTK_ICON_LOOKUP_FORCE_SIZE);
-    if (!icon_info) {
-        g_warning ("Fallback icon for %s not found", mimetype);
-        return NULL;
-    }
-
-    fallback_icon = gtk_icon_info_load_surface (icon_info, NULL, NULL);
-    return fallback_icon;
-}
+// TODO: Perhaps this should be a GtkWidget with a layout, but this was easier to map for now.
+G_DEFINE_TYPE (FontViewItem, font_view_item, GTK_TYPE_BOX)
 
 static void
 font_view_item_dispose (GObject *obj)
 {
     FontViewItem *self = FONT_VIEW_ITEM (obj);
 
-    g_clear_object (&self->item);
     g_cancellable_cancel (self->thumbnail_cancellable);
     g_clear_object (&self->thumbnail_cancellable);
 
@@ -152,26 +125,24 @@ font_view_item_class_init (FontViewItemClass *klass)
 static void
 font_view_item_init (FontViewItem *self)
 {
-    GtkWidget *box;
-    gint scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (self));
-
-    box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
-    gtk_container_add (GTK_CONTAINER (self), box);
+    gtk_orientable_set_orientation(GTK_ORIENTABLE(self), GTK_ORIENTATION_VERTICAL);
+    gtk_box_set_spacing(GTK_BOX(self), 6);
 
-    self->image = gtk_image_new ();
-    gtk_widget_set_margin_start (self->image, 6);
-    gtk_widget_set_margin_end (self->image, 6);
-    gtk_widget_set_halign (self->image, GTK_ALIGN_CENTER);
-    gtk_image_set_from_surface (GTK_IMAGE (self->image), load_fallback_icon (scale_factor));
-    gtk_container_add (GTK_CONTAINER (box), self->image);
+    self->font_preview = gtk_label_new(NULL);
+    gtk_widget_add_css_class(self->font_preview, "font-preview");
+    gtk_widget_set_margin_start (self->font_preview, 6);
+    gtk_widget_set_margin_end (self->font_preview, 6);
+    gtk_widget_set_halign (self->font_preview, GTK_ALIGN_CENTER);
+    gtk_box_append (GTK_BOX(self), self->font_preview);
 
     self->label = gtk_label_new (NULL);
     gtk_widget_set_halign (self->label, GTK_ALIGN_CENTER);
-    gtk_label_set_line_wrap (GTK_LABEL (self->label), TRUE);
-    gtk_label_set_line_wrap_mode (GTK_LABEL (self->label), PANGO_WRAP_WORD_CHAR);
+    // TODO: Adapt to GTK4
+    //gtk_label_set_line_wrap (GTK_LABEL (self->label), TRUE);
+    //gtk_label_set_line_wrap_mode (GTK_LABEL (self->label), PANGO_WRAP_WORD_CHAR);
     gtk_label_set_max_width_chars (GTK_LABEL (self->label), 18);
     gtk_label_set_justify (GTK_LABEL (self->label), GTK_JUSTIFY_CENTER);
-    gtk_container_add (GTK_CONTAINER (box), self->label);
+    gtk_box_append (GTK_BOX(self), self->label);
 }
 
 #define ATTRIBUTES_FOR_CREATING_THUMBNAIL \
@@ -181,191 +152,35 @@ font_view_item_init (FontViewItem *self)
     G_FILE_ATTRIBUTE_THUMBNAIL_PATH"," \
     G_FILE_ATTRIBUTE_THUMBNAILING_FAILED
 
-static GdkPixbuf *
-create_thumbnail (GFile       *font_file,
-                  const gchar *thumb_uri,
-                  gint         scale_factor)
+static GtkWidget *
+font_view_item_new ()
 {
-    g_autoptr(GdkPixbuf) pixbuf = NULL;
-    g_autoptr(GError) error = NULL;
-    g_autoptr(GFileInfo) info = NULL;
-    g_autoptr(GnomeDesktopThumbnailFactory) factory = NULL;
-    guint64 mtime;
-
-    info = g_file_query_info (font_file, ATTRIBUTES_FOR_CREATING_THUMBNAIL,
-                              G_FILE_QUERY_INFO_NONE,
-                              NULL, &error);
-
-    /* we don't care about reporting errors here, just fail the
-     * thumbnail.
-     */
-    if (info == NULL) {
-        g_autofree gchar *file_uri = g_file_get_uri (font_file);
-        g_debug ("Can't query info for file %s: %s", file_uri, error->message);
-        return NULL;
-    }
-
-    factory = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE);
-    pixbuf = gnome_desktop_thumbnail_factory_generate_thumbnail
-        (factory, thumb_uri, g_file_info_get_content_type (info));
-
-    mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
-    if (pixbuf != NULL) {
-        GdkPixbuf *scaled = gdk_pixbuf_scale_simple (pixbuf,
-                                                     128 * scale_factor,
-                                                     128 * scale_factor,
-                                                     GDK_INTERP_BILINEAR);
-        gnome_desktop_thumbnail_factory_save_thumbnail (factory, pixbuf,
-                                                        thumb_uri, (time_t) mtime);
-        g_object_unref (pixbuf);
-        pixbuf = scaled;
-    } else {
-        gnome_desktop_thumbnail_factory_create_failed_thumbnail (factory,
-                                                                 thumb_uri, (time_t) mtime);
-    }
+    FontViewItem *view_item = g_object_new (FONT_VIEW_TYPE_ITEM, NULL);
 
-    return g_steal_pointer (&pixbuf);
+    return GTK_WIDGET (view_item);
 }
 
-static void
-font_view_item_load_thumbnail_job (GTask *task,
-                                   gpointer source_object,
-                                   gpointer task_data,
-                                   GCancellable *cancellable)
+static void font_view_item_bind(FontViewItem *self, FontViewModelItem *item)
 {
-    FontViewItem *self = source_object;
-    FontViewModelItem *item = self->item;
-    gint scale_factor = GPOINTER_TO_INT (task_data);
-    g_autoptr(GdkPixbuf) pixbuf = NULL;
-    g_autoptr(GError) error = NULL;
-    g_autofree gchar *thumb_path = NULL, *thumb_uri = NULL, *file_uri = NULL;
-    gint face_index;
-    GFile *font_file;
-
-    if (g_task_return_error_if_cancelled (task))
-        return;
-
-    face_index = font_view_model_item_get_face_index (item);
-    font_file = font_view_model_item_get_font_file (item);
-    file_uri = g_file_get_uri (font_file);
-
-    if (face_index == 0) {
-        g_autoptr(GFileInfo) info = NULL;
-        gboolean thumb_failed;
-
-        thumb_uri = g_strdup (file_uri);
-        info = g_file_query_info (font_file,
-                                  ATTRIBUTES_FOR_EXISTING_THUMBNAIL,
-                                  G_FILE_QUERY_INFO_NONE,
-                                  NULL, &error);
-
-        if (error != NULL) {
-            g_debug ("Can't query info for file %s: %s", file_uri, error->message);
-            g_task_return_error (task, g_steal_pointer(&error));
-            return;
-        }
-
-        thumb_failed = g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_THUMBNAILING_FAILED);
-        if (thumb_failed) {
-            g_task_return_pointer (task, NULL, NULL);
-            return;
-        }
-
-        thumb_path = g_strdup (g_file_info_get_attribute_byte_string (info, 
G_FILE_ATTRIBUTE_THUMBNAIL_PATH));
-    } else {
-        g_autofree gchar *checksum = NULL, *filename = NULL;
-
-        thumb_uri = g_strdup_printf ("%s#0x%08X", file_uri, face_index);
-        checksum = g_compute_checksum_for_data (G_CHECKSUM_MD5,
-                                                (const guchar *) thumb_uri,
-                                                strlen (thumb_uri));
-        filename = g_strdup_printf ("%s.png", checksum);
-
-        thumb_path = g_build_filename (g_get_user_cache_dir (),
-                                       "thumbnails",
-                                       "large",
-                                       filename,
-                                       NULL);
-
-        if (!g_file_test (thumb_path, G_FILE_TEST_IS_REGULAR))
-            g_clear_pointer (&thumb_path, g_free);
-    }
-
-    if (thumb_path != NULL) {
-        g_autoptr(GFile) thumb_file = NULL;
-        g_autoptr(GFileInputStream) is = NULL;
-
-        thumb_file = g_file_new_for_path (thumb_path);
-        is = g_file_read (thumb_file, NULL, &error);
-
-        if (error != NULL) {
-            g_debug ("Can't read file %s: %s", thumb_path, error->message);
-            g_task_return_error (task, g_steal_pointer(&error));
-            return;
-        }
-
-        pixbuf = gdk_pixbuf_new_from_stream_at_scale (G_INPUT_STREAM (is),
-                                                      128 * scale_factor, 128 * scale_factor,
-                                                      TRUE,
-                                                      NULL, &error);
-
-        if (error != NULL) {
-            g_debug ("Can't read thumbnail pixbuf %s: %s", thumb_path, error->message);
-            g_task_return_error (task, g_steal_pointer(&error));
-            return;
-        }
-    } else {
-        pixbuf = create_thumbnail (font_file, thumb_uri, scale_factor);
-    }
-
-    if (pixbuf != NULL)
-        g_task_return_pointer (task, gdk_cairo_surface_create_from_pixbuf (pixbuf, scale_factor, NULL),
-                               (GDestroyNotify) cairo_surface_destroy);
-    else
-        g_task_return_pointer (task, NULL, NULL);
+    gtk_label_set_text (GTK_LABEL (self->label),
+                        font_view_model_item_get_font_name (item));
+    gtk_label_set_text (GTK_LABEL (self->font_preview),
+                        font_view_model_item_get_font_preview_text(item));
+    
+    PangoAttrList* list = pango_attr_list_new();              
+    PangoAttribute* attr = pango_attr_font_desc_new(font_view_model_item_get_font_description(item));
+    pango_attr_list_insert(list, attr);
+    gtk_label_set_attributes(GTK_LABEL (self->font_preview),list);                
 }
 
-static void
-font_view_item_thumbnail_loaded (GObject *source_object,
-                                 GAsyncResult *result,
-                                 gpointer user_data)
+static void font_view_item_unbind(FontViewItem *self)
 {
-    FontViewItem *self = user_data;
-    cairo_surface_t *surface = g_task_propagate_pointer (G_TASK (result), NULL);
+    gtk_label_set_text (GTK_LABEL (self->label), NULL);
+    gtk_label_set_text(GTK_LABEL(self->font_preview), NULL);
+    gtk_label_set_attributes(GTK_LABEL(self->font_preview), NULL);
 
+    g_cancellable_cancel (self->thumbnail_cancellable);
     g_clear_object (&self->thumbnail_cancellable);
-
-    if (surface != NULL) {
-        gtk_image_set_from_surface (GTK_IMAGE (self->image), surface);
-        cairo_surface_destroy (surface);
-    }
-}
-
-static void
-font_view_item_load_thumbnail (FontViewItem *self)
-{
-    g_autoptr(GTask) task = NULL;
-    gint scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (self));
-
-    self->thumbnail_cancellable = g_cancellable_new ();
-    task = g_task_new (self, self->thumbnail_cancellable,
-                       font_view_item_thumbnail_loaded, self);
-    g_task_set_task_data (task, GINT_TO_POINTER (scale_factor), NULL);
-    g_task_run_in_thread (task, font_view_item_load_thumbnail_job);
-}
-
-static GtkWidget *
-font_view_item_new (FontViewModelItem *item)
-{
-    FontViewItem *view_item = g_object_new (FONT_VIEW_TYPE_ITEM, NULL);
-
-    view_item->item = g_object_ref (item);
-    gtk_label_set_text (GTK_LABEL (view_item->label),
-                        font_view_model_item_get_font_name (item));
-    font_view_item_load_thumbnail (view_item);
-    gtk_widget_show_all (GTK_WIDGET (view_item));
-
-    return GTK_WIDGET (view_item);
 }
 
 static void font_view_application_do_overview (FontViewApplication *self);
@@ -448,7 +263,7 @@ strip_version (gchar **original)
 }
 
 static void
-add_row (GtkWidget *grid,
+add_row (GtkBox *list,
          const gchar *name,
          const gchar *value,
          gboolean multiline)
@@ -456,20 +271,19 @@ add_row (GtkWidget *grid,
     GtkWidget *name_w, *label;
     int i;
     const char *p;
-
+    GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
     name_w = gtk_label_new (name);
     gtk_style_context_add_class (gtk_widget_get_style_context (name_w), "dim-label");
     gtk_widget_set_halign (name_w, GTK_ALIGN_END);
     gtk_widget_set_valign (name_w, GTK_ALIGN_START);
 
-    gtk_container_add (GTK_CONTAINER (grid), name_w);
+    gtk_box_append(GTK_BOX(hbox), name_w);
 
     label = gtk_label_new (value);
     gtk_widget_set_halign (label, GTK_ALIGN_START);
     gtk_widget_set_valign (label, GTK_ALIGN_START);
     gtk_label_set_selectable (GTK_LABEL(label), TRUE);
 
-    gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
     gtk_label_set_xalign (GTK_LABEL (label), 0.0);
 
     gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
@@ -491,9 +305,8 @@ add_row (GtkWidget *grid,
         }
     }
 
-    gtk_grid_attach_next_to (GTK_GRID (grid), label,
-                             name_w, GTK_POS_RIGHT,
-                             1, 1);
+    gtk_box_append(GTK_BOX(hbox), label);
+    gtk_box_append(list, hbox);
 }
 
 #define FixedToFloat(f) (((float)(f))/65536.0)
@@ -622,7 +435,7 @@ get_features (FT_Face face)
 
 static void
 populate_grid (FontViewApplication *self,
-               GtkWidget *grid,
+               GtkBox *grid,
                FT_Face face)
 {
     g_autoptr (GFileInfo) info = NULL;
@@ -741,7 +554,7 @@ populate_grid (FontViewApplication *self,
 
 static void
 populate_details (FontViewApplication *self,
-                  GtkWidget *grid,
+                  GtkBox *grid,
                   FT_Face face)
 {
     g_autofree gchar *glyph_count = NULL, *features = NULL;
@@ -779,58 +592,96 @@ install_button_refresh_appearance (FontViewApplication *self,
 {
     FT_Face face;
     GtkStyleContext *context;
-    GtkWidget *current_label;
-
-    context = gtk_widget_get_style_context (self->install_button);
 
-    current_label = gtk_bin_get_child (GTK_BIN (self->install_button));
-    gtk_container_remove (GTK_CONTAINER (self->install_button), current_label);
+    context = gtk_widget_get_style_context ((GtkWidget*) self->install_button);
 
     if (error != NULL) {
-        gtk_container_add (GTK_CONTAINER (self->install_button), self->install_failed_label);
-        gtk_widget_set_sensitive (self->install_button, FALSE);
+        gtk_button_set_label(self->install_button, _("Failed"));
+        gtk_widget_set_sensitive ((GtkWidget*) self->install_button, FALSE);
         gtk_style_context_remove_class (context, "suggested-action");
     } else {
         face = sushi_font_widget_get_ft_face (SUSHI_FONT_WIDGET (self->font_widget));
 
         if (font_view_model_has_face (FONT_VIEW_MODEL (self->model), face)) {
-            gtk_container_add (GTK_CONTAINER (self->install_button), self->installed_label);
-            gtk_widget_set_sensitive (self->install_button, FALSE);
+            gtk_button_set_label(self->install_button, _("Installed"));
+            gtk_widget_set_sensitive ((GtkWidget*) self->install_button, FALSE);
             gtk_style_context_remove_class (context, "suggested-action");
         } else if (self->cancellable != NULL) {
-            gtk_container_add (GTK_CONTAINER (self->install_button), self->installing_label);
-            gtk_widget_set_sensitive (self->install_button, FALSE);
+            gtk_button_set_label(self->install_button, _("Installing"));
+            gtk_widget_set_sensitive ((GtkWidget*) self->install_button, FALSE);
         } else {
-            gtk_container_add (GTK_CONTAINER (self->install_button), self->install_label);
-            gtk_widget_set_sensitive (self->install_button, TRUE);
+            gtk_button_set_label(self->install_button, _("Install"));
+            gtk_widget_set_sensitive ((GtkWidget*) self->install_button, TRUE);
             gtk_style_context_add_class (context, "suggested-action");
         }
     }
 }
 
+static char* font_name_closure(gpointer self) {
+    FontViewModelItem* item = FONT_VIEW_MODEL_ITEM(self);
+
+    return g_strdup(font_view_model_item_get_font_name(item));
+}
+
 static void
-font_view_populate_from_model (FontViewApplication *self,
-                               guint position,
-                               guint removed,
-                               guint added)
-{
-    GtkFlowBox *flow_box = GTK_FLOW_BOX (self->flow_box);
-    GListModel *list_model = font_view_model_get_list_model (self->model);
-    gint i;
+font_item_setup(GtkSignalListItemFactory *self,
+               GtkListItem              *listitem,
+               gpointer                  user_data) {
+                   gtk_list_item_set_activatable(listitem, true);
+   gtk_list_item_set_child(listitem, font_view_item_new());
+}
 
-    while (removed--) {
-        GtkFlowBoxChild *child;
+static void
+font_item_bind(GtkSignalListItemFactory *self,
+               GtkListItem              *listitem,
+               gpointer                  user_data) {
+    FontViewModelItem* model_item = gtk_list_item_get_item(listitem);
+    FontViewItem* item = FONT_VIEW_ITEM(gtk_list_item_get_child(listitem));
+    font_view_item_bind(item, model_item);
+}
 
-        child = gtk_flow_box_get_child_at_index (flow_box, position);
-        gtk_widget_destroy (GTK_WIDGET (child));
-    }
+static void
+font_item_unbind(GtkSignalListItemFactory *self,
+               GtkListItem              *listitem,
+               gpointer                  user_data) {
+    FontViewItem* item = FONT_VIEW_ITEM(gtk_list_item_get_child(listitem));
+    font_view_item_unbind(item);
+}
 
-    for (i = 0; i < added; i++) {
-        g_autoptr(FontViewModelItem) item = g_list_model_get_item (list_model, position + i);
-        GtkWidget *widget = font_view_item_new (item);
+static void
+font_item_teardown(GtkSignalListItemFactory *self,
+               GtkListItem              *listitem,
+               gpointer                  user_data) {
+}
 
-        gtk_flow_box_insert (flow_box, widget, position + i);
-    }
+static void
+font_view_create_grid_view (FontViewApplication *self)
+{
+    
+    GListModel *list_model = font_view_model_get_list_model (self->model);
+    GtkFilter* filter = GTK_FILTER(
+        gtk_string_filter_new(
+            gtk_closure_expression_new(G_TYPE_STRING, 
+                g_cclosure_new(G_CALLBACK(font_name_closure), NULL, NULL), 0, NULL)));
+    self->filter = filter;
+    GtkSorter* sorter = GTK_SORTER(
+        gtk_string_sorter_new(
+            gtk_closure_expression_new(G_TYPE_STRING, 
+                g_cclosure_new(G_CALLBACK(font_name_closure), NULL, NULL), 0, NULL)));
+    self->sorter = sorter;
+
+    GtkSortListModel* sort_model = gtk_sort_list_model_new(list_model, sorter);
+    GtkFilterListModel* filter_model = gtk_filter_list_model_new(G_LIST_MODEL(sort_model), filter);
+    GtkListItemFactory* factory = gtk_signal_list_item_factory_new();
+    
+    g_signal_connect(factory, "setup",  G_CALLBACK(font_item_setup), NULL);
+    g_signal_connect(factory, "bind",  G_CALLBACK(font_item_bind), NULL);
+    g_signal_connect(factory, "unbind",  G_CALLBACK(font_item_unbind), NULL);
+    g_signal_connect(factory, "teardown", G_CALLBACK(font_item_teardown), NULL);
+    
+    GtkNoSelection* selection = gtk_no_selection_new (G_LIST_MODEL(filter_model));
+    self->grid_view = gtk_grid_view_new(GTK_SELECTION_MODEL(selection), factory);
+    gtk_grid_view_set_single_click_activate(GTK_GRID_VIEW(self->grid_view), true);
 }
 
 static void
@@ -844,9 +695,6 @@ font_model_items_changed_cb (GListModel *model,
 
     if (self->font_file != NULL)
         install_button_refresh_appearance (self, NULL);
-
-    if (self->flow_box != NULL)
-        font_view_populate_from_model (self, position, removed, added);
 }
 
 static void
@@ -864,7 +712,7 @@ font_view_show_error (FontViewApplication *self,
                                      primary_text);
     gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
                                               "%s", secondary_text);
-    g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
+    g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_unparent), NULL);
     gtk_widget_show (dialog);
 }
 
@@ -1040,13 +888,15 @@ font_widget_loaded_cb (SushiFontWidget *font_widget,
     self->font_file = g_file_new_for_uri (uri);
 
     if (face->family_name) {
-        hdy_header_bar_set_title (HDY_HEADER_BAR (self->header), face->family_name);
+        GtkWidget* label = gtk_label_new(face->family_name);
+        gtk_header_bar_set_title_widget (GTK_HEADER_BAR (self->header), label);
     } else {
         g_autofree gchar *basename = g_file_get_basename (self->font_file);
-        hdy_header_bar_set_title (HDY_HEADER_BAR (self->header), basename);
+        GtkWidget* label = gtk_label_new(basename);
+        gtk_header_bar_set_title_widget (GTK_HEADER_BAR (self->header), label);
     }
 
-    hdy_header_bar_set_subtitle (HDY_HEADER_BAR (self->header), face->style_name);
+    // gtk_header_bar_set_subtitle (GTK_HEADER_BAR (self->header), face->style_name);
 
     install_button_refresh_appearance (self, NULL);
 }
@@ -1057,7 +907,8 @@ info_button_clicked_cb (GtkButton *button,
 {
     FontViewApplication *self = user_data;
     GtkWidget *grid;
-    GtkWidget *child;
+    // TODO:
+    // GtkWidget *child;
     FT_Face face = sushi_font_widget_get_ft_face (SUSHI_FONT_WIDGET (self->font_widget));
 
     if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) {
@@ -1068,58 +919,25 @@ info_button_clicked_cb (GtkButton *button,
     if (face == NULL)
         return;
 
-    child = gtk_bin_get_child (GTK_BIN (self->swin_info));
-    if (child)
-        gtk_widget_destroy (child);
+    // TODO:
+    // child = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (self->swin_info));
+    // if (child)
+    //    gtk_widget_unparent (child);
 
-    grid = gtk_grid_new ();
+    grid = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
     gtk_orientable_set_orientation (GTK_ORIENTABLE (grid), GTK_ORIENTATION_VERTICAL);
-    g_object_set (grid, "margin", 20, NULL);
-    gtk_grid_set_column_spacing (GTK_GRID (grid), 8);
-    gtk_grid_set_row_spacing (GTK_GRID (grid), 2);
+    g_object_set (grid, "margin-start", 20, NULL);
+    g_object_set (grid, "margin-end", 20, NULL);
+    g_object_set (grid, "margin-top", 20, NULL);
+    g_object_set (grid, "margin-bottom", 20, NULL);
 
-    populate_grid (self, grid, face);
-    populate_details (self, grid, face);
-    gtk_container_add (GTK_CONTAINER (self->swin_info), grid);
+    populate_grid (self, GTK_BOX(grid), face);
+    populate_details (self, GTK_BOX(grid), face);
+    gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (self->swin_info), grid);
 
-    gtk_widget_show_all (self->swin_info);
     gtk_stack_set_visible_child_name (GTK_STACK (self->stack), "info");
 }
 
-static gboolean
-font_view_filter_func (GtkFlowBoxChild *child,
-                       gpointer user_data)
-{
-    FontViewApplication *self = user_data;
-    FontViewItem *view_item = FONT_VIEW_ITEM (child);
-    FontViewModelItem *item = view_item->item;
-    g_autofree gchar *cf_name = NULL, *cf_search = NULL;
-    const char *font_name, *search;
-
-    if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->search_toggle)))
-        return TRUE;
-
-    search = gtk_entry_get_text (GTK_ENTRY (self->search_entry));
-    font_name = font_view_model_item_get_font_name (item);
-
-    cf_name = g_utf8_casefold (font_name, -1);
-    cf_search = g_utf8_casefold (search, -1);
-
-    return strstr (cf_name, cf_search) != NULL;
-}
-
-static gint
-font_view_sort_func (GtkFlowBoxChild *child1,
-                     GtkFlowBoxChild *child2,
-                     gpointer user_data)
-{
-    FontViewModelItem *item1 = FONT_VIEW_ITEM (child1)->item;
-    FontViewModelItem *item2 = FONT_VIEW_ITEM (child2)->item;
-
-    return g_strcmp0 (font_view_model_item_get_collation_key (item1),
-                      font_view_model_item_get_collation_key (item2));
-}
-
 static void
 font_view_ensure_model (FontViewApplication *self)
 {
@@ -1144,53 +962,36 @@ font_view_application_do_open (FontViewApplication *self,
     if (self->install_button == NULL) {
         g_autoptr(GtkSizeGroup) install_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
 
-        self->install_label = g_object_ref_sink (gtk_label_new (_("Install")));
-        gtk_widget_show (self->install_label);
-        gtk_size_group_add_widget (install_size_group, self->install_label);
-        self->installing_label = g_object_ref_sink (gtk_label_new (_("Installing…")));
-        gtk_widget_show (self->installing_label);
-        gtk_size_group_add_widget (install_size_group, self->installing_label);
-        self->installed_label = g_object_ref_sink (gtk_label_new (_("Installed")));
-        gtk_widget_show (self->installed_label);
-        gtk_size_group_add_widget (install_size_group, self->installed_label);
-        self->install_failed_label = g_object_ref_sink (gtk_label_new (_("Failed")));
-        gtk_widget_show (self->install_failed_label);
-        gtk_size_group_add_widget (install_size_group, self->install_failed_label);
-
-        self->install_button = gtk_button_new ();
-        gtk_container_add (GTK_CONTAINER (self->install_button), self->install_label);
-        gtk_widget_set_valign (self->install_button, GTK_ALIGN_CENTER);
-        gtk_style_context_add_class (gtk_widget_get_style_context (self->install_button),
+        self->install_button = GTK_BUTTON(gtk_button_new ());
+        gtk_button_set_label(self->install_button, _("Install"));
+        gtk_widget_set_valign ((GtkWidget*) self->install_button, GTK_ALIGN_CENTER);
+        gtk_style_context_add_class (gtk_widget_get_style_context ((GtkWidget*) self->install_button),
                                      "text-button");
-        hdy_header_bar_pack_end (HDY_HEADER_BAR (self->header), self->install_button);
+        gtk_header_bar_pack_end (GTK_HEADER_BAR (self->header), (GtkWidget*) self->install_button);
 
         g_signal_connect (self->install_button, "clicked",
                           G_CALLBACK (install_button_clicked_cb), self);
     }
 
     if (self->info_button == NULL) {
-        self->info_button = gtk_toggle_button_new_with_label (_("Info"));
-        gtk_widget_set_valign (self->info_button, GTK_ALIGN_CENTER);
-        gtk_style_context_add_class (gtk_widget_get_style_context (self->info_button),
+        self->info_button = GTK_TOGGLE_BUTTON(gtk_toggle_button_new_with_label (_("Info")));
+        gtk_widget_set_valign ((GtkWidget*) self->info_button, GTK_ALIGN_CENTER);
+        gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET(self->info_button)),
                                      "text-button");
-        hdy_header_bar_pack_end (HDY_HEADER_BAR (self->header), self->info_button);
+        gtk_header_bar_pack_end (GTK_HEADER_BAR (self->header), GTK_WIDGET(self->info_button));
 
         g_signal_connect (self->info_button, "toggled",
                           G_CALLBACK (info_button_clicked_cb), self);
     }
 
     if (self->back_button == NULL) {
-        GtkWidget *back_image;
-
         self->back_button = gtk_button_new ();
-        back_image = gtk_image_new_from_icon_name ("go-previous-symbolic",
-                                                   GTK_ICON_SIZE_MENU);
-        gtk_button_set_image (GTK_BUTTON (self->back_button), back_image);
+        gtk_button_set_icon_name (GTK_BUTTON (self->back_button), "go-previous-symbolic");
         gtk_widget_set_tooltip_text (self->back_button, _("Back"));
         gtk_widget_set_valign (self->back_button, GTK_ALIGN_CENTER);
         gtk_style_context_add_class (gtk_widget_get_style_context (self->back_button),
                                      "image-button");
-        hdy_header_bar_pack_start (HDY_HEADER_BAR (self->header), self->back_button);
+        gtk_header_bar_pack_start (GTK_HEADER_BAR (self->header), self->back_button);
 
         gtk_actionable_set_action_name (GTK_ACTIONABLE (self->back_button), "app.back");
     }
@@ -1204,7 +1005,7 @@ font_view_application_do_open (FontViewApplication *self,
         GtkWidget *viewport;
 
         self->font_widget = GTK_WIDGET (sushi_font_widget_new (uri, face_index));
-        gtk_container_add (GTK_CONTAINER (self->swin_preview), self->font_widget);
+        gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (self->swin_preview), self->font_widget);
         viewport = gtk_widget_get_parent (self->font_widget);
         gtk_scrollable_set_hscroll_policy (GTK_SCROLLABLE (viewport), GTK_SCROLL_NATURAL);
         gtk_scrollable_set_vscroll_policy (GTK_SCROLLABLE (viewport), GTK_SCROLL_NATURAL);
@@ -1218,19 +1019,18 @@ font_view_application_do_open (FontViewApplication *self,
         sushi_font_widget_load (SUSHI_FONT_WIDGET (self->font_widget));
     }
 
-    gtk_widget_show_all (self->main_window);
     gtk_stack_set_visible_child_name (GTK_STACK (self->stack), "preview");
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->info_button), FALSE);
+    gtk_toggle_button_set_active (self->info_button, FALSE);
 }
 
 static void
-view_child_activated_cb (GtkFlowBox *flow_box,
-                         GtkFlowBoxChild *child,
-                         gpointer user_data)
+view_child_activated_cb (GtkGridView *grid_view,
+                         guint        position,
+                         gpointer     user_data)
 {
     FontViewApplication *self = user_data;
-    FontViewItem *view_item = FONT_VIEW_ITEM (child);
-    FontViewModelItem *item = view_item->item;
+    GtkSelectionModel* model = gtk_grid_view_get_model(grid_view);
+    FontViewModelItem *item = FONT_VIEW_MODEL_ITEM (g_list_model_get_item(G_LIST_MODEL(model), position));
     GFile *font_file;
     gint face_index;
 
@@ -1246,16 +1046,15 @@ font_view_application_do_overview (FontViewApplication *self)
 {
     g_clear_object (&self->font_file);
 
-    g_clear_pointer (&self->back_button, gtk_widget_destroy);
-    g_clear_pointer (&self->info_button, gtk_widget_destroy);
+    g_clear_pointer (&self->back_button, gtk_widget_unparent);
 
-    if (self->install_button) {
-        g_clear_pointer (&self->install_label, gtk_widget_destroy);
-        g_clear_pointer (&self->installing_label, gtk_widget_destroy);
-        g_clear_pointer (&self->installed_label, gtk_widget_destroy);
-        g_clear_pointer (&self->install_failed_label, gtk_widget_destroy);
+    if (self->info_button) {
+        gtk_widget_unparent(GTK_WIDGET(self->info_button));
+        self->info_button = NULL;
+    }
 
-        gtk_widget_destroy (self->install_button);
+    if (self->install_button) {
+        gtk_widget_unparent (GTK_WIDGET(self->install_button));
         self->install_button = NULL;
     }
 
@@ -1263,65 +1062,33 @@ font_view_application_do_overview (FontViewApplication *self)
     gtk_widget_show (self->menu_button);
 
     font_view_ensure_model (self);
-
-    hdy_header_bar_set_title (HDY_HEADER_BAR (self->header), _("All Fonts"));
-    hdy_header_bar_set_subtitle (HDY_HEADER_BAR (self->header), NULL);
-
-    if (self->flow_box == NULL) {
-        GtkWidget *flow_box;
-
-        self->flow_box = flow_box = gtk_flow_box_new ();
-        g_object_set (flow_box,
-                      "column-spacing", VIEW_COLUMN_SPACING,
-                      "margin", VIEW_MARGIN,
-                      "selection-mode", GTK_SELECTION_NONE,
+    GtkWidget* title_label = gtk_label_new(_("All Fonts"));
+    gtk_header_bar_set_title_widget (GTK_HEADER_BAR (self->header), title_label);
+    // TODO: GTK4 - Setup subtitle
+    // gtk_header_bar_set_subtitle (GTK_HEADER_BAR (self->header), NULL);
+
+    if (self->grid_view == NULL) {
+        GtkWidget *grid_view;
+
+        font_view_create_grid_view(self);
+        grid_view = self->grid_view;
+        
+        g_object_set (grid_view,
+                      //  "column-spacing", VIEW_COLUMN_SPACING,
+                      // TODO: Set all margins
+                      "margin-start", VIEW_MARGIN,
                       "vexpand", TRUE,
                       NULL);
-        gtk_flow_box_set_filter_func (GTK_FLOW_BOX (flow_box),
-                                      font_view_filter_func,
-                                      self, NULL);
-        gtk_flow_box_set_sort_func (GTK_FLOW_BOX (flow_box),
-                                    font_view_sort_func,
-                                    self, NULL);
-        g_signal_connect (flow_box, "child-activated",
+
+        // TODO: Activate might not be correct/setup correctly
+        g_signal_connect (grid_view, "activate",
                           G_CALLBACK (view_child_activated_cb), self);
-        gtk_container_add (GTK_CONTAINER (self->swin_view), flow_box);
-
-        /* Instead of using gtk_flow_box_bind_model(), we populate the view
-         * manually, since we want to support filtering and sorting through
-         * the flowbox, which somehow gtk_flow_box_bind_model() does not support.
-         */
-        font_view_populate_from_model
-            (self, 0, 0,
-             g_list_model_get_n_items (font_view_model_get_list_model (self->model)));
+        gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (self->swin_view), grid_view);  
     }
 
-    gtk_widget_show_all (self->main_window);
     gtk_stack_set_visible_child_name (GTK_STACK (self->stack), "overview");
 }
 
-static gboolean
-font_view_window_key_press_event_cb (GtkWidget *widget,
-                                     GdkEventKey *event,
-                                     gpointer user_data)
-{
-    FontViewApplication *self = user_data;
-
-    if (event->keyval == GDK_KEY_q &&
-        (event->state & GDK_CONTROL_MASK) != 0) {
-        g_application_quit (G_APPLICATION (self));
-        return TRUE;
-    }
-
-    if (event->keyval == GDK_KEY_f &&
-        (event->state & GDK_CONTROL_MASK) != 0) {
-        gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (self->search_bar), TRUE);
-        return TRUE;
-    }
-
-    return gtk_search_bar_handle_event (GTK_SEARCH_BAR (self->search_bar), (GdkEvent *)event);
-}
-
 static void
 query_info_ready_cb (GObject *object,
                      GAsyncResult *res,
@@ -1364,7 +1131,7 @@ action_quit (GSimpleAction *action,
              gpointer user_data)
 {
     FontViewApplication *self = user_data;
-    gtk_widget_destroy (self->main_window);
+    gtk_window_destroy (GTK_WINDOW(self->main_window));
 }
 
 static void
@@ -1412,40 +1179,42 @@ static void
 search_text_changed (GtkEntry *entry,
                      FontViewApplication *self)
 {
-    gtk_flow_box_invalidate_filter (GTK_FLOW_BOX (self->flow_box));
+    const char* search = gtk_editable_get_text (GTK_EDITABLE (self->search_entry));
+
+    if (search == NULL || g_strcmp0(search, "") == 0) {
+        gtk_string_filter_set_search(GTK_STRING_FILTER(self->filter), NULL);
+        return;
+    }
+
+    gtk_string_filter_set_search(GTK_STRING_FILTER(self->filter), g_strdup(search));
 }
 
 static void
 ensure_window (FontViewApplication *self)
 {
     g_autoptr(GtkBuilder) builder = NULL;
-    GtkWidget *window, *swin, *box, *image;
+    GtkWidget *swin, *box, *image;
+    GtkApplicationWindow* window;
     GMenuModel *menu;
 
     if (self->main_window)
         return;
 
-    self->main_window = window = hdy_application_window_new ();
-    gtk_window_set_application (GTK_WINDOW (window), GTK_APPLICATION (self));
+    self->main_window = window = GTK_APPLICATION_WINDOW(gtk_application_window_new (GTK_APPLICATION (self)));
     gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
     gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
     gtk_window_set_icon_name (GTK_WINDOW (window), FONT_VIEW_ICON_NAME);
 
-    self->header = hdy_header_bar_new ();
-    hdy_header_bar_set_show_close_button (HDY_HEADER_BAR (self->header), TRUE);
+    self->header = gtk_header_bar_new ();
     gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (self->header)),
                                  "titlebar");
 
-    g_signal_connect (window, "key-press-event",
-                      G_CALLBACK (font_view_window_key_press_event_cb), self);
-
     self->main_grid = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
-    gtk_container_add (GTK_CONTAINER (self->main_grid), self->header);
-    gtk_container_add (GTK_CONTAINER (self->main_window), self->main_grid);
+    gtk_window_set_child (GTK_WINDOW (self->main_window), self->main_grid);
 
     self->stack = gtk_stack_new ();
     gtk_stack_set_transition_type (GTK_STACK (self->stack), GTK_STACK_TRANSITION_TYPE_CROSSFADE);
-    gtk_container_add (GTK_CONTAINER (self->main_grid), self->stack);
+    gtk_box_append (GTK_BOX (self->main_grid), self->stack);
     gtk_widget_set_hexpand (self->stack, TRUE);
     gtk_widget_set_vexpand (self->stack, TRUE);
 
@@ -1457,48 +1226,43 @@ ensure_window (FontViewApplication *self)
     menu = G_MENU_MODEL (gtk_builder_get_object (builder, "app-menu"));
 
     self->menu_button = gtk_menu_button_new ();
-    image = gtk_image_new_from_icon_name ("open-menu-symbolic", GTK_ICON_SIZE_BUTTON);
-    gtk_widget_show (image);
-    gtk_container_add (GTK_CONTAINER (self->menu_button), image);
+    gtk_menu_button_set_icon_name (GTK_MENU_BUTTON (self->menu_button), "open-menu-symbolic");
     gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (self->menu_button), menu);
-    gtk_widget_set_no_show_all (self->menu_button, TRUE);
-    gtk_widget_show (self->menu_button);
-    hdy_header_bar_pack_end (HDY_HEADER_BAR (self->header), self->menu_button);
+
+    gtk_header_bar_pack_end (GTK_HEADER_BAR (self->header), self->menu_button);
 
     self->search_bar = gtk_search_bar_new ();
-    gtk_container_add (GTK_CONTAINER (box), self->search_bar);
+    gtk_box_append (GTK_BOX (box), self->search_bar);
+    gtk_search_bar_set_key_capture_widget(GTK_SEARCH_BAR(self->search_bar), GTK_WIDGET(window));
     self->search_entry = gtk_search_entry_new ();
-    gtk_entry_set_width_chars (GTK_ENTRY (self->search_entry), 40);
-    gtk_container_add (GTK_CONTAINER (self->search_bar), self->search_entry);
+    gtk_search_bar_set_child (GTK_SEARCH_BAR (self->search_bar), self->search_entry);
     self->search_toggle = gtk_toggle_button_new ();
-    gtk_widget_set_no_show_all (self->search_toggle, TRUE);
-    gtk_widget_show (self->search_toggle);
-    image = gtk_image_new_from_icon_name ("edit-find-symbolic", GTK_ICON_SIZE_BUTTON);
-    gtk_widget_show (image);
-    gtk_container_add (GTK_CONTAINER (self->search_toggle), image);
-    hdy_header_bar_pack_end (HDY_HEADER_BAR (self->header), self->search_toggle);
+    image = gtk_image_new_from_icon_name ("edit-find-symbolic");
+    gtk_button_set_child(GTK_BUTTON(self->search_toggle), image);
+    gtk_header_bar_pack_end (GTK_HEADER_BAR (self->header), self->search_toggle);
     g_object_bind_property (self->search_bar, "search-mode-enabled",
                             self->search_toggle, "active",
                             G_BINDING_BIDIRECTIONAL);
 
     g_signal_connect (self->search_entry, "search-changed", G_CALLBACK (search_text_changed), self);
 
-    self->swin_view = swin = gtk_scrolled_window_new (NULL, NULL);
+    self->swin_view = swin = gtk_scrolled_window_new ();
     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
                                     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-    gtk_container_add (GTK_CONTAINER (box), self->swin_view);
+    gtk_box_append (GTK_BOX (box), self->swin_view);
 
-    self->swin_preview = swin = gtk_scrolled_window_new (NULL, NULL);
+    self->swin_preview = swin = gtk_scrolled_window_new ();
     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
                                     GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
     gtk_stack_add_named (GTK_STACK (self->stack), swin, "preview");
 
-    self->swin_info = swin = gtk_scrolled_window_new (NULL, NULL);
+    self->swin_info = swin = gtk_scrolled_window_new ();
     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
                                     GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
     gtk_stack_add_named (GTK_STACK (self->stack), swin, "info");
 
-    gtk_widget_show_all (window);
+gtk_window_set_titlebar(GTK_WINDOW(window), GTK_HEADER_BAR(self->header));
+    gtk_window_present(GTK_WINDOW(window));
 }
 
 static void
@@ -1508,7 +1272,7 @@ font_view_application_startup (GApplication *application)
 
     G_APPLICATION_CLASS (font_view_application_parent_class)->startup (application);
 
-    hdy_init ();
+    adw_init ();
 
     if (!FcInit ())
         g_critical ("Can't initialize fontconfig library");
diff --git a/src/meson.build b/src/meson.build
index 826c59b..396c8b2 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -31,7 +31,7 @@ executable('gnome-thumbnail-font', thumbnail_sources,
 
 executable('gnome-font-viewer', viewer_sources + resources,
   include_directories: [ root_inc, include_directories('.') ],
-  dependencies: [ mathlib_dep, glib_dep, gtk_dep, libhandy_dep, harfbuzz_dep, fontconfig_dep, freetype2_dep, 
gnomedesktop_dep ],
+  dependencies: [ mathlib_dep, glib_dep, gtk_dep, libadwaita_dep, harfbuzz_dep, fontconfig_dep, 
freetype2_dep, gnomedesktop_dep ],
   install: true)
 
 desktop_file = 'org.gnome.font-viewer.desktop'
diff --git a/src/sushi-font-widget.c b/src/sushi-font-widget.c
index ac1fcd4..eeff810 100644
--- a/src/sushi-font-widget.c
+++ b/src/sushi-font-widget.c
@@ -27,6 +27,7 @@
 #include "sushi-font-widget.h"
 #include "sushi-font-loader.h"
 
+#include <graphene.h>
 #include <hb-glib.h>
 #include <math.h>
 
@@ -476,7 +477,7 @@ sushi_font_widget_size_request (GtkWidget *drawing_area,
   cr = cairo_create (surface);
   context = gtk_widget_get_style_context (drawing_area);
   state = gtk_style_context_get_state (context);
-  gtk_style_context_get_padding (context, state, &padding);
+  gtk_style_context_get_padding (context, &padding);
 
   sizes = build_sizes_table (face, &n_sizes, &alpha_size, &title_size);
 
@@ -558,35 +559,27 @@ sushi_font_widget_size_request (GtkWidget *drawing_area,
 }
 
 static void
-sushi_font_widget_get_preferred_width (GtkWidget *drawing_area,
-                                       gint *minimum_width,
-                                       gint *natural_width)
+sushi_font_widget_measure (GtkWidget      *widget,
+                           GtkOrientation  orientation,
+                           int             for_size,
+                           int            *minimum,
+                           int            *natural,
+                           int            *minimum_baseline,
+                           int            *natural_baseline)
 {
-  gint width;
-
-  sushi_font_widget_size_request (drawing_area, &width, NULL, NULL);
-
-  *minimum_width = 0;
-  *natural_width = width;
+  if (orientation == GTK_ORIENTATION_HORIZONTAL) {
+    sushi_font_widget_size_request (widget, &natural, NULL, NULL);
+    *minimum = 0;
+  } else {
+    sushi_font_widget_size_request (widget, NULL, &natural, &minimum);
+  }
 }
 
 static void
-sushi_font_widget_get_preferred_height (GtkWidget *drawing_area,
-                                        gint *minimum_height,
-                                        gint *natural_height)
-{
-  gint height, min_height;
-
-  sushi_font_widget_size_request (drawing_area, NULL, &height, &min_height);
-
-  *minimum_height = min_height;
-  *natural_height = height;
-}
-
-static gboolean
-sushi_font_widget_draw (GtkWidget *drawing_area,
-                        cairo_t *cr)
+sushi_font_widget_snapshot (GtkWidget *drawing_area,
+                            GtkSnapshot *snapshot)
 {
+  
   SushiFontWidget *self = SUSHI_FONT_WIDGET (drawing_area);
   g_autofree gint *sizes = NULL;
   gint n_sizes, alpha_size, title_size, pos_y = 0, i;
@@ -595,23 +588,24 @@ sushi_font_widget_draw (GtkWidget *drawing_area,
   GtkStyleContext *context;
   GdkRGBA color;
   GtkBorder padding;
-  GtkStateFlags state;
   gint allocated_width, allocated_height;
 
   if (face == NULL)
-    return FALSE;
+    return;
 
   context = gtk_widget_get_style_context (drawing_area);
-  state = gtk_style_context_get_state (context);
 
   allocated_width = gtk_widget_get_allocated_width (drawing_area);
   allocated_height = gtk_widget_get_allocated_height (drawing_area);
 
+  graphene_rect_t* rect = graphene_rect_alloc();
+  graphene_rect_init(rect, 0, 0, allocated_width, allocated_height);
+    cairo_t* cr = gtk_snapshot_append_cairo (snapshot, rect);
   gtk_render_background (context, cr,
                          0, 0, allocated_width, allocated_height);
 
-  gtk_style_context_get_color (context, state, &color);
-  gtk_style_context_get_padding (context, state, &padding);
+  gtk_style_context_get_color (context, &color);
+  gtk_style_context_get_padding (context, &padding);
 
   gdk_cairo_set_source_rgba (cr, &color);
 
@@ -662,8 +656,6 @@ sushi_font_widget_draw (GtkWidget *drawing_area,
 
  end:
   cairo_font_face_destroy (font);
-
-  return FALSE;
 }
 
 static void
@@ -709,9 +701,6 @@ sushi_font_widget_init (SushiFontWidget *self)
 
   if (err != FT_Err_Ok)
     g_error ("Unable to initialize FreeType");
-
-  gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (self)),
-                               GTK_STYLE_CLASS_VIEW);
 }
 
 static void
@@ -801,9 +790,8 @@ sushi_font_widget_class_init (SushiFontWidgetClass *klass)
   oclass->get_property = sushi_font_widget_get_property;
   oclass->constructed = sushi_font_widget_constructed;
 
-  wclass->draw = sushi_font_widget_draw;
-  wclass->get_preferred_width = sushi_font_widget_get_preferred_width;
-  wclass->get_preferred_height = sushi_font_widget_get_preferred_height;
+  wclass->snapshot = sushi_font_widget_snapshot;
+  wclass->measure = sushi_font_widget_measure;
 
   properties[PROP_URI] =
     g_param_spec_string ("uri",


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