Mercurial > pidgin
comparison src/gtkimhtml.c @ 3922:30f52e7afd1d
[gaim-migrate @ 4094]
This is gtkimhtml2--it's a subclass of gtktextview. It's not done yet. It doesn't
do smileys or images, and what it does do so far, it doesn't do perfectly. But it's
perfectly 100% usable, and like 80,000 times faster than gtkimhtml + Pango.
committer: Tailor Script <tailor@pidgin.im>
author | Sean Egan <seanegan@gmail.com> |
---|---|
date | Fri, 08 Nov 2002 06:10:35 +0000 |
parents | 988485669631 |
children | fb60cd7a2506 |
comparison
equal
deleted
inserted
replaced
3921:67209a7ee924 | 3922:30f52e7afd1d |
---|---|
21 | 21 |
22 #ifdef HAVE_CONFIG_H | 22 #ifdef HAVE_CONFIG_H |
23 #include <config.h> | 23 #include <config.h> |
24 #endif | 24 #endif |
25 #include "gtkimhtml.h" | 25 #include "gtkimhtml.h" |
26 | |
27 #ifndef _WIN32 | |
28 #include <X11/Xlib.h> | |
29 #include <gdk/gdkx.h> | |
30 #else | |
31 #include <gdk/gdkwin32.h> | |
32 #endif | |
33 | |
34 #include <stdlib.h> | |
35 #include <gtk/gtk.h> | 26 #include <gtk/gtk.h> |
36 #include <string.h> | 27 #include <string.h> |
37 #include <ctype.h> | 28 #include <ctype.h> |
38 #include <stdio.h> | 29 #include <stdio.h> |
39 #include <math.h> | 30 #include <math.h> |
40 #ifdef HAVE_LANGINFO_CODESET | 31 #ifdef HAVE_LANGINFO_CODESET |
41 #include <langinfo.h> | 32 #include <langinfo.h> |
42 #include <locale.h> | 33 #include <locale.h> |
43 #endif | 34 #endif |
44 | 35 |
45 #ifdef _WIN32 | 36 |
46 /* GDK_SELECTION_PRIMARY is ignored win32 GTK */ | 37 /* POINT_SIZE converts from AIM font sizes to point sizes. It probably should be redone in such a |
47 #undef GDK_SELECTION_PRIMARY | 38 * way that it base the sizes off the default font size rather than using arbitrary font sizes. */ |
48 #define GDK_SELECTION_PRIMARY GDK_SELECTION_CLIPBOARD | |
49 #endif | |
50 | |
51 #include <gdk-pixbuf/gdk-pixbuf.h> | |
52 #include <gdk-pixbuf/gdk-pixbuf-loader.h> | |
53 | |
54 #include <pango/pango.h> | |
55 | |
56 #include "pixmaps/angel.xpm" | |
57 #include "pixmaps/bigsmile.xpm" | |
58 #include "pixmaps/burp.xpm" | |
59 #include "pixmaps/crossedlips.xpm" | |
60 #include "pixmaps/cry.xpm" | |
61 #include "pixmaps/embarrassed.xpm" | |
62 #include "pixmaps/kiss.xpm" | |
63 #include "pixmaps/moneymouth.xpm" | |
64 #include "pixmaps/sad.xpm" | |
65 #include "pixmaps/scream.xpm" | |
66 #include "pixmaps/smile.xpm" | |
67 #include "pixmaps/smile8.xpm" | |
68 #include "pixmaps/think.xpm" | |
69 #include "pixmaps/tongue.xpm" | |
70 #include "pixmaps/wink.xpm" | |
71 #include "pixmaps/yell.xpm" | |
72 | |
73 #define MAX_FONT_SIZE 7 | 39 #define MAX_FONT_SIZE 7 |
74 | |
75 #define POINT_SIZE(x) (_point_sizes [MIN ((x), MAX_FONT_SIZE) - 1]) | 40 #define POINT_SIZE(x) (_point_sizes [MIN ((x), MAX_FONT_SIZE) - 1]) |
76 static gint _point_sizes [] = { 8, 10, 12, 14, 20, 30, 40 }; | 41 static gint _point_sizes [] = { 4, 6, 8, 10, 20, 30, 40 }; |
77 | 42 |
78 #define DEFAULT_PRE_FACE "sans" | 43 /* The four elements present in a <FONT> tag contained in a struct */ |
79 | |
80 #define BORDER_SIZE 2 | |
81 #define TOP_BORDER 10 | |
82 #define MIN_HEIGHT 20 | |
83 #define HR_HEIGHT 2 | |
84 #define TOOLTIP_TIMEOUT 500 | |
85 | |
86 #define DIFF(a, b) (((a) > (b)) ? ((a) - (b)) : ((b) - (a))) | |
87 #define COLOR_MOD 0x8000 | |
88 #define COLOR_DIFF 0x800 | |
89 | |
90 #define TYPE_TEXT 0 | |
91 #define TYPE_SMILEY 1 | |
92 #define TYPE_IMG 2 | |
93 #define TYPE_SEP 3 | |
94 #define TYPE_BR 4 | |
95 #define TYPE_COMMENT 5 | |
96 | |
97 #define GTK_IMHTML_GET_STYLE_FONT(style) gtk_style_get_font (style) | |
98 | |
99 #define DRAW_IMG(x) (((x)->type == TYPE_IMG) || (imhtml->smileys && ((x)->type == TYPE_SMILEY))) | |
100 | |
101 typedef struct _GtkIMHtmlBit GtkIMHtmlBit; | |
102 typedef struct _FontDetail FontDetail; | 44 typedef struct _FontDetail FontDetail; |
103 | |
104 struct _GtkSmileyTree { | |
105 GString *values; | |
106 GtkSmileyTree **children; | |
107 gchar **image; | |
108 }; | |
109 | |
110 /* | |
111 * PROTOS | |
112 */ | |
113 extern void debug_printf(char * fmt, ...); | |
114 | |
115 static GtkSmileyTree* | |
116 gtk_smiley_tree_new () | |
117 { | |
118 return g_new0 (GtkSmileyTree, 1); | |
119 } | |
120 | |
121 static void | |
122 gtk_smiley_tree_insert (GtkSmileyTree *tree, | |
123 const gchar *text, | |
124 gchar **image) | |
125 { | |
126 GtkSmileyTree *t = tree; | |
127 const gchar *x = text; | |
128 | |
129 if (!strlen (x)) | |
130 return; | |
131 | |
132 while (*x) { | |
133 gchar *pos; | |
134 gint index; | |
135 | |
136 if (!t->values) | |
137 t->values = g_string_new (""); | |
138 | |
139 pos = strchr (t->values->str, *x); | |
140 if (!pos) { | |
141 t->values = g_string_append_c (t->values, *x); | |
142 index = t->values->len - 1; | |
143 t->children = g_realloc (t->children, t->values->len * sizeof (GtkSmileyTree *)); | |
144 t->children [index] = g_new0 (GtkSmileyTree, 1); | |
145 } else | |
146 index = (int) pos - (int) t->values->str; | |
147 | |
148 t = t->children [index]; | |
149 | |
150 x++; | |
151 } | |
152 | |
153 t->image = image; | |
154 } | |
155 | |
156 static void | |
157 gtk_smiley_tree_remove (GtkSmileyTree *tree, | |
158 const gchar *text) | |
159 { | |
160 GtkSmileyTree *t = tree; | |
161 const gchar *x = text; | |
162 gint len = 0; | |
163 | |
164 while (*x) { | |
165 gchar *pos; | |
166 | |
167 if (!t->values) | |
168 return; | |
169 | |
170 pos = strchr (t->values->str, *x); | |
171 if (pos) | |
172 t = t->children [(int) pos - (int) t->values->str]; | |
173 else | |
174 return; | |
175 | |
176 x++; len++; | |
177 } | |
178 | |
179 if (t->image) | |
180 t->image = NULL; | |
181 } | |
182 | |
183 static gint | |
184 gtk_smiley_tree_lookup (GtkSmileyTree *tree, | |
185 const gchar *text) | |
186 { | |
187 GtkSmileyTree *t = tree; | |
188 const gchar *x = text; | |
189 gint len = 0; | |
190 | |
191 while (*x) { | |
192 gchar *pos; | |
193 | |
194 if (!t->values) | |
195 break; | |
196 | |
197 pos = strchr (t->values->str, *x); | |
198 if (pos) | |
199 t = t->children [(int) pos - (int) t->values->str]; | |
200 else | |
201 break; | |
202 | |
203 x++; len++; | |
204 } | |
205 | |
206 if (t->image) | |
207 return len; | |
208 | |
209 return 0; | |
210 } | |
211 | |
212 static gchar** | |
213 gtk_smiley_tree_image (GtkSmileyTree *tree, | |
214 const gchar *text) | |
215 { | |
216 GtkSmileyTree *t = tree; | |
217 const gchar *x = text; | |
218 | |
219 while (*x) { | |
220 gchar *pos; | |
221 | |
222 if (!t->values) | |
223 return NULL; | |
224 | |
225 pos = strchr (t->values->str, *x); | |
226 if (pos) { | |
227 t = t->children [(int) pos - (int) t->values->str]; | |
228 } else | |
229 return NULL; | |
230 | |
231 x++; | |
232 } | |
233 | |
234 return t->image; | |
235 } | |
236 | |
237 static void | |
238 gtk_smiley_tree_destroy (GtkSmileyTree *tree) | |
239 { | |
240 GSList *list = g_slist_append (NULL, tree); | |
241 | |
242 while (list) { | |
243 GtkSmileyTree *t = list->data; | |
244 gint i; | |
245 list = g_slist_remove(list, t); | |
246 if (t->values) { | |
247 for (i = 0; i < t->values->len; i++) | |
248 list = g_slist_append (list, t->children [i]); | |
249 g_string_free (t->values, TRUE); | |
250 g_free (t->children); | |
251 } | |
252 g_free (t); | |
253 } | |
254 } | |
255 | |
256 void | |
257 gtk_imhtml_remove_smileys (GtkIMHtml *imhtml) | |
258 { | |
259 g_return_if_fail (imhtml != NULL); | |
260 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
261 | |
262 gtk_smiley_tree_destroy (imhtml->smiley_data); | |
263 imhtml->smiley_data = gtk_smiley_tree_new (); | |
264 } | |
265 | |
266 void | |
267 gtk_imhtml_reset_smileys (GtkIMHtml *imhtml) | |
268 { | |
269 gtk_imhtml_remove_smileys(imhtml); | |
270 gtk_imhtml_init_smileys (imhtml); | |
271 } | |
272 | |
273 | |
274 struct im_image { | |
275 gchar *filename; | |
276 | |
277 gint len; | |
278 gpointer data; | |
279 | |
280 gint x,y; | |
281 gint width,height; | |
282 GtkIMHtml *imhtml; | |
283 GtkIMHtmlBit *bit; | |
284 GdkPixbuf *pb; | |
285 }; | |
286 | |
287 struct _GtkIMHtmlBit { | |
288 gint type; | |
289 | |
290 gchar *text; | |
291 struct im_image *img; | |
292 GdkPixmap *pm; | |
293 GdkBitmap *bm; | |
294 | |
295 PangoFontDescription *font; | |
296 GdkColor *fore; | |
297 GdkColor *back; | |
298 GdkColor *bg; | |
299 gboolean underline; | |
300 gboolean strike; | |
301 gchar *url; | |
302 | |
303 GList *chunks; | |
304 }; | |
305 | |
306 struct _FontDetail { | 45 struct _FontDetail { |
307 gushort size; | 46 gushort size; |
308 gchar *face; | 47 gchar *face; |
309 GdkColor *fore; | 48 gchar *fore; |
310 GdkColor *back; | 49 gchar *back; |
311 }; | 50 }; |
312 | 51 |
313 struct line_info { | 52 /* GtkIMHtml has one signal--URL_CLICKED */ |
314 gint x; | |
315 gint y; | |
316 gint width; | |
317 gint height; | |
318 gint ascent; | |
319 | |
320 gboolean selected; | |
321 gchar *sel_start; | |
322 gchar *sel_end; | |
323 | |
324 gchar *text; | |
325 GtkIMHtmlBit *bit; | |
326 }; | |
327 | |
328 struct clickable { | |
329 gint x; | |
330 gint y; | |
331 gint width; | |
332 gint height; | |
333 GtkIMHtml *imhtml; | |
334 GtkIMHtmlBit *bit; | |
335 }; | |
336 | |
337 static GtkLayoutClass *parent_class = NULL; | |
338 | |
339 enum { | |
340 TARGET_STRING, | |
341 TARGET_TEXT, | |
342 TARGET_COMPOUND_TEXT | |
343 }; | |
344 | |
345 enum { | 53 enum { |
346 URL_CLICKED, | 54 URL_CLICKED, |
347 LAST_SIGNAL | 55 LAST_SIGNAL |
348 }; | 56 }; |
349 static guint signals [LAST_SIGNAL] = { 0 }; | 57 static guint signals [LAST_SIGNAL] = { 0 }; |
350 | 58 |
351 static void gtk_imhtml_draw_bit (GtkIMHtml *, GtkIMHtmlBit *); | 59 |
352 static GdkColor *gtk_imhtml_get_color (const gchar *); | 60 /* Boring GTK stuff */ |
353 static gint gtk_imhtml_motion_notify_event (GtkWidget *, GdkEventMotion *); | 61 static void gtk_imhtml_class_init (GtkIMHtmlClass *class) |
354 | 62 { |
355 static void | 63 GtkObjectClass *object_class; |
356 gtk_imhtml_finalize (GObject *object) | 64 object_class = (GtkObjectClass*) class; |
357 { | 65 signals[URL_CLICKED] = gtk_signal_new("url_clicked", |
358 GtkIMHtml *imhtml; | 66 GTK_RUN_FIRST, |
359 | 67 GTK_CLASS_TYPE(object_class), |
360 imhtml = GTK_IMHTML (object); | 68 GTK_SIGNAL_OFFSET(GtkIMHtmlClass, url_clicked), |
361 | 69 gtk_marshal_NONE__POINTER, |
362 gtk_imhtml_clear (imhtml); | 70 GTK_TYPE_NONE, 1, |
363 | 71 GTK_TYPE_POINTER); |
364 if (imhtml->selected_text) | 72 } |
365 g_string_free (imhtml->selected_text, TRUE); | 73 |
366 | 74 static void gtk_imhtml_init (GtkIMHtml *imhtml) |
367 if (imhtml->default_font) | 75 { |
368 pango_font_description_free (imhtml->default_font); | 76 GtkTextIter iter; |
369 if (imhtml->default_fg_color) | 77 imhtml->text_buffer = gtk_text_buffer_new(NULL); |
370 gdk_color_free (imhtml->default_fg_color); | 78 gtk_text_buffer_get_end_iter (imhtml->text_buffer, &iter); |
371 if (imhtml->default_bg_color) | 79 imhtml->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, FALSE); |
372 gdk_color_free (imhtml->default_bg_color); | 80 gtk_text_view_set_buffer(GTK_TEXT_VIEW(imhtml), imhtml->text_buffer); |
373 if (imhtml->default_hl_color) | 81 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(imhtml), GTK_WRAP_WORD); |
374 gdk_color_free (imhtml->default_hl_color); | 82 gtk_text_view_set_editable(GTK_TEXT_VIEW(imhtml), FALSE); |
375 if (imhtml->default_hlfg_color) | 83 gtk_text_view_set_pixels_below_lines(GTK_TEXT_VIEW(imhtml), 5); |
376 gdk_color_free (imhtml->default_hlfg_color); | 84 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(imhtml), FALSE); |
377 | 85 /*gtk_text_view_set_justification(GTK_TEXT_VIEW(imhtml), GTK_JUSTIFY_FILL);*/ |
378 gdk_cursor_destroy (imhtml->hand_cursor); | |
379 gdk_cursor_destroy (imhtml->arrow_cursor); | |
380 | |
381 gtk_smiley_tree_destroy (imhtml->smiley_data); | |
382 | |
383 G_OBJECT_CLASS (parent_class)->finalize (object); | |
384 } | |
385 | |
386 static void | |
387 gtk_imhtml_realize (GtkWidget *widget) | |
388 { | |
389 GtkIMHtml *imhtml; | |
390 GdkWindowAttr attributes; | |
391 gint attributes_mask; | |
392 | |
393 g_return_if_fail (widget != NULL); | |
394 g_return_if_fail (GTK_IS_IMHTML (widget)); | |
395 | |
396 imhtml = GTK_IMHTML (widget); | |
397 GTK_WIDGET_SET_FLAGS (imhtml, GTK_REALIZED); | |
398 | |
399 attributes.window_type = GDK_WINDOW_CHILD; | |
400 attributes.x = widget->allocation.x; | |
401 attributes.y = widget->allocation.y; | |
402 attributes.width = widget->allocation.width; | |
403 attributes.height = widget->allocation.height; | |
404 attributes.wclass = GDK_INPUT_OUTPUT; | |
405 attributes.visual = gtk_widget_get_visual (widget); | |
406 attributes.colormap = gtk_widget_get_colormap (widget); | |
407 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK; | |
408 | |
409 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; | |
410 | |
411 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), | |
412 &attributes, attributes_mask); | |
413 gdk_window_set_user_data (widget->window, widget); | |
414 | |
415 attributes.x = widget->style->xthickness + BORDER_SIZE; | |
416 attributes.y = widget->style->xthickness + BORDER_SIZE; | |
417 attributes.width = MAX (1, (gint) widget->allocation.width - (gint) attributes.x * 2); | |
418 attributes.height = MAX (1, (gint) widget->allocation.height - (gint) attributes.y * 2); | |
419 attributes.event_mask = gtk_widget_get_events (widget) | |
420 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | |
421 | GDK_POINTER_MOTION_MASK | GDK_EXPOSURE_MASK | GDK_LEAVE_NOTIFY_MASK; | |
422 | |
423 GTK_LAYOUT (imhtml)->bin_window = gdk_window_new (widget->window, | |
424 &attributes, attributes_mask); | |
425 gdk_window_set_user_data (GTK_LAYOUT (imhtml)->bin_window, widget); | |
426 | |
427 widget->style = gtk_style_attach (widget->style, widget->window); | |
428 | |
429 gdk_window_set_cursor (widget->window, imhtml->arrow_cursor); | |
430 | |
431 imhtml->context = gtk_widget_get_pango_context(widget); | |
432 imhtml->default_font = pango_font_description_copy(pango_context_get_font_description(imhtml->context)); | |
433 | |
434 gdk_window_set_background (widget->window, &widget->style->base [GTK_STATE_NORMAL]); | |
435 gdk_window_set_background (GTK_LAYOUT (imhtml)->bin_window, | |
436 &widget->style->base [GTK_STATE_NORMAL]); | |
437 | |
438 imhtml->default_fg_color = gdk_color_copy (>K_WIDGET (imhtml)->style->fg [GTK_STATE_NORMAL]); | |
439 imhtml->default_bg_color = gdk_color_copy (>K_WIDGET (imhtml)->style->base [GTK_STATE_NORMAL]); | |
440 imhtml->default_hl_color = gdk_color_copy (>K_WIDGET (imhtml)->style->bg [GTK_STATE_SELECTED]); | |
441 imhtml->default_hlfg_color=gdk_color_copy (>K_WIDGET (imhtml)->style->fg [GTK_STATE_SELECTED]); | |
442 | |
443 gdk_window_show (GTK_LAYOUT (imhtml)->bin_window); | |
444 } | |
445 | |
446 static gboolean | |
447 similar_colors (GdkColor *bg, | |
448 GdkColor *fg) | |
449 { | |
450 if ((DIFF (bg->red, fg->red) < COLOR_DIFF) && | |
451 (DIFF (bg->green, fg->green) < COLOR_DIFF) && | |
452 (DIFF (bg->blue, fg->blue) < COLOR_DIFF)) { | |
453 fg->red = (0xff00 - COLOR_MOD > bg->red) ? | |
454 bg->red + COLOR_MOD : bg->red - COLOR_MOD; | |
455 fg->green = (0xff00 - COLOR_MOD > bg->green) ? | |
456 bg->green + COLOR_MOD : bg->green - COLOR_MOD; | |
457 fg->blue = (0xff00 - COLOR_MOD > bg->blue) ? | |
458 bg->blue + COLOR_MOD : bg->blue - COLOR_MOD; | |
459 return TRUE; | |
460 } | |
461 return FALSE; | |
462 } | |
463 | |
464 /* This is an expensive function! Don't blame me. I only stole it from eel */ | |
465 static gint | |
466 text_width(PangoContext *context, PangoFontDescription *desc, | |
467 const char *text, gint len) | |
468 { | |
469 static PangoLayout *layout = NULL; | |
470 int width; | |
471 | |
472 if (layout == NULL) | |
473 layout = pango_layout_new(context); | |
474 | |
475 pango_layout_set_font_description(layout, desc); | |
476 pango_layout_set_text(layout, text, len); | |
477 pango_layout_get_pixel_size(layout, &width, NULL); | |
478 | |
479 /* g_object_unref(G_OBJECT(layout)); */ | |
480 | |
481 return width; | |
482 } | |
483 | |
484 static gint | |
485 string_width(PangoContext *context, PangoFontDescription *desc, | |
486 const char *text) | |
487 { | |
488 return text_width(context, desc, text, -1); | |
489 } | |
490 | |
491 static void | |
492 set_layout_font(PangoLayout *layout, const char *text, guint len, | |
493 PangoFontDescription *desc) | |
494 { | |
495 PangoAttribute *attr; | |
496 PangoAttrList *list; | |
497 | |
498 if (len == -1) | |
499 len = strlen(text); | |
500 | |
501 attr = pango_attr_font_desc_new(desc); | |
502 | |
503 attr->start_index = 0; | |
504 attr->end_index = len; | |
505 | |
506 list = pango_attr_list_new(); | |
507 pango_attr_list_insert(list, attr); | |
508 | |
509 pango_layout_set_attributes(layout, list); | |
510 pango_attr_list_unref(list); | |
511 | |
512 pango_layout_set_indent(layout, 0); | |
513 pango_layout_set_justify(layout, FALSE); | |
514 pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT); | |
515 } | |
516 | |
517 static gint | |
518 get_layout_first_baseline(PangoLayout* layout) | |
519 { | |
520 PangoLayoutIter* iter = pango_layout_get_iter(layout); | |
521 gint result = pango_layout_iter_get_baseline(iter) / PANGO_SCALE; | |
522 pango_layout_iter_free(iter); | |
523 return result; | |
524 } | |
525 | |
526 static void | |
527 draw_text (GtkIMHtml *imhtml, | |
528 struct line_info *line) | |
529 { | |
530 GtkIMHtmlBit *bit; | |
531 GdkGC *gc; | |
532 GdkColormap *cmap; | |
533 GdkWindow *window = GTK_LAYOUT (imhtml)->bin_window; | |
534 gfloat xoff, yoff; | |
535 GdkColor *bg, *fg; | |
536 PangoLayout *layout; | |
537 PangoFontMetrics *metrics; | |
538 gchar *start = NULL, *end = NULL; | |
539 | |
540 if (GTK_LAYOUT (imhtml)->freeze_count) | |
541 return; | |
542 | |
543 bit = line->bit; | |
544 gc = gdk_gc_new (window); | |
545 cmap = gtk_widget_get_colormap (GTK_WIDGET (imhtml)); | |
546 xoff = GTK_LAYOUT (imhtml)->hadjustment->value; | |
547 yoff = GTK_LAYOUT (imhtml)->vadjustment->value; | |
548 | |
549 if (bit->bg != NULL) { | |
550 gdk_color_alloc (cmap, bit->bg); | |
551 gdk_gc_set_foreground (gc, bit->bg); | |
552 bg = bit->bg; | |
553 } else { | |
554 gdk_color_alloc (cmap, imhtml->default_bg_color); | |
555 gdk_gc_set_foreground (gc, imhtml->default_bg_color); | |
556 bg = imhtml->default_bg_color; | |
557 } | |
558 | |
559 gdk_draw_rectangle (window, gc, TRUE, line->x - xoff, line->y - yoff, | |
560 line->width ? line->width : imhtml->xsize, line->height); | |
561 | |
562 if (!line->text) { | |
563 gdk_gc_unref (gc); | |
564 return; | |
565 } | |
566 | |
567 if (bit->back != NULL) { | |
568 gdk_color_alloc (cmap, bit->back); | |
569 gdk_gc_set_foreground (gc, bit->back); | |
570 gdk_draw_rectangle (window, gc, TRUE, line->x - xoff, line->y - yoff, | |
571 string_width (imhtml->context, bit->font, line->text), line->height); | |
572 bg = bit->back; | |
573 } | |
574 | |
575 bg = gdk_color_copy (bg); | |
576 | |
577 if (line->selected) { | |
578 gint width, x; | |
579 | |
580 if ((line->sel_start > line->sel_end) && (line->sel_end != NULL)) { | |
581 start = line->sel_end; | |
582 end = line->sel_start; | |
583 } else { | |
584 start = line->sel_start; | |
585 end = line->sel_end; | |
586 } | |
587 | |
588 if (start == NULL) | |
589 x = 0; | |
590 else | |
591 x = text_width (imhtml->context, bit->font, line->text, start - line->text); | |
592 | |
593 if (end == NULL) | |
594 end = strchr(line->text, '\0'); | |
595 | |
596 width = text_width (imhtml->context, bit->font, line->text, end - line->text) - x; | |
597 | |
598 gdk_gc_set_foreground (gc, imhtml->default_hl_color); | |
599 | |
600 gdk_draw_rectangle (window, gc, TRUE, x + line->x - xoff, line->y - yoff, | |
601 width, line->height); | |
602 gdk_gc_set_foreground (gc, imhtml->default_hlfg_color); | |
603 fg = gdk_color_copy(imhtml->default_hlfg_color); | |
604 } | |
605 if (bit->url) { | |
606 GdkColor *tc = gtk_imhtml_get_color ("#0000a0"); | |
607 gdk_color_alloc (cmap, tc); | |
608 gdk_gc_set_foreground (gc, tc); | |
609 fg = gdk_color_copy (tc); | |
610 gdk_color_free (tc); | |
611 } else if (bit->fore) { | |
612 gdk_color_alloc (cmap, bit->fore); | |
613 gdk_gc_set_foreground (gc, bit->fore); | |
614 fg = gdk_color_copy (bit->fore); | |
615 } else { | |
616 gdk_color_alloc (cmap, imhtml->default_fg_color); | |
617 gdk_gc_set_foreground (gc, imhtml->default_fg_color); | |
618 fg = gdk_color_copy (imhtml->default_fg_color); | |
619 } | |
620 | |
621 if (similar_colors (bg, fg)) { | |
622 gdk_color_alloc (cmap, fg); | |
623 gdk_gc_set_foreground (gc, fg); | |
624 } | |
625 | 86 |
626 metrics = pango_context_get_metrics(imhtml->context, bit->font, NULL); | 87 /* These tags will be used often and can be reused--we create them on init and then apply them by name |
627 | 88 * other tags (color, size, face, etc.) will have to be created and applied dynamically */ |
628 if (start) { | 89 gtk_text_buffer_create_tag(imhtml->text_buffer, "BOLD", "weight", PANGO_WEIGHT_BOLD, NULL); |
629 int offset = 0; | 90 gtk_text_buffer_create_tag(imhtml->text_buffer, "ITALICS", "style", PANGO_STYLE_ITALIC, NULL); |
630 | 91 gtk_text_buffer_create_tag(imhtml->text_buffer, "UNDERLINE", "underline", PANGO_UNDERLINE_SINGLE, NULL); |
631 layout = gtk_widget_create_pango_layout(GTK_WIDGET(imhtml), NULL); | 92 gtk_text_buffer_create_tag(imhtml->text_buffer, "STRIKE", "strikethrough", TRUE, NULL); |
632 pango_layout_set_text(layout, line->text, start - line->text); | 93 gtk_text_buffer_create_tag(imhtml->text_buffer, "SUB", "rise", -5000, NULL); |
633 set_layout_font(layout, line->text, start - line->text, bit->font); | 94 gtk_text_buffer_create_tag(imhtml->text_buffer, "SUP", "rise", 5000, NULL); |
634 gdk_draw_layout(window, gc, line->x - xoff, | 95 gtk_text_buffer_create_tag(imhtml->text_buffer, "PRE", "family", "Monospace", NULL); |
635 line->y - yoff + line->ascent - | |
636 get_layout_first_baseline(layout), layout); | |
637 g_object_unref(G_OBJECT(layout)); | |
638 | |
639 offset = text_width (imhtml->context, bit->font, line->text, start - line->text); | |
640 if (bit->underline || bit->url) | |
641 gdk_draw_rectangle (window, gc, TRUE, line->x - xoff, | |
642 line->y - yoff + line->ascent + 1, | |
643 offset, 1); | |
644 if (bit->strike) | |
645 gdk_draw_rectangle (window, gc, TRUE, line->x - xoff, | |
646 line->y - yoff + line->ascent - | |
647 ((pango_font_metrics_get_ascent(metrics) / PANGO_SCALE) / 2), | |
648 offset, 1); | |
649 gdk_gc_set_foreground (gc, imhtml->default_hlfg_color); | |
650 | |
651 layout = gtk_widget_create_pango_layout(GTK_WIDGET(imhtml), NULL); | |
652 pango_layout_set_text(layout, start, end - start); | |
653 set_layout_font(layout, start, end - start, bit->font); | |
654 gdk_draw_layout(window, gc, line->x - xoff + offset, | |
655 line->y - yoff + line->ascent - | |
656 get_layout_first_baseline(layout), layout); | |
657 g_object_unref(G_OBJECT(layout)); | |
658 | |
659 if (bit->underline || bit->url) | |
660 gdk_draw_rectangle (window, gc, TRUE, line->x - xoff + offset, | |
661 line->y - yoff + line->ascent + 1, | |
662 text_width (imhtml->context, bit->font, line->text, end - start), 1); | |
663 if (bit->strike) | |
664 gdk_draw_rectangle (window, gc, TRUE, line->x - xoff + offset, | |
665 line->y - yoff + line->ascent - | |
666 ((pango_font_metrics_get_ascent(metrics) / PANGO_SCALE) / 2), | |
667 text_width (imhtml->context, bit->font, line->text, end - start), 1); | |
668 offset = text_width (imhtml->context, bit->font, line->text, end - line->text); | |
669 gdk_gc_set_foreground (gc, fg); | |
670 | |
671 layout = gtk_widget_create_pango_layout(GTK_WIDGET(imhtml), end); | |
672 set_layout_font(layout, end, -1, bit->font); | |
673 gdk_draw_layout(window, gc, line->x - xoff + offset, | |
674 line->y - yoff + line->ascent - | |
675 get_layout_first_baseline(layout), layout); | |
676 | |
677 g_object_unref(G_OBJECT(layout)); | |
678 | |
679 if (bit->underline || bit->url) | |
680 gdk_draw_rectangle (window, gc, TRUE, line->x - xoff + offset, | |
681 line->y - yoff + line->ascent + 1, | |
682 string_width (imhtml->context, bit->font, end), 1); | |
683 if (bit->strike) | |
684 gdk_draw_rectangle (window, gc, TRUE, line->x - xoff + offset, | |
685 line->y - yoff + line->ascent - | |
686 ((pango_font_metrics_get_ascent(metrics) / PANGO_SCALE) / 2), | |
687 string_width (imhtml->context, bit->font, end), 1); | |
688 } else { | |
689 layout = gtk_widget_create_pango_layout(GTK_WIDGET(imhtml), line->text); | |
690 set_layout_font(layout, line->text, -1, bit->font); | |
691 gdk_draw_layout(window, gc, line->x - xoff, | |
692 line->y - yoff + line->ascent - | |
693 get_layout_first_baseline(layout), layout); | |
694 g_object_unref(G_OBJECT(layout)); | |
695 | |
696 if (bit->underline || bit->url) | |
697 gdk_draw_rectangle (window, gc, TRUE, line->x - xoff, line->y - yoff + line->ascent + 1, | |
698 string_width (imhtml->context, bit->font, line->text), 1); | |
699 if (bit->strike) | |
700 gdk_draw_rectangle (window, gc, TRUE, line->x - xoff, | |
701 line->y - yoff + line->ascent - | |
702 ((pango_font_metrics_get_ascent(metrics) / PANGO_SCALE) / 2), | |
703 string_width (imhtml->context, bit->font, line->text), 1); | |
704 } | |
705 | |
706 pango_font_metrics_unref(metrics); | |
707 | |
708 gdk_color_free (bg); | |
709 gdk_color_free (fg); | |
710 | |
711 gdk_gc_unref (gc); | |
712 } | |
713 | |
714 static void | |
715 draw_img (GtkIMHtml *imhtml, | |
716 struct line_info *line) | |
717 { | |
718 GtkIMHtmlBit *bit; | |
719 GdkGC *gc; | |
720 GdkColormap *cmap; | |
721 gint width, height, hoff; | |
722 GdkWindow *window = GTK_LAYOUT (imhtml)->bin_window; | |
723 gfloat xoff, yoff; | |
724 | |
725 if (GTK_LAYOUT (imhtml)->freeze_count) | |
726 return; | |
727 | |
728 bit = line->bit; | |
729 gdk_window_get_size (bit->pm, &width, &height); | |
730 hoff = (line->height - height) / 2; | |
731 xoff = GTK_LAYOUT (imhtml)->hadjustment->value; | |
732 yoff = GTK_LAYOUT (imhtml)->vadjustment->value; | |
733 gc = gdk_gc_new (window); | |
734 cmap = gtk_widget_get_colormap (GTK_WIDGET (imhtml)); | |
735 | 96 |
736 if (bit->bg != NULL) { | 97 /* When hovering over a link, we show the hand cursor--elsewhere we show the plain ol' pointer cursor */ |
737 gdk_color_alloc (cmap, bit->bg); | |
738 gdk_gc_set_foreground (gc, bit->bg); | |
739 } else { | |
740 gdk_color_alloc (cmap, imhtml->default_bg_color); | |
741 gdk_gc_set_foreground (gc, imhtml->default_bg_color); | |
742 } | |
743 | |
744 gdk_draw_rectangle (window, gc, TRUE, line->x - xoff, line->y - yoff, line->width, line->height); | |
745 | |
746 if (line->selected) { | |
747 gdk_color_alloc (cmap, imhtml->default_hl_color); | |
748 gdk_gc_set_foreground(gc, imhtml->default_hl_color); | |
749 gdk_draw_rectangle (window, gc, TRUE, line->x - xoff, line->y - yoff, | |
750 width, line->height); | |
751 } else if (bit->back != NULL) { | |
752 gdk_color_alloc (cmap, bit->back); | |
753 gdk_gc_set_foreground (gc, bit->back); | |
754 } | |
755 | |
756 if (bit->bm) { | |
757 gdk_gc_set_clip_mask(gc, bit->bm); | |
758 gdk_gc_set_clip_origin(gc, line->x - xoff, line->y - yoff + hoff); | |
759 } | |
760 gdk_draw_pixmap (window, gc, bit->pm, 0, 0, line->x - xoff, line->y - yoff + hoff, -1, -1); | |
761 | |
762 gdk_gc_unref (gc); | |
763 } | |
764 | |
765 static void | |
766 draw_line (GtkIMHtml *imhtml, | |
767 struct line_info *line) | |
768 { | |
769 GtkIMHtmlBit *bit; | |
770 GdkDrawable *drawable; | |
771 GdkColormap *cmap; | |
772 GdkGC *gc; | |
773 guint line_height; | |
774 gfloat xoff, yoff; | |
775 | |
776 if (GTK_LAYOUT (imhtml)->freeze_count) | |
777 return; | |
778 | |
779 xoff = GTK_LAYOUT (imhtml)->hadjustment->value; | |
780 yoff = GTK_LAYOUT (imhtml)->vadjustment->value; | |
781 bit = line->bit; | |
782 drawable = GTK_LAYOUT (imhtml)->bin_window; | |
783 cmap = gtk_widget_get_colormap (GTK_WIDGET (imhtml)); | |
784 gc = gdk_gc_new (drawable); | |
785 | |
786 if (line->selected) { | |
787 gdk_color_alloc (cmap, imhtml->default_hl_color); | |
788 gdk_gc_set_foreground (gc, imhtml->default_hl_color); | |
789 } else if (bit->bg != NULL) { | |
790 gdk_color_alloc (cmap, bit->bg); | |
791 gdk_gc_set_foreground (gc, bit->bg); | |
792 } else { | |
793 gdk_color_alloc (cmap, imhtml->default_bg_color); | |
794 gdk_gc_set_foreground (gc, imhtml->default_bg_color); | |
795 } | |
796 | |
797 gdk_draw_rectangle (drawable, gc, TRUE, line->x - xoff, line->y - yoff, | |
798 line->width, line->height); | |
799 | |
800 | |
801 if (line->selected) { | |
802 gdk_color_alloc (cmap, imhtml->default_hlfg_color); | |
803 gdk_gc_set_foreground (gc, imhtml->default_hlfg_color); | |
804 } else { | |
805 gdk_color_alloc (cmap, imhtml->default_fg_color); | |
806 gdk_gc_set_foreground (gc, imhtml->default_fg_color); | |
807 } | |
808 | |
809 line_height = line->height / 2; | |
810 | |
811 gdk_draw_rectangle (drawable, gc, TRUE, line->x - xoff, line->y - yoff + line_height / 2, | |
812 line->width, line_height); | |
813 | |
814 gdk_gc_unref (gc); | |
815 } | |
816 | |
817 static void | |
818 gtk_imhtml_draw_focus (GtkWidget *widget) | |
819 { | |
820 GtkIMHtml *imhtml; | |
821 gint x = 0, | |
822 y = 0, | |
823 w = 0, | |
824 h = 0; | |
825 | |
826 imhtml = GTK_IMHTML (widget); | |
827 | |
828 if (!GTK_WIDGET_DRAWABLE (widget)) | |
829 return; | |
830 | |
831 if (GTK_WIDGET_HAS_FOCUS (widget)) { | |
832 gtk_paint_focus (widget->style, widget->window, GTK_STATE_NORMAL, NULL, widget, "text", | |
833 0, 0, widget->allocation.width - 1, widget->allocation.height - 1); | |
834 x = 1; y = 1; w = 2; h = 2; | |
835 } | |
836 | |
837 gtk_paint_shadow (widget->style, widget->window, GTK_STATE_NORMAL, | |
838 GTK_SHADOW_IN, NULL, widget, "text", x, y, | |
839 widget->allocation.width - w, widget->allocation.height - h); | |
840 } | |
841 | |
842 static void | |
843 gtk_imhtml_draw_exposed (GtkIMHtml *imhtml) | |
844 { | |
845 GList *bits; | |
846 GtkIMHtmlBit *bit; | |
847 GList *chunks; | |
848 struct line_info *line; | |
849 gfloat x, y; | |
850 guint32 width, height; | |
851 | |
852 x = GTK_LAYOUT (imhtml)->hadjustment->value; | |
853 y = GTK_LAYOUT (imhtml)->vadjustment->value; | |
854 gdk_window_get_size (GTK_LAYOUT (imhtml)->bin_window, &width, &height); | |
855 | |
856 bits = imhtml->bits; | |
857 | |
858 while (bits) { | |
859 bit = bits->data; | |
860 chunks = bit->chunks; | |
861 if (DRAW_IMG (bit)) { | |
862 if (chunks) { | |
863 line = chunks->data; | |
864 if ((line->x <= x + width) && | |
865 (line->y <= y + height) && | |
866 (x <= line->x + line->width) && | |
867 (y <= line->y + line->height)) | |
868 draw_img (imhtml, line); | |
869 } | |
870 } else if (bit->type == TYPE_SEP) { | |
871 if (chunks) { | |
872 line = chunks->data; | |
873 if ((line->x <= x + width) && | |
874 (line->y <= y + height) && | |
875 (x <= line->x + line->width) && | |
876 (y <= line->y + line->height)) | |
877 draw_line (imhtml, line); | |
878 | |
879 line = chunks->next->data; | |
880 if ((line->x <= x + width) && | |
881 (line->y <= y + height) && | |
882 (x <= line->x + line->width) && | |
883 (y <= line->y + line->height)) | |
884 draw_text (imhtml, line); | |
885 } | |
886 } else { | |
887 while (chunks) { | |
888 line = chunks->data; | |
889 if ((line->x <= x + width) && | |
890 (line->y <= y + height) && | |
891 (x <= line->x + line->width) && | |
892 (y <= line->y + line->height)) | |
893 draw_text (imhtml, line); | |
894 chunks = g_list_next (chunks); | |
895 } | |
896 } | |
897 bits = g_list_next (bits); | |
898 } | |
899 | |
900 gtk_imhtml_draw_focus (GTK_WIDGET (imhtml)); | |
901 } | |
902 | |
903 static void | |
904 gtk_imhtml_style_set (GtkWidget *widget, | |
905 GtkStyle *style) | |
906 { | |
907 GtkIMHtml *imhtml; | |
908 | |
909 g_return_if_fail (widget != NULL); | |
910 g_return_if_fail (GTK_IS_IMHTML (widget)); | |
911 | |
912 if (GTK_WIDGET_CLASS (parent_class)->style_set) | |
913 (* GTK_WIDGET_CLASS (parent_class)->style_set) (widget, style); | |
914 | |
915 if (!GTK_WIDGET_REALIZED (widget)) | |
916 return; | |
917 | |
918 imhtml = GTK_IMHTML (widget); | |
919 if (imhtml->default_fg_color) | |
920 gdk_color_free(imhtml->default_fg_color); | |
921 if (imhtml->default_bg_color) | |
922 gdk_color_free(imhtml->default_bg_color); | |
923 if (imhtml->default_hl_color) | |
924 gdk_color_free(imhtml->default_hl_color); | |
925 if (imhtml->default_hlfg_color) | |
926 gdk_color_free(imhtml->default_hlfg_color); | |
927 imhtml->default_fg_color = gdk_color_copy (>K_WIDGET (imhtml)->style->fg [GTK_STATE_NORMAL]); | |
928 imhtml->default_bg_color = gdk_color_copy (>K_WIDGET (imhtml)->style->base [GTK_STATE_NORMAL]); | |
929 imhtml->default_hl_color = gdk_color_copy (>K_WIDGET (imhtml)->style->bg [GTK_STATE_SELECTED]); | |
930 imhtml->default_hlfg_color=gdk_color_copy (>K_WIDGET (imhtml)->style->fg [GTK_STATE_SELECTED]); | |
931 gdk_window_set_background (widget->window, &widget->style->base [GTK_STATE_NORMAL]); | |
932 gdk_window_set_background (GTK_LAYOUT (imhtml)->bin_window, | |
933 &widget->style->base [GTK_STATE_NORMAL]); | |
934 gtk_imhtml_draw_exposed (imhtml); | |
935 } | |
936 | |
937 static gint | |
938 gtk_imhtml_expose_event (GtkWidget *widget, | |
939 GdkEventExpose *event) | |
940 { | |
941 GtkIMHtml *imhtml; | |
942 | |
943 g_return_val_if_fail (widget != NULL, FALSE); | |
944 g_return_val_if_fail (GTK_IS_IMHTML (widget), FALSE); | |
945 | |
946 imhtml = GTK_IMHTML (widget); | |
947 gtk_imhtml_draw_exposed (imhtml); | |
948 | |
949 return FALSE; | |
950 } | |
951 | |
952 static void | |
953 gtk_imhtml_redraw_all (GtkIMHtml *imhtml) | |
954 { | |
955 GList *b; | |
956 GtkIMHtmlBit *bit; | |
957 GtkAdjustment *vadj; | |
958 gfloat oldvalue; | |
959 gint oldy; | |
960 | |
961 vadj = GTK_LAYOUT (imhtml)->vadjustment; | |
962 oldvalue = vadj->value / vadj->upper; | |
963 oldy = imhtml->y; | |
964 | |
965 gtk_layout_freeze (GTK_LAYOUT (imhtml)); | |
966 | |
967 g_list_free (imhtml->line); | |
968 imhtml->line = NULL; | |
969 | |
970 while (imhtml->click) { | |
971 g_free (imhtml->click->data); | |
972 imhtml->click = g_list_remove (imhtml->click, imhtml->click->data); | |
973 } | |
974 | |
975 imhtml->x = 0; | |
976 imhtml->y = TOP_BORDER; | |
977 imhtml->llheight = 0; | |
978 imhtml->llascent = 0; | |
979 | |
980 if (GTK_LAYOUT (imhtml)->vadjustment->value < TOP_BORDER) | |
981 gdk_window_clear_area (GTK_LAYOUT (imhtml)->bin_window, 0, 0, | |
982 imhtml->xsize, | |
983 TOP_BORDER - GTK_LAYOUT (imhtml)->vadjustment->value); | |
984 | |
985 b = imhtml->bits; | |
986 while (b) { | |
987 bit = b->data; | |
988 b = g_list_next (b); | |
989 while (bit->chunks) { | |
990 struct line_info *li = bit->chunks->data; | |
991 if (li->text) | |
992 g_free (li->text); | |
993 bit->chunks = g_list_remove (bit->chunks, li); | |
994 g_free (li); | |
995 } | |
996 gtk_imhtml_draw_bit (imhtml, bit); | |
997 } | |
998 | |
999 GTK_LAYOUT (imhtml)->height = imhtml->y; | |
1000 GTK_LAYOUT (imhtml)->vadjustment->upper = imhtml->y; | |
1001 gtk_signal_emit_by_name (GTK_OBJECT (GTK_LAYOUT (imhtml)->vadjustment), "changed"); | |
1002 | |
1003 gtk_widget_set_usize (GTK_WIDGET (imhtml), -1, imhtml->y); | |
1004 gtk_adjustment_set_value (vadj, vadj->upper * oldvalue); | |
1005 | |
1006 if (GTK_LAYOUT (imhtml)->bin_window && (imhtml->y < oldy)) { | |
1007 GdkGC *gc; | |
1008 GdkColormap *cmap; | |
1009 | |
1010 gc = gdk_gc_new (GTK_LAYOUT (imhtml)->bin_window); | |
1011 cmap = gtk_widget_get_colormap (GTK_WIDGET (imhtml)); | |
1012 | |
1013 gdk_color_alloc (cmap, imhtml->default_bg_color); | |
1014 gdk_gc_set_foreground (gc, imhtml->default_bg_color); | |
1015 | |
1016 gdk_draw_rectangle (GTK_LAYOUT (imhtml)->bin_window, gc, TRUE, | |
1017 0, imhtml->y - GTK_LAYOUT (imhtml)->vadjustment->value, | |
1018 GTK_WIDGET (imhtml)->allocation.width, | |
1019 oldy - imhtml->y); | |
1020 | |
1021 gdk_gc_unref (gc); | |
1022 } | |
1023 | |
1024 gtk_layout_thaw (GTK_LAYOUT (imhtml)); | |
1025 gtk_imhtml_draw_focus (GTK_WIDGET (imhtml)); | |
1026 } | |
1027 | |
1028 static void | |
1029 gtk_imhtml_size_allocate (GtkWidget *widget, | |
1030 GtkAllocation *allocation) | |
1031 { | |
1032 GtkIMHtml *imhtml; | |
1033 GtkLayout *layout; | |
1034 gint new_xsize, new_ysize; | |
1035 | |
1036 g_return_if_fail (widget != NULL); | |
1037 g_return_if_fail (GTK_IS_IMHTML (widget)); | |
1038 g_return_if_fail (allocation != NULL); | |
1039 | |
1040 imhtml = GTK_IMHTML (widget); | |
1041 layout = GTK_LAYOUT (widget); | |
1042 | |
1043 widget->allocation = *allocation; | |
1044 | |
1045 new_xsize = MAX (1, (gint) allocation->width - | |
1046 (gint) (widget->style->xthickness + BORDER_SIZE) * 2); | |
1047 new_ysize = MAX (1, (gint) allocation->height - | |
1048 (gint) (widget->style->ythickness + BORDER_SIZE) * 2); | |
1049 | |
1050 if (GTK_WIDGET_REALIZED (widget)) { | |
1051 gint x = widget->style->xthickness + BORDER_SIZE; | |
1052 gint y = widget->style->ythickness + BORDER_SIZE; | |
1053 gdk_window_move_resize (widget->window, | |
1054 allocation->x, allocation->y, | |
1055 allocation->width, allocation->height); | |
1056 gdk_window_move_resize (layout->bin_window, | |
1057 x, y, new_xsize, new_ysize); | |
1058 } | |
1059 | |
1060 layout->hadjustment->page_size = new_xsize; | |
1061 layout->hadjustment->page_increment = new_xsize / 2; | |
1062 layout->hadjustment->lower = 0; | |
1063 layout->hadjustment->upper = imhtml->x; | |
1064 | |
1065 layout->vadjustment->page_size = new_ysize; | |
1066 layout->vadjustment->page_increment = new_ysize / 2; | |
1067 layout->vadjustment->lower = 0; | |
1068 layout->vadjustment->upper = imhtml->y; | |
1069 | |
1070 gtk_signal_emit_by_name (GTK_OBJECT (layout->hadjustment), "changed"); | |
1071 gtk_signal_emit_by_name (GTK_OBJECT (layout->vadjustment), "changed"); | |
1072 | |
1073 if (new_xsize == imhtml->xsize) { | |
1074 if ((GTK_LAYOUT (imhtml)->vadjustment->value > imhtml->y - new_ysize)) { | |
1075 if (imhtml->y > new_ysize) | |
1076 gtk_adjustment_set_value (GTK_LAYOUT (imhtml)->vadjustment, | |
1077 imhtml->y - new_ysize); | |
1078 else | |
1079 gtk_adjustment_set_value (GTK_LAYOUT (imhtml)->vadjustment, 0); | |
1080 } | |
1081 return; | |
1082 } | |
1083 | |
1084 imhtml->xsize = new_xsize; | |
1085 | |
1086 if (GTK_WIDGET_REALIZED (widget)) | |
1087 gtk_imhtml_redraw_all (imhtml); | |
1088 } | |
1089 | |
1090 static void | |
1091 gtk_imhtml_select_none (GtkIMHtml *imhtml) | |
1092 { | |
1093 GList *bits; | |
1094 GList *chunks; | |
1095 GtkIMHtmlBit *bit; | |
1096 struct line_info *chunk; | |
1097 | |
1098 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
1099 | |
1100 bits = imhtml->bits; | |
1101 while (bits) { | |
1102 bit = bits->data; | |
1103 chunks = bit->chunks; | |
1104 | |
1105 while (chunks) { | |
1106 chunk = chunks->data; | |
1107 | |
1108 if (chunk->selected) { | |
1109 chunk->selected = FALSE; | |
1110 chunk->sel_start = chunk->text; | |
1111 chunk->sel_end = NULL; | |
1112 if (DRAW_IMG (bit)) | |
1113 draw_img (imhtml, chunk); | |
1114 else if ((bit->type == TYPE_SEP) && (bit->chunks->data == chunk)) | |
1115 draw_line (imhtml, chunk); | |
1116 else if (chunk->width) | |
1117 draw_text (imhtml, chunk); | |
1118 } | |
1119 | |
1120 chunks = g_list_next (chunks); | |
1121 } | |
1122 | |
1123 bits = g_list_next (bits); | |
1124 } | |
1125 imhtml->sel_endchunk = NULL; | |
1126 } | |
1127 | |
1128 static gchar* | |
1129 get_position (GtkIMHtml *imhtml, | |
1130 struct line_info *chunk, | |
1131 gint x, | |
1132 gboolean smileys) | |
1133 { | |
1134 gint width = x - chunk->x; | |
1135 gchar *text; | |
1136 gchar *pos; | |
1137 guint total = 0; | |
1138 | |
1139 switch (chunk->bit->type) { | |
1140 case TYPE_TEXT: | |
1141 case TYPE_COMMENT: | |
1142 text = chunk->text; | |
1143 break; | |
1144 case TYPE_SMILEY: | |
1145 if (smileys) | |
1146 return NULL; | |
1147 else | |
1148 text = chunk->text; | |
1149 break; | |
1150 default: | |
1151 return NULL; | |
1152 break; | |
1153 } | |
1154 | |
1155 if (width <= 0) | |
1156 return text; | |
1157 | |
1158 for (pos = text; *pos != '\0'; pos++) { | |
1159 gint char_width = text_width (imhtml->context, chunk->bit->font, pos, 1); | |
1160 if ((width > total) && (width <= total + char_width)) { | |
1161 if (width < total + (char_width / 2)) | |
1162 return pos; | |
1163 else | |
1164 return ++pos; | |
1165 } | |
1166 total += char_width; | |
1167 } | |
1168 | |
1169 return pos; | |
1170 } | |
1171 | |
1172 static GString* | |
1173 append_to_sel (GString *string, | |
1174 struct line_info *chunk, | |
1175 gboolean smileys) | |
1176 { | |
1177 GString *new_string; | |
1178 gchar *buf; | |
1179 gchar *start; | |
1180 gint length; | |
1181 | |
1182 switch (chunk->bit->type) { | |
1183 case TYPE_TEXT: | |
1184 case TYPE_COMMENT: | |
1185 start = (chunk->sel_start == NULL) ? chunk->text : chunk->sel_start; | |
1186 length = (chunk->sel_end == NULL) ? strlen (start) : chunk->sel_end - start; | |
1187 if (length <= 0) | |
1188 return string; | |
1189 buf = g_strndup (start, length); | |
1190 break; | |
1191 case TYPE_SMILEY: | |
1192 if (smileys) { | |
1193 start = (chunk->sel_start == NULL) ? chunk->bit->text : chunk->sel_start; | |
1194 length = (chunk->sel_end == NULL) ? strlen (start) : chunk->sel_end - start; | |
1195 if (length <= 0) | |
1196 return string; | |
1197 buf = g_strndup (start, length); | |
1198 } else { | |
1199 start = (chunk->sel_start == NULL) ? chunk->text : chunk->sel_start; | |
1200 length = (chunk->sel_end == NULL) ? strlen (start) : chunk->sel_end - start; | |
1201 if (length <= 0) | |
1202 return string; | |
1203 buf = g_strndup (start, length); | |
1204 } | |
1205 break; | |
1206 case TYPE_BR: | |
1207 buf = g_strdup ("\n"); | |
1208 break; | |
1209 default: | |
1210 return string; | |
1211 break; | |
1212 } | |
1213 | |
1214 new_string = g_string_append (string, buf); | |
1215 g_free (buf); | |
1216 | |
1217 return new_string; | |
1218 } | |
1219 | |
1220 static void | |
1221 chunk_select_words (struct line_info *chunk) | |
1222 { | |
1223 char *start, *end; | |
1224 | |
1225 start = chunk->sel_start; | |
1226 end = chunk->sel_end; | |
1227 | |
1228 if (start != chunk->text) { | |
1229 if (isalnum(*start) || *start == '\'') | |
1230 while (start > chunk->text && | |
1231 (isalnum(*(start-1)) || *(start-1) == '\'')) | |
1232 start--; | |
1233 else if (isspace(*start)) | |
1234 while (start > chunk->text && isspace(*(start-1))) | |
1235 start--; | |
1236 else if (ispunct(*start)) | |
1237 while (start > chunk->text && ispunct(*(start-1))) | |
1238 start--; | |
1239 } | |
1240 chunk->sel_start = start; | |
1241 | |
1242 if (end != NULL) { | |
1243 if (isalnum(*end) || *end == '\'') | |
1244 while (*end != '\0' && | |
1245 (isalnum(*end) || *end == '\'')) | |
1246 end++; | |
1247 else if (isspace(*end)) | |
1248 while (*end != '\0' && isspace(*end)) | |
1249 end++; | |
1250 else if (ispunct(*end)) | |
1251 while (*end != '\0' && ispunct(*end)) | |
1252 end++; | |
1253 } | |
1254 chunk->sel_end = end; | |
1255 } | |
1256 | |
1257 #define COORDS_IN_CHUNK(xx, yy) (((xx) < chunk->x + chunk->width) && \ | |
1258 ((yy) < chunk->y + chunk->height)) | |
1259 | |
1260 static void | |
1261 gtk_imhtml_select_bits (GtkIMHtml *imhtml) | |
1262 { | |
1263 GList *bits; | |
1264 GList *chunks; | |
1265 GtkIMHtmlBit *bit; | |
1266 struct line_info *chunk; | |
1267 | |
1268 guint startx = imhtml->sel_startx, | |
1269 starty = imhtml->sel_starty, | |
1270 endx = imhtml->sel_endx, | |
1271 endy = imhtml->sel_endy; | |
1272 gchar *new_pos; | |
1273 gint selection = 0; | |
1274 guint mode = imhtml->sel_mode; | |
1275 gboolean smileys = imhtml->smileys; | |
1276 gboolean redraw = FALSE; | |
1277 gboolean got_start = FALSE; | |
1278 gboolean got_end = FALSE; | |
1279 | |
1280 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
1281 | |
1282 if (!imhtml->selection) | |
1283 return; | |
1284 | |
1285 if (imhtml->selected_text) { | |
1286 g_string_free (imhtml->selected_text, TRUE); | |
1287 imhtml->selected_text = g_string_new (""); | |
1288 } | |
1289 | |
1290 if (mode == 2) | |
1291 startx = endx = 0; | |
1292 | |
1293 bits = imhtml->bits; | |
1294 while (bits) { | |
1295 bit = bits->data; | |
1296 chunks = bit->chunks; | |
1297 | |
1298 while (chunks) { | |
1299 chunk = chunks->data; | |
1300 | |
1301 switch (selection) { | |
1302 case 0: | |
1303 if (COORDS_IN_CHUNK (startx, starty)) { | |
1304 new_pos = get_position (imhtml, chunk, startx, smileys); | |
1305 if (!chunk->selected || | |
1306 (chunk->sel_start != new_pos) || | |
1307 (chunk->sel_end != NULL)) | |
1308 redraw = TRUE; | |
1309 chunk->selected = TRUE; | |
1310 chunk->sel_start = new_pos; | |
1311 chunk->sel_end = NULL; | |
1312 selection++; | |
1313 got_start = TRUE; | |
1314 if (mode == 2) | |
1315 endy += chunk->height; | |
1316 if (mode == 1) | |
1317 chunk_select_words (chunk); | |
1318 } | |
1319 | |
1320 if (COORDS_IN_CHUNK (endx, endy)) { | |
1321 if (got_start) { | |
1322 new_pos = get_position (imhtml, chunk, endx, smileys); | |
1323 if (chunk->sel_end != new_pos) | |
1324 redraw = TRUE; | |
1325 if (chunk->sel_start > new_pos) { | |
1326 chunk->sel_end = chunk->sel_start; | |
1327 chunk->sel_start = new_pos; | |
1328 } else | |
1329 chunk->sel_end = new_pos; | |
1330 selection = 2; | |
1331 imhtml->sel_endchunk = chunk; | |
1332 got_end = TRUE; | |
1333 if (mode == 1) | |
1334 chunk_select_words (chunk); | |
1335 } else { | |
1336 new_pos = get_position (imhtml, chunk, endx, smileys); | |
1337 if ( !chunk->selected || | |
1338 (chunk->sel_start != new_pos) || | |
1339 (chunk->sel_end != NULL)) | |
1340 redraw = TRUE; | |
1341 chunk->selected = TRUE; | |
1342 chunk->sel_start = new_pos; | |
1343 chunk->sel_end = NULL; | |
1344 selection++; | |
1345 imhtml->sel_endchunk = chunk; | |
1346 got_end = TRUE; | |
1347 if (mode == 2) | |
1348 starty += chunk->height; | |
1349 if (mode == 1) | |
1350 chunk_select_words (chunk); | |
1351 } | |
1352 } else if (!COORDS_IN_CHUNK (startx, starty) && !got_start) { | |
1353 if (chunk->selected) | |
1354 redraw = TRUE; | |
1355 chunk->selected = FALSE; | |
1356 chunk->sel_start = chunk->text; | |
1357 chunk->sel_end = NULL; | |
1358 } | |
1359 | |
1360 break; | |
1361 case 1: | |
1362 if (!got_start && COORDS_IN_CHUNK (startx, starty)) { | |
1363 new_pos = get_position (imhtml, chunk, startx, smileys); | |
1364 if ( !chunk->selected || | |
1365 (chunk->sel_end != new_pos) || | |
1366 (chunk->sel_start != chunk->text)) | |
1367 redraw = TRUE; | |
1368 chunk->selected = TRUE; | |
1369 chunk->sel_start = chunk->text; | |
1370 chunk->sel_end = new_pos; | |
1371 selection++; | |
1372 got_start = TRUE; | |
1373 if (mode == 1) | |
1374 chunk_select_words (chunk); | |
1375 } else if (!got_end && COORDS_IN_CHUNK (endx, endy)) { | |
1376 new_pos = get_position (imhtml, chunk, endx, smileys); | |
1377 if ( !chunk->selected || | |
1378 (chunk->sel_end != new_pos) || | |
1379 (chunk->sel_start != chunk->text)) | |
1380 redraw = TRUE; | |
1381 chunk->selected = TRUE; | |
1382 chunk->sel_start = chunk->text; | |
1383 chunk->sel_end = new_pos; | |
1384 selection++; | |
1385 imhtml->sel_endchunk = chunk; | |
1386 got_end = TRUE; | |
1387 if (mode == 1) | |
1388 chunk_select_words (chunk); | |
1389 } else { | |
1390 if ( !chunk->selected || | |
1391 (chunk->sel_end != NULL) || | |
1392 (chunk->sel_start != chunk->text)) | |
1393 redraw = TRUE; | |
1394 chunk->selected = TRUE; | |
1395 chunk->sel_start = chunk->text; | |
1396 chunk->sel_end = NULL; | |
1397 } | |
1398 | |
1399 break; | |
1400 case 2: | |
1401 if (chunk->selected) | |
1402 redraw = TRUE; | |
1403 chunk->selected = FALSE; | |
1404 chunk->sel_start = chunk->text; | |
1405 chunk->sel_end = NULL; | |
1406 break; | |
1407 } | |
1408 | |
1409 if (chunk->selected == TRUE) | |
1410 imhtml->selected_text = append_to_sel (imhtml->selected_text, | |
1411 chunk, smileys); | |
1412 | |
1413 if (redraw) { | |
1414 if (DRAW_IMG (bit)) | |
1415 draw_img (imhtml, chunk); | |
1416 else if ((bit->type == TYPE_SEP) && (bit->chunks->data == chunk)) | |
1417 draw_line (imhtml, chunk); | |
1418 else if (chunk->width) | |
1419 draw_text (imhtml, chunk); | |
1420 redraw = FALSE; | |
1421 } | |
1422 | |
1423 chunks = g_list_next (chunks); | |
1424 } | |
1425 | |
1426 bits = g_list_next (bits); | |
1427 } | |
1428 } | |
1429 | |
1430 static void | |
1431 gtk_imhtml_select_in_chunk (GtkIMHtml *imhtml, | |
1432 struct line_info *chunk) | |
1433 { | |
1434 GtkIMHtmlBit *bit = chunk->bit; | |
1435 gchar *new_pos; | |
1436 guint endx = imhtml->sel_endx; | |
1437 guint startx = imhtml->sel_startx; | |
1438 guint starty = imhtml->sel_starty; | |
1439 gboolean smileys = imhtml->smileys; | |
1440 gboolean redraw = FALSE; | |
1441 | |
1442 new_pos = get_position (imhtml, chunk, endx, smileys); | |
1443 if ((starty < chunk->y) || | |
1444 ((starty < chunk->y + chunk->height) && (startx < endx))) { | |
1445 if (chunk->sel_end != new_pos) | |
1446 redraw = TRUE; | |
1447 chunk->sel_end = new_pos; | |
1448 } else { | |
1449 if (chunk->sel_start != new_pos) | |
1450 redraw = TRUE; | |
1451 chunk->sel_start = new_pos; | |
1452 } | |
1453 | |
1454 if (redraw) { | |
1455 if (DRAW_IMG (bit)) | |
1456 draw_img (imhtml, chunk); | |
1457 else if ((bit->type == TYPE_SEP) && | |
1458 (bit->chunks->data == chunk)) | |
1459 draw_line (imhtml, chunk); | |
1460 else if (chunk->width) | |
1461 draw_text (imhtml, chunk); | |
1462 } | |
1463 } | |
1464 | |
1465 static gint | |
1466 scroll_timeout (GtkIMHtml *imhtml) | |
1467 { | |
1468 GdkEventMotion event; | |
1469 gint x, y; | |
1470 GdkModifierType mask; | |
1471 | |
1472 imhtml->scroll_timer = 0; | |
1473 | |
1474 gdk_window_get_pointer (GTK_LAYOUT (imhtml)->bin_window, &x, &y, &mask); | |
1475 | |
1476 if (mask & GDK_BUTTON1_MASK) { | |
1477 event.is_hint = 0; | |
1478 event.x = x; | |
1479 event.y = y; | |
1480 event.state = mask; | |
1481 | |
1482 gtk_imhtml_motion_notify_event (GTK_WIDGET (imhtml), &event); | |
1483 } | |
1484 | |
1485 return FALSE; | |
1486 } | |
1487 | |
1488 static gint | |
1489 gtk_imhtml_tip_paint (GtkIMHtml *imhtml) | |
1490 { | |
1491 int x,y; | |
1492 GtkStyle *style; | |
1493 PangoLayout *layout; | |
1494 if (imhtml->tip_bit->url) | |
1495 layout = gtk_widget_create_pango_layout (imhtml->tip_window, imhtml->tip_bit->url); | |
1496 else if (imhtml->tip_bit->img) | |
1497 layout = gtk_widget_create_pango_layout (imhtml->tip_window, imhtml->tip_bit->img->filename); | |
1498 else | |
1499 return FALSE; | |
1500 | |
1501 style = imhtml->tip_window->style; | |
1502 pango_layout_get_size (layout, &x, &y); | |
1503 | |
1504 if (!imhtml->tip_bit) | |
1505 return FALSE; | |
1506 | |
1507 gtk_paint_flat_box (style, imhtml->tip_window->window, GTK_STATE_NORMAL, GTK_SHADOW_OUT, | |
1508 NULL, imhtml->tip_window, "tooltip", 0, 0, -1, -1); | |
1509 | |
1510 gtk_paint_layout (style, imhtml->tip_window->window, GTK_STATE_NORMAL, TRUE, | |
1511 NULL, imhtml->tip_window, "tooltip", 4, 4, layout); | |
1512 | |
1513 g_object_unref (layout); | |
1514 return FALSE; | |
1515 } | |
1516 | |
1517 static gint | |
1518 gtk_imhtml_tip (gpointer data) | |
1519 { | |
1520 GtkIMHtml *imhtml = data; | |
1521 GtkWidget *widget = GTK_WIDGET (imhtml); | |
1522 GtkStyle *style; | |
1523 PangoLayout *layout; | |
1524 gint x, y, w, h, scr_w, scr_h; | |
1525 | |
1526 if (!imhtml->tip_bit || !GTK_WIDGET_DRAWABLE (widget)) { | |
1527 imhtml->tip_timer = 0; | |
1528 return FALSE; | |
1529 } | |
1530 | |
1531 if (imhtml->tip_window) | |
1532 gtk_widget_destroy (imhtml->tip_window); | |
1533 | |
1534 imhtml->tip_window = gtk_window_new (GTK_WINDOW_POPUP); | |
1535 gtk_widget_set_app_paintable (imhtml->tip_window, TRUE); | |
1536 gtk_window_set_policy (GTK_WINDOW (imhtml->tip_window), FALSE, FALSE, TRUE); | |
1537 gtk_widget_set_name (imhtml->tip_window, "gtk-tooltips"); | |
1538 gtk_signal_connect_object (GTK_OBJECT (imhtml->tip_window), "expose_event", | |
1539 GTK_SIGNAL_FUNC (gtk_imhtml_tip_paint), GTK_OBJECT (imhtml)); | |
1540 | |
1541 gtk_widget_ensure_style (imhtml->tip_window); | |
1542 style = imhtml->tip_window->style; | |
1543 layout = gtk_widget_create_pango_layout(imhtml->tip_window, | |
1544 imhtml->tip_bit->url ? imhtml->tip_bit->url : imhtml->tip_bit->img->filename); | |
1545 | |
1546 scr_w = gdk_screen_width (); | |
1547 scr_h = gdk_screen_height (); | |
1548 | |
1549 pango_layout_get_size(layout, &w, &h); | |
1550 | |
1551 w = PANGO_PIXELS(w) + 8; | |
1552 h = PANGO_PIXELS(h) + 8; | |
1553 | |
1554 gdk_window_get_pointer (NULL, &x, &y, NULL); | |
1555 if (GTK_WIDGET_NO_WINDOW (widget)) | |
1556 y += widget->allocation.y; | |
1557 | |
1558 x -= ((w >> 1) + 4); | |
1559 | |
1560 if ((x + w) > scr_w) | |
1561 x -= (x + w) - scr_w; | |
1562 else if (x < 0) | |
1563 x = 0; | |
1564 | |
1565 if ((y + h + + 4) > scr_h) | |
1566 y = y - h; | |
1567 else | |
1568 y = y + h - 4; | |
1569 | |
1570 gtk_widget_set_usize (imhtml->tip_window, w, h); | |
1571 gtk_widget_set_uposition (imhtml->tip_window, x, y); | |
1572 gtk_widget_show (imhtml->tip_window); | |
1573 | |
1574 imhtml->tip_timer = 0; | |
1575 g_object_unref(layout); | |
1576 | |
1577 return FALSE; | |
1578 } | |
1579 | |
1580 static gint | |
1581 gtk_imhtml_motion_notify_event (GtkWidget *widget, | |
1582 GdkEventMotion *event) | |
1583 { | |
1584 gint x, y; | |
1585 GdkModifierType state; | |
1586 GtkIMHtml *imhtml = GTK_IMHTML (widget); | |
1587 GtkAdjustment *vadj = GTK_LAYOUT (widget)->vadjustment; | |
1588 GtkAdjustment *hadj = GTK_LAYOUT (widget)->hadjustment; | |
1589 | |
1590 if (event->is_hint) | |
1591 gdk_window_get_pointer (event->window, &x, &y, &state); | |
1592 else { | |
1593 x = event->x + hadj->value; | |
1594 y = event->y + vadj->value; | |
1595 state = event->state; | |
1596 } | |
1597 | |
1598 if (state & GDK_BUTTON1_MASK) { | |
1599 gint diff; | |
1600 gint height = vadj->page_size; | |
1601 gint yy = y - vadj->value; | |
1602 | |
1603 if (((yy < 0) || (yy > height)) && | |
1604 (imhtml->scroll_timer == 0) && | |
1605 (vadj->upper > vadj->page_size)) { | |
1606 imhtml->scroll_timer = gtk_timeout_add (100, | |
1607 (GtkFunction) scroll_timeout, | |
1608 imhtml); | |
1609 diff = (yy < 0) ? (yy / 2) : ((yy - height) / 2); | |
1610 gtk_adjustment_set_value (vadj, | |
1611 MIN (vadj->value + diff, vadj->upper - height)); | |
1612 } | |
1613 | |
1614 if (imhtml->selection) { | |
1615 struct line_info *chunk = imhtml->sel_endchunk; | |
1616 imhtml->sel_endx = MAX (x, 0); | |
1617 imhtml->sel_endy = MAX (y, 0); | |
1618 if ((chunk == NULL) || | |
1619 (x < chunk->x) || | |
1620 (x > chunk->x + chunk->width) || | |
1621 (y < chunk->y) || | |
1622 (y > chunk->y + chunk->height) || | |
1623 (imhtml->sel_mode > 0)) | |
1624 gtk_imhtml_select_bits (imhtml); | |
1625 else | |
1626 gtk_imhtml_select_in_chunk (imhtml, chunk); | |
1627 } | |
1628 } else { | |
1629 GList *click = imhtml->click; | |
1630 struct clickable *uw; | |
1631 | |
1632 while (click) { | |
1633 uw = (struct clickable *) click->data; | |
1634 if ((uw->bit->url) && (x > uw->x) && (x < uw->x + uw->width) && | |
1635 (y > uw->y) && (y < uw->y + uw->height) && | |
1636 (uw->bit->url || uw->bit->img)) { | |
1637 if (imhtml->tip_bit != uw->bit) { | |
1638 imhtml->tip_bit = uw->bit; | |
1639 if (imhtml->tip_timer != 0) | |
1640 gtk_timeout_remove (imhtml->tip_timer); | |
1641 if (imhtml->tip_window) { | |
1642 gtk_widget_destroy (imhtml->tip_window); | |
1643 imhtml->tip_window = NULL; | |
1644 } | |
1645 imhtml->tip_timer = gtk_timeout_add (TOOLTIP_TIMEOUT, | |
1646 gtk_imhtml_tip, | |
1647 imhtml); | |
1648 } | |
1649 if (uw->bit->url) | |
1650 gdk_window_set_cursor (GTK_LAYOUT (imhtml)->bin_window, | |
1651 imhtml->hand_cursor); | |
1652 return TRUE; | |
1653 } | |
1654 click = g_list_next (click); | |
1655 } | |
1656 } | |
1657 | |
1658 if (imhtml->tip_timer) { | |
1659 gtk_timeout_remove (imhtml->tip_timer); | |
1660 imhtml->tip_timer = 0; | |
1661 } | |
1662 if (imhtml->tip_window) { | |
1663 gtk_widget_destroy (imhtml->tip_window); | |
1664 imhtml->tip_window = NULL; | |
1665 } | |
1666 imhtml->tip_bit = NULL; | |
1667 | |
1668 gdk_window_set_cursor (GTK_LAYOUT (imhtml)->bin_window, imhtml->arrow_cursor); | |
1669 | |
1670 return TRUE; | |
1671 } | |
1672 | |
1673 static gint | |
1674 gtk_imhtml_leave_notify_event (GtkWidget *widget, | |
1675 GdkEventCrossing *event) | |
1676 { | |
1677 GtkIMHtml *imhtml = GTK_IMHTML (widget); | |
1678 | |
1679 if (imhtml->tip_timer) { | |
1680 gtk_timeout_remove (imhtml->tip_timer); | |
1681 imhtml->tip_timer = 0; | |
1682 } | |
1683 if (imhtml->tip_window) { | |
1684 gtk_widget_destroy (imhtml->tip_window); | |
1685 imhtml->tip_window = NULL; | |
1686 } | |
1687 imhtml->tip_bit = NULL; | |
1688 return TRUE; | |
1689 } | |
1690 struct imgsv { | |
1691 GtkWidget *savedialog; | |
1692 struct im_image *img; | |
1693 }; | |
1694 | |
1695 static void | |
1696 save_img (GtkObject *object, | |
1697 gpointer data) | |
1698 { | |
1699 struct imgsv *is = data; | |
1700 struct im_image *img = is->img; | |
1701 const gchar *filename; | |
1702 FILE *f; | |
1703 filename = gtk_file_selection_get_filename(GTK_FILE_SELECTION(is->savedialog)); | |
1704 debug_printf("Saving %s\n", filename); | |
1705 if (! (f=fopen(filename, "w"))) { | |
1706 /* There should be some sort of dialog */ | |
1707 debug_printf("Could not open file for writing.\n"); | |
1708 gtk_widget_destroy(is->savedialog); | |
1709 g_free(is); | |
1710 return; | |
1711 } | |
1712 | |
1713 fwrite(img->data, 1, img->len, f); | |
1714 fclose(f); | |
1715 gtk_widget_destroy(is->savedialog); | |
1716 g_free(is); | |
1717 } | |
1718 | |
1719 static void | |
1720 save_img_dialog (GtkObject *object, | |
1721 gpointer data) | |
1722 { | |
1723 struct imgsv *is = g_malloc(sizeof(struct imgsv)); | |
1724 struct im_image *img = data; | |
1725 GtkWidget *savedialog = gtk_file_selection_new ("Gaim - Save Image"); | |
1726 gtk_file_selection_set_filename (GTK_FILE_SELECTION(savedialog), img->filename); | |
1727 gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION(savedialog)->cancel_button), | |
1728 "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy), | |
1729 (gpointer) savedialog); | |
1730 | |
1731 is->img = img; | |
1732 is->savedialog = savedialog; | |
1733 | |
1734 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION(savedialog)->ok_button), | |
1735 "clicked", GTK_SIGNAL_FUNC (save_img), is); | |
1736 gtk_widget_show (savedialog); | |
1737 | |
1738 | |
1739 } | |
1740 | |
1741 | |
1742 static void | |
1743 menu_open_url (GtkObject *object, | |
1744 gpointer data) | |
1745 { | |
1746 struct clickable *uw = data; | |
1747 | |
1748 gtk_signal_emit (GTK_OBJECT (uw->imhtml), signals [URL_CLICKED], uw->bit->url); | |
1749 } | |
1750 | |
1751 static void | |
1752 menu_copy_link (GtkObject *object, | |
1753 gpointer data) | |
1754 { | |
1755 struct clickable *uw = data; | |
1756 GtkIMHtml *imhtml = uw->imhtml; | |
1757 | |
1758 if (imhtml->selected_text) | |
1759 g_string_free (imhtml->selected_text, TRUE); | |
1760 | |
1761 gtk_imhtml_select_none (uw->imhtml); | |
1762 | |
1763 imhtml->selection = TRUE; | |
1764 imhtml->selected_text = g_string_new (uw->bit->url); | |
1765 | |
1766 gtk_selection_owner_set (GTK_WIDGET (imhtml), GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME); | |
1767 } | |
1768 | |
1769 static gint | |
1770 gtk_imhtml_button_press_event (GtkWidget *widget, | |
1771 GdkEventButton *event) | |
1772 { | |
1773 GtkIMHtml *imhtml = GTK_IMHTML (widget); | |
1774 GtkAdjustment *vadj = GTK_LAYOUT (widget)->vadjustment; | |
1775 GtkAdjustment *hadj = GTK_LAYOUT (widget)->hadjustment; | |
1776 gint x, y; | |
1777 | |
1778 x = event->x + hadj->value; | |
1779 y = event->y + vadj->value; | |
1780 | |
1781 if (event->button == 1) { | |
1782 imhtml->sel_startx = imhtml->sel_endx = x; | |
1783 imhtml->sel_starty = imhtml->sel_endy = y; | |
1784 imhtml->selection = TRUE; | |
1785 if (event->type == GDK_BUTTON_PRESS) { | |
1786 imhtml->sel_mode = 0; /* select by letter */ | |
1787 gtk_imhtml_select_none (imhtml); | |
1788 } else if (event->type == GDK_2BUTTON_PRESS) { | |
1789 imhtml->sel_mode = 1; /* select by word */ | |
1790 gtk_imhtml_select_none (imhtml); | |
1791 } else if (event->type == GDK_3BUTTON_PRESS) { | |
1792 imhtml->sel_mode = 2; /* select by line */ | |
1793 gtk_imhtml_select_bits (imhtml); | |
1794 } | |
1795 } | |
1796 | |
1797 if (event->button == 3) { | |
1798 GList *click = imhtml->click; | |
1799 struct clickable *uw; | |
1800 | |
1801 while (click) { | |
1802 uw = click->data; | |
1803 if ((x > uw->x) && (x < uw->x + uw->width) && | |
1804 (y > uw->y) && (y < uw->y + uw->height)) { | |
1805 static GtkWidget *menu = NULL; | |
1806 GtkWidget *button; | |
1807 | |
1808 /* | |
1809 * If a menu already exists, destroy it before creating a new one, | |
1810 * thus freeing-up the memory it occupied. | |
1811 */ | |
1812 if(menu) | |
1813 gtk_widget_destroy(menu); | |
1814 | |
1815 menu = gtk_menu_new(); | |
1816 | |
1817 if (uw->bit->url) { | |
1818 button = gtk_menu_item_new_with_label ("Open URL"); | |
1819 gtk_signal_connect (GTK_OBJECT (button), "activate", | |
1820 GTK_SIGNAL_FUNC (menu_open_url), uw); | |
1821 gtk_menu_append (GTK_MENU (menu), button); | |
1822 gtk_widget_show (button); | |
1823 | |
1824 button = gtk_menu_item_new_with_label ("Copy Link Location"); | |
1825 gtk_signal_connect (GTK_OBJECT (button), "activate", | |
1826 GTK_SIGNAL_FUNC (menu_copy_link), uw); | |
1827 gtk_menu_append (GTK_MENU (menu), button); | |
1828 gtk_widget_show (button); | |
1829 } | |
1830 | |
1831 if (uw->bit->img) { | |
1832 button = gtk_menu_item_new_with_label ("Save Image"); | |
1833 gtk_signal_connect (GTK_OBJECT (button), "activate", | |
1834 GTK_SIGNAL_FUNC (save_img_dialog), uw->bit->img); | |
1835 gtk_menu_append (GTK_MENU (menu), button); | |
1836 gtk_widget_show (button); | |
1837 } | |
1838 | |
1839 gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 3, event->time); | |
1840 | |
1841 if (imhtml->tip_timer) { | |
1842 gtk_timeout_remove (imhtml->tip_timer); | |
1843 imhtml->tip_timer = 0; | |
1844 } | |
1845 if (imhtml->tip_window) { | |
1846 gtk_widget_destroy (imhtml->tip_window); | |
1847 imhtml->tip_window = NULL; | |
1848 } | |
1849 imhtml->tip_bit = NULL; | |
1850 | |
1851 return TRUE; | |
1852 } | |
1853 click = g_list_next (click); | |
1854 } | |
1855 } | |
1856 | |
1857 return TRUE; | |
1858 } | |
1859 | |
1860 static gint | |
1861 gtk_imhtml_button_release_event (GtkWidget *widget, | |
1862 GdkEventButton *event) | |
1863 { | |
1864 GtkIMHtml *imhtml = GTK_IMHTML (widget); | |
1865 GtkAdjustment *vadj = GTK_LAYOUT (widget)->vadjustment; | |
1866 GtkAdjustment *hadj = GTK_LAYOUT (widget)->hadjustment; | |
1867 gint x, y; | |
1868 | |
1869 x = event->x + hadj->value; | |
1870 y = event->y + vadj->value; | |
1871 | |
1872 if ((event->button == 1) && imhtml->selection) { | |
1873 if ((x == imhtml->sel_startx) && (y == imhtml->sel_starty) && | |
1874 (imhtml->sel_mode == 0)) { | |
1875 imhtml->sel_startx = imhtml->sel_starty = 0; | |
1876 imhtml->selection = FALSE; | |
1877 gtk_imhtml_select_none (imhtml); | |
1878 } else { | |
1879 imhtml->sel_endx = MAX (x, 0); | |
1880 imhtml->sel_endy = MAX (y, 0); | |
1881 gtk_imhtml_select_bits (imhtml); | |
1882 } | |
1883 | |
1884 gtk_selection_owner_set (widget, GDK_SELECTION_PRIMARY, event->time); | |
1885 } | |
1886 | |
1887 if ((event->button == 1) && (imhtml->sel_startx == 0)) { | |
1888 GList *click = imhtml->click; | |
1889 struct clickable *uw; | |
1890 | |
1891 while (click) { | |
1892 uw = (struct clickable *) click->data; | |
1893 if ((x > uw->x) && (x < uw->x + uw->width) && | |
1894 (y > uw->y) && (y < uw->y + uw->height)) { | |
1895 gtk_signal_emit (GTK_OBJECT (imhtml), signals [URL_CLICKED], | |
1896 uw->bit->url); | |
1897 return TRUE; | |
1898 } | |
1899 click = g_list_next (click); | |
1900 } | |
1901 } | |
1902 | |
1903 return TRUE; | |
1904 } | |
1905 | |
1906 static void | |
1907 gtk_imhtml_selection_get (GtkWidget *widget, | |
1908 GtkSelectionData *sel_data, | |
1909 guint sel_info, | |
1910 guint32 time) | |
1911 { | |
1912 GtkIMHtml *imhtml; | |
1913 gchar *string; | |
1914 gint length; | |
1915 | |
1916 g_return_if_fail (widget != NULL); | |
1917 g_return_if_fail (GTK_IS_IMHTML (widget)); | |
1918 g_return_if_fail (sel_data->selection == GDK_SELECTION_PRIMARY); | |
1919 | |
1920 imhtml = GTK_IMHTML (widget); | |
1921 | |
1922 g_return_if_fail (imhtml->selected_text != NULL); | |
1923 g_return_if_fail (imhtml->selected_text->str != NULL); | |
1924 | |
1925 if (imhtml->selected_text->len <= 0) | |
1926 return; | |
1927 | |
1928 string = g_strdup (imhtml->selected_text->str); | |
1929 length = strlen (string); | |
1930 | |
1931 if (sel_info == TARGET_STRING) { | |
1932 gtk_selection_data_set (sel_data, | |
1933 GDK_SELECTION_TYPE_STRING, | |
1934 8 * sizeof (gchar), | |
1935 (guchar *) string, | |
1936 length); | |
1937 } else if ((sel_info == TARGET_TEXT) || (sel_info == TARGET_COMPOUND_TEXT)) { | |
1938 guchar *text; | |
1939 GdkAtom encoding; | |
1940 gint format; | |
1941 gint new_length; | |
1942 | |
1943 gdk_string_to_compound_text (string, &encoding, &format, &text, &new_length); | |
1944 gtk_selection_data_set (sel_data, encoding, format, text, new_length); | |
1945 gdk_free_compound_text (text); | |
1946 } | |
1947 | |
1948 g_free (string); | |
1949 } | |
1950 | |
1951 static gint | |
1952 gtk_imhtml_selection_clear_event (GtkWidget *widget, | |
1953 GdkEventSelection *event) | |
1954 { | |
1955 GtkIMHtml *imhtml; | |
1956 | |
1957 g_return_val_if_fail (widget != NULL, FALSE); | |
1958 g_return_val_if_fail (GTK_IS_IMHTML (widget), FALSE); | |
1959 g_return_val_if_fail (event != NULL, FALSE); | |
1960 g_return_val_if_fail (event->selection == GDK_SELECTION_PRIMARY, TRUE); | |
1961 | |
1962 if (!gtk_selection_clear (widget, event)) | |
1963 return FALSE; | |
1964 | |
1965 imhtml = GTK_IMHTML (widget); | |
1966 | |
1967 gtk_imhtml_select_none (imhtml); | |
1968 | |
1969 return TRUE; | |
1970 } | |
1971 | |
1972 static void | |
1973 gtk_imhtml_adjustment_changed (GtkAdjustment *adjustment, | |
1974 GtkIMHtml *imhtml) | |
1975 { | |
1976 GtkLayout *layout = GTK_LAYOUT (imhtml); | |
1977 | |
1978 if (!GTK_WIDGET_MAPPED (imhtml) || !GTK_WIDGET_REALIZED (imhtml)) | |
1979 return; | |
1980 | |
1981 if (layout->freeze_count) | |
1982 return; | |
1983 | |
1984 if (layout->vadjustment->value < TOP_BORDER) | |
1985 gdk_window_clear_area (layout->bin_window, 0, 0, | |
1986 imhtml->xsize, TOP_BORDER - layout->vadjustment->value); | |
1987 | |
1988 gtk_imhtml_draw_exposed (imhtml); | |
1989 } | |
1990 | |
1991 static void | |
1992 gtk_imhtml_set_scroll_adjustments (GtkLayout *layout, | |
1993 GtkAdjustment *hadj, | |
1994 GtkAdjustment *vadj) | |
1995 { | |
1996 gboolean need_adjust = FALSE; | |
1997 | |
1998 g_return_if_fail (layout != NULL); | |
1999 g_return_if_fail (GTK_IS_IMHTML (layout)); | |
2000 | |
2001 if (hadj) | |
2002 g_return_if_fail (GTK_IS_ADJUSTMENT (hadj)); | |
2003 else | |
2004 hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0)); | |
2005 if (vadj) | |
2006 g_return_if_fail (GTK_IS_ADJUSTMENT (vadj)); | |
2007 else | |
2008 vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0)); | |
2009 | |
2010 if (layout->hadjustment && (layout->hadjustment != hadj)) { | |
2011 gtk_signal_disconnect_by_data (GTK_OBJECT (layout->hadjustment), layout); | |
2012 gtk_object_unref (GTK_OBJECT (layout->hadjustment)); | |
2013 } | |
2014 | |
2015 if (layout->vadjustment && (layout->vadjustment != vadj)) { | |
2016 gtk_signal_disconnect_by_data (GTK_OBJECT (layout->vadjustment), layout); | |
2017 gtk_object_unref (GTK_OBJECT (layout->vadjustment)); | |
2018 } | |
2019 | |
2020 if (layout->hadjustment != hadj) { | |
2021 layout->hadjustment = hadj; | |
2022 gtk_object_ref (GTK_OBJECT (layout->hadjustment)); | |
2023 gtk_object_sink (GTK_OBJECT (layout->hadjustment)); | |
2024 | |
2025 gtk_signal_connect (GTK_OBJECT (layout->hadjustment), "value_changed", | |
2026 (GtkSignalFunc) gtk_imhtml_adjustment_changed, layout); | |
2027 need_adjust = TRUE; | |
2028 } | |
2029 | |
2030 if (layout->vadjustment != vadj) { | |
2031 layout->vadjustment = vadj; | |
2032 gtk_object_ref (GTK_OBJECT (layout->vadjustment)); | |
2033 gtk_object_sink (GTK_OBJECT (layout->vadjustment)); | |
2034 | |
2035 gtk_signal_connect (GTK_OBJECT (layout->vadjustment), "value_changed", | |
2036 (GtkSignalFunc) gtk_imhtml_adjustment_changed, layout); | |
2037 need_adjust = TRUE; | |
2038 } | |
2039 | |
2040 if (need_adjust) | |
2041 gtk_imhtml_adjustment_changed (NULL, GTK_IMHTML (layout)); | |
2042 } | |
2043 | |
2044 static void | |
2045 gtk_imhtml_class_init (GtkIMHtmlClass *class) | |
2046 { | |
2047 GObjectClass *gobject_class; | |
2048 GtkObjectClass *object_class; | |
2049 GtkWidgetClass *widget_class; | |
2050 GtkLayoutClass *layout_class; | |
2051 | |
2052 gobject_class = (GObjectClass*) class; | |
2053 object_class = (GtkObjectClass*) class; | |
2054 widget_class = (GtkWidgetClass*) class; | |
2055 layout_class = (GtkLayoutClass*) class; | |
2056 | |
2057 parent_class = gtk_type_class (GTK_TYPE_LAYOUT); | |
2058 | |
2059 signals [URL_CLICKED] = | |
2060 gtk_signal_new ("url_clicked", | |
2061 GTK_RUN_FIRST, | |
2062 GTK_CLASS_TYPE (object_class), | |
2063 GTK_SIGNAL_OFFSET (GtkIMHtmlClass, url_clicked), | |
2064 gtk_marshal_NONE__POINTER, | |
2065 GTK_TYPE_NONE, 1, | |
2066 GTK_TYPE_POINTER); | |
2067 | |
2068 gobject_class->finalize = gtk_imhtml_finalize; | |
2069 | |
2070 widget_class->realize = gtk_imhtml_realize; | |
2071 widget_class->style_set = gtk_imhtml_style_set; | |
2072 widget_class->expose_event = gtk_imhtml_expose_event; | |
2073 widget_class->size_allocate = gtk_imhtml_size_allocate; | |
2074 widget_class->motion_notify_event = gtk_imhtml_motion_notify_event; | |
2075 widget_class->leave_notify_event = gtk_imhtml_leave_notify_event; | |
2076 widget_class->button_press_event = gtk_imhtml_button_press_event; | |
2077 widget_class->button_release_event = gtk_imhtml_button_release_event; | |
2078 widget_class->selection_get = gtk_imhtml_selection_get; | |
2079 widget_class->selection_clear_event = gtk_imhtml_selection_clear_event; | |
2080 | |
2081 layout_class->set_scroll_adjustments = gtk_imhtml_set_scroll_adjustments; | |
2082 } | |
2083 | |
2084 /* the font stuff is the most insane stuff. i don't understand it half | |
2085 * the time. so we're going to comment it. isn't that wonderful. */ | |
2086 | |
2087 /* when you g_strsplit a valid font name, these are the positions of all the various parts of it. */ | |
2088 #define FNDRY 1 | |
2089 #define FMLY 2 | |
2090 #define WGHT 3 | |
2091 #define SLANT 4 | |
2092 #define SWDTH 5 | |
2093 #define ADSTYL 6 | |
2094 #define PXLSZ 7 | |
2095 #define PTSZ 8 | |
2096 #define RESX 9 | |
2097 #define RESY 10 | |
2098 #define SPC 11 | |
2099 #define AVGWDTH 12 | |
2100 #define RGSTRY 13 | |
2101 #define ENCDNG 14 | |
2102 | |
2103 #if 0 | |
2104 static const gchar* | |
2105 gtk_imhtml_get_font_name (PangoFontDescription *font) | |
2106 { | |
2107 return pango_font_description_get_family(font); | |
2108 } | |
2109 #endif | |
2110 | |
2111 static PangoFontDescription * | |
2112 gtk_imhtml_font_load (GtkIMHtml *imhtml, | |
2113 gchar *name, | |
2114 gboolean bold, | |
2115 gboolean italics, | |
2116 gint fontsize) | |
2117 { | |
2118 PangoFontDescription *default_font = imhtml->default_font; | |
2119 PangoFontDescription *ret_font; | |
2120 | |
2121 if (!name && !bold && !italics && !fontsize) | |
2122 return default_font; | |
2123 // return pango_font_description_copy(default_font); | |
2124 | |
2125 ret_font = pango_font_description_copy(default_font); | |
2126 | |
2127 if (name) | |
2128 pango_font_description_set_family(ret_font, name); | |
2129 | |
2130 if (italics) | |
2131 pango_font_description_set_style(ret_font, PANGO_STYLE_ITALIC); | |
2132 | |
2133 if (bold) | |
2134 pango_font_description_set_weight(ret_font, PANGO_WEIGHT_BOLD); | |
2135 | |
2136 if (fontsize) | |
2137 { | |
2138 pango_font_description_set_size(ret_font, | |
2139 POINT_SIZE(fontsize) * PANGO_SCALE); | |
2140 } | |
2141 | |
2142 return ret_font; | |
2143 } | |
2144 | |
2145 static void | |
2146 gtk_imhtml_init (GtkIMHtml *imhtml) | |
2147 { | |
2148 static const GtkTargetEntry targets [] = { | |
2149 { "STRING", 0, TARGET_STRING }, | |
2150 { "TEXT", 0, TARGET_TEXT }, | |
2151 { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT } | |
2152 }; | |
2153 | |
2154 imhtml->hand_cursor = gdk_cursor_new (GDK_HAND2); | 98 imhtml->hand_cursor = gdk_cursor_new (GDK_HAND2); |
2155 imhtml->arrow_cursor = gdk_cursor_new (GDK_LEFT_PTR); | 99 imhtml->arrow_cursor = gdk_cursor_new (GDK_LEFT_PTR); |
2156 | 100 |
2157 GTK_WIDGET_SET_FLAGS (GTK_WIDGET (imhtml), GTK_CAN_FOCUS); | 101 } |
2158 gtk_selection_add_targets (GTK_WIDGET (imhtml), GDK_SELECTION_PRIMARY, targets, 3); | 102 |
2159 } | 103 GtkWidget *gtk_imhtml_new(void *a, void *b) |
2160 | 104 { |
2161 GtkType | 105 return GTK_WIDGET(gtk_type_new(gtk_imhtml_get_type())); |
2162 gtk_imhtml_get_type (void) | 106 } |
2163 { | 107 |
2164 static GtkType imhtml_type = 0; | 108 GtkType gtk_imhtml_get_type() |
109 { | |
110 static guint imhtml_type = 0; | |
2165 | 111 |
2166 if (!imhtml_type) { | 112 if (!imhtml_type) { |
2167 static const GtkTypeInfo imhtml_info = { | 113 GtkTypeInfo imhtml_info = { |
2168 "GtkIMHtml", | 114 "GtkIMHtml", |
2169 sizeof (GtkIMHtml), | 115 sizeof (GtkIMHtml), |
2170 sizeof (GtkIMHtmlClass), | 116 sizeof (GtkIMHtmlClass), |
2171 (GtkClassInitFunc) gtk_imhtml_class_init, | 117 (GtkClassInitFunc) gtk_imhtml_class_init, |
2172 (GtkObjectInitFunc) gtk_imhtml_init, | 118 (GtkObjectInitFunc) gtk_imhtml_init, |
2173 NULL, | 119 NULL, |
2174 NULL, | |
2175 NULL | 120 NULL |
2176 }; | 121 }; |
2177 | 122 |
2178 imhtml_type = gtk_type_unique (GTK_TYPE_LAYOUT, &imhtml_info); | 123 imhtml_type = gtk_type_unique (gtk_text_view_get_type (), &imhtml_info); |
2179 } | 124 } |
2180 | 125 |
2181 return imhtml_type; | 126 return imhtml_type; |
2182 } | 127 } |
2183 | 128 |
2184 void | 129 /* The call back for an event on a link tag. */ |
2185 gtk_imhtml_init_smileys (GtkIMHtml *imhtml) | 130 void tag_event(GtkTextTag *tag, GObject *arg1, GdkEvent *event, GtkTextIter *arg2, char *url) { |
2186 { | 131 if (event->type == GDK_BUTTON_RELEASE) { |
2187 g_return_if_fail (imhtml != NULL); | 132 /* A link was clicked--we emit the "url_clicked" signal with the URL as the argument */ |
2188 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | 133 // if ((GdkEventButton)(event)->button == 1) |
2189 | 134 gtk_signal_emit (G_OBJECT(arg1), signals[URL_CLICKED], url); |
2190 imhtml->smiley_data = gtk_smiley_tree_new (); | 135 } else if (event->type == GDK_ENTER_NOTIFY) { |
2191 | 136 /* make a hand cursor and a tooltip timeout -- if GTK worked as it should */ |
2192 gtk_imhtml_associate_smiley (imhtml, ":)", smile_xpm); | 137 } else if (event->type == GDK_LEAVE_NOTIFY) { |
2193 gtk_imhtml_associate_smiley (imhtml, ":-)", smile_xpm); | 138 /* clear timeout and make an arrow cursor again --if GTK worked as it should */ |
2194 | 139 } |
2195 gtk_imhtml_associate_smiley (imhtml, ":(", sad_xpm); | 140 } |
2196 gtk_imhtml_associate_smiley (imhtml, ":-(", sad_xpm); | 141 |
2197 | 142 #define VALID_TAG(x) if (!g_strncasecmp (string, x ">", strlen (x ">"))) { \ |
2198 gtk_imhtml_associate_smiley (imhtml, ";)", wink_xpm); | 143 *tag = g_strndup (string, strlen (x)); \ |
2199 gtk_imhtml_associate_smiley (imhtml, ";-)", wink_xpm); | 144 *len = strlen (x) + 1; \ |
2200 | 145 return TRUE; \ |
2201 gtk_imhtml_associate_smiley (imhtml, ":-p", tongue_xpm); | 146 } \ |
2202 gtk_imhtml_associate_smiley (imhtml, ":-P", tongue_xpm); | 147 (*type)++ |
2203 | 148 |
2204 gtk_imhtml_associate_smiley (imhtml, "=-O", scream_xpm); | 149 #define VALID_OPT_TAG(x) if (!g_strncasecmp (string, x " ", strlen (x " "))) { \ |
2205 gtk_imhtml_associate_smiley (imhtml, "=-o", scream_xpm); | 150 const gchar *c = string + strlen (x " "); \ |
2206 gtk_imhtml_associate_smiley (imhtml, ":-*", kiss_xpm); | 151 gchar e = '"'; \ |
2207 gtk_imhtml_associate_smiley (imhtml, ">:O", yell_xpm); | 152 gboolean quote = FALSE; \ |
2208 gtk_imhtml_associate_smiley (imhtml, ">:o", yell_xpm); | 153 while (*c) { \ |
2209 gtk_imhtml_associate_smiley (imhtml, "8-)", smile8_xpm); | 154 if (*c == '"' || *c == '\'') { \ |
2210 gtk_imhtml_associate_smiley (imhtml, ":-$", moneymouth_xpm); | 155 if (quote && (*c == e)) \ |
2211 gtk_imhtml_associate_smiley (imhtml, ":-!", burp_xpm); | 156 quote = !quote; \ |
2212 gtk_imhtml_associate_smiley (imhtml, ":-[", embarrassed_xpm); | 157 else if (!quote) { \ |
2213 gtk_imhtml_associate_smiley (imhtml, ":'(", cry_xpm); | 158 quote = !quote; \ |
2214 | 159 e = *c; \ |
2215 gtk_imhtml_associate_smiley (imhtml, ":-/", think_xpm); | 160 } \ |
2216 gtk_imhtml_associate_smiley (imhtml, ":-\\", think_xpm); | 161 } else if (!quote && (*c == '>')) \ |
2217 | 162 break; \ |
2218 gtk_imhtml_associate_smiley (imhtml, ":-X", crossedlips_xpm); | 163 c++; \ |
2219 gtk_imhtml_associate_smiley (imhtml, ":-x", crossedlips_xpm); | 164 } \ |
2220 gtk_imhtml_associate_smiley (imhtml, ":-D", bigsmile_xpm); | 165 if (*c) { \ |
2221 gtk_imhtml_associate_smiley (imhtml, ":-d", bigsmile_xpm); | 166 *tag = g_strndup (string, c - string); \ |
2222 gtk_imhtml_associate_smiley (imhtml, "O:-)", angel_xpm); | 167 *len = c - string + 1; \ |
2223 } | 168 return TRUE; \ |
2224 | 169 } \ |
2225 GtkWidget* | 170 } \ |
2226 gtk_imhtml_new (GtkAdjustment *hadj, | 171 (*type)++ |
2227 GtkAdjustment *vadj) | 172 |
2228 { | |
2229 GtkIMHtml *imhtml = gtk_type_new (GTK_TYPE_IMHTML); | |
2230 | |
2231 gtk_imhtml_set_adjustments (imhtml, hadj, vadj); | |
2232 | |
2233 imhtml->im_images = NULL; | |
2234 | |
2235 imhtml->bits = NULL; | |
2236 imhtml->click = NULL; | |
2237 | |
2238 imhtml->x = 0; | |
2239 imhtml->y = TOP_BORDER; | |
2240 imhtml->llheight = 0; | |
2241 imhtml->llascent = 0; | |
2242 imhtml->line = NULL; | |
2243 | |
2244 imhtml->selected_text = g_string_new (""); | |
2245 imhtml->scroll_timer = 0; | |
2246 | |
2247 imhtml->img = NULL; | |
2248 | |
2249 imhtml->smileys = TRUE; | |
2250 imhtml->comments = FALSE; | |
2251 | |
2252 gtk_imhtml_init_smileys (imhtml); | |
2253 | |
2254 return GTK_WIDGET (imhtml); | |
2255 } | |
2256 | |
2257 void | |
2258 gtk_imhtml_set_adjustments (GtkIMHtml *imhtml, | |
2259 GtkAdjustment *hadj, | |
2260 GtkAdjustment *vadj) | |
2261 { | |
2262 gtk_layout_set_hadjustment (GTK_LAYOUT (imhtml), hadj); | |
2263 gtk_layout_set_vadjustment (GTK_LAYOUT (imhtml), vadj); | |
2264 } | |
2265 | |
2266 void | |
2267 gtk_imhtml_set_defaults (GtkIMHtml *imhtml, | |
2268 PangoFontDescription *font, | |
2269 GdkColor *fg_color, | |
2270 GdkColor *bg_color) | |
2271 { | |
2272 g_return_if_fail (imhtml != NULL); | |
2273 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
2274 | |
2275 if (font) { | |
2276 if (imhtml->default_font) | |
2277 pango_font_description_free(imhtml->default_font); | |
2278 imhtml->default_font = pango_font_description_copy(font); | |
2279 } | |
2280 | |
2281 if (fg_color) { | |
2282 if (imhtml->default_fg_color) | |
2283 gdk_color_free (imhtml->default_fg_color); | |
2284 imhtml->default_fg_color = gdk_color_copy (fg_color); | |
2285 } | |
2286 | |
2287 if (bg_color) { | |
2288 if (imhtml->default_bg_color) | |
2289 gdk_color_free (imhtml->default_bg_color); | |
2290 imhtml->default_bg_color = gdk_color_copy (bg_color); | |
2291 gdk_window_set_background (GTK_LAYOUT (imhtml)->bin_window, imhtml->default_bg_color); | |
2292 } | |
2293 } | |
2294 | |
2295 void | |
2296 gtk_imhtml_set_img_handler (GtkIMHtml *imhtml, | |
2297 GtkIMHtmlImage handler) | |
2298 { | |
2299 g_return_if_fail (imhtml != NULL); | |
2300 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
2301 | |
2302 imhtml->img = handler; | |
2303 } | |
2304 | |
2305 void | |
2306 gtk_imhtml_associate_smiley (GtkIMHtml *imhtml, | |
2307 gchar *text, | |
2308 gchar **xpm) | |
2309 { | |
2310 g_return_if_fail (imhtml != NULL); | |
2311 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
2312 g_return_if_fail (text != NULL); | |
2313 | |
2314 if (xpm == NULL) | |
2315 gtk_smiley_tree_remove (imhtml->smiley_data, text); | |
2316 else | |
2317 gtk_smiley_tree_insert (imhtml->smiley_data, text, xpm); | |
2318 } | |
2319 | |
2320 static void | |
2321 new_line (GtkIMHtml *imhtml) | |
2322 { | |
2323 GList *last = g_list_last (imhtml->line); | |
2324 struct line_info *li; | |
2325 | |
2326 if (last) { | |
2327 li = last->data; | |
2328 if (li->x + li->width != imhtml->xsize) | |
2329 li->width = imhtml->xsize - li->x; | |
2330 } | |
2331 | |
2332 last = imhtml->line; | |
2333 if (last) { | |
2334 li = last->data; | |
2335 if (li->height < MIN_HEIGHT) { | |
2336 while (last) { | |
2337 gint diff; | |
2338 li = last->data; | |
2339 diff = MIN_HEIGHT - li->height; | |
2340 li->height = MIN_HEIGHT; | |
2341 li->ascent += diff / 2; | |
2342 last = g_list_next (last); | |
2343 } | |
2344 imhtml->llheight = MIN_HEIGHT; | |
2345 } | |
2346 } | |
2347 | |
2348 g_list_free (imhtml->line); | |
2349 imhtml->line = NULL; | |
2350 | |
2351 imhtml->x = 0; | |
2352 imhtml->y += imhtml->llheight; | |
2353 imhtml->llheight = 0; | |
2354 imhtml->llascent = 0; | |
2355 } | |
2356 | |
2357 static void | |
2358 backwards_update (GtkIMHtml *imhtml, | |
2359 GtkIMHtmlBit *bit, | |
2360 gint height, | |
2361 gint ascent) | |
2362 { | |
2363 gint diff; | |
2364 GList *ls = NULL; | |
2365 struct line_info *li; | |
2366 struct clickable *uw; | |
2367 struct im_image *img; | |
2368 | |
2369 if (height > imhtml->llheight) { | |
2370 diff = height - imhtml->llheight; | |
2371 | |
2372 ls = imhtml->line; | |
2373 while (ls) { | |
2374 li = ls->data; | |
2375 li->height += diff; | |
2376 if (ascent) | |
2377 li->ascent = ascent; | |
2378 else | |
2379 li->ascent += diff / 2; | |
2380 ls = g_list_next (ls); | |
2381 } | |
2382 | |
2383 ls = imhtml->click; | |
2384 while (ls) { | |
2385 uw = ls->data; | |
2386 if (uw->y + diff > imhtml->y) | |
2387 uw->y += diff; | |
2388 ls = g_list_next (ls); | |
2389 } | |
2390 | |
2391 ls = imhtml->im_images; | |
2392 while(ls) { | |
2393 img = ls->data; | |
2394 if (img->y + diff > imhtml->y) | |
2395 img->y += diff; | |
2396 ls = g_list_next(ls); | |
2397 } | |
2398 | |
2399 imhtml->llheight = height; | |
2400 if (ascent) | |
2401 imhtml->llascent = ascent; | |
2402 else | |
2403 imhtml->llascent += diff / 2; | |
2404 } | |
2405 } | |
2406 | |
2407 static void | |
2408 add_text_renderer (GtkIMHtml *imhtml, | |
2409 GtkIMHtmlBit *bit, | |
2410 gchar *text) | |
2411 { | |
2412 struct line_info *li; | |
2413 struct clickable *uw; | |
2414 PangoFontMetrics *metrics; | |
2415 gint width; | |
2416 | |
2417 if (text) | |
2418 width = string_width (imhtml->context, bit->font, text); | |
2419 else | |
2420 width = 0; | |
2421 | |
2422 li = g_new0 (struct line_info, 1); | |
2423 li->x = imhtml->x; | |
2424 li->y = imhtml->y; | |
2425 li->width = width; | |
2426 li->height = imhtml->llheight; | |
2427 if (text) { | |
2428 metrics = pango_context_get_metrics(imhtml->context, bit->font, NULL); | |
2429 li->ascent = MAX (imhtml->llascent, pango_font_metrics_get_ascent(metrics) / PANGO_SCALE); | |
2430 pango_font_metrics_unref(metrics); | |
2431 } else | |
2432 li->ascent = 0; | |
2433 li->text = text; | |
2434 li->bit = bit; | |
2435 | |
2436 if (bit->url) { | |
2437 uw = g_new0 (struct clickable, 1); | |
2438 uw->x = imhtml->x; | |
2439 uw->y = imhtml->y; | |
2440 uw->width = width; | |
2441 uw->height = imhtml->llheight; | |
2442 uw->imhtml = imhtml; | |
2443 uw->bit = bit; | |
2444 imhtml->click = g_list_append (imhtml->click, uw); | |
2445 } | |
2446 | |
2447 bit->chunks = g_list_append (bit->chunks, li); | |
2448 imhtml->line = g_list_append (imhtml->line, li); | |
2449 } | |
2450 | |
2451 static void | |
2452 add_img_renderer (GtkIMHtml *imhtml, | |
2453 GtkIMHtmlBit *bit) | |
2454 { | |
2455 struct line_info *li; | |
2456 struct clickable *uw; | |
2457 gint width; | |
2458 | |
2459 gdk_window_get_size (bit->pm, &width, NULL); | |
2460 | |
2461 li = g_new0 (struct line_info, 1); | |
2462 li->x = imhtml->x; | |
2463 li->y = imhtml->y; | |
2464 li->width = width; | |
2465 li->height = imhtml->llheight; | |
2466 li->ascent = 0; | |
2467 li->bit = bit; | |
2468 | |
2469 | |
2470 if (bit->url || bit->img) { | |
2471 uw = g_new0 (struct clickable, 1); | |
2472 uw->x = imhtml->x; | |
2473 uw->y = imhtml->y; | |
2474 uw->width = width; | |
2475 uw->height = imhtml->llheight; | |
2476 uw->imhtml = imhtml; | |
2477 uw->bit = bit; | |
2478 imhtml->click = g_list_append (imhtml->click, uw); | |
2479 } | |
2480 | |
2481 bit->chunks = g_list_append (bit->chunks, li); | |
2482 imhtml->line = g_list_append (imhtml->line, li); | |
2483 | |
2484 imhtml->x += width; | |
2485 } | |
2486 | |
2487 static void | |
2488 gtk_imhtml_draw_bit (GtkIMHtml *imhtml, | |
2489 GtkIMHtmlBit *bit) | |
2490 { | |
2491 PangoFontMetrics *metrics; | |
2492 gint width, height; | |
2493 | |
2494 g_return_if_fail (imhtml != NULL); | |
2495 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
2496 g_return_if_fail (bit != NULL); | |
2497 | |
2498 | |
2499 if ( ((bit->type == TYPE_TEXT) || | |
2500 ((bit->type == TYPE_SMILEY) && !imhtml->smileys) || | |
2501 ((bit->type == TYPE_COMMENT) && imhtml->comments)) && | |
2502 bit->text) { | |
2503 gchar *copy = g_strdup (bit->text); | |
2504 gint pos = 0; | |
2505 gboolean seenspace = FALSE; | |
2506 gchar *tmp; | |
2507 | |
2508 metrics = pango_context_get_metrics(imhtml->context, bit->font, NULL); | |
2509 height = (pango_font_metrics_get_ascent(metrics) + pango_font_metrics_get_descent(metrics)) / PANGO_SCALE; | |
2510 width = string_width (imhtml->context, bit->font, bit->text); | |
2511 | |
2512 if ((imhtml->x != 0) && ((imhtml->x + width) > imhtml->xsize)) { | |
2513 gint remain = imhtml->xsize - imhtml->x; | |
2514 while (text_width (imhtml->context, bit->font, copy, pos) < remain) { | |
2515 if (copy [pos] == ' ') | |
2516 seenspace = TRUE; | |
2517 pos++; | |
2518 } | |
2519 if (seenspace) { | |
2520 while (copy [pos - 1] != ' ') pos--; | |
2521 | |
2522 tmp = g_strndup (copy, pos); | |
2523 | |
2524 backwards_update (imhtml, bit, height, pango_font_metrics_get_ascent(metrics) / PANGO_SCALE); | |
2525 add_text_renderer (imhtml, bit, tmp); | |
2526 } else | |
2527 pos = 0; | |
2528 seenspace = FALSE; | |
2529 new_line (imhtml); | |
2530 } | |
2531 | |
2532 backwards_update (imhtml, bit, height, pango_font_metrics_get_ascent(metrics) / PANGO_SCALE); | |
2533 | |
2534 while (pos < strlen (bit->text)) { | |
2535 width = string_width (imhtml->context, bit->font, copy + pos); | |
2536 if (imhtml->x + width > imhtml->xsize) { | |
2537 gint newpos = 0; | |
2538 gint remain = imhtml->xsize - imhtml->x; | |
2539 while (text_width (imhtml->context, bit->font, copy + pos, newpos) < remain) { | |
2540 if (copy [pos + newpos] == ' ') | |
2541 seenspace = TRUE; | |
2542 newpos++; | |
2543 } | |
2544 | |
2545 if (seenspace) | |
2546 while (copy [pos + newpos - 1] != ' ') newpos--; | |
2547 | |
2548 if (newpos == 0) | |
2549 break; | |
2550 | |
2551 tmp = g_strndup (copy + pos, newpos); | |
2552 pos += newpos; | |
2553 | |
2554 backwards_update (imhtml, bit, height, pango_font_metrics_get_ascent(metrics) / PANGO_SCALE); | |
2555 add_text_renderer (imhtml, bit, tmp); | |
2556 | |
2557 seenspace = FALSE; | |
2558 new_line (imhtml); | |
2559 } else { | |
2560 tmp = g_strdup (copy + pos); | |
2561 | |
2562 backwards_update (imhtml, bit, height, pango_font_metrics_get_ascent(metrics) / PANGO_SCALE); | |
2563 add_text_renderer (imhtml, bit, tmp); | |
2564 | |
2565 pos = strlen (bit->text); | |
2566 | |
2567 imhtml->x += width; | |
2568 } | |
2569 } | |
2570 | |
2571 pango_font_metrics_unref(metrics); | |
2572 g_free(copy); | |
2573 } else if ((bit->type == TYPE_SMILEY) || (bit->type == TYPE_IMG)) { | |
2574 if (bit->img) { | |
2575 GdkPixbuf *imagepb = bit->img->pb; | |
2576 GdkPixbuf *tmp = NULL; | |
2577 if (gdk_pixbuf_get_width(imagepb) > imhtml->xsize - imhtml->x) | |
2578 new_line (imhtml); | |
2579 | |
2580 if (gdk_pixbuf_get_width(imagepb) > imhtml->xsize) { | |
2581 tmp = gdk_pixbuf_scale_simple(imagepb, imhtml->xsize, | |
2582 gdk_pixbuf_get_height(imagepb) * | |
2583 imhtml->xsize/ | |
2584 gdk_pixbuf_get_width(imagepb), | |
2585 GDK_INTERP_TILES); | |
2586 if (bit->pm) | |
2587 gdk_pixmap_unref (bit->pm); | |
2588 if (bit->bm) | |
2589 gdk_bitmap_unref (bit->bm); | |
2590 gdk_pixbuf_render_pixmap_and_mask(tmp, &(bit->pm), &(bit->bm), 100); | |
2591 gdk_pixbuf_unref(tmp); | |
2592 } | |
2593 else { | |
2594 if (bit->pm) | |
2595 gdk_pixmap_unref (bit->pm); | |
2596 if (bit->bm) | |
2597 gdk_bitmap_unref (bit->bm); | |
2598 gdk_pixbuf_render_pixmap_and_mask(imagepb, &(bit->pm), &(bit->bm), 100); | |
2599 } | |
2600 } | |
2601 | |
2602 gdk_window_get_size (bit->pm, &width, &height); | |
2603 | |
2604 if ((imhtml->x != 0) && ((imhtml->x + width) > imhtml->xsize)) | |
2605 new_line (imhtml); | |
2606 else | |
2607 backwards_update (imhtml, bit, height, 0); | |
2608 | |
2609 add_img_renderer (imhtml, bit); | |
2610 } else if (bit->type == TYPE_BR) { | |
2611 new_line (imhtml); | |
2612 add_text_renderer (imhtml, bit, NULL); | |
2613 } else if (bit->type == TYPE_SEP) { | |
2614 struct line_info *li; | |
2615 if (imhtml->llheight) | |
2616 new_line (imhtml); | |
2617 | |
2618 li = g_new0 (struct line_info, 1); | |
2619 li->x = imhtml->x; | |
2620 li->y = imhtml->y; | |
2621 li->width = imhtml->xsize; | |
2622 li->height = HR_HEIGHT * 2; | |
2623 li->ascent = 0; | |
2624 li->text = NULL; | |
2625 li->bit = bit; | |
2626 | |
2627 bit->chunks = g_list_append (bit->chunks, li); | |
2628 | |
2629 imhtml->llheight = HR_HEIGHT * 2; | |
2630 new_line (imhtml); | |
2631 add_text_renderer (imhtml, bit, NULL); | |
2632 } | |
2633 | |
2634 } | |
2635 | |
2636 void | |
2637 gtk_imhtml_show_smileys (GtkIMHtml *imhtml, | |
2638 gboolean show) | |
2639 { | |
2640 g_return_if_fail (imhtml != NULL); | |
2641 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
2642 | |
2643 imhtml->smileys = show; | |
2644 | |
2645 if (GTK_WIDGET_VISIBLE (GTK_WIDGET (imhtml))) | |
2646 gtk_imhtml_redraw_all (imhtml); | |
2647 } | |
2648 | |
2649 void | |
2650 gtk_imhtml_show_comments (GtkIMHtml *imhtml, | |
2651 gboolean show) | |
2652 { | |
2653 g_return_if_fail (imhtml != NULL); | |
2654 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
2655 | |
2656 imhtml->comments = show; | |
2657 | |
2658 if (GTK_WIDGET_VISIBLE (GTK_WIDGET (imhtml))) | |
2659 gtk_imhtml_redraw_all (imhtml); | |
2660 } | |
2661 | |
2662 static GdkColor * | |
2663 gtk_imhtml_get_color (const gchar *color) | |
2664 { | |
2665 GdkColor c; | |
2666 | |
2667 if (!gdk_color_parse (color, &c)) | |
2668 return NULL; | |
2669 | |
2670 return gdk_color_copy (&c); | |
2671 } | |
2672 | |
2673 static gboolean | |
2674 gtk_imhtml_is_smiley (GtkIMHtml *imhtml, | |
2675 const gchar *text, | |
2676 gint *len) | |
2677 { | |
2678 *len = gtk_smiley_tree_lookup (imhtml->smiley_data, text); | |
2679 return (*len > 0); | |
2680 } | |
2681 | |
2682 static GtkIMHtmlBit * | |
2683 gtk_imhtml_new_bit (GtkIMHtml *imhtml, | |
2684 gint type, | |
2685 gchar *text, | |
2686 gint bold, | |
2687 gint italics, | |
2688 gint underline, | |
2689 gint strike, | |
2690 FontDetail *font, | |
2691 GdkColor *bg, | |
2692 gchar *url, | |
2693 gint pre, | |
2694 gint sub, | |
2695 gint sup) | |
2696 { | |
2697 GtkIMHtmlBit *bit = NULL; | |
2698 | |
2699 g_return_val_if_fail (imhtml != NULL, NULL); | |
2700 g_return_val_if_fail (GTK_IS_IMHTML (imhtml), NULL); | |
2701 | |
2702 if ((type == TYPE_TEXT) && ((text == NULL) || (strlen (text) == 0))) | |
2703 return NULL; | |
2704 | |
2705 bit = g_new0 (GtkIMHtmlBit, 1); | |
2706 bit->type = type; | |
2707 | |
2708 if ((text != NULL) && (strlen (text) != 0)) | |
2709 bit->text = g_strdup (text); | |
2710 | |
2711 if ((font != NULL) || bold || italics || pre) { | |
2712 if (font && (bold || italics || font->size || font->face || pre)) { | |
2713 if (pre) { | |
2714 bit->font = gtk_imhtml_font_load (imhtml, DEFAULT_PRE_FACE, bold, italics, font->size); | |
2715 } else { | |
2716 bit->font = gtk_imhtml_font_load (imhtml, font->face, bold, italics, font->size); | |
2717 } | |
2718 } else if (bold || italics || pre) { | |
2719 if (pre) { | |
2720 bit->font = gtk_imhtml_font_load (imhtml, DEFAULT_PRE_FACE, bold, italics, 0); | |
2721 } else { | |
2722 bit->font = gtk_imhtml_font_load (imhtml, NULL, bold, italics, 0); | |
2723 } | |
2724 } | |
2725 | |
2726 if (font && (type != TYPE_BR)) { | |
2727 if (font->fore != NULL) | |
2728 bit->fore = gdk_color_copy (font->fore); | |
2729 | |
2730 if (font->back != NULL) | |
2731 bit->back = gdk_color_copy (font->back); | |
2732 } | |
2733 } | |
2734 | |
2735 if (((bit->type == TYPE_TEXT) || (bit->type == TYPE_SMILEY) || (bit->type == TYPE_COMMENT)) && | |
2736 (bit->font == NULL)) | |
2737 bit->font = pango_font_description_copy (imhtml->default_font); | |
2738 | |
2739 if (bg != NULL) | |
2740 bit->bg = gdk_color_copy (bg); | |
2741 | |
2742 bit->underline = underline; | |
2743 bit->strike = strike; | |
2744 | |
2745 if (url != NULL) | |
2746 bit->url = g_strdup (url); | |
2747 | |
2748 if (type == TYPE_SMILEY) { | |
2749 GdkColor *clr; | |
2750 | |
2751 if ((font != NULL) && (font->back != NULL)) | |
2752 clr = font->back; | |
2753 else | |
2754 clr = (bg != NULL) ? bg : imhtml->default_bg_color; | |
2755 | |
2756 bit->pm = gdk_pixmap_create_from_xpm_d (GTK_WIDGET (imhtml)->window, | |
2757 &bit->bm, | |
2758 clr, | |
2759 gtk_smiley_tree_image (imhtml->smiley_data, text)); | |
2760 } | |
2761 | |
2762 return bit; | |
2763 } | |
2764 | |
2765 #define NEW_TEXT_BIT gtk_imhtml_new_bit (imhtml, TYPE_TEXT, ws, bold, italics, underline, strike, \ | |
2766 fonts ? fonts->data : NULL, bg, url, pre, sub, sup) | |
2767 #define NEW_SMILEY_BIT gtk_imhtml_new_bit (imhtml, TYPE_SMILEY, ws, bold, italics, underline, strike, \ | |
2768 fonts ? fonts->data : NULL, bg, url, pre, sub, sup) | |
2769 #define NEW_SEP_BIT gtk_imhtml_new_bit (imhtml, TYPE_SEP, NULL, 0, 0, 0, 0, NULL, bg, NULL, 0, 0, 0) | |
2770 #define NEW_BR_BIT gtk_imhtml_new_bit (imhtml, TYPE_BR, NULL, 0, 0, 0, 0, \ | |
2771 fonts ? fonts->data : NULL, bg, NULL, 0, 0, 0) | |
2772 #define NEW_COMMENT_BIT gtk_imhtml_new_bit (imhtml, TYPE_COMMENT, ws, bold, italics, underline, strike, \ | |
2773 fonts ? fonts->data : NULL, bg, url, pre, sub, sup) | |
2774 | |
2775 #define NEW_BIT(bit) ws [wpos] = '\0'; \ | |
2776 { GtkIMHtmlBit *tmp = bit; if (tmp != NULL) \ | |
2777 newbits = g_list_append (newbits, tmp); } \ | |
2778 wpos = 0; ws [wpos] = '\0' | |
2779 | |
2780 #define UPDATE_BG_COLORS \ | |
2781 { \ | |
2782 GdkColormap *cmap; \ | |
2783 GList *rev; \ | |
2784 cmap = gtk_widget_get_colormap (GTK_WIDGET (imhtml)); \ | |
2785 rev = g_list_last (newbits); \ | |
2786 while (rev) { \ | |
2787 GtkIMHtmlBit *bit = rev->data; \ | |
2788 if (bit->bg) \ | |
2789 gdk_color_free (bit->bg); \ | |
2790 bit->bg = gdk_color_copy (bg); \ | |
2791 if (bit->type == TYPE_BR) \ | |
2792 break; \ | |
2793 rev = g_list_previous (rev); \ | |
2794 } \ | |
2795 if (!rev) { \ | |
2796 rev = g_list_last (imhtml->bits); \ | |
2797 while (rev) { \ | |
2798 GtkIMHtmlBit *bit = rev->data; \ | |
2799 if (bit->bg) \ | |
2800 gdk_color_free (bit->bg); \ | |
2801 bit->bg = gdk_color_copy (bg); \ | |
2802 gdk_color_alloc (cmap, bit->bg); \ | |
2803 if (bit->type == TYPE_BR) \ | |
2804 break; \ | |
2805 rev = g_list_previous (rev); \ | |
2806 } \ | |
2807 } \ | |
2808 } | |
2809 | 173 |
2810 static gboolean | 174 static gboolean |
2811 gtk_imhtml_is_amp_escape (const gchar *string, | 175 gtk_imhtml_is_amp_escape (const gchar *string, |
2812 gchar *replace, | 176 gchar *replace, |
2813 gint *length) | 177 gint *length) |
2853 return FALSE; | 217 return FALSE; |
2854 } | 218 } |
2855 | 219 |
2856 return TRUE; | 220 return TRUE; |
2857 } | 221 } |
2858 | |
2859 #define VALID_TAG(x) if (!g_strncasecmp (string, x ">", strlen (x ">"))) { \ | |
2860 *tag = g_strndup (string, strlen (x)); \ | |
2861 *len = strlen (x) + 1; \ | |
2862 return TRUE; \ | |
2863 } \ | |
2864 (*type)++ | |
2865 | |
2866 #define VALID_OPT_TAG(x) if (!g_strncasecmp (string, x " ", strlen (x " "))) { \ | |
2867 const gchar *c = string + strlen (x " "); \ | |
2868 gchar e = '"'; \ | |
2869 gboolean quote = FALSE; \ | |
2870 while (*c) { \ | |
2871 if (*c == '"' || *c == '\'') { \ | |
2872 if (quote && (*c == e)) \ | |
2873 quote = !quote; \ | |
2874 else if (!quote) { \ | |
2875 quote = !quote; \ | |
2876 e = *c; \ | |
2877 } \ | |
2878 } else if (!quote && (*c == '>')) \ | |
2879 break; \ | |
2880 c++; \ | |
2881 } \ | |
2882 if (*c) { \ | |
2883 *tag = g_strndup (string, c - string); \ | |
2884 *len = c - string + 1; \ | |
2885 return TRUE; \ | |
2886 } \ | |
2887 } \ | |
2888 (*type)++ | |
2889 | 222 |
2890 static gboolean | 223 static gboolean |
2891 gtk_imhtml_is_tag (const gchar *string, | 224 gtk_imhtml_is_tag (const gchar *string, |
2892 gchar **tag, | 225 gchar **tag, |
2893 gint *len, | 226 gint *len, |
2996 while (*e && !isspace ((gint) *e)) e++; | 329 while (*e && !isspace ((gint) *e)) e++; |
2997 return g_strndup (a, e - a); | 330 return g_strndup (a, e - a); |
2998 } | 331 } |
2999 } | 332 } |
3000 | 333 |
3001 GString* | 334 |
3002 gtk_imhtml_append_text (GtkIMHtml *imhtml, | 335 |
3003 const gchar *text, | 336 #define NEW_TEXT_BIT 0 |
3004 gint len, | 337 #define NEW_HR_BIT 1 |
3005 GtkIMHtmlOptions options) | 338 #define NEW_BIT(x) ws [wpos] = '\0'; \ |
3006 { | 339 mark2 = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); \ |
340 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, -1); \ | |
341 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); \ | |
342 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &siter, mark2); \ | |
343 gtk_text_buffer_delete_mark(imhtml->text_buffer, mark2); \ | |
344 if (bold) \ | |
345 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", &siter, &iter); \ | |
346 if (italics) \ | |
347 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", &siter, &iter); \ | |
348 if (underline) \ | |
349 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", &siter, &iter); \ | |
350 if (strike) \ | |
351 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "STRIKE", &siter, &iter); \ | |
352 if (sub) \ | |
353 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "SUB", &siter, &iter); \ | |
354 if (sup) \ | |
355 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "SUP", &siter, &iter); \ | |
356 if (pre) \ | |
357 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "PRE", &siter, &iter); \ | |
358 if (bg) { \ | |
359 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "background", bg, NULL); \ | |
360 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ | |
361 } \ | |
362 if (fonts) { \ | |
363 FontDetail *fd = fonts->data; \ | |
364 if (fd->fore) { \ | |
365 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "foreground", fd->fore, NULL); \ | |
366 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ | |
367 } \ | |
368 if (fd->back) { \ | |
369 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "background", fd->back, NULL); \ | |
370 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ | |
371 } \ | |
372 if (fd->face) { \ | |
373 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "font", fd->face, NULL); \ | |
374 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ | |
375 } \ | |
376 if (fd->size) { \ | |
377 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "size-points", (double)POINT_SIZE(fd->size), NULL); \ | |
378 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ | |
379 } \ | |
380 } \ | |
381 if (url) { \ | |
382 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "foreground", "blue", "underline", PANGO_UNDERLINE_SINGLE, NULL); \ | |
383 g_signal_connect(G_OBJECT(texttag), "event", G_CALLBACK(tag_event), strdup(url)); \ | |
384 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ | |
385 } \ | |
386 wpos = 0; \ | |
387 ws[0] = 0; \ | |
388 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); \ | |
389 | |
390 | |
391 /* if (x == NEW_HR_BIT) { \ | |
392 sep = gtk_hseparator_new(); \ | |
393 gtk_widget_size_request(GTK_WIDGET(imhtml), &req); \ | |
394 gtk_widget_set_size_request(sep, 20, -1); \ | |
395 anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, &iter); \ | |
396 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), sep, anchor); \ | |
397 gtk_widget_show(sep); \ | |
398 } */ | |
399 | |
400 GString* gtk_imhtml_append_text (GtkIMHtml *imhtml, | |
401 const gchar *text, | |
402 gint len, | |
403 GtkIMHtmlOptions options) | |
404 { | |
405 gint pos = 0; | |
406 GString *str = NULL; | |
407 GtkTextIter iter, siter; | |
408 GtkTextMark *mark, *mark2; | |
409 GtkTextChildAnchor *anchor; | |
410 GtkTextTag *texttag; | |
411 GtkWidget *sep; | |
412 GtkRequisition req; | |
413 gchar *ws; | |
414 gchar *tag; | |
415 gchar *url = NULL; | |
416 gchar *bg = NULL; | |
417 gint tlen, wpos=0; | |
418 gint type; | |
3007 const gchar *c; | 419 const gchar *c; |
3008 gboolean binary = TRUE; | |
3009 gchar *ws; | |
3010 gint pos = 0; | |
3011 gint wpos = 0; | |
3012 | |
3013 gchar *tag; | |
3014 gint tlen; | |
3015 gint type; | |
3016 | |
3017 gchar amp; | 420 gchar amp; |
3018 | |
3019 gint smilelen; | |
3020 | |
3021 GList *newbits = NULL; | |
3022 | 421 |
3023 guint bold = 0, | 422 guint bold = 0, |
3024 italics = 0, | 423 italics = 0, |
3025 underline = 0, | 424 underline = 0, |
3026 strike = 0, | 425 strike = 0, |
3027 sub = 0, | 426 sub = 0, |
3028 sup = 0, | 427 sup = 0, |
3029 title = 0, | 428 title = 0, |
3030 pre = 0; | 429 pre = 0; |
430 | |
3031 GSList *fonts = NULL; | 431 GSList *fonts = NULL; |
3032 GdkColor *bg = NULL; | |
3033 gchar *url = NULL; | |
3034 | |
3035 GtkAdjustment *vadj; | |
3036 gboolean scrolldown = TRUE; | |
3037 | |
3038 GString *retval = NULL; | |
3039 | 432 |
3040 g_return_val_if_fail (imhtml != NULL, NULL); | 433 g_return_val_if_fail (imhtml != NULL, NULL); |
3041 g_return_val_if_fail (GTK_IS_IMHTML (imhtml), NULL); | 434 g_return_val_if_fail (GTK_IS_IMHTML (imhtml), NULL); |
3042 g_return_val_if_fail (text != NULL, NULL); | 435 g_return_val_if_fail (text != NULL, NULL); |
436 g_return_val_if_fail (len != 0, NULL); | |
437 | |
438 c = text; | |
439 if (len == -1) | |
440 len = strlen(text); | |
441 ws = g_malloc(len + 1); | |
442 ws[0] = 0; | |
3043 | 443 |
3044 if (options & GTK_IMHTML_RETURN_LOG) | 444 if (options & GTK_IMHTML_RETURN_LOG) |
3045 retval = g_string_new (""); | 445 str = g_string_new(""); |
3046 | 446 |
3047 vadj = GTK_LAYOUT (imhtml)->vadjustment; | 447 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); |
3048 if ((vadj->value < imhtml->y - GTK_WIDGET (imhtml)->allocation.height) && | 448 mark = gtk_text_buffer_create_mark (imhtml->text_buffer, NULL, &iter, /* right grav */ FALSE); |
3049 (vadj->upper >= GTK_WIDGET (imhtml)->allocation.height)) | |
3050 scrolldown = FALSE; | |
3051 | |
3052 c = text; | |
3053 if (len == -1) { | |
3054 binary = FALSE; | |
3055 len = strlen (text); | |
3056 } | |
3057 | |
3058 ws = g_malloc (len + 1); | |
3059 ws [0] = '\0'; | |
3060 | |
3061 while (pos < len) { | 449 while (pos < len) { |
3062 if (*c == '<' && gtk_imhtml_is_tag (c + 1, &tag, &tlen, &type)) { | 450 if (*c == '<' && gtk_imhtml_is_tag (c + 1, &tag, &tlen, &type)) { |
3063 c++; | 451 c++; |
3064 pos++; | 452 pos++; |
3065 switch (type) { | 453 switch (type) |
3066 case 1: /* B */ | 454 { |
3067 case 2: /* BOLD */ | 455 case 1: /* B */ |
3068 NEW_BIT (NEW_TEXT_BIT); | 456 case 2: /* BOLD */ |
3069 bold++; | 457 NEW_BIT (NEW_TEXT_BIT); |
458 bold++; | |
459 break; | |
460 case 3: /* /B */ | |
461 case 4: /* /BOLD */ | |
462 NEW_BIT (NEW_TEXT_BIT); | |
463 if (bold) | |
464 bold--; | |
465 break; | |
466 case 5: /* I */ | |
467 case 6: /* ITALIC */ | |
468 NEW_BIT (NEW_TEXT_BIT); | |
469 italics++; | |
470 break; | |
471 case 7: /* /I */ | |
472 case 8: /* /ITALIC */ | |
473 NEW_BIT (NEW_TEXT_BIT); | |
474 if (italics) | |
475 italics--; | |
476 break; | |
477 case 9: /* U */ | |
478 case 10: /* UNDERLINE */ | |
479 NEW_BIT (NEW_TEXT_BIT); | |
480 underline++; | |
481 break; | |
482 case 11: /* /U */ | |
483 case 12: /* /UNDERLINE */ | |
484 NEW_BIT (NEW_TEXT_BIT); | |
485 if (underline) | |
486 underline--; | |
487 break; | |
488 case 13: /* S */ | |
489 case 14: /* STRIKE */ | |
490 NEW_BIT (NEW_TEXT_BIT); | |
491 strike++; | |
492 break; | |
493 case 15: /* /S */ | |
494 case 16: /* /STRIKE */ | |
495 NEW_BIT (NEW_TEXT_BIT); | |
496 if (strike) | |
497 strike--; | |
498 break; | |
499 case 17: /* SUB */ | |
500 NEW_BIT (NEW_TEXT_BIT); | |
501 sub++; | |
502 break; | |
503 case 18: /* /SUB */ | |
504 NEW_BIT (NEW_TEXT_BIT); | |
505 if (sub) | |
506 sub--; | |
507 break; | |
508 case 19: /* SUP */ | |
509 NEW_BIT (NEW_TEXT_BIT); | |
510 sup++; | |
3070 break; | 511 break; |
3071 case 3: /* /B */ | 512 case 20: /* /SUP */ |
3072 case 4: /* /BOLD */ | 513 NEW_BIT (NEW_TEXT_BIT); |
3073 NEW_BIT (NEW_TEXT_BIT); | 514 if (sup) |
3074 if (bold) | 515 sup--; |
3075 bold--; | 516 break; |
3076 break; | 517 case 21: /* PRE */ |
3077 case 5: /* I */ | 518 NEW_BIT (NEW_TEXT_BIT); |
3078 case 6: /* ITALIC */ | 519 pre++; |
3079 NEW_BIT (NEW_TEXT_BIT); | 520 break; |
3080 italics++; | 521 case 22: /* /PRE */ |
3081 break; | 522 NEW_BIT (NEW_TEXT_BIT); |
3082 case 7: /* /I */ | 523 if (pre) |
3083 case 8: /* /ITALIC */ | 524 pre--; |
3084 NEW_BIT (NEW_TEXT_BIT); | 525 break; |
3085 if (italics) | 526 case 23: /* TITLE */ |
3086 italics--; | 527 NEW_BIT (NEW_TEXT_BIT); |
3087 break; | 528 title++; |
3088 case 9: /* U */ | 529 break; |
3089 case 10: /* UNDERLINE */ | 530 case 24: /* /TITLE */ |
3090 NEW_BIT (NEW_TEXT_BIT); | 531 if (title) { |
3091 underline++; | 532 if (options & GTK_IMHTML_NO_TITLE) { |
3092 break; | 533 wpos = 0; |
3093 case 11: /* /U */ | 534 ws [wpos] = '\0'; |
3094 case 12: /* /UNDERLINE */ | 535 } |
3095 NEW_BIT (NEW_TEXT_BIT); | 536 title--; |
3096 if (underline) | |
3097 underline--; | |
3098 break; | |
3099 case 13: /* S */ | |
3100 case 14: /* STRIKE */ | |
3101 NEW_BIT (NEW_TEXT_BIT); | |
3102 strike++; | |
3103 break; | |
3104 case 15: /* /S */ | |
3105 case 16: /* /STRIKE */ | |
3106 NEW_BIT (NEW_TEXT_BIT); | |
3107 if (strike) | |
3108 strike--; | |
3109 break; | |
3110 case 17: /* SUB */ | |
3111 NEW_BIT (NEW_TEXT_BIT); | |
3112 sub++; | |
3113 break; | |
3114 case 18: /* /SUB */ | |
3115 NEW_BIT (NEW_TEXT_BIT); | |
3116 if (sub) | |
3117 sub--; | |
3118 break; | |
3119 case 19: /* SUP */ | |
3120 NEW_BIT (NEW_TEXT_BIT); | |
3121 sup++; | |
3122 break; | |
3123 case 20: /* /SUP */ | |
3124 NEW_BIT (NEW_TEXT_BIT); | |
3125 if (sup) | |
3126 sup--; | |
3127 break; | |
3128 case 21: /* PRE */ | |
3129 NEW_BIT (NEW_TEXT_BIT); | |
3130 pre++; | |
3131 break; | |
3132 case 22: /* /PRE */ | |
3133 NEW_BIT (NEW_TEXT_BIT); | |
3134 if (pre) | |
3135 pre--; | |
3136 break; | |
3137 case 23: /* TITLE */ | |
3138 NEW_BIT (NEW_TEXT_BIT); | |
3139 title++; | |
3140 break; | |
3141 case 24: /* /TITLE */ | |
3142 if (title) { | |
3143 if (options & GTK_IMHTML_NO_TITLE) { | |
3144 wpos = 0; | |
3145 ws [wpos] = '\0'; | |
3146 } | 537 } |
3147 title--; | 538 break; |
3148 } | 539 case 25: /* BR */ |
3149 break; | 540 ws[wpos] = '\n'; |
3150 case 25: /* BR */ | 541 wpos++; |
3151 NEW_BIT (NEW_TEXT_BIT); | 542 NEW_BIT (NEW_TEXT_BIT); |
3152 NEW_BIT (NEW_BR_BIT); | 543 break; |
3153 break; | 544 case 26: /* HR */ |
3154 case 26: /* HR */ | 545 case 42: /* HR (opt) */ |
3155 NEW_BIT (NEW_TEXT_BIT); | 546 ws[wpos++] = '\n'; |
3156 NEW_BIT (NEW_SEP_BIT); | 547 NEW_BIT(NEW_HR_BIT); |
3157 break; | 548 break; |
3158 case 27: /* /FONT */ | 549 case 27: /* /FONT */ |
3159 if (fonts) { | 550 if (fonts) { |
3160 FontDetail *font = fonts->data; | 551 FontDetail *font = fonts->data; |
3161 NEW_BIT (NEW_TEXT_BIT); | 552 NEW_BIT (NEW_TEXT_BIT); |
3162 fonts = g_slist_remove (fonts, font); | 553 fonts = g_slist_remove (fonts, font); |
3163 if (font->face) | 554 if (font->face) |
3164 g_free (font->face); | 555 g_free (font->face); |
3165 if (font->fore) | 556 if (font->fore) |
3166 gdk_color_free (font->fore); | 557 g_free (font->fore); |
3167 if (font->back) | 558 if (font->back) |
3168 gdk_color_free (font->back); | 559 g_free (font->back); |
3169 g_free (font); | 560 g_free (font); |
3170 } | 561 } |
3171 break; | 562 break; |
3172 case 28: /* /A */ | 563 case 28: /* /A */ |
3173 if (url) { | 564 if (url) { |
3174 NEW_BIT (NEW_TEXT_BIT); | 565 NEW_BIT(NEW_TEXT_BIT); |
3175 g_free (url); | 566 g_free(url); |
3176 url = NULL; | 567 url = NULL; |
3177 } | |
3178 break; | |
3179 case 29: /* P */ | |
3180 case 30: /* /P */ | |
3181 case 31: /* H3 */ | |
3182 case 32: /* /H3 */ | |
3183 case 33: /* HTML */ | |
3184 case 34: /* /HTML */ | |
3185 case 35: /* BODY */ | |
3186 case 36: /* /BODY */ | |
3187 case 37: /* FONT */ | |
3188 case 38: /* HEAD */ | |
3189 case 39: /* /HEAD */ | |
3190 break; | |
3191 case 40: /* BINARY */ | |
3192 | |
3193 NEW_BIT (NEW_TEXT_BIT); | |
3194 while (pos < len) { | |
3195 if (!g_strncasecmp("</BINARY>", c, strlen("</BINARY>"))) | |
3196 break; | 568 break; |
3197 else { | |
3198 c++; | |
3199 pos++; | |
3200 } | 569 } |
3201 } | 570 case 29: /* P */ |
3202 c = c - tlen; /* Because it will add this later */ | 571 case 30: /* /P */ |
3203 break; | 572 case 31: /* H3 */ |
3204 case 41: /* /BINARY */ | 573 case 32: /* /H3 */ |
3205 break; | 574 case 33: /* HTML */ |
3206 | 575 case 34: /* /HTML */ |
3207 case 42: /* HR (opt) */ | 576 case 35: /* BODY */ |
3208 NEW_BIT (NEW_TEXT_BIT); | 577 case 36: /* /BODY */ |
3209 NEW_BIT (NEW_SEP_BIT); | 578 case 37: /* FONT */ |
3210 break; | 579 case 38: /* HEAD */ |
3211 case 43: /* FONT (opt) */ | 580 case 39: /* /HEAD */ |
3212 { | 581 break; |
3213 gchar *color, *back, *face, *size; | 582 case 40: /* BINARY */ |
3214 FontDetail *font; | 583 case 41: /* /BINARY */ |
3215 | 584 break; |
3216 color = gtk_imhtml_get_html_opt (tag, "COLOR="); | 585 case 43: /* FONT (opt) */ |
3217 back = gtk_imhtml_get_html_opt (tag, "BACK="); | 586 { |
3218 face = gtk_imhtml_get_html_opt (tag, "FACE="); | 587 gchar *color, *back, *face, *size; |
3219 size = gtk_imhtml_get_html_opt (tag, "SIZE="); | 588 FontDetail *font, *oldfont = NULL; |
3220 | 589 color = gtk_imhtml_get_html_opt (tag, "COLOR="); |
3221 if (!(color || back || face || size)) | 590 back = gtk_imhtml_get_html_opt (tag, "BACK="); |
3222 break; | 591 face = gtk_imhtml_get_html_opt (tag, "FACE="); |
3223 | 592 size = gtk_imhtml_get_html_opt (tag, "SIZE="); |
3224 NEW_BIT (NEW_TEXT_BIT); | 593 |
3225 | 594 if (!(color || back || face || size)) |
3226 font = g_new0 (FontDetail, 1); | 595 break; |
3227 if (color && !(options & GTK_IMHTML_NO_COLOURS)) | 596 |
3228 font->fore = gtk_imhtml_get_color (color); | 597 NEW_BIT (NEW_TEXT_BIT); |
3229 if (back && !(options & GTK_IMHTML_NO_COLOURS)) | 598 |
3230 font->back = gtk_imhtml_get_color (back); | 599 font = g_new0 (FontDetail, 1); |
3231 if (face && !(options & GTK_IMHTML_NO_FONTS)) | 600 if (fonts) |
3232 font->face = g_strdup (face); | 601 oldfont = fonts->data; |
3233 if (size && !(options & GTK_IMHTML_NO_SIZES)) { | 602 |
3234 if (*size == '+') { | 603 if (color && !(options & GTK_IMHTML_NO_COLOURS)) |
3235 sscanf (size + 1, "%hd", &font->size); | 604 font->fore = color; |
3236 font->size += 3; | 605 else if (oldfont && oldfont->fore) |
3237 } else if (*size == '-') { | 606 font->fore = g_strdup(oldfont->fore); |
3238 sscanf (size + 1, "%hd", &font->size); | 607 |
3239 font->size = MAX (0, 3 - font->size); | 608 if (back && !(options & GTK_IMHTML_NO_COLOURS)) |
3240 } else if (isdigit (*size)) { | 609 font->back = back; |
3241 sscanf (size, "%hd", &font->size); | 610 else if (oldfont && oldfont->back) |
611 font->back = g_strdup(oldfont->back); | |
612 | |
613 if (face && !(options & GTK_IMHTML_NO_FONTS)) | |
614 font->face = face; | |
615 else if (oldfont && oldfont->face) | |
616 font->face = g_strdup(oldfont->face); | |
617 | |
618 if (size && !(options & GTK_IMHTML_NO_SIZES)) { | |
619 if (*size == '+') { | |
620 sscanf (size + 1, "%hd", &font->size); | |
621 font->size += 3; | |
622 } else if (*size == '-') { | |
623 sscanf (size + 1, "%hd", &font->size); | |
624 font->size = MAX (0, 3 - font->size); | |
625 } else if (isdigit (*size)) { | |
626 sscanf (size, "%hd", &font->size); | |
627 } | |
628 } else if (oldfont) | |
629 font->size = oldfont->size; | |
630 g_free(size); | |
631 fonts = g_slist_prepend (fonts, font); | |
3242 } | 632 } |
3243 } | 633 break; |
3244 | 634 case 44: /* BODY (opt) */ |
3245 g_free (color); | 635 if (!(options & GTK_IMHTML_NO_COLOURS)) { |
3246 g_free (back); | 636 char *bgcolor = gtk_imhtml_get_html_opt (tag, "BGCOLOR="); |
3247 g_free (face); | 637 if (bgcolor) { |
3248 g_free (size); | 638 NEW_BIT(NEW_TEXT_BIT); |
3249 | 639 if (bg) |
3250 if (fonts) { | 640 g_free(bg); |
3251 FontDetail *oldfont = fonts->data; | 641 bg = bgcolor; |
3252 if (!font->size) | |
3253 font->size = oldfont->size; | |
3254 if (!font->face && oldfont->face) | |
3255 font->face = g_strdup (oldfont->face); | |
3256 if (!font->fore && oldfont->fore) | |
3257 font->fore = gdk_color_copy (oldfont->fore); | |
3258 if (!font->back && oldfont->back) | |
3259 font->back = gdk_color_copy (oldfont->back); | |
3260 } | |
3261 | |
3262 fonts = g_slist_prepend (fonts, font); | |
3263 } | |
3264 break; | |
3265 case 44: /* BODY (opt) */ | |
3266 if (!(options & GTK_IMHTML_NO_COLOURS)) { | |
3267 gchar *bgcolor = gtk_imhtml_get_html_opt (tag, "BGCOLOR="); | |
3268 if (bgcolor) { | |
3269 GdkColor *tmp = gtk_imhtml_get_color (bgcolor); | |
3270 g_free (bgcolor); | |
3271 if (tmp) { | |
3272 NEW_BIT (NEW_TEXT_BIT); | |
3273 bg = tmp; | |
3274 UPDATE_BG_COLORS; | |
3275 } | 642 } |
3276 } | 643 } |
644 break; | |
645 case 45: /* A (opt) */ | |
646 { | |
647 gchar *href = gtk_imhtml_get_html_opt (tag, "HREF="); | |
648 if (href) { | |
649 NEW_BIT (NEW_TEXT_BIT); | |
650 if (url) | |
651 g_free (url); | |
652 url = href; | |
653 } | |
654 } | |
655 break; | |
656 case 47: /* P (opt) */ | |
657 case 48: /* H3 (opt) */ | |
658 break; | |
659 case 49: /* comment */ | |
660 NEW_BIT (NEW_TEXT_BIT); | |
661 wpos = g_snprintf (ws, len, "%s", tag); | |
662 NEW_BIT (NEW_COMMENT_BIT); | |
663 break; | |
664 default: | |
665 break; | |
3277 } | 666 } |
3278 break; | |
3279 case 45: /* A (opt) */ | |
3280 { | |
3281 gchar *href = gtk_imhtml_get_html_opt (tag, "HREF="); | |
3282 if (href) { | |
3283 NEW_BIT (NEW_TEXT_BIT); | |
3284 g_free (url); | |
3285 url = href; | |
3286 } | |
3287 } | |
3288 break; | |
3289 case 46: /* IMG (opt) */ | |
3290 { | |
3291 gchar *src = gtk_imhtml_get_html_opt (tag, "SRC="); | |
3292 gchar *id = gtk_imhtml_get_html_opt (tag, "ID="); | |
3293 gchar *datasize = gtk_imhtml_get_html_opt (tag, "DATASIZE="); | |
3294 gchar **xpm; | |
3295 GdkColor *clr; | |
3296 GtkIMHtmlBit *bit; | |
3297 | |
3298 if (!src) | |
3299 break; | |
3300 | |
3301 if (!imhtml->img && id && datasize) { /* This is an embedded IM image */ | |
3302 char *tmp, *imagedata, *e; | |
3303 const gchar *alltext; | |
3304 struct im_image *img; | |
3305 GdkPixbufLoader *load; | |
3306 GdkPixbuf *imagepb = NULL; | |
3307 GError *err; | |
3308 NEW_BIT (NEW_TEXT_BIT); | |
3309 if (!id || !datasize) | |
3310 break; | |
3311 tmp = g_malloc(strlen("<DATA ID=\"\" SIZE=\"\">") + | |
3312 strlen(id) + strlen(datasize)); | |
3313 g_snprintf(tmp, strlen("<DATA ID=\"\" SIZE=\"\">") + | |
3314 strlen(id) + strlen(datasize) + 1, | |
3315 "<DATA ID=\"%s\" SIZE=\"%s\">", id, datasize); | |
3316 alltext = c; | |
3317 while (g_strncasecmp(alltext, tmp, strlen(tmp)) && alltext < (c + len)) | |
3318 alltext++; | |
3319 alltext = alltext + strlen("<DATA ID=\"\" SIZE=\"\">") + strlen(id) + strlen(datasize); | |
3320 g_free(tmp); | |
3321 if (atoi(datasize) > len - pos) | |
3322 break; | |
3323 imagedata = g_malloc(atoi(datasize)); | |
3324 memcpy(imagedata, alltext, atoi(datasize)); | |
3325 | |
3326 if (!GTK_WIDGET_REALIZED (imhtml)) | |
3327 gtk_widget_realize (GTK_WIDGET (imhtml)); | |
3328 | |
3329 img = g_new0 (struct im_image, 1); | |
3330 tmp = e = src; | |
3331 while (*tmp){ | |
3332 if (*tmp == '/' || *tmp == '\\') { | |
3333 tmp++; | |
3334 src = tmp; | |
3335 } else | |
3336 tmp++; | |
3337 } | |
3338 | |
3339 *tmp = '\0'; | |
3340 | |
3341 img->filename = g_strdup(src); | |
3342 img->len = atoi(datasize); | |
3343 if (img->len) { | |
3344 img->data = g_malloc(img->len); | |
3345 memcpy(img->data, imagedata, img->len); | |
3346 load = gdk_pixbuf_loader_new(); | |
3347 | |
3348 if (!gdk_pixbuf_loader_write(load, imagedata, | |
3349 img->len, &err)) | |
3350 debug_printf("IM Image corrupt or unreadable.\n"); | |
3351 else | |
3352 imagepb = gdk_pixbuf_loader_get_pixbuf(load); | |
3353 img->pb = imagepb; | |
3354 } | |
3355 if (imagepb) { | |
3356 bit = g_new0 (GtkIMHtmlBit, 1); | |
3357 bit->type = TYPE_IMG; | |
3358 bit->img = img; | |
3359 if (url) | |
3360 bit->url = g_strdup (url); | |
3361 | |
3362 NEW_BIT (bit); | |
3363 } else { | |
3364 g_free(img->filename); | |
3365 g_free(img->data); | |
3366 } | |
3367 g_free(imagedata); | |
3368 g_free(e); | |
3369 g_free(id); | |
3370 g_free(datasize); | |
3371 | |
3372 break; | |
3373 } | |
3374 | |
3375 if (!imhtml->img || ((xpm = imhtml->img (src)) == NULL)) { | |
3376 g_free (src); | |
3377 break; | |
3378 } | |
3379 | |
3380 if (!fonts || ((clr = ((FontDetail *) fonts->data)->back) == NULL)) | |
3381 clr = (bg != NULL) ? bg : imhtml->default_bg_color; | |
3382 | |
3383 if (!GTK_WIDGET_REALIZED (imhtml)) | |
3384 gtk_widget_realize (GTK_WIDGET (imhtml)); | |
3385 | |
3386 bit = g_new0 (GtkIMHtmlBit, 1); | |
3387 bit->type = TYPE_IMG; | |
3388 bit->pm = gdk_pixmap_create_from_xpm_d (GTK_WIDGET (imhtml)->window, | |
3389 &bit->bm, clr, xpm); | |
3390 if (url) | |
3391 bit->url = g_strdup (url); | |
3392 | |
3393 NEW_BIT (bit); | |
3394 | |
3395 g_free (src); | |
3396 } | |
3397 break; | |
3398 case 47: /* P (opt) */ | |
3399 case 48: /* H3 (opt) */ | |
3400 break; | |
3401 case 49: /* comment */ | |
3402 NEW_BIT (NEW_TEXT_BIT); | |
3403 wpos = g_snprintf (ws, len, "%s", tag); | |
3404 NEW_BIT (NEW_COMMENT_BIT); | |
3405 break; | |
3406 default: | |
3407 break; | |
3408 } | |
3409 g_free (tag); | |
3410 c += tlen; | 667 c += tlen; |
3411 pos += tlen; | 668 pos += tlen; |
3412 } else if (*c == '&' && gtk_imhtml_is_amp_escape (c, &, &tlen)) { | 669 } else if (*c == '&' && gtk_imhtml_is_amp_escape (c, &, &tlen)) { |
3413 ws [wpos++] = amp; | 670 ws [wpos++] = amp; |
3414 c += tlen; | 671 c += tlen; |
3415 pos += tlen; | 672 pos += tlen; |
3416 } else if (*c == '\n') { | 673 } else if (*c == '\n') { |
3417 if (!(options & GTK_IMHTML_NO_NEWLINE)) { | 674 if (!(options & GTK_IMHTML_NO_NEWLINE)) { |
675 ws[wpos] = '\n'; | |
676 wpos++; | |
3418 NEW_BIT (NEW_TEXT_BIT); | 677 NEW_BIT (NEW_TEXT_BIT); |
3419 NEW_BIT (NEW_BR_BIT); | |
3420 } | 678 } |
3421 c++; | 679 c++; |
3422 pos++; | 680 pos++; |
3423 } else if (gtk_imhtml_is_smiley (imhtml, c, &smilelen)) { | |
3424 NEW_BIT (NEW_TEXT_BIT); | |
3425 wpos = g_snprintf (ws, smilelen + 1, "%s", c); | |
3426 NEW_BIT (NEW_SMILEY_BIT); | |
3427 c += smilelen; | |
3428 pos += smilelen; | |
3429 } else if (*c) { | 681 } else if (*c) { |
3430 ws [wpos++] = *c++; | 682 ws [wpos++] = *c++; |
3431 pos++; | 683 pos++; |
3432 } else { | 684 } else { |
3433 break; | 685 break; |
3434 } | 686 } |
3435 } | 687 } |
3436 | 688 |
3437 NEW_BIT (NEW_TEXT_BIT); | 689 NEW_BIT(NEW_TEXT_BIT); |
3438 | |
3439 while (newbits) { | |
3440 GtkIMHtmlBit *bit = newbits->data; | |
3441 imhtml->bits = g_list_append (imhtml->bits, bit); | |
3442 newbits = g_list_remove (newbits, bit); | |
3443 gtk_imhtml_draw_bit (imhtml, bit); | |
3444 } | |
3445 | |
3446 GTK_LAYOUT (imhtml)->height = imhtml->y; | |
3447 GTK_LAYOUT (imhtml)->vadjustment->upper = imhtml->y; | |
3448 gtk_signal_emit_by_name (GTK_OBJECT (GTK_LAYOUT (imhtml)->vadjustment), "changed"); | |
3449 | |
3450 gtk_widget_set_usize (GTK_WIDGET (imhtml), -1, imhtml->y); | |
3451 | |
3452 if (!(options & GTK_IMHTML_NO_SCROLL) && | |
3453 scrolldown && | |
3454 (imhtml->y >= MAX (1, | |
3455 (GTK_WIDGET (imhtml)->allocation.height - | |
3456 (GTK_WIDGET (imhtml)->style->ythickness + BORDER_SIZE) * 2)))) | |
3457 gtk_adjustment_set_value (vadj, imhtml->y - | |
3458 MAX (1, (GTK_WIDGET (imhtml)->allocation.height - | |
3459 (GTK_WIDGET (imhtml)->style->ythickness + | |
3460 BORDER_SIZE) * 2))); | |
3461 | |
3462 if (url) { | 690 if (url) { |
3463 g_free (url); | 691 g_free (url); |
3464 if (retval) | 692 if (str) |
3465 retval = g_string_append (retval, "</A>"); | 693 str = g_string_append (str, "</A>"); |
3466 } | 694 } |
3467 if (bg) | 695 |
3468 gdk_color_free (bg); | 696 if (str) { |
3469 while (fonts) { | |
3470 FontDetail *font = fonts->data; | |
3471 fonts = g_slist_remove (fonts, font); | |
3472 if (font->face) | |
3473 g_free (font->face); | |
3474 if (font->fore) | |
3475 gdk_color_free (font->fore); | |
3476 if (font->back) | |
3477 gdk_color_free (font->back); | |
3478 g_free (font); | |
3479 if (retval) | |
3480 retval = g_string_append (retval, "</FONT>"); | |
3481 } | |
3482 if (retval) { | |
3483 while (bold) { | 697 while (bold) { |
3484 retval = g_string_append (retval, "</B>"); | 698 str = g_string_append (str, "</B>"); |
3485 bold--; | 699 bold--; |
3486 } | 700 } |
3487 while (italics) { | 701 while (italics) { |
3488 retval = g_string_append (retval, "</I>"); | 702 str = g_string_append (str, "</I>"); |
3489 italics--; | 703 italics--; |
3490 } | 704 } |
3491 while (underline) { | 705 while (underline) { |
3492 retval = g_string_append (retval, "</U>"); | 706 str = g_string_append (str, "</U>"); |
3493 underline--; | 707 underline--; |
3494 } | 708 } |
3495 while (strike) { | 709 while (strike) { |
3496 retval = g_string_append (retval, "</S>"); | 710 str = g_string_append (str, "</S>"); |
3497 strike--; | 711 strike--; |
3498 } | 712 } |
3499 while (sub) { | 713 while (sub) { |
3500 retval = g_string_append (retval, "</SUB>"); | 714 str = g_string_append (str, "</SUB>"); |
3501 sub--; | 715 sub--; |
3502 } | 716 } |
3503 while (sup) { | 717 while (sup) { |
3504 retval = g_string_append (retval, "</SUP>"); | 718 str = g_string_append (str, "</SUP>"); |
3505 sup--; | 719 sup--; |
3506 } | 720 } |
3507 while (title) { | 721 while (title) { |
3508 retval = g_string_append (retval, "</TITLE>"); | 722 str = g_string_append (str, "</TITLE>"); |
3509 title--; | 723 title--; |
3510 } | 724 } |
3511 while (pre) { | 725 while (pre) { |
3512 retval = g_string_append (retval, "</PRE>"); | 726 str = g_string_append (str, "</PRE>"); |
3513 pre--; | 727 pre--; |
3514 } | 728 } |
3515 } | 729 } |
3516 g_free (ws); | 730 //g_free (ws); |
3517 | 731 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (imhtml), mark, |
3518 return retval; | 732 0, TRUE, 0.0, 1.0); |
3519 } | 733 gtk_text_buffer_delete_mark (imhtml->text_buffer, mark); |
734 return str; | |
735 } | |
736 | |
737 void gtk_imhtml_set_adjustments (GtkIMHtml *imhtml, | |
738 GtkAdjustment *hadj, | |
739 GtkAdjustment *vadj){} | |
740 | |
741 void gtk_imhtml_set_defaults (GtkIMHtml *imhtml, | |
742 PangoFontDescription *font, | |
743 GdkColor *fg_color, | |
744 GdkColor *bg_color){} | |
745 | |
746 void gtk_imhtml_set_img_handler (GtkIMHtml *imhtml, | |
747 GtkIMHtmlImage handler){} | |
748 | |
749 void gtk_imhtml_associate_smiley (GtkIMHtml *imhtml, | |
750 gchar *text, | |
751 gchar **xpm){} | |
752 void gtk_imhtml_init_smileys (GtkIMHtml *imhtml){} | |
753 void gtk_imhtml_remove_smileys (GtkIMHtml *imhtml){} | |
754 void gtk_imhtml_reset_smileys (GtkIMHtml *imhtml){} | |
755 void gtk_imhtml_show_smileys (GtkIMHtml *imhtml, | |
756 gboolean show){} | |
757 | |
758 void gtk_imhtml_show_comments (GtkIMHtml *imhtml, | |
759 gboolean show){} | |
3520 | 760 |
3521 void | 761 void |
3522 gtk_imhtml_clear (GtkIMHtml *imhtml) | 762 gtk_imhtml_clear (GtkIMHtml *imhtml) |
3523 { | 763 { |
3524 GtkLayout *layout; | 764 GtkTextIter start, end; |
3525 | |
3526 g_return_if_fail (imhtml != NULL); | |
3527 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
3528 | |
3529 layout = GTK_LAYOUT (imhtml); | |
3530 | |
3531 while (imhtml->bits) { | |
3532 GtkIMHtmlBit *bit = imhtml->bits->data; | |
3533 imhtml->bits = g_list_remove (imhtml->bits, bit); | |
3534 if (bit->text) | |
3535 g_free (bit->text); | |
3536 if (bit->font) | |
3537 pango_font_description_free(bit->font); | |
3538 //gdk_font_unref (bit->font); | |
3539 if (bit->fore) | |
3540 gdk_color_free (bit->fore); | |
3541 if (bit->back) | |
3542 gdk_color_free (bit->back); | |
3543 if (bit->bg) | |
3544 gdk_color_free (bit->bg); | |
3545 if (bit->url) | |
3546 g_free (bit->url); | |
3547 if (bit->pm) | |
3548 gdk_pixmap_unref (bit->pm); | |
3549 if (bit->bm) | |
3550 gdk_bitmap_unref (bit->bm); | |
3551 if (bit->img) { | |
3552 g_free(bit->img->filename); | |
3553 g_free(bit->img->data); | |
3554 gdk_pixbuf_unref(bit->img->pb); | |
3555 g_free(bit->img); | |
3556 } | |
3557 | |
3558 while (bit->chunks) { | |
3559 struct line_info *li = bit->chunks->data; | |
3560 if (li->text) | |
3561 g_free (li->text); | |
3562 bit->chunks = g_list_remove (bit->chunks, li); | |
3563 g_free (li); | |
3564 } | |
3565 g_free (bit); | |
3566 } | |
3567 | |
3568 while (imhtml->click) { | |
3569 g_free (imhtml->click->data); | |
3570 imhtml->click = g_list_remove (imhtml->click, imhtml->click->data); | |
3571 } | |
3572 | 765 |
3573 while (imhtml->im_images) { | 766 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); |
3574 imhtml->im_images = g_list_remove(imhtml->im_images, imhtml->im_images->data); | 767 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); |
3575 } | 768 gtk_text_buffer_delete(imhtml->text_buffer, &start, &end); |
3576 | 769 } |
3577 if (imhtml->selected_text) { | 770 |
3578 g_string_free (imhtml->selected_text, TRUE); | 771 void gtk_imhtml_page_up (GtkIMHtml *imhtml){} |
3579 imhtml->selected_text = g_string_new (""); | 772 void gtk_imhtml_page_down (GtkIMHtml *imhtml){} |
3580 } | |
3581 | |
3582 imhtml->sel_startx = 0; | |
3583 imhtml->sel_starty = 0; | |
3584 imhtml->sel_endx = 0; | |
3585 imhtml->sel_endx = 0; | |
3586 imhtml->sel_endchunk = NULL; | |
3587 | |
3588 if (imhtml->tip_timer) { | |
3589 gtk_timeout_remove (imhtml->tip_timer); | |
3590 imhtml->tip_timer = 0; | |
3591 } | |
3592 if (imhtml->tip_window) { | |
3593 gtk_widget_destroy (imhtml->tip_window); | |
3594 imhtml->tip_window = NULL; | |
3595 } | |
3596 imhtml->tip_bit = NULL; | |
3597 | |
3598 if (imhtml->scroll_timer) { | |
3599 gtk_timeout_remove (imhtml->scroll_timer); | |
3600 imhtml->scroll_timer = 0; | |
3601 } | |
3602 | |
3603 g_list_free(imhtml->im_images); | |
3604 imhtml->im_images = NULL; | |
3605 | |
3606 imhtml->x = 0; | |
3607 imhtml->y = TOP_BORDER; | |
3608 imhtml->xsize = 0; | |
3609 imhtml->llheight = 0; | |
3610 imhtml->llascent = 0; | |
3611 if (imhtml->line) | |
3612 g_list_free (imhtml->line); | |
3613 imhtml->line = NULL; | |
3614 | |
3615 layout->hadjustment->page_size = 0; | |
3616 layout->hadjustment->page_increment = 0; | |
3617 layout->hadjustment->lower = 0; | |
3618 layout->hadjustment->upper = imhtml->x; | |
3619 gtk_adjustment_set_value (layout->hadjustment, 0); | |
3620 | |
3621 layout->vadjustment->page_size = 0; | |
3622 layout->vadjustment->page_increment = 0; | |
3623 layout->vadjustment->lower = 0; | |
3624 layout->vadjustment->upper = imhtml->y; | |
3625 gtk_adjustment_set_value (layout->vadjustment, 0); | |
3626 | |
3627 if (GTK_WIDGET_REALIZED (GTK_WIDGET (imhtml))) { | |
3628 gdk_window_set_cursor (GTK_LAYOUT (imhtml)->bin_window, imhtml->arrow_cursor); | |
3629 gdk_window_clear (GTK_LAYOUT (imhtml)->bin_window); | |
3630 gtk_signal_emit_by_name (GTK_OBJECT (layout->hadjustment), "changed"); | |
3631 gtk_signal_emit_by_name (GTK_OBJECT (layout->vadjustment), "changed"); | |
3632 } | |
3633 } | |
3634 | |
3635 void | |
3636 gtk_imhtml_page_up (GtkIMHtml *imhtml) | |
3637 { | |
3638 GtkAdjustment *vadj; | |
3639 | |
3640 g_return_if_fail (imhtml != NULL); | |
3641 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
3642 | |
3643 vadj = GTK_LAYOUT (imhtml)->vadjustment; | |
3644 gtk_adjustment_set_value (vadj, MAX (vadj->value - vadj->page_increment, | |
3645 vadj->lower)); | |
3646 gtk_signal_emit_by_name (GTK_OBJECT (vadj), "changed"); | |
3647 } | |
3648 | |
3649 void | |
3650 gtk_imhtml_page_down (GtkIMHtml *imhtml) | |
3651 { | |
3652 GtkAdjustment *vadj; | |
3653 | |
3654 g_return_if_fail (imhtml != NULL); | |
3655 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
3656 | |
3657 vadj = GTK_LAYOUT (imhtml)->vadjustment; | |
3658 gtk_adjustment_set_value (vadj, MIN (vadj->value + vadj->page_increment, | |
3659 vadj->upper - vadj->page_size)); | |
3660 gtk_signal_emit_by_name (GTK_OBJECT (vadj), "changed"); | |
3661 } | |
3662 | |
3663 void | |
3664 gtk_imhtml_to_bottom (GtkIMHtml *imhtml) | |
3665 { | |
3666 GtkAdjustment *vadj; | |
3667 | |
3668 g_return_if_fail (imhtml != NULL); | |
3669 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
3670 | |
3671 vadj = GTK_LAYOUT (imhtml)->vadjustment; | |
3672 gtk_adjustment_set_value (vadj, vadj->upper - vadj->page_size); | |
3673 gtk_signal_emit_by_name (GTK_OBJECT (vadj), "changed"); | |
3674 } |