Clickable links API
Andrew Victor
avictor.za at gmail.com
Sun Mar 27 17:41:59 EDT 2011
hi,
A long-time ago we discussed the clickable links in the conversation
window that MXit uses for menus.
<http://pidgin.im/pipermail/devel/2009-November/009045.html>
We're currently overriding PurpleNotifyUiOps.notify_uri, which doesn't
always work well (especially on Windows), doesn't seem to be supported
by Adium, and IMHO is a hack.
I'd like to propose an API enhancement (preferably for 2.8.0) that
should improve this:
1. Extend PurplePluginProtocolInfo with an additional optional method:
/**
* A link was selected in a conversation.
*
* @param gc The connection
* @param who The contact associated with the conversation
* @param uri The URL that was selected
*
* @since 2.8.0
*/
void (*link_selected)(PurpleConnection *gc, const char *who, const
char *uri);
2. Extend the Conversation API with a
'purple_conversation_link_selected' function:
/**
* An internal link was selected in a Conversation
*
* @param conv The conversation
* @param uri The selected URL
*
* @since 2.8.0
*/
void purple_conversation_link_selected(PurpleConversation *conv,
const char* uri);
3. Pidgin calls gtk_imhtml_class_register_protocol() to register a
protocol handler for some protocol name. (I've been using
"internal://" - but that be changed)
Once GtkIMHtml detects the link-click it will call the handler, which
calls purple_conversation_link_selected() which in-turn calls the
prpl->link_selected().
A patch is appended for review.
Your thoughts?
Regards,
Andrew Victor
============================================================
--- libpurple/conversation.c 7cede383dd7d23720d80e0517411b41e088b87cd
+++ libpurple/conversation.c ad3f15b6b397e4332c04d871121d109718480296
@@ -2301,6 +2301,24 @@ time_t purple_conversation_message_get_t
return msg->when;
}
+void purple_conversation_link_selected(PurpleConversation *conv,
const char* uri)
+{
+ PurplePluginProtocolInfo *prpl_info = NULL;
+ PurpleConnection *gc;
+
+ g_return_if_fail(conv != NULL);
+
+ gc = purple_conversation_get_gc(conv);
+ if (!gc) /* no longer connected */
+ return;
+
+ prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc));
+ g_return_if_fail(prpl_info != NULL);
+
+ if (prpl_info->link_selected != NULL)
+ prpl_info->link_selected(gc, purple_conversation_get_name(conv), uri);
+}
+
gboolean
purple_conversation_do_command(PurpleConversation *conv, const gchar *cmdline,
const gchar *markup, gchar **error)
============================================================
--- libpurple/conversation.h 1b5c4abc64bc9456e7f4d60bf23713f150e1da94
+++ libpurple/conversation.h 51c68e3b7ffd9824798c17bd95e345d4a661c5cc
@@ -796,6 +796,16 @@ time_t purple_conversation_message_get_t
*/
time_t purple_conversation_message_get_timestamp(PurpleConvMessage *msg);
+/**
+ * An internal link was selected in a Conversation
+ *
+ * @param conv The conversation
+ * @param uri The selected URL
+ *
+ * @since 2.8.0
+ */
+void purple_conversation_link_selected(PurpleConversation *conv,
const char* uri);
+
/*@}*/
============================================================
--- libpurple/protocols/bonjour/bonjour.c 36c6d536994d7b5cbb85fb2a6a08f57586b140e0
+++ libpurple/protocols/bonjour/bonjour.c 987996f0fb6eeacebdbd0c274c69880bafa81396
@@ -536,7 +536,8 @@ static PurplePluginProtocolInfo prpl_inf
NULL, /*
set_public_alias */
NULL, /*
get_public_alias */
NULL, /*
add_buddy_with_invite */
- NULL /*
add_buddies_with_invite */
+ NULL, /*
add_buddies_with_invite */
+ NULL /* link_selected */
};
static PurplePluginInfo info =
============================================================
--- libpurple/protocols/gg/gg.c f9645a358190f517bd28e07af3eaf59b22f7cb9f
+++ libpurple/protocols/gg/gg.c 8f170984c3b4e31d8df5f62096f6516edfc4742e
@@ -2582,7 +2582,9 @@ static PurplePluginProtocolInfo prpl_inf
NULL, /* set_public_alias */
NULL, /* get_public_alias */
NULL, /* add_buddy_with_invite */
- NULL /* add_buddies_with_invite */
+ NULL, /* add_buddies_with_invite */
+ NULL /* link_selected */
+
};
static PurplePluginInfo info = {
============================================================
--- libpurple/protocols/irc/irc.c a7dd36a573f3e22b836727e3e2790521901e8950
+++ libpurple/protocols/irc/irc.c 9d096e5d4710c5ccacf5413c25de62c6467cb4a9
@@ -992,7 +992,8 @@ static PurplePluginProtocolInfo prpl_inf
NULL, /* set_public_alias */
NULL, /* get_public_alias */
NULL, /* add_buddy_with_invite */
- NULL /* add_buddies_with_invite */
+ NULL, /* add_buddies_with_invite */
+ NULL /* link_selected */
};
static gboolean load_plugin (PurplePlugin *plugin) {
============================================================
--- libpurple/protocols/jabber/libxmpp.c a8d36f925713b21b21fe5aca4b62c01aaf9c207c
+++ libpurple/protocols/jabber/libxmpp.c 7430f52c9a8d8ae574c44f503146102b8828073a
@@ -131,7 +131,8 @@ static PurplePluginProtocolInfo prpl_inf
NULL, /* set_public_alias */
NULL, /* get_public_alias */
NULL, /* add_buddy_with_invite */
- NULL /* add_buddies_with_invite */
+ NULL, /* add_buddies_with_invite */
+ NULL /* link_selected */
};
static gboolean load_plugin(PurplePlugin *plugin)
============================================================
--- libpurple/protocols/msn/msn.c 05271130bd391a7ec1d4816e41d07e4d7e6b5338
+++ libpurple/protocols/msn/msn.c efb8790b51a05f661bbb089b371a2f52575897b1
@@ -3000,7 +3000,8 @@ static PurplePluginProtocolInfo prpl_inf
msn_set_public_alias, /* set_public_alias */
msn_get_public_alias, /* get_public_alias */
msn_add_buddy, /* add_buddy_with_invite */
- NULL /* add_buddies_with_invite */
+ NULL, /* add_buddies_with_invite */
+ NULL /* link_selected */
};
static PurplePluginInfo info =
============================================================
--- libpurple/protocols/mxit/markup.c 1494d9bde0b5ad7028b8171d08352176b740967e
+++ libpurple/protocols/mxit/markup.c 739fd19cc7ba18ffc97680a9ba3c3720d54d10ad
@@ -142,6 +142,13 @@ void mxit_add_html_link( struct RXMsgDat
g_free( retstr64 );
g_string_append_printf( mx->msg, "<a href=\"%s\">%s</a>", link, displayname );
+#elif defined(MXIT_LINK_CLICK_NEW)
+ gchar* linkdata;
+
+ linkdata = purple_base64_encode( (const unsigned char*) linkname,
strlen( linkname ) );
+
+ g_string_append_printf( mx->msg, "<a href=\"%s%s\">%s</a>",
"internal://", linkdata, displayname );
+ g_free( linkdata );
#else
g_string_append_printf( mx->msg, "<b>%s</b>", linkname );
#endif
============================================================
--- libpurple/protocols/mxit/mxit.c 4d59ad8656ff2e1afd030e1b36109bee7dee7fbf
+++ libpurple/protocols/mxit/mxit.c 9f0db9bf0f01e3a1c622ae49259b6d6173a56cf6
@@ -661,6 +661,28 @@ static GList* mxit_blist_menu( PurpleBli
return m;
}
+static void mxit_link_selected( PurpleConnection* gc, const char *
who, const char *uri )
+{
+ gchar* link = NULL;
+ gsize len;
+ gboolean is_command = FALSE;
+
+ purple_debug_info( MXIT_PLUGIN_ID, "mxit_link_selected: who='%s'
uri='%s'\n", who, uri );
+
+ /* decode the base64 payload */
+ link = (gchar*) purple_base64_decode( uri + strlen( "internal://" ), &len );
+ purple_debug_info( MXIT_PLUGIN_ID, "Clicked Link: '%s'\n", link );
+
+ /* determine if it's a command-response to send */
+ is_command = g_str_has_prefix( link, "::type=reply|" );
+
+ /* send click message back to MXit */
+ mxit_send_message( gc->proto_data, who, link, FALSE, is_command );
+
+ g_free( link );
+ link = NULL;
+}
+
/*========================================================================================================================*/
static PurplePluginProtocolInfo proto_info = {
@@ -744,7 +766,8 @@ static PurplePluginProtocolInfo proto_in
NULL, /* set_public_alias */
NULL, /* get_public_alias */
mxit_add_buddy, /* add_buddy_with_invite */
- NULL /* add_buddies_with_invite */
+ NULL, /* add_buddies_with_invite */
+ mxit_link_selected /* link_selected */
};
============================================================
--- libpurple/protocols/mxit/mxit.h 285c04ee0f8a64b8c9cfe5169a49aa0909cf8189
+++ libpurple/protocols/mxit/mxit.h 855410982f6366d0b1bc5b9d5b75e5fac145e9c4
@@ -108,7 +108,8 @@
/* define this to enable the link clicking support */
-#define MXIT_LINK_CLICK
+#undef MXIT_LINK_CLICK
+#define MXIT_LINK_CLICK_NEW
#ifdef MXIT_LINK_CLICK
#define MXIT_LINK_PREFIX "gopher://"
============================================================
--- libpurple/protocols/myspace/myspace.c 8b720fae9e178327c605495ac5176308e90fc288
+++ libpurple/protocols/myspace/myspace.c 9788aaa8915ae56aca49b6c031bccb5fcd36ef88
@@ -3099,7 +3099,8 @@ static PurplePluginProtocolInfo prpl_inf
NULL, /* set_public_alias */
NULL, /* get_public_alias */
NULL, /* add_buddy_with_invite */
- NULL /* add_buddies_with_invite */
+ NULL, /* add_buddies_with_invite */
+ NULL /* link_selected */
};
/**
============================================================
--- libpurple/protocols/novell/novell.c 068fb38ed404fd2ad79057e3ef7eaf2e50630577
+++ libpurple/protocols/novell/novell.c 9dbb351e0912a933f16f6274deb7312a2772bad9
@@ -3533,7 +3533,8 @@ static PurplePluginProtocolInfo prpl_inf
NULL, /* set_public_alias */
NULL, /* get_public_alias */
NULL, /* add_buddy_with_invite */
- NULL /* add_buddies_with_invite */
+ NULL, /* add_buddies_with_invite */
+ NULL /* link_selected */
};
static PurplePluginInfo info = {
============================================================
--- libpurple/protocols/oscar/libaim.c a64b5eca261a904a5ecc60290abcaec53a3432f3
+++ libpurple/protocols/oscar/libaim.c 65e422f2c2106d0c7903e8d86a40f45ec60f3e89
@@ -102,7 +102,8 @@ static PurplePluginProtocolInfo prpl_inf
NULL, /* set_public_alias */
NULL, /* get_public_alias */
oscar_add_buddy, /* add_buddy_with_invite */
- NULL /* add_buddies_with_invite */
+ NULL, /* add_buddies_with_invite */
+ NULL /* link_selected */
};
static PurplePluginInfo info =
============================================================
--- libpurple/protocols/oscar/libicq.c 1cee78d9aad16734383b5c0b7511c58bd67026b5
+++ libpurple/protocols/oscar/libicq.c d75d61ac08c8391297d331d85f07d1e785d82efc
@@ -112,7 +112,8 @@ static PurplePluginProtocolInfo prpl_inf
NULL, /* set_public_alias */
NULL, /* get_public_alias */
oscar_add_buddy, /* add_buddy_with_invite */
- NULL /* add_buddies_with_invite */
+ NULL, /* add_buddies_with_invite */
+ NULL /* link_selected */
};
static PurplePluginInfo info =
============================================================
--- libpurple/protocols/qq/qq.c ff38ebede657d4a7a0227cada83ba03090b62797
+++ libpurple/protocols/qq/qq.c ddd1d84638f774b3dea9674946fc64105f07fa29
@@ -1044,7 +1044,8 @@ static PurplePluginProtocolInfo prpl_inf
NULL, /* set_public_alias */
NULL, /* get_public_alias */
NULL, /* add_buddy_with_invite */
- NULL /* add_buddies_with_invite */
+ NULL, /* add_buddies_with_invite */
+ NULL /* link_selected */
};
static PurplePluginInfo info = {
============================================================
--- libpurple/protocols/simple/simple.c 8d392d04f8c644822f0826ee92941a8e72ed6a17
+++ libpurple/protocols/simple/simple.c 4fff7ab30058f70b592d0221cec0c49054e0022b
@@ -2114,7 +2114,8 @@ static PurplePluginProtocolInfo prpl_inf
NULL, /* set_public_alias */
NULL, /* get_public_alias */
NULL, /* add_buddy_with_invite */
- NULL /* add_buddies_with_invite */
+ NULL, /* add_buddies_with_invite */
+ NULL /* link_selected */
};
============================================================
--- libpurple/protocols/yahoo/libyahoo.c a871e3427922dc201c58b80316d86bfe4e67f5c6
+++ libpurple/protocols/yahoo/libyahoo.c 2f8e2b6b29a958d1575b3e93c430d8c64d8a7277
@@ -269,7 +269,8 @@ static PurplePluginProtocolInfo prpl_inf
NULL, /* set_public_alias */
NULL, /* get_public_alias */
NULL, /* add_buddy_with_invite */
- NULL /* add_buddies_with_invite */
+ NULL, /* add_buddies_with_invite */
+ NULL /* link_selected */
};
static PurplePluginInfo info =
============================================================
--- libpurple/protocols/yahoo/libyahoojp.c da89c3568e9054e458c7510b1cc67a6f5f46c190
+++ libpurple/protocols/yahoo/libyahoojp.c b27006be02eb7477be7757e810bd9d33b45ed655
@@ -165,7 +165,8 @@ static PurplePluginProtocolInfo prpl_inf
NULL, /* set_public_alias */
NULL, /* get_public_alias */
NULL, /* add_buddy_with_invite */
- NULL /* add_buddies_with_invite */
+ NULL, /* add_buddies_with_invite */
+ NULL /* link_selected */
};
static PurplePluginInfo info =
============================================================
--- libpurple/protocols/zephyr/zephyr.c f236ae11f9522c76f54fce85e1df41f42cdbadbe
+++ libpurple/protocols/zephyr/zephyr.c c4014ecfa1c304be04f6cc63e9fc45c901106fbf
@@ -2913,7 +2913,8 @@ static PurplePluginProtocolInfo prpl_inf
NULL, /* set_public_alias */
NULL, /* get_public_alias */
NULL, /* add_buddy_with_invite */
- NULL /* add_buddies_with_invite */
+ NULL, /* add_buddies_with_invite */
+ NULL /* link_selected */
};
static PurplePluginInfo info = {
============================================================
--- libpurple/prpl.h 00ddff21fbb760369b95f999cb7ead428862bfb2
+++ libpurple/prpl.h 5df68759496d83b2f9f90a84d65226ad1753cc62
@@ -647,6 +647,18 @@ struct _PurplePluginProtocolInfo
*/
void (*add_buddy_with_invite)(PurpleConnection *pc, PurpleBuddy
*buddy, PurpleGroup *group, const char *message);
void (*add_buddies_with_invite)(PurpleConnection *pc, GList
*buddies, GList *groups, const char *message);
+
+ /**
+ * A link was selected in a conversation.
+ *
+ * @param gc The connection
+ * @param who The contact associated with the conversation
+ * @param uri The URL that was selected
+ *
+ * @since 2.8.0
+ */
+ void (*link_selected)(PurpleConnection *gc, const char *who, const char *uri);
+
};
#define PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl, member) \
============================================================
--- pidgin/gtkutils.c b95797e31c92492ca20a4c2d89261c7f3e17acf2
+++ pidgin/gtkutils.c f4280e7eaa9072471560a890737074e8b767ff55
@@ -45,6 +45,7 @@
#include <gdk/gdkkeysyms.h>
+
#include "conversation.h"
#include "debug.h"
#include "desktopitem.h"
@@ -3513,6 +3514,20 @@ pidgin_make_scrollable(GtkWidget *child,
return child;
}
+static gboolean
+internal_clicked_cb(GtkIMHtml *imhtml, GtkIMHtmlLink *link)
+{
+ PidginConversation *conv = g_object_get_data(G_OBJECT(imhtml), "gtkconv");
+ const char *uri = gtk_imhtml_link_get_url(link);
+
+ purple_debug_info("gtkutils", "Internal link clicked: '%s'\n", uri);
+
+ if (conv)
+ purple_conversation_link_selected(conv->active_conv, uri);
+
+ return TRUE;
+}
+
void pidgin_utils_init(void)
{
gtk_imhtml_class_register_protocol("http://", url_clicked_cb,
link_context_menu);
@@ -3524,6 +3539,9 @@ void pidgin_utils_init(void)
gtk_imhtml_class_register_protocol("file://", file_clicked_cb,
file_context_menu);
gtk_imhtml_class_register_protocol("audio://", audio_clicked_cb,
audio_context_menu);
+ /* Internal link */
+ gtk_imhtml_class_register_protocol("internal://", internal_clicked_cb, dummy);
+
/* Example custom URL handler. */
gtk_imhtml_class_register_protocol("open://", open_dialog, dummy);
@@ -3554,6 +3572,8 @@ void pidgin_utils_uninit(void)
{
gtk_imhtml_class_register_protocol("open://", NULL, NULL);
+ gtk_imhtml_class_register_protocol("internal://", NULL, NULL);
+
/* If we have GNOME handlers registered, unregister them. */
if (registered_url_handlers)
{
More information about the Devel
mailing list