overhauling of URL detection, including channel, nick, etc 'words'

This commit is contained in:
RichardHitt
2013-01-02 14:50:26 -08:00
parent 7f2846a5bd
commit 4af624627e
10 changed files with 402 additions and 280 deletions

View File

@@ -1058,7 +1058,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);

View File

@@ -2242,20 +2242,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;
}
@@ -2266,23 +2260,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;
}
if ((even->state & 13) == prefs.hex_gui_url_mod)
word_type = mg_word_check (xtext, word);
url_last (&start, &end);
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;
}
@@ -2296,7 +2295,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:
@@ -2304,26 +2303,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);
menu_chanmenu (sess, even, word + (ispunct (*word)? 1: 0));
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);

View File

@@ -13,7 +13,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
* =========================================================================
*
* xtext, the text widget used by X-Chat.
@@ -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;
}
/* 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->skip_border_fills = TRUE;
xtext->render_hilights_only = TRUE;
xtext->skip_stamp = TRUE;
gtk_xtext_render_ents (xtext, word_ent, NULL);
xtext->skip_border_fills = FALSE;
xtext->render_hilights_only = FALSE;
xtext->skip_stamp = FALSE;
gdk_window_set_cursor (GTK_WIDGET (xtext)->window,
xtext->hand_cursor);
xtext->cursor_hand = TRUE;
}
return FALSE;
/* 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->skip_border_fills = TRUE;
xtext->render_hilights_only = TRUE;
xtext->skip_stamp = TRUE;
gtk_xtext_render_ents (xtext, word_ent, NULL);
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;
}

View File

@@ -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);