comparison src/gtkimhtml.c @ 5012:3ee1b1409660

[gaim-migrate @ 5348] javabsp let us save IM images, and I plugged a few memory leaks committer: Tailor Script <tailor@pidgin.im>
author Nathan Walp <nwalp@pidgin.im>
date Sat, 05 Apr 2003 01:45:13 +0000
parents c307d769cefa
children a17a84895585
comparison
equal deleted inserted replaced
5011:330a78666a5b 5012:3ee1b1409660
55 55
56 static gboolean gtk_motion_event_notify(GtkWidget *imhtml, GdkEventMotion *event, gpointer user_data); 56 static gboolean gtk_motion_event_notify(GtkWidget *imhtml, GdkEventMotion *event, gpointer user_data);
57 static gboolean gtk_leave_event_notify(GtkWidget *imhtml, GdkEventCrossing *event, gpointer user_data); 57 static gboolean gtk_leave_event_notify(GtkWidget *imhtml, GdkEventCrossing *event, gpointer user_data);
58 58
59 static gboolean gtk_size_allocate_cb(GtkIMHtml *widget, GtkAllocation *alloc, gpointer user_data); 59 static gboolean gtk_size_allocate_cb(GtkIMHtml *widget, GtkAllocation *alloc, gpointer user_data);
60
61 static gboolean gaim_im_image_clicked(GtkWidget *w, GdkEvent *event, gaim_im_image *image);
62
60 static gint gtk_imhtml_tip (gpointer data); 63 static gint gtk_imhtml_tip (gpointer data);
61 64
62 65
63 /* POINT_SIZE converts from AIM font sizes to point sizes. It probably should be redone in such a 66 /* POINT_SIZE converts from AIM font sizes to point sizes. It probably should be redone in such a
64 * way that it base the sizes off the default font size rather than using arbitrary font sizes. */ 67 * way that it base the sizes off the default font size rather than using arbitrary font sizes. */
797 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ 800 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \
798 } \ 801 } \
799 } \ 802 } \
800 if (url) { \ 803 if (url) { \
801 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "foreground", "blue", "underline", PANGO_UNDERLINE_SINGLE, NULL); \ 804 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "foreground", "blue", "underline", PANGO_UNDERLINE_SINGLE, NULL); \
802 g_signal_connect(G_OBJECT(texttag), "event", G_CALLBACK(tag_event), strdup(url)); \ 805 g_signal_connect(G_OBJECT(texttag), "event", G_CALLBACK(tag_event), g_strdup(url)); \
803 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ 806 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \
804 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, NULL); \ 807 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, NULL); \
805 g_object_set_data(G_OBJECT(texttag), "link_url", g_strdup(url)); \ 808 g_object_set_data(G_OBJECT(texttag), "link_url", g_strdup(url)); \
806 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ 809 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \
807 } \ 810 } \
1133 if (!gdk_pixbuf_loader_write(load, imagedata, im_len, &error)){ 1136 if (!gdk_pixbuf_loader_write(load, imagedata, im_len, &error)){
1134 fprintf(stderr, "IM Image corrupted or unreadable.: %s\n", error->message); 1137 fprintf(stderr, "IM Image corrupted or unreadable.: %s\n", error->message);
1135 } else { 1138 } else {
1136 imagepb = gdk_pixbuf_loader_get_pixbuf(load); 1139 imagepb = gdk_pixbuf_loader_get_pixbuf(load);
1137 if (imagepb) { 1140 if (imagepb) {
1138 scalable = gaim_im_image_new(imagepb); 1141 scalable = gaim_im_image_new(imagepb, g_strdup(src));
1139 NEW_BIT(NEW_SCALABLE_BIT); 1142 NEW_BIT(NEW_SCALABLE_BIT);
1143 g_object_unref(imagepb);
1140 } 1144 }
1141 } 1145 }
1142 1146
1143 gdk_pixbuf_loader_close(load, NULL); 1147 gdk_pixbuf_loader_close(load, NULL);
1144 1148
1419 widget->old_rect = rect; 1423 widget->old_rect = rect;
1420 return FALSE; 1424 return FALSE;
1421 } 1425 }
1422 1426
1423 /* GtkIMHtmlScalable, gaim_im_image, gaim_hr */ 1427 /* GtkIMHtmlScalable, gaim_im_image, gaim_hr */
1424 GtkIMHtmlScalable *gaim_im_image_new(GdkPixbuf *img) 1428 GtkIMHtmlScalable *gaim_im_image_new(GdkPixbuf *img, gchar *filename)
1425 { 1429 {
1426 gaim_im_image *im_image = g_malloc(sizeof(gaim_im_image)); 1430 gaim_im_image *im_image = g_malloc(sizeof(gaim_im_image));
1431 GtkImage *image = GTK_IMAGE(gtk_image_new_from_pixbuf(img));
1427 1432
1428 GTK_IMHTML_SCALABLE(im_image)->scale = gaim_im_image_scale; 1433 GTK_IMHTML_SCALABLE(im_image)->scale = gaim_im_image_scale;
1429 GTK_IMHTML_SCALABLE(im_image)->add_to = gaim_im_image_add_to; 1434 GTK_IMHTML_SCALABLE(im_image)->add_to = gaim_im_image_add_to;
1430 GTK_IMHTML_SCALABLE(im_image)->free = gaim_im_image_free; 1435 GTK_IMHTML_SCALABLE(im_image)->free = gaim_im_image_free;
1431 im_image->image = img; 1436 im_image->image = image;
1432 im_image->width = gdk_pixbuf_get_width(img); 1437 im_image->width = gdk_pixbuf_get_width(img);
1433 im_image->height = gdk_pixbuf_get_height(img); 1438 im_image->height = gdk_pixbuf_get_height(img);
1434 im_image->imhtml = NULL;
1435 im_image->mark = NULL; 1439 im_image->mark = NULL;
1440 im_image->filename = filename;
1436 1441
1437 return GTK_IMHTML_SCALABLE(im_image); 1442 return GTK_IMHTML_SCALABLE(im_image);
1438 } 1443 }
1439 1444
1440 void gaim_im_image_scale(GtkIMHtmlScalable *scale, int width, int height) 1445 void gaim_im_image_scale(GtkIMHtmlScalable *scale, int width, int height)
1441 { 1446 {
1442 gaim_im_image *image = (gaim_im_image *)scale; 1447 gaim_im_image *image = (gaim_im_image *)scale;
1443 1448
1444 if(image->width > width || image->height > height){ 1449 if(image->width > width || image->height > height){
1450 GdkPixbuf *old_image = gtk_image_get_pixbuf(image->image);
1445 GdkPixbuf *new_image = NULL; 1451 GdkPixbuf *new_image = NULL;
1446 GtkTextIter start, end;
1447 float factor; 1452 float factor;
1448 int new_width = image->width, new_height = image->height; 1453 int new_width = image->width, new_height = image->height;
1449
1450 gtk_text_buffer_get_iter_at_mark(image->imhtml->text_buffer, &start, image->mark);
1451 end = start;
1452 gtk_text_iter_forward_char(&end);
1453 gtk_text_buffer_delete(image->imhtml->text_buffer, &start, &end);
1454 1454
1455 if(image->width > width){ 1455 if(image->width > width){
1456 factor = (float)(width)/image->width; 1456 factor = (float)(width)/image->width;
1457 new_width = width; 1457 new_width = width;
1458 new_height = image->height * factor; 1458 new_height = image->height * factor;
1461 factor = (float)(height)/new_height; 1461 factor = (float)(height)/new_height;
1462 new_height = height; 1462 new_height = height;
1463 new_width = new_width * factor; 1463 new_width = new_width * factor;
1464 } 1464 }
1465 1465
1466 gtk_text_buffer_get_iter_at_mark(image->imhtml->text_buffer, &start, image->mark); 1466 new_image = gdk_pixbuf_scale_simple(old_image, new_width, new_height, GDK_INTERP_BILINEAR);
1467 new_image = gdk_pixbuf_scale_simple(image->image, new_width, new_height, GDK_INTERP_BILINEAR); 1467 gtk_image_set_from_pixbuf(image->image, new_image);
1468 gtk_text_buffer_insert_pixbuf(image->imhtml->text_buffer, &start, new_image);
1469
1470 g_object_unref(G_OBJECT(new_image)); 1468 g_object_unref(G_OBJECT(new_image));
1471 } 1469 }
1472 } 1470 }
1473 1471
1474 void gaim_im_image_free(GtkIMHtmlScalable *scale) 1472 void gaim_im_image_free(GtkIMHtmlScalable *scale)
1475 { 1473 {
1476 gaim_im_image *image = (gaim_im_image *)scale; 1474 gaim_im_image *image = (gaim_im_image *)scale;
1477 1475 /*
1478 g_object_unref(image->image); 1476 g_object_unref(image->image);
1477 */
1478 g_free(image->filename);
1479 g_free(scale); 1479 g_free(scale);
1480 } 1480 }
1481 1481
1482 void gaim_im_image_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter) 1482 void gaim_im_image_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter)
1483 { 1483 {
1484 gaim_im_image *image = (gaim_im_image *)scale; 1484 gaim_im_image *image = (gaim_im_image *)scale;
1485 1485 GtkWidget *box = gtk_event_box_new();
1486 image->mark = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, iter, TRUE); 1486 GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter);
1487 gtk_text_buffer_insert_pixbuf(imhtml->text_buffer, iter, image->image); 1487
1488 image->imhtml = imhtml; 1488 gtk_container_add(GTK_CONTAINER(box), GTK_WIDGET(image->image));
1489
1490 gtk_widget_show(GTK_WIDGET(image->image));
1491 gtk_widget_show(box);
1492
1493 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), box, anchor);
1494 g_signal_connect(G_OBJECT(box), "event", G_CALLBACK(gaim_im_image_clicked), image);
1489 } 1495 }
1490 1496
1491 GtkIMHtmlScalable *gaim_hr_new() 1497 GtkIMHtmlScalable *gaim_hr_new()
1492 { 1498 {
1493 gaim_hr *hr = g_malloc(sizeof(gaim_hr)); 1499 gaim_hr *hr = g_malloc(sizeof(gaim_hr));
1519 void gaim_hr_free(GtkIMHtmlScalable *scale) 1525 void gaim_hr_free(GtkIMHtmlScalable *scale)
1520 { 1526 {
1521 /* gtk_widget_destroy(((gaim_hr *)scale)->sep); */ 1527 /* gtk_widget_destroy(((gaim_hr *)scale)->sep); */
1522 g_free(scale); 1528 g_free(scale);
1523 } 1529 }
1530
1531 static void write_img_to_file(GtkWidget *w, GtkFileSelection *sel)
1532 {
1533 const gchar *filename = gtk_file_selection_get_filename(sel);
1534 gaim_im_image *image = g_object_get_data(G_OBJECT(sel), "gaim_im_image");
1535 gchar *type = NULL;
1536 GSList *formats = gdk_pixbuf_get_formats();
1537 GError *error = NULL;
1538
1539 while(formats){
1540 GdkPixbufFormat *format = formats->data;
1541 gchar **extensions = gdk_pixbuf_format_get_extensions(format);
1542 gpointer p = extensions;
1543
1544 while(gdk_pixbuf_format_is_writable(format) && extensions && extensions[0]){
1545 gchar *fmt_ext = extensions[0];
1546 const gchar* file_ext = filename + strlen(filename) - strlen(fmt_ext);
1547
1548 if(!strcmp(fmt_ext, file_ext)){
1549 type = gdk_pixbuf_format_get_name(format);
1550 break;
1551 }
1552
1553 extensions++;
1554 }
1555
1556 g_strfreev(p);
1557
1558 if(type)
1559 break;
1560
1561 formats = formats->next;
1562 }
1563
1564 /* If I can't find a valid type, I will just tell the user about it and then assume
1565 it's a png */
1566 if(!type){
1567 gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
1568 _("Gaim was unable to guess the image type base on the file extension supplied. Defaulting to PNG."));
1569 type = g_strdup("png");
1570 }
1571
1572 gdk_pixbuf_save(gtk_image_get_pixbuf(image->image), filename, type, &error, NULL);
1573
1574 if(error){
1575 gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
1576 _("Error saving image: %s"), error->message);
1577 g_error_free(error);
1578 }
1579
1580 g_slist_free(formats);
1581 g_free(type);
1582 }
1583
1584 static void gaim_im_image_save(GtkWidget *w, gaim_im_image *image)
1585 {
1586 GtkWidget *sel = gtk_file_selection_new(_("Gaim - Save Image"));
1587
1588 gtk_file_selection_set_filename(GTK_FILE_SELECTION(sel), image->filename);
1589 g_object_set_data(G_OBJECT(sel), "gaim_im_image", image);
1590 g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(sel)->ok_button), "clicked",
1591 G_CALLBACK(write_img_to_file), sel);
1592
1593 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(sel)->ok_button), "clicked",
1594 G_CALLBACK(gtk_widget_destroy), sel);
1595 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(sel)->cancel_button), "clicked",
1596 G_CALLBACK(gtk_widget_destroy), sel);
1597
1598 gtk_widget_show(sel);
1599 }
1600
1601 static gboolean gaim_im_image_clicked(GtkWidget *w, GdkEvent *event, gaim_im_image *image)
1602 {
1603 GdkEventButton *event_button = (GdkEventButton *) event;
1604
1605 if (event->type == GDK_BUTTON_RELEASE) {
1606 if(event_button->button == 3) {
1607 GtkWidget *img, *item, *menu;
1608 gchar *text = g_strdup_printf(_("_Save Image..."));
1609 menu = gtk_menu_new();
1610
1611 /* buttons and such */
1612 img = gtk_image_new_from_stock(GTK_STOCK_SAVE, GTK_ICON_SIZE_MENU);
1613 item = gtk_image_menu_item_new_with_mnemonic(text);
1614 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img);
1615 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(gaim_im_image_save), image);
1616 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1617
1618 gtk_widget_show_all(menu);
1619 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
1620 event_button->button, event_button->time);
1621
1622 g_free(text);
1623 return TRUE;
1624 }
1625 }
1626 if(event->type == GDK_BUTTON_PRESS && event_button->button == 3)
1627 return TRUE; /* Clicking the right mouse button on a link shouldn't
1628 be caught by the regular GtkTextView menu */
1629 else
1630 return FALSE; /* Let clicks go through if we didn't catch anything */
1631
1632 }