[ghex/gtk4-port: 47/91] Implement: Dark mode, undo, redo
- From: Logan Rathbone <larathbone src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [ghex/gtk4-port: 47/91] Implement: Dark mode, undo, redo
- Date: Thu, 12 Aug 2021 23:35:10 +0000 (UTC)
commit 704a6bd3aab2079d302698a86828afdee30769a1
Author: Logan Rathbone <poprocks gmail com>
Date: Fri Jan 22 00:08:56 2021 -0500
Implement: Dark mode, undo, redo
data/org.gnome.GHex.gschema.xml.in | 10 +++-
src/Makefile | 2 +-
src/common-ui.c | 100 +++++++++++++++++++-------------
src/common-ui.h | 6 +-
src/configuration.c | 27 +++++++++
src/configuration.h | 29 +++++++---
src/ghex-application-window.c | 81 +++++++++++++++++++++++---
src/gtkhex.c | 113 +++++++++++++++++++++++++++++++++++--
src/hex-document.c | 25 ++++++++
src/hex-document.h | 34 +++++------
src/preferences.c | 82 ++++++++++++++++++++++++++-
src/preferences.ui | 27 +++++++++
src/print.c | 70 ++++++++++++-----------
src/print.h | 43 +++++++-------
14 files changed, 513 insertions(+), 136 deletions(-)
---
diff --git a/data/org.gnome.GHex.gschema.xml.in b/data/org.gnome.GHex.gschema.xml.in
index 32f8a54d..79dc2b87 100644
--- a/data/org.gnome.GHex.gschema.xml.in
+++ b/data/org.gnome.GHex.gschema.xml.in
@@ -10,6 +10,11 @@
<value nick="words" value="2"/>
<value nick="longwords" value="4"/>
</enum>
+ <enum id="org.gnome.GHex.DarkMode">
+ <value nick="off" value="0"/>
+ <value nick="on" value="1"/>
+ <value nick="system" value="2"/>
+ </enum>
<schema id="org.gnome.GHex" path="/org/gnome/ghex/">
<key name="font" type="s">
@@ -25,12 +30,15 @@
<default>'Sans 12'</default>
</key>
<key name="print-shaded-rows" type="u">
- <range min="0" max=@XML_SHADED_BOX_MAX@>
+ <range min="0" max=@XML_SHADED_BOX_MAX@/>
<default>0</default>
</key>
<key name="show-offsets" type="b">
<default>false</default>
</key>
+ <key name="dark-mode" enum="org.gnome.GHex.DarkMode">
+ <default>'system'</default>
+ </key>
</schema>
</schemalist>
diff --git a/src/Makefile b/src/Makefile
index b383dc7c..9a1a6bed 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -12,7 +12,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 configuration.o preferences.o common-ui.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 common-ui.o print.o
compile-resources:
glib-compile-resources ghex.gresource.xml --target=resources.c --generate-source
diff --git a/src/common-ui.c b/src/common-ui.c
index 3ce691d4..40ccaa41 100644
--- a/src/common-ui.c
+++ b/src/common-ui.c
@@ -33,6 +33,7 @@
#if 0
static void ghex_print(GtkHex *gh, gboolean preview);
+
guint group_type[3] = {
GROUP_BYTE,
GROUP_WORD,
@@ -252,7 +253,7 @@ common_about_cb (GtkWindow *parent)
/* Translators: these two strings here indicate the copyright time span,
e.g. 1998-2018. */
- copyright = g_strdup_printf (_("Copyright © %Id–%Id The GHex authors"),
+ copyright = g_strdup_printf (_("Copyright © %d–%d The GHex authors"),
1998, 2021);
gtk_show_about_dialog (parent,
@@ -821,6 +822,7 @@ revert_cb (GtkAction *action,
gtk_widget_destroy (mbox);
}
}
+#endif
/**
* ghex_print
@@ -829,75 +831,93 @@ to display the print dialog.
*
* Prints or previews the current document.
**/
-static void
-ghex_print(GtkHex *gh, gboolean preview)
+void
+common_print (GtkWindow *parent, GtkHex *gh, gboolean preview)
{
- GHexPrintJobInfo *pji;
+ GHexPrintJobInfo *job;
HexDocument *doc;
GtkPrintOperationResult result;
GError *error = NULL;
- gchar *basename;
- gchar *gtk_file_name;
+ char *basename;
+ char *gtk_file_name;
- doc = gh->document;
+ g_return_if_fail (GTK_IS_HEX (gh));
+
+ doc = gtk_hex_get_document (gh);
+ g_return_if_fail (HEX_IS_DOCUMENT (doc));
gtk_file_name = g_filename_to_utf8 (doc->file_name, -1, NULL, NULL, NULL);
basename = g_filename_display_basename (gtk_file_name);
- pji = ghex_print_job_info_new(doc, gh->group_type);
- pji->master = gtk_print_operation_new ();
- pji->config = gtk_print_settings_new ();
- gtk_print_settings_set (pji->config, GTK_PRINT_SETTINGS_OUTPUT_BASENAME, basename);
- gtk_print_settings_set_paper_size (pji->config, gtk_paper_size_new (GTK_PAPER_NAME_A4));
- gtk_print_operation_set_unit (pji->master, GTK_UNIT_POINTS);
- gtk_print_operation_set_print_settings (pji->master, pji->config);
- gtk_print_operation_set_embed_page_setup (pji->master, TRUE);
- gtk_print_operation_set_show_progress (pji->master, TRUE);
- g_signal_connect (pji->master, "draw-page",
- G_CALLBACK (print_page), pji);
- g_signal_connect (pji->master, "begin-print",
- G_CALLBACK (begin_print), pji);
-
- if (!pji)
+ job = ghex_print_job_info_new (doc, gtk_hex_get_group_type (gh));
+ job->master = gtk_print_operation_new ();
+ job->config = gtk_print_settings_new ();
+ gtk_print_settings_set (job->config, GTK_PRINT_SETTINGS_OUTPUT_BASENAME,
+ basename);
+ gtk_print_settings_set_paper_size (job->config,
+ gtk_paper_size_new (NULL)); /* system default */
+ gtk_print_operation_set_unit (job->master, GTK_UNIT_POINTS);
+ gtk_print_operation_set_print_settings (job->master, job->config);
+ gtk_print_operation_set_embed_page_setup (job->master, TRUE);
+ gtk_print_operation_set_show_progress (job->master, TRUE);
+ g_signal_connect (job->master, "draw-page",
+ G_CALLBACK (print_page), job);
+ g_signal_connect (job->master, "begin-print",
+ G_CALLBACK (begin_print), job);
+
+ if (!job)
return;
- pji->preview = preview;
+ job->preview = preview;
- if (!pji->preview)
- result = gtk_print_operation_run (pji->master, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG, NULL,
&error);
- else
- result = gtk_print_operation_run (pji->master, GTK_PRINT_OPERATION_ACTION_PREVIEW, NULL,
&error);
+ result = gtk_print_operation_run (job->master,
+ (job->preview ? GTK_PRINT_OPERATION_ACTION_PREVIEW :
+ GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG),
+ parent,
+ &error);
if (result == GTK_PRINT_OPERATION_RESULT_ERROR) {
- g_print ("%s\n", error->message);
+ char *tmp;
+
+ /* Translators: This is an error string for a print-related error
+ * dialog. The %s is the error generated by GError. */
+ tmp = g_strdup_printf (_("An error has occurred: %s"),
+ error->message);
+
+ display_error_dialog (parent, tmp);
+
+ g_free (tmp);
g_error_free (error);
}
- ghex_print_job_info_destroy (pji);
+ ghex_print_job_info_destroy (job);
g_free (basename);
g_free (gtk_file_name);
}
void
-display_error_dialog (GHexWindow *win, const gchar *msg)
+display_error_dialog (GtkWindow *parent, const char *msg)
{
GtkWidget *error_dlg;
- g_return_if_fail (win != NULL);
- g_return_if_fail (msg != NULL);
- error_dlg = gtk_message_dialog_new (
- GTK_WINDOW (win),
+ g_return_if_fail (GTK_IS_WINDOW(parent));
+ g_return_if_fail (msg);
+
+ error_dlg = gtk_message_dialog_new (parent,
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR,
- GTK_BUTTONS_OK,
- "%s",
- msg);
+ GTK_BUTTONS_CLOSE,
+ "%s", msg);
- gtk_dialog_set_default_response (GTK_DIALOG (error_dlg), GTK_RESPONSE_OK);
+ gtk_dialog_set_default_response (GTK_DIALOG (error_dlg),
+ GTK_RESPONSE_CLOSE);
gtk_window_set_resizable (GTK_WINDOW (error_dlg), FALSE);
- gtk_dialog_run (GTK_DIALOG (error_dlg));
- gtk_widget_destroy (error_dlg);
+ gtk_widget_show (error_dlg);
+
+ g_signal_connect (error_dlg, "response",
+ G_CALLBACK (gtk_window_destroy), NULL);
}
+#if 0
void
display_info_dialog (GHexWindow *win, const gchar *msg, ...)
{
diff --git a/src/common-ui.h b/src/common-ui.h
index d90c6c5c..40ae4728 100644
--- a/src/common-ui.h
+++ b/src/common-ui.h
@@ -3,7 +3,7 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* common-ui.h - Common UI utility functions
- Copyright (C) 2004 Free Software Foundation
+ Copyright © 2004 Free Software Foundation
Copyright © 2021 Logan Rathbone
GHex is free software; you can redistribute it and/or
@@ -29,8 +29,10 @@
#include <gtk/gtk.h>
#include <glib/gi18n.h>
+#include <gtkhex.h>
#include "configuration.h"
+#include "print.h"
G_BEGIN_DECLS
@@ -38,6 +40,8 @@ G_BEGIN_DECLS
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);
G_END_DECLS
diff --git a/src/configuration.c b/src/configuration.c
index c747695b..91b4d931 100644
--- a/src/configuration.c
+++ b/src/configuration.c
@@ -37,6 +37,10 @@ char *header_font_name;
char *data_font_name;
guint shaded_box_size;
gboolean show_offsets_column;
+int def_dark_mode;
+/* Will default to false here. We can't set it until we get a 'screen', so
+ * we'll save calling get_sys_default_is_dark() until GHex launches. */
+gboolean sys_default_is_dark;
static void
offsets_column_changed_cb (GSettings *settings,
@@ -56,6 +60,25 @@ group_changed_cb (GSettings *settings,
def_group_type = g_settings_get_enum (settings, key);
}
+static void
+dark_mode_changed_cb (GSettings *settings,
+ const gchar *key,
+ gpointer user_data)
+{
+ def_dark_mode = g_settings_get_enum (settings, key);
+}
+
+void
+get_sys_default_is_dark (void)
+{
+ GtkSettings *gtk_settings;
+
+ gtk_settings = gtk_settings_get_default ();
+ g_object_get (gtk_settings,
+ "gtk-application-prefer-dark-theme", &sys_default_is_dark,
+ NULL);
+}
+
static void
box_size_changed_cb (GSettings *settings,
const gchar *key,
@@ -113,6 +136,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_DARK_MODE,
+ G_CALLBACK (dark_mode_changed_cb), NULL);
+ dark_mode_changed_cb (settings, GHEX_PREF_DARK_MODE, 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);
diff --git a/src/configuration.h b/src/configuration.h
index 46847001..fba191f2 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -4,6 +4,7 @@
/* configuration.h - constants and declarations for GSettings
Copyright (C) 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
@@ -20,7 +21,7 @@
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_CONFIGURATION_H
@@ -31,12 +32,19 @@
G_BEGIN_DECLS
/* GSettings keys */
-#define GHEX_PREF_FONT "font"
-#define GHEX_PREF_GROUP "group-data-by"
-#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"
+#define GHEX_PREF_FONT "font"
+#define GHEX_PREF_GROUP "group-data-by"
+#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"
+#define GHEX_PREF_DARK_MODE "dark-mode"
+
+enum dark_mode {
+ DARK_MODE_OFF,
+ DARK_MODE_ON,
+ DARK_MODE_SYSTEM
+};
/* Our preferred settings; as only one copy of them is required,
* we'll make them global vars, though this is a bit ugly.
@@ -45,15 +53,20 @@ extern char *def_font_name;
extern char *data_font_name, *header_font_name;
extern char *offset_fmt;
extern gboolean show_offsets_column;
-
extern guint shaded_box_size;
extern int def_group_type;
+extern int def_dark_mode;
+extern gboolean sys_default_is_dark;
extern GSettings *settings;
/* Initializes the gsettings client */
void ghex_init_configuration (void);
+/* Cache the system default of prefer-dark-theme as gtk does not do this for
+ * us. */
+void get_sys_default_is_dark (void);
+
G_END_DECLS
#endif /* GHEX_CONFIGURATION_H */
diff --git a/src/ghex-application-window.c b/src/ghex-application-window.c
index 59fd98f8..bab0bbee 100644
--- a/src/ghex-application-window.c
+++ b/src/ghex-application-window.c
@@ -113,6 +113,9 @@ static GParamSpec *properties[N_PROPERTIES] = { NULL, };
*/
static const char *main_actions[] = {
"ghex.save-as",
+ "ghex.print",
+ "ghex.print-preview",
+ "win.group-data-by",
"ghex.show-conversions",
"ghex.insert-mode",
"ghex.find",
@@ -299,7 +302,7 @@ set_css_provider_font_from_settings (GHexApplicationWindow *self)
g_debug("%s: css_str: %s", __func__, css_str);
- gtk_css_provider_load_from_data (GTK_STYLE_PROVIDER(self->provider),
+ gtk_css_provider_load_from_data (self->provider,
css_str, -1);
}
@@ -330,6 +333,28 @@ set_gtkhex_group_type_from_settings (GtkHex *gh)
gtk_hex_set_group_type (gh, def_group_type);
}
+static void
+set_dark_mode_from_settings (GHexApplicationWindow *self)
+{
+ GtkSettings *gtk_settings;
+
+ gtk_settings = gtk_settings_get_default ();
+
+ g_debug ("%s: def_dark_mode: %d", __func__, def_dark_mode);
+
+ if (def_dark_mode == DARK_MODE_SYSTEM) {
+ g_object_set (G_OBJECT(gtk_settings),
+ "gtk-application-prefer-dark-theme",
+ sys_default_is_dark,
+ NULL);
+ } else {
+ g_object_set (G_OBJECT(gtk_settings),
+ "gtk-application-prefer-dark-theme",
+ def_dark_mode == DARK_MODE_ON ? TRUE : FALSE,
+ NULL);
+ }
+}
+
/* Common macro for the `settings*changed_cb` stuff.
* Between _START and _END, put in function calls that use `gh` to be applied
@@ -709,6 +734,12 @@ ghex_application_window_document_changed_cb (HexDocument *doc,
g_return_if_fail (GHEX_IS_APPLICATION_WINDOW (self));
+ /* The appwindow as a whole not interested in any document changes that
+ * don't pertain to the one that is actually in view.
+ */
+ if (doc != gtk_hex_get_document (self->gh))
+ return;
+
ghex_application_window_set_can_save (self,
hex_document_has_changed (doc));
}
@@ -1099,6 +1130,32 @@ save_as (GtkWidget *widget,
g_clear_object (&existing_file);
}
+static void
+print_preview (GtkWidget *widget,
+ const char *action_name,
+ GVariant *parameter)
+{
+ GHexApplicationWindow *self = GHEX_APPLICATION_WINDOW(widget);
+
+ g_return_if_fail (GTK_IS_HEX(self->gh));
+ (void)widget, (void)action_name, (void)parameter; /* unused */
+
+ common_print (GTK_WINDOW(self), self->gh, /* preview: */ TRUE);
+}
+
+static void
+do_print (GtkWidget *widget,
+ const char *action_name,
+ GVariant *parameter)
+{
+ GHexApplicationWindow *self = GHEX_APPLICATION_WINDOW(widget);
+
+ g_return_if_fail (GTK_IS_HEX(self->gh));
+ (void)widget, (void)action_name, (void)parameter; /* unused */
+
+ common_print (GTK_WINDOW(self), self->gh, /* preview: */ FALSE);
+}
+
/* convenience helper function to build a GtkHex widget pre-loaded with
* a hex document, from a GFile *.
*/
@@ -1637,6 +1694,12 @@ ghex_application_window_init (GHexApplicationWindow *self)
gtk_widget_init_template (widget);
+ /* Cache system default of prefer-dark-mode; gtk does not do this. This
+ * is run here as it cannot be done until we have a 'screen'. */
+ get_sys_default_is_dark ();
+ /* Do dark mode if requested */
+ set_dark_mode_from_settings (self);
+
/* Setup conversions box and pane */
self->dialog = hex_dialog_new ();
self->dialog_widget = hex_dialog_getview (self->dialog);
@@ -1679,6 +1742,8 @@ ghex_application_window_init (GHexApplicationWindow *self)
g_signal_connect (settings, "changed::" GHEX_PREF_GROUP,
G_CALLBACK (settings_group_type_changed_cb), self);
+ g_signal_connect_swapped (settings, "changed::" GHEX_PREF_DARK_MODE,
+ G_CALLBACK (set_dark_mode_from_settings), self);
/* Actions - SETTINGS */
@@ -1850,6 +1915,14 @@ ghex_application_window_class_init(GHexApplicationWindowClass *klass)
NULL, // GVariant string param_type
save_as);
+ gtk_widget_class_install_action (widget_class, "ghex.print",
+ NULL, // GVariant string param_type
+ do_print);
+
+ gtk_widget_class_install_action (widget_class, "ghex.print-preview",
+ NULL, // GVariant string param_type
+ print_preview);
+
gtk_widget_class_install_action (widget_class, "ghex.show-conversions",
NULL, // GVariant string param_type
toggle_conversions);
@@ -1883,12 +1956,6 @@ ghex_application_window_class_init(GHexApplicationWindowClass *klass)
"ghex.converter", "converter-open");
-
-// gtk_widget_class_install_action (widget_class, "win.group-data-by",
-// "i", // GVariant string param_type
-// NULL);
-
-
/* WIDGET TEMPLATE .UI */
gtk_widget_class_set_template_from_resource (widget_class,
diff --git a/src/gtkhex.c b/src/gtkhex.c
index ad42bc4e..42255a2e 100644
--- a/src/gtkhex.c
+++ b/src/gtkhex.c
@@ -240,7 +240,7 @@ popup_context_menu(GtkWidget *widget, double x, double y)
g_object_unref (builder);
}
-/* ACTIONS - just wrappers around callbacks for this widget. */
+/* ACTIONS */
static void
copy_action (GtkWidget *widget,
@@ -256,6 +256,72 @@ copy_action (GtkWidget *widget,
gtk_hex_copy_to_clipboard (gh);
}
+static void
+redo_action (GtkWidget *widget,
+ const char *action_name,
+ GVariant *parameter)
+{
+ GtkHex *gh = GTK_HEX(widget);
+ HexDocument *doc;
+ HexChangeData *cd;
+
+ (void)action_name, (void)parameter;
+
+ g_return_if_fail (GTK_IS_HEX(gh));
+ g_return_if_fail (HEX_IS_DOCUMENT(gh->document));
+
+ /* shorthand. */
+ doc = gh->document;
+
+ if (doc->undo_stack && doc->undo_top != doc->undo_stack) {
+ hex_document_redo(doc);
+
+ cd = doc->undo_top->data;
+
+ gtk_hex_set_cursor(gh, cd->start);
+ gtk_hex_set_nibble(gh, cd->lower_nibble);
+ }
+}
+
+static void
+doc_undo_redo_cb (HexDocument *doc, gpointer user_data)
+{
+ GtkHex *gh = GTK_HEX(user_data);
+ g_return_if_fail (GTK_IS_HEX (gh));
+
+ gtk_widget_action_set_enabled (GTK_WIDGET(gh),
+ "gtkhex.undo", hex_document_can_undo (doc));
+ gtk_widget_action_set_enabled (GTK_WIDGET(gh),
+ "gtkhex.redo", hex_document_can_redo (doc));
+}
+
+static void
+undo_action (GtkWidget *widget,
+ const char *action_name,
+ GVariant *parameter)
+{
+ GtkHex *gh = GTK_HEX(widget);
+ HexDocument *doc;
+ HexChangeData *cd;
+
+ (void)action_name, (void)parameter;
+
+ g_return_if_fail (GTK_IS_HEX(gh));
+ g_return_if_fail (HEX_IS_DOCUMENT(gh->document));
+
+ /* shorthand */
+ doc = gh->document;
+
+ if (doc->undo_top) {
+ cd = doc->undo_top->data;
+
+ hex_document_undo(doc);
+
+ gtk_hex_set_cursor(gh, cd->start);
+ gtk_hex_set_nibble(gh, cd->lower_nibble);
+ }
+}
+
/*
* ?_to_pointer translates mouse coordinates in hex/ascii view
* to cursor coordinates.
@@ -2809,12 +2875,22 @@ gtk_hex_snapshot (GtkWidget *widget, GtkSnapshot *snapshot)
}
}
-static void gtk_hex_document_changed(HexDocument* doc, gpointer change_data,
+static void
+gtk_hex_document_changed (HexDocument* doc, gpointer change_data,
gboolean push_undo, gpointer data)
{
- gtk_hex_real_data_changed (GTK_HEX(data), 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),
+ "gtkhex.undo", hex_document_can_undo (doc));
+ gtk_widget_action_set_enabled (GTK_WIDGET(gh),
+ "gtkhex.redo", hex_document_can_redo (doc));
+}
static void
gtk_hex_class_init (GtkHexClass *klass)
@@ -2894,9 +2970,16 @@ gtk_hex_class_init (GtkHexClass *klass)
NULL, // GVariant string param_type
copy_action);
+ gtk_widget_class_install_action (widget_class, "gtkhex.undo",
+ NULL, // GVariant string param_type
+ undo_action);
- /* SHORTCUTS (not to be confused with keybindings, which are set up
- * in gtk_hex_init) */
+ gtk_widget_class_install_action (widget_class, "gtkhex.redo",
+ NULL, // GVariant string param_type
+ redo_action);
+
+ /* SHORTCUTS FOR ACTIONS (not to be confused with keybindings, which are
+ * set up in gtk_hex_init) */
/* Ctrl+c - copy */
gtk_widget_class_add_binding_action (widget_class,
@@ -3240,6 +3323,14 @@ gtk_hex_init(GtkHex *gh)
g_signal_connect(G_OBJECT(gh->adj), "value-changed",
G_CALLBACK(display_scrolled), gh);
+
+ /* ACTIONS - Undo / Redo should start out disabled. */
+
+ gtk_widget_action_set_enabled (GTK_WIDGET(gh),
+ "gtkhex.undo", FALSE);
+ gtk_widget_action_set_enabled (GTK_WIDGET(gh),
+ "gtkhex.redo", FALSE);
+
}
GtkWidget *gtk_hex_new(HexDocument *owner) {
@@ -3249,8 +3340,18 @@ GtkWidget *gtk_hex_new(HexDocument *owner) {
g_return_val_if_fail (gh != NULL, NULL);
gh->document = owner;
+
+ /* Setup document signals (can't do in _init because we don't have
+ * access to that object yet.
+ */
g_signal_connect (G_OBJECT (gh->document), "document-changed",
G_CALLBACK (gtk_hex_document_changed), gh);
+
+ g_signal_connect (G_OBJECT (gh->document), "undo",
+ G_CALLBACK (doc_undo_redo_cb), gh);
+
+ g_signal_connect (G_OBJECT (gh->document), "redo",
+ G_CALLBACK (doc_undo_redo_cb), gh);
return GTK_WIDGET(gh);
}
diff --git a/src/hex-document.c b/src/hex-document.c
index abc6e451..806d35fd 100644
--- a/src/hex-document.c
+++ b/src/hex-document.c
@@ -1,3 +1,5 @@
+/* vim: colorcolumn=80 ts=4 sw=4
+ */
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* hex-document.c - implementation of a hex document
@@ -1157,3 +1159,26 @@ hex_document_change_file_name (HexDocument *doc, const char *new_file_name)
return FALSE;
}
}
+
+gboolean
+hex_document_can_undo (HexDocument *doc)
+{
+ if (! doc->undo_max)
+ return FALSE;
+ else if (doc->undo_top)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+gboolean
+hex_document_can_redo (HexDocument *doc)
+{
+ if (! doc->undo_stack)
+ return FALSE;
+ else if (doc->undo_stack != doc->undo_top)
+ return TRUE;
+ else
+ return FALSE;
+}
+
diff --git a/src/hex-document.h b/src/hex-document.h
index 53c8940e..bb27c2c2 100644
--- a/src/hex-document.h
+++ b/src/hex-document.h
@@ -21,8 +21,8 @@
Author: Jaka Mocnik <jaka gnu org>
*/
-#ifndef __HEX_DOCUMENT_H__
-#define __HEX_DOCUMENT_H__
+#ifndef HEX_DOCUMENT_H
+#define HEX_DOCUMENT_H
#include <stdio.h>
@@ -94,42 +94,44 @@ GType hex_document_get_type(void);
HexDocument *hex_document_new(void);
HexDocument *hex_document_new_from_file(const gchar *name);
void hex_document_set_data(HexDocument *doc, guint offset,
- guint len, guint rep_len, guchar *data,
- gboolean undoable);
+ guint len, guint rep_len, guchar *data,
+ gboolean undoable);
void hex_document_set_byte(HexDocument *doc, guchar val, guint offset,
- gboolean insert, gboolean undoable);
+ gboolean insert, gboolean undoable);
void hex_document_set_nibble(HexDocument *doc, guchar val,
- guint offset, gboolean lower_nibble,
- gboolean insert, gboolean undoable);
+ guint offset, gboolean lower_nibble,
+ gboolean insert, gboolean undoable);
guchar hex_document_get_byte(HexDocument *doc, guint offset);
guchar *hex_document_get_data(HexDocument *doc, guint offset, guint len);
void hex_document_delete_data(HexDocument *doc, guint offset,
- guint len, gboolean undoable);
+ guint len, gboolean undoable);
gint hex_document_read(HexDocument *doc);
gint hex_document_write(HexDocument *doc);
gint hex_document_write_to_file(HexDocument *doc, FILE *file);
gint hex_document_export_html(HexDocument *doc,
- gchar *html_path, gchar *base_name,
- guint start, guint end,
- guint cpl, guint lpp, guint cpw);
+ gchar *html_path, gchar *base_name,
+ guint start, guint end,
+ guint cpl, guint lpp, guint cpw);
gboolean hex_document_has_changed(HexDocument *doc);
void hex_document_changed(HexDocument *doc, gpointer change_data,
- gboolean push_undo);
+ gboolean push_undo);
void hex_document_set_max_undo(HexDocument *doc, guint max_undo);
gboolean hex_document_undo(HexDocument *doc);
gboolean hex_document_redo(HexDocument *doc);
gint hex_document_compare_data(HexDocument *doc, guchar *s2,
- gint pos, gint len);
+ gint pos, gint len);
gint hex_document_find_forward(HexDocument *doc, guint start,
- guchar *what, gint len, guint
*found);
+ guchar *what, gint len, guint *found);
gint hex_document_find_backward(HexDocument *doc, guint start,
- guchar *what, gint len, guint
*found);
+ guchar *what, gint len, guint *found);
void hex_document_remove_view(HexDocument *doc, GtkWidget *view);
GtkWidget *hex_document_add_view(HexDocument *doc);
const GList *hex_document_get_list(void);
gboolean hex_document_is_writable(HexDocument *doc);
gboolean hex_document_change_file_name (HexDocument *doc, const char *new_file_name);
+gboolean hex_document_can_undo (HexDocument *doc);
+gboolean hex_document_can_redo (HexDocument *doc);
G_END_DECLS
-#endif /* __HEX_DOCUMENT_H__ */
+#endif /* HEX_DOCUMENT_H */
diff --git a/src/preferences.c b/src/preferences.c
index cc85def0..f7989f69 100644
--- a/src/preferences.c
+++ b/src/preferences.c
@@ -86,6 +86,8 @@ static GtkWidget *long_chkbtn;
static GtkWidget *shaded_box_chkbtn;
static GtkWidget *shaded_box_spinbtn;
static GtkWidget *shaded_box_box;
+static GtkWidget *dark_mode_switch;
+static GtkWidget *system_default_chkbtn;
static GtkWidget *close_button;
static GtkWidget *help_button;
@@ -307,6 +309,52 @@ monospace_only (GtkWidget *font_button)
NULL, NULL); /* no user data, no destroy func for same. */
}
+static gboolean
+dark_mode_set_cb (GtkSwitch *widget,
+ gboolean state,
+ gpointer user_data)
+{
+ int dark_mode;
+
+ (void)user_data; /* unused */
+
+ if (state)
+ dark_mode = DARK_MODE_ON;
+ else
+ dark_mode = DARK_MODE_OFF;
+
+ g_settings_set_enum (settings,
+ GHEX_PREF_DARK_MODE,
+ dark_mode);
+
+ return GDK_EVENT_PROPAGATE;
+}
+
+static void
+system_default_set_cb (GtkCheckButton *checkbutton,
+ gpointer user_data)
+{
+ gboolean checked;
+ int dark_mode;
+
+ (void)user_data; /* unused */
+
+ checked = gtk_check_button_get_active (checkbutton);
+
+ gtk_widget_set_sensitive (dark_mode_switch,
+ checked ? FALSE : TRUE);
+
+ if (checked) {
+ dark_mode = DARK_MODE_SYSTEM;
+ } else {
+ dark_mode = gtk_switch_get_active (GTK_SWITCH(dark_mode_switch)) ?
+ DARK_MODE_ON : DARK_MODE_OFF;
+ }
+ g_settings_set_enum (settings,
+ GHEX_PREF_DARK_MODE,
+ dark_mode);
+}
+
static void
setup_signals (void)
{
@@ -321,6 +369,14 @@ setup_signals (void)
g_signal_connect (header_font_button, "font-set",
G_CALLBACK(font_set_cb), GINT_TO_POINTER(HEADER_FONT));
+ /* dark mode */
+
+ g_signal_connect (dark_mode_switch, "state-set",
+ G_CALLBACK(dark_mode_set_cb), NULL);
+
+ g_signal_connect (system_default_chkbtn, "toggled",
+ G_CALLBACK(system_default_set_cb), NULL);
+
/* group type checkbuttons */
g_signal_connect (bytes_chkbtn, "toggled",
@@ -354,16 +410,34 @@ setup_signals (void)
G_CALLBACK(help_clicked_cb), NULL);
}
-/* put all of your GET_WIDGET calls other than the main prefs_dialog widget
- * and CSS-only stuff in here, please.
- */
static void
grab_widget_values_from_settings (void)
{
+ GtkSettings *gtk_settings;
+
/* font_button */
gtk_font_chooser_set_font (GTK_FONT_CHOOSER(font_button),
def_font_name);
+ /* dark mode stuff */
+
+ /* Set switch to appropriate position and grey out if system default */
+ if (def_dark_mode == DARK_MODE_SYSTEM)
+ {
+ gtk_check_button_set_active (GTK_CHECK_BUTTON(system_default_chkbtn),
+ TRUE);
+ gtk_widget_set_sensitive (dark_mode_switch, FALSE);
+ gtk_switch_set_state (GTK_SWITCH(dark_mode_switch),
+ sys_default_is_dark);
+ } else
+ {
+ gtk_check_button_set_active (GTK_CHECK_BUTTON(system_default_chkbtn),
+ FALSE);
+ gtk_widget_set_sensitive (dark_mode_switch, TRUE);
+ gtk_switch_set_state (GTK_SWITCH(dark_mode_switch),
+ def_dark_mode == DARK_MODE_ON ? TRUE : FALSE);
+ }
+
/* data_font_button */
gtk_font_chooser_set_font (GTK_FONT_CHOOSER(data_font_button),
data_font_name);
@@ -426,6 +500,8 @@ init_widgets (void)
GET_WIDGET (shaded_box_chkbtn);
GET_WIDGET (shaded_box_spinbtn);
GET_WIDGET (shaded_box_box);
+ GET_WIDGET (dark_mode_switch);
+ GET_WIDGET (system_default_chkbtn);
GET_WIDGET (close_button);
GET_WIDGET (help_button);
diff --git a/src/preferences.ui b/src/preferences.ui
index 8d25cdff..99f64331 100644
--- a/src/preferences.ui
+++ b/src/preferences.ui
@@ -37,19 +37,46 @@
<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> <!-- dark mode hbox
-->
+ <object
class="GtkBox">
+ <property
name="orientation">horizontal</property>
+ <property
name="spacing">18</property>
+
+ <child>
+
<object class="GtkLabel" id="dark_mode_label">
+
<property name="label" translatable="yes">Dark Mode</property>
+
</object>
+ </child>
+ <child>
+
<object class="GtkSwitch" id="dark_mode_switch">
+
<property name="active">false</property>
+
</object>
+ </child>
+ <child>
+
<object class="GtkCheckButton" id="system_default_chkbtn">
+
<property name="label" translatable="yes">Use system default</property>
+
</object>
+ </child>
+
+ </object>
+ </child> <!-- /dark mode hbox
-->
+
<child> <!-- group_type_frame
-->
<object
class="GtkFrame" id="group_type_frame">
<property
name="label" translatable="yes">Hex Group Type</property>
diff --git a/src/print.c b/src/print.c
index 451b209b..9f057faa 100644
--- a/src/print.c
+++ b/src/print.c
@@ -1,3 +1,5 @@
+/* vim: colorcolumn=80 ts=4 sw=4
+ */
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* print.c - print a HexDocument
@@ -26,23 +28,19 @@
# include <config.h>
#endif /* HAVE_CONFIG_H */
-#include <glib/gi18n.h>
-
#include "print.h"
-#include "gtkhex.h"
-#include "ui.h"
#define is_printable(c) (((((guchar)c)>=0x20) && (((guchar)c)<0x7F))?1:0)
-gchar *data_font_name, *header_font_name;
+char *data_font_name, *header_font_name;
guint shaded_box_size;
static void print_header(GHexPrintJobInfo *pji, unsigned int page);
static void print_row(GHexPrintJobInfo *pji, unsigned int offset,
unsigned int bytes, int row);
-static void format_hex(HexDocument *doc, guint gt, gchar *out,
+static void format_hex(HexDocument *doc, guint gt, char *out,
guint start, guint end);
-static void format_ascii(HexDocument *doc, gchar *out,
+static void format_ascii(HexDocument *doc, char *out,
guint start, guint end);
static void print_shaded_boxes( GHexPrintJobInfo *pji, guint page,
guint max_row);
@@ -52,12 +50,12 @@ static void print_header(GHexPrintJobInfo *pji, unsigned int page)
{
PangoLayout *layout;
cairo_t *cr = gtk_print_context_get_cairo_context (pji->pc);
- gchar *text1 = g_filename_to_utf8 (pji->doc->file_name, -1, NULL,
+ char *text1 = g_filename_to_utf8 (pji->doc->file_name, -1, NULL,
NULL, NULL);
- gchar *text2 = g_strdup_printf (_("Page: %i/%i"), page, pji->pages);
- gchar *pagetext = g_strdup_printf ("%d", page);
- gdouble x, y;
- gint width, height;
+ char *text2 = g_strdup_printf (_("Page: %i/%i"), page, pji->pages);
+ char *pagetext = g_strdup_printf ("%d", page);
+ double x, y;
+ int width, height;
layout = gtk_print_context_create_pango_layout (pji->pc);
pango_layout_set_text (layout, pagetext, -1);
@@ -99,13 +97,14 @@ static void print_row(GHexPrintJobInfo *pji, unsigned int offset,
unsigned int bytes, int row)
{
PangoLayout *layout;
- gdouble x, y;
+ double x, y;
const int TEMP_LEN = 256;
- gchar *temp = g_malloc(TEMP_LEN + 1);
+ char *temp = g_malloc(TEMP_LEN + 1);
cairo_t *cr = gtk_print_context_get_cairo_context (pji->pc);
y = pji->header_height +
(pji->font_char_height*(row + 1));
+
/* Print Offset */
cairo_move_to (cr, 0, y);
layout = gtk_print_context_create_pango_layout (pji->pc);
@@ -115,6 +114,7 @@ static void print_row(GHexPrintJobInfo *pji, unsigned int offset,
pango_layout_set_indent (layout, 0);
pango_cairo_show_layout (cr, layout);
g_object_unref (layout);
+
/* Print Hex */
x = pji->font_char_width*pji->offset_chars +
pji->pad_size ;
@@ -142,13 +142,13 @@ static void print_row(GHexPrintJobInfo *pji, unsigned int offset,
g_free(temp);
}
-static void format_hex(HexDocument *doc, guint gt, gchar *out,
- guint start, guint end)
+static void format_hex (HexDocument *doc, guint gt, char *out,
+ guint start, guint end)
{
- gint i, j, low, high;
+ int i, j, low, high;
guchar c;
- for(i = start + 1, j = 0; i <= end; i++) {
+ for (i = start + 1, j = 0; i <= end; i++) {
c = hex_document_get_byte(doc, i - 1);
low = c & 0x0F;
high = (c & 0xF0) >> 4;
@@ -156,18 +156,19 @@ static void format_hex(HexDocument *doc, guint gt, gchar *out,
out[j++] = ((high < 10)?(high + '0'):(high - 10 + 'A'));
out[j++] = ((low < 10)?(low + '0'):(low - 10 + 'A'));
- if(i % gt == 0)
+ if (i % gt == 0)
out[j++] = ' ';
}
out[j++] = 0;
}
-static void format_ascii(HexDocument *doc, gchar *out, guint start, guint end)
+static void format_ascii (HexDocument *doc,
+ char *out, guint start, guint end)
{
- gint i, j;
+ int i, j;
guchar c;
- for(i = start, j = 0; i < end; i++, j++) {
+ for (i = start, j = 0; i < end; i++, j++) {
c = hex_document_get_byte(doc, i);
if (is_printable(c))
out[j] = c;
@@ -178,24 +179,26 @@ static void format_ascii(HexDocument *doc, gchar *out, guint start, guint end)
}
static void print_shaded_boxes(GHexPrintJobInfo *pji, guint page,
- guint max_row)
+ guint max_row)
{
guint i;
guint box_size = shaded_box_size;
- if(box_size == 0)
+ if (box_size == 0)
return;
- for(i = box_size + 1;
+ for (i = box_size + 1;
i <= pji->rows_per_page && i <= max_row;
i += box_size*2)
+ {
print_shaded_box (pji, i+1, ((i + box_size - 1) > max_row ?
max_row - i + 1 : box_size));
+ }
}
-static void print_shaded_box(GHexPrintJobInfo *pji, guint row, guint rows)
+static void print_shaded_box (GHexPrintJobInfo *pji, guint row, guint rows)
{
- gdouble box_top;
+ double box_top;
cairo_t *cr = gtk_print_context_get_cairo_context (pji->pc);
box_top = pji->header_height + row * pji->font_char_height;
@@ -221,7 +224,7 @@ static void print_shaded_box(GHexPrintJobInfo *pji, guint row, guint rows)
* Creates a new GHexPrintJobInfo object.
**/
GHexPrintJobInfo *
-ghex_print_job_info_new(HexDocument *doc, guint group_type)
+ghex_print_job_info_new (HexDocument *doc, guint group_type)
{
GHexPrintJobInfo *pji;
PangoFontDescription *d_font;
@@ -266,7 +269,7 @@ ghex_print_job_info_new(HexDocument *doc, guint group_type)
* Destroys the GHexPrintJobInfo object pointed to by pji.
**/
void
-ghex_print_job_info_destroy(GHexPrintJobInfo *pji)
+ghex_print_job_info_destroy (GHexPrintJobInfo *pji)
{
pango_font_description_free (pji->h_font);
pango_font_description_free (pji->d_font);
@@ -288,8 +291,8 @@ begin_print (GtkPrintOperation *operation,
PangoLayout *layout;
GHexPrintJobInfo *pji = (GHexPrintJobInfo *)data;
pji->pc = context;
- gint font_width, font_height;
- gint printable_width, printable_height;
+ int font_width, font_height;
+ int printable_width, printable_height;
layout = gtk_print_context_create_pango_layout (context);
pango_layout_set_text (layout, " ", -1);
@@ -326,10 +329,10 @@ begin_print (GtkPrintOperation *operation,
void
print_page (GtkPrintOperation *operation,
GtkPrintContext *context,
- gint page_nr,
+ int page_nr,
gpointer data)
{
- gint j, max_row;
+ int j, max_row;
GHexPrintJobInfo *pji = (GHexPrintJobInfo *)data;
g_return_if_fail(pji != NULL);
@@ -358,4 +361,3 @@ print_page (GtkPrintOperation *operation,
print_row (pji, file_offset, length, j);
}
}
-
diff --git a/src/print.h b/src/print.h
index 0527858c..46290f3d 100644
--- a/src/print.h
+++ b/src/print.h
@@ -1,3 +1,5 @@
+/* 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
@@ -21,12 +23,13 @@
Author: Jaka Mocnik <jaka gnu org>
*/
-#ifndef __GHEX_PRINT_H__
-#define __GHEX_PRINT_H__
+#ifndef GHEX_PRINT_H
+#define GHEX_PRINT_H
#include <gtk/gtk.h>
-
-#include "hex-document.h"
+#include <glib/gi18n.h>
+#include <gtkhex.h>
+#include <hex-document.h>
G_BEGIN_DECLS
@@ -40,34 +43,36 @@ struct _GHexPrintJobInfo {
PangoFontDescription *d_font, *h_font;
HexDocument *doc;
- int pages;
- gint range;
- gint page_first;
- gint page_last;
+ int pages;
+ int range;
+ int page_first;
+ int page_last;
- gdouble header_height;
+ double header_height;
- gint font_char_width;
- gint font_char_height;
+ int font_char_width;
+ int font_char_height;
- int bytes_per_row, rows_per_page;
- gdouble pad_size;
- int offset_chars ; /* How many chars are used in the offset window */
- int gt; /* group_type */
+ int bytes_per_row, rows_per_page;
+ double pad_size;
+ int offset_chars ; /* How many chars are used in the offset window */
+ int gt; /* group_type */
gboolean preview;
};
-/* printing */
+/* FUNCTION DECLARATIONS */
+
void begin_print (GtkPrintOperation *operation,
GtkPrintContext *context,
gpointer data);
void print_page (GtkPrintOperation *operation,
GtkPrintContext *context,
- gint page_nr,
+ int page_nr,
gpointer data);
-GHexPrintJobInfo *ghex_print_job_info_new(HexDocument *doc, guint group_type);
+GHexPrintJobInfo *ghex_print_job_info_new (HexDocument *doc,
+ guint group_type);
void ghex_print_job_info_destroy(GHexPrintJobInfo *pji);
G_END_DECLS
-#endif /* !__GHEX_PRINT_H__ */
+#endif /* GHEX_PRINT_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]