[ghex/gtk4-port: 42/91] Work on prefs dialog - mostly a rewrite.




commit 442612e4702169cde433a5329b5d7cb4c86d3ee5
Author: Logan Rathbone <poprocks gmail com>
Date:   Tue Jan 19 23:10:44 2021 -0500

    Work on prefs dialog - mostly a rewrite.

 data/gtkhex-4.pc.in               |   2 -
 data/org.gnome.GHex.gschema.xml   |  62 ++--
 po/POTFILES.in                    |   2 +-
 src/Makefile                      |   2 +-
 src/STUB.c                        |   3 +
 src/chartable.c                   |   7 -
 src/{config.c => configuration.c} | 116 +-----
 src/configuration.h               |  36 +-
 src/ghex-application-window.c     |  85 ++++-
 src/ghex-application-window.h     |   1 +
 src/ghex.gresource.xml            |   1 +
 src/gtkhex.c                      |   3 -
 src/meson.build                   |   2 +-
 src/preferences.c                 | 736 ++++++++++----------------------------
 src/preferences.h                 |  38 +-
 src/preferences.ui                | 218 +++++++++++
 16 files changed, 573 insertions(+), 741 deletions(-)
---
diff --git a/data/gtkhex-4.pc.in b/data/gtkhex-4.pc.in
index 569aea74..61eca64f 100644
--- a/data/gtkhex-4.pc.in
+++ b/data/gtkhex-4.pc.in
@@ -7,7 +7,5 @@ Name: gtkhex
 Description: GtkHex - A hex display widget.
 Version: @VERSION@
 Requires: gtk4
-Requires.private: gail-3.0
 Libs: -L${libdir} -lgtkhex-4
 Cflags: -I${includedir}/gtkhex-4
-
diff --git a/data/org.gnome.GHex.gschema.xml b/data/org.gnome.GHex.gschema.xml
index d41d263e..8941643a 100644
--- a/data/org.gnome.GHex.gschema.xml
+++ b/data/org.gnome.GHex.gschema.xml
@@ -1,35 +1,35 @@
+<!-- vim: ts=4 sw=4
+-->
 <schemalist>
 
-  <enum id="org.gnome.GHex.GroupType">
-    <value nick="bytes" value="1"/>
-    <value nick="words" value="2"/>
-    <value nick="longwords" value="4"/>
-  </enum>
+       <!-- it does not appear possible to automate this with meson presently.
+               See: https://github.com/mesonbuild/meson/issues/1687
+       -->
+       <enum id="org.gnome.GHex.GroupType">
+               <value nick="bytes" value="1"/>
+               <value nick="words" value="2"/>
+               <value nick="longwords" value="4"/>
+       </enum>
+
+       <schema id="org.gnome.GHex" path="/org/gnome/ghex/">
+               <key name="font" type="s">
+                       <default>'Monospace 12'</default>
+               </key>
+               <key name="group-data-by" enum="org.gnome.GHex.GroupType">
+                       <default>'bytes'</default>
+               </key>
+               <key name="print-font-data" type="s">
+                       <default>'Monospace 10'</default>
+               </key>
+               <key name="print-font-header" type="s">
+                       <default>'Sans 12'</default>
+               </key>
+               <key name="print-shaded-rows" type="u">
+                       <default>0</default>
+               </key>
+               <key name="show-offsets" type="b">
+                       <default>false</default>
+               </key>
+       </schema>
 
-  <schema id="org.gnome.GHex" path="/org/gnome/ghex/">
-    <key name="font" type="s">
-      <default>'Monospace 12'</default>
-    </key>
-    <key name="group-data-by" enum="org.gnome.GHex.GroupType">
-      <default>'bytes'</default>
-    </key>
-    <key name="max-undo-depth" type="u">
-      <default>100</default>
-    </key>
-    <key name="offset-format" type="s">
-      <default>'0x%X'</default>
-    </key>
-    <key name="print-font-data" type="s">
-      <default>'Courier 10'</default>
-    </key>
-    <key name="print-font-header" type="s">
-      <default>'Helvetica 12'</default>
-    </key>
-    <key name="print-shaded-rows" type="u">
-      <default>0</default>
-    </key>
-    <key name="show-offsets" type="b">
-      <default>true</default>
-    </key>
-  </schema>
 </schemalist>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index fb78d31f..1eb51a08 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -3,7 +3,7 @@
 data/org.gnome.GHex.appdata.xml.in
 data/org.gnome.GHex.desktop.in
 src/chartable.c
-src/config.c
+src/configuration.c
 src/converter.c
 src/findreplace.c
 src/ghex-ui.xml
diff --git a/src/Makefile b/src/Makefile
index fcf6132d..e8f22967 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -11,7 +11,7 @@ CFLAGS=-Wall -Wextra -Werror=implicit -std=c11 -pedantic \
 
 .PHONY: clean compile-resources
 
-STUB: gtkhex.o hex-document.o ghex-application-window.o hex-dialog.o findreplace.o chartable.o converter.o 
resources.o
+STUB: gtkhex.o hex-document.o ghex-application-window.o hex-dialog.o findreplace.o chartable.o converter.o 
resources.o configuration.o preferences.o
 
 compile-resources:
        glib-compile-resources ghex.gresource.xml --target=resources.c --generate-source
diff --git a/src/STUB.c b/src/STUB.c
index 4b030a2f..2aeb23fd 100644
--- a/src/STUB.c
+++ b/src/STUB.c
@@ -3,6 +3,7 @@
 
 #include <gtkhex.h>
 #include "ghex-application-window.h"
+#include "configuration.h"
 
 static void
 activate (GtkApplication *app,
@@ -24,6 +25,8 @@ main (int argc, char *argv[])
        GtkApplication *app;
        int status;
 
+       ghex_init_configuration ();
+
        app = gtk_application_new("org.gtk.example", G_APPLICATION_FLAGS_NONE);
        g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
 
diff --git a/src/chartable.c b/src/chartable.c
index 078d6406..5773d68b 100644
--- a/src/chartable.c
+++ b/src/chartable.c
@@ -263,13 +263,6 @@ GtkWidget *create_char_table(GtkWindow *parent_win, GtkHex *gh)
        gtk_box_append (GTK_BOX(hbox), cbtn);
        gtk_box_append (GTK_BOX(vbox), hbox);
 
-#if 0
-       gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
-       gtk_box_pack_start(GTK_BOX(hbox), lbl, TRUE, TRUE, 4);
-       gtk_box_pack_start(GTK_BOX(hbox), cbtn, FALSE, TRUE, 12);
-       gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
-#endif
-
        gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW(sw), ctv);
        gtk_window_set_child (GTK_WINDOW (ct), vbox);
 
diff --git a/src/config.c b/src/configuration.c
similarity index 51%
rename from src/config.c
rename to src/configuration.c
index e2a80c03..3067ee23 100644
--- a/src/config.c
+++ b/src/configuration.c
@@ -1,5 +1,7 @@
+/* vim: colorcolumn=80 ts=4 sw=4
+ */
 /* -*- mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* config.c - configuration loading/saving via gnome-config routines
+/* configuration.c - configuration loading/saving via GSettings
 
    Copyright (C) 1997 - 2004 Free Software Foundation
 
@@ -28,36 +30,24 @@
 #include <string.h>
 
 #include "configuration.h"
-#include "gtkhex.h"
-#include "ghex-window.h"
 
-#define DEFAULT_FONT "Monospace 12"
+GSettings *settings;
 
-GSettings *settings = NULL;
-
-gint def_group_type = GROUP_BYTE;
-guint max_undo_depth;
-gchar *offset_fmt = NULL;
-PangoFontMetrics *def_metrics = NULL; /* Changes for Gnome 2.0 */
-PangoFontDescription *def_font_desc = NULL;
-gchar *def_font_name = NULL;
-gboolean show_offsets_column = TRUE;
+int def_group_type;
+char *def_font_name;
+char *header_font_name;
+char *data_font_name;
+guint shaded_box_size;
+gboolean show_offsets_column;
 
 static void
 offsets_column_changed_cb (GSettings   *settings,
                            const gchar *key,
                            gpointer     user_data)
 {
-    const GList *winn;
     gboolean show_off = g_settings_get_boolean (settings, key);
 
     show_offsets_column = show_off;
-    winn = ghex_window_get_list ();
-    while (winn) {
-        if (GHEX_WINDOW (winn->data)->gh)
-            gtk_hex_show_offsets (GHEX_WINDOW (winn->data)->gh, show_off);
-        winn = g_list_next (winn);
-    }
 }
 
 static void
@@ -68,22 +58,6 @@ group_changed_cb (GSettings   *settings,
     def_group_type = g_settings_get_enum (settings, key);
 }
 
