| 192 webkit_network_request_set_uri(request, tmp); |
195 webkit_network_request_set_uri(request, tmp); |
| 193 g_free(b64); |
196 g_free(b64); |
| 194 g_free(tmp); |
197 g_free(tmp); |
| 195 } |
198 } |
| 196 } |
199 } |
| |
200 } |
| |
201 |
| |
202 static void |
| |
203 webview_resource_loaded(WebKitWebView *web_view, WebKitWebFrame *web_frame, |
| |
204 WebKitWebResource *web_resource, gpointer user_data) |
| |
205 { |
| |
206 PidginWebViewPriv *priv = PIDGIN_WEBVIEW_GET_PRIVATE(web_view); |
| |
207 const gchar *uri; |
| |
208 GString *data; |
| |
209 PurpleStoredImage *image; |
| |
210 |
| |
211 if (!purple_str_has_caseprefix( |
| |
212 webkit_web_resource_get_mime_type(web_resource), "image/")) |
| |
213 { |
| |
214 return; |
| |
215 } |
| |
216 |
| |
217 uri = webkit_web_resource_get_uri(web_resource); |
| |
218 if (g_hash_table_lookup(priv->loaded_images, uri)) |
| |
219 return; |
| |
220 |
| |
221 data = webkit_web_resource_get_data(web_resource); |
| |
222 if (data->len == 0) |
| |
223 return; |
| |
224 |
| |
225 /* TODO: we could avoid copying data, if uri is a |
| |
226 * PURPLE_STORED_IMAGE_PROTOCOL or PURPLE_STOCK_IMAGE_PROTOCOL */ |
| |
227 image = purple_imgstore_new(g_memdup(data->str, data->len), |
| |
228 data->len, NULL); |
| |
229 g_return_if_fail(image != NULL); |
| |
230 |
| |
231 g_hash_table_insert(priv->loaded_images, g_strdup(uri), image); |
| |
232 } |
| |
233 |
| |
234 static PurpleStoredImage * |
| |
235 webview_resource_get_loaded(WebKitWebView *web_view, const gchar *uri) |
| |
236 { |
| |
237 PidginWebViewPriv *priv = PIDGIN_WEBVIEW_GET_PRIVATE(web_view); |
| |
238 |
| |
239 g_return_val_if_fail(priv != NULL, NULL); |
| |
240 |
| |
241 return g_hash_table_lookup(priv->loaded_images, uri); |
| 197 } |
242 } |
| 198 |
243 |
| 199 static void |
244 static void |
| 200 process_load_queue_element(PidginWebView *webview) |
245 process_load_queue_element(PidginWebView *webview) |
| 201 { |
246 { |
| 514 |
559 |
| 515 return menuitem; |
560 return menuitem; |
| 516 } |
561 } |
| 517 |
562 |
| 518 static void |
563 static void |
| |
564 webview_image_saved(GtkWidget *dialog, gint response, gpointer _unused) |
| |
565 { |
| |
566 PurpleStoredImage *image; |
| |
567 gchar *filename; |
| |
568 GError *error = NULL; |
| |
569 |
| |
570 if (response != GTK_RESPONSE_ACCEPT) { |
| |
571 gtk_widget_destroy(dialog); |
| |
572 return; |
| |
573 } |
| |
574 |
| |
575 image = g_object_get_data(G_OBJECT(dialog), "pidgin-gtkwebview-image"); |
| |
576 g_return_if_fail(image != NULL); |
| |
577 |
| |
578 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); |
| |
579 g_return_if_fail(filename != NULL); |
| |
580 g_return_if_fail(filename[0] != '\0'); |
| |
581 |
| |
582 g_file_set_contents(filename, purple_imgstore_get_data(image), |
| |
583 purple_imgstore_get_size(image), &error); |
| |
584 if (error) { |
| |
585 purple_debug_error("gtkwebview", "Failed saving image: %s", |
| |
586 error->message); |
| |
587 /* TODO: we should display a notification here */ |
| |
588 } |
| |
589 |
| |
590 g_free(filename); |
| |
591 gtk_widget_destroy(dialog); |
| |
592 } |
| |
593 |
| |
594 static void |
| |
595 webview_image_save(GtkWidget *item, WebKitDOMHTMLImageElement *image_node) |
| |
596 { |
| |
597 const gchar *src = webkit_dom_html_image_element_get_src(image_node); |
| |
598 WebKitWebView *webview; |
| |
599 PurpleStoredImage *image; |
| |
600 GtkFileChooserDialog *dialog; |
| |
601 gchar *filename; |
| |
602 GtkWidget *parent; |
| |
603 |
| |
604 webview = g_object_get_data(G_OBJECT(image_node), "pidgin-gtkwebview"); |
| |
605 g_return_if_fail(webview != NULL); |
| |
606 |
| |
607 image = webview_resource_get_loaded(webview, src); |
| |
608 g_return_if_fail(image != NULL); |
| |
609 |
| |
610 parent = gtk_widget_get_ancestor(item, GTK_TYPE_WINDOW); |
| |
611 dialog = GTK_FILE_CHOOSER_DIALOG(gtk_file_chooser_dialog_new( |
| |
612 _("Save Image"), |
| |
613 parent ? GTK_WINDOW(parent) : NULL, |
| |
614 GTK_FILE_CHOOSER_ACTION_SAVE, |
| |
615 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, |
| |
616 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, |
| |
617 NULL)); |
| |
618 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE); |
| |
619 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT); |
| |
620 |
| |
621 /* TODO: use image's file name, if there is one */ |
| |
622 filename = g_strdup_printf(_("image.%s"), |
| |
623 purple_imgstore_get_extension(image)); |
| |
624 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), filename); |
| |
625 g_free(filename); |
| |
626 |
| |
627 g_signal_connect(G_OBJECT(dialog), "response", |
| |
628 G_CALLBACK(webview_image_saved), NULL); |
| |
629 |
| |
630 purple_imgstore_ref(image); |
| |
631 g_object_set_data_full(G_OBJECT(dialog), "pidgin-gtkwebview-image", |
| |
632 image, (GDestroyNotify)purple_imgstore_unref); |
| |
633 |
| |
634 gtk_widget_show(GTK_WIDGET(dialog)); |
| |
635 } |
| |
636 |
| |
637 static void |
| 519 do_popup_menu(WebKitWebView *webview, int button, int time, int context, |
638 do_popup_menu(WebKitWebView *webview, int button, int time, int context, |
| 520 WebKitDOMNode *node, const char *uri) |
639 WebKitDOMNode *node, const char *uri) |
| 521 { |
640 { |
| 522 GtkWidget *menu; |
641 GtkWidget *menu; |
| 523 GtkWidget *cut, *copy, *paste, *delete, *select; |
642 GtkWidget *cut, *copy, *paste, *delete, *select; |
| |
643 gboolean show_clipboard = TRUE; |
| |
644 WebKitDOMHTMLImageElement *image_node = NULL; |
| 524 |
645 |
| 525 menu = gtk_menu_new(); |
646 menu = gtk_menu_new(); |
| 526 g_signal_connect(menu, "selection-done", |
647 g_signal_connect(menu, "selection-done", |
| 527 G_CALLBACK(gtk_widget_destroy), NULL); |
648 G_CALLBACK(gtk_widget_destroy), NULL); |
| 528 |
649 |
| 529 if ((context & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK) |
650 if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK) { |
| 530 && !(context & WEBKIT_HIT_TEST_RESULT_CONTEXT_SELECTION)) { |
|
| 531 PidginWebViewProtocol *proto = NULL; |
651 PidginWebViewProtocol *proto = NULL; |
| 532 GList *children; |
652 GList *children; |
| 533 |
653 WebKitDOMNode *link_node = node; |
| 534 while (node && !WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT(node)) { |
654 |
| 535 node = webkit_dom_node_get_parent_node(node); |
655 while (link_node && !WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT(link_node)) { |
| |
656 link_node = webkit_dom_node_get_parent_node(node); |
| 536 } |
657 } |
| 537 |
658 |
| 538 if (uri && node) |
659 if (uri && link_node) |
| 539 proto = webview_find_protocol(uri, FALSE); |
660 proto = webview_find_protocol(uri, FALSE); |
| 540 |
661 |
| 541 if (proto && proto->context_menu) { |
662 if (proto && proto->context_menu) { |
| 542 proto->context_menu(PIDGIN_WEBVIEW(webview), |
663 proto->context_menu(PIDGIN_WEBVIEW(webview), |
| 543 WEBKIT_DOM_HTML_ANCHOR_ELEMENT(node), menu); |
664 WEBKIT_DOM_HTML_ANCHOR_ELEMENT(link_node), menu); |
| 544 } |
665 } |
| 545 |
666 |
| 546 children = gtk_container_get_children(GTK_CONTAINER(menu)); |
667 children = gtk_container_get_children(GTK_CONTAINER(menu)); |
| 547 if (!children) { |
668 if (!children) { |
| 548 GtkWidget *item = gtk_menu_item_new_with_label(_("No actions available")); |
669 GtkWidget *item = gtk_menu_item_new_with_label(_("No actions available")); |
| 552 } else { |
673 } else { |
| 553 g_list_free(children); |
674 g_list_free(children); |
| 554 } |
675 } |
| 555 gtk_widget_show_all(menu); |
676 gtk_widget_show_all(menu); |
| 556 |
677 |
| 557 } else { |
678 show_clipboard = FALSE; |
| |
679 } |
| |
680 |
| |
681 if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE) { |
| |
682 WebKitDOMNode *_image_node = node; |
| |
683 |
| |
684 while (_image_node && !WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT(_image_node)) { |
| |
685 _image_node = webkit_dom_node_get_parent_node(_image_node); |
| |
686 } |
| |
687 if (_image_node) |
| |
688 image_node = WEBKIT_DOM_HTML_IMAGE_ELEMENT(_image_node); |
| |
689 /* don't do it on our theme smileys */ |
| |
690 } |
| |
691 if (image_node && webkit_dom_html_image_element_get_complete(image_node)) { |
| |
692 GtkWidget *menu_item; |
| |
693 int width, height; |
| |
694 |
| |
695 width = webkit_dom_html_image_element_get_width(image_node); |
| |
696 height = webkit_dom_html_image_element_get_height(image_node); |
| |
697 |
| |
698 /* XXX */ |
| |
699 g_object_set_data(G_OBJECT(image_node), "pidgin-gtkwebview", webview); |
| |
700 |
| |
701 menu_item = gtk_image_menu_item_new_with_mnemonic( |
| |
702 _("_Save Image...")); |
| |
703 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), |
| |
704 gtk_image_new_from_stock(GTK_STOCK_SAVE, GTK_ICON_SIZE_MENU)); |
| |
705 g_signal_connect_object(G_OBJECT(menu_item), "activate", |
| |
706 G_CALLBACK(webview_image_save), image_node, 0); |
| |
707 gtk_widget_show(menu_item); |
| |
708 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); |
| |
709 |
| |
710 #if 0 |
| |
711 /* TODO */ |
| |
712 if (width <= 96 && height <= 96) { |
| |
713 menu_item = gtk_image_menu_item_new_with_mnemonic( |
| |
714 _("_Add Custom Smiley...")); |
| |
715 gtk_image_menu_item_set_image( |
| |
716 GTK_IMAGE_MENU_ITEM(menu_item), |
| |
717 gtk_image_new_from_stock(GTK_STOCK_ADD, |
| |
718 GTK_ICON_SIZE_MENU)); |
| |
719 g_signal_connect(G_OBJECT(item), "activate", |
| |
720 G_CALLBACK(), save); |
| |
721 gtk_widget_show(menu_item); |
| |
722 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); |
| |
723 } |
| |
724 #endif |
| |
725 |
| |
726 show_clipboard = FALSE; |
| |
727 } |
| |
728 |
| |
729 if (show_clipboard) { |
| 558 /* Using connect_swapped means we don't need any wrapper functions */ |
730 /* Using connect_swapped means we don't need any wrapper functions */ |
| 559 cut = pidgin_new_item_from_stock(menu, _("Cu_t"), GTK_STOCK_CUT, |
731 cut = pidgin_new_item_from_stock(menu, _("Cu_t"), GTK_STOCK_CUT, |
| 560 NULL, NULL, 0, 0, NULL); |
732 NULL, NULL, 0, 0, NULL); |
| 561 g_signal_connect_swapped(G_OBJECT(cut), "activate", |
733 g_signal_connect_swapped(G_OBJECT(cut), "activate", |
| 562 G_CALLBACK(webkit_web_view_cut_clipboard), |
734 G_CALLBACK(webkit_web_view_cut_clipboard), |
| 1088 G_CALLBACK(webview_load_finished), NULL); |
1262 G_CALLBACK(webview_load_finished), NULL); |
| 1089 |
1263 |
| 1090 g_signal_connect(G_OBJECT(webview), "resource-request-starting", |
1264 g_signal_connect(G_OBJECT(webview), "resource-request-starting", |
| 1091 G_CALLBACK(webview_resource_loading), NULL); |
1265 G_CALLBACK(webview_resource_loading), NULL); |
| 1092 |
1266 |
| |
1267 g_signal_connect(G_OBJECT(webview), "resource-load-finished", |
| |
1268 G_CALLBACK(webview_resource_loaded), NULL); |
| |
1269 |
| 1093 inspector = webkit_web_view_get_inspector(WEBKIT_WEB_VIEW(webview)); |
1270 inspector = webkit_web_view_get_inspector(WEBKIT_WEB_VIEW(webview)); |
| 1094 g_signal_connect(G_OBJECT(inspector), "inspect-web-view", |
1271 g_signal_connect(G_OBJECT(inspector), "inspect-web-view", |
| 1095 G_CALLBACK(webview_inspector_create), NULL); |
1272 G_CALLBACK(webview_inspector_create), NULL); |
| 1096 g_signal_connect(G_OBJECT(inspector), "show-window", |
1273 g_signal_connect(G_OBJECT(inspector), "show-window", |
| 1097 G_CALLBACK(webview_inspector_show), webview); |
1274 G_CALLBACK(webview_inspector_show), webview); |
| |
1275 |
| |
1276 priv->loaded_images = g_hash_table_new_full(g_str_hash, g_str_equal, |
| |
1277 g_free, (GDestroyNotify)purple_imgstore_unref); |
| 1098 } |
1278 } |
| 1099 |
1279 |
| 1100 GType |
1280 GType |
| 1101 pidgin_webview_get_type(void) |
1281 pidgin_webview_get_type(void) |
| 1102 { |
1282 { |