gnucash stable: Multiple changes pushed

Robert Fewell bobit at code.gnucash.org
Wed Dec 10 05:18:26 EST 2025


Updated	 via  https://github.com/Gnucash/gnucash/commit/46fe4557 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/ed03e61d (commit)
	from  https://github.com/Gnucash/gnucash/commit/c8023434 (commit)



commit 46fe45570f8adbda9ce5360b1f369d65f2c65b0e
Author: Robert Fewell <14uBobIT at gmail.com>
Date:   Fri Nov 28 14:37:04 2025 +0000

    Add CSS to make the About dialog text view
    background the same as the rest of the dialog.
    This can be over ridden by the users own CSS file.

diff --git a/gnucash/gnome-utils/gnc-main-window.cpp b/gnucash/gnome-utils/gnc-main-window.cpp
index b89cf40a81..7f4e112924 100644
--- a/gnucash/gnome-utils/gnc-main-window.cpp
+++ b/gnucash/gnome-utils/gnc-main-window.cpp
@@ -5418,6 +5418,19 @@ create_url_text_tag (GtkDialog *dialog,
     return url_tt;
 }
 
+static void
+add_textview_css_class (GtkTextView *textview)
+{
+    GdkRGBA color;
+    GtkStyleContext *stylectxt = gtk_widget_get_style_context (GTK_WIDGET(textview));
+    gtk_style_context_get_color (stylectxt, GTK_STATE_FLAG_NORMAL, &color);
+
+    if (gnc_is_dark_theme (&color))
+        gtk_style_context_add_class (stylectxt, "gnc-class-textview-dark");
+    else
+        gtk_style_context_add_class (stylectxt, "gnc-class-textview");
+}
+
 static void
 add_about_paths (GtkDialog *dialog)
 {
@@ -5441,6 +5454,8 @@ add_about_paths (GtkDialog *dialog)
     GdkRGBA link_color = get_link_color ();
     gint max_text_width = get_max_text_width (GTK_TEXT_VIEW(textview), ep_vec);
 
+    add_textview_css_class (GTK_TEXT_VIEW(textview));
+
     gtk_text_view_set_left_margin (GTK_TEXT_VIEW(textview), DEFAULT_MARGIN);
     gtk_text_view_set_right_margin (GTK_TEXT_VIEW(textview), DEFAULT_MARGIN);
     gtk_text_view_set_top_margin (GTK_TEXT_VIEW(textview), DEFAULT_MARGIN);
diff --git a/gnucash/gnucash.css b/gnucash/gnucash.css
index 703d2ca30c..0eecd09322 100644
--- a/gnucash/gnucash.css
+++ b/gnucash/gnucash.css
@@ -89,3 +89,14 @@ dialog#GnuCash > box > box > label
 {
   font-size: 24px;
 }
+
+/* Setting the Textview background for light and dark themes */
+.gnc-class-textview * {
+  background-color: rgb(246,245,244);
+}
+
+.gnc-class-textview-dark * {
+  background-color: rgb(53,53,53);
+}
+
+

commit ed03e61dab301f1f0d48c3ad9a2b45e7f0ce35dc
Author: Robert Fewell <14uBobIT at gmail.com>
Date:   Mon Nov 24 14:46:55 2025 +0000

    Add ability to copy About dialog configuration
    settings to the clipboard so they can all be
    pasted in one go.

diff --git a/gnucash/gnome-utils/gnc-main-window.cpp b/gnucash/gnome-utils/gnc-main-window.cpp
index 9a81bfec9b..b89cf40a81 100644
--- a/gnucash/gnome-utils/gnc-main-window.cpp
+++ b/gnucash/gnome-utils/gnc-main-window.cpp
@@ -5266,22 +5266,162 @@ url_signal_cb (GtkAboutDialog *dialog, gchar *uri, gpointer data)
     return TRUE;
 }
 