-static void
-max_undo_depth_changed_cb (GSettings   *settings,
-                           const gchar *key,
-                           gpointer     user_data)
-{
-    const GList *docn;
-
-    g_settings_get (settings, key, "u", &max_undo_depth);
-
-    docn = hex_document_get_list ();
-    while (docn) {
-        hex_document_set_max_undo (HEX_DOCUMENT (docn->data), max_undo_depth);
-        docn = g_list_next (docn);
-    }
-}
-
 static void
 box_size_changed_cb (GSettings   *settings,
                      const gchar *key,
@@ -92,74 +66,19 @@ box_size_changed_cb (GSettings   *settings,
     g_settings_get (settings, key, "u", &shaded_box_size);
 }
 
-static void
-offset_format_changed_cb (GSettings   *settings,
-                          const gchar *key,
-                          gpointer     user_data)
-{
-    gchar *old_offset_fmt = offset_fmt;
-    gint len, i;
-    gboolean expect_spec;
-
-    offset_fmt = g_strdup (g_settings_get_string (settings, key));
-
-    /* check for a valid format string */
-    len = strlen (offset_fmt);
-    expect_spec = FALSE;
-    for (i = 0; i < len; i++) {
-        if (offset_fmt[i] == '%')
-            expect_spec = TRUE;
-        if (expect_spec &&
-            ((offset_fmt[i] >= 'a' && offset_fmt[i] <= 'z') ||
-             (offset_fmt[i] >= 'A' && offset_fmt[i] <= 'Z'))) {
-            expect_spec = FALSE;
-            if (offset_fmt[i] != 'x' && offset_fmt[i] != 'd' &&
-                offset_fmt[i] != 'o' && offset_fmt[i] != 'X' &&
-                offset_fmt[i] != 'P' && offset_fmt[i] != 'p') {
-                g_free (offset_fmt);
-                offset_fmt = old_offset_fmt;
-                g_settings_set_string (settings, GHEX_PREF_OFFSET_FORMAT, "%X");
-            }
-        }
-    }
-    if (offset_fmt != old_offset_fmt)
-        g_free (old_offset_fmt);
-}
-
 static void
 font_changed_cb (GSettings   *settings,
                  const gchar *key,
                  gpointer     user_data)
 {
-    const GList *winn;
     const gchar *font_name = g_settings_get_string (settings, key);
-    PangoFontMetrics *new_metrics;
-    PangoFontDescription *new_desc;
 
     g_return_if_fail (font_name != NULL);
 
-    if ((new_metrics = gtk_hex_load_font (font_name)) != NULL) {
-        new_desc = pango_font_description_from_string (font_name);
-        winn = ghex_window_get_list ();
-        while (winn) {
-            if (GHEX_WINDOW (winn->data)->gh)
-                gtk_hex_set_font (GHEX_WINDOW (winn->data)->gh, new_metrics, new_desc);
-            winn = g_list_next (winn);
-        }
-
-        if (def_metrics)
-            pango_font_metrics_unref (def_metrics);
-
-        if (def_font_desc)
-            pango_font_description_free (def_font_desc);
+       if (def_font_name)
+               g_free (def_font_name);
 
-        if (def_font_name)
-            g_free (def_font_name);
-
-        def_metrics = new_metrics;
-        def_font_name = g_strdup (font_name);
-        def_font_desc = new_desc;
-    }
+       def_font_name = g_strdup (font_name);
 }
 
 static void
@@ -196,19 +115,10 @@ void ghex_init_configuration ()
                       G_CALLBACK (group_changed_cb), NULL);
     group_changed_cb (settings, GHEX_PREF_GROUP, NULL);
 
-    g_signal_connect (settings, "changed::" GHEX_PREF_MAX_UNDO_DEPTH,
-                      G_CALLBACK (max_undo_depth_changed_cb), NULL);
-    max_undo_depth_changed_cb (settings, GHEX_PREF_MAX_UNDO_DEPTH, NULL);
-
     g_signal_connect (settings, "changed::" GHEX_PREF_BOX_SIZE,
                       G_CALLBACK (box_size_changed_cb), NULL);
     box_size_changed_cb (settings, GHEX_PREF_BOX_SIZE, NULL);
 
-
-    g_signal_connect (settings, "changed::" GHEX_PREF_OFFSET_FORMAT,
-                      G_CALLBACK (offset_format_changed_cb), NULL);
-    offset_format_changed_cb (settings, GHEX_PREF_OFFSET_FORMAT, NULL);
-
     g_signal_connect (settings, "changed::" GHEX_PREF_FONT,
                       G_CALLBACK (font_changed_cb), NULL);
     font_changed_cb (settings, GHEX_PREF_FONT, NULL);
diff --git a/src/configuration.h b/src/configuration.h
index 97c42aad..d196d037 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -1,5 +1,7 @@
+/* vim: colorcolumn=80 ts=4 sw=4
+ */
 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* print.h - printing related stuff for ghex
+/* configuration.h - constants and declarations for GSettings
 
    Copyright (C) 1998 - 2004 Free Software Foundation
 
@@ -21,8 +23,8 @@
    Author: Jaka Mocnik <jaka gnu org>
 */
 
-#ifndef __GHEX_CONFIGURATION_H__
-#define __GHEX_CONFIGURATION_H__
+#ifndef GHEX_CONFIGURATION_H
+#define GHEX_CONFIGURATION_H
 
 #include <gtk/gtk.h>
 
@@ -34,33 +36,27 @@ G_BEGIN_DECLS
 /* GSettings keys */
 #define GHEX_PREF_FONT               "font"
 #define GHEX_PREF_GROUP              "group-data-by"
-#define GHEX_PREF_MAX_UNDO_DEPTH     "max-undo-depth"
-#define GHEX_PREF_OFFSET_FORMAT      "offset-format"
 #define GHEX_PREF_DATA_FONT          "print-font-data"
 #define GHEX_PREF_HEADER_FONT        "print-font-header"
 #define GHEX_PREF_BOX_SIZE           "print-shaded-rows"
 #define GHEX_PREF_OFFSETS_COLUMN     "show-offsets"
 
-/* our preferred settings; as only one copy of them is required,
-   we'll make them global vars, although this is a bit ugly */
-extern PangoFontMetrics *def_metrics;
-extern PangoFontDescription *def_font_desc;
+/* Our preferred settings; as only one copy of them is required,
+ * we'll make them global vars, though this is a bit ugly.
+ */
+extern char                    *def_font_name;
+extern char                    *data_font_name, *header_font_name;
+extern char                    *offset_fmt;
+extern gboolean                show_offsets_column;
 
-extern gchar      *def_font_name;
-extern gchar      *data_font_name, *header_font_name;
-extern gdouble    data_font_size, header_font_size;    
-extern guint      max_undo_depth;
-extern gchar      *offset_fmt;
-extern gboolean   show_offsets_column;
+extern guint           shaded_box_size;
+extern int                     def_group_type;
 
-extern guint      shaded_box_size;
-extern gint       def_group_type;
-
-extern GSettings *settings;
+extern GSettings       *settings;
 
 /* Initializes the gsettings client */
 void ghex_init_configuration (void);
 
 G_END_DECLS
 
-#endif /* !__GHEX_CONFIGURATION_H__ */
+#endif /* GHEX_CONFIGURATION_H */
diff --git a/src/ghex-application-window.c b/src/ghex-application-window.c
index 639adf59..8a873a81 100644
--- a/src/ghex-application-window.c
+++ b/src/ghex-application-window.c
@@ -4,10 +4,13 @@
 #include <gtkhex.h>
 
 #include "ghex-application-window.h"
+
+#include "configuration.h"
 #include "hex-dialog.h"
 #include "findreplace.h"
 #include "chartable.h"
 #include "converter.h"
+#include "preferences.h"
 
 /* DEFINES */
 
@@ -69,19 +72,13 @@ struct _GHexApplicationWindow
        GList *gh_list;
        gboolean can_save;
 
-       // TEST - NOT 100% SURE I WANNA GO THIS ROUTE YET.
        GtkWidget *find_dialog;
        GtkWidget *replace_dialog;
        GtkWidget *jump_dialog;
        GtkWidget *chartable;
        GtkWidget *converter;
 
-/*
- * for i in `cat ghex-application-window.ui |grep -i 'id=' |sed -e 's,^\s*,,g' |sed -e 's,.*id=",,' |sed -e 
's,">,,'`; do echo $i >> tmp.txt; done
- */
-
-/* for i in `cat tmp.txt`; do echo GtkWidget *${i}; done
- */
+       /* From GtkBuilder: */
        GtkWidget *no_doc_label;
        GtkWidget *hex_notebook;
        GtkWidget *conversions_box;
@@ -159,6 +156,35 @@ static void update_gui_data (GHexApplicationWindow *self);
 // FIXME - This could be the wrong approach. I don't know if we can
 // guarantee the tab will be un-switchable while the dialog is up.
        
