Mercurial > pidgin
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 } |