Index: gnome-terminal-3.6.2/src/terminal-screen.c
===================================================================
--- gnome-terminal-3.6.2.orig/src/terminal-screen.c
+++ gnome-terminal-3.6.2/src/terminal-screen.c
@@ -50,6 +50,7 @@
#include "eggshell.h"
#define URL_MATCH_CURSOR (GDK_HAND2)
+static const gchar *hints = "0123456789abcdefghijklmnopqrstuvwxyzABDEFGHIJKLMNOPQRSTUVWXYZ";
typedef struct
{
@@ -75,8 +76,16 @@ struct _TerminalScreenPrivate
gboolean user_title; /* title was manually set */
GSList *match_tags;
guint launch_child_source_id;
+ GSList *urls;
};
+typedef struct {
+ gchar *uri;
+ gint flavor;
+ guint x;
+ guint y;
+} HintData;
+
enum
{
PROFILE_SET,
@@ -115,11 +124,15 @@ static void terminal_screen_drag_data_re
GtkSelectionData *selection_data,
guint info,
guint time);
+static gboolean terminal_screen_draw (GtkWidget *widget,
+ cairo_t *cr);
static void terminal_screen_system_font_notify_cb (TerminalApp *app,
GParamSpec *pspec,
TerminalScreen *screen);
static void terminal_screen_change_font (TerminalScreen *screen);
static gboolean terminal_screen_popup_menu (GtkWidget *widget);
+static gboolean terminal_screen_key_press (GtkWidget *widget,
+ GdkEventKey *event);
static gboolean terminal_screen_button_press (GtkWidget *widget,
GdkEventButton *event);
static void terminal_screen_launch_child_on_idle (TerminalScreen *screen);
@@ -236,6 +249,28 @@ free_tag_data (TagData *tagdata)
g_slice_free (TagData, tagdata);
}
+static gint _hint_compare(gconstpointer a,
+ gconstpointer b)
+{
+ const HintData *ah = a;
+ const HintData *bh = b;
+
+ if (ah->y != bh->y)
+ {
+ return bh->y - ah->y;
+ }
+ return bh->x - ah->x;
+}
+
+static void _hint_free(gpointer data)
+{
+ const HintData *h = data;
+
+ g_free (h->uri);
+ g_free (data);
+}
+
+
static void
terminal_screen_class_enable_menu_bar_accel_notify_cb (TerminalApp *app,
GParamSpec *pspec,
@@ -525,7 +560,9 @@ terminal_screen_class_init (TerminalScre
#endif
widget_class->drag_data_received = terminal_screen_drag_data_received;
widget_class->button_press_event = terminal_screen_button_press;
+ widget_class->key_press_event = terminal_screen_key_press;
widget_class->popup_menu = terminal_screen_popup_menu;
+ widget_class->draw = terminal_screen_draw;
terminal_class->child_exited = terminal_screen_child_exited;
@@ -1600,10 +1637,52 @@ terminal_screen_popup_menu (GtkWidget *w
}
static gboolean
+terminal_screen_key_press (GtkWidget *widget,
+ GdkEventKey *event)
+{
+ TerminalScreen *screen = TERMINAL_SCREEN (widget);
+ TerminalScreenPrivate *priv = screen->priv;
+
+ if (priv->urls)
+ {
+ const gchar *i;
+ if (event->length == 1 && (i = strchr (hints, event->string[0])))
+ {
+ gboolean handled = FALSE;
+ char *matched_string;
+ int matched_flavor = 0;
+ HintData *h = g_slist_nth_data (priv->urls, i - hints);
+
+ if (!h)
+ {
+ return TRUE;
+ }
+ g_signal_emit (screen, signals[MATCH_CLICKED], 0,
+ h->uri,
+ h->flavor,
+ 0,
+ &handled);
+ }
+ else if (event->keyval != GDK_KEY_Escape)
+ {
+ return TRUE;
+ }
+ g_slist_free_full (priv->urls, _hint_free);
+ priv->urls = NULL;
+ gtk_widget_queue_draw (widget);
+
+ return TRUE;
+ }
+
+ return GTK_WIDGET_CLASS (terminal_screen_parent_class)->key_press_event (widget, event);
+}
+
+static gboolean
terminal_screen_button_press (GtkWidget *widget,
GdkEventButton *event)
{
TerminalScreen *screen = TERMINAL_SCREEN (widget);
+ TerminalScreenPrivate *priv = screen->priv;
gboolean (* button_press_event) (GtkWidget*, GdkEventButton*) =
GTK_WIDGET_CLASS (terminal_screen_parent_class)->button_press_event;
int char_width, char_height, row, col;
@@ -1612,6 +1691,13 @@ terminal_screen_button_press (GtkWidget
guint state;
GtkBorder *inner_border = NULL;
+ if (priv->urls)
+ {
+ g_object_unref (priv->urls);
+ priv->urls = NULL;
+ gtk_widget_queue_draw (widget);
+ }
+
state = event->state & gtk_accelerator_get_default_mod_mask ();
terminal_screen_get_cell_size (screen, &char_width, &char_height);
@@ -2329,3 +2415,122 @@ terminal_screen_has_foreground_process (
return TRUE;
#endif
}
+
+void
+terminal_screen_uri_launch (TerminalScreen *screen)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+ GArray *attrs = g_array_new (FALSE, TRUE, sizeof (VteCharAttributes));
+
+ guint i = 0;
+
+ gchar *tmp = vte_terminal_get_text (VTE_TERMINAL (screen),
+ NULL, NULL, attrs);
+ long r0 = g_array_index (attrs, VteCharAttributes, 0).row;
+
+ for (i = 0; i < n_url_regexes; ++i)
+ {
+ GMatchInfo *match = NULL;
+ g_regex_match (url_regexes[i],
+ tmp,
+ 0,
+ &match);
+ while (g_match_info_matches (match))
+ {
+ gint s, e;
+ HintData *hint = g_new0 (HintData, 1);
+ VteCharAttributes *attr;
+
+ g_match_info_fetch_pos (match, 0, &s, &e);
+ attr = &g_array_index (attrs, VteCharAttributes, s);
+
+ hint->uri = g_match_info_fetch (match, 0);
+ hint->x = attr->column;
+ hint->y = attr->row - r0;
+ hint->flavor = url_regex_patterns[i].flavor;
+
+ priv->urls = g_slist_insert_sorted (priv->urls,
+ hint,
+ _hint_compare);
+
+ g_match_info_next (match, NULL);
+ }
+ g_match_info_free (match);
+ }
+
+ if (priv->urls)
+ {
+ gtk_widget_queue_draw (GTK_WIDGET (screen));
+ }
+
+ g_free (tmp);
+ g_array_free (attrs, TRUE);
+}
+
+static gboolean
+terminal_screen_draw (GtkWidget* widget,
+ cairo_t* cr)
+{
+ TerminalScreen *screen = TERMINAL_SCREEN (widget);
+ TerminalScreenPrivate *priv = screen->priv;
+
+ GTK_WIDGET_CLASS (terminal_screen_parent_class)->draw (widget, cr);
+
+ if (priv->urls)
+ {
+ GSList *iter;
+
+ GtkWidgetPath *path = gtk_widget_path_new ();
+ GtkStyleContext *context = gtk_style_context_new ();
+ int char_width, char_height;
+ GtkBorder *inner_border;
+ guint i = 0;
+
+ gtk_widget_path_append_type (path, GTK_TYPE_WINDOW);
+
+ gtk_style_context_set_path (context, path);
+ gtk_widget_path_unref (path);
+
+ gtk_style_context_set_screen (context, gtk_widget_get_screen (widget));
+ gtk_style_context_add_class (context, GTK_STYLE_CLASS_TOOLTIP);
+
+ terminal_screen_get_cell_size (screen, &char_width, &char_height);
+
+ gtk_widget_style_get (widget, "inner-border", &inner_border, NULL);
+
+ for (iter = priv->urls; iter != NULL && hints[i] != '\0'; iter = g_slist_next (iter))
+ {
+ HintData *h = iter->data;
+ gint x, y;
+ PangoLayout *layout;
+ gchar hint[2] = " ";
+ hint[0] = hints[i++];
+
+ x = h->x;
+ y = h->y;
+
+ layout = gtk_widget_create_pango_layout (widget, hint);
+ pango_layout_set_font_description (layout,
+ vte_terminal_get_font (VTE_TERMINAL (widget)));
+
+ gtk_render_background (context, cr,
+ (inner_border ? inner_border->left : 0) + x * char_width - 6,
+ (inner_border ? inner_border->top : 0) + y * char_height - 6,
+ char_width + 12, char_height + 12);
+ gtk_render_frame (context, cr,
+ (inner_border ? inner_border->left : 0) + x * char_width - 6,
+ (inner_border ? inner_border->top : 0) + y * char_height - 6,
+ char_width + 12, char_height + 12);
+
+ gtk_render_layout (context, cr,
+ (inner_border ? inner_border->left : 0) + x * char_width,
+ (inner_border ? inner_border->top : 0) + y * char_height,
+ layout);
+ g_object_unref (layout);
+ }
+
+ g_object_unref (context);
+ }
+
+ return FALSE;
+}
Index: gnome-terminal-3.6.2/src/terminal-screen.h
===================================================================
--- gnome-terminal-3.6.2.orig/src/terminal-screen.h
+++ gnome-terminal-3.6.2/src/terminal-screen.h
@@ -155,6 +155,8 @@ TerminalScreenPopupInfo *terminal_screen
void terminal_screen_popup_info_unref (TerminalScreenPopupInfo *info);
+void terminal_screen_uri_launch (TerminalScreen *screen);
+
G_END_DECLS
#endif /* TERMINAL_SCREEN_H */
Index: gnome-terminal-3.6.2/src/terminal-window.c
===================================================================
--- gnome-terminal-3.6.2.orig/src/terminal-window.c
+++ gnome-terminal-3.6.2/src/terminal-window.c
@@ -204,6 +204,8 @@ static void search_find_prev_callback
TerminalWindow *window);
static void search_clear_highlight_callback (GtkAction *action,
TerminalWindow *window);
+static void search_launch_urls_callback (GtkAction *action,
+ TerminalWindow *window);
static void terminal_set_title_callback (GtkAction *action,
TerminalWindow *window);
static void terminal_add_encoding_callback (GtkAction *action,
@@ -1885,6 +1887,9 @@ terminal_window_init (TerminalWindow *wi
{ "SearchClearHighlight", NULL, N_("_Clear Highlight"), "<shift><control>J",
NULL,
G_CALLBACK (search_clear_highlight_callback) },
+ { "SearchLaunchUrls", NULL, N_("_Launch URL"), "<shift><control>L",
+ NULL,
+ G_CALLBACK (search_launch_urls_callback) },
#if 0
{ "SearchGoToLine", GTK_STOCK_JUMP_TO, N_("Go to _Line..."), "<shift><control>I",
NULL,
@@ -3822,6 +3827,19 @@ search_clear_highlight_callback (GtkActi
}
static void
+search_launch_urls_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ GtkTreeModel *urls;
+ GtkTreeIter iter;
+
+ if (G_UNLIKELY (!window->priv->active_screen))
+ return;
+
+ terminal_screen_uri_launch (window->priv->active_screen);
+}
+
+static void
terminal_set_title_dialog_response_cb (GtkWidget *dialog,
int response,
TerminalScreen *screen)
Index: gnome-terminal-3.6.2/src/terminal.xml
===================================================================
--- gnome-terminal-3.6.2.orig/src/terminal.xml
+++ gnome-terminal-3.6.2/src/terminal.xml
@@ -35,6 +35,7 @@
<menuitem action="SearchFind"/>
<menuitem action="SearchFindNext"/>
<menuitem action="SearchFindPrevious"/>
+ <menuitem action="SearchLaunchUrls"/>
<!--
<menuitem action="SearchIncrementalSearch"/>
-->