+static void
+settings_offsets_column_changed_cb (GSettings   *settings,
+               const gchar     *key,
+               gpointer        user_data)
+{
+       GHexApplicationWindow *self = GHEX_APPLICATION_WINDOW(user_data);
+       GtkNotebook *notebook = GTK_NOTEBOOK(self->hex_notebook);
+       int i;
+
+       g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
+
+       for (i = gtk_notebook_get_n_pages(notebook) - 1; i >= 0; --i)
+       {
+               GHexNotebookTab *tab;
+               GtkHex *gh;
+
+               g_debug ("%s: Working on %d'th page", __func__, i);
+
+               gh = GTK_HEX(gtk_notebook_get_nth_page (notebook, i));
+               g_return_if_fail (GTK_IS_HEX (gh));
+
+               tab = GHEX_NOTEBOOK_TAB(gtk_notebook_get_tab_label (notebook,
+                                       GTK_WIDGET(gh)));
+               g_return_if_fail (GHEX_IS_NOTEBOOK_TAB (tab));
+
+               gtk_hex_show_offsets (gh, show_offsets_column);
+       }
+}
+
 GHexNotebookTab *
 ghex_application_window_get_current_tab (GHexApplicationWindow *self)
 {
@@ -184,10 +210,18 @@ ghex_application_window_remove_tab (GHexApplicationWindow *self,
        GtkNotebook *notebook = GTK_NOTEBOOK(self->hex_notebook);
        int page_num;
 
+       g_return_if_fail (GTK_IS_HEX(tab->gh));
+
        page_num = gtk_notebook_page_num (notebook,
                        GTK_WIDGET(tab->gh));
 
        gtk_notebook_remove_page (notebook, page_num);
+
+       /* FIXME - remove as a possible optimization - but let's keep it in
+        * for now for debugging purposes. */
+       g_return_if_fail (g_list_find (self->gh_list, tab->gh));
+       self->gh_list = g_list_remove (self->gh_list, tab->gh);
+
        g_object_unref (tab);
 }
 
@@ -871,8 +905,8 @@ new_gh_from_gfile (GFile *file)
        doc = hex_document_new_from_file (path);
        gh = GTK_HEX(gtk_hex_new (doc));
 
-       // FIXME - should be based on settings
-       gtk_hex_show_offsets (gh, TRUE);
+       /* Initialize whether offsets should be shown based on setting. */
+       gtk_hex_show_offsets (gh, show_offsets_column);
 
        if (error)      g_error_free (error);
        g_clear_object (&info);
@@ -950,6 +984,22 @@ toggle_conversions (GtkWidget *widget,
        }
 }
 
