summary refs log tree commit diff stats
path: root/src/fe-gtk
diff options
context:
space:
mode:
authorTingPing <tingping@tingping.se>2013-01-08 13:09:33 -0800
committerTingPing <tingping@tingping.se>2013-01-08 13:09:33 -0800
commitc8419ae43a3384da2ffbc30f855eaf45b79c883e (patch)
tree286916393bf0e7835da0d7debc472b6e6adedb5c /src/fe-gtk
parent0213f21a46001cedd8b1c2d5e362b359214636d8 (diff)
parentccc82895edfd1a0c0e7f8d4c18dc2dac720881e8 (diff)
Merge pull request #359 from RichardHitt/master
Overhaul of URL detection, includes nick, channel, etc
Diffstat (limited to 'src/fe-gtk')
-rw-r--r--src/fe-gtk/fe-gtk.c2
-rw-r--r--src/fe-gtk/maingui.c65
-rw-r--r--src/fe-gtk/xtext.c123
-rw-r--r--src/fe-gtk/xtext.h4
4 files changed, 117 insertions, 77 deletions
diff --git a/src/fe-gtk/fe-gtk.c b/src/fe-gtk/fe-gtk.c
index 9f6c439a..2767fc52 100644
--- a/src/fe-gtk/fe-gtk.c
+++ b/src/fe-gtk/fe-gtk.c
@@ -1059,7 +1059,7 @@ static void
 fe_open_url_locale (const char *url)
 {
 	/* the http:// part's missing, prepend it, otherwise it won't always work */
-	if (strchr (url, ':') == NULL && url_check_word (url, strlen (url)) != WORD_PATH)
+	if (strchr (url, ':') == NULL && url_check_word (url) != WORD_PATH)
 	{
 		url = g_strdup_printf ("http://%s", url);
 		fe_open_url_inner (url);
diff --git a/src/fe-gtk/maingui.c b/src/fe-gtk/maingui.c
index 388ca97d..fee8f320 100644
--- a/src/fe-gtk/maingui.c
+++ b/src/fe-gtk/maingui.c
@@ -2244,20 +2244,14 @@ mg_create_topicbar (session *sess, GtkWidget *box)
 /* check if a word is clickable */
 
 static int
-mg_word_check (GtkWidget * xtext, char *word, int len)
+mg_word_check (GtkWidget * xtext, char *word)
 {
 	session *sess = current_sess;
 	int ret;
 
-	ret = url_check_word (word, len);	/* common/url.c */
-	if (ret == 0)
-	{
-		if (( (word[0]=='@' || word[0]=='+' || word[0]=='%') && userlist_find (sess, word+1)) || userlist_find (sess, word))
-			return WORD_NICK;
-
-		if (sess->type == SESS_DIALOG)
-			return WORD_DIALOG;
-	}
+	ret = url_check_word (word);
+	if (ret == 0 && sess->type == SESS_DIALOG)
+		return WORD_DIALOG;
 
 	return ret;
 }
@@ -2268,23 +2262,28 @@ static void
 mg_word_clicked (GtkWidget *xtext, char *word, GdkEventButton *even)
 {
 	session *sess = current_sess;
+	int word_type, start, end;
+	char *tmp;
 
-	if (even->button == 1)			/* left button */
+	if (word == NULL)
 	{
-		if (word == NULL)
-		{
+		if (even->button == 1)		/* left button */
 			mg_focus (sess);
-			return;
-		}
+		return;
+	}
+
+	word_type = mg_word_check (xtext, word);
+	url_last (&start, &end);
 
-		if ((even->state & 13) == prefs.hex_gui_url_mod)
+	if (even->button == 1 && (even->state & 13) == prefs.hex_gui_url_mod)
+	{
+		switch (word_type)
 		{
-			switch (mg_word_check (xtext, word, strlen (word)))
-			{
-			case WORD_URL:
-			case WORD_HOST:
-				fe_open_url (word);
-			}
+		case WORD_URL:
+		case WORD_HOST:
+			word[end] = 0;
+			word += start;
+			fe_open_url (word);
 		}
 		return;
 	}
@@ -2298,7 +2297,7 @@ mg_word_clicked (GtkWidget *xtext, char *word, GdkEventButton *even)
 		return;
 	}
 
-	switch (mg_word_check (xtext, word, strlen (word)))
+	switch (word_type)
 	{
 	case 0:
 	case WORD_PATH:
@@ -2306,26 +2305,22 @@ mg_word_clicked (GtkWidget *xtext, char *word, GdkEventButton *even)
 		break;
 	case WORD_URL:
 	case WORD_HOST:
+		word[end] = 0;
+		word += start;
 		menu_urlmenu (even, word);
 		break;
 	case WORD_NICK:
-		menu_nickmenu (sess, even, (word[0]=='@' || word[0]=='+' || word[0]=='%') ?
-			word+1 : word, FALSE);
+		menu_nickmenu (sess, even, word + (ispunct (*word)? 1: 0), FALSE);
 		break;
 	case WORD_CHANNEL:
-		if (*word == '@' || *word == '+' || *word=='^' || *word=='%' || *word=='*')
-			word++;
 		menu_chanmenu (sess, even, word);
 		break;
 	case WORD_EMAIL:
-		{
-			char *newword = malloc (strlen (word) + 10);
-			if (*word == '~')
-				word++;
-			sprintf (newword, "mailto:%s", word);
-			menu_urlmenu (even, newword);
-			free (newword);
-		}
+		word[end] = 0;
+		word += start;
+		tmp = g_strdup_printf("mailto:%s", word + (ispunct (*word)? 1: 0));
+		menu_urlmenu (even, tmp);
+		g_free (tmp);
 		break;
 	case WORD_DIALOG:
 		menu_nickmenu (sess, even, sess->channel, FALSE);
diff --git a/src/fe-gtk/xtext.c b/src/fe-gtk/xtext.c
index e8419b5a..e2dc2b7c 100644
--- a/src/fe-gtk/xtext.c
+++ b/src/fe-gtk/xtext.c
@@ -73,6 +73,7 @@
 #include "../common/fe.h"
 #include "../common/util.h"
 #include "../common/hexchatc.h"
+#include "../common/url.h"
 #include "fe-gtk.h"
 #include "xtext.h"
 #include "fkeys.h"
@@ -1901,7 +1902,7 @@ gtk_xtext_selection_update (GtkXText * xtext, GdkEventMotion * event, int p_y, g
 
 static char *
 gtk_xtext_get_word (GtkXText * xtext, int x, int y, textentry ** ret_ent,
-						  int *ret_off, int *ret_len)
+						  int *ret_off, int *ret_len, GSList **slp)
 {
 	textentry *ent;
 	int offset;
@@ -1950,9 +1951,9 @@ gtk_xtext_get_word (GtkXText * xtext, int x, int y, textentry ** ret_ent,
 	if (ret_off)
 		*ret_off = word - ent->str;
 	if (ret_len)
-		*ret_len = str - word;
+		*ret_len = len;		/* Length before stripping */
 
-	return gtk_xtext_strip_color (word, len, xtext->scratch_buffer, NULL, NULL, NULL, FALSE);
+	return gtk_xtext_strip_color (word, len, xtext->scratch_buffer, NULL, NULL, slp, FALSE);
 }
 
 #ifdef MOTION_MONITOR
@@ -2028,14 +2029,62 @@ gtk_xtext_check_mark_stamp (GtkXText *xtext, GdkModifierType mask)
 	return redraw;
 }
 
+static int
+gtk_xtext_get_word_adjust (GtkXText *xtext, int x, int y, textentry **word_ent, int *offset, int *len)
+{
+	GSList *slp = NULL;
+	unsigned char *word;
+	int word_type = 0;
+
+	word = gtk_xtext_get_word (xtext, x, y, word_ent, offset, len, &slp);
+	if (word)
+	{
+		int laststart, lastend;
+
+		word_type = xtext->urlcheck_function (GTK_WIDGET (xtext), word);
+		if (word_type > 0)
+		{
+			if (url_last (&laststart, &lastend))
+			{
+				int cumlen, startadj = 0, endadj = 0;
+				offlen_t o;
+				GSList *sl;
+
+				for (sl = slp, cumlen = 0; sl; sl = g_slist_next (sl))
+				{
+					o.u = GPOINTER_TO_UINT (sl->data);
+					startadj = o.o.off - cumlen;
+					cumlen += o.o.len;
+					if (laststart < cumlen)
+						break;
+				}
+				for (sl = slp, cumlen = 0; sl; sl = g_slist_next (sl))
+				{
+					o.u = GPOINTER_TO_UINT (sl->data);
+					endadj = o.o.off - cumlen;
+					cumlen += o.o.len;
+					if (lastend < cumlen)
+						break;
+				}
+				laststart += startadj;
+				*offset += laststart;
+				*len = lastend + endadj - laststart;
+			}
+		}
+	}
+	g_slist_free (slp);
+
+	return word_type;
+}
+
 static gboolean
 gtk_xtext_motion_notify (GtkWidget * widget, GdkEventMotion * event)
 {
 	GtkXText *xtext = GTK_XTEXT (widget);
 	GdkModifierType mask;
 	int redraw, tmp, x, y, offset, len, line_x;
-	unsigned char *word;
 	textentry *word_ent;
+	int word_type;
 
 	gdk_window_get_pointer (widget->window, &x, &y, &mask);
 
@@ -2104,43 +2153,40 @@ gtk_xtext_motion_notify (GtkWidget * widget, GdkEventMotion * event)
 	if (xtext->urlcheck_function == NULL)
 		return FALSE;
 
-	word = gtk_xtext_get_word (xtext, x, y, &word_ent, &offset, &len);
-	if (word)
+	word_type = gtk_xtext_get_word_adjust (xtext, x, y, &word_ent, &offset, &len);
+	if (word_type > 0)
 	{
-		if (xtext->urlcheck_function (GTK_WIDGET (xtext), word, len) > 0)
+		if (!xtext->cursor_hand ||
+			 xtext->hilight_ent != word_ent ||
+			 xtext->hilight_start != offset ||
+			 xtext->hilight_end != offset + len)
 		{
-			if (!xtext->cursor_hand ||
-				 xtext->hilight_ent != word_ent ||
-				 xtext->hilight_start != offset ||
-				 xtext->hilight_end != offset + len)
+			if (!xtext->cursor_hand)
 			{
-				if (!xtext->cursor_hand)
-				{
-					gdk_window_set_cursor (GTK_WIDGET (xtext)->window,
-											  		xtext->hand_cursor);
-					xtext->cursor_hand = TRUE;
-				}
+				gdk_window_set_cursor (GTK_WIDGET (xtext)->window,
+										  		xtext->hand_cursor);
+				xtext->cursor_hand = TRUE;
+			}
 
-				/* un-render the old hilight */
-				if (xtext->hilight_ent)
-					gtk_xtext_unrender_hilight (xtext);
+			/* un-render the old hilight */
+			if (xtext->hilight_ent)
+				gtk_xtext_unrender_hilight (xtext);
 
-				xtext->hilight_ent = word_ent;
-				xtext->hilight_start = offset;
-				xtext->hilight_end = offset + len;
+			xtext->hilight_ent = word_ent;
+			xtext->hilight_start = offset;
+			xtext->hilight_end = offset + len;
 
-				xtext->skip_border_fills = TRUE;
-				xtext->render_hilights_only = TRUE;
-				xtext->skip_stamp = TRUE;
+			xtext->skip_border_fills = TRUE;
+			xtext->render_hilights_only = TRUE;
+			xtext->skip_stamp = TRUE;
 
-				gtk_xtext_render_ents (xtext, word_ent, NULL);
+			gtk_xtext_render_ents (xtext, word_ent, NULL);
 
-				xtext->skip_border_fills = FALSE;
-				xtext->render_hilights_only = FALSE;
-				xtext->skip_stamp = FALSE;
-			}
-			return FALSE;
+			xtext->skip_border_fills = FALSE;
+			xtext->render_hilights_only = FALSE;
+			xtext->skip_stamp = FALSE;
 		}
+		return FALSE;
 	}
 
 	gtk_xtext_leave_notify (widget, NULL);
@@ -2280,7 +2326,7 @@ gtk_xtext_button_release (GtkWidget * widget, GdkEventButton * event)
 
 		if (!xtext->hilighting)
 		{
-			word = gtk_xtext_get_word (xtext, event->x, event->y, 0, 0, 0);
+			word = gtk_xtext_get_word (xtext, event->x, event->y, 0, 0, 0, 0);
 			g_signal_emit (G_OBJECT (xtext), xtext_signals[WORD_CLICK], 0, word ? word : NULL, event);
 		} else
 		{
@@ -2288,7 +2334,6 @@ gtk_xtext_button_release (GtkWidget * widget, GdkEventButton * event)
 		}
 	}
 
-
 	return FALSE;
 }
 
@@ -2305,7 +2350,7 @@ gtk_xtext_button_press (GtkWidget * widget, GdkEventButton * event)
 
 	if (event->button == 3 || event->button == 2) /* right/middle click */
 	{
-		word = gtk_xtext_get_word (xtext, x, y, 0, 0, 0);
+		word = gtk_xtext_get_word (xtext, x, y, 0, 0, 0, 0);
 		if (word)
 		{
 			g_signal_emit (G_OBJECT (xtext), xtext_signals[WORD_CLICK], 0,
@@ -2322,7 +2367,7 @@ gtk_xtext_button_press (GtkWidget * widget, GdkEventButton * event)
 	if (event->type == GDK_2BUTTON_PRESS)	/* WORD select */
 	{
 		gtk_xtext_check_mark_stamp (xtext, mask);
-		if (gtk_xtext_get_word (xtext, x, y, &ent, &offset, &len))
+		if (gtk_xtext_get_word (xtext, x, y, &ent, &offset, &len, 0))
 		{
 			if (len == 0)
 				return FALSE;
@@ -2343,7 +2388,7 @@ gtk_xtext_button_press (GtkWidget * widget, GdkEventButton * event)
 	if (event->type == GDK_3BUTTON_PRESS)	/* LINE select */
 	{
 		gtk_xtext_check_mark_stamp (xtext, mask);
-		if (gtk_xtext_get_word (xtext, x, y, &ent, 0, 0))
+		if (gtk_xtext_get_word (xtext, x, y, &ent, 0, 0, 0))
 		{
 			gtk_xtext_selection_clear (xtext->buffer);
 			ent->mark_start = 0;
@@ -2852,7 +2897,7 @@ gtk_xtext_render_flush (GtkXText * xtext, int x, int y, unsigned char *str,
 {
 	int str_width, dofill;
 	GdkDrawable *pix = NULL;
-	int dest_x, dest_y;
+	int dest_x = 0, dest_y = 0;
 
 	if (xtext->dont_render || len < 1 || xtext->hidden)
 		return 0;
@@ -5904,7 +5949,7 @@ gtk_xtext_set_tint (GtkXText *xtext, int tint_red, int tint_green, int tint_blue
 }
 
 void
-gtk_xtext_set_urlcheck_function (GtkXText *xtext, int (*urlcheck_function) (GtkWidget *, char *, int))
+gtk_xtext_set_urlcheck_function (GtkXText *xtext, int (*urlcheck_function) (GtkWidget *, char *))
 {
 	xtext->urlcheck_function = urlcheck_function;
 }
diff --git a/src/fe-gtk/xtext.h b/src/fe-gtk/xtext.h
index 48c71d0c..cc6bbebb 100644
--- a/src/fe-gtk/xtext.h
+++ b/src/fe-gtk/xtext.h
@@ -179,7 +179,7 @@ struct _GtkXText
 	unsigned char scratch_buffer[4096];
 
 	void (*error_function) (int type);
-	int (*urlcheck_function) (GtkWidget * xtext, char *word, int len);
+	int (*urlcheck_function) (GtkWidget * xtext, char *word);
 
 	int jump_out_offset;	/* point at which to stop rendering */
 	int jump_in_offset;	/* "" start rendering */
@@ -274,7 +274,7 @@ void gtk_xtext_set_show_separator (GtkXText *xtext, gboolean show_separator);
 void gtk_xtext_set_thin_separator (GtkXText *xtext, gboolean thin_separator);
 void gtk_xtext_set_time_stamp (xtext_buffer *buf, gboolean timestamp);
 void gtk_xtext_set_tint (GtkXText *xtext, int tint_red, int tint_green, int tint_blue);
-void gtk_xtext_set_urlcheck_function (GtkXText *xtext, int (*urlcheck_function) (GtkWidget *, char *, int));
+void gtk_xtext_set_urlcheck_function (GtkXText *xtext, int (*urlcheck_function) (GtkWidget *, char *));
 void gtk_xtext_set_wordwrap (GtkXText *xtext, gboolean word_wrap);
 
 xtext_buffer *gtk_xtext_buffer_new (GtkXText *xtext);