[gnome-terminal] window: Add option to decode timestamps in context menu



commit 59886f9e7d2b2447c1c52cd23d866d9a531581ae
Author: Christian Persch <chpe src gnome org>
Date:   Tue Nov 17 21:45:10 2020 +0100

    window: Add option to decode timestamps in context menu
    
    Based on a patch by Egmont Koblinger <egmont gmail com>.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=757540

 src/org.gnome.Terminal.gschema.xml |  5 ++++
 src/terminal-libgsystem.h          | 10 +++++++
 src/terminal-schemas.h             |  1 +
 src/terminal-screen.c              | 21 ++++++++++----
 src/terminal-screen.h              |  1 +
 src/terminal-util.c                | 59 +++++++++++++++++++++++++++++++-------
 src/terminal-util.h                |  1 +
 src/terminal-window.c              | 30 +++++++++++++++----
 8 files changed, 105 insertions(+), 23 deletions(-)
---
diff --git a/src/org.gnome.Terminal.gschema.xml b/src/org.gnome.Terminal.gschema.xml
index be00aa2d..1a629341 100644
--- a/src/org.gnome.Terminal.gschema.xml
+++ b/src/org.gnome.Terminal.gschema.xml
@@ -669,6 +669,11 @@
       <summary>Whether to ask for confirmation before closing a terminal</summary>
     </key>
 
+    <key name="context-info" type="as">
+      <default>['numbers']</default>
+      <summary>Additional info section items to appear in the context menu</summary>
+    </key>
+
     <key name="default-show-menubar" type="b">
       <default>true</default>
       <summary>Whether to show the menubar in new windows</summary>
diff --git a/src/terminal-libgsystem.h b/src/terminal-libgsystem.h
index 906a127d..4c84dc30 100644
--- a/src/terminal-libgsystem.h
+++ b/src/terminal-libgsystem.h
@@ -51,6 +51,7 @@ G_BEGIN_DECLS
 GS_DEFINE_CLEANUP_FUNCTION0(GArray*, gs_local_array_unref, g_array_unref)
 GS_DEFINE_CLEANUP_FUNCTION0(GBytes*, gs_local_bytes_unref, g_bytes_unref)
 GS_DEFINE_CLEANUP_FUNCTION0(GChecksum*, gs_local_checksum_free, g_checksum_free)
+GS_DEFINE_CLEANUP_FUNCTION0(GDateTime*, gs_local_date_time_unref, g_date_time_unref)
 GS_DEFINE_CLEANUP_FUNCTION0(GError*, gs_local_free_error, g_error_free)
 GS_DEFINE_CLEANUP_FUNCTION0(GHashTable*, gs_local_hashtable_unref, g_hash_table_unref)
 GS_DEFINE_CLEANUP_FUNCTION0(GKeyFile*, gs_local_key_file_unref, g_key_file_unref)
@@ -164,6 +165,15 @@ static inline void gs_local_gstring_free (void *v) \
  */
 #define gs_free_checksum __attribute__ ((cleanup(gs_local_checksum_free)))
 