+
+static void
+open_preferences (GtkWidget *widget,
+               const char *action_name,
+               GVariant *parameter)
+{
+       GHexApplicationWindow *self = GHEX_APPLICATION_WINDOW(widget);
+       GtkWidget *prefs_dialog;
+
+       (void)parameter, (void)action_name;             /* unused */
+
+       // TEST
+       prefs_dialog = create_preferences_dialog();
+       gtk_widget_show (prefs_dialog);
+}
+
 static void
 toggle_insert_mode (GtkWidget *widget,
                const char *action_name,
@@ -1384,6 +1434,11 @@ ghex_application_window_init (GHexApplicationWindow *self)
        g_signal_connect (self, "close-request",
                        G_CALLBACK(close_request_cb), self);
 
+       /* Signals - SETTINGS */
+
+    g_signal_connect (settings, "changed::" GHEX_PREF_OFFSETS_COLUMN,
+                      G_CALLBACK (settings_offsets_column_changed_cb), self);
+
        /* Setup notebook signals */
 
        g_signal_connect (self->hex_notebook, "switch-page",
@@ -1530,6 +1585,10 @@ ghex_application_window_class_init(GHexApplicationWindowClass *klass)
                        NULL,   // GVariant string param_type
                        toggle_insert_mode);
 
+       gtk_widget_class_install_action (widget_class, "ghex.preferences",
+                       NULL,   // GVariant string param_type
+                       open_preferences);
+
        gtk_widget_class_install_property_action (widget_class,
                        "ghex.find", "find-open");
 
@@ -1669,3 +1728,11 @@ ghex_application_window_add_hex (GHexApplicationWindow *self,
        replace_dialog_set_hex (REPLACE_DIALOG(self->replace_dialog), self->gh);
        jump_dialog_set_hex (JUMP_DIALOG(self->jump_dialog), self->gh);
 }
+
+GList *
+ghex_application_window_get_list (GHexApplicationWindow *self)
+{
+       g_return_val_if_fail (GHEX_IS_APPLICATION_WINDOW (self), NULL);
+
+       return self->gh_list;
+}
diff --git a/src/ghex-application-window.h b/src/ghex-application-window.h
index 66272a9f..ca7d26af 100644
--- a/src/ghex-application-window.h
+++ b/src/ghex-application-window.h
@@ -18,5 +18,6 @@ void          ghex_application_window_set_hex (GHexApplicationWindow *self,
                                GtkHex *gh);
 void           ghex_application_window_activate_tab (GHexApplicationWindow *self,
                                GtkHex *gh);
+GList *                ghex_application_window_get_list (GHexApplicationWindow *self);
 
 #endif
diff --git a/src/ghex.gresource.xml b/src/ghex.gresource.xml
index 7957b542..b0759631 100644
--- a/src/ghex.gresource.xml
+++ b/src/ghex.gresource.xml
@@ -7,5 +7,6 @@
        <gresource prefix="/org/gnome/ghex">
                <file preprocess="xml-stripblanks" compressed="true">ghex-application-window.ui</file>
                <file preprocess="xml-stripblanks" compressed="true">context-menu.ui</file>
+               <file preprocess="xml-stripblanks" compressed="true">preferences.ui</file>
        </gresource>
 </gresources>
diff --git a/src/gtkhex.c b/src/gtkhex.c
index c8c018d5..b4ac5785 100644
--- a/src/gtkhex.c
+++ b/src/gtkhex.c
@@ -2972,15 +2972,12 @@ gtk_hex_init(GtkHex *gh)
 
        gh->auto_highlight = NULL;
 
-       // GTK4 - TEST - DON'T KNOW IF NECESSARY FOR KEYBOARD STUFF - FIXME
        gtk_widget_set_can_focus (widget, TRUE);
        gtk_widget_set_focusable (widget, TRUE);
 
        gtk_widget_set_vexpand (widget, TRUE);
        gtk_widget_set_hexpand (widget, TRUE);
 
-       // API CHANGE - FIXME REWRITE.
-//     gtk_widget_set_events(GTK_WIDGET(gh), GDK_KEY_PRESS_MASK);
 
        /* Init CSS */
 
diff --git a/src/meson.build b/src/meson.build
index 1d8c7f28..77f5927f 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -49,7 +49,7 @@ libghex_dep = declare_dependency(
 ghex_sources = [
   'chartable.c',
   'chartable.h',
-  'config.c',
+  'configuration.c',
   'configuration.h',
   'converter.c',
   'converter.h',
diff --git a/src/preferences.c b/src/preferences.c
index 1f7409c7..88ee43b4 100644
--- a/src/preferences.c
+++ b/src/preferences.c
@@ -1,7 +1,10 @@
+/* vim: colorcolumn=80 ts=4 sw=4
+ */
 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* preferences.c - setting the preferences
+/* FIXME.c - a window with a character table
 
-   Copyright (C) 1998 - 2004 Free Software Foundation
+   Copyright © 1998 - 2004 Free Software Foundation
+   Copyright © 2021 Logan Rathbone
 
    GHex is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -18,596 +21,253 @@
    If not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
-   Author: Jaka Mocnik <jaka gnu org>
+   Original Author: Jaka Mocnik <jaka gnu org>
 */
 
 #ifdef HAVE_CONFIG_H
 #  include <config.h>
 #endif /* HAVE_CONFIG_H */
 
-#include <gtk/gtk.h>
-#include <glib/gi18n.h>
-
 #include "preferences.h"
-#include "configuration.h"
-#include "ghex-window.h"
-#include "ui.h"
-
-#define MAX_MAX_UNDO_DEPTH 100000
-
-static void select_font_cb(GtkWidget *w, PropertyUI *pui);
-static void select_display_font_cb(GtkWidget *w, PropertyUI *pui);
-static void max_undo_changed_cb(GtkAdjustment *adj, PropertyUI *pui);
-static void box_size_changed_cb(GtkAdjustment *adj, PropertyUI *pui);
-static void offset_cb(GtkWidget *w, PropertyUI *pui);
-static void prefs_response_cb(GtkDialog *dlg, gint response, PropertyUI *pui);
-static void offsets_col_cb(GtkToggleButton *tb, PropertyUI *pui);
-static void group_type_cb(GtkRadioButton *rd, PropertyUI *pui);
-static void format_activated_cb(GtkEntry *entry, PropertyUI *pui);
-static gboolean format_focus_out_event_cb(GtkEntry *entry, GdkEventFocus *event,
-                                                                                 PropertyUI *pui);
-
-PropertyUI *prefs_ui = NULL;
-
-PropertyUI *
-create_prefs_dialog()
-{
-       GtkWidget *vbox, *label, *frame, *box, *fbox, *flabel, *grid;
-       GtkAdjustment *undo_adj, *box_adj;
-       GtkWidget *notebook;
-
-       GSList *group;
-       PropertyUI *pui;
-
-       int i;
 
-       gboolean gail_up;
-
-       pui = g_new0(PropertyUI, 1);
-       
-       pui->pbox = gtk_dialog_new();
-       gtk_window_set_title(GTK_WINDOW(pui->pbox), _("GHex Preferences"));
-       
-       gtk_dialog_add_button (GTK_DIALOG (pui->pbox),
-                                                  GTK_STOCK_CLOSE,
-                                                  GTK_RESPONSE_CLOSE);
-
-       gtk_dialog_add_button (GTK_DIALOG (pui->pbox),
-                                                  GTK_STOCK_HELP,
-                                                  GTK_RESPONSE_HELP);
+/* provides ``settings'' and def_* globals, as well as GHEX_PREF_* defines. */
+#include "configuration.h"
 
-       g_signal_connect(G_OBJECT(pui->pbox), "response",
-                                        G_CALLBACK(prefs_response_cb), pui);
+#define PREFS_RESOURCE "/org/gnome/ghex/preferences.ui"
 
-       g_signal_connect(G_OBJECT(pui->pbox), "delete-event",
-                                        G_CALLBACK (gtk_widget_hide_on_delete),
-                                        NULL);
+#define GET_WIDGET(X) \
+       X = GTK_WIDGET(gtk_builder_get_object (builder, #X)); \
+       g_assert (GTK_IS_WIDGET (X))
 
-       notebook = gtk_notebook_new();
-       gtk_widget_show(notebook);
-       gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(pui->pbox))), notebook);
+/* PRIVATE DATATYPES */
 
-       /* editing page */
-       vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
-       gtk_widget_show(vbox);
+typedef enum {
+       GUI_FONT,
+       DATA_FONT,
+       HEADER_FONT
+} FontType;
 
-       /* max undo levels */
-       undo_adj = GTK_ADJUSTMENT(gtk_adjustment_new(MIN(max_undo_depth, MAX_MAX_UNDO_DEPTH),
-                                                                                                0, 
MAX_MAX_UNDO_DEPTH, 1, 10, 0));
+/* STATIC GLOBALS */
 
-       box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
-       gtk_widget_show(box);
+static GtkBuilder *builder;
 
-       label = gtk_label_new_with_mnemonic(_("_Maximum number of undo levels:"));
-       gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
-       gtk_box_pack_start (GTK_BOX(box), label, TRUE, TRUE, 8);
-       gtk_widget_show(label);
-                                                 
-       pui->undo_spin = gtk_spin_button_new(undo_adj, 1, 0);
-       gtk_box_pack_end (GTK_BOX(box), GTK_WIDGET(pui->undo_spin), FALSE, TRUE, 8);
-       gtk_widget_show(pui->undo_spin);
+/* use GET_WIDGET(X) macro to set these from builder, where
+ * X == var name == builder id name. Don't include quotation marks.
+ */
+/* main widget */
+static GtkWidget *prefs_dialog;
 
-       gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, TRUE, 8);
+/* for css stuff */
+static GtkWidget *content_area_box;
+static GtkWidget *font_frame, *group_type_frame, *print_font_frame;
 
-       /* cursor offset format */
-       box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
-       gtk_widget_show(box);
+/* widgets that interact with settings */
+static GtkWidget *font_button;
+static GtkWidget *data_font_button;
+static GtkWidget *header_font_button;
+static GtkWidget *show_offsets_chkbtn;
+static GtkWidget *bytes_chkbtn;
+static GtkWidget *words_chkbtn;
+static GtkWidget *long_chkbtn;
+static GtkWidget *shaded_box_chkbtn;
+static GtkWidget *shaded_box_spinbtn;
+static GtkWidget *shaded_box_box;
 
-       gtk_label_set_mnemonic_widget(GTK_LABEL(label), pui->undo_spin);
+/* PRIVATE DECLARATIONS */
 
-       gail_up = GTK_IS_ACCESSIBLE(gtk_widget_get_accessible(label)) ;
 
-       if (gail_up) {
-               add_atk_namedesc (pui->undo_spin, _("Undo levels"), _("Select maximum number of undo 
levels"));
-               add_atk_relation (pui->undo_spin, label, ATK_RELATION_LABELLED_BY);
-       }
 
-       label = gtk_label_new_with_mnemonic(_("_Show cursor offset in statusbar as:"));
-       gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
-       gtk_box_pack_start (GTK_BOX(box), label, TRUE, TRUE, 8);
-       gtk_widget_show(label);
-
-       pui->format = gtk_entry_new();
-       g_signal_connect(G_OBJECT(pui->format), "activate",
-                                        G_CALLBACK(format_activated_cb), pui);
-       g_signal_connect(G_OBJECT(pui->format), "focus_out_event",
-                                        G_CALLBACK(format_focus_out_event_cb), pui);
-       gtk_box_pack_start (GTK_BOX(box), pui->format, TRUE, TRUE, 8);
-       gtk_widget_show(pui->format);
-
-       pui->offset_menu = gtk_combo_box_text_new();
-       gtk_label_set_mnemonic_widget (GTK_LABEL(label), pui->offset_menu);
-       gtk_widget_show(pui->offset_menu);
-       gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(pui->offset_menu),
-                                                                  _("Decimal"));
-       gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(pui->offset_menu),
-                                                                  _("Hexadecimal"));
-       gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(pui->offset_menu),
-                                                                  _("Custom"));
-       g_signal_connect(G_OBJECT(pui->offset_menu), "changed",
-                                        G_CALLBACK(offset_cb), pui);
-       gtk_box_pack_end(GTK_BOX(box), GTK_WIDGET(pui->offset_menu),
-                                        FALSE, TRUE, 8);
-
-       gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, TRUE, 4);
-
-       if (gail_up) {
-               add_atk_namedesc (pui->format, "format_entry", _("Enter the cursor offset format"));
-               add_atk_namedesc (pui->offset_menu, "format_combobox", _("Select the cursor offset format"));
-               add_atk_relation (label, pui->format, ATK_RELATION_LABEL_FOR);
-               add_atk_relation (pui->format, label, ATK_RELATION_LABELLED_BY);
-               add_atk_relation (label, pui->offset_menu, ATK_RELATION_LABEL_FOR);
-               add_atk_relation (pui->offset_menu, label, ATK_RELATION_LABELLED_BY);
-               add_atk_relation (pui->format, pui->offset_menu, ATK_RELATION_CONTROLLED_BY);
-               add_atk_relation (pui->offset_menu, pui->format, ATK_RELATION_CONTROLLER_FOR);
-       }
+/* PRIVATE FUNCTIONS */
 
-       /* show offsets check button */
-       pui->offsets_col = gtk_check_button_new_with_mnemonic(_("Sh_ow offsets column"));
-       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pui->offsets_col), show_offsets_column);
-       gtk_box_pack_start(GTK_BOX(vbox), pui->offsets_col, FALSE, TRUE, 4);
-       gtk_widget_show(pui->offsets_col);
+#define APPLY_PROVIDER_TO(PROVIDER, WIDGET)                                                                  
  \
+       context = gtk_widget_get_style_context (WIDGET);                                                \
+       gtk_style_context_add_provider (context, GTK_STYLE_PROVIDER(PROVIDER),  \
+                       GTK_STYLE_PROVIDER_PRIORITY_APPLICATION)
+static void
+do_css_stuff(void)
+{
+       GtkStyleContext *context;
+       GtkCssProvider *box_provider, *frame_provider;
 
-       label = gtk_label_new(_("Editing"));
-       gtk_widget_show(label);
-       gtk_notebook_append_page (GTK_NOTEBOOK(notebook), vbox, label);
+       /* Grab layout-oriented widgets and set CSS styling. */
+       GET_WIDGET (content_area_box);
+       GET_WIDGET (font_frame);
+       GET_WIDGET (group_type_frame);
+       GET_WIDGET (print_font_frame);
 
-       /* display page */
-       vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
-       gtk_widget_show(vbox);
-       
-       /* display font */
-       frame = gtk_frame_new(_("Font"));
-       gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
-       gtk_widget_show(frame);
-       
-       fbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
-       pui->font_button = gtk_font_button_new();
-       gtk_font_button_set_font_name(GTK_FONT_BUTTON(pui->font_button),
-                                                                 def_font_name);
-       g_signal_connect (pui->font_button, "font-set",
-                         G_CALLBACK (select_display_font_cb), pui);
-       flabel = gtk_label_new("");
-       gtk_label_set_mnemonic_widget (GTK_LABEL (flabel), pui->font_button);
-       gtk_widget_show(flabel);
-       gtk_widget_show(GTK_WIDGET(pui->font_button));
-       gtk_container_set_border_width(GTK_CONTAINER(fbox), 4);
-       gtk_box_pack_start (GTK_BOX (fbox), GTK_WIDGET(pui->font_button), FALSE, TRUE, 12);
-       
-       gtk_widget_show(fbox);
-       gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(fbox));
-       
-       gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 4);
-       
-       /* default group type */
-       frame = gtk_frame_new(_("Default Group Type"));
-       gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
-       gtk_widget_show(frame);
-
-       box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
-       gtk_widget_show(box);
-       group = NULL;
-       for(i = 0; i < 3; i++) {
-               pui->group_type[i] = GTK_RADIO_BUTTON(gtk_radio_button_new_with_mnemonic(group, 
_(group_type_label[i])));
-               gtk_widget_show(GTK_WIDGET(pui->group_type[i]));
-               gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(pui->group_type[i]), TRUE, TRUE, 2);
-               group = gtk_radio_button_get_group(pui->group_type[i]);
-       }
-       gtk_container_add(GTK_CONTAINER(frame), box);
-       gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 4);
        
