Mercurial > pidgin.yaz
comparison pidgin/gtkimhtml.c @ 27842:acef4202e147
propagate from branch 'im.pidgin.pidgin' (head 217103c3e954ff2d295a6590ad3477d357894f9c)
to branch 'im.pidgin.pidgin.yaz' (head 0a5a324e3974fba2b40dcd1bb82fb1cc8b8fcabf)
author | Yoshiki Yazawa <yaz@honeyplanet.jp> |
---|---|
date | Sun, 25 May 2008 04:30:41 +0000 |
parents | 22f8b5512ef4 88d67b1bb52a |
children | 30eaeb7cc076 |
comparison
equal
deleted
inserted
replaced
27841:5fc417883a5d | 27842:acef4202e147 |
---|---|
30 #endif | 30 #endif |
31 | 31 |
32 #include "internal.h" | 32 #include "internal.h" |
33 #include "pidgin.h" | 33 #include "pidgin.h" |
34 #include "pidginstock.h" | 34 #include "pidginstock.h" |
35 #include "gtkutils.h" | |
36 #include "smiley.h" | |
37 #include "imgstore.h" | |
35 | 38 |
36 #include "debug.h" | 39 #include "debug.h" |
37 #include "util.h" | 40 #include "util.h" |
38 #include "gtkimhtml.h" | 41 #include "gtkimhtml.h" |
42 #include "gtksmiley.h" | |
39 #include "gtksourceiter.h" | 43 #include "gtksourceiter.h" |
40 #include "gtksourceundomanager.h" | 44 #include "gtksourceundomanager.h" |
41 #include "gtksourceview-marshal.h" | 45 #include "gtksourceview-marshal.h" |
42 #include <gtk/gtk.h> | 46 #include <gtk/gtk.h> |
43 #include <glib/gerror.h> | 47 #include <glib/gerror.h> |
393 | 397 |
394 /* Don't scroll here if we're in the middle of a smooth scroll */ | 398 /* Don't scroll here if we're in the middle of a smooth scroll */ |
395 if (scroll && imhtml->scroll_time == NULL && | 399 if (scroll && imhtml->scroll_time == NULL && |
396 GTK_WIDGET_REALIZED(imhtml)) | 400 GTK_WIDGET_REALIZED(imhtml)) |
397 gtk_imhtml_scroll_to_end(imhtml, FALSE); | 401 gtk_imhtml_scroll_to_end(imhtml, FALSE); |
402 } | |
403 | |
404 #define DEFAULT_SEND_COLOR "#204a87" | |
405 #define DEFAULT_RECV_COLOR "#cc0000" | |
406 #define DEFAULT_HIGHLIGHT_COLOR "#AF7F00" | |
407 #define DEFAULT_ACTION_COLOR "#062585" | |
408 #define DEFAULT_WHISPER_ACTION_COLOR "#6C2585" | |
409 #define DEFAULT_WHISPER_COLOR "#00FF00" | |
410 | |
411 static void (*parent_style_set)(GtkWidget *widget, GtkStyle *prev_style); | |
412 | |
413 static void | |
414 gtk_imhtml_style_set(GtkWidget *widget, GtkStyle *prev_style) | |
415 { | |
416 int i; | |
417 struct { | |
418 const char *tag; | |
419 const char *color; | |
420 const char *def; | |
421 } styles[] = { | |
422 {"send-name", "send-name-color", DEFAULT_SEND_COLOR}, | |
423 {"receive-name", "receive-name-color", DEFAULT_RECV_COLOR}, | |
424 {"highlight-name", "highlight-name-color", DEFAULT_HIGHLIGHT_COLOR}, | |
425 {"action-name", "action-name-color", DEFAULT_ACTION_COLOR}, | |
426 {"whisper-action-name", "whisper-action-name-color", DEFAULT_WHISPER_ACTION_COLOR}, | |
427 {"whisper-name", "whisper-name-color", DEFAULT_WHISPER_COLOR}, | |
428 {NULL, NULL, NULL} | |
429 }; | |
430 GtkIMHtml *imhtml = GTK_IMHTML(widget); | |
431 GtkTextTagTable *table = gtk_text_buffer_get_tag_table(imhtml->text_buffer); | |
432 | |
433 for (i = 0; styles[i].tag; i++) { | |
434 GdkColor *color = NULL; | |
435 GtkTextTag *tag = gtk_text_tag_table_lookup(table, styles[i].tag); | |
436 if (!tag) { | |
437 purple_debug_warning("gtkimhtml", "Cannot find tag '%s'. This should never happen. Please file a bug.\n", styles[i].tag); | |
438 continue; | |
439 } | |
440 gtk_widget_style_get(widget, styles[i].color, &color, NULL); | |
441 if (color) { | |
442 g_object_set(tag, "foreground-gdk", color, NULL); | |
443 gdk_color_free(color); | |
444 } else { | |
445 GdkColor defcolor; | |
446 gdk_color_parse(styles[i].def, &defcolor); | |
447 g_object_set(tag, "foreground-gdk", &defcolor, NULL); | |
448 } | |
449 } | |
450 parent_style_set(widget, prev_style); | |
398 } | 451 } |
399 | 452 |
400 static gint | 453 static gint |
401 gtk_imhtml_tip_paint (GtkIMHtml *imhtml) | 454 gtk_imhtml_tip_paint (GtkIMHtml *imhtml) |
402 { | 455 { |
1431 gobject_class->finalize = gtk_imhtml_finalize; | 1484 gobject_class->finalize = gtk_imhtml_finalize; |
1432 widget_class->drag_motion = gtk_text_view_drag_motion; | 1485 widget_class->drag_motion = gtk_text_view_drag_motion; |
1433 widget_class->expose_event = gtk_imhtml_expose_event; | 1486 widget_class->expose_event = gtk_imhtml_expose_event; |
1434 parent_size_allocate = widget_class->size_allocate; | 1487 parent_size_allocate = widget_class->size_allocate; |
1435 widget_class->size_allocate = gtk_imhtml_size_allocate; | 1488 widget_class->size_allocate = gtk_imhtml_size_allocate; |
1489 parent_style_set = widget_class->style_set; | |
1490 widget_class->style_set = gtk_imhtml_style_set; | |
1436 | 1491 |
1437 gtk_widget_class_install_style_property(widget_class, g_param_spec_boxed("hyperlink-color", | 1492 gtk_widget_class_install_style_property(widget_class, g_param_spec_boxed("hyperlink-color", |
1438 _("Hyperlink color"), | 1493 _("Hyperlink color"), |
1439 _("Color to draw hyperlinks."), | 1494 _("Color to draw hyperlinks."), |
1440 GDK_TYPE_COLOR, G_PARAM_READABLE)); | 1495 GDK_TYPE_COLOR, G_PARAM_READABLE)); |
1456 GDK_TYPE_COLOR, G_PARAM_READABLE)); | 1511 GDK_TYPE_COLOR, G_PARAM_READABLE)); |
1457 gtk_widget_class_install_style_property(widget_class, g_param_spec_boxed("action-name-color", | 1512 gtk_widget_class_install_style_property(widget_class, g_param_spec_boxed("action-name-color", |
1458 _("Action Message Name Color"), | 1513 _("Action Message Name Color"), |
1459 _("Color to draw the name of an action message."), | 1514 _("Color to draw the name of an action message."), |
1460 GDK_TYPE_COLOR, G_PARAM_READABLE)); | 1515 GDK_TYPE_COLOR, G_PARAM_READABLE)); |
1516 gtk_widget_class_install_style_property(widget_class, g_param_spec_boxed("whisper-action-name-color", | |
1517 _("Action Message Name Color for Whispered Message"), | |
1518 _("Color to draw the name of an action message."), | |
1519 GDK_TYPE_COLOR, G_PARAM_READABLE)); | |
1520 gtk_widget_class_install_style_property(widget_class, g_param_spec_boxed("whisper-name-color", | |
1521 _("Whisper Message Name Color"), | |
1522 _("Color to draw the name of an action message."), | |
1523 GDK_TYPE_COLOR, G_PARAM_READABLE)); | |
1461 | 1524 |
1462 /* Customizable typing notification ... sort of. Example: | 1525 /* Customizable typing notification ... sort of. Example: |
1463 * GtkIMHtml::typing-notification-font = "monospace italic light 8.0" | 1526 * GtkIMHtml::typing-notification-font = "monospace italic light 8.0" |
1464 * GtkIMHtml::typing-notification-color = "#ff0000" | 1527 * GtkIMHtml::typing-notification-color = "#ff0000" |
1465 * GtkIMHtml::typing-notification-enable = 1 | 1528 * GtkIMHtml::typing-notification-enable = 1 |
1517 gtk_text_buffer_create_tag(imhtml->text_buffer, "STRIKE", "strikethrough", TRUE, NULL); | 1580 gtk_text_buffer_create_tag(imhtml->text_buffer, "STRIKE", "strikethrough", TRUE, NULL); |
1518 gtk_text_buffer_create_tag(imhtml->text_buffer, "SUB", "rise", -5000, NULL); | 1581 gtk_text_buffer_create_tag(imhtml->text_buffer, "SUB", "rise", -5000, NULL); |
1519 gtk_text_buffer_create_tag(imhtml->text_buffer, "SUP", "rise", 5000, NULL); | 1582 gtk_text_buffer_create_tag(imhtml->text_buffer, "SUP", "rise", 5000, NULL); |
1520 gtk_text_buffer_create_tag(imhtml->text_buffer, "PRE", "family", "Monospace", NULL); | 1583 gtk_text_buffer_create_tag(imhtml->text_buffer, "PRE", "family", "Monospace", NULL); |
1521 gtk_text_buffer_create_tag(imhtml->text_buffer, "search", "background", "#22ff00", "weight", "bold", NULL); | 1584 gtk_text_buffer_create_tag(imhtml->text_buffer, "search", "background", "#22ff00", "weight", "bold", NULL); |
1585 gtk_text_buffer_create_tag(imhtml->text_buffer, "comment", "weight", PANGO_WEIGHT_NORMAL, | |
1522 #if FALSE && GTK_CHECK_VERSION(2,10,10) | 1586 #if FALSE && GTK_CHECK_VERSION(2,10,10) |
1523 gtk_text_buffer_create_tag(imhtml->text_buffer, "comment", "invisible", FALSE, NULL); | 1587 "invisible", FALSE, |
1524 #endif | 1588 #endif |
1589 NULL); | |
1590 | |
1591 gtk_text_buffer_create_tag(imhtml->text_buffer, "send-name", "weight", PANGO_WEIGHT_BOLD, NULL); | |
1592 gtk_text_buffer_create_tag(imhtml->text_buffer, "receive-name", "weight", PANGO_WEIGHT_BOLD, NULL); | |
1593 gtk_text_buffer_create_tag(imhtml->text_buffer, "highlight-name", "weight", PANGO_WEIGHT_BOLD, NULL); | |
1594 gtk_text_buffer_create_tag(imhtml->text_buffer, "action-name", "weight", PANGO_WEIGHT_BOLD, NULL); | |
1595 gtk_text_buffer_create_tag(imhtml->text_buffer, "whisper-action-name", "weight", PANGO_WEIGHT_BOLD, NULL); | |
1596 gtk_text_buffer_create_tag(imhtml->text_buffer, "whisper-name", "weight", PANGO_WEIGHT_BOLD, NULL); | |
1525 | 1597 |
1526 /* When hovering over a link, we show the hand cursor--elsewhere we show the plain ol' pointer cursor */ | 1598 /* When hovering over a link, we show the hand cursor--elsewhere we show the plain ol' pointer cursor */ |
1527 imhtml->hand_cursor = gdk_cursor_new (GDK_HAND2); | 1599 imhtml->hand_cursor = gdk_cursor_new (GDK_HAND2); |
1528 imhtml->arrow_cursor = gdk_cursor_new (GDK_LEFT_PTR); | 1600 imhtml->arrow_cursor = gdk_cursor_new (GDK_LEFT_PTR); |
1529 imhtml->text_cursor = gdk_cursor_new (GDK_XTERM); | 1601 imhtml->text_cursor = gdk_cursor_new (GDK_XTERM); |
3061 wpos = g_snprintf (ws, len, "%s", tag); | 3133 wpos = g_snprintf (ws, len, "%s", tag); |
3062 gtk_text_buffer_insert_with_tags_by_name(imhtml->text_buffer, iter, ws, wpos, "comment", NULL); | 3134 gtk_text_buffer_insert_with_tags_by_name(imhtml->text_buffer, iter, ws, wpos, "comment", NULL); |
3063 #else | 3135 #else |
3064 if (imhtml->show_comments && !(options & GTK_IMHTML_NO_COMMENTS)) { | 3136 if (imhtml->show_comments && !(options & GTK_IMHTML_NO_COMMENTS)) { |
3065 wpos = g_snprintf (ws, len, "%s", tag); | 3137 wpos = g_snprintf (ws, len, "%s", tag); |
3066 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); | 3138 gtk_text_buffer_insert_with_tags_by_name(imhtml->text_buffer, iter, ws, wpos, "comment", NULL); |
3067 } | 3139 } |
3068 #endif | 3140 #endif |
3069 ws[0] = '\0'; wpos = 0; | 3141 ws[0] = '\0'; wpos = 0; |
3070 | 3142 |
3071 /* NEW_BIT (NEW_COMMENT_BIT); */ | 3143 /* NEW_BIT (NEW_COMMENT_BIT); */ |
3629 #endif /* FILECHOOSER */ | 3701 #endif /* FILECHOOSER */ |
3630 | 3702 |
3631 gtk_widget_show(image->filesel); | 3703 gtk_widget_show(image->filesel); |
3632 } | 3704 } |
3633 | 3705 |
3706 static void | |
3707 gtk_imhtml_custom_smiley_save(GtkWidget *w, GtkIMHtmlImage *image) | |
3708 { | |
3709 /* Create an add dialog */ | |
3710 PidginSmiley *editor = pidgin_smiley_edit(NULL, NULL); | |
3711 pidgin_smiley_editor_set_shortcut(editor, image->filename); | |
3712 pidgin_smiley_editor_set_image(editor, image->pixbuf); | |
3713 } | |
3714 | |
3634 /* | 3715 /* |
3635 * So, um, AIM Direct IM lets you send any file, not just images. You can | 3716 * So, um, AIM Direct IM lets you send any file, not just images. You can |
3636 * just insert a sound or a file or whatever in a conversation. It's | 3717 * just insert a sound or a file or whatever in a conversation. It's |
3637 * basically like file transfer, except there is an icon to open the file | 3718 * basically like file transfer, except there is an icon to open the file |
3638 * embedded in the conversation. Someone should make the Purple core handle | 3719 * embedded in the conversation. Someone should make the Purple core handle |
3653 item = gtk_image_menu_item_new_with_mnemonic(text); | 3734 item = gtk_image_menu_item_new_with_mnemonic(text); |
3654 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); | 3735 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); |
3655 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(gtk_imhtml_image_save), image); | 3736 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(gtk_imhtml_image_save), image); |
3656 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); | 3737 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
3657 | 3738 |
3739 /* Add menu item for adding custom smiley to local smileys */ | |
3740 /* we only add the menu if the image is of "custom smiley size" | |
3741 <= 96x96 pixels */ | |
3742 if (image->width <= 96 && image->height <= 96) { | |
3743 text = g_strdup_printf(_("_Add Custom Smiley...")); | |
3744 img = gtk_image_new_from_stock(GTK_STOCK_ADD, GTK_ICON_SIZE_MENU); | |
3745 item = gtk_image_menu_item_new_with_mnemonic(text); | |
3746 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); | |
3747 g_signal_connect(G_OBJECT(item), "activate", | |
3748 G_CALLBACK(gtk_imhtml_custom_smiley_save), image); | |
3749 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); | |
3750 } | |
3751 | |
3658 gtk_widget_show_all(menu); | 3752 gtk_widget_show_all(menu); |
3659 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, | 3753 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, |
3660 event_button->button, event_button->time); | 3754 event_button->button, event_button->time); |
3661 | 3755 |
3662 g_free(text); | 3756 g_free(text); |
3674 static gboolean gtk_imhtml_smiley_clicked(GtkWidget *w, GdkEvent *event, GtkIMHtmlSmiley *smiley) | 3768 static gboolean gtk_imhtml_smiley_clicked(GtkWidget *w, GdkEvent *event, GtkIMHtmlSmiley *smiley) |
3675 { | 3769 { |
3676 GdkPixbufAnimation *anim = NULL; | 3770 GdkPixbufAnimation *anim = NULL; |
3677 GtkIMHtmlScalable *image = NULL; | 3771 GtkIMHtmlScalable *image = NULL; |
3678 gboolean ret; | 3772 gboolean ret; |
3679 | 3773 |
3680 if (event->type != GDK_BUTTON_RELEASE || ((GdkEventButton*)event)->button != 3) | 3774 if (event->type != GDK_BUTTON_RELEASE || ((GdkEventButton*)event)->button != 3) |
3681 return FALSE; | 3775 return FALSE; |
3682 | 3776 |
3683 anim = gtk_smiley_get_image(smiley); | 3777 anim = gtk_smiley_get_image(smiley); |
3684 if (!anim) | 3778 if (!anim) |
4910 return buf; | 5004 return buf; |
4911 } else if (strncmp(name, "FONT SIZE ", 10) == 0) { | 5005 } else if (strncmp(name, "FONT SIZE ", 10) == 0) { |
4912 g_snprintf(buf, sizeof(buf), "<font size=\"%s\">", &name[10]); | 5006 g_snprintf(buf, sizeof(buf), "<font size=\"%s\">", &name[10]); |
4913 return buf; | 5007 return buf; |
4914 } else { | 5008 } else { |
4915 return ""; | 5009 char *str = buf; |
5010 gboolean isset; | |
5011 int ivalue = 0; | |
5012 GdkColor *color = NULL; | |
5013 GObject *obj = G_OBJECT(tag); | |
5014 gboolean empty = TRUE; | |
5015 | |
5016 str += g_snprintf(str, sizeof(buf) - (str - buf), "<span style='"); | |
5017 | |
5018 /* Weight */ | |
5019 g_object_get(obj, "weight-set", &isset, "weight", &ivalue, NULL); | |
5020 if (isset) { | |
5021 const char *weight = ""; | |
5022 if (ivalue >= PANGO_WEIGHT_ULTRABOLD) | |
5023 weight = "bolder"; | |
5024 else if (ivalue >= PANGO_WEIGHT_BOLD) | |
5025 weight = "bold"; | |
5026 else if (ivalue >= PANGO_WEIGHT_NORMAL) | |
5027 weight = "normal"; | |
5028 else | |
5029 weight = "lighter"; | |
5030 | |
5031 str += g_snprintf(str, sizeof(buf) - (str - buf), "font-weight: %s;", weight); | |
5032 empty = FALSE; | |
5033 } | |
5034 | |
5035 /* Foreground color */ | |
5036 g_object_get(obj, "foreground-set", &isset, "foreground-gdk", &color, NULL); | |
5037 if (isset && color) { | |
5038 str += g_snprintf(str, sizeof(buf) - (str - buf), | |
5039 "color: #%02x%02x%02x;", | |
5040 color->red >> 8, color->green >> 8, color->blue >> 8); | |
5041 gdk_color_free(color); | |
5042 empty = FALSE; | |
5043 } | |
5044 | |
5045 /* Background color */ | |
5046 g_object_get(obj, "background-set", &isset, "background-gdk", &color, NULL); | |
5047 if (isset && color) { | |
5048 str += g_snprintf(str, sizeof(buf) - (str - buf), | |
5049 "background: #%02x%02x%02x;", | |
5050 color->red >> 8, color->green >> 8, color->blue >> 8); | |
5051 gdk_color_free(color); | |
5052 empty = FALSE; | |
5053 } | |
5054 | |
5055 /* Underline */ | |
5056 g_object_get(obj, "underline-set", &isset, "underline", &ivalue, NULL); | |
5057 if (isset) { | |
5058 switch (ivalue) { | |
5059 case PANGO_UNDERLINE_NONE: | |
5060 case PANGO_UNDERLINE_ERROR: | |
5061 break; | |
5062 default: | |
5063 str += g_snprintf(str, sizeof(buf) - (str - buf), "text-decoration: underline;"); | |
5064 } | |
5065 } | |
5066 | |
5067 g_snprintf(str, sizeof(buf) - (str - buf), "'>"); | |
5068 | |
5069 return (empty ? "" : buf); | |
4916 } | 5070 } |
4917 } | 5071 } |
4918 | 5072 |
4919 static const gchar *tag_to_html_end(GtkTextTag *tag) | 5073 static const gchar *tag_to_html_end(GtkTextTag *tag) |
4920 { | 5074 { |
4942 } else if (strncmp(name, "FONT FACE ", 10) == 0) { | 5096 } else if (strncmp(name, "FONT FACE ", 10) == 0) { |
4943 return "</font>"; | 5097 return "</font>"; |
4944 } else if (strncmp(name, "FONT SIZE ", 10) == 0) { | 5098 } else if (strncmp(name, "FONT SIZE ", 10) == 0) { |
4945 return "</font>"; | 5099 return "</font>"; |
4946 } else { | 5100 } else { |
5101 const char *props[] = {"weight-set", "foreground-set", "background-set", | |
5102 "size-set", "underline-set", NULL}; | |
5103 int i; | |
5104 for (i = 0; props[i]; i++) { | |
5105 gboolean set = FALSE; | |
5106 g_object_get(G_OBJECT(tag), props[i], &set, NULL); | |
5107 if (set) | |
5108 return "</span>"; | |
5109 } | |
5110 | |
4947 return ""; | 5111 return ""; |
4948 } | 5112 } |
4949 } | 5113 } |
4950 | 5114 |
4951 static gboolean tag_ends_here(GtkTextTag *tag, GtkTextIter *iter, GtkTextIter *niter) | 5115 static gboolean tag_ends_here(GtkTextTag *tag, GtkTextIter *iter, GtkTextIter *niter) |
5271 } | 5435 } |
5272 | 5436 |
5273 if (flags & PURPLE_CONNECTION_NO_IMAGES) | 5437 if (flags & PURPLE_CONNECTION_NO_IMAGES) |
5274 buttons &= ~GTK_IMHTML_IMAGE; | 5438 buttons &= ~GTK_IMHTML_IMAGE; |
5275 | 5439 |
5440 if (flags & PURPLE_CONNECTION_ALLOW_CUSTOM_SMILEY) | |
5441 buttons |= GTK_IMHTML_CUSTOM_SMILEY; | |
5442 else | |
5443 buttons &= ~GTK_IMHTML_CUSTOM_SMILEY; | |
5444 | |
5276 gtk_imhtml_set_format_functions(imhtml, buttons); | 5445 gtk_imhtml_set_format_functions(imhtml, buttons); |
5277 } | 5446 } |
5278 | 5447 |
5279 | 5448 /******* |
5449 * GtkIMHtmlSmiley functions | |
5450 *******/ | |
5451 static void gtk_custom_smiley_allocated(GdkPixbufLoader *loader, gpointer user_data) | |
5452 { | |
5453 GtkIMHtmlSmiley *smiley; | |
5454 | |
5455 smiley = (GtkIMHtmlSmiley *)user_data; | |
5456 smiley->icon = gdk_pixbuf_loader_get_animation(loader); | |
5457 | |
5458 if (smiley->icon) | |
5459 g_object_ref(G_OBJECT(smiley->icon)); | |
5460 #ifdef DEBUG_CUSTOM_SMILEY | |
5461 purple_debug_info("custom-smiley", "gtk_custom_smiley_allocated(): got GdkPixbufAnimation %p for smiley '%s'\n", smiley->icon, smiley->smile); | |
5462 #endif | |
5463 } | |
5464 | |
5465 static void gtk_custom_smiley_closed(GdkPixbufLoader *loader, gpointer user_data) | |
5466 { | |
5467 GtkIMHtmlSmiley *smiley; | |
5468 GtkWidget *icon = NULL; | |
5469 GtkTextChildAnchor *anchor = NULL; | |
5470 GSList *current = NULL; | |
5471 | |
5472 smiley = (GtkIMHtmlSmiley *)user_data; | |
5473 if (!smiley->imhtml) { | |
5474 #ifdef DEBUG_CUSTOM_SMILEY | |
5475 purple_debug_error("custom-smiley", "gtk_custom_smiley_closed(): orphan smiley found: %p\n", smiley); | |
5476 #endif | |
5477 g_object_unref(G_OBJECT(loader)); | |
5478 smiley->loader = NULL; | |
5479 return; | |
5480 } | |
5481 | |
5482 for (current = smiley->anchors; current; current = g_slist_next(current)) { | |
5483 | |
5484 icon = gtk_image_new_from_animation(smiley->icon); | |
5485 | |
5486 #ifdef DEBUG_CUSTOM_SMILEY | |
5487 purple_debug_info("custom-smiley", "gtk_custom_smiley_closed(): got GtkImage %p from GtkPixbufAnimation %p for smiley '%s'\n", | |
5488 icon, smiley->icon, smiley->smile); | |
5489 #endif | |
5490 if (icon) { | |
5491 GList *wids; | |
5492 gtk_widget_show(icon); | |
5493 | |
5494 anchor = GTK_TEXT_CHILD_ANCHOR(current->data); | |
5495 wids = gtk_text_child_anchor_get_widgets(anchor); | |
5496 | |
5497 g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_plaintext", purple_unescape_html(smiley->smile), g_free); | |
5498 g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_htmltext", g_strdup(smiley->smile), g_free); | |
5499 | |
5500 if (smiley->imhtml) { | |
5501 if (wids) { | |
5502 GList *children = gtk_container_get_children(GTK_CONTAINER(wids->data)); | |
5503 g_list_foreach(children, (GFunc)gtk_widget_destroy, NULL); | |
5504 g_list_free(children); | |
5505 gtk_container_add(GTK_CONTAINER(wids->data), icon); | |
5506 } else | |
5507 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(smiley->imhtml), icon, anchor); | |
5508 } | |
5509 g_list_free(wids); | |
5510 } | |
5511 | |
5512 } | |
5513 | |
5514 g_slist_free(smiley->anchors); | |
5515 smiley->anchors = NULL; | |
5516 | |
5517 g_object_unref(G_OBJECT(loader)); | |
5518 smiley->loader = NULL; | |
5519 } | |
5520 | |
5521 static void | |
5522 gtk_custom_smiley_size_prepared(GdkPixbufLoader *loader, gint width, gint height, gpointer data) | |
5523 { | |
5524 #define CUSTOM_SMILEY_SIZE 96 /* XXX: Should this be a theme setting? */ | |
5525 if (width <= CUSTOM_SMILEY_SIZE && height <= CUSTOM_SMILEY_SIZE) | |
5526 return; | |
5527 | |
5528 if (width >= height) { | |
5529 height = height * CUSTOM_SMILEY_SIZE / width; | |
5530 width = CUSTOM_SMILEY_SIZE; | |
5531 } else { | |
5532 width = width * CUSTOM_SMILEY_SIZE / height; | |
5533 height = CUSTOM_SMILEY_SIZE; | |
5534 } | |
5535 | |
5536 gdk_pixbuf_loader_set_size(loader, width, height); | |
5537 } | |
5538 | |
5539 void | |
5540 gtk_imhtml_smiley_reload(GtkIMHtmlSmiley *smiley) | |
5541 { | |
5542 if (smiley->icon) | |
5543 g_object_unref(smiley->icon); | |
5544 if (smiley->loader) | |
5545 g_object_unref(smiley->loader); /* XXX: does this crash? */ | |
5546 | |
5547 smiley->icon = NULL; | |
5548 smiley->loader = NULL; | |
5549 | |
5550 if (smiley->file) { | |
5551 /* We do not use the pixbuf loader for a smiley that can be loaded | |
5552 * from a file. (e.g., local custom smileys) | |
5553 */ | |
5554 return; | |
5555 } | |
5556 | |
5557 smiley->loader = gdk_pixbuf_loader_new(); | |
5558 | |
5559 g_signal_connect(smiley->loader, "area_prepared", G_CALLBACK(gtk_custom_smiley_allocated), smiley); | |
5560 g_signal_connect(smiley->loader, "closed", G_CALLBACK(gtk_custom_smiley_closed), smiley); | |
5561 g_signal_connect(smiley->loader, "size_prepared", G_CALLBACK(gtk_custom_smiley_size_prepared), smiley); | |
5562 } | |
5563 | |
5564 GtkIMHtmlSmiley *gtk_imhtml_smiley_create(const char *file, const char *shortcut, gboolean hide, | |
5565 GtkIMHtmlSmileyFlags flags) | |
5566 { | |
5567 GtkIMHtmlSmiley *smiley = g_new0(GtkIMHtmlSmiley, 1); | |
5568 smiley->file = g_strdup(file); | |
5569 smiley->smile = g_strdup(shortcut); | |
5570 smiley->hidden = hide; | |
5571 smiley->flags = flags; | |
5572 gtk_imhtml_smiley_reload(smiley); | |
5573 return smiley; | |
5574 } | |
5575 | |
5576 void gtk_imhtml_smiley_destroy(GtkIMHtmlSmiley *smiley) | |
5577 { | |
5578 g_free(smiley->smile); | |
5579 g_free(smiley->file); | |
5580 if (smiley->icon) | |
5581 g_object_unref(smiley->icon); | |
5582 if (smiley->loader) | |
5583 g_object_unref(smiley->loader); | |
5584 g_free(smiley); | |
5585 } | |
5586 |