[ghex/gtk4-port: 51/91] Implement layout manager and many fixes and tweaks.




commit 5bcb010c37feaf2f6629d8bdd104d12ce645f9a5
Author: Logan Rathbone <poprocks gmail com>
Date:   Sat Jan 23 22:50:16 2021 -0500

    Implement layout manager and many fixes and tweaks.

 src/Makefile                  |    3 +-
 src/STUB.c                    |  110 ----
 src/chartable.c               |   56 +-
 src/chartable.h               |    6 +
 src/common-ui.c               |   35 +-
 src/common-ui.h               |    3 +-
 src/debug-test.sh             |    2 +-
 src/findreplace.c             |  143 ++---
 src/findreplace.h             |    4 +-
 src/ghex-application-window.c |   23 +-
 src/ghex-ui.xml               |   59 --
 src/ghex-window.c             | 1377 -----------------------------------------
 src/ghex-window.h             |  114 ----
 src/gtkhex-layout-manager.c   |  418 +++++++++++++
 src/gtkhex-layout-manager.h   |   52 ++
 src/gtkhex.c                  |  655 ++++----------------
 src/meson.build               |    5 +-
 17 files changed, 752 insertions(+), 2313 deletions(-)
---
diff --git a/src/Makefile b/src/Makefile
index 9a1a6bed..24dc351f 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -7,12 +7,11 @@ CFLAGS=-Wall -Wextra -Werror=implicit -std=c11 -pedantic \
        -Wno-unused-variable -Wno-unused-parameter \
        $(GTK_CFLAGS) \
        -I../build -I. \
-       -DHAVE_CONFIG_H \
        $(DEBUG)
 
 .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 configuration.o preferences.o common-ui.o print.o
+main: gtkhex.o hex-document.o ghex-application-window.o hex-dialog.o findreplace.o chartable.o converter.o 
resources.o configuration.o preferences.o common-ui.o print.o gtkhex-layout-manager.o
 
 compile-resources:
        glib-compile-resources ghex.gresource.xml --target=resources.c --generate-source
diff --git a/src/chartable.c b/src/chartable.c
index 5773d68b..769372e4 100644
--- a/src/chartable.c
+++ b/src/chartable.c
@@ -4,6 +4,8 @@
 /* chartable.c - a window with a character table
 
    Copyright (C) 1998 - 2004 Free Software Foundation
+   Copyright © 2005-2020 FIXME
+   Copyright © Logan Rathbone <poprocks gmail com>
 
    GHex is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -20,24 +22,15 @@
    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>
 */
 
+#include "chartable.h"
+
 #ifdef HAVE_CONFIG_H
 #  include <config.h>
 #endif /* HAVE_CONFIG_H */
 
-#include <stdlib.h>
-
-#include <gtk/gtk.h>
-#include <gdk/gdkkeysyms.h>
-#include <glib/gi18n.h>
-
-#include <gtkhex.h>
-#include "chartable.h"
-//#include "ghex-window.h"
-//#include "ui.h"
-
 /* STATIC GLOBALS */
 
 static GtkTreeSelection *sel_row = NULL;
@@ -121,19 +114,23 @@ chartable_row_activated_cb (GtkTreeView *tree_view,
        insert_char (tree_view, model);
 }
 
-
-#if 0
-static gboolean select_chartable_row_cb(GtkTreeView *treeview, GdkEventButton *event, gpointer data)
+static void
+inbtn_clicked_cb (GtkButton *button, gpointer user_data)
 {
-       GtkTreeModel *model = GTK_TREE_MODEL(data);
+       GtkTreeView *treeview = GTK_TREE_VIEW(user_data);
+       GtkTreeModel *model;
+
+       g_return_if_fail (GTK_IS_TREE_VIEW(treeview));
 
-       if(event->type == GDK_2BUTTON_PRESS)
-               insert_char(treeview, model);
-       return FALSE;
+       (void)button;   /* unused */
+
+       model = gtk_tree_view_get_model (treeview);
+
+       insert_char (treeview, model);
 }
-#endif
 
-static void hide_chartable_cb (GtkButton *button, gpointer user_data)
+static void
+hide_chartable_cb (GtkButton *button, gpointer user_data)
 {
        GtkWindow *win = GTK_WINDOW(user_data);
 
@@ -148,7 +145,7 @@ GtkWidget *create_char_table(GtkWindow *parent_win, GtkHex *gh)
        static gchar *titles[] = {  N_("ASCII"), N_("Hex"), N_("Decimal"),
                N_("Octal"), N_("Binary") };
        gchar *real_titles[5];
-       GtkWidget *ct, *sw, *ctv, *cbtn, *vbox, *hbox, *lbl;
+       GtkWidget *ct, *sw, *ctv, *inbtn, *cbtn, *vbox, *hbox, *lbl;
        GtkListStore *store;
        GtkCellRenderer *cell_renderer;
        GtkTreeViewColumn *column;
@@ -238,18 +235,12 @@ GtkWidget *create_char_table(GtkWindow *parent_win, GtkHex *gh)
        g_signal_connect (ctv, "row-activated",
                        G_CALLBACK(chartable_row_activated_cb), GTK_TREE_MODEL(store));
 
-       // REWRITE
-#if 0
-       g_signal_connect(G_OBJECT(ct), "delete-event",
-                                        G_CALLBACK(delete_event_cb), ct);
-       g_signal_connect(G_OBJECT(ctv), "button_press_event",
-                                        G_CALLBACK(select_chartable_row_cb), GTK_TREE_MODEL(store));
-       g_signal_connect(G_OBJECT(ctv), "key_press_event",
-                                        G_CALLBACK(key_press_cb), GTK_TREE_MODEL(store));
-#endif
-
        gtk_widget_grab_focus(ctv);
 
+       inbtn = gtk_button_new_with_mnemonic (_("_Insert Character"));
+       g_signal_connect(G_OBJECT (inbtn), "clicked",
+                                       G_CALLBACK(inbtn_clicked_cb), ctv);
+
        cbtn = gtk_button_new_with_mnemonic (_("_Close"));
        g_signal_connect(G_OBJECT (cbtn), "clicked",
                                        G_CALLBACK(hide_chartable_cb), ct);
@@ -260,6 +251,7 @@ GtkWidget *create_char_table(GtkWindow *parent_win, GtkHex *gh)
 
        gtk_box_append (GTK_BOX(vbox), sw);
        gtk_box_append (GTK_BOX(hbox), lbl);
+       gtk_box_append (GTK_BOX(hbox), inbtn);
        gtk_box_append (GTK_BOX(hbox), cbtn);
        gtk_box_append (GTK_BOX(vbox), hbox);
 
diff --git a/src/chartable.h b/src/chartable.h
index a0d4640d..5b2ac47e 100644
--- a/src/chartable.h
+++ b/src/chartable.h
@@ -24,7 +24,13 @@
 #ifndef GHEX_CHARTABLE_H
 #define GHEX_CHARTABLE_H
 
+#include <stdlib.h>
+
 #include <gtk/gtk.h>
+#include <glib/gi18n.h>
+
+#include "gtkhex.h"
+#include "common-ui.h"
 
 G_BEGIN_DECLS
 
diff --git a/src/common-ui.c b/src/common-ui.c
index d6fa90f6..876cb655 100644
--- a/src/common-ui.c
+++ b/src/common-ui.c
@@ -24,10 +24,11 @@
    Original Author: Jaka Mocnik <jaka gnu org>
 */
 
-#include <config.h>            /* Not optional for this. */
-
 #include "common-ui.h"
 
+/* Not optional. */
+#include <config.h>
+
 #if 0
 static void ghex_print(GtkHex *gh, gboolean preview);
 
@@ -892,29 +893,41 @@ common_print (GtkWindow *parent, GtkHex *gh, gboolean preview)
        g_free (gtk_file_name);
 }
 