-       label = gtk_label_new(_("Display"));
-       gtk_widget_show(label);
-       gtk_notebook_append_page (GTK_NOTEBOOK(notebook), vbox, label);
-       
-       /* printing page */
-       vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
-       gtk_widget_show(vbox);
-
-       /* paper selection */
-       frame = gtk_frame_new(_("Paper size"));
-       gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
-       gtk_widget_show(frame);
-
-       /* data & header font selection */
-       frame = gtk_frame_new(_("Fonts"));
-       gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
-       gtk_widget_show(frame);
-
-       grid = gtk_grid_new ();
-       g_object_set (grid,
-                     "orientation", GTK_ORIENTATION_VERTICAL,
-                     "row-spacing", 6,
-                     "column-spacing", 12,
-                     NULL);
-       gtk_widget_show (grid);
-
-       label = gtk_label_new_with_mnemonic(_("_Data font:"));
-       gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
-       gtk_widget_show(label);
-       gtk_container_add (GTK_CONTAINER (grid), label);
-
-       pui->df_button = gtk_font_button_new_with_font(def_font_name);
-       g_signal_connect (G_OBJECT (pui->df_button), "font_set",
-                                         G_CALLBACK (select_font_cb), pui);
-       pui->df_label = gtk_label_new("");
-       gtk_label_set_mnemonic_widget (GTK_LABEL (pui->df_label), pui->df_button);
-
-       gtk_label_set_mnemonic_widget (GTK_LABEL (label), pui->df_button);
-
-       if (gail_up) {
-               add_atk_namedesc (pui->df_button, _("Data font"), _("Select the data font"));
-               add_atk_relation (pui->df_button, label, ATK_RELATION_LABELLED_BY);
-       }       
-       
-       gtk_widget_set_hexpand (pui->df_button, TRUE);
-       gtk_widget_show(pui->df_button);
-       gtk_grid_attach_next_to (GTK_GRID (grid), pui->df_button, label,
-                                GTK_POS_RIGHT, 1, 1);
-
-       label = gtk_label_new_with_mnemonic(_("Header fo_nt:"));
-       gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
-       gtk_widget_show(label);
-       gtk_container_add (GTK_CONTAINER (grid), label);
-       pui->hf_button = gtk_font_button_new_with_font(def_font_name);
-       g_signal_connect (G_OBJECT (pui->hf_button), "font_set",
-                                         G_CALLBACK (select_font_cb), pui);
-       pui->hf_label = gtk_label_new("");
-       gtk_label_set_mnemonic_widget (GTK_LABEL (pui->hf_label), pui->hf_button);
-
-       gtk_label_set_mnemonic_widget (GTK_LABEL (label), pui->hf_button);
-
-       if (gail_up) {
-               add_atk_namedesc (pui->hf_button, _("Header font"), _("Select the header font"));
-               add_atk_relation (pui->hf_button, label, ATK_RELATION_LABELLED_BY);
-       }
-
-       gtk_widget_set_hexpand (pui->hf_button, TRUE);
-       gtk_widget_show(pui->hf_button);
-       gtk_grid_attach_next_to (GTK_GRID (grid), pui->hf_button, label,
-                                GTK_POS_RIGHT, 1, 1);
-
-       label = gtk_label_new("");
-       gtk_widget_set_hexpand (label, TRUE);
-       gtk_widget_show(label);
-       gtk_grid_attach (GTK_GRID (grid), label, 2, 1, 1, 1);
-
-       gtk_container_add (GTK_CONTAINER (frame), grid);
-
-       gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE,
-                                          4);
-
-       /* shaded box entry */
-       box_adj = GTK_ADJUSTMENT(gtk_adjustment_new(0, 0, 1000, 1, 10, 0));
-
-       box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
-       gtk_widget_show(box);
-
-       label = gtk_label_new_with_mnemonic(_("_Print shaded box over:"));
-       gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
-       gtk_box_pack_start (GTK_BOX(box), label, TRUE, TRUE, 4);
-       gtk_widget_show(label);
-                                                 
-       pui->box_size_spin = gtk_spin_button_new(box_adj, 1, 0);
-       gtk_box_pack_start (GTK_BOX(box), GTK_WIDGET(pui->box_size_spin), FALSE, TRUE, 8);
-       gtk_widget_show(pui->box_size_spin);
-
-       gtk_label_set_mnemonic_widget (GTK_LABEL (label), pui->box_size_spin);
-
-       if (gail_up) {
-               add_atk_namedesc (pui->box_size_spin, _("Box size"), _("Select size of box (in number of 
lines)"));
-               add_atk_relation (pui->box_size_spin, label, ATK_RELATION_LABELLED_BY);
-       }
-
-       label = gtk_label_new(_("lines (0 for no box)"));
-       gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
-       gtk_box_pack_start (GTK_BOX(box), label, FALSE, TRUE, 4);
-       gtk_widget_show(label);
-
-       gtk_box_pack_start(GTK_BOX(vbox), box, TRUE, TRUE, 4);
-
-       label = gtk_label_new(_("Printing"));
-       gtk_widget_show(label);
-       gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, label);
-
-       for(i = 0; i < 3; i++)
-               g_signal_connect(G_OBJECT(pui->group_type[i]), "clicked",
-                                                G_CALLBACK(group_type_cb), pui);
-       g_signal_connect(G_OBJECT(pui->offsets_col), "toggled",
-                                        G_CALLBACK(offsets_col_cb), pui);
-       g_signal_connect(G_OBJECT(undo_adj), "value-changed",
-                                        G_CALLBACK(max_undo_changed_cb), pui);
-       g_signal_connect(G_OBJECT(box_adj), "value-changed",
-                                        G_CALLBACK(box_size_changed_cb), pui);
-
-       return pui;
+       /* overall padding for content area: */
+       box_provider = gtk_css_provider_new ();
+       gtk_css_provider_load_from_data (box_provider,
+                                                                               "* {\n"
+                                                                               "  padding-left: 24px;\n"
+                                                                               "  padding-right: 24px;\n"
+                                                                               "}\n", -1);
+
+       APPLY_PROVIDER_TO(box_provider, content_area_box);
+
+       /* padding for our frames (they look god-awful without a bit) */
+       frame_provider = gtk_css_provider_new ();
+       gtk_css_provider_load_from_data (frame_provider,
+                                                                               "* {\n"
+                                                                               "  padding: 12px;\n"
+                                                                               "}\n",  -1);
+
+       APPLY_PROVIDER_TO(frame_provider, font_frame);
+       APPLY_PROVIDER_TO(frame_provider, group_type_frame);
+       APPLY_PROVIDER_TO(frame_provider, print_font_frame);
 }
+#undef APPLY_PROVIDER_TO
 
+/* note the lack of const and the ugly cast below. This is to silence a
+ * warning about incompatible types.
+ */
+static gboolean
+monospace_font_filter (/* const */ PangoFontFamily *family,
+               const PangoFontFace *face,
+               gpointer data)
+{
+       (void)face, (void)data;
 
-void set_current_prefs(PropertyUI *pui) {
-       int i;
-
-       for(i = 0; i < 3; i++)
-               if(def_group_type == group_type[i]) {
-                       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pui->group_type[i]), TRUE);
-                       break;
-               }
-       
-       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pui->offsets_col), show_offsets_column);
-       gtk_spin_button_set_value(GTK_SPIN_BUTTON(pui->undo_spin), (gfloat)max_undo_depth);
-       gtk_spin_button_set_value(GTK_SPIN_BUTTON(pui->box_size_spin), (gfloat)shaded_box_size);
-
-       gtk_widget_set_sensitive(pui->format, FALSE);
-       gtk_entry_set_text(GTK_ENTRY(pui->format), offset_fmt);
-       if(strcmp(offset_fmt, "%d") == 0)
-               gtk_combo_box_set_active(GTK_COMBO_BOX(pui->offset_menu), 0);
-       else if(strcmp(offset_fmt, "0x%X") == 0)
-               gtk_combo_box_set_active(GTK_COMBO_BOX(pui->offset_menu), 1);
-       else {
-               gtk_combo_box_set_active(GTK_COMBO_BOX(pui->offset_menu), 2);
-               gtk_widget_set_sensitive(pui->format, TRUE);
-       }
-
-       if(header_font_name)
-               gtk_font_button_set_font_name(GTK_FONT_BUTTON(pui->hf_button),
-                        header_font_name);
-       if(data_font_name)
-               gtk_font_button_set_font_name(GTK_FONT_BUTTON(pui->df_button),
-                        data_font_name);
-       if(def_font_name)
-               gtk_font_button_set_font_name(GTK_FONT_BUTTON(pui->font_button),
-                                                                         def_font_name);
-
-       gtk_dialog_set_default_response(GTK_DIALOG(pui->pbox), GTK_RESPONSE_CLOSE);
+       if (pango_font_family_is_monospace (family))
+               return TRUE;
+       else
+               return FALSE;
 }
 
 static void