+#define DEFAULT_MARGIN 5
+
+static void
+set_text_cursor (GdkWindow *win, GdkCursorType type)
+{
+    if (!win && !type)
+        return;
+
+    GdkCursor *current = gdk_window_get_cursor (win);
+    if (type == gdk_cursor_get_cursor_type (current))
+        return;
+
+    GdkCursor *cur = gdk_cursor_new_for_display (gdk_window_get_display (win), type);
+    gdk_window_set_cursor (win, cur);
+}
+
+static gboolean
+textview_motion_notify_cb (GtkWidget *textview,
+                           GdkEventMotion *event,
+                           gpointer user_data)
+{
+    if (event->state & GDK_BUTTON1_MASK)
+        return false;
+
+    GtkTextIter iter;
+    gboolean valid = gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW(textview),
+                                                         &iter, event->x, event->y);
+
+    if (valid && (event->y > DEFAULT_MARGIN))
+    {
+        GSList *tt_list = gtk_text_iter_get_tags (&iter);
+
+        if (tt_list)
+        {
+            GtkTextTag *tt = (GtkTextTag*)g_slist_nth_data (tt_list, 0);
+
+            if (g_object_get_data (G_OBJECT(tt), "link"))
+                set_text_cursor (event->window, GDK_HAND1);
+            else
+                set_text_cursor (event->window, GDK_XTERM);
+
+            g_slist_free (tt_list);
+        }
+        else
+            set_text_cursor (event->window, GDK_XTERM);
+    }
+    else
+        set_text_cursor (event->window, GDK_XTERM);
+
+    return true;
+}
+
 static gboolean
