pidgin/gtkutils.c

changeset 26378
e85d894af8a5
parent 25889
26d9ca30335c
child 26572
1c3c4e6ee338
equal deleted inserted replaced
26377:9124a345ed3a 26378:e85d894af8a5
54 #include "prpl.h" 54 #include "prpl.h"
55 #include "request.h" 55 #include "request.h"
56 #include "signals.h" 56 #include "signals.h"
57 #include "util.h" 57 #include "util.h"
58 58
59 #include "gtkaccount.h"
60 #include "gtkprefs.h"
61
59 #include "gtkconv.h" 62 #include "gtkconv.h"
60 #include "gtkdialogs.h" 63 #include "gtkdialogs.h"
61 #include "gtkimhtml.h" 64 #include "gtkimhtml.h"
62 #include "gtkimhtmltoolbar.h" 65 #include "gtkimhtmltoolbar.h"
63 #include "pidginstock.h" 66 #include "pidginstock.h"
69 GtkWidget *menu; 72 GtkWidget *menu;
70 gint default_item; 73 gint default_item;
71 } AopMenu; 74 } AopMenu;
72 75
73 static guint accels_save_timer = 0; 76 static guint accels_save_timer = 0;
77 static GList *gnome_url_handlers = NULL;
74 78
75 static gboolean 79 static gboolean
76 url_clicked_idle_cb(gpointer data) 80 url_clicked_idle_cb(gpointer data)
77 { 81 {
78 purple_notify_uri(NULL, data); 82 purple_notify_uri(NULL, data);
79 g_free(data); 83 g_free(data);
80 return FALSE; 84 return FALSE;
81 } 85 }
82 86
83 static void 87 static gboolean
84 url_clicked_cb(GtkWidget *w, const char *uri) 88 url_clicked_cb(GtkIMHtml *unused, GtkIMHtmlLink *link)
85 { 89 {
90 const char *uri = gtk_imhtml_link_get_url(link);
86 g_idle_add(url_clicked_idle_cb, g_strdup(uri)); 91 g_idle_add(url_clicked_idle_cb, g_strdup(uri));
92 return TRUE;
87 } 93 }
88 94
89 static GtkIMHtmlFuncs gtkimhtml_cbs = { 95 static GtkIMHtmlFuncs gtkimhtml_cbs = {
90 (GtkIMHtmlGetImageFunc)purple_imgstore_find_by_id, 96 (GtkIMHtmlGetImageFunc)purple_imgstore_find_by_id,
91 (GtkIMHtmlGetImageDataFunc)purple_imgstore_get_data, 97 (GtkIMHtmlGetImageDataFunc)purple_imgstore_get_data,
99 pidgin_setup_imhtml(GtkWidget *imhtml) 105 pidgin_setup_imhtml(GtkWidget *imhtml)
100 { 106 {
101 PangoFontDescription *desc = NULL; 107 PangoFontDescription *desc = NULL;
102 g_return_if_fail(imhtml != NULL); 108 g_return_if_fail(imhtml != NULL);
103 g_return_if_fail(GTK_IS_IMHTML(imhtml)); 109 g_return_if_fail(GTK_IS_IMHTML(imhtml));
104
105 g_signal_connect(G_OBJECT(imhtml), "url_clicked",
106 G_CALLBACK(url_clicked_cb), NULL);
107 110
108 pidgin_themes_smiley_themeize(imhtml); 111 pidgin_themes_smiley_themeize(imhtml);
109 112
110 gtk_imhtml_set_funcs(GTK_IMHTML(imhtml), &gtkimhtml_cbs); 113 gtk_imhtml_set_funcs(GTK_IMHTML(imhtml), &gtkimhtml_cbs);
111 114
565 /* Create the label */ 568 /* Create the label */
566 label = gtk_label_new (lbl); 569 label = gtk_label_new (lbl);
567 gtk_widget_show (label); 570 gtk_widget_show (label);
568 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT); 571 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
569 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); 572 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
570 573
571 gtk_container_add(GTK_CONTAINER(item), hbox); 574 gtk_container_add(GTK_CONTAINER(item), hbox);
572 gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0); 575 gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0);
573 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); 576 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
574 577
575 g_object_set_data(G_OBJECT (item), data, per_item_data); 578 g_object_set_data(G_OBJECT (item), data, per_item_data);
1922 g_free(data); 1925 g_free(data);
1923 } 1926 }
1924 #endif /* !NEW_STYLE_COMPLETION */ 1927 #endif /* !NEW_STYLE_COMPLETION */
1925 1928
1926 #ifdef NEW_STYLE_COMPLETION 1929 #ifdef NEW_STYLE_COMPLETION
1927 static gboolean screenname_completion_match_func(GtkEntryCompletion *completion, 1930 static gboolean buddyname_completion_match_func(GtkEntryCompletion *completion,
1928 const gchar *key, GtkTreeIter *iter, gpointer user_data) 1931 const gchar *key, GtkTreeIter *iter, gpointer user_data)
1929 { 1932 {
1930 GtkTreeModel *model; 1933 GtkTreeModel *model;
1931 GValue val1; 1934 GValue val1;
1932 GValue val2; 1935 GValue val2;
1955 g_value_unset(&val2); 1958 g_value_unset(&val2);
1956 1959
1957 return FALSE; 1960 return FALSE;
1958 } 1961 }
1959 1962
1960 static gboolean screenname_completion_match_selected_cb(GtkEntryCompletion *completion, 1963 static gboolean buddyname_completion_match_selected_cb(GtkEntryCompletion *completion,
1961 GtkTreeModel *model, GtkTreeIter *iter, PidginCompletionData *data) 1964 GtkTreeModel *model, GtkTreeIter *iter, PidginCompletionData *data)
1962 { 1965 {
1963 GValue val; 1966 GValue val;
1964 GtkWidget *optmenu = data->accountopt; 1967 GtkWidget *optmenu = data->accountopt;
1965 PurpleAccount *account; 1968 PurpleAccount *account;
1981 1984
1982 return TRUE; 1985 return TRUE;
1983 } 1986 }
1984 1987
1985 static void 1988 static void
1986 add_screenname_autocomplete_entry(GtkListStore *store, const char *buddy_alias, const char *contact_alias, 1989 add_buddyname_autocomplete_entry(GtkListStore *store, const char *buddy_alias, const char *contact_alias,
1987 const PurpleAccount *account, const char *screenname) 1990 const PurpleAccount *account, const char *buddyname)
1988 { 1991 {
1989 GtkTreeIter iter; 1992 GtkTreeIter iter;
1990 gboolean completion_added = FALSE; 1993 gboolean completion_added = FALSE;
1991 gchar *normalized_screenname; 1994 gchar *normalized_buddyname;
1992 gchar *tmp; 1995 gchar *tmp;
1993 1996
1994 tmp = g_utf8_normalize(screenname, -1, G_NORMALIZE_DEFAULT); 1997 tmp = g_utf8_normalize(buddyname, -1, G_NORMALIZE_DEFAULT);
1995 normalized_screenname = g_utf8_casefold(tmp, -1); 1998 normalized_buddyname = g_utf8_casefold(tmp, -1);
1996 g_free(tmp); 1999 g_free(tmp);
1997 2000
1998 /* There's no sense listing things like: 'xxx "xxx"' 2001 /* There's no sense listing things like: 'xxx "xxx"'
1999 when the screenname and buddy alias match. */ 2002 when the name and buddy alias match. */
2000 if (buddy_alias && strcmp(buddy_alias, screenname)) { 2003 if (buddy_alias && strcmp(buddy_alias, buddyname)) {
2001 char *completion_entry = g_strdup_printf("%s \"%s\"", screenname, buddy_alias); 2004 char *completion_entry = g_strdup_printf("%s \"%s\"", buddyname, buddy_alias);
2002 char *tmp2 = g_utf8_normalize(buddy_alias, -1, G_NORMALIZE_DEFAULT); 2005 char *tmp2 = g_utf8_normalize(buddy_alias, -1, G_NORMALIZE_DEFAULT);
2003 2006
2004 tmp = g_utf8_casefold(tmp2, -1); 2007 tmp = g_utf8_casefold(tmp2, -1);
2005 g_free(tmp2); 2008 g_free(tmp2);
2006 2009
2007 gtk_list_store_append(store, &iter); 2010 gtk_list_store_append(store, &iter);
2008 gtk_list_store_set(store, &iter, 2011 gtk_list_store_set(store, &iter,
2009 0, completion_entry, 2012 0, completion_entry,
2010 1, screenname, 2013 1, buddyname,
2011 2, normalized_screenname, 2014 2, normalized_buddyname,
2012 3, tmp, 2015 3, tmp,
2013 4, account, 2016 4, account,
2014 -1); 2017 -1);
2015 g_free(completion_entry); 2018 g_free(completion_entry);
2016 g_free(tmp); 2019 g_free(tmp);
2017 completion_added = TRUE; 2020 completion_added = TRUE;
2018 } 2021 }
2019 2022
2020 /* There's no sense listing things like: 'xxx "xxx"' 2023 /* There's no sense listing things like: 'xxx "xxx"'
2021 when the screenname and contact alias match. */ 2024 when the name and contact alias match. */
2022 if (contact_alias && strcmp(contact_alias, screenname)) { 2025 if (contact_alias && strcmp(contact_alias, buddyname)) {
2023 /* We don't want duplicates when the contact and buddy alias match. */ 2026 /* We don't want duplicates when the contact and buddy alias match. */
2024 if (!buddy_alias || strcmp(contact_alias, buddy_alias)) { 2027 if (!buddy_alias || strcmp(contact_alias, buddy_alias)) {
2025 char *completion_entry = g_strdup_printf("%s \"%s\"", 2028 char *completion_entry = g_strdup_printf("%s \"%s\"",
2026 screenname, contact_alias); 2029 buddyname, contact_alias);
2027 char *tmp2 = g_utf8_normalize(contact_alias, -1, G_NORMALIZE_DEFAULT); 2030 char *tmp2 = g_utf8_normalize(contact_alias, -1, G_NORMALIZE_DEFAULT);
2028 2031
2029 tmp = g_utf8_casefold(tmp2, -1); 2032 tmp = g_utf8_casefold(tmp2, -1);
2030 g_free(tmp2); 2033 g_free(tmp2);
2031 2034
2032 gtk_list_store_append(store, &iter); 2035 gtk_list_store_append(store, &iter);
2033 gtk_list_store_set(store, &iter, 2036 gtk_list_store_set(store, &iter,
2034 0, completion_entry, 2037 0, completion_entry,
2035 1, screenname, 2038 1, buddyname,
2036 2, normalized_screenname, 2039 2, normalized_buddyname,
2037 3, tmp, 2040 3, tmp,
2038 4, account, 2041 4, account,
2039 -1); 2042 -1);
2040 g_free(completion_entry); 2043 g_free(completion_entry);
2041 g_free(tmp); 2044 g_free(tmp);
2042 completion_added = TRUE; 2045 completion_added = TRUE;
2043 } 2046 }
2044 } 2047 }
2045 2048
2046 if (completion_added == FALSE) { 2049 if (completion_added == FALSE) {
2047 /* Add the buddy's screenname. */ 2050 /* Add the buddy's name. */
2048 gtk_list_store_append(store, &iter); 2051 gtk_list_store_append(store, &iter);
2049 gtk_list_store_set(store, &iter, 2052 gtk_list_store_set(store, &iter,
2050 0, screenname, 2053 0, buddyname,
2051 1, screenname, 2054 1, buddyname,
2052 2, normalized_screenname, 2055 2, normalized_buddyname,
2053 3, NULL, 2056 3, NULL,
2054 4, account, 2057 4, account,
2055 -1); 2058 -1);
2056 } 2059 }
2057 2060
2058 g_free(normalized_screenname); 2061 g_free(normalized_buddyname);
2059 } 2062 }
2060 #endif /* NEW_STYLE_COMPLETION */ 2063 #endif /* NEW_STYLE_COMPLETION */
2061 2064
2062 static void get_log_set_name(PurpleLogSet *set, gpointer value, PidginCompletionData *data) 2065 static void get_log_set_name(PurpleLogSet *set, gpointer value, PidginCompletionData *data)
2063 { 2066 {
2064 PidginFilterBuddyCompletionEntryFunc filter_func = data->filter_func; 2067 PidginFilterBuddyCompletionEntryFunc filter_func = data->filter_func;
2065 gpointer user_data = data->filter_func_user_data; 2068 gpointer user_data = data->filter_func_user_data;
2066 2069
2067 /* 1. Don't show buddies because we will have gotten them already. 2070 /* 1. Don't show buddies because we will have gotten them already.
2068 * 2. The boxes that use this autocomplete code handle only IMs. */ 2071 * 2. The boxes that use this autocomplete code handle only IMs. */
2069 if (!set->buddy && set->type == PURPLE_LOG_IM) { 2072 if (!set->buddy && set->type == PURPLE_LOG_IM) {
2070 PidginBuddyCompletionEntry entry; 2073 PidginBuddyCompletionEntry entry;
2071 entry.is_buddy = FALSE; 2074 entry.is_buddy = FALSE;
2072 entry.entry.logged_buddy = set; 2075 entry.entry.logged_buddy = set;
2073 2076
2074 if (filter_func(&entry, user_data)) { 2077 if (filter_func(&entry, user_data)) {
2075 #ifdef NEW_STYLE_COMPLETION 2078 #ifdef NEW_STYLE_COMPLETION
2076 add_screenname_autocomplete_entry(data->store, 2079 add_buddyname_autocomplete_entry(data->store,
2077 NULL, NULL, set->account, set->name); 2080 NULL, NULL, set->account, set->name);
2078 #else 2081 #else
2079 /* Steal the name for the GCompletion. */ 2082 /* Steal the name for the GCompletion. */
2080 data->log_items = g_list_append(data->log_items, set->name); 2083 data->log_items = g_list_append(data->log_items, set->name);
2081 set->name = set->normalized_name = NULL; 2084 set->name = set->normalized_name = NULL;
2117 entry.is_buddy = TRUE; 2120 entry.is_buddy = TRUE;
2118 entry.entry.buddy = (PurpleBuddy *) bnode; 2121 entry.entry.buddy = (PurpleBuddy *) bnode;
2119 2122
2120 if (filter_func(&entry, user_data)) { 2123 if (filter_func(&entry, user_data)) {
2121 #ifdef NEW_STYLE_COMPLETION 2124 #ifdef NEW_STYLE_COMPLETION
2122 add_screenname_autocomplete_entry(data->store, 2125 add_buddyname_autocomplete_entry(data->store,
2123 ((PurpleContact *)cnode)->alias, 2126 ((PurpleContact *)cnode)->alias,
2124 purple_buddy_get_contact_alias(entry.entry.buddy), 2127 purple_buddy_get_contact_alias(entry.entry.buddy),
2125 entry.entry.buddy->account, 2128 entry.entry.buddy->account,
2126 entry.entry.buddy->name 2129 entry.entry.buddy->name
2127 ); 2130 );
2148 g_list_free(data->log_items); 2151 g_list_free(data->log_items);
2149 #endif /* NEW_STYLE_COMPLETION */ 2152 #endif /* NEW_STYLE_COMPLETION */
2150 } 2153 }
2151 2154
2152 static void 2155 static void
2153 screenname_autocomplete_destroyed_cb(GtkWidget *widget, gpointer data) 2156 buddyname_autocomplete_destroyed_cb(GtkWidget *widget, gpointer data)
2154 { 2157 {
2155 g_free(data); 2158 g_free(data);
2156 purple_signals_disconnect_by_handle(widget); 2159 purple_signals_disconnect_by_handle(widget);
2157 } 2160 }
2158 2161
2160 repopulate_autocomplete(gpointer something, gpointer data) 2163 repopulate_autocomplete(gpointer something, gpointer data)
2161 { 2164 {
2162 add_completion_list(data); 2165 add_completion_list(data);
2163 } 2166 }
2164 2167
2165
2166 void 2168 void
2167 pidgin_setup_screenname_autocomplete_with_filter(GtkWidget *entry, GtkWidget *accountopt, PidginFilterBuddyCompletionEntryFunc filter_func, gpointer user_data) 2169 pidgin_setup_screenname_autocomplete_with_filter(GtkWidget *entry, GtkWidget *accountopt, PidginFilterBuddyCompletionEntryFunc filter_func, gpointer user_data)
2168 { 2170 {
2169 PidginCompletionData *data; 2171 PidginCompletionData *data;
2170 2172
2171 #ifdef NEW_STYLE_COMPLETION 2173 #ifdef NEW_STYLE_COMPLETION
2172 /* Store the displayed completion value, the screenname, the UTF-8 normalized & casefolded screenname, 2174 /*
2173 * the UTF-8 normalized & casefolded value for comparison, and the account. */ 2175 * Store the displayed completion value, the buddy name, the UTF-8
2176 * normalized & casefolded buddy name, the UTF-8 normalized &
2177 * casefolded value for comparison, and the account.
2178 */
2174 GtkListStore *store; 2179 GtkListStore *store;
2175 2180
2176 GtkEntryCompletion *completion; 2181 GtkEntryCompletion *completion;
2177 2182
2178 data = g_new0(PidginCompletionData, 1); 2183 data = g_new0(PidginCompletionData, 1);
2189 } 2194 }
2190 data->store = store; 2195 data->store = store;
2191 2196
2192 add_completion_list(data); 2197 add_completion_list(data);
2193 2198
2194 /* Sort the completion list by screenname. */ 2199 /* Sort the completion list by buddy name */
2195 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), 2200 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store),
2196 1, GTK_SORT_ASCENDING); 2201 1, GTK_SORT_ASCENDING);
2197 2202
2198 completion = gtk_entry_completion_new(); 2203 completion = gtk_entry_completion_new();
2199 gtk_entry_completion_set_match_func(completion, screenname_completion_match_func, NULL, NULL); 2204 gtk_entry_completion_set_match_func(completion, buddyname_completion_match_func, NULL, NULL);
2200 2205
2201 g_signal_connect(G_OBJECT(completion), "match-selected", 2206 g_signal_connect(G_OBJECT(completion), "match-selected",
2202 G_CALLBACK(screenname_completion_match_selected_cb), data); 2207 G_CALLBACK(buddyname_completion_match_selected_cb), data);
2203 2208
2204 gtk_entry_set_completion(GTK_ENTRY(entry), completion); 2209 gtk_entry_set_completion(GTK_ENTRY(entry), completion);
2205 g_object_unref(completion); 2210 g_object_unref(completion);
2206 2211
2207 gtk_entry_completion_set_model(completion, GTK_TREE_MODEL(store)); 2212 gtk_entry_completion_set_model(completion, GTK_TREE_MODEL(store));
2244 purple_signal_connect(purple_accounts_get_handle(), "account-added", entry, 2249 purple_signal_connect(purple_accounts_get_handle(), "account-added", entry,
2245 PURPLE_CALLBACK(repopulate_autocomplete), data); 2250 PURPLE_CALLBACK(repopulate_autocomplete), data);
2246 purple_signal_connect(purple_accounts_get_handle(), "account-removed", entry, 2251 purple_signal_connect(purple_accounts_get_handle(), "account-removed", entry,
2247 PURPLE_CALLBACK(repopulate_autocomplete), data); 2252 PURPLE_CALLBACK(repopulate_autocomplete), data);
2248 2253
2249 g_signal_connect(G_OBJECT(entry), "destroy", G_CALLBACK(screenname_autocomplete_destroyed_cb), data); 2254 g_signal_connect(G_OBJECT(entry), "destroy", G_CALLBACK(buddyname_autocomplete_destroyed_cb), data);
2250 } 2255 }
2251 2256
2252 gboolean 2257 gboolean
2253 pidgin_screenname_autocomplete_default_filter(const PidginBuddyCompletionEntry *completion_entry, gpointer all_accounts) { 2258 pidgin_screenname_autocomplete_default_filter(const PidginBuddyCompletionEntry *completion_entry, gpointer all_accounts) {
2254 gboolean all = GPOINTER_TO_INT(all_accounts); 2259 gboolean all = GPOINTER_TO_INT(all_accounts);
3238 return "dim grey"; 3243 return "dim grey";
3239 3244
3240 style = gtk_widget_get_style(widget); 3245 style = gtk_widget_get_style(widget);
3241 if (!style) 3246 if (!style)
3242 return "dim grey"; 3247 return "dim grey";
3243 3248
3244 snprintf(dim_grey_string, sizeof(dim_grey_string), "#%02x%02x%02x", 3249 snprintf(dim_grey_string, sizeof(dim_grey_string), "#%02x%02x%02x",
3245 style->text_aa[GTK_STATE_NORMAL].red >> 8, 3250 style->text_aa[GTK_STATE_NORMAL].red >> 8,
3246 style->text_aa[GTK_STATE_NORMAL].green >> 8, 3251 style->text_aa[GTK_STATE_NORMAL].green >> 8,
3247 style->text_aa[GTK_STATE_NORMAL].blue >> 8); 3252 style->text_aa[GTK_STATE_NORMAL].blue >> 8);
3248 return dim_grey_string; 3253 return dim_grey_string;
3478 g_object_ref(pixbuf); 3483 g_object_ref(pixbuf);
3479 g_object_unref(loader); 3484 g_object_unref(loader);
3480 return pixbuf; 3485 return pixbuf;
3481 } 3486 }
3482 3487
3488 static void url_copy(GtkWidget *w, gchar *url)
3489 {
3490 GtkClipboard *clipboard;
3491
3492 clipboard = gtk_widget_get_clipboard(w, GDK_SELECTION_PRIMARY);
3493 gtk_clipboard_set_text(clipboard, url, -1);
3494
3495 clipboard = gtk_widget_get_clipboard(w, GDK_SELECTION_CLIPBOARD);
3496 gtk_clipboard_set_text(clipboard, url, -1);
3497 }
3498
3499 static gboolean
3500 link_context_menu(GtkIMHtml *imhtml, GtkIMHtmlLink *link, GtkWidget *menu)
3501 {
3502 GtkWidget *img, *item;
3503 const char *url;
3504
3505 url = gtk_imhtml_link_get_url(link);
3506
3507 /* Open Link */
3508 img = gtk_image_new_from_stock(GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU);
3509 item = gtk_image_menu_item_new_with_mnemonic(_("_Open Link"));
3510 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img);
3511 g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(gtk_imhtml_link_activate), link);
3512 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
3513
3514 /* Copy Link Location */
3515 img = gtk_image_new_from_stock(GTK_STOCK_COPY, GTK_ICON_SIZE_MENU);
3516 item = gtk_image_menu_item_new_with_mnemonic(_("_Copy Link Location"));
3517 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img);
3518 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(url_copy), (gpointer)url);
3519 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
3520
3521 return TRUE;
3522 }
3523
3524 static gboolean
3525 copy_email_address(GtkIMHtml *imhtml, GtkIMHtmlLink *link, GtkWidget *menu)
3526 {
3527 GtkWidget *img, *item;
3528 const char *text;
3529 char *address;
3530 #define MAILTOSIZE (sizeof("mailto:") - 1)
3531
3532 text = gtk_imhtml_link_get_url(link);
3533 g_return_val_if_fail(text && strlen(text) > MAILTOSIZE, FALSE);
3534 address = (char*)text + MAILTOSIZE;
3535
3536 /* Copy Email Address */
3537 img = gtk_image_new_from_stock(GTK_STOCK_COPY, GTK_ICON_SIZE_MENU);
3538 item = gtk_image_menu_item_new_with_mnemonic(_("_Copy Email Address"));
3539 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img);
3540 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(url_copy), address);
3541 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
3542
3543 return TRUE;
3544 }
3545
3546 /* XXX: The following two functions are for demonstration purposes only! */
3547 static gboolean
3548 open_dialog(GtkIMHtml *imhtml, GtkIMHtmlLink *link)
3549 {
3550 const char *url;
3551 const char *str;
3552
3553 url = gtk_imhtml_link_get_url(link);
3554 if (!url || strlen(url) < sizeof("open://"))
3555 return FALSE;
3556
3557 str = url + sizeof("open://") - 1;
3558
3559 if (strcmp(str, "accounts") == 0)
3560 pidgin_accounts_window_show();
3561 else if (strcmp(str, "prefs") == 0)
3562 pidgin_prefs_show();
3563 else
3564 return FALSE;
3565 return TRUE;
3566 }
3567
3568 static gboolean
3569 dummy(GtkIMHtml *imhtml, GtkIMHtmlLink *link, GtkWidget *menu)
3570 {
3571 return TRUE;
3572 }
3573
3574 static gboolean
3575 register_gnome_url_handlers(void)
3576 {
3577 char *tmp;
3578 char *err;
3579 char *c;
3580 char *start;
3581
3582 tmp = g_find_program_in_path("gconftool-2");
3583 if (tmp == NULL)
3584 return FALSE;
3585
3586 tmp = NULL;
3587 if (!g_spawn_command_line_sync("gconftool-2 --all-dirs /desktop/gnome/url-handlers",
3588 &tmp, &err, NULL, NULL))
3589 {
3590 g_free(tmp);
3591 g_free(err);
3592 g_return_val_if_reached(FALSE);
3593 }
3594 g_free(err);
3595 err = NULL;
3596
3597 for (c = start = tmp ; *c ; c++)
3598 {
3599 /* Skip leading spaces. */
3600 if (c == start && *c == ' ')
3601 start = c + 1;
3602 else if (*c == '\n')
3603 {
3604 *c = '\0';
3605 if (g_str_has_prefix(start, "/desktop/gnome/url-handlers/"))
3606 {
3607 char *cmd;
3608 char *tmp2 = NULL;
3609 char *protocol;
3610
3611 /* If there is an enabled boolean, honor it. */
3612 cmd = g_strdup_printf("gconftool-2 -g %s/enabled", start);
3613 if (g_spawn_command_line_sync(cmd, &tmp2, &err, NULL, NULL))
3614 {
3615 g_free(err);
3616 err = NULL;
3617 if (!strcmp(tmp2, "false\n"))
3618 {
3619 g_free(tmp2);
3620 g_free(cmd);
3621 start = c + 1;
3622 continue;
3623 }
3624 }
3625 g_free(cmd);
3626 g_free(tmp2);
3627
3628 start += sizeof("/desktop/gnome/url-handlers/") - 1;
3629
3630 protocol = g_strdup_printf("%s:", start);
3631 gnome_url_handlers = g_list_prepend(gnome_url_handlers, protocol);
3632 gtk_imhtml_class_register_protocol(protocol, url_clicked_cb, link_context_menu);
3633 }
3634 start = c + 1;
3635 }
3636 }
3637 g_free(tmp);
3638
3639 return (gnome_url_handlers != NULL);
3640 }
3641
3642 void pidgin_utils_init(void)
3643 {
3644 gtk_imhtml_class_register_protocol("http://", url_clicked_cb, link_context_menu);
3645 gtk_imhtml_class_register_protocol("https://", url_clicked_cb, link_context_menu);
3646 gtk_imhtml_class_register_protocol("ftp://", url_clicked_cb, link_context_menu);
3647 gtk_imhtml_class_register_protocol("gopher://", url_clicked_cb, link_context_menu);
3648 gtk_imhtml_class_register_protocol("mailto:", url_clicked_cb, copy_email_address);
3649
3650 /* Example custom URL handler. */
3651 gtk_imhtml_class_register_protocol("open://", open_dialog, dummy);
3652
3653 /* If we're under GNOME, try registering the system URL handlers. */
3654 if (purple_running_gnome())
3655 register_gnome_url_handlers();
3656 }
3657
3658 void pidgin_utils_uninit(void)
3659 {
3660 gtk_imhtml_class_register_protocol("open://", NULL, NULL);
3661
3662 /* If we have GNOME handlers registered, unregister them. */
3663 if (gnome_url_handlers)
3664 {
3665 GList *l;
3666 for (l = gnome_url_handlers ; l ; l = l->next)
3667 {
3668 gtk_imhtml_class_register_protocol((char *)l->data, NULL, NULL);
3669 g_free(l->data);
3670 }
3671 g_list_free(gnome_url_handlers);
3672 gnome_url_handlers = NULL;
3673 return;
3674 }
3675
3676 gtk_imhtml_class_register_protocol("http://", NULL, NULL);
3677 gtk_imhtml_class_register_protocol("https://", NULL, NULL);
3678 gtk_imhtml_class_register_protocol("ftp://", NULL, NULL);
3679 gtk_imhtml_class_register_protocol("mailto:", NULL, NULL);
3680 gtk_imhtml_class_register_protocol("gopher://", NULL, NULL);
3681 }
3682

mercurial