pidgin/gtkutils.c

changeset 41270
8b773de09aaf
parent 41266
64805b295a5c
child 41277
1b6374960c08
equal deleted inserted replaced
41269:c82a353713f6 41270:8b773de09aaf
59 AOP_DATA_COLUMN, 59 AOP_DATA_COLUMN,
60 AOP_COLUMN_COUNT 60 AOP_COLUMN_COUNT
61 }; 61 };
62 62
63 enum { 63 enum {
64 DND_FILE_TRANSFER,
65 DND_IM_IMAGE,
66 DND_BUDDY_ICON
67 };
68
69 enum {
70 COMPLETION_DISPLAYED_COLUMN, /* displayed completion value */ 64 COMPLETION_DISPLAYED_COLUMN, /* displayed completion value */
71 COMPLETION_BUDDY_COLUMN, /* buddy name */ 65 COMPLETION_BUDDY_COLUMN, /* buddy name */
72 COMPLETION_NORMALIZED_COLUMN, /* UTF-8 normalized & casefolded buddy name */ 66 COMPLETION_NORMALIZED_COLUMN, /* UTF-8 normalized & casefolded buddy name */
73 COMPLETION_COMPARISON_COLUMN, /* UTF-8 normalized & casefolded value for comparison */ 67 COMPLETION_COMPARISON_COLUMN, /* UTF-8 normalized & casefolded value for comparison */
74 COMPLETION_ACCOUNT_COLUMN, /* account */ 68 COMPLETION_ACCOUNT_COLUMN, /* account */
81 75
82 typedef struct { 76 typedef struct {
83 GtkTreeModel *model; 77 GtkTreeModel *model;
84 gint default_item; 78 gint default_item;
85 } AopMenu; 79 } AopMenu;
86
87 typedef struct {
88 char *filename;
89 PurpleAccount *account;
90 char *who;
91 } _DndData;
92 80
93 typedef struct 81 typedef struct
94 { 82 {
95 GtkWidget *entry; 83 GtkWidget *entry;
96 GtkWidget *accountopt; 84 GtkWidget *accountopt;
571 NULL); 559 NULL);
572 560
573 gtk_tree_path_free(path); 561 gtk_tree_path_free(path);
574 } 562 }
575 563
576
577 static void dnd_image_ok_callback(_DndData *data, int choice)
578 {
579 const gchar *shortname;
580 gchar *filedata;
581 size_t size;
582 GStatBuf st;
583 GError *err = NULL;
584 PurpleBuddy *buddy;
585 PurpleContact *contact;
586 PurpleImage *img;
587
588 switch (choice) {
589 case DND_BUDDY_ICON:
590 if (g_stat(data->filename, &st)) {
591 char *str;
592
593 str = g_strdup_printf(_("The following error has occurred loading %s: %s"),
594 data->filename, g_strerror(errno));
595 purple_notify_error(NULL, NULL,
596 _("Failed to load image"), str, NULL);
597 g_free(str);
598
599 break;
600 }
601
602 buddy = purple_blist_find_buddy(data->account, data->who);
603 if (!buddy) {
604 purple_debug_info("custom-icon", "You can only set custom icons for people on your buddylist.\n");
605 break;
606 }
607 contact = purple_buddy_get_contact(buddy);
608 purple_buddy_icons_node_set_custom_icon_from_file((PurpleBlistNode*)contact, data->filename);
609 break;
610 case DND_FILE_TRANSFER:
611 purple_serv_send_file(purple_account_get_connection(data->account), data->who, data->filename);
612 break;
613 case DND_IM_IMAGE:
614 if (!g_file_get_contents(data->filename, &filedata, &size,
615 &err)) {
616 char *str;
617
618 str = g_strdup_printf(_("The following error has occurred loading %s: %s"), data->filename, err->message);
619 purple_notify_error(NULL, NULL,
620 _("Failed to load image"), str, NULL);
621
622 g_error_free(err);
623 g_free(str);
624
625 break;
626 }
627 shortname = strrchr(data->filename, G_DIR_SEPARATOR);
628 shortname = shortname ? shortname + 1 : data->filename;
629 img = purple_image_new_from_data((guint8 *)filedata, size);
630 purple_image_set_friendly_filename(img, shortname);
631
632 # warning fix this when talkatu has a way to programmatically insert an image
633 // pidgin_webview_insert_image(PIDGIN_WEBVIEW(gtkconv->entry), img);
634 g_object_unref(img);
635
636 break;
637 }
638 g_free(data->filename);
639 g_free(data->who);
640 g_free(data);
641 }
642
643 static void dnd_image_cancel_callback(_DndData *data, int choice)
644 {
645 g_free(data->filename);
646 g_free(data->who);
647 g_free(data);
648 }
649
650 static void dnd_set_icon_ok_cb(_DndData *data)
651 {
652 dnd_image_ok_callback(data, DND_BUDDY_ICON);
653 }
654
655 static void dnd_set_icon_cancel_cb(_DndData *data)
656 {
657 g_free(data->filename);
658 g_free(data->who);
659 g_free(data);
660 }
661
662 static void
663 pidgin_dnd_file_send_image(PurpleAccount *account, const gchar *who,
664 const gchar *filename)
665 {
666 PurpleConnection *gc = purple_account_get_connection(account);
667 PurpleProtocol *protocol = NULL;
668 _DndData *data = g_new0(_DndData, 1);
669 gboolean ft = FALSE, im = FALSE;
670
671 data->who = g_strdup(who);
672 data->filename = g_strdup(filename);
673 data->account = account;
674
675 if (gc)
676 protocol = purple_connection_get_protocol(gc);
677
678 if (!(purple_connection_get_flags(gc) & PURPLE_CONNECTION_FLAG_NO_IMAGES))
679 im = TRUE;
680
681 if (protocol && PURPLE_IS_PROTOCOL_XFER(protocol)) {
682 PurpleProtocolXferInterface *iface =
683 PURPLE_PROTOCOL_XFER_GET_IFACE(protocol);
684
685 if(iface->can_receive) {
686 ft = purple_protocol_xfer_can_receive(
687 PURPLE_PROTOCOL_XFER(protocol),
688 gc, who);
689 } else {
690 ft = (iface->send_file) ? TRUE : FALSE;
691 }
692 }
693
694 if (im && ft) {
695 purple_request_choice(NULL, NULL,
696 _("You have dragged an image"),
697 _("You can send this image as a file "
698 "transfer, embed it into this message, "
699 "or use it as the buddy icon for this user."),
700 (gpointer)DND_FILE_TRANSFER, _("OK"),
701 (GCallback)dnd_image_ok_callback, _("Cancel"),
702 (GCallback)dnd_image_cancel_callback,
703 purple_request_cpar_from_account(account), data,
704 _("Set as buddy icon"), DND_BUDDY_ICON,
705 _("Send image file"), DND_FILE_TRANSFER,
706 _("Insert in message"), DND_IM_IMAGE,
707 NULL);
708 } else if (!(im || ft)) {
709 purple_request_yes_no(NULL, NULL, _("You have dragged an image"),
710 _("Would you like to set it as the buddy icon for this user?"),
711 PURPLE_DEFAULT_ACTION_NONE,
712 purple_request_cpar_from_account(account),
713 data, (GCallback)dnd_set_icon_ok_cb, (GCallback)dnd_set_icon_cancel_cb);
714 } else {
715 purple_request_choice(NULL, NULL,
716 _("You have dragged an image"),
717 (ft ? _("You can send this image as a file transfer, or use it as the buddy icon for this user.") :
718 _("You can insert this image into this message, or use it as the buddy icon for this user")),
719 GINT_TO_POINTER(ft ? DND_FILE_TRANSFER : DND_IM_IMAGE),
720 _("OK"), (GCallback)dnd_image_ok_callback,
721 _("Cancel"), (GCallback)dnd_image_cancel_callback,
722 purple_request_cpar_from_account(account),
723 data,
724 _("Set as buddy icon"), DND_BUDDY_ICON,
725 (ft ? _("Send image file") : _("Insert in message")), (ft ? DND_FILE_TRANSFER : DND_IM_IMAGE),
726 NULL);
727 }
728
729 }
730
731 #ifndef _WIN32
732 static void
733 pidgin_dnd_file_send_desktop(PurpleAccount *account, const gchar *who,
734 const gchar *filename)
735 {
736 gchar *name;
737 gchar *type;
738 gchar *url;
739 GKeyFile *desktop_file;
740 PurpleConversation *conv;
741 PidginConversation *gtkconv;
742 GError *error = NULL;
743
744 desktop_file = g_key_file_new();
745
746 if (!g_key_file_load_from_file(desktop_file, filename, G_KEY_FILE_NONE, &error)) {
747 if (error) {
748 purple_debug_warning("D&D", "Failed to load %s: %s\n",
749 filename, error->message);
750 g_error_free(error);
751 }
752 return;
753 }
754
755 name = g_key_file_get_string(desktop_file, G_KEY_FILE_DESKTOP_GROUP,
756 G_KEY_FILE_DESKTOP_KEY_NAME, &error);
757 if (error) {
758 purple_debug_warning("D&D", "Failed to read the Name from a desktop file: %s\n",
759 error->message);
760 g_error_free(error);
761
762 }
763
764 type = g_key_file_get_string(desktop_file, G_KEY_FILE_DESKTOP_GROUP,
765 G_KEY_FILE_DESKTOP_KEY_TYPE, &error);
766 if (error) {
767 purple_debug_warning("D&D", "Failed to read the Type from a desktop file: %s\n",
768 error->message);
769 g_error_free(error);
770
771 }
772
773 url = g_key_file_get_string(desktop_file, G_KEY_FILE_DESKTOP_GROUP,
774 G_KEY_FILE_DESKTOP_KEY_URL, &error);
775 if (error) {
776 purple_debug_warning("D&D", "Failed to read the Type from a desktop file: %s\n",
777 error->message);
778 g_error_free(error);
779
780 }
781
782
783 /* If any of this is null, do nothing. */
784 if (!name || !type || !url) {
785 g_free(type);
786 g_free(name);
787 g_free(url);
788
789 return;
790 }
791
792 /* I don't know if we really want to do anything here. Most of
793 * the desktop item types are crap like "MIME Type" (I have no
794 * clue how that would be a desktop item) and "Comment"...
795 * nothing we can really send. The only logical one is
796 * "Application," but do we really want to send a binary and
797 * nothing else? Probably not. I'll just give an error and
798 * return. */
799 /* The original patch sent the icon used by the launcher. That's probably wrong */
800 if (purple_strequal(type, "Link")) {
801 purple_notify_error(NULL, NULL, _("Cannot send launcher"),
802 _("You dragged a desktop launcher. Most "
803 "likely you wanted to send the target "
804 "of this launcher instead of this "
805 "launcher itself."), NULL);
806
807 } else {
808 GtkTextBuffer *buffer = NULL;
809 GtkTextMark *mark = NULL;
810 GtkTextIter iter;
811
812 conv = PURPLE_CONVERSATION(purple_im_conversation_new(account, who));
813 gtkconv = PIDGIN_CONVERSATION(conv);
814
815 buffer = talkatu_editor_get_buffer(TALKATU_EDITOR(gtkconv->editor));
816 mark = gtk_text_buffer_get_insert(buffer);
817
818 gtk_text_buffer_get_iter_at_mark(buffer, &iter, mark);
819
820 talkatu_buffer_insert_link(TALKATU_BUFFER(buffer), &iter, name, url);
821 }
822
823 g_free(type);
824 g_free(name);
825 g_free(url);
826 }
827 #endif /* _WIN32 */
828
829 void
830 pidgin_dnd_file_manage(GtkSelectionData *sd, PurpleAccount *account, const char *who)
831 {
832 GdkPixbuf *pb;
833 GList *files = purple_uri_list_extract_filenames((const gchar *) gtk_selection_data_get_data(sd));
834 PurpleConnection *gc = purple_account_get_connection(account);
835 gchar *filename = NULL;
836 gchar *basename = NULL;
837
838 g_return_if_fail(account != NULL);
839 g_return_if_fail(who != NULL);
840
841 for ( ; files; files = g_list_delete_link(files, files)) {
842 g_free(filename);
843 g_free(basename);
844
845 filename = files->data;
846 basename = g_path_get_basename(filename);
847
848 /* XXX - Make ft API support creating a transfer with more than one file */
849 if (!g_file_test(filename, G_FILE_TEST_EXISTS)) {
850 continue;
851 }
852
853 /* XXX - make ft api suupport sending a directory */
854 /* Are we dealing with a directory? */
855 if (g_file_test(filename, G_FILE_TEST_IS_DIR)) {
856 char *str, *str2;
857
858 str = g_strdup_printf(_("Cannot send folder %s."), basename);
859 str2 = g_strdup_printf(_("%s cannot transfer a folder. You will need to send the files within individually."), PIDGIN_NAME);
860
861 purple_notify_error(NULL, NULL, str, str2,
862 purple_request_cpar_from_connection(gc));
863
864 g_free(str);
865 g_free(str2);
866 continue;
867 }
868
869 /* Are we dealing with an image? */
870 pb = pidgin_pixbuf_new_from_file(filename);
871 if (pb) {
872 pidgin_dnd_file_send_image(account, who, filename);
873
874 g_object_unref(G_OBJECT(pb));
875
876 continue;
877 }
878
879 #ifndef _WIN32
880 /* Are we trying to send a .desktop file? */
881 else if (g_str_has_suffix(basename, ".desktop")) {
882 pidgin_dnd_file_send_desktop(account, who, filename);
883
884 continue;
885 }
886 #endif /* _WIN32 */
887
888 /* Everything is fine, let's send */
889 purple_serv_send_file(gc, who, filename);
890 }
891
892 g_free(filename);
893 g_free(basename);
894 }
895 564
896 void pidgin_buddy_icon_get_scale_size(GdkPixbuf *buf, PurpleBuddyIconSpec *spec, PurpleBuddyIconScaleFlags rules, int *width, int *height) 565 void pidgin_buddy_icon_get_scale_size(GdkPixbuf *buf, PurpleBuddyIconSpec *spec, PurpleBuddyIconScaleFlags rules, int *width, int *height)
897 { 566 {
898 *width = gdk_pixbuf_get_width(buf); 567 *width = gdk_pixbuf_get_width(buf);
899 *height = gdk_pixbuf_get_height(buf); 568 *height = gdk_pixbuf_get_height(buf);

mercurial