-void
-display_error_dialog (GtkWindow *parent, const char *msg)
+static void
+display_dialog (GtkWindow *parent, const char *msg, GtkMessageType type)
 {
-       GtkWidget *error_dlg;
+       GtkWidget *dialog;
 
        g_return_if_fail (GTK_IS_WINDOW(parent));
        g_return_if_fail (msg);
 
-       error_dlg = gtk_message_dialog_new (parent,
+       dialog = gtk_message_dialog_new (parent,
                        GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
-                       GTK_MESSAGE_ERROR,
+                       type,
                        GTK_BUTTONS_CLOSE,
                        "%s", msg);
 
-       gtk_dialog_set_default_response (GTK_DIALOG (error_dlg),
+       gtk_dialog_set_default_response (GTK_DIALOG (dialog),
                        GTK_RESPONSE_CLOSE);
-       gtk_window_set_resizable (GTK_WINDOW (error_dlg), FALSE);
-       gtk_widget_show (error_dlg);
+       gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+       gtk_widget_show (dialog);
 
-       g_signal_connect (error_dlg, "response",
+       g_signal_connect (dialog, "response",
                        G_CALLBACK (gtk_window_destroy), NULL);
 }
 
+void
+display_error_dialog (GtkWindow *parent, const char *msg)
+{
+       display_dialog (parent, msg, GTK_MESSAGE_ERROR);
+}
+
+void
+display_info_dialog (GtkWindow *parent, const char *msg)
+{
+       display_dialog (parent, msg, GTK_MESSAGE_INFO);
+}
+
 #if 0
 void
 display_info_dialog (GHexWindow *win, const gchar *msg, ...)
diff --git a/src/common-ui.h b/src/common-ui.h
index 40ae4728..cbbca4ad 100644
--- a/src/common-ui.h
+++ b/src/common-ui.h
@@ -29,8 +29,8 @@
 
 #include <gtk/gtk.h>
 #include <glib/gi18n.h>
-#include <gtkhex.h>
 
+#include "gtkhex.h"
 #include "configuration.h"
 #include "print.h"
 
@@ -42,6 +42,7 @@ void common_help_cb (GtkWindow *parent);
 void common_about_cb (GtkWindow *parent);
 void common_print (GtkWindow *parent, GtkHex *gh, gboolean preview);
 void display_error_dialog (GtkWindow *parent, const char *msg);
+void display_info_dialog (GtkWindow *parent, const char *msg);
 
 G_END_DECLS
 
diff --git a/src/debug-test.sh b/src/debug-test.sh
index e97a0a4e..2f1c91de 100755
--- a/src/debug-test.sh
+++ b/src/debug-test.sh
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-TEST_PROG="./STUB"
+TEST_PROG="./main"
 
 # GTK_DEBUG=interactive \
        G_ENABLE_DIAGNOSTIC=1 \
diff --git a/src/findreplace.c b/src/findreplace.c
index 935a953c..70de85d0 100644
--- a/src/findreplace.c
+++ b/src/findreplace.c
@@ -30,19 +30,13 @@
    Author: Jaka Mocnik <jaka gnu org>
 */
 
-#ifdef HAVE_CONFIG_H
-#  include <config.h>
-#endif
-
-#include <gtk/gtk.h>
-#include <glib/gi18n.h>
-
 #include "findreplace.h"
-//#include "ui.h"
-#include "gtkhex.h"
-#include "configuration.h"
+
+/* Not optional. */
+#include <config.h>
 
 /* DEFINES */
+
 #define JUMP_DIALOG_CSS_NAME "jumpdialog"
 
 /* GOBJECT DEFINITIONS */
@@ -104,8 +98,6 @@ G_DEFINE_TYPE (ReplaceDialog, replace_dialog, GTK_TYPE_WIDGET)
 
 /* PRIVATE FUNCTION DECLARATIONS */
 
-//static gint find_delete_event_cb(GtkWidget *w, GdkEventAny *e,
-//             FindDialog *dialog);
 static void find_cancel_cb(GtkButton *button, gpointer user_data);
 static void replace_cancel_cb (GtkButton *button, gpointer user_data);
 static void jump_cancel_cb (GtkButton *button, gpointer user_data);
@@ -121,11 +113,11 @@ static gint get_search_string(HexDocument *doc, gchar **str);
 static GtkWidget *
 create_hex_view(HexDocument *doc)
 {
-    GtkWidget *gh = hex_document_add_view(doc);
+    GtkWidget *gh = hex_document_add_view (doc);
+
+       gtk_widget_set_hexpand (gh, TRUE);
 
-       // TEST
-       gtk_hex_set_group_type(GTK_HEX(gh), GROUP_BYTE);
-//     gtk_hex_set_group_type(GTK_HEX(gh), def_group_type);
+       gtk_hex_set_group_type (GTK_HEX(gh), def_group_type);
 
        // FIXME - JUST DELETE?
 #if 0
@@ -134,8 +126,8 @@ create_hex_view(HexDocument *doc)
     }
 #endif
 
-    gtk_hex_set_insert_mode(GTK_HEX(gh), TRUE);
-    gtk_hex_set_geometry(GTK_HEX(gh), 16, 4);
+    gtk_hex_set_insert_mode (GTK_HEX(gh), TRUE);
+    gtk_hex_set_geometry (GTK_HEX(gh), 16, 4);
 
     return gh;
 }
@@ -152,23 +144,6 @@ static gint get_search_string(HexDocument *doc, gchar **str)
        return size;
 }
 
-#if 0
-/* find and advanced find need special close dialogs, since they
- * need to do stuff with the highlights
- */
-static gint find_delete_event_cb(GtkWidget *w, GdkEventAny *e, FindDialog *dialog)
-{
-       GHexWindow *win = ghex_window_get_active();
-       GtkHex *gh = win->gh;
-       
-       if (dialog->auto_highlight) gtk_hex_delete_autohighlight(gh, dialog->auto_highlight);
-       dialog->auto_highlight = NULL;
-       gtk_widget_hide(w);
-
-       return TRUE;
-}
-#endif
-
 static void
 replace_cancel_cb (GtkButton *button, gpointer user_data)
 {
@@ -219,6 +194,7 @@ find_next_cb(GtkButton *button, gpointer user_data)
 {
        FindDialog *self = FIND_DIALOG(user_data);
        GtkWidget *widget = GTK_WIDGET(user_data);
+       GtkWindow *parent;
        HexDocument *doc;
        guint cursor_pos;
        guint offset, str_len;
@@ -229,13 +205,16 @@ find_next_cb(GtkButton *button, gpointer user_data)
 
        (void)button;   /* unused */
 
+       parent = GTK_WINDOW(gtk_widget_get_native (widget));
+       if (! GTK_IS_WINDOW(parent))
+               parent = NULL;
+
        doc = gtk_hex_get_document(self->gh);
        cursor_pos = gtk_hex_get_cursor(self->gh);
 
-       if ((str_len = get_search_string(self->f_doc, &str)) == 0) {
-               g_debug(_("There is no string to search for!"));
-               // FIXME
-//             display_error_dialog (self, _("There is no string to search for!"));
+       if ((str_len = get_search_string(self->f_doc, &str)) == 0)
+       {
+               display_error_dialog (parent, _("There is no string to search for!"));
                return;
        }
 
@@ -256,9 +235,7 @@ find_next_cb(GtkButton *button, gpointer user_data)
                gtk_hex_set_cursor(self->gh, offset);
        }
        else {
-               // FIXME - NOT IMPLEMENTED
-//             ghex_window_flash(win, _("End Of File reached"));
-//             display_info_dialog(self, _("String was not found!\n"));
+               display_info_dialog (parent, _("String was not found!\n"));
        }
 
        if (str)
@@ -270,6 +247,7 @@ find_prev_cb(GtkButton *button, gpointer user_data)
 {
        FindDialog *self = FIND_DIALOG(user_data);
        GtkWidget *widget = GTK_WIDGET(user_data);
+       GtkWindow *parent;
        HexDocument *doc;
        guint cursor_pos;
        guint offset, str_len;
@@ -280,12 +258,15 @@ find_prev_cb(GtkButton *button, gpointer user_data)
 
        (void)button;   /* unused */
 
+       parent = GTK_WINDOW(gtk_widget_get_native (widget));
+       if (! GTK_IS_WINDOW(parent))
+               parent = NULL;
+
        doc = gtk_hex_get_document(self->gh);
        cursor_pos = gtk_hex_get_cursor(self->gh);
 
        if ((str_len = get_search_string(self->f_doc, &str)) == 0) {
-               // FIXME
-//             display_error_dialog (self, _("There is no string to search for!"));
+               display_error_dialog (parent, _("There is no string to search for!"));
                return;
        }
 
@@ -304,9 +285,7 @@ find_prev_cb(GtkButton *button, gpointer user_data)
                gtk_hex_set_cursor(self->gh, offset);
        }
        else {
-               // FIXME - NOT IMPLEMENTED
-//             ghex_window_flash(win, _("Beginning Of File reached"));
-//             display_info_dialog(self, _("String was not found!\n"));
+               display_info_dialog (parent, _("String was not found!\n"));
        }
        if (str)
                g_free(str);
@@ -317,6 +296,7 @@ goto_byte_cb(GtkButton *button, gpointer user_data)
 {
        JumpDialog *self = JUMP_DIALOG(user_data);
        GtkWidget *widget = GTK_WIDGET(user_data);
+       GtkWindow *parent;
        HexDocument *doc;
        guint cursor_pos;
        GtkEntry *entry;
@@ -331,6 +311,10 @@ goto_byte_cb(GtkButton *button, gpointer user_data)
 
        (void)button;   /* unused */
 
+       parent = GTK_WINDOW(gtk_widget_get_native (widget));
+       if (! GTK_IS_WINDOW(parent))
+               parent = NULL;
+
        doc = gtk_hex_get_document(self->gh);
        cursor_pos = gtk_hex_get_cursor(self->gh);
 
@@ -352,8 +336,7 @@ goto_byte_cb(GtkButton *button, gpointer user_data)
        }
        
        if (len == 0) {
-               // FIXME
-//             display_error_dialog (self, _("No offset has been specified!"));
+               display_error_dialog (parent, _("No offset has been specified!"));
                return;
        }
 
@@ -377,36 +360,27 @@ goto_byte_cb(GtkButton *button, gpointer user_data)
                (sscanf(byte_str, "%d", &byte) == 1))) {
                if(is_relative) {
                        if(is_relative == -1 && byte > cursor_pos) {
-                               // FIXME
-#if 0
-                               display_error_dialog(self,
+                               display_error_dialog(parent,
                                                                 _("The specified offset is beyond the "
                                                                " file boundaries!"));
-#endif
                                return;
                        }
                        byte = byte * is_relative + cursor_pos;
                }
                if (byte >= doc->file_size) {
-                       // FIXME
-#if 0
-                       display_error_dialog(self,
+                       display_error_dialog(parent,
                                                                 _("Can not position cursor beyond the "
                                                                   "End Of File!"));
-#endif
                } else {
                        gtk_hex_set_cursor(self->gh, byte);
                }
        }
        else {
-               // FIXME
-#if 0
-               display_error_dialog(self,
+               display_error_dialog(parent,
                                _("You may only give the offset as:\n"
                                        "  - a positive decimal number, or\n"
                                        "  - a hex number, beginning with '0x', or\n"
                                        "  - a '+' or '-' sign, followed by a relative offset"));
-#endif
        }
 }
 
@@ -415,6 +389,7 @@ replace_next_cb (GtkButton *button, gpointer user_data)
 {
        ReplaceDialog *self = REPLACE_DIALOG(user_data);
        GtkWidget *widget = GTK_WIDGET(user_data);
+       GtkWindow *parent;
        HexDocument *doc;
        guint cursor_pos;
        guint offset, str_len;
@@ -423,12 +398,15 @@ replace_next_cb (GtkButton *button, gpointer user_data)
        g_return_if_fail (REPLACE_IS_DIALOG(self));
        g_return_if_fail (GTK_IS_HEX(self->gh));
 
+       parent = GTK_WINDOW(gtk_widget_get_native (widget));
+       if (! GTK_IS_WINDOW(parent))
+               parent = NULL;
+
        doc = gtk_hex_get_document (self->gh);
        cursor_pos = gtk_hex_get_cursor (self->gh);
 
        if ((str_len = get_search_string(self->f_doc, &str)) == 0) {
-               // FIXME
-//             display_error_dialog (self, _("There is no string to search for!"));
+               display_error_dialog (parent, _("There is no string to search for!"));
                return;
        }
 
@@ -438,9 +416,7 @@ replace_next_cb (GtkButton *button, gpointer user_data)
                gtk_hex_set_cursor(self->gh, offset);
        }
        else {
-               // FIXME - NOT IMPLEMENTED
-//             display_info_dialog (self, _("String was not found!\n"));
-//             ghex_window_flash(win, _("End Of File reached"));
+               display_info_dialog (parent, _("String was not found!\n"));
        }
 
        if (str)
@@ -452,6 +428,7 @@ replace_one_cb(GtkButton *button, gpointer user_data)
 {
        ReplaceDialog *self = REPLACE_DIALOG(user_data);
        GtkWidget *widget = GTK_WIDGET(user_data);
+       GtkWindow *parent;
        HexDocument *doc;
        guint cursor_pos;
        gchar *find_str = NULL, *rep_str = NULL;
@@ -462,12 +439,15 @@ replace_one_cb(GtkButton *button, gpointer user_data)
 
        (void)button;   /* unused */
 
+       parent = GTK_WINDOW(gtk_widget_get_native (widget));
+       if (! GTK_IS_WINDOW(parent))
+               parent = NULL;
+
        doc = gtk_hex_get_document (self->gh);
        cursor_pos = gtk_hex_get_cursor (self->gh);
        
        if ((find_len = get_search_string(self->f_doc, &find_str)) == 0) {
-               // FIXME
-//             display_error_dialog (self, _("There is no string to search for!"));
+               display_error_dialog (parent, _("There is no string to search for!"));
                return;
        }
        rep_len = get_search_string(self->r_doc, &rep_str);
@@ -487,9 +467,7 @@ replace_one_cb(GtkButton *button, gpointer user_data)
                gtk_hex_set_cursor(self->gh, offset);
        }
        else {
-               // FIXME - NOT IMPLEMENTED
-//             display_info_dialog(self, _("End Of File reached!"));
-//             ghex_window_flash(win, _("End Of File reached!"));
+               display_info_dialog (parent, _("String was not found!"));
        }
 
 clean_up:
@@ -505,9 +483,10 @@ replace_all_cb (GtkButton *button, gpointer user_data)
 {
        ReplaceDialog *self = REPLACE_DIALOG(user_data);
        GtkWidget *widget = GTK_WIDGET(user_data);
+       GtkWindow *parent;
        HexDocument *doc;
        guint cursor_pos;
-       gchar *find_str = NULL, *rep_str = NULL, *flash;
+       gchar *find_str = NULL, *rep_str = NULL;
        guint find_len, rep_len, offset, count;
 
        g_return_if_fail (REPLACE_IS_DIALOG(self));
@@ -515,12 +494,15 @@ replace_all_cb (GtkButton *button, gpointer user_data)
 
        (void)button;   /* unused */
 
+       parent = GTK_WINDOW(gtk_widget_get_native (widget));
+       if (! GTK_IS_WINDOW(parent))
+               parent = NULL;
+
        doc = gtk_hex_get_document (self->gh);
        cursor_pos = gtk_hex_get_cursor (self->gh);
 
        if ((find_len = get_search_string(self->f_doc, &find_str)) == 0) {
-               // FIXME
-//             display_error_dialog (self, _("There is no string to search for!"));
+               display_error_dialog (parent, _("There is no string to search for!"));
                return;
        }
        rep_len = get_search_string(self->r_doc, &rep_str);
@@ -541,17 +523,9 @@ replace_all_cb (GtkButton *button, gpointer user_data)
        gtk_hex_set_cursor(self->gh, MIN(offset, doc->file_size));  
 
        if(count == 0) {
-               // FIXME
-//             display_info_dialog (self, _("No occurrences were found."));
+               display_info_dialog (parent, _("No occurrences were found."));
        }
        
-       flash = g_strdup_printf(ngettext("Replaced %d occurrence.",
-                                                                        "Replaced %d occurrences.",
-                                                                        count), count);
-       // FIXME - NOT IMPLEMENTED
-//     ghex_window_flash(win, flash);
-       g_free(flash);
-
 clean_up:
        if (find_str)
                g_free(find_str);
@@ -620,7 +594,6 @@ find_dialog_init (FindDialog *self)
 }
 
 
-// TODO - see: find_delete_event_cb for some possible destructor hints here?
 static void
 find_dialog_dispose(GObject *object)
 {
@@ -866,7 +839,7 @@ jump_dialog_init (JumpDialog *self)
 
        /* Widget */
 
-       self->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+       self->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
        gtk_widget_set_parent (self->box, widget);
        
        /* FIXME/TODO - this is not very intuitive. */
diff --git a/src/findreplace.h b/src/findreplace.h
index 76917bcc..327328f2 100644
--- a/src/findreplace.h
+++ b/src/findreplace.h
@@ -29,9 +29,11 @@
 #define FINDREPLACE_H 
 
 #include <gtk/gtk.h>
+#include <glib/gi18n.h>
 
 #include "gtkhex.h"
-#include "findreplace.h"
+#include "configuration.h"
+#include "common-ui.h"
 
 G_BEGIN_DECLS
 
diff --git a/src/ghex-application-window.c b/src/ghex-application-window.c
index 426b833c..23d4173f 100644
--- a/src/ghex-application-window.c
+++ b/src/ghex-application-window.c
@@ -1,5 +1,26 @@
 /* vim: ts=4 sw=4 colorcolumn=80
- */
+ * -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* ghex-application-window.c - GHex main application window
+
+   Copyright © 2021 Logan Rathbone <poprocks gmail com>
+
+   GHex is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   GHex is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GHex; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+   Original GHex Author: Jaka Mocnik <jaka gnu org>
+*/
 
 #include "ghex-application-window.h"
 
diff --git a/src/gtkhex-layout-manager.c b/src/gtkhex-layout-manager.c
new file mode 100644
index 00000000..51cecae2
--- /dev/null
+++ b/src/gtkhex-layout-manager.c
@@ -0,0 +1,418 @@
+/* vim: ts=4 sw=4 colorcolumn=80
+ * -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* gtkhex-layout-manager.h - declaration of a GtkHex layout manager
+
+   Copyright © 2021 Logan Rathbone <poprocks gmail com>
+
+   GHex is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   GHex is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GHex; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+   Original GHex Author: Jaka Mocnik <jaka gnu org>
+*/
+
+#include "gtkhex-layout-manager.h"
+
+#define OFFSETS_CPL            10
+#define HEX_RATIO              0.75
+#define ASCII_RATIO            0.25
+
+struct _GtkHexLayout {
+       GtkLayoutManager parent_instance;
+
+       GtkWidget *offets;
+       GtkWidget *hex;
+       GtkWidget *ascii;
+
+       guint char_width;
+//     guint group_type;
+
+       int hex_width;
+       int ascii_width;
+};
+
+G_DEFINE_TYPE (GtkHexLayout, gtk_hex_layout, GTK_TYPE_LAYOUT_MANAGER)
+
+struct _GtkHexLayoutChild {
+       GtkLayoutChild parent_instance;
+
+       GtkHexLayoutColumn column;
+};
+
+enum {
+  PROP_CHILD_COLUMN = 1,
+
+  N_CHILD_PROPERTIES
+};
+
+static GParamSpec *child_props[N_CHILD_PROPERTIES];
+
+/* Some code required to use g_param_spec_enum below. */
+
+#define GTK_HEX_LAYOUT_COLUMN (gtk_hex_layout_column_get_type ())
+static GType
+gtk_hex_layout_column_get_type (void)
+{
+       static GType hex_layout_column_type = 0;
+       static const GEnumValue format_types[] = {
+               {OFFSETS_COLUMN, "Offsets", "offsets"},
+               {HEX_COLUMN, "Hex", "hex"},
+               {ASCII_COLUMN, "ASCII", "ascii"},
+               {0, NULL, NULL}
+       };
+       if (! hex_layout_column_type) {
+               hex_layout_column_type =
+                       g_enum_register_static ("GstAudioParseFormat", format_types);
+       }
+       return hex_layout_column_type;
+}
+
+
+G_DEFINE_TYPE (GtkHexLayoutChild, gtk_hex_layout_child, GTK_TYPE_LAYOUT_CHILD)
+
+
+/* LAYOUT CHILD METHODS */
+
+static void
+gtk_hex_layout_child_set_property (GObject *gobject,
+               guint         prop_id,
+               const GValue *value,
+               GParamSpec   *pspec)
+{
+       GtkHexLayoutChild *self = GTK_HEX_LAYOUT_CHILD(gobject);
+
+       switch (prop_id)
+       {
+               case PROP_CHILD_COLUMN:
+                       self->column = g_value_get_enum (value);
+                       break;
+
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+                       break;
+       }
+}
+
+static void
+gtk_hex_layout_child_get_property (GObject    *gobject,
+               guint       prop_id,
+               GValue     *value,
+               GParamSpec *pspec)
+{
+       GtkHexLayoutChild *self = GTK_HEX_LAYOUT_CHILD(gobject);
+
+       switch (prop_id)
+       {
+               case PROP_CHILD_COLUMN:
+                       g_value_set_enum (value, self->column);
+                       break;
+
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+                       break;
+       }
+}
+
+static void
+gtk_hex_layout_child_finalize (GObject *gobject)
+{
+       GtkHexLayoutChild *self = GTK_HEX_LAYOUT_CHILD (gobject);
+
+       G_OBJECT_CLASS (gtk_hex_layout_child_parent_class)->finalize (gobject);
+}
+
+static void
+gtk_hex_layout_child_dispose (GObject *gobject)
+{
+       GtkHexLayoutChild *self = GTK_HEX_LAYOUT_CHILD (gobject);
+
+       G_OBJECT_CLASS (gtk_hex_layout_child_parent_class)->finalize (gobject);
+}
+
+static void
+gtk_hex_layout_child_class_init (GtkHexLayoutChildClass *klass)
+{
+       GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+       gobject_class->set_property = gtk_hex_layout_child_set_property;
+       gobject_class->get_property = gtk_hex_layout_child_get_property;
+       gobject_class->finalize = gtk_hex_layout_child_finalize;
+       gobject_class->dispose = gtk_hex_layout_child_dispose;
+
+       child_props[PROP_CHILD_COLUMN] = g_param_spec_enum ("column",
+                       "Column type",
+                       "The column type of a child of a hex layout",
+                       GTK_HEX_LAYOUT_COLUMN,
+                       HEX_COLUMN,
+                       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+                               G_PARAM_EXPLICIT_NOTIFY);
+
+       g_object_class_install_properties (gobject_class,
+                       N_CHILD_PROPERTIES, child_props);
+}
+
+static void
+gtk_hex_layout_child_init (GtkHexLayoutChild *self)
+{
+}
+
+
+/* LAYOUT MANAGER METHODS */
+
+static void
+gtk_hex_layout_measure (GtkLayoutManager *layout_manager,
+               GtkWidget               *widget,
+               GtkOrientation  orientation,
+               int                             for_size,
+               int                             *minimum,
+               int                             *natural,
+               int                             *minimum_baseline,
+               int                             *natural_baseline)
+{
+       GtkHexLayoutChild *child_info;
+       GtkWidget *child;
+       int minimum_size = 0;
+       int natural_size = 0;
+
+       for (child = gtk_widget_get_first_child (widget);
+                       child != NULL;
+                       child = gtk_widget_get_next_sibling (child))
+       {
+               int child_min = 0, child_nat = 0;
+
+               if (!gtk_widget_should_layout (child))
+                       continue;
+
+               child_info =
+                       GTK_HEX_LAYOUT_CHILD(gtk_layout_manager_get_layout_child
+                                       (layout_manager, child));
+
+               gtk_widget_measure (child, orientation,
+                               /* for-size: */ -1,             /* == unknown. */
+                               &child_min, &child_nat,
+                               NULL, NULL);
+               minimum_size = MAX (minimum_size, child_min);
+               natural_size = MAX (natural_size, child_nat);
+       }
+
+       // TEST - I have no idea what I'm supposed to be doing here.
+
+       if (minimum != NULL)
+               *minimum = minimum_size;
+       if (natural != NULL)
+               *natural = natural_size;
+}
+
+static void
+gtk_hex_layout_allocate (GtkLayoutManager *layout_manager,
+               GtkWidget        *widget,
+               int               width,
+               int               height,
+               int               baseline)
+{
+       GtkHexLayout *self = GTK_HEX_LAYOUT (layout_manager);
+       GtkHexLayoutChild *child_info;
+       GtkWidget *child;
+       gboolean have_offsets = FALSE;
+       gboolean have_hex = FALSE;
+       gboolean have_ascii = FALSE;
+       GtkAllocation base_alloc = {.x = 0, .y = 0, .width = 0, .height = height};
+       GtkAllocation off_alloc = base_alloc;   /* GdkRectangle */
+       GtkAllocation hex_alloc = base_alloc;
+       GtkAllocation asc_alloc = base_alloc;
+       GtkAllocation scr_alloc = base_alloc;
+       GtkAllocation tmp_alloc = {0};
+
+       for (child = gtk_widget_get_first_child (widget);
+                       child != NULL;
+                       child = gtk_widget_get_next_sibling (child))
+       {
+               GtkRequisition child_req = { .width = 0, .height = 0 };
+
+               if (! gtk_widget_should_layout (child))
+                       continue;
+
+               /* Get preferred size of the child widget
+                */
+               gtk_widget_get_preferred_size (child, &child_req, NULL);
+
+               /* Setup allocation depending on what column we're in.
+                */
+               child_info =
+                       GTK_HEX_LAYOUT_CHILD(gtk_layout_manager_get_layout_child (layout_manager,
+                                               child));
+
+               switch (child_info->column)
+               {
+                       case OFFSETS_COLUMN:
+                               have_offsets = TRUE;
+                               off_alloc.width = OFFSETS_CPL * self->char_width;
+                               break;
+                       case HEX_COLUMN:
+                               have_hex = TRUE;
+                               break;
+                       case ASCII_COLUMN:
+                               have_ascii = TRUE;
+                               break;
+                       case SCROLLBAR_COLUMN:
+                               scr_alloc.x = width;
+                               scr_alloc.width = child_req.width;
+                               scr_alloc.height = height;
+                               break;
+                       default:
+                               g_error ("%s: Programming error. The requested column is invalid.",
+                                               __func__);
+                               break;
+               }
+       }
+       
+       for (child = gtk_widget_get_first_child (widget);
+                       child != NULL;
+                       child = gtk_widget_get_next_sibling (child))
+       {
+               GtkRequisition child_req = { .width = 0, .height = 0 };
+
+               if (! gtk_widget_should_layout (child))
+                       continue;
+
+               /* Get preferred size of the child widget
+                */
+               gtk_widget_get_preferred_size (child, &child_req, NULL);
+
+               /* Setup allocation depending on what column we're in.
+                */
+               child_info =
+                       GTK_HEX_LAYOUT_CHILD(gtk_layout_manager_get_layout_child
+                                       (layout_manager, child));
+
+               switch (child_info->column)
+               {
+                       case OFFSETS_COLUMN:
+                               tmp_alloc = off_alloc;
+                               break;
+
+                       case HEX_COLUMN:
+                               hex_alloc.width = width - off_alloc.width;
+                               hex_alloc.width -= scr_alloc.width;
+                               if (have_ascii) {
+                                       hex_alloc.width *= HEX_RATIO;
+                                       hex_alloc.x += off_alloc.width;
+                               }
+                               tmp_alloc = hex_alloc;
+                               break;
+
+                       case ASCII_COLUMN:
+                               asc_alloc.x += off_alloc.width;
+                               asc_alloc.width = width;
+                               asc_alloc.width -= off_alloc.width;
+                               asc_alloc.width -= scr_alloc.width;
+                               if (have_hex) {
+                                       asc_alloc.width *= ASCII_RATIO;
+                                       asc_alloc.x += (width - off_alloc.width - scr_alloc.width)
+                                               * HEX_RATIO;
+                               }
+                               tmp_alloc = asc_alloc;
+                               break;
+
+                       case SCROLLBAR_COLUMN:
+                               tmp_alloc = scr_alloc;
+                               break;
+
+                       default:
+                               g_error ("%s: Programming error. The requested column is invalid.",
+                                               __func__);
+                               break;
+               }
+
+               gtk_widget_size_allocate (child,
+                       &tmp_alloc,
+                       -1);    /* baseline, or -1 */
+       }
+}
+
+static GtkSizeRequestMode
+gtk_hex_layout_get_request_mode (GtkLayoutManager *layout_manager,
+               GtkWidget        *widget)
+{
+       /* I understand this is the default return type anyway; but I guess it
+        * makes sense to explicit.
+        */
+       return GTK_SIZE_REQUEST_CONSTANT_SIZE;
+}
+
+static GtkLayoutChild *
+gtk_hex_layout_create_layout_child (GtkLayoutManager *manager,
+               GtkWidget        *widget,
+               GtkWidget        *for_child)
+{
+       return g_object_new (GTK_TYPE_HEX_LAYOUT_CHILD,
+                       "layout-manager", manager,
+                       "child-widget", for_child,
+                       NULL);
+}
+
+static void
+gtk_hex_layout_class_init (GtkHexLayoutClass *klass)
+{
+       GtkLayoutManagerClass *layout_class = GTK_LAYOUT_MANAGER_CLASS (klass);
+
+       layout_class->get_request_mode = gtk_hex_layout_get_request_mode;
+       layout_class->measure = gtk_hex_layout_measure;
+       layout_class->allocate = gtk_hex_layout_allocate;
+       layout_class->create_layout_child = gtk_hex_layout_create_layout_child;
+}
+
+static void
+gtk_hex_layout_init (GtkHexLayout *self)
+{
+       g_debug ("%s: TEST - SETTING A DEFAULT MINIMUM CHAR-WIDTH",
+                       __func__);
+       self->char_width = 20;
+}
+
+/* GtkHexLayout - Public Methods */
+
+GtkLayoutManager *
+gtk_hex_layout_new (void)
+{
+  return g_object_new (GTK_TYPE_HEX_LAYOUT, NULL);
+}
+
+void
+gtk_hex_layout_set_char_width (GtkHexLayout *layout, guint width)
+{
+       layout->char_width = width;
+
+       gtk_layout_manager_layout_changed (GTK_LAYOUT_MANAGER(layout));
+}
+
+/* GtkHexLayoutChild - Public Methods */
+
+void
+gtk_hex_layout_child_set_column (GtkHexLayoutChild *child,
+               GtkHexLayoutColumn column)
+{
+       g_return_if_fail (GTK_IS_HEX_LAYOUT_CHILD (child));
+
+       if (child->column == column)
+               return;
+
+       child->column = column;
+
+       gtk_layout_manager_layout_changed
+               (gtk_layout_child_get_layout_manager (GTK_LAYOUT_CHILD(child)));
+
+       g_object_notify_by_pspec (G_OBJECT(child),
+                       child_props[PROP_CHILD_COLUMN]);
+}
diff --git a/src/gtkhex-layout-manager.h b/src/gtkhex-layout-manager.h
new file mode 100644
index 00000000..58fce879
--- /dev/null
+++ b/src/gtkhex-layout-manager.h
@@ -0,0 +1,52 @@
+/* vim: ts=4 sw=4 colorcolumn=80
+ * -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* gtkhex-layout-manager.h - declaration of a GtkHex layout manager
+
+   Copyright © 2021 Logan Rathbone <poprocks gmail com>
+
+   GHex is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   GHex is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GHex; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+   Original GHex Author: Jaka Mocnik <jaka gnu org>
+*/
+
+#ifndef GTK_HEX_LAYOUT_MANAGER_H
+#define GTK_HEX_LAYOUT_MANAGER_H
+
+#include <gtk/gtk.h>
+
+#define GTK_TYPE_HEX_LAYOUT (gtk_hex_layout_get_type ())
+G_DECLARE_FINAL_TYPE (GtkHexLayout, gtk_hex_layout, GTK, HEX_LAYOUT,
+               GtkLayoutManager)
+
+typedef enum {
+       OFFSETS_COLUMN,
+       HEX_COLUMN,
+       ASCII_COLUMN,
+       SCROLLBAR_COLUMN
+} GtkHexLayoutColumn;
+
+#define GTK_TYPE_HEX_LAYOUT_CHILD (gtk_hex_layout_child_get_type ())
+G_DECLARE_FINAL_TYPE (GtkHexLayoutChild, gtk_hex_layout_child,
+               GTK, HEX_LAYOUT_CHILD,
+               GtkLayoutChild)
+
+GtkLayoutManager *     gtk_hex_layout_new (void);
+void                           gtk_hex_layout_set_char_width (GtkHexLayout *layout,
+                                               guint width);
+void                           gtk_hex_layout_child_set_column (GtkHexLayoutChild *child,
+                                               GtkHexLayoutColumn column);
+
+#endif
diff --git a/src/gtkhex.c b/src/gtkhex.c
index 37a07d88..c5ef6253 100644
--- a/src/gtkhex.c
+++ b/src/gtkhex.c
@@ -30,21 +30,32 @@
    Original Author: Jaka Mocnik <jaka gnu org>
 */
 
-#include <config.h>
+#include "gtkhex.h"
 
 #include <string.h>
 
-#include "hex-document.h"
-#include "gtkhex.h"
+/* Not optional. */
+#include <config.h>
+
+/* Don't move these from the source file as they are not part of the public
+ * header.
+ */
+#include "gtkhex-layout-manager.h"
 
 /* LAR - TEMPORARY FOR TESTING ONLY */
 
 #ifdef ENABLE_DEBUG
-#define TEST_DEBUG_FUNCTION_START g_debug ("%s: start", __func__);
+#define TEST_DEBUG_FUNCTION_START g_debug ("%s: [START]", __func__);
 #else
 #define TEST_DEBUG_FUNCTION_START /* */
 #endif
 
+#ifdef ENABLE_DEBUG
+#define TEST_DEBUG_FUNCTION_END g_debug ("%s: [END]", __func__);
+#else
+#define TEST_DEBUG_FUNCTION_END /* */
+#endif
+
 #define NOT_IMPLEMENTED \
        g_critical("%s: NOT IMPLEMENTED", __func__);
 
@@ -53,7 +64,7 @@
 //#define CSS_NAME "entry"
 
 /* default minimum drawing area size (for ascii and hex widgets) in pixels. */
-#define DEFAULT_DA_SIZE 100
+#define DEFAULT_DA_SIZE 50
 
 /* LAR - defines copied from the old header. */
 
@@ -83,6 +94,7 @@ enum {
        CUT_CLIPBOARD_SIGNAL,
        COPY_CLIPBOARD_SIGNAL,
        PASTE_CLIPBOARD_SIGNAL,
+       DRAW_COMPLETE_SIGNAL,
        LAST_SIGNAL
 };
 
@@ -139,6 +151,7 @@ struct _GtkHex
 
        HexDocument *document;
 
+       GtkLayoutManager *layout_manager;
        GtkWidget *box;                         /* main box for layout */
 
        GtkWidget *xdisp, *adisp;       /* DrawingArea */
@@ -399,6 +412,11 @@ get_char_width (GtkHex *gh)
        /* scale down from pango units to pixels */
        width = PANGO_PIXELS(width);
        
+       /* update layout manager */
+       if (GTK_IS_HEX_LAYOUT(gh->layout_manager)) {
+               gtk_hex_layout_set_char_width (gh->layout_manager, width);
+       }
+
        return width;
 }
 
@@ -626,8 +644,6 @@ render_xc (GtkHex *gh,
 
        g_return_if_fail (gtk_widget_get_realized (gh->xdisp));
 
-       TEST_DEBUG_FUNCTION_START
-
        context = gtk_widget_get_style_context (gh->xdisp);
        state = gtk_widget_get_state_flags (gh->xdisp);
 
@@ -941,16 +957,11 @@ render_hex_lines (GtkHex *gh,
        g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET(gh)));
        g_return_if_fail (gh->cpl > 0);
 
-       TEST_DEBUG_FUNCTION_START
-
        context = gtk_widget_get_style_context (widget);
        state = gtk_widget_get_state_flags (widget);
        cursor_line = gh->cursor_pos / gh->cpl - gh->top_line;
        gtk_widget_get_allocation (widget, &allocation);
 
-       g_debug("%s: WIDTH: %d HEIGHT: %d",
-                       __func__, allocation.width, allocation.height);
-
        /* render background. */
        gtk_render_background (context, cr,
                        /* x: */                0,
@@ -966,9 +977,9 @@ render_hex_lines (GtkHex *gh,
         * it to make it clearer?
         */
        frm_len = format_xblock (gh, gh->disp_buffer,
-                       (gh->top_line+min_lines)*gh->cpl,
-                       MIN((gh->top_line+max_lines+1)*gh->cpl,
-                               gh->document->file_size) );
+                       (gh->top_line + min_lines) * gh->cpl,
+                       MIN( (gh->top_line + max_lines + 1) * gh->cpl,
+                               gh->document->file_size ));
        
        for (int i = min_lines; i <= max_lines; i++)
        {
@@ -991,9 +1002,6 @@ render_hex_lines (GtkHex *gh,
                                gh->xlayout);
        }
        
-       // TEST
-       g_debug("%s: cursor_line: %d - min_lines: %d - max_lines: %d - cursor_shown: %d",
-                       __func__, cursor_line, min_lines, max_lines, gh->cursor_shown);
        if ( (cursor_line >= min_lines) && (cursor_line <= max_lines) &&
                        (gh->cursor_shown) )
        {
@@ -1017,8 +1025,6 @@ render_ascii_lines (GtkHex *gh,
        g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET(gh)));
        g_return_if_fail (gh->cpl);
 
-       TEST_DEBUG_FUNCTION_START
-
        context = gtk_widget_get_style_context (widget);
        state = gtk_widget_get_state_flags (widget);
        cursor_line = gh->cursor_pos / gh->cpl - gh->top_line;
@@ -1035,9 +1041,9 @@ render_ascii_lines (GtkHex *gh,
        max_lines = MIN(max_lines, gh->lines);
        
        frm_len = format_ablock (gh, gh->disp_buffer,
-                       (gh->top_line+min_lines)*gh->cpl,
-                       MIN((gh->top_line+max_lines+1)*gh->cpl,
-                               gh->document->file_size));
+                       (gh->top_line + min_lines) * gh->cpl,
+                       MIN( (gh->top_line + max_lines + 1) * gh->cpl,
+                               gh->document->file_size ));
        
        for (int i = min_lines; i <= max_lines; i++)
        {
@@ -1079,8 +1085,6 @@ render_offsets (GtkHex *gh,
        /* offset chars (8) + 1 (null terminator) */
        char offstr[9];
 
-       TEST_DEBUG_FUNCTION_START 
-
        g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (gh)));
 
        context = gtk_widget_get_style_context (widget);
@@ -1126,9 +1130,10 @@ hex_draw (GtkDrawingArea *drawing_area,
        GtkHex *gh = GTK_HEX(user_data);
        int xcpl = 0;
 
-       TEST_DEBUG_FUNCTION_START 
        g_return_if_fail(GTK_IS_HEX(gh));
 
+       TEST_DEBUG_FUNCTION_START
+
        /* Here's the idea here:  the hex drawing widget can expand at will,
         * and we generate our cpl as a whole and to be passed to the ascii draw
         * function based on that.
@@ -1137,9 +1142,6 @@ hex_draw (GtkDrawingArea *drawing_area,
         * the hex lines and before proceeding to draw the ascii widget.
         */
 
-       g_debug("%s: width: %d - height: %d",
-                       __func__, width, height);
-
        /* Total number of characters that can be displayed per line on the hex
         * widget (xcpl) is the simplest calculation:
         */
@@ -1169,11 +1171,7 @@ hex_draw (GtkDrawingArea *drawing_area,
        /* pixel width of ascii drawing area */
        gh->adisp_width = gh->cpl * gh->char_width;
 
-       /* set visible lines */
-       gh->vis_lines = height / gh->char_height;
-
        /* If gh->cpl is not greater than 0, something has gone wrong. */
-       g_debug("%s: gh->cpl: %d", __func__, gh->cpl);
        g_return_if_fail (gh->cpl > 0);
 
        /* Now that we have gh->cpl defined, run this function to bump all
@@ -1185,6 +1183,8 @@ hex_draw (GtkDrawingArea *drawing_area,
         * lines!
         */
        render_hex_lines (gh, cr, 0, gh->vis_lines);
+
+       TEST_DEBUG_FUNCTION_END
 }
 
 
@@ -1197,13 +1197,9 @@ ascii_draw (GtkDrawingArea *drawing_area,
 {
        GtkHex *gh = GTK_HEX(user_data);
 
-       TEST_DEBUG_FUNCTION_START 
        g_return_if_fail(GTK_IS_HEX(gh));
 
-       gtk_drawing_area_set_content_width (drawing_area, gh->adisp_width);
-
-       g_debug("%s: width: %d - height: %d",
-                       __func__, width, height);
+       TEST_DEBUG_FUNCTION_START
 
        render_ascii_lines (gh, cr, 0, gh->vis_lines);
 
@@ -1224,6 +1220,8 @@ ascii_draw (GtkDrawingArea *drawing_area,
 
        render_ascii_lines (gh, cr, imin, imax);
 #endif
+
+       TEST_DEBUG_FUNCTION_END
 }
 
 static void
@@ -1234,17 +1232,7 @@ offsets_draw (GtkDrawingArea *drawing_area,
                            gpointer user_data)
 {
        GtkHex *gh = GTK_HEX(user_data);
-
        g_return_if_fail(GTK_IS_HEX(gh));
-       TEST_DEBUG_FUNCTION_START 
-
-       /* FIXME - MAGIC NUMBER - set the width to 8 + 1 = 9 characters
-        * (this is fixed based on offset length always being 8 chars.)  */
-       gtk_drawing_area_set_content_width (drawing_area,
-                       9 * gh->char_width);
-
-       g_debug("%s: width: %d - height: %d",
-                       __func__, width, height);
 
        render_offsets (gh, cr, 0, gh->vis_lines);
 
@@ -1268,9 +1256,7 @@ offsets_draw (GtkDrawingArea *drawing_area,
 #endif
 }
 
-// FIXME - CLEAN UP THIS MESS! Not touching it right now because I don't
-// know whether we'll need to 'revive' some variables that aren't really
-// used here, like 'old_cpl'
+// FIXME - CLEAN UP FURTHER.
 /*
  * this calculates how many bytes we can stuff into one line and how many
  * lines we can display according to the current size of the widget
@@ -1279,87 +1265,12 @@ static void
 recalc_displays(GtkHex *gh)
 {
        GtkWidget *widget = GTK_WIDGET (gh);
-       int old_cpl = gh->cpl;
-       gboolean scroll_to_cursor;
-       gdouble value;
-       int total_cpl, xcpl;
-       // TEST
-       GtkStyleContext *context;
-       GtkBorder padding;
-       GtkBorder border;
-
-       // TEST - no longer needed??
-#if 0
-       context = gtk_widget_get_style_context (widget);
-
-       gtk_style_context_get_padding (context, &padding);
-       gtk_style_context_get_border (context, &border);
-#endif
+       int xcpl;
 
        /*
         * Only change the value of the adjustment to put the cursor on screen
         * if the cursor is currently within the displayed portion.
         */
-       // FIXME - WTF??
-       scroll_to_cursor = (gh->cpl == 0) ||
-               ((gh->cursor_pos / gh->cpl >= gtk_adjustment_get_value (gh->adj)) &&
-                (gh->cursor_pos / gh->cpl <= gtk_adjustment_get_value (gh->adj) +
-                         gh->vis_lines - 1));
-       
-       // TEST - no longer needed?
-#if 0
-       gh->xdisp_width = 1;
-       gh->adisp_width = 1;
-#endif
-
-#if 0
-       // API CHANGE
-       total_width -= 20 +             // LAR DUMB TEST
-                      2 * padding.left + 2 * padding.right + req.width;
-
-//     total_width -= 2*gtk_container_get_border_width(GTK_CONTAINER(gh)) +
-//                    2 * padding.left + 2 * padding.right + req.width;
-
-       if(gh->show_offsets)
-               total_width -= padding.left + padding.right + 9 * gh->char_width;
-#endif
-
-       // TEST - MOVED TO HEX_DRAW
-#if 0
-       // TEST - DUMB HACK
-       total_width = total_width - padding.left - padding.right - 
-               border.left - border.right - 100;
-
-       total_cpl = total_width / gh->char_width;
-
-       /* Sanity check. */
-       if (total_cpl == 0 || total_width < 0) {
-               gh->cpl = gh->lines = gh->vis_lines = 0;
-               g_critical("%s: Something has gone wrong; total cpl is 0 or "
-                               "width is too small.");
-               return;
-       }
-       
-       /* calculate how many bytes we can stuff in one line */
-       gh->cpl = 0;
-       do {
-               if (gh->cpl % gh->group_type == 0 && total_cpl < gh->group_type * 3)
-                       break;
-               
-               gh->cpl++;        /* just added one more char */
-               total_cpl -= 3;   /* 2 for xdisp, 1 for adisp */
-               
-               if (gh->cpl % gh->group_type == 0)      /* just ended a group */
-                       total_cpl--;
-
-       } while (total_cpl > 0);
-
-       /* If gh->cpl is not greater than 0, something has gone wrong. */
-       g_debug("%s: gh->cpl: %d", __func__, gh->cpl);
-       g_return_if_fail (gh->cpl > 0);
-#endif
-
-       // TEST
        if (gh->document->file_size == 0 || gh->cpl == 0)
 //     if (gh->document->file_size == 0)
                gh->lines = 1;
@@ -1369,40 +1280,32 @@ recalc_displays(GtkHex *gh)
                        gh->lines++;
        }
 
-       // TEST - TRYING MOVING TO HEX_DRAW
-#if 0
-       /* set visible lines */
-       gh->vis_lines = height / gh->char_height;
-#endif
-
-       // MOVED TO HEX_DRAW
-#if 0
-       /* display width of ascii drawing area */
-       gh->adisp_width = gh->cpl * gh->char_width;
-#endif
        /* set number of hex characters per line */
+       // FIXME - different than 'xcpl' in hex_draw. confusing.
        xcpl = gh->cpl * 2 + (gh->cpl - 1) / gh->group_type;
 
-#if 0
-       /* display width of hex drawing area */
-       gh->xdisp_width = xcpl * gh->char_width;
-
-       gh->extra_width = total_width - gh->xdisp_width - gh->adisp_width;
-       g_debug("%s: TOTAL_WIDTH: %d - GH->ADISP_WIDTH: %d - GH->XDISP_WIDTH: %d - GH->EXTRA_WIDTH: %d",
-                       __func__,
-                       total_width, gh->adisp_width, gh->xdisp_width, gh->extra_width);
-#endif
-
        if (gh->disp_buffer)
                g_free (gh->disp_buffer);
        
        gh->disp_buffer = g_malloc ((xcpl + 1) * (gh->vis_lines + 1));
+}
+
+static void
+recalc_scrolling (GtkHex *gh)
+{
+       gboolean scroll_to_cursor;
+       gdouble value;
+
+       scroll_to_cursor = (gh->cpl == 0) ||
+               ((gh->cursor_pos / gh->cpl >= gtk_adjustment_get_value (gh->adj)) &&
+                (gh->cursor_pos / gh->cpl <= gtk_adjustment_get_value (gh->adj) +
+                         gh->vis_lines - 1));
 
        /* calculate new display position */
        if (gh->cpl == 0)       // TEST to avoid divide by zero
                value = 0;
        else
-               value = MIN (gh->top_line * old_cpl / gh->cpl, gh->lines - gh->vis_lines);
+               value = MIN (gh->top_line, gh->lines - gh->vis_lines);
 
        /* clamp value */
        value = MAX (0, value);
@@ -1433,7 +1336,7 @@ recalc_displays(GtkHex *gh)
  * connected to value-changed signal of scrollbar's GtkAdjustment
  */
 static void
-display_scrolled(GtkAdjustment *adj, GtkHex *gh)
+display_scrolled (GtkAdjustment *adj, GtkHex *gh)
 {
        gint dx;
        gint dy;
@@ -1443,20 +1346,25 @@ display_scrolled(GtkAdjustment *adj, GtkHex *gh)
        g_return_if_fail (gtk_widget_is_drawable (gh->xdisp) &&
                        gtk_widget_is_drawable (gh->adisp));
 
-       g_debug("%s: ADJ: %f",
+       g_debug("%s: ADJ - VALUE: %f",
                        __func__,
-                       gtk_adjustment_get_page_size (gh->adj));
+                       gtk_adjustment_get_value (gh->adj));
 
-       gh->top_line = gtk_adjustment_get_value(adj);
+       gh->top_line = gtk_adjustment_get_value (adj);
 
        gtk_hex_update_all_auto_highlights(gh, TRUE, TRUE);
        gtk_hex_invalidate_all_highlights(gh);
 
-       // TEST FOR SCROLLING - yes it's needed.. not the best appraoch, but for
-       // now it works.
+       /* FIXME - this works, but feels hackish. The problem is, _snapshot_child
+        * does nothing if it 'detects' that a widget does not need to be redrawn
+        * which is what it seems to think re: our drawing areas on a scroll event.
+        */
        gtk_widget_queue_draw (GTK_WIDGET(gh->adisp));
        gtk_widget_queue_draw (GTK_WIDGET(gh->xdisp));
        gtk_widget_queue_draw (GTK_WIDGET(gh->offsets));
+       gtk_widget_queue_draw (GTK_WIDGET(gh));
+
+       TEST_DEBUG_FUNCTION_END
 }
 
 /*
@@ -1475,7 +1383,6 @@ scroll_timeout_handler(GtkHex *gh)
        return TRUE;
 }
 
-/* REWRITE */
 static gboolean
 scroll_cb (GtkEventControllerScroll *controller,
                double                    dx,
@@ -1483,12 +1390,9 @@ scroll_cb (GtkEventControllerScroll *controller,
                gpointer                  user_data)
 {
        GtkHex *gh = GTK_HEX (user_data);
-//     GtkWidget *widget = GTK_WIDGET (gh->xdisp);
        guint button;
        double old_value, new_value;
 
-       TEST_DEBUG_FUNCTION_START
-
        g_return_val_if_fail (GTK_IS_HEX(gh), FALSE);
 
        old_value = gtk_adjustment_get_value(gh->adj);
@@ -1513,16 +1417,12 @@ hex_pressed_cb (GtkGestureClick *gesture,
        GtkWidget *widget = GTK_WIDGET (gh->xdisp);
        guint button;
 
-       TEST_DEBUG_FUNCTION_START 
        g_return_if_fail (GTK_IS_HEX(gh));
        g_return_if_fail (GTK_IS_WIDGET(widget));
 
        button = gtk_gesture_single_get_current_button
                (GTK_GESTURE_SINGLE(gesture));
 
-       g_debug("%s: n_press: %d, x: %f - y: %f - button: %u",
-                       __func__, n_press, x, y, button);
-
        /* Single-press */
        if (button == GDK_BUTTON_PRIMARY)
        {
@@ -1591,7 +1491,6 @@ hex_released_cb (GtkGestureClick *gesture,
        GtkWidget *widget = GTK_WIDGET (gh->xdisp);
        guint button;
 
-       TEST_DEBUG_FUNCTION_START 
        g_return_if_fail (GTK_IS_HEX(gh));
        g_return_if_fail (GTK_IS_WIDGET(widget));
 
@@ -1612,6 +1511,8 @@ hex_released_cb (GtkGestureClick *gesture,
        }
 }
 
+// FIXME - UNUSED FOR NOW - HERE'S BOILERPLATE IF NEEDED LATER
+#if 0
 static void
 hex_drag_begin_cb (GtkGestureDrag *gesture,
                double          start_x,
@@ -1622,7 +1523,6 @@ hex_drag_begin_cb (GtkGestureDrag *gesture,
        GtkWidget *widget = GTK_WIDGET (gh->xdisp);
        guint button;
 
-       TEST_DEBUG_FUNCTION_START 
        g_return_if_fail (GTK_IS_HEX(gh));
        g_return_if_fail (GTK_IS_WIDGET(widget));
 
@@ -1641,13 +1541,13 @@ hex_drag_end_cb (GtkGestureDrag *gesture,
        GtkWidget *widget = GTK_WIDGET (gh->xdisp);
        guint button;
 
-       TEST_DEBUG_FUNCTION_START 
        g_return_if_fail (GTK_IS_HEX(gh));
        g_return_if_fail (GTK_IS_WIDGET(widget));
 
        g_debug("%s: offset_x: %f - offset_y: %f",
                        __func__, offset_x, offset_y);
 }
+#endif
 
 static void
 hex_drag_update_cb (GtkGestureDrag *gesture,
@@ -1658,35 +1558,19 @@ hex_drag_update_cb (GtkGestureDrag *gesture,
        GtkHex *gh = GTK_HEX (user_data);
        GtkWidget *widget = GTK_WIDGET (gh->xdisp);
        guint button;
-
-       // TEST
        double start_x, start_y;
        double x, y;
-
-       // TEST - FROM OLD CODE:
        GtkAllocation allocation;
 
-       TEST_DEBUG_FUNCTION_START 
        g_return_if_fail (GTK_IS_HEX(gh));
        g_return_if_fail (GTK_IS_WIDGET(widget));
 
-       g_debug("%s: offset_x: %f - offset_y: %f",
-                       __func__, offset_x, offset_y);
-
-       gtk_widget_get_allocation(widget, &allocation);
-
-       g_debug("%s: allocation: x: %d - y: %d - width: %d - height: %d",
-                       __func__,
-                       allocation.x, allocation.y, allocation.width, allocation.height);
-
-       gtk_gesture_drag_get_start_point(gesture, &start_x, &start_y);
+       gtk_widget_get_allocation (widget, &allocation);
+       gtk_gesture_drag_get_start_point (gesture, &start_x, &start_y);
 
        x = start_x + offset_x;
        y = start_y + offset_y;
 
-       g_debug("%s: x: %f - y: %f",
-                       __func__, x, y);
-
        if (y < 0) {
                gh->scroll_dir = -1;
        } else if (y >= allocation.height) {
@@ -1702,8 +1586,6 @@ hex_drag_update_cb (GtkGestureDrag *gesture,
                                                          G_SOURCE_FUNC(scroll_timeout_handler),
                                                          gh);
                }
-               // FIXME - don't really like this - seems like it's setting up for
-               // silent failure. Maybe put a debugging msg once understand better.
                return;
        }
        else {
@@ -1731,16 +1613,12 @@ ascii_pressed_cb (GtkGestureClick *gesture,
        GtkWidget *widget = GTK_WIDGET (gh->adisp);
        guint button;
 
-       TEST_DEBUG_FUNCTION_START 
        g_return_if_fail (GTK_IS_HEX(gh));
        g_return_if_fail (GTK_IS_WIDGET(widget));
 
        button = gtk_gesture_single_get_current_button
                (GTK_GESTURE_SINGLE(gesture));
 
-       g_debug("%s: n_press: %d, x: %f - y: %f",
-                       __func__, n_press, x, y);
-
        /* Single-press */
        if (button == GDK_BUTTON_PRIMARY)
        {
@@ -1767,8 +1645,6 @@ ascii_pressed_cb (GtkGestureClick *gesture,
        /* Right-click */
        else if (button == GDK_BUTTON_SECONDARY)
        {
-               g_debug("%s: RIGHT CLICK - TRYING TO POPUP CONTEXT MENU.", __func__);
-
                popup_context_menu(widget, x, y);
        }
        /* Middle-click press. */
@@ -1809,7 +1685,6 @@ ascii_released_cb (GtkGestureClick *gesture,
        GtkWidget *widget = GTK_WIDGET (gh->adisp);
        guint button;
 
-       TEST_DEBUG_FUNCTION_START 
        g_return_if_fail (GTK_IS_HEX(gh));
        g_return_if_fail (GTK_IS_WIDGET(widget));
 
@@ -1841,35 +1716,19 @@ ascii_drag_update_cb (GtkGestureDrag *gesture,
        GtkHex *gh = GTK_HEX (user_data);
        GtkWidget *widget = GTK_WIDGET (gh->adisp);
        guint button;
-
-       // TEST
        double start_x, start_y;
        double x, y;
-
-       // TEST - FROM OLD CODE:
        GtkAllocation allocation;
 
-       TEST_DEBUG_FUNCTION_START 
        g_return_if_fail (GTK_IS_HEX(gh));
        g_return_if_fail (GTK_IS_WIDGET(widget));
 
-       g_debug("%s: offset_x: %f - offset_y: %f",
-                       __func__, offset_x, offset_y);
-
        gtk_widget_get_allocation(widget, &allocation);
-
-       g_debug("%s: allocation: x: %d - y: %d - width: %d - height: %d",
-                       __func__,
-                       allocation.x, allocation.y, allocation.width, allocation.height);
-
        gtk_gesture_drag_get_start_point(gesture, &start_x, &start_y);
 
        x = start_x + offset_x;
        y = start_y + offset_y;
 
-       g_debug("%s: x: %f - y: %f",
-                       __func__, x, y);
-
        if (y < 0) {
                gh->scroll_dir = -1;
        } else if (y >= allocation.height) {
@@ -1885,8 +1744,6 @@ ascii_drag_update_cb (GtkGestureDrag *gesture,
                                                          G_SOURCE_FUNC(scroll_timeout_handler),
                                                          gh);
                }
-               // FIXME - don't really like this - seems like it's setting up for
-               // silent failure. Maybe put a debugging msg once understand better.
                return;
        }
        else {
@@ -1913,8 +1770,6 @@ key_press_cb (GtkEventControllerKey *controller,
        GtkWidget *widget = GTK_WIDGET(user_data);
        gboolean ret = TRUE;
 
-       TEST_DEBUG_FUNCTION_START
-
        hide_cursor(gh);
 
        /* don't trample over Ctrl */
@@ -1932,7 +1787,7 @@ key_press_cb (GtkEventControllerKey *controller,
        }
 
        switch(keyval) {
-               // TEST - COPY
+               // FIXME TEST - COPY
        case GDK_KEY_F12:
                g_debug("F12 PRESSED - TESTING CLIPBOARD COPY");
                gtk_hex_copy_to_clipboard (gh);
@@ -2096,8 +1951,6 @@ key_release_cb (GtkEventControllerKey *controller,
        GtkWidget *widget = GTK_WIDGET(user_data);
        gboolean ret = TRUE;
 
-       TEST_DEBUG_FUNCTION_START
-
        /* avoid shift key getting 'stuck' */
 
        if (state & GDK_SHIFT_MASK) {
@@ -2111,8 +1964,6 @@ show_offsets_widget(GtkHex *gh)
 {
        g_return_if_fail (GTK_IS_WIDGET (gh->offsets));
 
-       TEST_DEBUG_FUNCTION_START 
-
        gtk_widget_show (gh->offsets);
 }
 
@@ -2121,8 +1972,6 @@ hide_offsets_widget(GtkHex *gh)
 {
        g_return_if_fail (gtk_widget_get_realized (gh->offsets));
 
-       TEST_DEBUG_FUNCTION_START 
-
        gtk_widget_hide (gh->offsets);
 }
 
@@ -2130,7 +1979,8 @@ hide_offsets_widget(GtkHex *gh)
 /*
  * default data_changed signal handler
  */
-static void gtk_hex_real_data_changed(GtkHex *gh, gpointer data) {
+static void gtk_hex_real_data_changed (GtkHex *gh, gpointer data)
+{
        HexChangeData *change_data = (HexChangeData *)data;
        gint start_line, end_line;
        guint lines;
@@ -2180,22 +2030,26 @@ static void gtk_hex_real_data_changed(GtkHex *gh, gpointer data) {
     {
         invalidate_offsets (gh, start_line, end_line);
     }
+
+       TEST_DEBUG_FUNCTION_END
 }
 
 static void
-bytes_changed(GtkHex *gh, int start, int end)
+bytes_changed (GtkHex *gh, int start, int end)
 {
        int start_line;
        int end_line;
 
-       g_return_if_fail(gh->cpl);      /* check for divide-by-zero issues */
+       g_return_if_fail (gh->cpl);     /* check for divide-by-zero issues */
 
-       start_line = start/gh->cpl - gh->top_line;
-       start_line = MAX(start_line, 0);
+       start_line = start / gh->cpl - gh->top_line;
+       start_line = MAX (start_line, 0);
 
-       end_line = end/gh->cpl - gh->top_line;
+       end_line = end / gh->cpl - gh->top_line;
 
-       g_return_if_fail(end_line >=0 && start_line <= gh->vis_lines);
+       /* Nothing needs to be done in some instances */
+       if (end_line < 0 || start_line > gh->vis_lines)
+               return;
 
     invalidate_hex_lines (gh, start_line, end_line);
     invalidate_ascii_lines (gh, start_line, end_line);
@@ -2607,6 +2461,18 @@ static void gtk_hex_real_paste_from_clipboard(GtkHex *gh,
 #endif
 }
 
+static void
+gtk_hex_real_draw_complete (GtkHex *gh,
+               gpointer user_data)
+{
+       TEST_DEBUG_FUNCTION_START
+
+       (void)user_data;
+       recalc_scrolling (gh);
+
+       TEST_DEBUG_FUNCTION_END
+}
+
 static void gtk_hex_finalize(GObject *gobject) {
        GtkHex *gh = GTK_HEX(gobject);
        
@@ -2627,200 +2493,6 @@ static void gtk_hex_finalize(GObject *gobject) {
        G_OBJECT_CLASS(gtk_hex_parent_class)->finalize(gobject);
 }
 
-
-
-// REWRITE FOR GESTURES/EVENT CONTROLLERS
-#if 0
-static gboolean gtk_hex_key_press(GtkWidget *w, GdkEventKey *event) {
-       GtkHex *gh = GTK_HEX(w);
-       gint ret = TRUE;
-
-       hide_cursor(gh);
-
-       if(!(event->state & GDK_SHIFT_MASK)) {
-               gh->selecting = FALSE;
-       }
-       else {
-               gh->selecting = TRUE;
-       }
-       switch(event->keyval) {
-       case GDK_KEY_BackSpace:
-               if(gh->cursor_pos > 0) {
-                       hex_document_set_data(gh->document, gh->cursor_pos - 1,
-                                                                 0, 1, NULL, TRUE);
-                       if (gh->selecting)
-                               gh->selecting = FALSE;
-                       gtk_hex_set_cursor(gh, gh->cursor_pos - 1);
-               }
-               break;
-       case GDK_KEY_Tab:
-       case GDK_KEY_KP_Tab:
-               if (gh->active_view == VIEW_ASCII) {
-                       gh->active_view = VIEW_HEX;
-               }
-               else {
-                       gh->active_view = VIEW_ASCII;
-               }
-               break;
-       case GDK_KEY_Delete:
-               if(gh->cursor_pos < gh->document->file_size) {
-                       hex_document_set_data(gh->document, gh->cursor_pos,
-                                                                 0, 1, NULL, TRUE);
-                       gtk_hex_set_cursor(gh, gh->cursor_pos);
-               }
-               break;
-       case GDK_KEY_Up:
-               gtk_hex_set_cursor(gh, gh->cursor_pos - gh->cpl);
-               break;
-       case GDK_KEY_Down:
-               gtk_hex_set_cursor(gh, gh->cursor_pos + gh->cpl);
-               break;
-       case GDK_KEY_Page_Up:
-               gtk_hex_set_cursor(gh, MAX(0, (gint)gh->cursor_pos - gh->vis_lines*gh->cpl));
-               break;
-       case GDK_KEY_Page_Down:
-               gtk_hex_set_cursor(gh, MIN((gint)gh->document->file_size, (gint)gh->cursor_pos + 
gh->vis_lines*gh->cpl));
-               break;
-       default:
-               if (event->state & GDK_MOD1_MASK) {
-                       show_cursor(gh);
-                       return FALSE;
-               }
-               if(gh->active_view == VIEW_HEX)
-                       switch(event->keyval) {
-                       case GDK_KEY_Left:
-                               if(!(event->state & GDK_SHIFT_MASK)) {
-                                       gh->lower_nibble = !gh->lower_nibble;
-                                       if(gh->lower_nibble)
-                                               gtk_hex_set_cursor(gh, gh->cursor_pos - 1);
-                               }
-                               else {
-                                       gtk_hex_set_cursor(gh, gh->cursor_pos - 1);
-                               }
-                               break;
-                       case GDK_KEY_Right:
-                               if(gh->cursor_pos >= gh->document->file_size)
-                                       break;
-                               if(!(event->state & GDK_SHIFT_MASK)) {
-                                       gh->lower_nibble = !gh->lower_nibble;
-                                       if(!gh->lower_nibble)
-                                               gtk_hex_set_cursor(gh, gh->cursor_pos + 1);
-                               }
-                               else {
-                                       gtk_hex_set_cursor(gh, gh->cursor_pos + 1);
-                               }
-                               break;
-                       default:
-                               if(event->length != 1)
-                                       ret = FALSE;
-                               else if((event->keyval >= '0')&&(event->keyval <= '9')) {
-                                       hex_document_set_nibble(gh->document, event->keyval - '0',
-                                                                                       gh->cursor_pos, 
gh->lower_nibble,
-                                                                                       gh->insert, TRUE);
-                                       if (gh->selecting)
-                                               gh->selecting = FALSE;
-                                       gh->lower_nibble = !gh->lower_nibble;
-                                       if(!gh->lower_nibble)
-                                               gtk_hex_set_cursor(gh, gh->cursor_pos + 1);
-                               }
-                               else if((event->keyval >= 'A')&&(event->keyval <= 'F')) {
-                                       hex_document_set_nibble(gh->document, event->keyval - 'A' + 10,
-                                                                                       gh->cursor_pos, 
gh->lower_nibble,
-                                                                                       gh->insert, TRUE);
-                                       if (gh->selecting)
-                                               gh->selecting = FALSE;
-                                       gh->lower_nibble = !gh->lower_nibble;
-                                       if(!gh->lower_nibble)
-                                               gtk_hex_set_cursor(gh, gh->cursor_pos + 1);
-                               }
-                               else if((event->keyval >= 'a')&&(event->keyval <= 'f')) {
-                                       hex_document_set_nibble(gh->document, event->keyval - 'a' + 10,
-                                                                                       gh->cursor_pos, 
gh->lower_nibble,
-                                                                                       gh->insert, TRUE);
-                                       if (gh->selecting)
-                                               gh->selecting = FALSE;
-                                       gh->lower_nibble = !gh->lower_nibble;
-                                       if(!gh->lower_nibble)
-                                               gtk_hex_set_cursor(gh, gh->cursor_pos + 1);
-                               }
-                               else if((event->keyval >= GDK_KEY_KP_0)&&(event->keyval <= GDK_KEY_KP_9)) {
-                                       hex_document_set_nibble(gh->document, event->keyval - GDK_KEY_KP_0,
-                                                                                       gh->cursor_pos, 
gh->lower_nibble,
-                                                                                       gh->insert, TRUE);
-                                       if (gh->selecting)
-                                               gh->selecting = FALSE;
-                                       gh->lower_nibble = !gh->lower_nibble;
-                                       if(!gh->lower_nibble)
-                                               gtk_hex_set_cursor(gh, gh->cursor_pos + 1);
-                               }
-                               else
-                                       ret = FALSE;
-
-                               break;      
-                       }
-               else if(gh->active_view == VIEW_ASCII)
-                       switch(event->keyval) {
-                       case GDK_KEY_Left:
-                               gtk_hex_set_cursor(gh, gh->cursor_pos - 1);
-                               break;
-                       case GDK_KEY_Right:
-                               gtk_hex_set_cursor(gh, gh->cursor_pos + 1);
-                               break;
-                       default:
-                               if(event->length != 1)
-                                       ret = FALSE;
-                               else if(is_displayable(event->keyval)) {
-                                       hex_document_set_byte(gh->document, event->keyval,
-                                                                                 gh->cursor_pos, gh->insert, 
TRUE);
-                                       if (gh->selecting)
-                                               gh->selecting = FALSE;
-                                       gtk_hex_set_cursor(gh, gh->cursor_pos + 1);
-                               }
-                               else if((event->keyval >= GDK_KEY_KP_0)&&(event->keyval <= GDK_KEY_KP_9)) {
-                                       hex_document_set_byte(gh->document, event->keyval - GDK_KEY_KP_0 + 
'0',
-                                                                                       gh->cursor_pos, 
gh->insert, TRUE);
-                                       if (gh->selecting)
-                                               gh->selecting = FALSE;
-                                       gtk_hex_set_cursor(gh, gh->cursor_pos + 1);
-                               }
-                               else
-                                       ret = FALSE;
-
-                               break;
-                       }
-               break;
-       }
-
-       show_cursor(gh);
-       
-       return ret;
-}
-#endif
-
-// SWITCH TO GESTURES/EVENT CONTROLLERS
-#if 0
-static gboolean gtk_hex_key_release(GtkWidget *w, GdkEventKey *event) {
-       GtkHex *gh = GTK_HEX(w);
-
-       if (event->keyval == GDK_KEY_Shift_L || event->keyval == GDK_KEY_Shift_R) {
-               gh->selecting = FALSE;
-       }
-
-       return TRUE;
-}
-
-static gboolean gtk_hex_button_release(GtkWidget *w, GdkEventButton *event) {
-       GtkHex *gh = GTK_HEX(w);
-
-       if(event->state & GDK_SHIFT_MASK) {
-               gh->selecting = FALSE;
-       }
-
-       return TRUE;
-}
-#endif
-
-
 static void
 gtk_hex_snapshot (GtkWidget *widget, GtkSnapshot *snapshot)
 {
@@ -2830,7 +2502,7 @@ gtk_hex_snapshot (GtkWidget *widget, GtkSnapshot *snapshot)
        cairo_t *cr;
        GtkWidget *child;
 
-       TEST_DEBUG_FUNCTION_START 
+       TEST_DEBUG_FUNCTION_START
 
        /* Update character width & height */
        gh->char_width = get_char_width(gh);
@@ -2854,27 +2526,18 @@ gtk_hex_snapshot (GtkWidget *widget, GtkSnapshot *snapshot)
 
        cr = gtk_snapshot_append_cairo (snapshot, &rect);
 
-       g_debug("%s: width: %f - height: %f",
-                       __func__, width, height);
-
-       // TEST for trying render_xc
-       show_cursor(gh);
-
-       /* queue draw functions for drawing areas - order matters here as
-        * we're pegging certain elements of the ascii widget being drawn
-        * to after the hex widget is drawn.
+       /* queue child draw functions
         */
-       gtk_widget_snapshot_child (widget, gh->xdisp, snapshot);
-       gtk_widget_snapshot_child (widget, gh->adisp, snapshot);
-
-       /* queue draw functions for other children */
        for (child = gtk_widget_get_first_child (widget);
-                                                       /* don't draw these as we already did above. */
-                       child != NULL && child != gh->xdisp && child != gh->adisp;
+                       child != NULL;
                        child = gtk_widget_get_next_sibling (child))
        {
                gtk_widget_snapshot_child (widget, child, snapshot);
        }
+
+       g_signal_emit_by_name(G_OBJECT(gh), "draw-complete");
+
+       TEST_DEBUG_FUNCTION_END
 }
 
 static void
@@ -2884,8 +2547,6 @@ gtk_hex_document_changed (HexDocument* doc, gpointer change_data,
        GtkHex *gh = GTK_HEX(data);
        g_return_if_fail (GTK_IS_HEX (gh));
 
-       TEST_DEBUG_FUNCTION_START
-
     gtk_hex_real_data_changed (gh, change_data);
 
        gtk_widget_action_set_enabled (GTK_WIDGET(gh),
@@ -2902,7 +2563,7 @@ gtk_hex_class_init (GtkHexClass *klass)
 
        /* Layout manager: box-style layout. */
        gtk_widget_class_set_layout_manager_type (widget_class,
-                       GTK_TYPE_BOX_LAYOUT);
+                       GTK_TYPE_HEX_LAYOUT);
 
        /* CSS name */
 
@@ -2966,6 +2627,16 @@ gtk_hex_class_init (GtkHexClass *klass)
                                G_TYPE_NONE,
                                0);
        
+       gtkhex_signals[DRAW_COMPLETE_SIGNAL] = 
+               g_signal_new_class_handler ("draw-complete",
+                               G_OBJECT_CLASS_TYPE(object_class),
+                               G_SIGNAL_RUN_FIRST,
+                               G_CALLBACK(gtk_hex_real_draw_complete),
+                               NULL, NULL,
+                               NULL,
+                               G_TYPE_NONE,
+                               0);
+
        /* ACTIONS */
 
        gtk_widget_class_install_action (widget_class, "gtkhex.copy",
@@ -3004,30 +2675,7 @@ gtk_hex_class_init (GtkHexClass *klass)
                        "gtkhex.redo",
                        NULL);  // no args.
 
-       // API CHANGES
-//     klass->primary = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
-//     klass->clipboard = gtk_clipboard_get(GDK_NONE);
-
-       // LAR - NOTE - GTK4, THIS IS ONLY CALLED IF THE WIDGET DOES *NOT* HAVE
-       // A LAYOUT MANAGER
-       //
-       // POSSIBLE TODO - subclass a GtkLayoutManager and set the `allocate'
-       // vfunc.
-//     GTK_WIDGET_CLASS(klass)->size_allocate = gtk_hex_size_allocate;
-
-       
-       // GONESVILLE WITH GTK4
-//     GTK_WIDGET_CLASS(klass)->get_preferred_width = gtk_hex_get_preferred_width;
-//     GTK_WIDGET_CLASS(klass)->get_preferred_height = gtk_hex_get_preferred_height;
-       // LAR - no can do, gtk4 - just seems to draw a border??
-//     LAR - TEST FOR GTK4
        widget_class->snapshot = gtk_hex_snapshot;
-
-//     GTK4 API CHANGES - SWITCH TO GESTURES / EVENT CONTROLLERS
-//     GTK_WIDGET_CLASS(klass)->key_press_event = gtk_hex_key_press;
-//     GTK_WIDGET_CLASS(klass)->key_release_event = gtk_hex_key_release;
-//     GTK_WIDGET_CLASS(klass)->button_release_event = gtk_hex_button_release;
-
        object_class->finalize = gtk_hex_finalize;
 }
 
@@ -3036,12 +2684,16 @@ gtk_hex_init(GtkHex *gh)
 {
        GtkWidget *widget = GTK_WIDGET(gh);
 
+       GtkHexLayoutChild *child_info;
+
        GtkCssProvider *provider;
        GtkStyleContext *context;
 
        GtkGesture *gesture;
        GtkEventController *controller;
 
+       gh->layout_manager = gtk_widget_get_layout_manager (widget);
+
        gh->disp_buffer = NULL;
        gh->default_cpl = DEFAULT_CPL;
        gh->default_lines = DEFAULT_LINES;
@@ -3074,8 +2726,8 @@ gtk_hex_init(GtkHex *gh)
        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);
+//     gtk_widget_set_vexpand (widget, TRUE);
+//     gtk_widget_set_hexpand (widget, TRUE);
 
 
        /* Init CSS */
@@ -3110,8 +2762,12 @@ gtk_hex_init(GtkHex *gh)
 
        gh->offsets = gtk_drawing_area_new();
        gtk_widget_set_parent (gh->offsets, widget);
-       gtk_widget_set_halign (gh->offsets, GTK_ALIGN_START);
-       gtk_widget_set_hexpand (gh->offsets, FALSE);
+       child_info = GTK_HEX_LAYOUT_CHILD (gtk_layout_manager_get_layout_child
+                       (gh->layout_manager, gh->offsets));
+       gtk_hex_layout_child_set_column (child_info, OFFSETS_COLUMN);
+
+//     gtk_widget_set_halign (gh->offsets, GTK_ALIGN_START);
+//     gtk_widget_set_hexpand (gh->offsets, FALSE);
 
        /* Create the pango layout for the widget */
        gh->olayout = gtk_widget_create_pango_layout (gh->offsets, "");
@@ -3127,50 +2783,27 @@ gtk_hex_init(GtkHex *gh)
        context = gtk_widget_get_style_context (GTK_WIDGET (gh->offsets));
        gtk_style_context_add_class (context, "header");
 
-
        /* hide it by default. */
        gtk_widget_hide (gh->offsets);
 
 
-
-
        /* Setup our Hex drawing area. */
 
        gh->xdisp = gtk_drawing_area_new();
        gtk_widget_set_parent (gh->xdisp, widget);
-       gtk_widget_set_hexpand (gh->xdisp, TRUE);
+       child_info = GTK_HEX_LAYOUT_CHILD (gtk_layout_manager_get_layout_child
+                       (gh->layout_manager, gh->xdisp));
+       gtk_hex_layout_child_set_column (child_info, HEX_COLUMN);
 
        /* Create the pango layout for the widget */
        gh->xlayout = gtk_widget_create_pango_layout (gh->xdisp, "");
 
-       // TEST / MONITOR - not sure if needed for keyboard events. - NOT
-       // needed for mouse events.
-//     gtk_widget_set_can_focus (gh->xdisp, TRUE);
-
        gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (gh->xdisp),
                        hex_draw,       // GtkDrawingAreaDrawFunc draw_func,
                        gh,                     // gpointer user_data,
                        NULL);          // GDestroyNotify destroy);
 
 
-
-       // REWRITE - LAR
-#if 0
-
-       gtk_widget_set_events (gh->xdisp, GDK_EXPOSURE_MASK |
-                       GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
-                       GDK_BUTTON_MOTION_MASK | GDK_SCROLL_MASK);
-
-       g_signal_connect(G_OBJECT(gh->xdisp), "button_press_event",
-                                        G_CALLBACK(hex_button_cb), gh);
-       g_signal_connect(G_OBJECT(gh->xdisp), "button_release_event",
-                                        G_CALLBACK(hex_button_cb), gh);
-       g_signal_connect(G_OBJECT(gh->xdisp), "motion_notify_event",
-                                        G_CALLBACK(hex_motion_cb), gh);
-       g_signal_connect(G_OBJECT(gh->xdisp), "scroll_event",
-                                        G_CALLBACK(hex_scroll_cb), gh);
-#endif
-
        /* Set context var to hex widget's context... */
        context = gtk_widget_get_style_context (GTK_WIDGET (gh->xdisp));
        /* ... and add view class so we get certain theme colours for free. */
@@ -3182,16 +2815,15 @@ gtk_hex_init(GtkHex *gh)
 
        gh->adisp = gtk_drawing_area_new();
        gtk_widget_set_parent (gh->adisp, widget);
-       gtk_widget_set_halign (gh->adisp, GTK_ALIGN_START);
-       gtk_widget_set_hexpand (gh->adisp, FALSE);
+       child_info = GTK_HEX_LAYOUT_CHILD (gtk_layout_manager_get_layout_child
+                       (gh->layout_manager, gh->adisp));
+       gtk_hex_layout_child_set_column (child_info, ASCII_COLUMN);
+
        gtk_widget_set_name (gh->adisp, "asciidisplay");
        
        /* Create the pango layout for the widget */
        gh->alayout = gtk_widget_create_pango_layout (gh->adisp, "");
 
-       // LAR - TEST  - dont' know if needed - NOT needed for mouse clicks.
-//     gtk_widget_set_can_focus (gh->adisp, TRUE);
-
        gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (gh->adisp),
                        ascii_draw,     /* GtkDrawingAreaDrawFunc draw_func, */
                        gh,                     /* gpointer user_data, */
@@ -3204,22 +2836,6 @@ gtk_hex_init(GtkHex *gh)
                                        GTK_STYLE_PROVIDER (provider),
                                        GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
 
-       // LAR - REWRITE
-#if 0
-       gtk_widget_set_events (gh->adisp, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK
-                       | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_MOTION_MASK |
-                       GDK_SCROLL_MASK);
-
-       g_signal_connect(G_OBJECT(gh->adisp), "button_press_event",
-                                        G_CALLBACK(ascii_button_cb), gh);
-       g_signal_connect(G_OBJECT(gh->adisp), "button_release_event",
-                                        G_CALLBACK(ascii_button_cb), gh);
-       g_signal_connect(G_OBJECT(gh->adisp), "motion_notify_event",
-                                        G_CALLBACK(ascii_motion_cb), gh);
-       g_signal_connect(G_OBJECT(gh->adisp), "scroll_event",
-                                        G_CALLBACK(ascii_scroll_cb), gh);
-#endif
-
        /* Set a minimum size for hex/ascii drawing areas. */
 
        gtk_widget_set_size_request (gh->adisp,
@@ -3227,7 +2843,6 @@ gtk_hex_init(GtkHex *gh)
        gtk_widget_set_size_request (gh->xdisp,
                        DEFAULT_DA_SIZE, DEFAULT_DA_SIZE);
 
-
        /* Initialize Adjustment */
 
        gh->adj = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
@@ -3235,7 +2850,11 @@ gtk_hex_init(GtkHex *gh)
        /* Setup scrollbar. */
        gh->scrollbar = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL,
                        gh->adj);
+
        gtk_widget_set_parent (gh->scrollbar, widget);
+       child_info = GTK_HEX_LAYOUT_CHILD (gtk_layout_manager_get_layout_child
+                       (gh->layout_manager, gh->scrollbar));
+       gtk_hex_layout_child_set_column (child_info, SCROLLBAR_COLUMN);
 
        /* Connect gestures to ascii/hex drawing areas.
         */
@@ -3260,12 +2879,15 @@ gtk_hex_init(GtkHex *gh)
        /* drag gestures */
        gesture = gtk_gesture_drag_new ();
 
+       // TODO - IF NEEDED
+#if 0
        g_signal_connect (gesture, "drag-begin",
                        G_CALLBACK(hex_drag_begin_cb),
                        gh);
        g_signal_connect (gesture, "drag-end",
                        G_CALLBACK(hex_drag_end_cb),
                        gh);
+#endif
        g_signal_connect (gesture, "drag-update",
                        G_CALLBACK (hex_drag_update_cb),
                        gh);
@@ -3346,7 +2968,6 @@ gtk_hex_init(GtkHex *gh)
                        "gtkhex.undo", FALSE);
        gtk_widget_action_set_enabled (GTK_WIDGET(gh),
                        "gtkhex.redo", FALSE);
-
 }
 
 GtkWidget *gtk_hex_new(HexDocument *owner) {
@@ -3551,8 +3172,6 @@ void gtk_hex_set_group_type(GtkHex *gh, guint gt) {
  */
 void gtk_hex_show_offsets(GtkHex *gh, gboolean show)
 {
-       TEST_DEBUG_FUNCTION_START
-
        g_return_if_fail(gh != NULL);
        g_return_if_fail(GTK_IS_HEX(gh));
 
diff --git a/src/meson.build b/src/meson.build
index 45950341..9861eab3 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -1,6 +1,7 @@
 libghex_sources = [
   'gtkhex.c',
-  'hex-document.c'
+  'hex-document.c',
+  'gtkhex-layout-manager.c'
 ]
 
 libghex_headers = [
@@ -60,6 +61,8 @@ ghex_sources = [
   'ghex-application-window.h',
   'gtkhex.c',
   'gtkhex.h',
+  'gtkhex-layout-manager.c',
+  'gtkhex-layout-manager.h',
   'hex-dialog.c',
   'hex-dialog.h',
   'hex-document.c',


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