+/**
+ * gs_unref_date_time:
+ *
+ * Call g_date_time_free() on a variable location when it goes out
+ * of scope.  Note that unlike g_date_time_free(), the variable may
+ * be %NULL.
+ */
+#define gs_unref_date_time __attribute__ ((cleanup(gs_local_date_time_unref)))
+
 /**
  * gs_unref_bytes:
  *
diff --git a/src/terminal-schemas.h b/src/terminal-schemas.h
index cffc4ed8..08b6e85f 100644
--- a/src/terminal-schemas.h
+++ b/src/terminal-schemas.h
@@ -77,6 +77,7 @@ G_BEGIN_DECLS
 #define TERMINAL_PROFILE_WORD_CHAR_EXCEPTIONS_KEY       "word-char-exceptions"
 
 #define TERMINAL_SETTING_CONFIRM_CLOSE_KEY              "confirm-close"
+#define TERMINAL_SETTING_CONTEXT_INFO_KEY               "context-info"
 #define TERMINAL_SETTING_DEFAULT_SHOW_MENUBAR_KEY       "default-show-menubar"
 #define TERMINAL_SETTING_ENABLE_MENU_BAR_ACCEL_KEY      "menu-accelerator-enabled"
 #define TERMINAL_SETTING_ENABLE_MNEMONICS_KEY           "mnemonics-enabled"
diff --git a/src/terminal-screen.c b/src/terminal-screen.c
index 844b563c..f44de43a 100644
--- a/src/terminal-screen.c
+++ b/src/terminal-screen.c
@@ -163,7 +163,8 @@ static char* terminal_screen_check_hyperlink   (TerminalScreen            *scree
                                                 GdkEvent                  *event);
 static void terminal_screen_check_extra (TerminalScreen *screen,
                                          GdkEvent       *event,
-                                         char           **number_info);
+                                         char           **number_info,
+                                         char           **timestamp_info);
 static char* terminal_screen_check_match       (TerminalScreen            *screen,
                                                 GdkEvent                  *event,
                                                 int                  *flavor);
@@ -1683,6 +1684,7 @@ terminal_screen_popup_info_unref (TerminalScreenPopupInfo *info)
   g_free (info->hyperlink);
   g_free (info->url);
   g_free (info->number_info);
+  g_free (info->timestamp_info);
   g_slice_free (TerminalScreenPopupInfo, info);
 }
 
@@ -1708,7 +1710,8 @@ terminal_screen_do_popup (TerminalScreen *screen,
                           char *hyperlink,
                           char *url,
                           int url_flavor,
-                          char *number_info)
+                          char *number_info,
+                          char *timestamp_info)
 {
   TerminalScreenPopupInfo *info;
 
@@ -1720,6 +1723,7 @@ terminal_screen_do_popup (TerminalScreen *screen,
   info->url = url; /* adopted */
   info->url_flavor = url_flavor;
   info->number_info = number_info; /* adopted */
+  info->timestamp_info = timestamp_info; /* adopted */
 
   g_signal_emit (screen, signals[SHOW_POPUP_MENU], 0, info);
   terminal_screen_popup_info_unref (info);
@@ -1736,13 +1740,14 @@ terminal_screen_button_press (GtkWidget      *widget,
   gs_free char *url = NULL;
   int url_flavor = 0;
   gs_free char *number_info = NULL;
+  gs_free char *timestamp_info = NULL;
   guint state;
 
   state = event->state & gtk_accelerator_get_default_mod_mask ();
 
   hyperlink = terminal_screen_check_hyperlink (screen, (GdkEvent*)event);
   url = terminal_screen_check_match (screen, (GdkEvent*)event, &url_flavor);
-  terminal_screen_check_extra (screen, (GdkEvent*)event, &number_info);
+  terminal_screen_check_extra (screen, (GdkEvent*)event, &number_info, &timestamp_info);
 
   if (hyperlink != NULL &&
       (event->button == 1 || event->button == 2) &&
@@ -1783,19 +1788,21 @@ terminal_screen_button_press (GtkWidget      *widget,
           if (button_press_event && button_press_event (widget, event))
             return TRUE;
 
-          terminal_screen_do_popup (screen, event, hyperlink, url, url_flavor, number_info);
+          terminal_screen_do_popup (screen, event, hyperlink, url, url_flavor, number_info, timestamp_info);
           hyperlink = NULL; /* adopted to the popup info */
           url = NULL; /* ditto */
           number_info = NULL; /* ditto */
+          timestamp_info = NULL; /* ditto */
           return TRUE;
         }
       else if (!(event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK)))
         {
           /* do popup on shift+right-click */
-          terminal_screen_do_popup (screen, event, hyperlink, url, url_flavor, number_info);
+          terminal_screen_do_popup (screen, event, hyperlink, url, url_flavor, number_info, timestamp_info);
           hyperlink = NULL; /* adopted to the popup info */
           url = NULL; /* ditto */
           number_info = NULL; /* ditto */
+          timestamp_info = NULL; /* ditto */
           return TRUE;
         }
     }
