diff --git a/src/terminal-screen.c b/src/terminal-screen.c
index 9df4fc7a..1f080b13 100644
--- a/src/terminal-screen.c
+++ b/src/terminal-screen.c
@@ -152,6 +152,8 @@ static void terminal_screen_icon_title_changed        (VteTerminal *vte_terminal
 
 static void update_color_scheme                      (TerminalScreen *screen);
 
+static char* terminal_screen_check_hyperlink   (TerminalScreen            *screen,
+                                                GdkEvent                  *event);
 static void terminal_screen_check_extra (TerminalScreen *screen,
                                          GdkEvent       *event,
                                          char           **number_info);
@@ -1509,6 +1511,7 @@ terminal_screen_popup_info_unref (TerminalScreenPopupInfo *info)
 
   g_object_unref (info->screen);
   g_weak_ref_clear (&info->window_weak_ref);
+  g_free (info->hyperlink);
   g_free (info->url);
   g_free (info->number_info);
   g_slice_free (TerminalScreenPopupInfo, info);
@@ -1547,6 +1550,7 @@ terminal_screen_popup_menu (GtkWidget *widget)
 static void
 terminal_screen_do_popup (TerminalScreen *screen,
                           GdkEventButton *event,
+                          char *hyperlink,
                           char *url,
                           int url_flavor,
                           char *number_info)
@@ -1557,6 +1561,7 @@ terminal_screen_do_popup (TerminalScreen *screen,
   info->button = event->button;
   info->state = event->state & gtk_accelerator_get_default_mod_mask ();
   info->timestamp = event->time;
+  info->hyperlink = hyperlink; /* adopted */
   info->url = url; /* adopted */
   info->url_flavor = url_flavor;
   info->number_info = number_info; /* adopted */
@@ -1572,6 +1577,7 @@ terminal_screen_button_press (GtkWidget      *widget,
   TerminalScreen *screen = TERMINAL_SCREEN (widget);
   gboolean (* button_press_event) (GtkWidget*, GdkEventButton*) =
     GTK_WIDGET_CLASS (terminal_screen_parent_class)->button_press_event;
+  gs_free char *hyperlink = NULL;
   gs_free char *url = NULL;
   int url_flavor = 0;
   gs_free char *number_info = NULL;
@@ -1579,9 +1585,25 @@ terminal_screen_button_press (GtkWidget      *widget,
 
   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);
 
+  if (hyperlink != NULL &&
+      (event->button == 1 || event->button == 2) &&
+      (state & GDK_CONTROL_MASK))
+    {
+      gboolean handled = FALSE;
+
+      g_signal_emit (screen, signals[MATCH_CLICKED], 0,
+                     hyperlink,
+                     FLAVOR_AS_IS,
+                     state,
+                     &handled);
+      if (handled)
+        return TRUE; /* don't do anything else such as select with the click */
+    }
+
   if (url != NULL &&
       (event->button == 1 || event->button == 2) &&
       (state & GDK_CONTROL_MASK))
@@ -1606,16 +1628,18 @@ terminal_screen_button_press (GtkWidget      *widget,
           if (button_press_event && button_press_event (widget, event))
             return TRUE;
 
-          terminal_screen_do_popup (screen, event, url, url_flavor, number_info);
-          url = NULL; /* adopted to the popup info */
+          terminal_screen_do_popup (screen, event, hyperlink, url, url_flavor, number_info);
+          hyperlink = NULL; /* adopted to the popup info */
+          url = NULL; /* ditto */
           number_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, url, url_flavor, number_info);
-          url = NULL; /* adopted to the popup info */
+          terminal_screen_do_popup (screen, event, hyperlink, url, url_flavor, number_info);
+          hyperlink = NULL; /* adopted to the popup info */
+          url = NULL; /* ditto */
           number_info = NULL; /* ditto */
           return TRUE;
         }
@@ -1954,6 +1978,13 @@ terminal_screen_get_cell_size (TerminalScreen *screen,
 }
 
 static char*
+terminal_screen_check_hyperlink (TerminalScreen *screen,
+                                 GdkEvent       *event)
+{
+  return vte_terminal_get_hyperlink (VTE_TERMINAL (screen), event);
+}
+
+static char*
 terminal_screen_check_match (TerminalScreen *screen,
                              GdkEvent       *event,
                              int       *flavor)
diff --git a/src/terminal-screen.h b/src/terminal-screen.h
index f3b4013d..2e8f6dc6 100644
--- a/src/terminal-screen.h
+++ b/src/terminal-screen.h
@@ -142,6 +142,7 @@ struct _TerminalScreenPopupInfo {
   TerminalScreen *screen;
   char *url;
   TerminalURLFlavor url_flavor;
+  char *hyperlink;
   char *number_info;
   guint button;
   guint state;
diff --git a/src/terminal-util.c b/src/terminal-util.c
index c3c718a0..b374be33 100644
--- a/src/terminal-util.c
+++ b/src/terminal-util.c
@@ -20,6 +20,7 @@
  */
 
 #include "config.h"
+#define _GNU_SOURCE /* for strchrnul */
 
 #include <string.h>
 #include <stdlib.h>
@@ -1104,3 +1105,54 @@ 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_hyperlink_uri_markup:
+ * @uri: a URI
+ *
+ * Formats @uri to be displayed in a tooltip.
+ * Performs URI-decoding and converts IDN hostname to UTF-8.
+ * Displays both this decoded version and the original if they differ.
+ *
+ * Returns: (transfer full): The formatted URI as pango markup
+ */
+char *terminal_util_hyperlink_uri_markup (const char *uri)
+{
+  gs_free char *unesc = NULL;
+
+  if (uri == NULL)
+    return NULL;
+
+  unesc = g_uri_unescape_string(uri, NULL);
+  if (unesc == NULL)
+    unesc = g_strdup(uri);
+
+  if (g_ascii_strncasecmp(unesc, "ftp://", 6) == 0 ||
+      g_ascii_strncasecmp(unesc, "http://", 7) == 0 ||
+      g_ascii_strncasecmp(unesc, "https://", 8) == 0) {
+    gs_free char *unidn = NULL;
+    char *hostname = strchr(unesc, '/') + 2;
+    char *hostname_end = strchrnul(hostname, '/');
+    char save = *hostname_end;
+    *hostname_end = '\0';
+    unidn = g_hostname_to_unicode(hostname);
+    *hostname_end = save;
+    if (unidn != NULL) {
+      char *new_unesc = g_strdup_printf("%.*s%s%s",
+                                        (int) (hostname - unesc),
+                                        unesc,
+                                        unidn,
+                                        hostname_end);
+      g_free(unesc);
+      unesc = new_unesc;
+    }
+  }
+
+  if (strcmp(unesc, uri) == 0) {
+    return g_markup_escape_text(uri, -1);
+  } else {
+    gs_free char *uri_m = g_markup_escape_text(uri, -1);
+    gs_free char *unesc_m = g_markup_escape_text(unesc, -1);
+    return g_strdup_printf("%s\n<small>(%s)</small>", unesc_m, uri_m);
+  }
+}
diff --git a/src/terminal-util.h b/src/terminal-util.h
index c5e6184d..a6b4e211 100644
--- a/src/terminal-util.h
+++ b/src/terminal-util.h
@@ -95,6 +95,8 @@ void terminal_util_bind_mnemonic_label_sensitivity (GtkWidget *widget);
 
 char *terminal_util_number_info (const char *str);
 
+char *terminal_util_hyperlink_uri_markup (const char *str);
+
 G_END_DECLS
 
 #endif /* TERMINAL_UTIL_H */
diff --git a/src/terminal-window.c b/src/terminal-window.c
index 2921c025..7cf58c0f 100644
--- a/src/terminal-window.c
+++ b/src/terminal-window.c
@@ -1951,6 +1951,38 @@ handle_tab_droped_on_desktop (GtkNotebook *source_notebook,
 /* Terminal screen popup menu handling */
 
 static void
+popup_open_hyperlink_callback (GtkAction *action,
+                               TerminalWindow *window)
+{
+  TerminalWindowPrivate *priv = window->priv;
+  TerminalScreenPopupInfo *info = priv->popup_info;
+
+  if (info == NULL)
+    return;
+
+  terminal_util_open_url (GTK_WIDGET (window), info->hyperlink, FLAVOR_AS_IS,
+                          gtk_get_current_event_time ());
+}
+
+static void
+popup_copy_hyperlink_callback (GtkAction *action,
+                               TerminalWindow *window)
+{
+  TerminalWindowPrivate *priv = window->priv;
+  TerminalScreenPopupInfo *info = priv->popup_info;
+  GtkClipboard *clipboard;
+
+  if (info == NULL)
+    return;
+
+  if (info->hyperlink == NULL)
+    return;
+
+  clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window), GDK_SELECTION_CLIPBOARD);
+  gtk_clipboard_set_text (clipboard, info->hyperlink, -1);
+}
+
+static void
 popup_open_url_callback (GtkAction *action,
                          TerminalWindow *window)
 {
@@ -2054,7 +2086,7 @@ popup_clipboard_targets_received_cb (GtkClipboard *clipboard,
   TerminalScreen *screen = info->screen;
   GtkWidget *popup_menu;
   GtkAction *action;
-  gboolean can_paste, can_paste_uris, show_link, show_email_link, show_call_link, show_number_info;
+  gboolean can_paste, can_paste_uris, show_hyperlink, show_link, show_email_link, show_call_link, show_number_info;
 
   window = terminal_screen_popup_info_ref_window (info);
   if (window == NULL ||
@@ -2072,11 +2104,17 @@ popup_clipboard_targets_received_cb (GtkClipboard *clipboard,
 
   can_paste = targets != NULL && gtk_targets_include_text (targets, n_targets);
   can_paste_uris = targets != NULL && gtk_targets_include_uri (targets, n_targets);
-  show_link = info->url != NULL && (info->url_flavor == FLAVOR_AS_IS || info->url_flavor == FLAVOR_DEFAULT_TO_HTTP);
-  show_email_link = info->url != NULL && info->url_flavor == FLAVOR_EMAIL;
-  show_call_link = info->url != NULL && info->url_flavor == FLAVOR_VOIP_CALL;
+  show_hyperlink = info->hyperlink != NULL;
+  show_link = !show_hyperlink && info->url != NULL && (info->url_flavor == FLAVOR_AS_IS || info->url_flavor == FLAVOR_DEFAULT_TO_HTTP);
+  show_email_link = !show_hyperlink && info->url != NULL && info->url_flavor == FLAVOR_EMAIL;
+  show_call_link = !show_hyperlink && info->url != NULL && info->url_flavor == FLAVOR_VOIP_CALL;
   show_number_info = info->number_info != NULL;
 
+  action = gtk_action_group_get_action (priv->action_group, "PopupOpenHyperlink");
+  gtk_action_set_visible (action, show_hyperlink);
+  action = gtk_action_group_get_action (priv->action_group, "PopupCopyHyperlinkAddress");
+  gtk_action_set_visible (action, show_hyperlink);
+
   action = gtk_action_group_get_action (priv->action_group, "PopupSendEmail");
   gtk_action_set_visible (action, show_email_link);
   action = gtk_action_group_get_action (priv->action_group, "PopupCopyEmailAddress");
@@ -2089,6 +2127,7 @@ popup_clipboard_targets_received_cb (GtkClipboard *clipboard,
   gtk_action_set_visible (action, show_link);
   action = gtk_action_group_get_action (priv->action_group, "PopupCopyLinkAddress");
   gtk_action_set_visible (action, show_link);
+
   action = gtk_action_group_get_action (priv->action_group, "PopupNumberInfo");
   gtk_action_set_label (action, info->number_info);
   gtk_action_set_sensitive (action, FALSE);
@@ -2562,6 +2601,12 @@ terminal_window_init (TerminalWindow *window)
         G_CALLBACK (help_inspector_callback) },
 
       /* Popup menu */
+      { "PopupOpenHyperlink", NULL, N_("_Open Hyperlink"), NULL,
+        NULL,
+        G_CALLBACK (popup_open_hyperlink_callback) },
+      { "PopupCopyHyperlinkAddress", NULL, N_("_Copy Hyperlink Address"), NULL,
+        NULL,
+        G_CALLBACK (popup_copy_hyperlink_callback) },
       { "PopupSendEmail", NULL, N_("_Send Mail To…"), NULL,
         NULL,
         G_CALLBACK (popup_open_url_callback) },
@@ -3082,6 +3127,22 @@ screen_font_any_changed_cb (TerminalScreen *screen,
   terminal_window_update_size (window);
 }
 
+static void
+screen_hyperlink_hover_uri_changed (TerminalScreen *screen,
+                                    const char *uri,
+                                    const GdkRectangle *bbox G_GNUC_UNUSED,
+                                    TerminalWindow *window G_GNUC_UNUSED)
+{
+  gs_free char *markup = NULL;
+
+  if (!gtk_widget_get_realized (GTK_WIDGET (screen)))
+    return;
+
+  markup = terminal_util_hyperlink_uri_markup (uri);
+
+  gtk_widget_set_tooltip_markup (GTK_WIDGET (screen), markup);
+}
+
 /* MDI container callbacks */
 
 static void
@@ -3444,6 +3505,8 @@ mdi_screen_added_cb (TerminalMdiContainer *container,
                     G_CALLBACK (screen_font_any_changed_cb), window);
   g_signal_connect (screen, "selection-changed",
                     G_CALLBACK (terminal_window_update_copy_sensitivity), window);
+  g_signal_connect (screen, "hyperlink-hover-uri-changed",
+                    G_CALLBACK (screen_hyperlink_hover_uri_changed), window);
 
   g_signal_connect (screen, "show-popup-menu",
                     G_CALLBACK (screen_show_popup_menu_callback), window);
@@ -3527,6 +3590,10 @@ mdi_screen_removed_cb (TerminalMdiContainer *container,
                                         G_CALLBACK (terminal_window_update_copy_sensitivity),
                                         window);
 
+  g_signal_handlers_disconnect_by_func (G_OBJECT (screen),
+                                        G_CALLBACK (screen_hyperlink_hover_uri_changed),
+                                        window);
+
   g_signal_handlers_disconnect_by_func (screen,
                                         G_CALLBACK (screen_show_popup_menu_callback),
                                         window);
diff --git a/src/terminal.xml b/src/terminal.xml
index d830149a..e72e5952 100644
--- a/src/terminal.xml
+++ b/src/terminal.xml
@@ -78,6 +78,9 @@
   </menubar>
 
   <popup name="Popup" action="Popup">
+    <menuitem action="PopupOpenHyperlink" />
+    <menuitem action="PopupCopyHyperlinkAddress" />
+    <separator />
     <menuitem action="PopupSendEmail" />
     <menuitem action="PopupCopyEmailAddress" />
     <menuitem action="PopupCall" />
