Yo.
gtk1-stable
v0_59_9
2003-03-01, Sean Egan
* Copyright (C) 2000, Eric Warmenhoven <warmenhoven@yahoo.com> * This program is free software; you can redistribute it and/or modify * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #ifdef HAVE_LANGINFO_CODESET #include <gdk-pixbuf/gdk-pixbuf.h> #include <gdk-pixbuf/gdk-pixbuf-loader.h> #include "pixmaps/broken.xpm" #define GTK_IMHTML_GET_STYLE_FONT(style) (style)->font #define GTK_CLASS_TYPE(class) (class)->type #include "pixmaps/angel.xpm" #include "pixmaps/bigsmile.xpm" #include "pixmaps/burp.xpm" #include "pixmaps/crossedlips.xpm" #include "pixmaps/cry.xpm" #include "pixmaps/embarrassed.xpm" #include "pixmaps/kiss.xpm" #include "pixmaps/moneymouth.xpm" #include "pixmaps/sad.xpm" #include "pixmaps/scream.xpm" #include "pixmaps/smile.xpm" #include "pixmaps/smile8.xpm" #include "pixmaps/think.xpm" #include "pixmaps/tongue.xpm" #include "pixmaps/wink.xpm" #include "pixmaps/yell.xpm" #define POINT_SIZE(x) (imhtml->use_pointsize ? x * 10 : \ _point_sizes [MIN ((x), MAX_FONT_SIZE) - 1]) static gint _point_sizes [] = { 80, 100, 120, 140, 200, 300, 400 }; #define DEFAULT_PRE_FACE "courier" #define TOOLTIP_TIMEOUT 500 #define DIFF(a, b) (((a) > (b)) ? ((a) - (b)) : ((b) - (a))) #define DRAW_IMG(x) (((x)->type == TYPE_IMG) || (imhtml->smileys && ((x)->type == TYPE_SMILEY))) typedef struct _GtkIMHtmlBit GtkIMHtmlBit; typedef struct _FontDetail FontDetail; GtkSmileyTree **children; return g_new0 (GtkSmileyTree, 1); gtk_smiley_tree_insert (GtkSmileyTree *tree, t->values = g_string_new (""); pos = strchr (t->values->str, *x); t->values = g_string_append_c (t->values, *x); index = t->values->len - 1; t->children = g_realloc (t->children, t->values->len * sizeof (GtkSmileyTree *)); t->children [index] = g_new0 (GtkSmileyTree, 1); index = (int) pos - (int) t->values->str; gtk_smiley_tree_remove (GtkSmileyTree *tree, pos = strchr (t->values->str, *x); t = t->children [(int) pos - (int) t->values->str]; gtk_smiley_tree_lookup (GtkSmileyTree *tree, pos = strchr (t->values->str, *x); t = t->children [(int) pos - (int) t->values->str]; gtk_smiley_tree_image (GtkSmileyTree *tree, pos = strchr (t->values->str, *x); t = t->children [(int) pos - (int) t->values->str]; gtk_smiley_tree_destroy (GtkSmileyTree *tree) GSList *list = g_slist_append (NULL, tree); GtkSmileyTree *t = list->data; list = g_slist_remove(list, t); for (i = 0; i < t->values->len; i++) list = g_slist_append (list, t->children [i]); g_string_free (t->values, TRUE); gtk_imhtml_remove_smileys (GtkIMHtml *imhtml) g_return_if_fail (imhtml != NULL); g_return_if_fail (GTK_IS_IMHTML (imhtml)); gtk_smiley_tree_destroy (imhtml->smiley_data); imhtml->smiley_data = gtk_smiley_tree_new (); gtk_imhtml_reset_smileys (GtkIMHtml *imhtml) gtk_imhtml_remove_smileys(imhtml); gtk_imhtml_init_smileys (imhtml); gtk_imhtml_set_use_pointsize (GtkIMHtml *imhtml, gboolean point) imhtml->use_pointsize = point; static GtkLayoutClass *parent_class = NULL; static guint signals [LAST_SIGNAL] = { 0 }; static void gtk_imhtml_draw_bit (GtkIMHtml *, GtkIMHtmlBit *); static GdkColor *gtk_imhtml_get_color (const gchar *); static gint gtk_imhtml_motion_notify_event (GtkWidget *, GdkEventMotion *); gtk_imhtml_destroy (GtkObject *object) imhtml = GTK_IMHTML (object); gtk_imhtml_clear (imhtml); if (imhtml->selected_text) g_string_free (imhtml->selected_text, TRUE); if (imhtml->default_font) gdk_font_unref (imhtml->default_font); if (imhtml->default_fg_color) gdk_color_free (imhtml->default_fg_color); if (imhtml->default_bg_color) gdk_color_free (imhtml->default_bg_color); if (imhtml->default_hl_color) gdk_color_free (imhtml->default_hl_color); if (imhtml->default_hlfg_color) gdk_color_free (imhtml->default_hlfg_color); gdk_cursor_destroy (imhtml->hand_cursor); gdk_cursor_destroy (imhtml->arrow_cursor); gtk_smiley_tree_destroy (imhtml->smiley_data); if (GTK_OBJECT_CLASS (parent_class)->destroy != NULL) (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); gtk_imhtml_realize (GtkWidget *widget) GdkWindowAttr attributes; g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_IMHTML (widget)); imhtml = GTK_IMHTML (widget); GTK_WIDGET_SET_FLAGS (imhtml, GTK_REALIZED); attributes.window_type = GDK_WINDOW_CHILD; attributes.x = widget->allocation.x; attributes.y = widget->allocation.y; attributes.width = widget->allocation.width; attributes.height = widget->allocation.height; attributes.wclass = GDK_INPUT_OUTPUT; attributes.visual = gtk_widget_get_visual (widget); attributes.colormap = gtk_widget_get_colormap (widget); attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK; attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); gdk_window_set_user_data (widget->window, widget); attributes.x = widget->style->klass->xthickness + BORDER_SIZE; attributes.y = widget->style->klass->xthickness + BORDER_SIZE; attributes.width = MAX (1, (gint) widget->allocation.width - (gint) attributes.x * 2); attributes.height = MAX (1, (gint) widget->allocation.height - (gint) attributes.y * 2); attributes.event_mask = gtk_widget_get_events (widget) | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_EXPOSURE_MASK | GDK_LEAVE_NOTIFY_MASK; GTK_LAYOUT (imhtml)->bin_window = gdk_window_new (widget->window, &attributes, attributes_mask); gdk_window_set_user_data (GTK_LAYOUT (imhtml)->bin_window, widget); widget->style = gtk_style_attach (widget->style, widget->window); gdk_window_set_cursor (widget->window, imhtml->arrow_cursor); imhtml->default_font = gdk_font_ref (GTK_IMHTML_GET_STYLE_FONT (widget->style)); gdk_window_set_background (widget->window, &widget->style->base [GTK_STATE_NORMAL]); gdk_window_set_background (GTK_LAYOUT (imhtml)->bin_window, &widget->style->base [GTK_STATE_NORMAL]); imhtml->default_fg_color = gdk_color_copy (>K_WIDGET (imhtml)->style->fg [GTK_STATE_NORMAL]); imhtml->default_bg_color = gdk_color_copy (>K_WIDGET (imhtml)->style->base [GTK_STATE_NORMAL]); imhtml->default_hl_color = gdk_color_copy (>K_WIDGET (imhtml)->style->bg [GTK_STATE_SELECTED]); imhtml->default_hlfg_color=gdk_color_copy (>K_WIDGET (imhtml)->style->fg [GTK_STATE_SELECTED]); gdk_window_show (GTK_LAYOUT (imhtml)->bin_window); similar_colors (GdkColor *bg, if ((DIFF (bg->red, fg->red) < COLOR_DIFF) && (DIFF (bg->green, fg->green) < COLOR_DIFF) && (DIFF (bg->blue, fg->blue) < COLOR_DIFF)) { fg->red = (0xff00 - COLOR_MOD > bg->red) ? bg->red + COLOR_MOD : bg->red - COLOR_MOD; fg->green = (0xff00 - COLOR_MOD > bg->green) ? bg->green + COLOR_MOD : bg->green - COLOR_MOD; fg->blue = (0xff00 - COLOR_MOD > bg->blue) ? bg->blue + COLOR_MOD : bg->blue - COLOR_MOD; draw_text (GtkIMHtml *imhtml, GdkWindow *window = GTK_LAYOUT (imhtml)->bin_window; gchar *start = NULL, *end = NULL; if (GTK_LAYOUT (imhtml)->freeze_count) gc = gdk_gc_new (window); cmap = gtk_widget_get_colormap (GTK_WIDGET (imhtml)); xoff = GTK_LAYOUT (imhtml)->hadjustment->value; yoff = GTK_LAYOUT (imhtml)->vadjustment->value; gdk_color_alloc (cmap, bit->bg); gdk_gc_set_foreground (gc, bit->bg); gdk_color_alloc (cmap, imhtml->default_bg_color); gdk_gc_set_foreground (gc, imhtml->default_bg_color); bg = imhtml->default_bg_color; gdk_draw_rectangle (window, gc, TRUE, line->x - xoff, line->y - yoff, line->width ? line->width : imhtml->xsize, line->height); gdk_color_alloc (cmap, bit->back); gdk_gc_set_foreground (gc, bit->back); gdk_draw_rectangle (window, gc, TRUE, line->x - xoff, line->y - yoff, gdk_string_width (bit->font, line->text), line->height); bg = gdk_color_copy (bg); if ((line->sel_start > line->sel_end) && (line->sel_end != NULL)) { x = gdk_text_width (bit->font, line->text, start - line->text); end = strchr(line->text, '\0'); width = gdk_text_width (bit->font, line->text, end - line->text) - x; gdk_gc_set_foreground (gc, imhtml->default_hl_color); gdk_draw_rectangle (window, gc, TRUE, x + line->x - xoff, line->y - yoff, gdk_gc_set_foreground (gc, imhtml->default_hlfg_color); fg = gdk_color_copy(imhtml->default_hlfg_color); GdkColor *tc = gtk_imhtml_get_color ("#0000a0"); gdk_color_alloc (cmap, tc); gdk_gc_set_foreground (gc, tc); fg = gdk_color_copy (tc); gdk_color_alloc (cmap, bit->fore); gdk_gc_set_foreground (gc, bit->fore); fg = gdk_color_copy (bit->fore); gdk_color_alloc (cmap, imhtml->default_fg_color); gdk_gc_set_foreground (gc, imhtml->default_fg_color); fg = gdk_color_copy (imhtml->default_fg_color); if (similar_colors (bg, fg)) { gdk_color_alloc (cmap, fg); gdk_gc_set_foreground (gc, fg); gdk_draw_text (window, bit->font, gc, line->x - xoff, line->y - yoff + line->ascent, line->text, start - line->text); offset = gdk_text_width(bit->font, line->text, start - line->text); if (bit->underline || bit->url) gdk_draw_rectangle (window, gc, TRUE, line->x - xoff, line->y - yoff + line->ascent + 1, gdk_draw_rectangle (window, gc, TRUE, line->x - xoff, line->y - yoff + line->ascent - (bit->font->ascent / 2), gdk_gc_set_foreground (gc, imhtml->default_hlfg_color); gdk_draw_text (window, bit->font, gc, line->x - xoff + offset, line->y - yoff + line->ascent, start, end - start); if (bit->underline || bit->url) gdk_draw_rectangle (window, gc, TRUE, line->x - xoff + offset, line->y - yoff + line->ascent + 1, gdk_text_width(bit->font, line->text, end - start), 1); gdk_draw_rectangle (window, gc, TRUE, line->x - xoff + offset, line->y - yoff + line->ascent - (bit->font->ascent / 2), gdk_text_width(bit->font, line->text, end - start), 1); offset = gdk_text_width(bit->font, line->text, end - line->text); gdk_gc_set_foreground (gc, fg); gdk_draw_string (window, bit->font, gc, line->x - xoff + offset, line->y - yoff + line->ascent, end); if (bit->underline || bit->url) gdk_draw_rectangle (window, gc, TRUE, line->x - xoff + offset, line->y - yoff + line->ascent + 1, gdk_string_width(bit->font, end), 1); gdk_draw_rectangle (window, gc, TRUE, line->x - xoff + offset, line->y - yoff + line->ascent - (bit->font->ascent / 2), gdk_string_width(bit->font, end), 1); gdk_draw_string (window, bit->font, gc, line->x - xoff, line->y - yoff + line->ascent, line->text); if (bit->underline || bit->url) gdk_draw_rectangle (window, gc, TRUE, line->x - xoff, line->y - yoff + line->ascent + 1, gdk_string_width (bit->font, line->text), 1); gdk_draw_rectangle (window, gc, TRUE, line->x - xoff, line->y - yoff + line->ascent - (bit->font->ascent / 2), gdk_string_width (bit->font, line->text), 1); draw_img (GtkIMHtml *imhtml, gint width, height, hoff; GdkWindow *window = GTK_LAYOUT (imhtml)->bin_window; if (GTK_LAYOUT (imhtml)->freeze_count) gdk_window_get_size (bit->pm, &width, &height); hoff = (line->height - height) / 2; xoff = GTK_LAYOUT (imhtml)->hadjustment->value; yoff = GTK_LAYOUT (imhtml)->vadjustment->value; gc = gdk_gc_new (window); cmap = gtk_widget_get_colormap (GTK_WIDGET (imhtml)); gdk_color_alloc (cmap, bit->bg); gdk_gc_set_foreground (gc, bit->bg); gdk_color_alloc (cmap, imhtml->default_bg_color); gdk_gc_set_foreground (gc, imhtml->default_bg_color); gdk_draw_rectangle (window, gc, TRUE, line->x - xoff, line->y - yoff, line->width, line->height); gdk_color_alloc (cmap, imhtml->default_hl_color); gdk_gc_set_foreground(gc, imhtml->default_hl_color); gdk_draw_rectangle (window, gc, TRUE, line->x - xoff, line->y - yoff, } else if (bit->back != NULL) { gdk_color_alloc (cmap, bit->back); gdk_gc_set_foreground (gc, bit->back); gdk_gc_set_clip_mask(gc, bit->bm); gdk_gc_set_clip_origin(gc, line->x - xoff, line->y - yoff + hoff); gdk_draw_pixmap (window, gc, bit->pm, 0, 0, line->x - xoff, line->y - yoff + hoff, -1, -1); draw_line (GtkIMHtml *imhtml, if (GTK_LAYOUT (imhtml)->freeze_count) xoff = GTK_LAYOUT (imhtml)->hadjustment->value; yoff = GTK_LAYOUT (imhtml)->vadjustment->value; drawable = GTK_LAYOUT (imhtml)->bin_window; cmap = gtk_widget_get_colormap (GTK_WIDGET (imhtml)); gc = gdk_gc_new (drawable); gdk_color_alloc (cmap, imhtml->default_hl_color); gdk_gc_set_foreground (gc, imhtml->default_hl_color); } else if (bit->bg != NULL) { gdk_color_alloc (cmap, bit->bg); gdk_gc_set_foreground (gc, bit->bg); gdk_color_alloc (cmap, imhtml->default_bg_color); gdk_gc_set_foreground (gc, imhtml->default_bg_color); gdk_draw_rectangle (drawable, gc, TRUE, line->x - xoff, line->y - yoff, line->width, line->height); gdk_color_alloc (cmap, imhtml->default_hlfg_color); gdk_gc_set_foreground (gc, imhtml->default_hlfg_color); gdk_color_alloc (cmap, imhtml->default_fg_color); gdk_gc_set_foreground (gc, imhtml->default_fg_color); line_height = line->height / 2; gdk_draw_rectangle (drawable, gc, TRUE, line->x - xoff, line->y - yoff + line_height / 2, line->width, line_height); gtk_imhtml_draw_focus (GtkWidget *widget) imhtml = GTK_IMHTML (widget); if (!GTK_WIDGET_DRAWABLE (widget)) if (GTK_WIDGET_HAS_FOCUS (widget)) { gtk_paint_focus (widget->style, widget->window, NULL, widget, "text", 0, 0, widget->allocation.width - 1, widget->allocation.height - 1); x = 1; y = 1; w = 2; h = 2; gtk_paint_shadow (widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_IN, NULL, widget, "text", x, y, widget->allocation.width - w, widget->allocation.height - h); gtk_imhtml_draw_exposed (GtkIMHtml *imhtml) x = GTK_LAYOUT (imhtml)->hadjustment->value; y = GTK_LAYOUT (imhtml)->vadjustment->value; gdk_window_get_size (GTK_LAYOUT (imhtml)->bin_window, &width, &height); if ((line->x <= x + width) && (line->y <= y + height) && (x <= line->x + line->width) && (y <= line->y + line->height)) } else if (bit->type == TYPE_SEP) { if ((line->x <= x + width) && (line->y <= y + height) && (x <= line->x + line->width) && (y <= line->y + line->height)) draw_line (imhtml, line); line = chunks->next->data; if ((line->x <= x + width) && (line->y <= y + height) && (x <= line->x + line->width) && (y <= line->y + line->height)) draw_text (imhtml, line); if ((line->x <= x + width) && (line->y <= y + height) && (x <= line->x + line->width) && (y <= line->y + line->height)) draw_text (imhtml, line); chunks = g_list_next (chunks); bits = g_list_next (bits); gtk_imhtml_draw_focus (GTK_WIDGET (imhtml)); gtk_imhtml_draw (GtkWidget *widget, imhtml = GTK_IMHTML (widget); gtk_imhtml_draw_exposed (imhtml); gtk_imhtml_style_set (GtkWidget *widget, g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_IMHTML (widget)); if (GTK_WIDGET_CLASS (parent_class)->style_set) (* GTK_WIDGET_CLASS (parent_class)->style_set) (widget, style); if (!GTK_WIDGET_REALIZED (widget)) imhtml = GTK_IMHTML (widget); if (imhtml->default_fg_color) gdk_color_free(imhtml->default_fg_color); if (imhtml->default_bg_color) gdk_color_free(imhtml->default_bg_color); if (imhtml->default_hl_color) gdk_color_free(imhtml->default_hl_color); if (imhtml->default_hlfg_color) gdk_color_free(imhtml->default_hlfg_color); imhtml->default_fg_color = gdk_color_copy (>K_WIDGET (imhtml)->style->fg [GTK_STATE_NORMAL]); imhtml->default_bg_color = gdk_color_copy (>K_WIDGET (imhtml)->style->base [GTK_STATE_NORMAL]); imhtml->default_hl_color = gdk_color_copy (>K_WIDGET (imhtml)->style->bg [GTK_STATE_SELECTED]); imhtml->default_hlfg_color=gdk_color_copy (>K_WIDGET (imhtml)->style->fg [GTK_STATE_SELECTED]); if (imhtml->default_font) gdk_font_unref (imhtml->default_font); imhtml->default_font = gdk_font_ref (GTK_IMHTML_GET_STYLE_FONT (widget->style)); gdk_window_set_background (widget->window, &widget->style->base [GTK_STATE_NORMAL]); gdk_window_set_background (GTK_LAYOUT (imhtml)->bin_window, &widget->style->base [GTK_STATE_NORMAL]); gtk_imhtml_draw_exposed (imhtml); gtk_imhtml_expose_event (GtkWidget *widget, g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GTK_IS_IMHTML (widget), FALSE); imhtml = GTK_IMHTML (widget); gtk_imhtml_draw_exposed (imhtml); gtk_imhtml_redraw_all (GtkIMHtml *imhtml) vadj = GTK_LAYOUT (imhtml)->vadjustment; oldvalue = vadj->value / vadj->upper; gtk_layout_freeze (GTK_LAYOUT (imhtml)); g_list_free (imhtml->line); g_free (imhtml->click->data); imhtml->click = g_list_remove (imhtml->click, imhtml->click->data); if (GTK_LAYOUT (imhtml)->vadjustment->value < TOP_BORDER) gdk_window_clear_area (GTK_LAYOUT (imhtml)->bin_window, 0, 0, TOP_BORDER - GTK_LAYOUT (imhtml)->vadjustment->value); struct line_info *li = bit->chunks->data; bit->chunks = g_list_remove (bit->chunks, li); gtk_imhtml_draw_bit (imhtml, bit); GTK_LAYOUT (imhtml)->height = imhtml->y; GTK_LAYOUT (imhtml)->vadjustment->upper = imhtml->y; gtk_signal_emit_by_name (GTK_OBJECT (GTK_LAYOUT (imhtml)->vadjustment), "changed"); gtk_widget_set_usize (GTK_WIDGET (imhtml), -1, imhtml->y); gtk_adjustment_set_value (vadj, vadj->upper * oldvalue); if (GTK_LAYOUT (imhtml)->bin_window && (imhtml->y < oldy)) { gc = gdk_gc_new (GTK_LAYOUT (imhtml)->bin_window); cmap = gtk_widget_get_colormap (GTK_WIDGET (imhtml)); gdk_color_alloc (cmap, imhtml->default_bg_color); gdk_gc_set_foreground (gc, imhtml->default_bg_color); gdk_draw_rectangle (GTK_LAYOUT (imhtml)->bin_window, gc, TRUE, 0, imhtml->y - GTK_LAYOUT (imhtml)->vadjustment->value, GTK_WIDGET (imhtml)->allocation.width, gtk_layout_thaw (GTK_LAYOUT (imhtml)); gtk_imhtml_draw_focus (GTK_WIDGET (imhtml)); gtk_imhtml_size_allocate (GtkWidget *widget, GtkAllocation *allocation) gint new_xsize, new_ysize; g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_IMHTML (widget)); g_return_if_fail (allocation != NULL); imhtml = GTK_IMHTML (widget); layout = GTK_LAYOUT (widget); widget->allocation = *allocation; new_xsize = MAX (1, (gint) allocation->width - (gint) (widget->style->klass->xthickness + BORDER_SIZE) * 2); new_ysize = MAX (1, (gint) allocation->height - (gint) (widget->style->klass->ythickness + BORDER_SIZE) * 2); if (GTK_WIDGET_REALIZED (widget)) { gint x = widget->style->klass->xthickness + BORDER_SIZE; gint y = widget->style->klass->ythickness + BORDER_SIZE; gdk_window_move_resize (widget->window, allocation->x, allocation->y, allocation->width, allocation->height); gdk_window_move_resize (layout->bin_window, x, y, new_xsize, new_ysize); layout->hadjustment->page_size = new_xsize; layout->hadjustment->page_increment = new_xsize / 2; layout->hadjustment->lower = 0; layout->hadjustment->upper = imhtml->x; layout->vadjustment->page_size = new_ysize; layout->vadjustment->page_increment = new_ysize / 2; layout->vadjustment->lower = 0; layout->vadjustment->upper = imhtml->y; gtk_signal_emit_by_name (GTK_OBJECT (layout->hadjustment), "changed"); gtk_signal_emit_by_name (GTK_OBJECT (layout->vadjustment), "changed"); if (new_xsize == imhtml->xsize) { if ((GTK_LAYOUT (imhtml)->vadjustment->value > imhtml->y - new_ysize)) { if (imhtml->y > new_ysize) gtk_adjustment_set_value (GTK_LAYOUT (imhtml)->vadjustment, gtk_adjustment_set_value (GTK_LAYOUT (imhtml)->vadjustment, 0); imhtml->xsize = new_xsize; if (GTK_WIDGET_REALIZED (widget)) gtk_imhtml_redraw_all (imhtml); gtk_imhtml_select_none (GtkIMHtml *imhtml) g_return_if_fail (GTK_IS_IMHTML (imhtml)); chunk->sel_start = chunk->text; draw_img (imhtml, chunk); else if ((bit->type == TYPE_SEP) && (bit->chunks->data == chunk)) draw_line (imhtml, chunk); draw_text (imhtml, chunk); chunks = g_list_next (chunks); bits = g_list_next (bits); imhtml->sel_endchunk = NULL; get_position (struct line_info *chunk, gint width = x - chunk->x; switch (chunk->bit->type) { for (pos = text; *pos != '\0'; pos++) { gint char_width = gdk_text_width (chunk->bit->font, pos, 1); if ((width > total) && (width <= total + char_width)) { if (width < total + (char_width / 2)) append_to_sel (GString *string, switch (chunk->bit->type) { start = (chunk->sel_start == NULL) ? chunk->text : chunk->sel_start; length = (chunk->sel_end == NULL) ? strlen (start) : chunk->sel_end - start; buf = g_strndup (start, length); start = (chunk->sel_start == NULL) ? chunk->bit->text : chunk->sel_start; length = (chunk->sel_end == NULL) ? strlen (start) : chunk->sel_end - start; buf = g_strndup (start, length); start = (chunk->sel_start == NULL) ? chunk->text : chunk->sel_start; length = (chunk->sel_end == NULL) ? strlen (start) : chunk->sel_end - start; buf = g_strndup (start, length); new_string = g_string_append (string, buf); chunk_select_words (struct line_info *chunk) start = chunk->sel_start; if (start != chunk->text) { if (isalnum(*start) || *start == '\'') while (start > chunk->text && (isalnum(*(start-1)) || *(start-1) == '\'')) else if (isspace(*start)) while (start > chunk->text && isspace(*(start-1))) else if (ispunct(*start)) while (start > chunk->text && ispunct(*(start-1))) chunk->sel_start = start; if (isalnum(*end) || *end == '\'') (isalnum(*end) || *end == '\'')) while (*end != '\0' && isspace(*end)) while (*end != '\0' && ispunct(*end)) #define COORDS_IN_CHUNK(xx, yy) (((xx) < chunk->x + chunk->width) && \ ((yy) < chunk->y + chunk->height)) gtk_imhtml_select_bits (GtkIMHtml *imhtml) guint startx = imhtml->sel_startx, starty = imhtml->sel_starty, guint mode = imhtml->sel_mode; gboolean smileys = imhtml->smileys; gboolean got_start = FALSE; gboolean got_end = FALSE; g_return_if_fail (GTK_IS_IMHTML (imhtml)); if (imhtml->selected_text) { g_string_free (imhtml->selected_text, TRUE); imhtml->selected_text = g_string_new (""); if (COORDS_IN_CHUNK (startx, starty)) { new_pos = get_position (chunk, startx, smileys); (chunk->sel_start != new_pos) || (chunk->sel_end != NULL)) chunk->sel_start = new_pos; chunk_select_words (chunk); if (COORDS_IN_CHUNK (endx, endy)) { new_pos = get_position (chunk, endx, smileys); if (chunk->sel_end != new_pos) if (chunk->sel_start > new_pos) { chunk->sel_end = chunk->sel_start; chunk->sel_start = new_pos; chunk->sel_end = new_pos; imhtml->sel_endchunk = chunk; chunk_select_words (chunk); new_pos = get_position (chunk, endx, smileys); (chunk->sel_start != new_pos) || (chunk->sel_end != NULL)) chunk->sel_start = new_pos; imhtml->sel_endchunk = chunk; chunk_select_words (chunk); } else if (!COORDS_IN_CHUNK (startx, starty) && !got_start) { chunk->sel_start = chunk->text; if (!got_start && COORDS_IN_CHUNK (startx, starty)) { new_pos = get_position (chunk, startx, smileys); (chunk->sel_end != new_pos) || (chunk->sel_start != chunk->text)) chunk->sel_start = chunk->text; chunk->sel_end = new_pos; chunk_select_words (chunk); } else if (!got_end && COORDS_IN_CHUNK (endx, endy)) { new_pos = get_position (chunk, endx, smileys); (chunk->sel_end != new_pos) || (chunk->sel_start != chunk->text)) chunk->sel_start = chunk->text; chunk->sel_end = new_pos; imhtml->sel_endchunk = chunk; chunk_select_words (chunk); (chunk->sel_end != NULL) || (chunk->sel_start != chunk->text)) chunk->sel_start = chunk->text; chunk->sel_start = chunk->text; if (chunk->selected == TRUE) imhtml->selected_text = append_to_sel (imhtml->selected_text, draw_img (imhtml, chunk); else if ((bit->type == TYPE_SEP) && (bit->chunks->data == chunk)) draw_line (imhtml, chunk); draw_text (imhtml, chunk); chunks = g_list_next (chunks); bits = g_list_next (bits); gtk_imhtml_select_in_chunk (GtkIMHtml *imhtml, GtkIMHtmlBit *bit = chunk->bit; guint endx = imhtml->sel_endx; guint startx = imhtml->sel_startx; guint starty = imhtml->sel_starty; gboolean smileys = imhtml->smileys; new_pos = get_position (chunk, endx, smileys); if ((starty < chunk->y) || ((starty < chunk->y + chunk->height) && (startx < endx))) { if (chunk->sel_end != new_pos) chunk->sel_end = new_pos; if (chunk->sel_start != new_pos) chunk->sel_start = new_pos; draw_img (imhtml, chunk); else if ((bit->type == TYPE_SEP) && (bit->chunks->data == chunk)) draw_line (imhtml, chunk); draw_text (imhtml, chunk); scroll_timeout (GtkIMHtml *imhtml) imhtml->scroll_timer = 0; gdk_window_get_pointer (GTK_LAYOUT (imhtml)->bin_window, &x, &y, &mask); if (mask & GDK_BUTTON1_MASK) { gtk_imhtml_motion_notify_event (GTK_WIDGET (imhtml), &event); gtk_imhtml_tip_paint (GtkIMHtml *imhtml) gint y, baseline_skip, gap; style = imhtml->tip_window->style; font = GTK_IMHTML_GET_STYLE_FONT (style); gap = (font->ascent + font->descent) / 4; baseline_skip = font->ascent + font->descent + gap; gtk_paint_flat_box (style, imhtml->tip_window->window, GTK_STATE_NORMAL, GTK_SHADOW_OUT, NULL, imhtml->tip_window, "tooltip", 0, 0, -1, -1); if (imhtml->tip_bit->url) gtk_paint_string (style, imhtml->tip_window->window, GTK_STATE_NORMAL, NULL, imhtml->tip_window, "tooltip", 4, y, imhtml->tip_bit->url); else if (imhtml->tip_bit->img) gtk_paint_string (style, imhtml->tip_window->window, GTK_STATE_NORMAL, NULL, imhtml->tip_window, "tooltip", 4, y, imhtml->tip_bit->img->filename); gtk_imhtml_tip (gpointer data) GtkIMHtml *imhtml = data; GtkWidget *widget = GTK_WIDGET (imhtml); gint gap, x, y, w, h, scr_w, scr_h, baseline_skip; if (!imhtml->tip_bit || !GTK_WIDGET_DRAWABLE (widget)) { gtk_widget_destroy (imhtml->tip_window); imhtml->tip_window = gtk_window_new (GTK_WINDOW_POPUP); gtk_widget_set_app_paintable (imhtml->tip_window, TRUE); gtk_window_set_policy (GTK_WINDOW (imhtml->tip_window), FALSE, FALSE, TRUE); gtk_widget_set_name (imhtml->tip_window, "gtk-tooltips"); gtk_signal_connect_object (GTK_OBJECT (imhtml->tip_window), "expose_event", GTK_SIGNAL_FUNC (gtk_imhtml_tip_paint), GTK_OBJECT (imhtml)); gtk_signal_connect_object (GTK_OBJECT (imhtml->tip_window), "draw", GTK_SIGNAL_FUNC (gtk_imhtml_tip_paint), GTK_OBJECT (imhtml)); gtk_widget_ensure_style (imhtml->tip_window); style = imhtml->tip_window->style; font = GTK_IMHTML_GET_STYLE_FONT (style); scr_w = gdk_screen_width (); scr_h = gdk_screen_height (); gap = (font->ascent + font->descent) / 4; baseline_skip = font->ascent + font->descent + gap; w = 8 + gdk_string_width (font, imhtml->tip_bit->img ? imhtml->tip_bit->img->filename : h = 8 - gap + baseline_skip; gdk_window_get_pointer (NULL, &x, &y, NULL); if (GTK_WIDGET_NO_WINDOW (widget)) y += widget->allocation.y; if ((y + h + + 4) > scr_h) y = y - imhtml->tip_bit->font->ascent + imhtml->tip_bit->font->descent; if (imhtml->tip_bit->font) y = y + imhtml->tip_bit->font->ascent + imhtml->tip_bit->font->descent; y = y + font->ascent + font->descent; gtk_widget_set_usize (imhtml->tip_window, w, h); gtk_widget_set_uposition (imhtml->tip_window, x, y); gtk_widget_show (imhtml->tip_window); gtk_imhtml_motion_notify_event (GtkWidget *widget, GtkIMHtml *imhtml = GTK_IMHTML (widget); GtkAdjustment *vadj = GTK_LAYOUT (widget)->vadjustment; GtkAdjustment *hadj = GTK_LAYOUT (widget)->hadjustment; gdk_window_get_pointer (event->window, &x, &y, &state); x = event->x + hadj->value; y = event->y + vadj->value; if (state & GDK_BUTTON1_MASK) { gint height = vadj->page_size; gint yy = y - vadj->value; if (((yy < 0) || (yy > height)) && (imhtml->scroll_timer == 0) && (vadj->upper > vadj->page_size)) { imhtml->scroll_timer = gtk_timeout_add (100, (GtkFunction) scroll_timeout, diff = (yy < 0) ? (yy / 2) : ((yy - height) / 2); gtk_adjustment_set_value (vadj, MIN (vadj->value + diff, vadj->upper - height)); struct line_info *chunk = imhtml->sel_endchunk; imhtml->sel_endx = MAX (x, 0); imhtml->sel_endy = MAX (y, 0); (x > chunk->x + chunk->width) || (y > chunk->y + chunk->height) || gtk_imhtml_select_bits (imhtml); gtk_imhtml_select_in_chunk (imhtml, chunk); GList *click = imhtml->click; uw = (struct clickable *) click->data; if ((uw->bit->url) && (x > uw->x) && (x < uw->x + uw->width) && (y > uw->y) && (y < uw->y + uw->height) && (uw->bit->url || uw->bit->img)) { if (imhtml->tip_bit != uw->bit) { imhtml->tip_bit = uw->bit; if (imhtml->tip_timer != 0) gtk_timeout_remove (imhtml->tip_timer); if (imhtml->tip_window) { gtk_widget_destroy (imhtml->tip_window); imhtml->tip_window = NULL; imhtml->tip_timer = gtk_timeout_add (TOOLTIP_TIMEOUT, gdk_window_set_cursor (GTK_LAYOUT (imhtml)->bin_window, click = g_list_next (click); gtk_timeout_remove (imhtml->tip_timer); if (imhtml->tip_window) { gtk_widget_destroy (imhtml->tip_window); imhtml->tip_window = NULL; gdk_window_set_cursor (GTK_LAYOUT (imhtml)->bin_window, imhtml->arrow_cursor); gtk_imhtml_leave_notify_event (GtkWidget *widget, GtkIMHtml *imhtml = GTK_IMHTML (widget); gtk_timeout_remove (imhtml->tip_timer); if (imhtml->tip_window) { gtk_widget_destroy (imhtml->tip_window); imhtml->tip_window = NULL; save_img (GtkObject *object, struct im_image *img = is->img; filename = gtk_file_selection_get_filename(GTK_FILE_SELECTION(is->savedialog)); g_print("Saving %s\n", filename); if (! (f=fopen(filename, "w"))) { /* There should be some sort of dialog */ g_print("Could not open file for writing.\n"); gtk_widget_destroy(is->savedialog); fwrite(img->data, 1, img->len, f); gtk_widget_destroy(is->savedialog); save_img_dialog (GtkObject *object, struct imgsv *is = g_malloc(sizeof(struct imgsv)); struct im_image *img = data; GtkWidget *savedialog = gtk_file_selection_new ("Gaim - Save Image"); gtk_file_selection_set_filename (GTK_FILE_SELECTION(savedialog), img->filename); gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION(savedialog)->cancel_button), "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy), is->savedialog = savedialog; gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION(savedialog)->ok_button), "clicked", GTK_SIGNAL_FUNC (save_img), is); gtk_widget_show (savedialog); menu_open_url (GtkObject *object, struct clickable *uw = data; gtk_signal_emit (GTK_OBJECT (uw->imhtml), signals [URL_CLICKED], uw->bit->url); menu_copy_link (GtkObject *object, struct clickable *uw = data; GtkIMHtml *imhtml = uw->imhtml; if (imhtml->selected_text) g_string_free (imhtml->selected_text, TRUE); gtk_imhtml_select_none (uw->imhtml); imhtml->selection = TRUE; imhtml->selected_text = g_string_new (uw->bit->url); gtk_selection_owner_set (GTK_WIDGET (imhtml), GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME); gtk_imhtml_button_press_event (GtkWidget *widget, GtkIMHtml *imhtml = GTK_IMHTML (widget); GtkAdjustment *vadj = GTK_LAYOUT (widget)->vadjustment; GtkAdjustment *hadj = GTK_LAYOUT (widget)->hadjustment; x = event->x + hadj->value; y = event->y + vadj->value; if (event->button == 1) { imhtml->sel_startx = imhtml->sel_endx = x; imhtml->sel_starty = imhtml->sel_endy = y; imhtml->selection = TRUE; if (event->type == GDK_BUTTON_PRESS) { imhtml->sel_mode = 0; /* select by letter */ gtk_imhtml_select_none (imhtml); } else if (event->type == GDK_2BUTTON_PRESS) { imhtml->sel_mode = 1; /* select by word */ gtk_imhtml_select_none (imhtml); } else if (event->type == GDK_3BUTTON_PRESS) { imhtml->sel_mode = 2; /* select by line */ gtk_imhtml_select_bits (imhtml); if (event->button == 3) { GList *click = imhtml->click; if ((x > uw->x) && (x < uw->x + uw->width) && (y > uw->y) && (y < uw->y + uw->height)) { static GtkWidget *menu = NULL; * If a menu already exists, destroy it before creating a new one, * thus freeing-up the memory it occupied. gtk_widget_destroy(menu); button = gtk_menu_item_new_with_label ("Open URL"); gtk_signal_connect (GTK_OBJECT (button), "activate", GTK_SIGNAL_FUNC (menu_open_url), uw); gtk_menu_append (GTK_MENU (menu), button); gtk_widget_show (button); button = gtk_menu_item_new_with_label ("Copy Link Location"); gtk_signal_connect (GTK_OBJECT (button), "activate", GTK_SIGNAL_FUNC (menu_copy_link), uw); gtk_menu_append (GTK_MENU (menu), button); gtk_widget_show (button); button = gtk_menu_item_new_with_label ("Save Image"); gtk_signal_connect (GTK_OBJECT (button), "activate", GTK_SIGNAL_FUNC (save_img_dialog), uw->bit->img); gtk_menu_append (GTK_MENU (menu), button); gtk_widget_show (button); gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 3, event->time); gtk_timeout_remove (imhtml->tip_timer); if (imhtml->tip_window) { gtk_widget_destroy (imhtml->tip_window); imhtml->tip_window = NULL; click = g_list_next (click); gtk_imhtml_button_release_event (GtkWidget *widget, GtkIMHtml *imhtml = GTK_IMHTML (widget); GtkAdjustment *vadj = GTK_LAYOUT (widget)->vadjustment; GtkAdjustment *hadj = GTK_LAYOUT (widget)->hadjustment; x = event->x + hadj->value; y = event->y + vadj->value; if ((event->button == 1) && imhtml->selection) { if ((x == imhtml->sel_startx) && (y == imhtml->sel_starty) && (imhtml->sel_mode == 0)) { imhtml->sel_startx = imhtml->sel_starty = 0; imhtml->selection = FALSE; gtk_imhtml_select_none (imhtml); imhtml->sel_endx = MAX (x, 0); imhtml->sel_endy = MAX (y, 0); gtk_imhtml_select_bits (imhtml); gtk_selection_owner_set (widget, GDK_SELECTION_PRIMARY, event->time); if ((event->button == 1) && (imhtml->sel_startx == 0)) { GList *click = imhtml->click; uw = (struct clickable *) click->data; if ((x > uw->x) && (x < uw->x + uw->width) && (y > uw->y) && (y < uw->y + uw->height)) { gtk_signal_emit (GTK_OBJECT (imhtml), signals [URL_CLICKED], click = g_list_next (click); gtk_imhtml_selection_get (GtkWidget *widget, GtkSelectionData *sel_data, g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_IMHTML (widget)); g_return_if_fail (sel_data->selection == GDK_SELECTION_PRIMARY); imhtml = GTK_IMHTML (widget); g_return_if_fail (imhtml->selected_text != NULL); g_return_if_fail (imhtml->selected_text->str != NULL); if (imhtml->selected_text->len <= 0) string = g_strdup (imhtml->selected_text->str); length = strlen (string); if (sel_info == TARGET_STRING) { gtk_selection_data_set (sel_data, GDK_SELECTION_TYPE_STRING, } else if ((sel_info == TARGET_TEXT) || (sel_info == TARGET_COMPOUND_TEXT)) { gdk_string_to_compound_text (string, &encoding, &format, &text, &new_length); gtk_selection_data_set (sel_data, encoding, format, text, new_length); gdk_free_compound_text (text); gtk_imhtml_selection_clear_event (GtkWidget *widget, GdkEventSelection *event) g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GTK_IS_IMHTML (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); g_return_val_if_fail (event->selection == GDK_SELECTION_PRIMARY, TRUE); if (!gtk_selection_clear (widget, event)) imhtml = GTK_IMHTML (widget); gtk_imhtml_select_none (imhtml); gtk_imhtml_adjustment_changed (GtkAdjustment *adjustment, GtkLayout *layout = GTK_LAYOUT (imhtml); if (!GTK_WIDGET_MAPPED (imhtml) || !GTK_WIDGET_REALIZED (imhtml)) if (layout->freeze_count) if (layout->vadjustment->value < TOP_BORDER) gdk_window_clear_area (layout->bin_window, 0, 0, imhtml->xsize, TOP_BORDER - layout->vadjustment->value); gtk_imhtml_draw_exposed (imhtml); gtk_imhtml_set_scroll_adjustments (GtkLayout *layout, gboolean need_adjust = FALSE; g_return_if_fail (layout != NULL); g_return_if_fail (GTK_IS_IMHTML (layout)); g_return_if_fail (GTK_IS_ADJUSTMENT (hadj)); hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0)); g_return_if_fail (GTK_IS_ADJUSTMENT (vadj)); vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0)); if (layout->hadjustment && (layout->hadjustment != hadj)) { gtk_signal_disconnect_by_data (GTK_OBJECT (layout->hadjustment), layout); gtk_object_unref (GTK_OBJECT (layout->hadjustment)); if (layout->vadjustment && (layout->vadjustment != vadj)) { gtk_signal_disconnect_by_data (GTK_OBJECT (layout->vadjustment), layout); gtk_object_unref (GTK_OBJECT (layout->vadjustment)); if (layout->hadjustment != hadj) { layout->hadjustment = hadj; gtk_object_ref (GTK_OBJECT (layout->hadjustment)); gtk_object_sink (GTK_OBJECT (layout->hadjustment)); gtk_signal_connect (GTK_OBJECT (layout->hadjustment), "value_changed", (GtkSignalFunc) gtk_imhtml_adjustment_changed, layout); if (layout->vadjustment != vadj) { layout->vadjustment = vadj; gtk_object_ref (GTK_OBJECT (layout->vadjustment)); gtk_object_sink (GTK_OBJECT (layout->vadjustment)); gtk_signal_connect (GTK_OBJECT (layout->vadjustment), "value_changed", (GtkSignalFunc) gtk_imhtml_adjustment_changed, layout); gtk_imhtml_adjustment_changed (NULL, GTK_IMHTML (layout)); gtk_imhtml_class_init (GtkIMHtmlClass *class) GtkObjectClass *object_class; GtkWidgetClass *widget_class; GtkLayoutClass *layout_class; object_class = (GtkObjectClass*) class; widget_class = (GtkWidgetClass*) class; layout_class = (GtkLayoutClass*) class; parent_class = gtk_type_class (GTK_TYPE_LAYOUT); gtk_signal_new ("url_clicked", GTK_CLASS_TYPE (object_class), GTK_SIGNAL_OFFSET (GtkIMHtmlClass, url_clicked), gtk_marshal_NONE__POINTER, gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL); object_class->destroy = gtk_imhtml_destroy; widget_class->realize = gtk_imhtml_realize; widget_class->draw = gtk_imhtml_draw; widget_class->draw_focus = gtk_imhtml_draw_focus; widget_class->style_set = gtk_imhtml_style_set; widget_class->expose_event = gtk_imhtml_expose_event; widget_class->size_allocate = gtk_imhtml_size_allocate; widget_class->motion_notify_event = gtk_imhtml_motion_notify_event; widget_class->leave_notify_event = gtk_imhtml_leave_notify_event; widget_class->button_press_event = gtk_imhtml_button_press_event; widget_class->button_release_event = gtk_imhtml_button_release_event; widget_class->selection_get = gtk_imhtml_selection_get; widget_class->selection_clear_event = gtk_imhtml_selection_clear_event; layout_class->set_scroll_adjustments = gtk_imhtml_set_scroll_adjustments; /* the font stuff is the most insane stuff. i don't understand it half * the time. so we're going to comment it. isn't that wonderful. */ /* when you g_strsplit a valid font name, these are the positions of all the various parts of it. */ gtk_imhtml_get_font_name (GdkFont *font) GdkFontPrivate *fontpriv = (GdkFontPrivate *) font; return fontpriv->names->data; gtk_imhtml_font_load (GtkIMHtml *imhtml, GdkFont *default_font = imhtml->default_font; char *italicstrings[] = {"i","o","*"}; int italicsind = 0, nameind = 0; gboolean usebold = TRUE, usesize = TRUE, useregenc = TRUE; /* if we're not changing anything, use the default. this is the common case */ if (!name && !bold && !italics && !fontsize) return gdk_font_ref (default_font); /* base things off of the default font name */ default_name = gtk_imhtml_get_font_name (default_font); /* the default font name can actually be several names separated by ','. * This is a fontset... used in foreign encodings. */ xnames = g_strsplit (default_name, ",", -1); for (pos = xnames; pos && *pos; pos++) { xname = g_strchomp (xname); xname = g_strchug (xname); xflds = g_strsplit (xname, "-", -1); /* figure out if we have a valid name. i wish there were an * easier way for determining how many values g_strplit gave */ for (i = 0; xflds [i]; i++); newvals = g_malloc0 (16 * sizeof (gchar *)); for (tmp = 1; tmp < 15; tmp++) newvals = g_memdup (xflds, 16 * sizeof (xflds)); /* we force foundry as "*" because i hate them. i should give a better reason. */ /* if it's "*" then it defaults to (nil) anyway. some fonts don't want (nil) */ if ((i > ADSTYL) && !xflds [ADSTYL][0]) /* If the font doesn't work the first time, we try it with * registry and encoding as "*" */ /* We'll try "i" "o" to get italics and then just use "*" */ newvals [SLANT] = italicstrings[italicsind]; if (usesize && fontsize) { g_snprintf (fs, sizeof (fs), "%d", POINT_SIZE (fontsize)); /* we got passed a name. it might be a list of names. */ gchar **tmp_nms = g_strsplit (name, ",", -1); for (j = 0; tmp_nms [j]; j++); names = g_new0 (char *, j + 2); for (j = 0; tmp_nms [j]; j++) /* Put the default font on the array. */ names [j] = g_strdup (xflds [FMLY]); newvals [FMLY] = names[nameind]; /* we didn't get a name. we come here if the gtk font name is valid */ names = g_new0 (gchar *, 2); names [0] = g_strdup (xflds [FMLY]); names = g_new0 (gchar *, 2); names [0] = g_strdup ("*"); tmp = g_strjoinv("-", newvals); /* We have to concat the xlfds in the fontset */ tmp = g_strconcat(garbage, ",", g_strjoinv ("-", newvals), NULL); if (default_font->type == GDK_FONT_FONT) ret_font = gdk_font_load (tmp); ret_font = gdk_fontset_load (tmp); /* If the font didn't load, we change some of the xlfds one by one * to get the closest we can. */ } else if (italics && italicsind != 2) { } else if (bold && usebold) { } else if (names && names[nameind++]) { ret_font = gdk_font_ref(default_font); } while (!ret_font); /* Loop with the new options */ gtk_imhtml_init (GtkIMHtml *imhtml) static const GtkTargetEntry targets [] = { { "STRING", 0, TARGET_STRING }, { "TEXT", 0, TARGET_TEXT }, { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT } imhtml->hand_cursor = gdk_cursor_new (GDK_HAND2); imhtml->arrow_cursor = gdk_cursor_new (GDK_LEFT_PTR); GTK_WIDGET_SET_FLAGS (GTK_WIDGET (imhtml), GTK_CAN_FOCUS); gtk_selection_add_targets (GTK_WIDGET (imhtml), GDK_SELECTION_PRIMARY, targets, 3); gtk_imhtml_get_type (void) static GtkType imhtml_type = 0; static const GtkTypeInfo imhtml_info = { (GtkClassInitFunc) gtk_imhtml_class_init, (GtkObjectInitFunc) gtk_imhtml_init, imhtml_type = gtk_type_unique (GTK_TYPE_LAYOUT, &imhtml_info); gtk_imhtml_init_smileys (GtkIMHtml *imhtml) g_return_if_fail (imhtml != NULL); g_return_if_fail (GTK_IS_IMHTML (imhtml)); imhtml->smiley_data = gtk_smiley_tree_new (); gtk_imhtml_associate_smiley (imhtml, ":)", smile_xpm); gtk_imhtml_associate_smiley (imhtml, ":-)", smile_xpm); gtk_imhtml_associate_smiley (imhtml, ":(", sad_xpm); gtk_imhtml_associate_smiley (imhtml, ":-(", sad_xpm); gtk_imhtml_associate_smiley (imhtml, ";)", wink_xpm); gtk_imhtml_associate_smiley (imhtml, ";-)", wink_xpm); gtk_imhtml_associate_smiley (imhtml, ":-p", tongue_xpm); gtk_imhtml_associate_smiley (imhtml, ":-P", tongue_xpm); gtk_imhtml_associate_smiley (imhtml, "=-O", scream_xpm); gtk_imhtml_associate_smiley (imhtml, "=-o", scream_xpm); gtk_imhtml_associate_smiley (imhtml, ":-*", kiss_xpm); gtk_imhtml_associate_smiley (imhtml, ">:O", yell_xpm); gtk_imhtml_associate_smiley (imhtml, ">:o", yell_xpm); gtk_imhtml_associate_smiley (imhtml, "8-)", smile8_xpm); gtk_imhtml_associate_smiley (imhtml, ":-$", moneymouth_xpm); gtk_imhtml_associate_smiley (imhtml, ":-!", burp_xpm); gtk_imhtml_associate_smiley (imhtml, ":-[", embarrassed_xpm); gtk_imhtml_associate_smiley (imhtml, ":'(", cry_xpm); gtk_imhtml_associate_smiley (imhtml, ":-/", think_xpm); gtk_imhtml_associate_smiley (imhtml, ":-\\", think_xpm); gtk_imhtml_associate_smiley (imhtml, ":-X", crossedlips_xpm); gtk_imhtml_associate_smiley (imhtml, ":-x", crossedlips_xpm); gtk_imhtml_associate_smiley (imhtml, ":-D", bigsmile_xpm); gtk_imhtml_associate_smiley (imhtml, ":-d", bigsmile_xpm); gtk_imhtml_associate_smiley (imhtml, "O:-)", angel_xpm); gtk_imhtml_new (GtkAdjustment *hadj, GtkIMHtml *imhtml = gtk_type_new (GTK_TYPE_IMHTML); gtk_imhtml_set_adjustments (imhtml, hadj, vadj); imhtml->im_images = NULL; imhtml->selected_text = g_string_new (""); imhtml->scroll_timer = 0; imhtml->comments = FALSE; gtk_imhtml_init_smileys (imhtml); return GTK_WIDGET (imhtml); gtk_imhtml_set_adjustments (GtkIMHtml *imhtml, gtk_layout_set_hadjustment (GTK_LAYOUT (imhtml), hadj); gtk_layout_set_vadjustment (GTK_LAYOUT (imhtml), vadj); gtk_imhtml_set_defaults (GtkIMHtml *imhtml, g_return_if_fail (imhtml != NULL); g_return_if_fail (GTK_IS_IMHTML (imhtml)); if (imhtml->default_font) gdk_font_unref (imhtml->default_font); imhtml->default_font = gdk_font_ref (font); if (imhtml->default_fg_color) gdk_color_free (imhtml->default_fg_color); imhtml->default_fg_color = gdk_color_copy (fg_color); if (imhtml->default_bg_color) gdk_color_free (imhtml->default_bg_color); imhtml->default_bg_color = gdk_color_copy (bg_color); gdk_window_set_background (GTK_LAYOUT (imhtml)->bin_window, imhtml->default_bg_color); gtk_imhtml_set_img_handler (GtkIMHtml *imhtml, g_return_if_fail (imhtml != NULL); g_return_if_fail (GTK_IS_IMHTML (imhtml)); gtk_imhtml_associate_smiley (GtkIMHtml *imhtml, g_return_if_fail (imhtml != NULL); g_return_if_fail (GTK_IS_IMHTML (imhtml)); g_return_if_fail (text != NULL); gtk_smiley_tree_remove (imhtml->smiley_data, text); gtk_smiley_tree_insert (imhtml->smiley_data, text, xpm); new_line (GtkIMHtml *imhtml) GList *last = g_list_last (imhtml->line); if (li->x + li->width != imhtml->xsize) li->width = imhtml->xsize - li->x; if (li->height < MIN_HEIGHT) { diff = MIN_HEIGHT - li->height; last = g_list_next (last); imhtml->llheight = MIN_HEIGHT; g_list_free (imhtml->line); imhtml->y += imhtml->llheight; backwards_update (GtkIMHtml *imhtml, if (height > imhtml->llheight) { diff = height - imhtml->llheight; if (uw->y + diff > imhtml->y) if (img->y + diff > imhtml->y) imhtml->llheight = height; imhtml->llascent = ascent; imhtml->llascent += diff / 2; add_text_renderer (GtkIMHtml *imhtml, width = gdk_string_width (bit->font, text); li = g_new0 (struct line_info, 1); li->height = imhtml->llheight; li->ascent = MAX (imhtml->llascent, bit->font->ascent); uw = g_new0 (struct clickable, 1); uw->height = imhtml->llheight; imhtml->click = g_list_append (imhtml->click, uw); bit->chunks = g_list_append (bit->chunks, li); imhtml->line = g_list_append (imhtml->line, li); add_img_renderer (GtkIMHtml *imhtml, gdk_window_get_size (bit->pm, &width, NULL); li = g_new0 (struct line_info, 1); li->height = imhtml->llheight; if (bit->url || bit->img) { uw = g_new0 (struct clickable, 1); uw->height = imhtml->llheight; imhtml->click = g_list_append (imhtml->click, uw); bit->chunks = g_list_append (bit->chunks, li); imhtml->line = g_list_append (imhtml->line, li); gtk_imhtml_draw_bit (GtkIMHtml *imhtml, g_return_if_fail (imhtml != NULL); g_return_if_fail (GTK_IS_IMHTML (imhtml)); g_return_if_fail (bit != NULL); if ( ((bit->type == TYPE_TEXT) || ((bit->type == TYPE_SMILEY) && !imhtml->smileys) || ((bit->type == TYPE_COMMENT) && imhtml->comments)) && gchar *copy = g_strdup (bit->text); gboolean seenspace = FALSE; height = bit->font->ascent + bit->font->descent; width = gdk_string_width (bit->font, bit->text); if ((imhtml->x != 0) && ((imhtml->x + width) > imhtml->xsize)) { gint remain = imhtml->xsize - imhtml->x; while (gdk_text_width (bit->font, copy, pos) < remain) { while (copy [pos - 1] != ' ') pos--; tmp = g_strndup (copy, pos); backwards_update (imhtml, bit, height, bit->font->ascent); add_text_renderer (imhtml, bit, tmp); backwards_update (imhtml, bit, height, bit->font->ascent); while (pos < strlen (bit->text)) { width = gdk_string_width (bit->font, copy + pos); if (imhtml->x + width > imhtml->xsize) { gint remain = imhtml->xsize - imhtml->x; while (gdk_text_width (bit->font, copy + pos, newpos) < remain) { if (copy [pos + newpos] == ' ') while (copy [pos + newpos - 1] != ' ') newpos--; tmp = g_strndup (copy + pos, newpos); backwards_update (imhtml, bit, height, bit->font->ascent); add_text_renderer (imhtml, bit, tmp); tmp = g_strdup (copy + pos); backwards_update (imhtml, bit, height, bit->font->ascent); add_text_renderer (imhtml, bit, tmp); pos = strlen (bit->text); } else if ((bit->type == TYPE_SMILEY) || (bit->type == TYPE_IMG)) { GdkPixbuf *imagepb = bit->img->pb; if (gdk_pixbuf_get_width(imagepb) > imhtml->xsize - imhtml->x) if (gdk_pixbuf_get_width(imagepb) > imhtml->xsize) { tmp = gdk_pixbuf_scale_simple(imagepb, imhtml->xsize, gdk_pixbuf_get_height(imagepb) * gdk_pixbuf_get_width(imagepb), gdk_pixmap_unref (bit->pm); gdk_bitmap_unref (bit->bm); gdk_pixbuf_render_pixmap_and_mask(tmp, &(bit->pm), &(bit->bm), 100); gdk_pixmap_unref (bit->pm); gdk_bitmap_unref (bit->bm); gdk_pixbuf_render_pixmap_and_mask(imagepb, &(bit->pm), &(bit->bm), 100); gdk_window_get_size (bit->pm, &width, &height); if ((imhtml->x != 0) && ((imhtml->x + width) > imhtml->xsize)) backwards_update (imhtml, bit, height, 0); add_img_renderer (imhtml, bit); } else if (bit->type == TYPE_BR) { add_text_renderer (imhtml, bit, NULL); } else if (bit->type == TYPE_SEP) { li = g_new0 (struct line_info, 1); li->width = imhtml->xsize; li->height = HR_HEIGHT * 2; bit->chunks = g_list_append (bit->chunks, li); imhtml->llheight = HR_HEIGHT * 2; add_text_renderer (imhtml, bit, NULL); gtk_imhtml_show_smileys (GtkIMHtml *imhtml, g_return_if_fail (imhtml != NULL); g_return_if_fail (GTK_IS_IMHTML (imhtml)); if (GTK_WIDGET_VISIBLE (GTK_WIDGET (imhtml))) gtk_imhtml_redraw_all (imhtml); gtk_imhtml_show_comments (GtkIMHtml *imhtml, g_return_if_fail (imhtml != NULL); g_return_if_fail (GTK_IS_IMHTML (imhtml)); if (GTK_WIDGET_VISIBLE (GTK_WIDGET (imhtml))) gtk_imhtml_redraw_all (imhtml); gtk_imhtml_get_color (const gchar *color) if (!gdk_color_parse (color, &c)) return gdk_color_copy (&c); gtk_imhtml_is_smiley (GtkIMHtml *imhtml, *len = gtk_smiley_tree_lookup (imhtml->smiley_data, text); gtk_imhtml_new_bit (GtkIMHtml *imhtml, GtkIMHtmlBit *bit = NULL; g_return_val_if_fail (imhtml != NULL, NULL); g_return_val_if_fail (GTK_IS_IMHTML (imhtml), NULL); if ((type == TYPE_TEXT) && ((text == NULL) || (strlen (text) == 0))) bit = g_new0 (GtkIMHtmlBit, 1); if ((text != NULL) && (strlen (text) != 0)) bit->text = g_strdup (text); if ((font != NULL) || bold || italics || pre) { if (font && (bold || italics || font->size || font->face || pre)) { bit->font = gtk_imhtml_font_load (imhtml, DEFAULT_PRE_FACE, bold, italics, font->size); bit->font = gtk_imhtml_font_load (imhtml, font->face, bold, italics, font->size); } else if (bold || italics || pre) { bit->font = gtk_imhtml_font_load (imhtml, DEFAULT_PRE_FACE, bold, italics, 0); bit->font = gtk_imhtml_font_load (imhtml, NULL, bold, italics, 0); if (font && (type != TYPE_BR)) { bit->fore = gdk_color_copy (font->fore); bit->back = gdk_color_copy (font->back); if (((bit->type == TYPE_TEXT) || (bit->type == TYPE_SMILEY) || (bit->type == TYPE_COMMENT)) && bit->font = gdk_font_ref (imhtml->default_font); bit->bg = gdk_color_copy (bg); bit->underline = underline; bit->url = g_strdup (url); if (type == TYPE_SMILEY) { if ((font != NULL) && (font->back != NULL)) clr = (bg != NULL) ? bg : imhtml->default_bg_color; bit->pm = gdk_pixmap_create_from_xpm_d (GTK_WIDGET (imhtml)->window, gtk_smiley_tree_image (imhtml->smiley_data, text)); #define NEW_TEXT_BIT gtk_imhtml_new_bit (imhtml, TYPE_TEXT, ws, bold, italics, underline, strike, \ fonts ? fonts->data : NULL, bg, url, pre, sub, sup) #define NEW_SMILEY_BIT gtk_imhtml_new_bit (imhtml, TYPE_SMILEY, ws, bold, italics, underline, strike, \ fonts ? fonts->data : NULL, bg, url, pre, sub, sup) #define NEW_SEP_BIT gtk_imhtml_new_bit (imhtml, TYPE_SEP, NULL, 0, 0, 0, 0, NULL, bg, NULL, 0, 0, 0) #define NEW_BR_BIT gtk_imhtml_new_bit (imhtml, TYPE_BR, NULL, 0, 0, 0, 0, \ fonts ? fonts->data : NULL, bg, NULL, 0, 0, 0) #define NEW_COMMENT_BIT gtk_imhtml_new_bit (imhtml, TYPE_COMMENT, ws, bold, italics, underline, strike, \ fonts ? fonts->data : NULL, bg, url, pre, sub, sup) #define NEW_BIT(bit) ws [wpos] = '\0'; \ { GtkIMHtmlBit *tmp = bit; if (tmp != NULL) \ newbits = g_list_append (newbits, tmp); } \ wpos = 0; ws [wpos] = '\0' #define UPDATE_BG_COLORS \ cmap = gtk_widget_get_colormap (GTK_WIDGET (imhtml)); \ rev = g_list_last (newbits); \ GtkIMHtmlBit *bit = rev->data; \ gdk_color_free (bit->bg); \ bit->bg = gdk_color_copy (bg); \ if (bit->type == TYPE_BR) \ rev = g_list_previous (rev); \ rev = g_list_last (imhtml->bits); \ GtkIMHtmlBit *bit = rev->data; \ gdk_color_free (bit->bg); \ bit->bg = gdk_color_copy (bg); \ gdk_color_alloc (cmap, bit->bg); \ if (bit->type == TYPE_BR) \ rev = g_list_previous (rev); \ gtk_imhtml_is_amp_escape (const gchar *string, g_return_val_if_fail (string != NULL, FALSE); g_return_val_if_fail (replace != NULL, FALSE); g_return_val_if_fail (length != NULL, FALSE); if (!g_strncasecmp (string, "&", 5)) { } else if (!g_strncasecmp (string, "<", 4)) { } else if (!g_strncasecmp (string, ">", 4)) { } else if (!g_strncasecmp (string, " ", 6)) { } else if (!g_strncasecmp (string, "©", 6)) { } else if (!g_strncasecmp (string, """, 6)) { } else if (!g_strncasecmp (string, "®", 5)) { } else if (*(string + 1) == '#') { if ((sscanf (string, "&#%u;", £) == 1) && pound != 0) { if (*(string + 3 + (gint)log10 (pound)) != ';') while (isdigit ((gint) string [*length])) (*length)++; if (string [*length] == ';') (*length)++; #define VALID_TAG(x) if (!g_strncasecmp (string, x ">", strlen (x ">"))) { \ *tag = g_strndup (string, strlen (x)); \ #define VALID_OPT_TAG(x) if (!g_strncasecmp (string, x " ", strlen (x " "))) { \ const gchar *c = string + strlen (x " "); \ gboolean quote = FALSE; \ if (*c == '"' || *c == '\'') { \ if (quote && (*c == e)) \ } else if (!quote && (*c == '>')) \ *tag = g_strndup (string, c - string); \ gtk_imhtml_is_tag (const gchar *string, if (!strchr (string, '>')) VALID_TAG ("/UNDERLINE"); if (!g_strncasecmp(string, "!--", strlen ("!--"))) { gchar *e = strstr (string + strlen("!--"), "-->"); *len = e - string + strlen ("-->"); *tag = g_strndup (string + strlen ("!--"), *len - strlen ("!---->")); gtk_imhtml_get_html_opt (gchar *tag, while (g_strncasecmp (t, opt, strlen (opt))) { while (*t && !((*t == ' ') && !quote)) { while (*t && (*t == ' ')) t++; if (!g_strncasecmp (t, opt, strlen (opt))) { if ((*t == '\"') || (*t == '\'')) { while (*e && (*e != *(t - 1))) e++; return g_strndup (a, e - a); while (*e && !isspace ((gint) *e)) e++; return g_strndup (a, e - a); gtk_imhtml_append_text (GtkIMHtml *imhtml, GtkIMHtmlOptions options) gboolean scrolldown = TRUE; g_return_val_if_fail (imhtml != NULL, NULL); g_return_val_if_fail (GTK_IS_IMHTML (imhtml), NULL); g_return_val_if_fail (text != NULL, NULL); if (options & GTK_IMHTML_RETURN_LOG) retval = g_string_new (""); vadj = GTK_LAYOUT (imhtml)->vadjustment; if ((vadj->value < imhtml->y - GTK_WIDGET (imhtml)->allocation.height) && (vadj->upper >= GTK_WIDGET (imhtml)->allocation.height)) if (*c == '<' && gtk_imhtml_is_tag (c + 1, &tag, &tlen, &type)) { case 12: /* /UNDERLINE */ if (options & GTK_IMHTML_NO_TITLE) { FontDetail *font = fonts->data; fonts = g_slist_remove (fonts, font); gdk_color_free (font->fore); gdk_color_free (font->back); if (!g_strncasecmp("</BINARY>", c, strlen("</BINARY>"))) c = c - tlen; /* Because it will add this later */ case 43: /* FONT (opt) */ gchar *color, *back, *face, *size; color = gtk_imhtml_get_html_opt (tag, "COLOR="); back = gtk_imhtml_get_html_opt (tag, "BACK="); face = gtk_imhtml_get_html_opt (tag, "FACE="); size = gtk_imhtml_get_html_opt (tag, "SIZE="); if (!(color || back || face || size)) font = g_new0 (FontDetail, 1); if (color && !(options & GTK_IMHTML_NO_COLOURS)) font->fore = gtk_imhtml_get_color (color); if (back && !(options & GTK_IMHTML_NO_COLOURS)) font->back = gtk_imhtml_get_color (back); if (face && !(options & GTK_IMHTML_NO_FONTS)) font->face = g_strdup (face); if (size && !(options & GTK_IMHTML_NO_SIZES)) { sscanf (size + 1, "%hd", &font->size); } else if (*size == '-') { sscanf (size + 1, "%hd", &font->size); font->size = MAX (0, 3 - font->size); } else if (isdigit (*size)) { sscanf (size, "%hd", &font->size); FontDetail *oldfont = fonts->data; font->size = oldfont->size; if (!font->face && oldfont->face) font->face = g_strdup (oldfont->face); if (!font->fore && oldfont->fore) font->fore = gdk_color_copy (oldfont->fore); if (!font->back && oldfont->back) font->back = gdk_color_copy (oldfont->back); fonts = g_slist_prepend (fonts, font); case 44: /* BODY (opt) */ if (!(options & GTK_IMHTML_NO_COLOURS)) { gchar *bgcolor = gtk_imhtml_get_html_opt (tag, "BGCOLOR="); GdkColor *tmp = gtk_imhtml_get_color (bgcolor); gchar *href = gtk_imhtml_get_html_opt (tag, "HREF="); gchar *src = gtk_imhtml_get_html_opt (tag, "SRC="); gchar *id = gtk_imhtml_get_html_opt (tag, "ID="); gchar *datasize = gtk_imhtml_get_html_opt (tag, "DATASIZE="); if (!imhtml->img && id && datasize) { /* This is an embedded IM image */ char *tmp, *imagedata, *e; GdkPixbuf *imagepb = NULL; tmp = g_malloc(strlen("<DATA ID=\"\" SIZE=\"\">") + strlen(id) + strlen(datasize)); g_snprintf(tmp, strlen("<DATA ID=\"\" SIZE=\"\">") + strlen(id) + strlen(datasize) + 1, "<DATA ID=\"%s\" SIZE=\"%s\">", id, datasize); while (g_strncasecmp(alltext, tmp, strlen(tmp)) && alltext < (c + len)) alltext = alltext + strlen("<DATA ID=\"\" SIZE=\"\">") + strlen(id) + strlen(datasize); if (atoi(datasize) > len - pos) imagedata = g_malloc(atoi(datasize)); memcpy(imagedata, alltext, atoi(datasize)); if (!GTK_WIDGET_REALIZED (imhtml)) gtk_widget_realize (GTK_WIDGET (imhtml)); img = g_new0 (struct im_image, 1); if (*tmp == '/' || *tmp == '\\') { img->filename = g_strdup(src); img->len = atoi(datasize); img->data = g_malloc(img->len); memcpy(img->data, imagedata, img->len); load = gdk_pixbuf_loader_new(); if (!gdk_pixbuf_loader_write(load, imagedata, img->len)) g_print("IM Image corrupt or unreadable.\n"); imagepb = gdk_pixbuf_loader_get_pixbuf(load); bit = g_new0 (GtkIMHtmlBit, 1); bit->url = g_strdup (url); bit = g_new0 (GtkIMHtmlBit, 1); bit->url = g_strdup (url); if (!fonts || ((clr = ((FontDetail *) fonts->data)->back) == NULL)) clr = (bg != NULL) ? bg : imhtml->default_bg_color; bit->pm = gdk_pixmap_create_from_xpm_d (GTK_WIDGET (imhtml)->window, &bit->bm, clr, broken_xpm); if (!imhtml->img || ((xpm = imhtml->img (src)) == NULL)) { if (!fonts || ((clr = ((FontDetail *) fonts->data)->back) == NULL)) clr = (bg != NULL) ? bg : imhtml->default_bg_color; if (!GTK_WIDGET_REALIZED (imhtml)) gtk_widget_realize (GTK_WIDGET (imhtml)); bit = g_new0 (GtkIMHtmlBit, 1); bit->pm = gdk_pixmap_create_from_xpm_d (GTK_WIDGET (imhtml)->window, bit->url = g_strdup (url); wpos = g_snprintf (ws, len, "%s", tag); NEW_BIT (NEW_COMMENT_BIT); } else if (*c == '&' && gtk_imhtml_is_amp_escape (c, &, &tlen)) { if (!(options & GTK_IMHTML_NO_NEWLINE)) { } else if (gtk_imhtml_is_smiley (imhtml, c, &smilelen)) { wpos = g_snprintf (ws, smilelen + 1, "%s", c); NEW_BIT (NEW_SMILEY_BIT); GtkIMHtmlBit *bit = newbits->data; imhtml->bits = g_list_append (imhtml->bits, bit); newbits = g_list_remove (newbits, bit); gtk_imhtml_draw_bit (imhtml, bit); GTK_LAYOUT (imhtml)->height = imhtml->y; GTK_LAYOUT (imhtml)->vadjustment->upper = imhtml->y; gtk_signal_emit_by_name (GTK_OBJECT (GTK_LAYOUT (imhtml)->vadjustment), "changed"); gtk_widget_set_usize (GTK_WIDGET (imhtml), -1, imhtml->y); if (!(options & GTK_IMHTML_NO_SCROLL) && (GTK_WIDGET (imhtml)->allocation.height - (GTK_WIDGET (imhtml)->style->klass->ythickness + BORDER_SIZE) * 2)))) gtk_adjustment_set_value (vadj, imhtml->y - MAX (1, (GTK_WIDGET (imhtml)->allocation.height - (GTK_WIDGET (imhtml)->style->klass->ythickness + retval = g_string_append (retval, "</A>"); FontDetail *font = fonts->data; fonts = g_slist_remove (fonts, font); gdk_color_free (font->fore); gdk_color_free (font->back); retval = g_string_append (retval, "</FONT>"); retval = g_string_append (retval, "</B>"); retval = g_string_append (retval, "</I>"); retval = g_string_append (retval, "</U>"); retval = g_string_append (retval, "</S>"); retval = g_string_append (retval, "</SUB>"); retval = g_string_append (retval, "</SUP>"); retval = g_string_append (retval, "</TITLE>"); retval = g_string_append (retval, "</PRE>"); gtk_imhtml_clear (GtkIMHtml *imhtml) g_return_if_fail (imhtml != NULL); g_return_if_fail (GTK_IS_IMHTML (imhtml)); layout = GTK_LAYOUT (imhtml); GtkIMHtmlBit *bit = imhtml->bits->data; imhtml->bits = g_list_remove (imhtml->bits, bit); gdk_font_unref (bit->font); gdk_color_free (bit->fore); gdk_color_free (bit->back); gdk_color_free (bit->bg); gdk_pixmap_unref (bit->pm); gdk_bitmap_unref (bit->bm); g_free(bit->img->filename); gdk_pixbuf_unref(bit->img->pb); struct line_info *li = bit->chunks->data; bit->chunks = g_list_remove (bit->chunks, li); g_free (imhtml->click->data); imhtml->click = g_list_remove (imhtml->click, imhtml->click->data); while (imhtml->im_images) { imhtml->im_images = g_list_remove(imhtml->im_images, imhtml->im_images->data); if (imhtml->selected_text) { g_string_free (imhtml->selected_text, TRUE); imhtml->selected_text = g_string_new (""); imhtml->sel_endchunk = NULL; gtk_timeout_remove (imhtml->tip_timer); if (imhtml->tip_window) { gtk_widget_destroy (imhtml->tip_window); imhtml->tip_window = NULL; if (imhtml->scroll_timer) { gtk_timeout_remove (imhtml->scroll_timer); imhtml->scroll_timer = 0; g_list_free(imhtml->im_images); imhtml->im_images = NULL; g_list_free (imhtml->line); layout->hadjustment->page_size = 0; layout->hadjustment->page_increment = 0; layout->hadjustment->lower = 0; layout->hadjustment->upper = imhtml->x; gtk_adjustment_set_value (layout->hadjustment, 0); layout->vadjustment->page_size = 0; layout->vadjustment->page_increment = 0; layout->vadjustment->lower = 0; layout->vadjustment->upper = imhtml->y; gtk_adjustment_set_value (layout->vadjustment, 0); if (GTK_WIDGET_REALIZED (GTK_WIDGET (imhtml))) { gdk_window_set_cursor (GTK_LAYOUT (imhtml)->bin_window, imhtml->arrow_cursor); gdk_window_clear (GTK_LAYOUT (imhtml)->bin_window); gtk_signal_emit_by_name (GTK_OBJECT (layout->hadjustment), "changed"); gtk_signal_emit_by_name (GTK_OBJECT (layout->vadjustment), "changed"); gtk_imhtml_page_up (GtkIMHtml *imhtml) g_return_if_fail (imhtml != NULL); g_return_if_fail (GTK_IS_IMHTML (imhtml)); vadj = GTK_LAYOUT (imhtml)->vadjustment; gtk_adjustment_set_value (vadj, MAX (vadj->value - vadj->page_increment, gtk_signal_emit_by_name (GTK_OBJECT (vadj), "changed"); gtk_imhtml_page_down (GtkIMHtml *imhtml) g_return_if_fail (imhtml != NULL); g_return_if_fail (GTK_IS_IMHTML (imhtml)); vadj = GTK_LAYOUT (imhtml)->vadjustment; gtk_adjustment_set_value (vadj, MIN (vadj->value + vadj->page_increment, vadj->upper - vadj->page_size)); gtk_signal_emit_by_name (GTK_OBJECT (vadj), "changed");