@@ -2163,7 +2170,8 @@ terminal_screen_check_match (TerminalScreen *screen,
 static void
 terminal_screen_check_extra (TerminalScreen *screen,
                              GdkEvent       *event,
-                             char           **number_info)
+                             char           **number_info,
+                             char           **timestamp_info)
 {
   guint i;
   char **matches;
@@ -2191,6 +2199,7 @@ terminal_screen_check_extra (TerminalScreen *screen,
                   if (!flavor_number_found)
                     {
                       *number_info = terminal_util_number_info (matches[i]);
+                      *timestamp_info = terminal_util_timestamp_info (matches[i]);
                       flavor_number_found = TRUE;
                     }
                   g_free (matches[i]);
diff --git a/src/terminal-screen.h b/src/terminal-screen.h
index 8ea33786..df59b1a5 100644
--- a/src/terminal-screen.h
+++ b/src/terminal-screen.h
@@ -150,6 +150,7 @@ struct _TerminalScreenPopupInfo {
   TerminalURLFlavor url_flavor;
   char *hyperlink;
   char *number_info;
+  char *timestamp_info;
   guint button;
   guint state;
   guint32 timestamp;
diff --git a/src/terminal-util.c b/src/terminal-util.c
index 3155e3f4..d4b6f80a 100644
--- a/src/terminal-util.c
+++ b/src/terminal-util.c
@@ -1030,22 +1030,21 @@ terminal_util_number_info (const char *str)
   gs_free char *hextmp = NULL;
   gs_free char *hexstr = NULL;
   gs_free char *magnitudestr = NULL;
-  unsigned long long num;
   gboolean exact = TRUE;
   gboolean hex = FALSE;
   const char *thousep;
 
-  errno = 0;
   /* Deliberately not handle octal */
-  if (str[1] == 'x' || str[1] == 'X') {
-    num = strtoull(str + 2, NULL, 16);
+  if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
+    str += 2;
     hex = TRUE;
-  } else {
-    num = strtoull(str, NULL, 10);
   }
-  if (errno) {
+
+  errno = 0;
+  char* end;
+  gint64 num = g_ascii_strtoull(str, &end, hex ? 16 : 10);
+  if (errno || str == end || num == -1)
     return NULL;
-  }
 
   /* No use in dec-hex conversion for so small numbers */
   if (num < 10) {
@@ -1057,18 +1056,18 @@ terminal_util_number_info (const char *str)
   if (thousep[0] != '\0') {
     /* If thousep is nonempty, use printf's magic which can handle
        more complex separating logics, e.g. 2+2+2+3 for some locales */
-    decstr = g_strdup_printf("%'llu", num);
+    decstr = g_strdup_printf("%'" G_GINT64_FORMAT, num);
   } else {
     /* If, however, thousep is empty, override it with a space so that we
        do always group the digits (that's the whole point of this feature;
        the choice of space guarantees not conflicting with the decimal separator) */
-    gs_free char *tmp = g_strdup_printf("%llu", num);
+    gs_free char *tmp = g_strdup_printf("%" G_GINT64_FORMAT, num);
     thousep = " ";
     decstr = add_separators(tmp, thousep, 3);
   }
 
   /* Group the hex digits by 4 using the same nonempty separator */
-  hextmp = g_strdup_printf("%llx", num);
+  hextmp = g_strdup_printf("%" G_GINT64_MODIFIER "x", (guint64)(num));
   hexstr = add_separators(hextmp, thousep, 4);
 
   /* Find out the human-readable magnitude, e.g. 15.99 Mi */
@@ -1093,6 +1092,44 @@ terminal_util_number_info (const char *str)
   return g_strdup_printf(hex ? "0x%2$s = %1$s%3$s" : "%s = 0x%s%s", decstr, hexstr, magnitudestr);
 }
 
+/**
+ * terminal_util_timestamp_info:
+ * @str: a dec or hex number as string
+ *
+ * Returns: (transfer full): Formatted localtime if @str is decimal and looks like a timestamp, or %NULL
+ */
+char *
+terminal_util_timestamp_info (const char *str)
+{
+  /* Bail out on hex numbers */
+  if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
+    return NULL;
+  }
+
+  /* Deliberately not handle octal */
+  errno = 0;
+  char* end;
+  gint64 num = g_ascii_strtoull (str, &end, 10);
+  if (errno || end == str || num == -1)
+    return NULL;
+
+  /* Java uses Unix time in milliseconds. */
+  if (num >= 1000000000000 && num <= 1999999999999)
+    num /= 1000;
+
+  /* Fun: use inclusive interval so you can right-click on these numbers
+   * and check the human-readable time in gnome-terminal.
+   * (They're Sep 9 2001 and May 18 2033 by the way.) */
+  if (num < 1000000000 || num > 1999999999)
+    return NULL;
+
+  gs_unref_date_time GDateTime* date = g_date_time_new_from_unix_utc (num);
+  if (date == NULL)
+    return NULL;
+
+  return g_date_time_format(date, "%c");
+}
+
 /**
  * terminal_util_uri_fixup:
  * @uri: The URI to verify and maybe fixup
diff --git a/src/terminal-util.h b/src/terminal-util.h
index 0f3e6bfa..07c9470a 100644
--- a/src/terminal-util.h
+++ b/src/terminal-util.h
@@ -93,6 +93,7 @@ void terminal_g_settings_set_rgba_palette (GSettings      *settings,
 void terminal_util_bind_mnemonic_label_sensitivity (GtkWidget *widget);
 
 char *terminal_util_number_info (const char *str);
+char *terminal_util_timestamp_info (const char *str);
 
 char *terminal_util_uri_fixup (const char *uri,
                                GError **error);
diff --git a/src/terminal-window.c b/src/terminal-window.c
index 7a8953c5..0bed828e 100644
--- a/src/terminal-window.c
+++ b/src/terminal-window.c
@@ -1727,14 +1727,32 @@ screen_show_popup_menu_cb (TerminalScreen *screen,
   }
 
   /* Info section */
-  if (info->number_info != NULL) {
-    gs_unref_object GMenu *section3 = g_menu_new ();
-    /* Non-existent action will make this item insensitive */
-    gs_unref_object GMenuItem *item3 = g_menu_item_new (info->number_info, "win.notexist");
-    g_menu_append_item (section3, item3);
-    g_menu_append_section (menu, NULL, G_MENU_MODEL (section3));
+  gs_strfreev char** citems = g_settings_get_strv (terminal_app_get_global_settings (terminal_app_get ()),
+                                                   TERMINAL_SETTING_CONTEXT_INFO_KEY);
+
+  gs_unref_object GMenu *section3 = g_menu_new ();
+
+  for (int i = 0; citems[i] != NULL; ++i) {
+    const char *citem = citems[i];
+
+    if (g_str_equal (citem, "numbers") &&
+        info->number_info != NULL) {
+      /* Non-existent action will make this item insensitive */
+      gs_unref_object GMenuItem *item3 = g_menu_item_new (info->number_info, "win.notexist");
+      g_menu_append_item (section3, item3);
+    }
+
+    if (g_str_equal (citem, "timestamps") &&
+        info->timestamp_info != NULL) {
+      /* Non-existent action will make this item insensitive */
+      gs_unref_object GMenuItem *item3 = g_menu_item_new (info->timestamp_info, "win.notexist");
+      g_menu_append_item (section3, item3);
+    }
   }
 
+  if (g_menu_model_get_n_items(G_MENU_MODEL (section3)) > 0)
+    g_menu_append_section (menu, NULL, G_MENU_MODEL (section3));
+
   /* Clipboard section */
   gs_unref_object GMenu *section4 = g_menu_new ();
 


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