-link_button_cb (GtkLinkButton *button, gpointer user_data)
+textview_url_activate (GtkTextTag *tag,
+                       GObject *object,
+                       GdkEvent *event,
+                       GtkTextIter *iter,
+                       gpointer user_data)
 {
-   const gchar *uri = gtk_link_button_get_uri (button);
-   gchar *escaped_uri = g_uri_escape_string (uri, ":/.\\", true);
-   gnc_launch_doclink (GTK_WINDOW(user_data), escaped_uri);
-   g_free (escaped_uri);
-   return TRUE;
+    GdkEventButton *event_button = (GdkEventButton*)event;
+
+    if ((event->type == GDK_BUTTON_RELEASE) &&
+        (event_button->button == 1) &&
+        (event_button->y > DEFAULT_MARGIN))
+    {
+        gchar *link = (gchar*)g_object_get_data (G_OBJECT(tag), "link");
+        PINFO("Link is '%s'", link);
+        gchar *escaped_uri = g_uri_escape_string (link, ":/.\\", true);
+        PINFO("Escaped Link is '%s'", escaped_uri);
+        gnc_launch_doclink (GTK_WINDOW(user_data), escaped_uri);
+        g_free (escaped_uri);
+
+        return true;
+    }
+    return false;
+}
+
+static gint
+get_max_text_width (GtkTextView *textview, std::vector<EnvPaths> ep_vec)
+{
+    gint max_text_width = 0;
+    for (const auto& ep : ep_vec)
+    {
+        gint text_width;
+        gchar *env_name = g_strconcat (ep.env_name, ":", nullptr);
+
+        PangoLayout *layout = gtk_widget_create_pango_layout (GTK_WIDGET(textview),
+                                                              env_name);
+
+        pango_layout_get_pixel_size (layout, &text_width, nullptr);
+        g_object_unref (layout);
+        g_free (env_name);
+
+        max_text_width = MAX(max_text_width, text_width);
+    }
+    return max_text_width;
+}
+
+static GtkTextTag *
+create_left_margin_text_tag (GtkTextView *textview,
+                             gchar *lmargin_tag,
+                             const gchar *text,
+                             gint max_width)
+{
+    if (!lmargin_tag)
+        return nullptr;
+
+    GtkTextTag *lmargin_tt = gtk_text_tag_new (lmargin_tag);
+    int text_width;
+
+    PangoLayout *layout = gtk_widget_create_pango_layout (GTK_WIDGET(textview), text);
+    pango_layout_get_pixel_size (layout, &text_width, nullptr);
+    g_object_unref (layout);
+
+    g_object_set (G_OBJECT(lmargin_tt), "left_margin",
+                  DEFAULT_MARGIN + max_width - text_width, nullptr);
+
+    return lmargin_tt;
+}
+
+static GdkRGBA
+get_link_color (void)
+{
+    GdkRGBA link_color;
+    GtkWidget *dummy_link_button = gtk_link_button_new_with_label ("https://www.gnucash.org", "Dummy");
+    GtkStyleContext *context = gtk_widget_get_style_context (GTK_WIDGET(dummy_link_button));
+    gtk_style_context_get_color (context, GTK_STATE_FLAG_LINK, &link_color);
+
+    return link_color;
+}
+
+static GtkTextTag *
+create_url_text_tag (GtkDialog *dialog,
+                     GdkRGBA link_color,
+                     gchar *url_tag,
+                     const gchar *uri)
+{
+    if (!url_tag)
+        return nullptr;
+
+    GtkTextTag *url_tt = gtk_text_tag_new (url_tag);
+    g_object_set (G_OBJECT(url_tt), "underline", PANGO_UNDERLINE_SINGLE,
+                                    "underline-set", true, nullptr);
+    g_object_set (G_OBJECT(url_tt), "foreground-rgba", &link_color, nullptr);
+
+    g_object_set_data_full (G_OBJECT(url_tt), "link", g_strdup (uri), g_free);
+
+    g_signal_connect (G_OBJECT(url_tt), "event",
+                      G_CALLBACK(textview_url_activate), dialog);
+    return url_tt;
 }
 
 static void
 add_about_paths (GtkDialog *dialog)
 {
     GtkWidget *page_vbox = gnc_get_dialog_widget_from_id (dialog, "page_vbox");
-    GtkWidget *grid;
-    gint i = 0;
 
     if (!page_vbox)
     {
@@ -5289,40 +5429,74 @@ add_about_paths (GtkDialog *dialog)
         return;
     }
 
-    grid = gtk_grid_new ();
+    GtkWidget *textview = gtk_text_view_new ();
+    GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(textview));
+    GtkTextTagTable *ttt = gtk_text_buffer_get_tag_table (buffer);
+    GtkTextIter iter;
+
+    std::vector<EnvPaths> ep_vec = gnc_list_all_paths ();
+    int ep_size = (int)ep_vec.size();
+    int row = 1;
+
+    GdkRGBA link_color = get_link_color ();
+    gint max_text_width = get_max_text_width (GTK_TEXT_VIEW(textview), ep_vec);
 
