summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSadrul Habib Chowdhury <sadrul@pidgin.im>2008-11-23 18:30:31 +0000
committerSadrul Habib Chowdhury <sadrul@pidgin.im>2008-11-23 18:30:31 +0000
commitf183a7b6b9989f3deabc4efa9d57344a4ea42f92 (patch)
treea928d3d36d2e27c7e1bee5e52d7f66cca190e279
parentff98c8876120439643ebb06e10df7fe1a9c5e74b (diff)
downloadpidgin-imhtml.customlinks.tar.gz
Clean up some crufts. I think this is now mergeable with .next.minor.imhtml.customlinks
-rw-r--r--ChangeLog.API3
-rw-r--r--pidgin/gtkimhtml.c174
-rw-r--r--pidgin/gtkimhtml.h51
-rw-r--r--pidgin/gtkutils.c79
4 files changed, 199 insertions, 108 deletions
diff --git a/ChangeLog.API b/ChangeLog.API
index 22550eb4cc..02ca649325 100644
--- a/ChangeLog.API
+++ b/ChangeLog.API
@@ -4,6 +4,9 @@ version 2.6.0 (??/??/????):
pidgin:
Added:
* gtk_imhtml_class_register_protocol
+ * gtk_imhtml_link_get_url, gtk_imhtml_link_get_text_tag,
+ gtk_imhtml_link_activate functions to process GtkIMHtmlLink objects
+ from GtkIMHtml protocol callbacks.
* pidgin_utils_init, pidgin_utils_uninit
version 2.5.0 (08/18/2008):
diff --git a/pidgin/gtkimhtml.c b/pidgin/gtkimhtml.c
index fe0386b814..bc14d0798d 100644
--- a/pidgin/gtkimhtml.c
+++ b/pidgin/gtkimhtml.c
@@ -88,13 +88,20 @@ struct im_image_data {
GtkTextMark *mark;
};
+struct _GtkIMHtmlLink
+{
+ GtkIMHtml *imhtml;
+ gchar *url;
+ GtkTextTag *tag;
+};
+
typedef struct _GtkIMHtmlProtocol
{
char *name;
int length;
- gboolean (*activate)(GtkIMHtml *imhtml, const char *text);
- gboolean (*context_menu)(GtkIMHtml *imhtml, const char *text, GtkWidget *menu);
+ gboolean (*activate)(GtkIMHtml *imhtml, GtkIMHtmlLink *link);
+ gboolean (*context_menu)(GtkIMHtml *imhtml, GtkIMHtmlLink *link, GtkWidget *menu);
} GtkIMHtmlProtocol;
static gboolean
@@ -125,6 +132,8 @@ static void imhtml_font_grow(GtkIMHtml *imhtml);
static void imhtml_font_shrink(GtkIMHtml *imhtml);
static void imhtml_clear_formatting(GtkIMHtml *imhtml);
static int gtk_imhtml_is_protocol(const char *text);
+static void gtk_imhtml_activate_tag(GtkIMHtml *imhtml, GtkTextTag *tag);
+static void gtk_imhtml_link_destroy(GtkIMHtmlLink *link);
/* POINT_SIZE converts from AIM font sizes to a point size scale factor. */
#define MAX_FONT_SIZE 7
@@ -1422,9 +1431,14 @@ static void
imhtml_url_clicked(GtkIMHtml *imhtml, const char *url)
{
GtkIMHtmlProtocol *proto = imhtml_find_protocol(url);
+ GtkIMHtmlLink *link;
if (!proto)
return;
- proto->activate(imhtml, url); /* XXX: Do something with the return value? */
+ link = g_new0(GtkIMHtmlLink, 1);
+ link->imhtml = g_object_ref(imhtml);
+ link->url = g_strdup(url);
+ proto->activate(imhtml, link); /* XXX: Do something with the return value? */
+ gtk_imhtml_link_destroy(link);
}
/* Boring GTK+ stuff */
@@ -1725,37 +1739,14 @@ GType gtk_imhtml_get_type()
return imhtml_type;
}
-struct url_data {
- GObject *object;
- gchar *url;
- GtkTextTag *tag;
-};
-
-static void url_data_destroy(gpointer mydata)
-{
- struct url_data *data = mydata;
- g_object_unref(data->object);
- g_object_unref(data->tag);
- g_free(data->url);
- g_free(data);
-}
-
-static void url_open(GtkWidget *w, struct url_data *data)
+static void gtk_imhtml_link_destroy(GtkIMHtmlLink *link)
{
- if(!data) return;
- g_signal_emit(data->object, signals[URL_CLICKED], 0, data->url);
- g_object_set_data(G_OBJECT(data->tag), "visited", GINT_TO_POINTER(TRUE));
- gtk_imhtml_set_link_color(GTK_IMHTML(data->object), data->tag);
-}
-
-static void url_copy(GtkWidget *w, gchar *url) {
- GtkClipboard *clipboard;
-
- clipboard = gtk_widget_get_clipboard(w, GDK_SELECTION_PRIMARY);
- gtk_clipboard_set_text(clipboard, url, -1);
-
- clipboard = gtk_widget_get_clipboard(w, GDK_SELECTION_CLIPBOARD);
- gtk_clipboard_set_text(clipboard, url, -1);
+ if (link->imhtml)
+ g_object_unref(link->imhtml);
+ if (link->tag)
+ g_object_unref(link->tag);
+ g_free(link->url);
+ g_free(link);
}
/* The callback for an event on a link tag. */
@@ -1771,22 +1762,16 @@ static gboolean tag_event(GtkTextTag *tag, GObject *imhtml, GdkEvent *event, Gtk
if (gtk_text_buffer_get_selection_bounds(
gtk_text_iter_get_buffer(arg2), &start, &end))
return FALSE;
-
- /* A link was clicked--we emit the "url_clicked" signal
- * with the URL as the argument */
- g_object_ref(G_OBJECT(tag));
- g_signal_emit(imhtml, signals[URL_CLICKED], 0, g_object_get_data(G_OBJECT(tag), "link_url"));
- g_object_unref(G_OBJECT(tag));
- g_object_set_data(G_OBJECT(tag), "visited", GINT_TO_POINTER(TRUE));
- gtk_imhtml_set_link_color(GTK_IMHTML(imhtml), tag);
+ gtk_imhtml_activate_tag(GTK_IMHTML(imhtml), tag);
return FALSE;
} else if(event_button->button == 3) {
- GtkWidget *img, *item, *menu;
+ GList *children;
+ GtkWidget *menu;
GtkIMHtmlProtocol *proto;
- struct url_data *tempdata = g_new(struct url_data, 1);
- tempdata->object = g_object_ref(imhtml);
- tempdata->url = g_strdup(g_object_get_data(G_OBJECT(tag), "link_url"));
- tempdata->tag = g_object_ref(tag);
+ GtkIMHtmlLink *link = g_new(GtkIMHtmlLink, 1);
+ link->imhtml = g_object_ref(imhtml);
+ link->url = g_strdup(g_object_get_data(G_OBJECT(tag), "link_url"));
+ link->tag = g_object_ref(tag);
/* Don't want the tooltip around if user right-clicked on link */
if (GTK_IMHTML(imhtml)->tip_window) {
@@ -1802,57 +1787,23 @@ static gboolean tag_event(GtkTextTag *tag, GObject *imhtml, GdkEvent *event, Gtk
else
gdk_window_set_cursor(event_button->window, GTK_IMHTML(imhtml)->arrow_cursor);
menu = gtk_menu_new();
- g_object_set_data_full(G_OBJECT(menu), "x-imhtml-url-data", tempdata, url_data_destroy);
+ g_object_set_data_full(G_OBJECT(menu), "x-imhtml-url-data", link,
+ (GDestroyNotify)gtk_imhtml_link_destroy);
- proto = imhtml_find_protocol(tempdata->url);
+ proto = imhtml_find_protocol(link->url);
- if (!strncmp(tempdata->url, "mailto:", 7))
- {
- /* Copy Email Address */
- img = gtk_image_new_from_stock(GTK_STOCK_COPY,
- GTK_ICON_SIZE_MENU);
- item = gtk_image_menu_item_new_with_mnemonic(
- _("_Copy Email Address"));
- gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img);
- g_signal_connect(G_OBJECT(item), "activate",
- G_CALLBACK(url_copy), tempdata->url + 7);
- gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
- }
- else if (proto && proto->context_menu)
- {
- GList *children;
- proto->context_menu(GTK_IMHTML(tempdata->object), tempdata->url, menu);
- children = gtk_container_get_children(GTK_CONTAINER(menu));
- if (!children) {
- item = gtk_menu_item_new_with_label(_("No actions available"));
- gtk_widget_show(item);
- gtk_widget_set_sensitive(item, FALSE);
- gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
- } else {
- g_list_free(children);
- }
+ if (proto && proto->context_menu) {
+ proto->context_menu(GTK_IMHTML(link->imhtml), link, menu);
}
- else
- {
- /* Open Link in Browser */
- img = gtk_image_new_from_stock(GTK_STOCK_JUMP_TO,
- GTK_ICON_SIZE_MENU);
- item = gtk_image_menu_item_new_with_mnemonic(
- _("_Open Link"));
- gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img);
- g_signal_connect(G_OBJECT(item), "activate",
- G_CALLBACK(url_open), tempdata);
- gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
- /* Copy Link Location */
- img = gtk_image_new_from_stock(GTK_STOCK_COPY,
- GTK_ICON_SIZE_MENU);
- item = gtk_image_menu_item_new_with_mnemonic(
- _("_Copy Link Location"));
- gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img);
- g_signal_connect(G_OBJECT(item), "activate",
- G_CALLBACK(url_copy), tempdata->url);
+ children = gtk_container_get_children(GTK_CONTAINER(menu));
+ if (!children) {
+ GtkWidget *item = gtk_menu_item_new_with_label(_("No actions available"));
+ gtk_widget_show(item);
+ gtk_widget_set_sensitive(item, FALSE);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+ } else {
+ g_list_free(children);
}
@@ -5797,8 +5748,8 @@ void gtk_imhtml_smiley_destroy(GtkIMHtmlSmiley *smiley)
}
gboolean gtk_imhtml_class_register_protocol(const char *name,
- gboolean (*activate)(GtkIMHtml *imhtml, const char *text),
- gboolean (*context_menu)(GtkIMHtml *imhtml, const char *text, GtkWidget *menu))
+ gboolean (*activate)(GtkIMHtml *imhtml, GtkIMHtmlLink *link),
+ gboolean (*context_menu)(GtkIMHtml *imhtml, GtkIMHtmlLink *link, GtkWidget *menu))
{
GtkIMHtmlClass *klass;
GtkIMHtmlProtocol *proto;
@@ -5828,3 +5779,38 @@ gboolean gtk_imhtml_class_register_protocol(const char *name,
return TRUE;
}
+static void
+gtk_imhtml_activate_tag(GtkIMHtml *imhtml, GtkTextTag *tag)
+{
+ /* A link was clicked--we emit the "url_clicked" signal
+ * with the URL as the argument */
+ g_object_ref(G_OBJECT(tag));
+ g_signal_emit(imhtml, signals[URL_CLICKED], 0, g_object_get_data(G_OBJECT(tag), "link_url"));
+ g_object_unref(G_OBJECT(tag));
+ g_object_set_data(G_OBJECT(tag), "visited", GINT_TO_POINTER(TRUE));
+ gtk_imhtml_set_link_color(GTK_IMHTML(imhtml), tag);
+}
+
+gboolean gtk_imhtml_link_activate(GtkIMHtmlLink *link)
+{
+ g_return_val_if_fail(link, FALSE);
+
+ if (link->tag) {
+ gtk_imhtml_activate_tag(link->imhtml, link->tag);
+ } else if (link->url) {
+ g_signal_emit(link->imhtml, signals[URL_CLICKED], 0, link->url);
+ } else
+ return FALSE;
+ return TRUE;
+}
+
+const char *gtk_imhtml_link_get_url(GtkIMHtmlLink *link)
+{
+ return link->url;
+}
+
+const GtkTextTag * gtk_imhtml_link_get_text_tag(GtkIMHtmlLink *link)
+{
+ return link->tag;
+}
+
diff --git a/pidgin/gtkimhtml.h b/pidgin/gtkimhtml.h
index 170bda3230..c199d5fead 100644
--- a/pidgin/gtkimhtml.h
+++ b/pidgin/gtkimhtml.h
@@ -60,6 +60,7 @@ typedef struct _GtkIMHtmlImage GtkIMHtmlImage;
typedef struct _GtkIMHtmlAnimation GtkIMHtmlAnimation;
typedef struct _GtkIMHtmlHr GtkIMHtmlHr;
typedef struct _GtkIMHtmlFuncs GtkIMHtmlFuncs;
+typedef struct _GtkIMHtmlLink GtkIMHtmlLink;
typedef enum {
GTK_IMHTML_BOLD = 1 << 0,
@@ -888,21 +889,57 @@ void gtk_imhtml_smiley_reload(GtkIMHtmlSmiley *smiley);
void gtk_imhtml_smiley_destroy(GtkIMHtmlSmiley *smiley);
/**
- * Register a protocol with the GtkIMHtml widget. Registering a protocol would allow
- * certain text to be clickable.
+ * Register a protocol with the GtkIMHtml widget. Registering a protocol would
+ * allow certain text to be clickable.
*
* @param name The name of the protocol (e.g. http://)
* @param activate The callback to trigger when the protocol text is clicked.
- * Removes any current protocol definition if @c NULL.
- * @param context_menu The callback totrigger when the context menu is popped up on
- * the protocol text.
+ * Removes any current protocol definition if @c NULL. The
+ * callback should return @c TRUE if the link was activated
+ * properly, @c FALSE otherwise.
+ * @param context_menu The callback to trigger when the context menu is popped
+ * up on the protocol text. The callback should return
+ * @c TRUE if the request for context menu was processed
+ * successfully, @c FALSE otherwise.
*
* @return @c TRUE if the protocol was successfully registered (or unregistered, when #activate is @c NULL)
* @since 2.6.0
*/
gboolean gtk_imhtml_class_register_protocol(const char *name,
- gboolean (*activate)(GtkIMHtml *imhtml, const char *text),
- gboolean (*context_menu)(GtkIMHtml *imhtml, const char *text, GtkWidget *menu));
+ gboolean (*activate)(GtkIMHtml *imhtml, GtkIMHtmlLink *link),
+ gboolean (*context_menu)(GtkIMHtml *imhtml, GtkIMHtmlLink *link, GtkWidget *menu));
+
+/**
+ * Get the URL associated with a link. This should be used by the IMHtml protocol-callbacks.
+ *
+ * @param link The GtkIMHtmlLink object sent to the callback functions
+ *
+ * @return The URL
+ * @since 2.6.0
+ */
+const char *gtk_imhtml_link_get_url(GtkIMHtmlLink *link);
+
+/**
+ * Get the GtkTextTag object (if any) associated with a particular link.
+ *
+ * @param link The GtkIMHtmlLink object sent to the callback functions
+ *
+ * @return The GtkTextTag object, or @c NULL
+ * @since 2.6.0
+ */
+const GtkTextTag * gtk_imhtml_link_get_text_tag(GtkIMHtmlLink *link);
+
+/**
+ * Activates a GtkIMHtmlLink object. This triggers the 'url-clicked' signal, marks the
+ * link as visited (when possible).
+ *
+ * @param link The GtkIMHtmlLink object sent to the callback functions
+ *
+ * @return @c TRUE if 'url-clicked' signal was emitted, @c FALSE otherwise.
+ * @since 2.6.0
+ */
+gboolean gtk_imhtml_link_activate(GtkIMHtmlLink *link);
+
/*@}*/
#ifdef __cplusplus
diff --git a/pidgin/gtkutils.c b/pidgin/gtkutils.c
index 9a0d70bba7..b29f2bf7c2 100644
--- a/pidgin/gtkutils.c
+++ b/pidgin/gtkutils.c
@@ -84,8 +84,9 @@ url_clicked_idle_cb(gpointer data)
}
static gboolean
-url_clicked_cb(GtkIMHtml *imhtml, const char *uri)
+url_clicked_cb(GtkIMHtml *unused, GtkIMHtmlLink *link)
{
+ const char *uri = gtk_imhtml_link_get_url(link);
g_idle_add(url_clicked_idle_cb, g_strdup(uri));
return TRUE;
}
@@ -3481,13 +3482,73 @@ GdkPixbuf * pidgin_pixbuf_from_imgstore(PurpleStoredImage *image)
return pixbuf;
}
+static void url_copy(GtkWidget *w, gchar *url)
+{
+ GtkClipboard *clipboard;
+
+ clipboard = gtk_widget_get_clipboard(w, GDK_SELECTION_PRIMARY);
+ gtk_clipboard_set_text(clipboard, url, -1);
+
+ clipboard = gtk_widget_get_clipboard(w, GDK_SELECTION_CLIPBOARD);
+ gtk_clipboard_set_text(clipboard, url, -1);
+}
+
+static gboolean
+link_context_menu(GtkIMHtml *imhtml, GtkIMHtmlLink *link, GtkWidget *menu)
+{
+ GtkWidget *img, *item;
+ const char *url;
+
+ url = gtk_imhtml_link_get_url(link);
+
+ /* Open Link in Browser */
+ img = gtk_image_new_from_stock(GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU);
+ item = gtk_image_menu_item_new_with_mnemonic(_("_Open Link"));
+ gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img);
+ g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(gtk_imhtml_link_activate), link);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+
+ /* Copy Link Location */
+ img = gtk_image_new_from_stock(GTK_STOCK_COPY, GTK_ICON_SIZE_MENU);
+ item = gtk_image_menu_item_new_with_mnemonic(_("_Copy Link Location"));
+ gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img);
+ g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(url_copy), (gpointer)url);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+
+ return TRUE;
+}
+
+static gboolean
+copy_email_address(GtkIMHtml *imhtml, GtkIMHtmlLink *link, GtkWidget *menu)
+{
+ GtkWidget *img, *item;
+ const char *text;
+ char *address;
+#define MAILTOSIZE (sizeof("mailto:") - 1)
+
+ text = gtk_imhtml_link_get_url(link);
+ g_return_val_if_fail(text && strlen(text) > MAILTOSIZE, FALSE);
+ address = (char*)text + MAILTOSIZE;
+
+ /* Copy Email Address */
+ img = gtk_image_new_from_stock(GTK_STOCK_COPY, GTK_ICON_SIZE_MENU);
+ item = gtk_image_menu_item_new_with_mnemonic(_("_Copy Email Address"));
+ gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img);
+ g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(url_copy), address);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+
+ return TRUE;
+}
+
/* XXX: The following two functions are for demonstration purposes only! */
static gboolean
-open_dialog(GtkIMHtml *imhtml, const char *url)
+open_dialog(GtkIMHtml *imhtml, GtkIMHtmlLink *link)
{
+ const char *url;
const char *str;
- if (strlen(url) < sizeof("open://"))
+ url = gtk_imhtml_link_get_url(link);
+ if (!url || strlen(url) < sizeof("open://"))
return FALSE;
str = url + sizeof("open://") - 1;
@@ -3502,16 +3563,18 @@ open_dialog(GtkIMHtml *imhtml, const char *url)
}
static gboolean
-dummy(GtkIMHtml *imhtml, const char *text, GtkWidget *menu)
+dummy(GtkIMHtml *imhtml, GtkIMHtmlLink *link, GtkWidget *menu)
{
return TRUE;
}
void pidgin_utils_init(void)
{
- gtk_imhtml_class_register_protocol("http://", url_clicked_cb, NULL);
- gtk_imhtml_class_register_protocol("https://", url_clicked_cb, NULL);
- gtk_imhtml_class_register_protocol("ftp://", url_clicked_cb, NULL);
+ gtk_imhtml_class_register_protocol("http://", url_clicked_cb, link_context_menu);
+ gtk_imhtml_class_register_protocol("https://", url_clicked_cb, link_context_menu);
+ gtk_imhtml_class_register_protocol("ftp://", url_clicked_cb, link_context_menu);
+ gtk_imhtml_class_register_protocol("gopher://", url_clicked_cb, link_context_menu);
+ gtk_imhtml_class_register_protocol("mailto:", url_clicked_cb, copy_email_address);
gtk_imhtml_class_register_protocol("open://", open_dialog, dummy);
}
@@ -3521,6 +3584,8 @@ void pidgin_utils_uninit(void)
gtk_imhtml_class_register_protocol("http://", NULL, NULL);
gtk_imhtml_class_register_protocol("https://", NULL, NULL);
gtk_imhtml_class_register_protocol("ftp://", NULL, NULL);
+ gtk_imhtml_class_register_protocol("mailto:", NULL, NULL);
+ gtk_imhtml_class_register_protocol("gopher://", NULL, NULL);
gtk_imhtml_class_register_protocol("open://", NULL, NULL);
}