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