-    for (const auto& ep : gnc_list_all_paths ())
+    gtk_text_view_set_left_margin (GTK_TEXT_VIEW(textview), DEFAULT_MARGIN);
+    gtk_text_view_set_right_margin (GTK_TEXT_VIEW(textview), DEFAULT_MARGIN);
+    gtk_text_view_set_top_margin (GTK_TEXT_VIEW(textview), DEFAULT_MARGIN);
+    gtk_text_view_set_bottom_margin (GTK_TEXT_VIEW(textview), DEFAULT_MARGIN);
+    gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW(textview), GTK_WRAP_NONE);
+
+    gtk_text_buffer_create_tag (buffer, "italic", "style", PANGO_STYLE_ITALIC, nullptr);
+
+    gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
+
+    for (const auto& ep : ep_vec)
     {
-        gchar *env_name = g_strconcat (ep.env_name, ":", NULL);
-        GtkWidget *label = gtk_label_new (env_name);
-        gtk_label_set_selectable (GTK_LABEL (label), TRUE);
-        const gchar *uri = gnc_uri_create_uri ("file", NULL, 0, NULL, NULL, ep.env_path);
+        gchar *env_name = g_strconcat (ep.env_name, ":", nullptr);
+        const gchar *uri = gnc_uri_create_uri ("file", nullptr, 0, nullptr, nullptr, ep.env_path);
         gchar *display_uri = gnc_doclink_get_unescaped_just_uri (uri);
-        GtkWidget *widget = gtk_link_button_new_with_label (uri, display_uri);
 
-        gtk_grid_attach (GTK_GRID(grid), label, 0, i, 1, 1);
-        gtk_widget_set_halign (label, GTK_ALIGN_END);
-        gtk_grid_attach (GTK_GRID(grid), widget, 1, i, 1, 1);
-        gtk_widget_set_halign (widget, GTK_ALIGN_START);
-        gtk_widget_set_margin_top (widget, 0);
-        gtk_widget_set_margin_bottom (widget, 0);
+        gchar *url_tag = g_strdup_printf ("%s%d", "url_tag", row);
+        gchar *lmargin_tag = g_strdup_printf ("%s%d", "lmargin_tag", row);
+
+        gtk_text_tag_table_add (ttt, create_left_margin_text_tag (GTK_TEXT_VIEW(textview),
+                                                                  lmargin_tag,
+                                                                  env_name,
+                                                                  max_text_width));
+        gtk_text_tag_table_add (ttt, create_url_text_tag (dialog,
+                                                          link_color,
+                                                          url_tag,
+                                                          uri));
+
+        gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, env_name, -1, lmargin_tag, nullptr);
+        gtk_text_buffer_insert (buffer, &iter, " ", -1);
+        gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, display_uri, -1, url_tag, nullptr);
+
+        g_free (url_tag);
+        g_free (lmargin_tag);
+        g_free (display_uri);
+        g_free (env_name);
 
         if (ep.modifiable)
         {
-            GtkWidget *mod_lab = gtk_label_new (_("(user modifiable)"));
-            gtk_grid_attach (GTK_GRID(grid), mod_lab, 2, i, 1, 1);
-            gtk_widget_show (mod_lab);
+            gtk_text_buffer_insert (buffer, &iter, " ", -1);
+            gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, _("(User modifiable)"), -1, "italic", nullptr);
         }
-        g_signal_connect (widget, "activate-link",
-                          G_CALLBACK(link_button_cb), dialog);
-        i++;
 
-        g_free (display_uri);
-        g_free (env_name);
+        if (row != ep_size)
+            gtk_text_buffer_insert (buffer, &iter, "\n", -1);
+
+        row++;
     }
-    gtk_container_add_with_properties (GTK_CONTAINER(page_vbox), grid,
-                                       "position", 1, NULL);
-    gtk_widget_show_all (grid);
+    gtk_text_view_set_editable (GTK_TEXT_VIEW(textview), false);
+
+    g_signal_connect (G_OBJECT(textview), "motion-notify-event",
+                      G_CALLBACK(textview_motion_notify_cb), nullptr);
+
+    gtk_container_add_with_properties (GTK_CONTAINER(page_vbox), textview,
+                                       "position", 1, nullptr);
+    gtk_widget_show_all (page_vbox);
 }
 
 /** Create and display the "about" dialog for gnucash.
diff --git a/gnucash/gnucash.css b/gnucash/gnucash.css
index c6d50a2d46..703d2ca30c 100644
--- a/gnucash/gnucash.css
+++ b/gnucash/gnucash.css
@@ -89,8 +89,3 @@ dialog#GnuCash > box > box > label
 {
   font-size: 24px;
 }
-dialog#GnuCash grid * {
-  padding-top: 0px;
-  padding-bottom: 0px;
-  min-height: 4px;
-}



Summary of changes:
 gnucash/gnome-utils/gnc-main-window.cpp | 253 ++++++++++++++++++++++++++++----
 gnucash/gnucash.css                     |  14 +-
 2 files changed, 231 insertions(+), 36 deletions(-)



More information about the gnucash-changes mailing list