-max_undo_changed_cb(GtkAdjustment *adj, PropertyUI *pui)
+font_set_cb (GtkFontButton *widget,
+               gpointer user_data)
 {
-       if((guint)gtk_adjustment_get_value(adj) != max_undo_depth) {
-               max_undo_depth = gtk_spin_button_get_value_as_int
-                       (GTK_SPIN_BUTTON(pui->undo_spin));
-               g_settings_set (settings,
-                               GHEX_PREF_MAX_UNDO_DEPTH,
-                               "u",
-                               max_undo_depth);
+       FontType type = GPOINTER_TO_INT(user_data);
+       char *tmp;
+       char **global;
+       char *pref;
+       GtkFontChooser *chooser = GTK_FONT_CHOOSER(widget);
+
+       if (type == GUI_FONT) {
+               global = &def_font_name;
+               pref = GHEX_PREF_FONT;
+       } else if (type == DATA_FONT) {
+               global = &data_font_name;
+               pref = GHEX_PREF_DATA_FONT;
+       } else if (type == HEADER_FONT) {
+               global = &header_font_name;
+               pref = GHEX_PREF_HEADER_FONT;
+       } else {
+               g_error ("%s: Programmer error - invalid enum passed to function.",
+                               __func__);
        }
-}
 
-static void
-box_size_changed_cb(GtkAdjustment *adj, PropertyUI *pui)
-{
-       if((guint)gtk_adjustment_get_value(adj) != shaded_box_size) {
-               shaded_box_size = gtk_spin_button_get_value_as_int
-                       (GTK_SPIN_BUTTON(pui->box_size_spin));
-               g_settings_set (settings,
-                               GHEX_PREF_BOX_SIZE,
-                               "u",
-                               shaded_box_size);
+       tmp = gtk_font_chooser_get_font (chooser);
+
+       if (tmp) {
+               if (*global)
+                       g_free (*global);
+               *global = tmp;
+               g_settings_set_string (settings,
+                               pref,
+                               *global);
+       } else {
+               g_warning ("%s: No chosen font detected. Doing nothing.", __func__);
        }
-}
 
-static void
-offsets_col_cb(GtkToggleButton *tb, PropertyUI *pui)
-{
-       show_offsets_column = gtk_toggle_button_get_active
-               (GTK_TOGGLE_BUTTON(pui->offsets_col));
-       g_settings_set_boolean (settings,
-                               GHEX_PREF_OFFSETS_COLUMN,
-                               show_offsets_column);
+       printf("TEST - def_font_name: %s - data_font_name: %s - header_font_name: %s\n", def_font_name, 
data_font_name, header_font_name);
 }
 
 static void
-group_type_cb(GtkRadioButton *rd, PropertyUI *pui)
+setup_signals (void)
 {
-       int i;
-
-       for(i = 0; i < 3; i++)
-               if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pui->group_type[i]))) {
-                       def_group_type = group_type[i];
-                       break;
-               }
-       g_settings_set_enum (settings,
-                            GHEX_PREF_GROUP,
-                            def_group_type);
-}
+       /* font_button */
 
-static void
-prefs_response_cb(GtkDialog *dlg, gint response, PropertyUI *pui)
-{
-       GError *error = NULL;
-
-       switch(response) {
-       case GTK_RESPONSE_HELP:
-               gtk_show_uri (NULL, "help:ghex/ghex-prefs",  gtk_get_current_event_time (), &error);
-               if(NULL != error) {
-                       GtkWidget *dialog;
-                       dialog = gtk_message_dialog_new
-                               (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
-                                _("There was an error displaying help: \n%s"),
-                                error->message);
-                       g_signal_connect(G_OBJECT (dialog), "response",
-                                                        G_CALLBACK (gtk_widget_destroy),
-                                                        NULL);
-                       gtk_window_set_resizable(GTK_WINDOW (dialog), FALSE);
-                       gtk_window_present (GTK_WINDOW (dialog));
-
-                       g_error_free(error);
-               }
-               break;
-       case GTK_RESPONSE_CLOSE:
-               gtk_widget_hide(pui->pbox);
-               break;
-       default:
-               gtk_widget_hide(pui->pbox);
-               break;
-       }
-}
+       /* Make font chooser only allow monospace fonts. */
+       gtk_font_chooser_set_filter_func (GTK_FONT_CHOOSER(font_button),
+                       (GtkFontFilterFunc)monospace_font_filter,
+                       NULL, NULL);    /* no user data, no destroy func for same. */
 
-static void
-select_display_font_cb(GtkWidget *w, PropertyUI *pui)
-{
-       PangoFontMetrics *new_metrics;
-       PangoFontDescription *new_desc;
-
-       if(strcmp(gtk_font_button_get_font_name
-                         (GTK_FONT_BUTTON(pui->font_button)),
-                         def_font_name) != 0) {
-               if((new_metrics = gtk_hex_load_font
-                       (gtk_font_button_get_font_name
-                        (GTK_FONT_BUTTON(pui->font_button)))) != NULL) {
-                       new_desc = pango_font_description_from_string
-                               (gtk_font_button_get_font_name
-                                (GTK_FONT_BUTTON (pui->font_button)));
-                       if (def_metrics)
-                               pango_font_metrics_unref (def_metrics);
-                       if (def_font_desc)
-                               pango_font_description_free (def_font_desc);
-                       def_metrics = new_metrics;
-                       if(def_font_name)
-                               g_free(def_font_name);
-                       def_font_name = g_strdup
-                               (gtk_font_button_get_font_name
-                                (GTK_FONT_BUTTON(pui->font_button)));
-                       def_font_desc = new_desc;
-                       g_settings_set_string (settings,
-                                              GHEX_PREF_FONT,
-                                              def_font_name);
-               }
-               else
-                       display_error_dialog (ghex_window_get_active(),
-                                                                 _("Can not open desired font!"));
-       }
-}
+       g_signal_connect (font_button, "font-set",
+                       G_CALLBACK(font_set_cb), GINT_TO_POINTER(GUI_FONT));
+
+       g_signal_connect (data_font_button, "font-set",
+                       G_CALLBACK(font_set_cb), GINT_TO_POINTER(DATA_FONT));
+
+       g_signal_connect (header_font_button, "font-set",
+                       G_CALLBACK(font_set_cb), GINT_TO_POINTER(HEADER_FONT));
 
-static void
-select_font_cb(GtkWidget *w, PropertyUI *pui)
-{
-       if(w == pui->df_button) {
-               if(data_font_name)
-                       g_free(data_font_name);
-               data_font_name = g_strdup(gtk_font_button_get_font_name
-                                                                 (GTK_FONT_BUTTON (pui->df_button)));
-               g_settings_set_string (settings,
-                                      GHEX_PREF_DATA_FONT,
-                                      data_font_name);
-       }
-       else if(w == pui->hf_button) {
-               if(header_font_name)
-                       g_free(header_font_name);
-               header_font_name = g_strdup(gtk_font_button_get_font_name
-                                                                       (GTK_FONT_BUTTON (pui->hf_button)));
-               g_settings_set_string (settings,
-                                      GHEX_PREF_HEADER_FONT,
-                                      header_font_name);
-       }
 }
 
+/* put all of your GET_WIDGET calls other than the main prefs_dialog widget
+ * and CSS-only stuff in here, please.
+ */
 static void
-update_offset_fmt_from_entry(GtkEntry *entry, PropertyUI *pui)
+grab_widget_values_from_settings (void)
 {
-       int i, len;
-       gchar *old_offset_fmt;
-       gboolean expect_spec;
-       const GList *win_list;
-
-       old_offset_fmt = offset_fmt;
-       offset_fmt = g_strdup(gtk_entry_get_text(GTK_ENTRY(pui->format)));
-       /* check for a valid format string */
-       len = strlen(offset_fmt);
-       expect_spec = FALSE;
-       for(i = 0; i < len; i++) {
-               if(offset_fmt[i] == '%')
-                       expect_spec = TRUE;
-               if( expect_spec &&
-                       ( (offset_fmt[i] >= 'a' && offset_fmt[i] <= 'z') ||
-                         (offset_fmt[i] >= 'A' && offset_fmt[i] <= 'Z') ) ) {
-                       expect_spec = FALSE;
-                       if(offset_fmt[i] != 'x' && offset_fmt[i] != 'd' &&
-                          offset_fmt[i] != 'o' && offset_fmt[i] != 'X' &&
-                          offset_fmt[i] != 'P' && offset_fmt[i] != 'p') {
-                               GtkWidget *msg_dialog;
-
-                               g_free(offset_fmt);
-                               offset_fmt = old_offset_fmt;
-                               gtk_entry_set_text(GTK_ENTRY(pui->format), old_offset_fmt);
-                               msg_dialog =
-                                       gtk_message_dialog_new(GTK_WINDOW(pui->pbox),
-                                                                                  GTK_DIALOG_MODAL|
-                                                                                  
GTK_DIALOG_DESTROY_WITH_PARENT,
-                                                                                  GTK_MESSAGE_ERROR,
-                                                                                  GTK_BUTTONS_OK,
-                                                                                  _("The offset format 
string contains invalid format specifier.\n"
-                                                                                        "Only 'x', 'X', 'p', 
'P', 'd' and 'o' are allowed."));
-                               gtk_dialog_run(GTK_DIALOG(msg_dialog));
-                               gtk_widget_destroy(msg_dialog);
-                               gtk_widget_grab_focus(pui->format);
-                               break;
-                       }
-               }
-       }
-       if(offset_fmt != old_offset_fmt)
-               g_free(old_offset_fmt);
-       g_settings_set_string (settings,
-                              GHEX_PREF_OFFSET_FORMAT,
-                              offset_fmt);
-       win_list = ghex_window_get_list();
-       while(NULL != win_list) {
-               ghex_window_update_status_message((GHexWindow *)win_list->data);
-               win_list = win_list->next;
+       /* font_button */
+       gtk_font_chooser_set_font (GTK_FONT_CHOOSER(font_button),
+                       def_font_name);
+
+       /* data_font_button */
+       gtk_font_chooser_set_font (GTK_FONT_CHOOSER(data_font_button),
+                       data_font_name);
+
+       /* header_font_button */
+       gtk_font_chooser_set_font (GTK_FONT_CHOOSER(header_font_button),
+                       header_font_name);
+
+       /* show_offsets_chkbtn */
+       gtk_check_button_set_active (GTK_CHECK_BUTTON(show_offsets_chkbtn),
+                       show_offsets_column);
+
+       /* group_type radio buttons
+        */
+       if (def_group_type == GROUP_BYTE) {
+               gtk_check_button_set_active (GTK_CHECK_BUTTON(bytes_chkbtn), TRUE);
+       } else if (def_group_type == GROUP_WORD) {
+               gtk_check_button_set_active (GTK_CHECK_BUTTON(words_chkbtn), TRUE);
+       } else if (def_group_type == GROUP_LONG) {
+               gtk_check_button_set_active (GTK_CHECK_BUTTON(long_chkbtn), TRUE);
+       } else {
+               g_warning ("group_type option invalid; falling back to BYTES.");
+               gtk_check_button_set_active (GTK_CHECK_BUTTON(bytes_chkbtn), TRUE);
        }
-}
 
-static gboolean
-format_focus_out_event_cb(GtkEntry *entry, GdkEventFocus *event, PropertyUI *pui)
-{
-       update_offset_fmt_from_entry(entry, pui);
-       return FALSE;
+       /* shaded_box_* */
+       gtk_check_button_set_active (GTK_CHECK_BUTTON(shaded_box_chkbtn),
+                       shaded_box_size > 0 ? TRUE : FALSE);
+       gtk_widget_set_sensitive (shaded_box_box,
+                       shaded_box_size > 0 ? TRUE : FALSE);
+       gtk_spin_button_set_value (GTK_SPIN_BUTTON(shaded_box_spinbtn),
+                       shaded_box_size);
 }
 
 static void
-format_activated_cb(GtkEntry *entry, PropertyUI *pui)
+init_widgets (void)
 {
-       update_offset_fmt_from_entry(entry, pui);
+       GET_WIDGET (font_button);
+       GET_WIDGET (data_font_button);
+       GET_WIDGET (header_font_button);
+       GET_WIDGET (show_offsets_chkbtn);
+       GET_WIDGET (bytes_chkbtn);
+       GET_WIDGET (words_chkbtn);
+       GET_WIDGET (long_chkbtn);
+       GET_WIDGET (shaded_box_chkbtn);
+       GET_WIDGET (shaded_box_spinbtn);
+       GET_WIDGET (shaded_box_box);
 }
 
-static void
-offset_cb(GtkWidget *w, PropertyUI *pui)
+/* PUBLIC FUNCTIONS */
+
+GtkWidget *
+create_preferences_dialog (void)
 {
-       int i = gtk_combo_box_get_active(GTK_COMBO_BOX(w)); 
-
-       switch(i) {
-       case 0:
-               gtk_entry_set_text(GTK_ENTRY(pui->format), "%d");
-               gtk_widget_set_sensitive(pui->format, FALSE);
-               break;
-       case 1:
-               gtk_entry_set_text(GTK_ENTRY(pui->format), "0x%X");
-               gtk_widget_set_sensitive(pui->format, FALSE);
-               break;
-       case 2:
-               gtk_widget_set_sensitive(pui->format, TRUE);
-               break;
-       }
-       update_offset_fmt_from_entry(GTK_ENTRY(pui->format), pui);
+       builder = gtk_builder_new_from_resource (PREFS_RESOURCE);
+
+       do_css_stuff ();
+       init_widgets ();
+       grab_widget_values_from_settings ();
+       setup_signals ();
+
+       GET_WIDGET (prefs_dialog);
+
+       return prefs_dialog;
 }
diff --git a/src/preferences.h b/src/preferences.h
index ef1d04a7..913dcac6 100644
--- a/src/preferences.h
+++ b/src/preferences.h
@@ -1,7 +1,8 @@
 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* print.h - printing related stuff for ghex
+/* preferences.h - Declarations pertaining to preferences
 
    Copyright (C) 2004 Free Software Foundation
+   Copyright © 2021 Logan Rathbone
 
    GHex is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -18,35 +19,22 @@
    If not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
-   Author: Jaka Mocnik <jaka gnu org>
+   Original Author: Jaka Mocnik <jaka gnu org>
 */
 
-#ifndef __GHEX_PREFERENCES_H__
-#define __GHEX_PREFERENCES_H__
+#ifndef GHEX_PREFERENCES_H
+#define GHEX_PREFERENCES_H
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <string.h>
+#include <gtkhex.h>    /* for GROUP_* enums */
 
 G_BEGIN_DECLS
 
-typedef struct _PropertyUI PropertyUI;
-struct _PropertyUI {
-       GtkWidget *pbox;
-       GtkCheckButton *group_type[3];
-       // GONE - GTK4
-//     GtkRadioButton *group_type[3];
-       GtkWidget *font_button, *undo_spin, *box_size_spin;
-       GtkWidget *offset_menu, *offset_choice[3];
-       GtkWidget *format, *offsets_col;
-       GtkWidget *paper_sel, *print_font_sel;
-       GtkWidget *df_button, *hf_button;
-       GtkWidget *df_label, *hf_label;
-};
-
-extern PropertyUI *prefs_ui;
-extern guint group_type[3];
-extern gchar *group_type_label[3];
-
-PropertyUI *create_prefs_dialog(void);
-void       set_current_prefs(PropertyUI *pui);
+GtkWidget *    create_preferences_dialog(void);
+//void         set_current_prefs(PropertyUI *pui);
 
 G_END_DECLS
 
-#endif /* !__GHEX_PREFERENCES_H__ */
+#endif /* GHEX_PREFERENCES_H */
diff --git a/src/preferences.ui b/src/preferences.ui
new file mode 100644
index 00000000..8d25cdff
--- /dev/null
+++ b/src/preferences.ui
@@ -0,0 +1,218 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- vim: ts=2 sw=2 foldmethod=indent
+-->
+
+<interface>
+
+       <object class="GtkDialog" id="prefs_dialog"> <!-- prefs_dialog -->
+               <property name="title" translatable="yes">Preferences</property>
+               <property name="default-width">400</property>
+               <property name="default-height">400</property>
+
+               <child internal-child="content_area"> <!-- box -->
+                       <object class="GtkBox" id="content_area_box">
+                               <property name="orientation">vertical</property>
+
+                               <child> <!-- stackswitcher -->
+                                       <object class="GtkStackSwitcher">
+                                               <property name="stack">stack</property>
+                                               <property name="halign">center</property>
+                                       </object>
+                               </child> <!-- /stackswitcher -->
+
+                               <child> <!-- stack -->
+                                       <object class="GtkStack" id="stack">
+                                               <property name="transition-type">crossfade</property>
+                                               <property name="vexpand">true</property>
+
+                                               <child> <!-- stackPage1 -->
+                                                       <object class="GtkStackPage">
+                                                               <property name="name">page1</property>
+                                                               <property name="title" 
translatable="yes">Display</property>
+                                                               <property name="child"> <!-- page1 child -->
+                                                                       <object class="GtkBox"> <!-- box -->
+                                                                               <property 
name="orientation">vertical</property>
+                                                                               <property 
name="spacing">18</property>
+
+                                                                               <child> <!-- font_frame -->
+                                                                                       <object 
class="GtkFrame" id="font_frame">
+                                                                                               <child 
type="label">
+                                                                                                       
<object class="GtkLabel" id="font_frame_label">
+                                                                                                             
  <property name="label" translatable="yes">Font</property>
+                                                                                                       
</object>
+                                                                                               </child>
+                                                                                               <child>
+                                                                                                       
<object class="GtkFontButton" id="font_button">
+                                                                                                             
  <property name="halign">start</property>
+                                                                                                       
</object>
+                                                                                               </child>
+                                                                                       </object>
+                                                                               </child> <!-- /font_frame -->
+
+                                                                               <child> <!-- group_type_frame 
-->
+                                                                                       <object 
class="GtkFrame" id="group_type_frame">
+                                                                                               <property 
name="label" translatable="yes">Hex Group Type</property>
+                                                                                               <child>
+                                                                                                       
<object class="GtkBox">
+                                                                                                             
  <property name="orientation">vertical</property>
+                                                                                                             
  <child>
+                                                                                                             
          <object class="GtkCheckButton" id="bytes_chkbtn">
+                                                                                                             
                  <property name="label" translatable="yes">Bytes</property>
+                                                                                                             
                          <!-- note: don't put group="bytes_checkbtn" here. -->
+                                                                                                             
          </object>
+                                                                                                             
  </child>
+                                                                                                             
  <child>
+                                                                                                             
          <object class="GtkCheckButton" id="words_chkbtn">
+                                                                                                             
                  <property name="label" translatable="yes">Words</property>
+                                                                                                             
                  <property name="group">bytes_chkbtn</property>
+                                                                                                             
          </object>
+                                                                                                             
  </child>
+                                                                                                             
  <child>
+                                                                                                             
          <object class="GtkCheckButton" id="long_chkbtn">
+                                                                                                             
                  <property name="label" translatable="yes">Longwords</property>
+                                                                                                             
                  <property name="group">bytes_chkbtn</property>
+                                                                                                             
          </object>
+                                                                                                             
  </child>
+                                                                                                       
</object>
+                                                                                               </child>
+
+                                                                                       </object>
+                                                                               </child> <!-- 
/group_type_frame -->
+
+                                                                               <child> <!-- 
show_offsets_chkbtn -->
+                                                                                       <object 
class="GtkCheckButton" id="show_offsets_chkbtn">
+                                                                                               <property 
name="label" translatable="yes">Show offsets column</property>
+                                                                                       </object>
+                                                                               </child> <!-- 
/show_offsets_chkbtn -->
+                                                                       </object> <!-- /box -->
+                                                               </property>     <!-- /page1 child -->
+                                                       </object>
+                                               </child> <!-- /stackPage1 -->
+
+                                               <child> <!-- stackPage2 -->
+                                                       <object class="GtkStackPage">
+                                                               <property name="name">page2</property>
+                                                               <property name="title" 
translatable="yes">Printing</property>
+                                                               <property name="child"> <!-- page2 child -->
+                                                                       <object class="GtkBox"> <!-- vbox -->
+                                                                               <property 
name="orientation">vertical</property>
+                                                                               <property 
name="spacing">18</property>
+
+                                                                               <child> <!-- print_font_frame 
-->
+                                                                                       <object 
class="GtkFrame" id="print_font_frame">
+                                                                                               <child 
type="label">
+                                                                                                       
<object class="GtkLabel" id="print_font_frame_label">
+                                                                                                             
  <property name="label" translatable="yes">Fonts</property>
+                                                                                                       
</object>
+                                                                                               </child>
+
+                                                                                               <child> <!-- 
print font grid -->
+                                                                                                       
<object class="GtkGrid">
+                                                                                                             
  <property name="margin-top">12</property>
+                                                                                                             
  <property name="margin-bottom">12</property>
+                                                                                                             
  <property name="row-spacing">12</property>
+                                                                                                             
  <property name="column-spacing">18</property>
+
+                                                                                                             
  <child>
+                                                                                                             
          <object class="GtkLabel">
+                                                                                                             
                  <property name="label" translatable="yes">Data font:</property>
+                                                                                                             
                  <property name="halign">start</property>
+                                                                                                             
                  <layout>
+                                                                                                             
                          <property name="row">0</property>
+                                                                                                             
                          <property name="column">0</property>
+                                                                                                             
                  </layout>
+                                                                                                             
          </object>
+                                                                                                             
  </child>
+                                                                                                             
  <child>
+                                                                                                             
          <object class="GtkLabel">
+                                                                                                             
                  <property name="label" translatable="yes">Header font:</property>
+                                                                                                             
                  <property name="halign">start</property>
+                                                                                                             
                  <layout>
+                                                                                                             
                          <property name="row">1</property>
+                                                                                                             
                          <property name="column">0</property>
+                                                                                                             
                  </layout>
+                                                                                                             
          </object>
+                                                                                                             
  </child>
+                                                                                                             
  <child>
+                                                                                                             
          <object class="GtkFontButton" id="data_font_button">
+                                                                                                             
                  <property name="halign">start</property>
+                                                                                                             
                  <layout>
+                                                                                                             
                          <property name="row">0</property>
+                                                                                                             
                          <property name="column">1</property>
+                                                                                                             
                  </layout>
+                                                                                                             
          </object>
+                                                                                                             
  </child>
+                                                                                                             
  <child>
+                                                                                                             
          <object class="GtkFontButton" id="header_font_button">
+                                                                                                             
                  <property name="halign">start</property>
+                                                                                                             
                  <layout>
+                                                                                                             
                          <property name="row">1</property>
+                                                                                                             
                          <property name="column">1</property>
+                                                                                                             
                  </layout>
+                                                                                                             
          </object>
+                                                                                                             
  </child>
+
+                                                                                                       
</object>
+                                                                                               </child> <!-- 
/print font grid -->
+
+                                                                                       </object>
+                                                                               </child> <!-- 
/print_font_frame -->
+
+                                                                               <child>
+                                                                                       <object 
class="GtkBox"> <!-- print shaded check hbox -->
+                                                                                               <property 
name="orientation">horizontal</property>
+                                                                                               <property 
name="spacing">12</property>
+                                                                                               <child>
+                                                                                                       
<object class="GtkCheckButton" id="shaded_box_chkbtn">
+                                                                                                             
  <property name="label" translatable="yes">Print shaded rows:</property>
+                                                                                                       
</object>
+                                                                                               </child>
+                                                                                       </object> <!-- /print 
shaded hbox -->
+                                                                               </child>
+
+                                                                               <child>
+                                                                                       <object 
class="GtkBox" id="shaded_box_box"> <!-- shaded_box hbox -->
+                                                                                               <property 
name="orientation">horizontal</property>
+                                                                                               <property 
name="spacing">12</property>
+                                                                                               <child>
+                                                                                                       
<object class="GtkLabel" id="shaded_box_label">
+                                                                                                             
  <property name="label" translatable="yes">Span across lines:</property>
+                                                                                                       
</object>
+                                                                                               </child>
+                                                                                               <child>
+                                                                                                       
<object class="GtkSpinButton" id="shaded_box_spinbtn" />
+                                                                                               </child>
+                                                                                       </object> <!-- 
/shaded_box hbox -->
+                                                                               </child>
+
+                                                                       </object> <!-- /vbox -->
+                                                               </property> <!-- /page2 child -->
+                                                       </object>
+                                               </child> <!-- /stackPage2 -->
+                                       </object>
+                               </child> <!-- /stack -->
+
+                       </object>
+               </child> <!-- /box -->
+
+               <child type="action">
+                       <object class="GtkButton" id="help_button">
+                               <property name="use-underline">true</property>
+                               <property name="label" translatable="yes">_Help</property>
+                       </object>
+               </child>
+               <child type="action">
+                       <object class="GtkButton" id="close_button">
+                               <property name="use-underline">true</property>
+                               <property name="label" translatable="yes">_Close</property>
+                       </object>
+               </child>
+
+               <action-widgets>
+                       <action-widget response="help">help_button</action-widget>
+                       <action-widget response="close" default="true">close_button</action-widget>
+               </action-widgets>
+       </object> <!-- /prefs_dialog -->
+
+</interface>


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